changeset 0:ada5e610ab86

imap-2007e
author yuuji@gentei.org
date Mon, 14 Sep 2009 15:17:45 +0900
parents
children 28a55bc1110c 5cecc027b845
files CONTENTS LICENSE.txt Makefile NOTICE README SUPPORT docs/BUILD docs/CONFIG docs/FAQ.html docs/FAQ.txt docs/IPv6.txt docs/RELNOTES docs/SSLBUILD docs/Y2K docs/bugs.txt docs/calendar.txt docs/commndmt.txt docs/draft/README docs/draft/i18n.txt docs/draft/sort.txt docs/drivers.txt docs/formats.txt docs/imaprc.txt docs/internal.txt docs/locking.txt docs/md5.txt docs/mixfmt.txt docs/naming.txt docs/rfc/README docs/rfc/rfc1732.txt docs/rfc/rfc1733.txt docs/rfc/rfc2061.txt docs/rfc/rfc2062.txt docs/rfc/rfc2087.txt docs/rfc/rfc2088.txt docs/rfc/rfc2177.txt docs/rfc/rfc2180.txt docs/rfc/rfc2193.txt docs/rfc/rfc2195.txt docs/rfc/rfc2221.txt docs/rfc/rfc2342.txt docs/rfc/rfc2683.txt docs/rfc/rfc2971.txt docs/rfc/rfc3348.txt docs/rfc/rfc3501.txt docs/rfc/rfc3502.txt docs/rfc/rfc3503.txt docs/rfc/rfc3516.txt docs/rfc/rfc3656.txt docs/rfc/rfc3691.txt docs/rfc/rfc4314.txt docs/rfc/rfc4315.txt docs/rfc/rfc4422.txt docs/rfc/rfc4466.txt docs/rfc/rfc4467.txt docs/rfc/rfc4468.txt docs/rfc/rfc4469.txt docs/rfc/rfc4505.txt docs/rfc/rfc4549.txt docs/rfc/rfc4551.txt docs/rfc/rfc4616.txt docs/rfc/rfc4731.txt docs/rfc/rfc4752.txt docs/rfc/rfc4790.txt docs/rfc/rfc4959.txt docs/rfc/rfc4978.txt docs/rfc/rfc5032.txt docs/rfc/rfc5051.txt docs/rfc/rfc5092.txt docs/rfc/rfc5161.txt docs/rfc/rfc5162.txt docs/rfc/rfc5234.txt makefile.nt makefile.ntk makefile.os2 makefile.w2k makefile.wce src/ansilib/memmove.c src/ansilib/memmove2.c src/ansilib/memset.c src/ansilib/strpbrk.c src/ansilib/strstr.c src/ansilib/strtok.c src/ansilib/strtoul.c src/c-client/auth_ext.c src/c-client/auth_gss.c src/c-client/auth_log.c src/c-client/auth_md5.c src/c-client/auth_pla.c src/c-client/c-client.h src/c-client/env.h src/c-client/flstring.c src/c-client/flstring.h src/c-client/fs.h src/c-client/ftl.h src/c-client/imap4r1.c src/c-client/imap4r1.h src/c-client/mail.c src/c-client/mail.h src/c-client/misc.c src/c-client/misc.h src/c-client/netmsg.c src/c-client/netmsg.h src/c-client/newsrc.c src/c-client/newsrc.h src/c-client/nl.h src/c-client/nntp.c src/c-client/nntp.h src/c-client/pop3.c src/c-client/rfc822.c src/c-client/rfc822.h src/c-client/smanager.c src/c-client/smtp.c src/c-client/smtp.h src/c-client/sslio.h src/c-client/tcp.h src/c-client/utf8.c src/c-client/utf8.h src/c-client/utf8aux.c src/c-client/utf8aux.h src/charset/big5.c src/charset/cns11643.c src/charset/decomtab.c src/charset/gb_12345.c src/charset/gb_2312.c src/charset/ibm.c src/charset/iso_8859.c src/charset/jis_0208.c src/charset/jis_0212.c src/charset/koi8_r.c src/charset/koi8_u.c src/charset/ksc_5601.c src/charset/tis_620.c src/charset/tmap.c src/charset/viscii.c src/charset/widths.c src/charset/windows.c src/dmail/Makefile src/dmail/dmail.1 src/dmail/dmail.c src/dmail/dquota.c src/dmail/dquota.h src/imapd/Makefile src/imapd/imapd.8 src/imapd/imapd.c src/imapd/makefile.nt src/imapd/makefile.ntk src/imapd/makefile.w2k src/ipopd/Makefile src/ipopd/ipop2d.c src/ipopd/ipop3d.c src/ipopd/ipopd.8 src/ipopd/makefile.nt src/ipopd/makefile.ntk src/ipopd/makefile.w2k src/mailutil/Makefile src/mailutil/mailutil.1 src/mailutil/mailutil.c src/mailutil/makefile.nt src/mailutil/makefile.ntk src/mailutil/makefile.w2k src/mlock/Makefile src/mlock/mlock.c src/mtest/Makefile src/mtest/makefile.nt src/mtest/makefile.ntk src/mtest/makefile.os2 src/mtest/makefile.w2k src/mtest/mtest.c src/osdep/amiga/Makefile src/osdep/amiga/ckp_std.c src/osdep/amiga/drivers src/osdep/amiga/dummy.c src/osdep/amiga/dummy.h src/osdep/amiga/env_ami.c src/osdep/amiga/env_ami.h src/osdep/amiga/fdstring.c src/osdep/amiga/fdstring.h src/osdep/amiga/fs_ami.c src/osdep/amiga/ftl_ami.c src/osdep/amiga/gethstid.c src/osdep/amiga/gr_waitp.c src/osdep/amiga/log_std.c src/osdep/amiga/mbx.c src/osdep/amiga/mh.c src/osdep/amiga/mix.c src/osdep/amiga/mkauths src/osdep/amiga/mmdf.c src/osdep/amiga/mtx.c src/osdep/amiga/mx.c src/osdep/amiga/news.c src/osdep/amiga/nl_ami.c src/osdep/amiga/os_ami.c src/osdep/amiga/os_ami.h src/osdep/amiga/phile.c src/osdep/amiga/pmatch.c src/osdep/amiga/pseudo.c src/osdep/amiga/pseudo.h src/osdep/amiga/scandir.c src/osdep/amiga/ssl_none.c src/osdep/amiga/tcp_ami.c src/osdep/amiga/tcp_ami.h src/osdep/amiga/tenex.c src/osdep/amiga/tz_bsd.c src/osdep/amiga/unix.c src/osdep/amiga/unix.h src/osdep/amiga/write.c src/osdep/dos/bezrkdos.c src/osdep/dos/drivers.bat src/osdep/dos/drivraux.bat src/osdep/dos/dummy.h src/osdep/dos/dummydos.c src/osdep/dos/env_dos.c src/osdep/dos/env_dos.h src/osdep/dos/fdstring.c src/osdep/dos/fdstring.h src/osdep/dos/fs_dos.c src/osdep/dos/ftl_dos.c src/osdep/dos/makefile src/osdep/dos/mkautaux.bat src/osdep/dos/mkauths.bat src/osdep/dos/mtestdbw.bat src/osdep/dos/mtestdnf.bat src/osdep/dos/mtestdnv.bat src/osdep/dos/mtestdpc.bat src/osdep/dos/mtestdwa.bat src/osdep/dos/mtestwsk.bat src/osdep/dos/mtxdos.c src/osdep/dos/nl_dos.c src/osdep/dos/os_dbw.c src/osdep/dos/os_dbw.h src/osdep/dos/os_dnf.c src/osdep/dos/os_dnf.h src/osdep/dos/os_dnv.c src/osdep/dos/os_dnv.h src/osdep/dos/os_dpc.c src/osdep/dos/os_dpc.h src/osdep/dos/os_dwa.c src/osdep/dos/os_dwa.h src/osdep/dos/os_wsk.c src/osdep/dos/os_wsk.h src/osdep/dos/pmatch.c src/osdep/dos/tcp_dos.c src/osdep/dos/tcp_dos.h src/osdep/dos/tcp_dwa.c src/osdep/dos/tcp_dwa.h src/osdep/dos/tcp_wsk.c src/osdep/dos/tcp_wsk.h src/osdep/dos/write.c src/osdep/mac/dummy.h src/osdep/mac/dummymac.c src/osdep/mac/env_mac.c src/osdep/mac/env_mac.h src/osdep/mac/fs_mac.c src/osdep/mac/ftl_mac.c src/osdep/mac/linkage.c src/osdep/mac/linkage.h src/osdep/mac/mtest.sit.hqx src/osdep/mac/nl_mac.c src/osdep/mac/os_mac.c src/osdep/mac/os_mac.h src/osdep/mac/osdep.h src/osdep/mac/pmatch.c src/osdep/mac/tcp_mac.c src/osdep/mac/tcp_mac.h src/osdep/nt/drivers.bat src/osdep/nt/drivraux.bat src/osdep/nt/dummy.h src/osdep/nt/dummynt.c src/osdep/nt/env_nt.c src/osdep/nt/env_nt.h src/osdep/nt/fdstring.c src/osdep/nt/fdstring.h src/osdep/nt/fs_nt.c src/osdep/nt/ftl_nt.c src/osdep/nt/ip4_nt.c src/osdep/nt/ip6_nt.c src/osdep/nt/kerb_mit.c src/osdep/nt/kerb_w2k.c src/osdep/nt/mailfile.h src/osdep/nt/makefile.nt src/osdep/nt/makefile.ntk src/osdep/nt/makefile.old src/osdep/nt/makefile.w2k src/osdep/nt/mbxnt.c src/osdep/nt/mkautaux.bat src/osdep/nt/mkauths.bat src/osdep/nt/mtxnt.c src/osdep/nt/nl_nt.c src/osdep/nt/os_nt.c src/osdep/nt/os_nt.h src/osdep/nt/os_ntk.c src/osdep/nt/os_old.c src/osdep/nt/os_w2k.c src/osdep/nt/pmatch.c src/osdep/nt/pseudo.c src/osdep/nt/pseudo.h src/osdep/nt/setproto.bat src/osdep/nt/ssl_none.c src/osdep/nt/ssl_nt.c src/osdep/nt/ssl_old.c src/osdep/nt/ssl_w2k.c src/osdep/nt/tcp_nt.c src/osdep/nt/tcp_nt.h src/osdep/nt/tenexnt.c src/osdep/nt/unixnt.c src/osdep/nt/unixnt.h src/osdep/nt/write.c src/osdep/nt/yunchan.c src/osdep/nt/yunchan.h src/osdep/os2/auths.cmd src/osdep/os2/drivers.cmd src/osdep/os2/dummy.h src/osdep/os2/dummyos2.c src/osdep/os2/env_os2.c src/osdep/os2/env_os2.h src/osdep/os2/fs_os2.c src/osdep/os2/ftl_os2.c src/osdep/os2/makefile.os2 src/osdep/os2/mbxnt.c src/osdep/os2/mtxnt.c src/osdep/os2/nl_os2.c src/osdep/os2/os_os2.c src/osdep/os2/os_os2.h src/osdep/os2/pmatch.c src/osdep/os2/pseudo.c src/osdep/os2/pseudo.h src/osdep/os2/setproto.cmd src/osdep/os2/tcp_os2.c src/osdep/os2/tcp_os2.h src/osdep/os2/tenexnt.c src/osdep/os2/unixnt.c src/osdep/os2/unixnt.h src/osdep/os2/write.c src/osdep/tops-20/build.ctl src/osdep/tops-20/dummy.h src/osdep/tops-20/dummyt20.c src/osdep/tops-20/env_t20.c src/osdep/tops-20/env_t20.h src/osdep/tops-20/fs_t20.c src/osdep/tops-20/ftl_t20.c src/osdep/tops-20/linkage.c src/osdep/tops-20/linkage.h src/osdep/tops-20/log_t20.c src/osdep/tops-20/nl_t20.c src/osdep/tops-20/os_t20.c src/osdep/tops-20/os_t20.h src/osdep/tops-20/pmatch.c src/osdep/tops-20/shortsym.h src/osdep/tops-20/tcp_t20.c src/osdep/tops-20/tcp_t20.h src/osdep/unix/Makefile src/osdep/unix/Makefile.gss src/osdep/unix/ckp_1st.c src/osdep/unix/ckp_2nd.c src/osdep/unix/ckp_3rd.c src/osdep/unix/ckp_a41.c src/osdep/unix/ckp_afs.c src/osdep/unix/ckp_bsi.c src/osdep/unix/ckp_cyg.c src/osdep/unix/ckp_dce.c src/osdep/unix/ckp_gss.c src/osdep/unix/ckp_nul.c src/osdep/unix/ckp_os4.c src/osdep/unix/ckp_pam.c src/osdep/unix/ckp_pmb.c src/osdep/unix/ckp_psx.c src/osdep/unix/ckp_sce.c src/osdep/unix/ckp_sec.c src/osdep/unix/ckp_ssn.c src/osdep/unix/ckp_std.c src/osdep/unix/ckp_sv4.c src/osdep/unix/ckp_svo.c src/osdep/unix/ckp_ult.c src/osdep/unix/crx_nfs.c src/osdep/unix/crx_std.c src/osdep/unix/drivers src/osdep/unix/dummy.c src/osdep/unix/dummy.h src/osdep/unix/env_unix.c src/osdep/unix/env_unix.h src/osdep/unix/fdstring.c src/osdep/unix/fdstring.h src/osdep/unix/flockcyg.c src/osdep/unix/flockcyg.h src/osdep/unix/flocklnx.c src/osdep/unix/flocksim.c src/osdep/unix/flocksim.h src/osdep/unix/fs_unix.c src/osdep/unix/fsync.c src/osdep/unix/ftl_unix.c src/osdep/unix/gethstid.c src/osdep/unix/getspnam.c src/osdep/unix/gr_wait.c src/osdep/unix/gr_wait4.c src/osdep/unix/gr_waitp.c src/osdep/unix/ip4_unix.c src/osdep/unix/ip6_unix.c src/osdep/unix/ipo_unix.c src/osdep/unix/kerb_mit.c src/osdep/unix/log_bsi.c src/osdep/unix/log_cyg.c src/osdep/unix/log_old.c src/osdep/unix/log_os4.c src/osdep/unix/log_sec.c src/osdep/unix/log_std.c src/osdep/unix/log_sv4.c src/osdep/unix/mbx.c src/osdep/unix/mh.c src/osdep/unix/mix.c src/osdep/unix/mkauths src/osdep/unix/mmdf.c src/osdep/unix/mtx.c src/osdep/unix/mx.c src/osdep/unix/news.c src/osdep/unix/nl_unix.c src/osdep/unix/opendir.c src/osdep/unix/os_a32.c src/osdep/unix/os_a32.h src/osdep/unix/os_a41.c src/osdep/unix/os_a41.h src/osdep/unix/os_aix.c src/osdep/unix/os_aix.h src/osdep/unix/os_aos.c src/osdep/unix/os_aos.h src/osdep/unix/os_art.c src/osdep/unix/os_art.h src/osdep/unix/os_asv.c src/osdep/unix/os_asv.h src/osdep/unix/os_aux.c src/osdep/unix/os_aux.h src/osdep/unix/os_bsd.c src/osdep/unix/os_bsd.h src/osdep/unix/os_bsf.c src/osdep/unix/os_bsf.h src/osdep/unix/os_bsi.c src/osdep/unix/os_bsi.h src/osdep/unix/os_cvx.c src/osdep/unix/os_cvx.h src/osdep/unix/os_cyg.c src/osdep/unix/os_cyg.h src/osdep/unix/os_d-g.c src/osdep/unix/os_d-g.h src/osdep/unix/os_do4.c src/osdep/unix/os_do4.h src/osdep/unix/os_drs.c src/osdep/unix/os_drs.h src/osdep/unix/os_dyn.c src/osdep/unix/os_dyn.h src/osdep/unix/os_hpp.c src/osdep/unix/os_hpp.h src/osdep/unix/os_isc.c src/osdep/unix/os_isc.h src/osdep/unix/os_lnx.c src/osdep/unix/os_lnx.h src/osdep/unix/os_lyn.c src/osdep/unix/os_lyn.h src/osdep/unix/os_mct.c src/osdep/unix/os_mct.h src/osdep/unix/os_mnt.c src/osdep/unix/os_mnt.h src/osdep/unix/os_nto.c src/osdep/unix/os_nto.h src/osdep/unix/os_nxt.c src/osdep/unix/os_nxt.h src/osdep/unix/os_os4.c src/osdep/unix/os_os4.h src/osdep/unix/os_osf.c src/osdep/unix/os_osf.h src/osdep/unix/os_osx.c src/osdep/unix/os_osx.h src/osdep/unix/os_ptx.c src/osdep/unix/os_ptx.h src/osdep/unix/os_pyr.c src/osdep/unix/os_pyr.h src/osdep/unix/os_qnx.c src/osdep/unix/os_qnx.h src/osdep/unix/os_s40.c src/osdep/unix/os_s40.h src/osdep/unix/os_sc5.c src/osdep/unix/os_sc5.h src/osdep/unix/os_sco.c src/osdep/unix/os_sco.h src/osdep/unix/os_sgi.c src/osdep/unix/os_sgi.h src/osdep/unix/os_shp.c src/osdep/unix/os_shp.h src/osdep/unix/os_slx.c src/osdep/unix/os_slx.h src/osdep/unix/os_sol.c src/osdep/unix/os_soln.h src/osdep/unix/os_solo.h src/osdep/unix/os_sos.c src/osdep/unix/os_sos.h src/osdep/unix/os_sua.c src/osdep/unix/os_sua.h src/osdep/unix/os_sun.c src/osdep/unix/os_sun.h src/osdep/unix/os_sv2.c src/osdep/unix/os_sv2.h src/osdep/unix/os_sv4.c src/osdep/unix/os_sv4.h src/osdep/unix/os_ult.c src/osdep/unix/os_ult.h src/osdep/unix/os_vu2.c src/osdep/unix/os_vu2.h src/osdep/unix/phile.c src/osdep/unix/pmatch.c src/osdep/unix/pseudo.c src/osdep/unix/pseudo.h src/osdep/unix/rename.c src/osdep/unix/scandir.c src/osdep/unix/setpgrp.c src/osdep/unix/sig_bsd.c src/osdep/unix/sig_psx.c src/osdep/unix/sig_sv4.c src/osdep/unix/ssl_none.c src/osdep/unix/ssl_unix.c src/osdep/unix/sslstdio.c src/osdep/unix/strerror.c src/osdep/unix/tcp_unix.c src/osdep/unix/tcp_unix.h src/osdep/unix/tenex.c src/osdep/unix/truncate.c src/osdep/unix/tz_bsd.c src/osdep/unix/tz_nul.c src/osdep/unix/tz_sv4.c src/osdep/unix/unix.c src/osdep/unix/unix.h src/osdep/unix/utime.c src/osdep/unix/write.c src/osdep/vms/build.com src/osdep/vms/clean.com src/osdep/vms/dummy.h src/osdep/vms/dummyvms.c src/osdep/vms/env_vms.c src/osdep/vms/env_vms.h src/osdep/vms/fs_vms.c src/osdep/vms/ftl_vms.c src/osdep/vms/link.opt src/osdep/vms/link_mnt.opt src/osdep/vms/link_nlb.opt src/osdep/vms/linkage.c src/osdep/vms/linkage.h src/osdep/vms/nl_vms.c src/osdep/vms/os_vms.c src/osdep/vms/os_vms.h src/osdep/vms/pmatch.c src/osdep/vms/tcp_vms.h src/osdep/vms/tcp_vmsl.c src/osdep/vms/tcp_vmsm.c src/osdep/vms/tcp_vmsn.c src/osdep/wce/drivers.bat src/osdep/wce/drivraux.bat src/osdep/wce/dummy.h src/osdep/wce/dummywce.c src/osdep/wce/env_wce.c src/osdep/wce/env_wce.h src/osdep/wce/fs_wce.c src/osdep/wce/ftl_wce.c src/osdep/wce/makefile.wce src/osdep/wce/mkautaux.bat src/osdep/wce/mkauths.bat src/osdep/wce/nl_wce.c src/osdep/wce/os_wce.c src/osdep/wce/os_wce.h src/osdep/wce/pmatch.c src/osdep/wce/setproto.bat src/osdep/wce/tcp_wce.c src/osdep/wce/tcp_wce.h src/tmail/Makefile src/tmail/tmail.1 src/tmail/tmail.c src/tmail/tquota.c src/tmail/tquota.h tools/Makefile tools/an tools/ua tools/uahelper.c
diffstat 579 files changed, 216392 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CONTENTS	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,75 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+			  TOOLKIT DIRECTORY CONTENTS
+
+Documentation:
+ . CONTENTS		this file
+ . LICENSE.txt		software license
+ . NOTICE		copyright notice
+ . README		read this file first
+ . SUPPORT		where to go to ask questions and/or report bugs
+ . docs/BUILD		build and installation instructions
+ . docs/CONFIG		detailed configuration notes
+ . docs/FAQ.html	frequently asked questions and answers
+ . docs/FAQ.txt		text version of FAQ.HTML
+ . docs/RELNOTES	release notes
+ . docs/SSLBUILD	build and installation instructions using SSL
+ . docs/Y2K		information relating to Y2K issues
+ . docs/bugs.txt	known bugs and deficiencies in this software
+ . docs/calendar.txt	information relating to the calendar
+ . docs/commndmt.txt	"ten commandments" on how to write a good IMAP client
+ . docs/draft/		Internet protocol documentation drafts
+ . docs/drivers.txt	how various mailbox format drivers interact, and
+			 comparable features and performance
+ . docs/formats.txt	mailbox formats
+ . docs/internal.txt	programming interfaces
+ . docs/locking.txt	how file locking works
+ . docs/md5.txt		CRAM-MD5 authentication setup instructions
+ . docs/mixfmt.txt	specification of new mix format
+ . docs/naming.txt	mailbox naming conventions
+ . docs/rfc/		Internet protocol documentation
+
+Sources:
+ . Makefile		master makefile for UNIX
+ . makefile.nt		master makefile for NT/Win32
+ . makefile.ntk		master makefile for NT/Win32 using Kerberos V
+ . makefile.os2		master makefile for OS/2
+ . makefile.w2k		master makefile for Windows 2000
+ . makefile.wce		master makefile for Windows CE
+ . src/ansilib		pre-processed ANSI library routines
+ . src/c-client		pre-processed c-client sources
+ . src/charset		pre-processed character set conversion tables
+ . src/dmail		pre-processed user mail delivery sources
+ . src/ipopd		pre-processed POP2/POP3 daemon sources
+ . src/imapd		pre-processed IMAP4rev1 daemon sources
+ . src/mailutil		pre-processed mailbox utility sources
+ . src/mlock		pre-processed mailbox locking sources
+ . src/mtest		pre-processed c-client testbed sources
+ . src/osdep/amiga	pre-processed Amiga-specific sources
+ . src/osdep/dos	pre-processed DOS-specific sources
+ . src/osdep/mac	pre-processed Mac-specific sources
+ . src/osdep/nt		pre-processed NT-specific sources
+ . src/osdep/os2	pre-processed OS/2-specific sources (incomplete)
+ . src/osdep/tops-20	pre-processed TOPS-20 specific sources
+ . src/osdep/unix	pre-processed UNIX-specific sources
+ . src/osdep/vms	pre-processed VAX/VMS specific sources
+ . src/osdep/wce	pre-processed Windows CE-specific sources (incomplete)
+ . src/tmail		pre-processed system mail delivery sources
+ . tools		internal tools needed as part of the build process
+
+Directories created at build time on UNIX and NT/Win32:
+ . c-client		post-processed c-client sources and binary
+ . ipopd		post-processed POP2/POP3 daemon sources and binaries
+ . imapd		post-processed IMAP4rev1 daemon sources and binaries
+ . mtest		post-processed c-client testbed sources and binaries
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LICENSE.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions. 
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below). 
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,736 @@
+# ========================================================================
+# Copyright 1988-2008 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+# Program:	IMAP Toolkit Makefile
+#
+# Author:	Mark Crispin
+#		UW Technology
+#		Seattle, WA  98195
+#		Internet: MRC@Washington.EDU
+#
+# Date:		7 December 1989
+# Last Edited:	12 May 2008
+
+
+# Normal command to build IMAP toolkit:
+#  make <port> [EXTRAAUTHENTICATORS=xxx] [EXTRADRIVERS=xxx] [EXTRACFLAGS=xxx]
+#	       [PASSWDTYPE=xxx] [SSLTYPE=xxx] [IP=n]
+
+
+# Port name.  These refer to the *standard* compiler on the given system.
+# This means, for example, that the hpx port is for HP's compiler and not for
+# a non-standard compiler such as gcc.
+#
+# If you are using gcc and it is not the standard compiler on your system, try
+# using an ANSI port that is close to what you have.  For example, if your
+# system is SVR4ish, try a32 or lnx; if it's more BSDish, try nxt, mct, or bsi.
+#
+# The following ports are bundled:
+# a32	AIX 3.2 for RS/6000
+# a41	AIX 4.1 for RS/6000
+# aix	AIX/370 (not RS/6000!!)
+# ami	AmigaDOS
+# am2	AmigaDOS with a 68020+
+# ama	AmigaDOS using AS225R2
+# amn	AmigaDOS with a 680x0 using "new" socket library
+# aos	AOS for RT
+# art	AIX 2.2.1 for RT
+# asv	Altos SVR4
+# aux	A/UX
+# bs3	BSD/i386 3.0 and higher
+# bsd	generic BSD 4.3 (as in ancient 1980s version)
+# bsf	FreeBSD
+# bsi	BSD/i386
+# bso	OpenBSD (yes, yet another one...)
+# cvx	Convex
+# cyg	Cygwin
+# d-g	Data General DG/UX prior to 5.4 (d41 port no longer exists)
+# d54	Data General DG/UX 5.4
+# do4	Apollo Domain/OS sr10.4
+# dpx	Bull DPX/2 B.O.S.
+# drs	ICL DRS/NX
+# dyn	Dynix
+# epx	EP/IX
+# ga4	GCC AIX 4.x for RS/6000
+# gas	GCC Altos SVR4
+# gcs	GCC Solaris with Blastwave Community Open Source Software
+# gh9   GCC HP-UX 9.x
+# ghp	GCC HP-UX 10.x
+# ghs	GCC HP-UX 10.x with Trusted Computer Base
+# go5	GCC 2.7.1 (95q4 from Skunkware _not_ 98q2!) SCO Open Server 5.0.x
+# gsc	GCC Santa Cruz Operation
+# gsg	GCC SGI
+# gso	GCC Solaris
+# gsu	GCC SUN-OS
+# gul	GCC RISC Ultrix (DEC-5000)
+# h11	HP-UX 11i
+# hpp	HP-UX 9.x (see gh9)
+# hpx	HP-UX 10.x (see ghp, ghs, hxd, and shp)
+# hxd	HP-UX 10.x with DCE security (see shp)
+# isc	Interactive Systems
+# ldb	Debian Linux
+# lfd	Fedora Core 4
+# ln8	Linux for Nokia N800
+# lnx	Linux with traditional passwords and crypt() in the C library
+#	 (see lnp, sl4, sl5, and slx)
+# lnp	Linux with Pluggable Authentication Modules (PAM)
+# lmd	Mandrake Linux
+# lr5	RedHat Enterprise 5 and later (same as lfd)
+# lrh	RedHat Linux 7.2 and later
+# lsu	SuSE Linux (same as lrh)
+# lyn	LynxOS
+# mct	MachTen
+# mnt	Atari ST Mint (not MacMint)
+# neb	NetBSD
+# nec	NEC UX
+# nto	QNX Neutrine RTP
+# nxt	NEXTSTEP
+# nx3	NEXTSTEP 3.x
+# osf	OSF/1 (see sos, os4)
+# os4	OSF/1 (Digital UNIX) 4
+# osi	Apple iPhone and iPod Touch
+# osx	Mac OS X
+# oxp	Mac OS X with Pluggable Authentication Modules (PAM)
+# ptx	PTX
+# pyr	Pyramid
+# qnx	QNX 4
+# s40	SUN-OS 4.0 (*not* Solaris)
+# sc5	SCO Open Server 5.0.x (see go5)
+# sco	Santa Cruz Operation (see sc5, go5)
+# shp	HP-UX with Trusted Computer Base
+# sgi	Silicon Graphics IRIX
+# sg6	Silicon Graphics IRIX 6.5
+# sl4	Linux using -lshadow to get the crypt() function
+# sl5	Linux with shadow passwords, no extra libraries
+# slx	Linux using -lcrypt to get the crypt() function
+# snx	Siemens Nixdorf SININX or Reliant UNIX
+# soc	Solaris with /opt/SUNWspro/bin/cc
+# sol	Solaris (won't work unless "ucbcc" works -- use gso instead)
+# sos	OSF/1 with SecureWare
+# ssn	SUN-OS with shadow password security
+# sua	Windows Vista (Enterprise or Ultima) Subsystem for Unix Applications
+# sun	SUN-OS 4.1 or better (*not* Solaris) (see ssn)
+# sv2	SVR2 on AT&T PC-7300 (incomplete port)
+# sv4	generic SVR4
+# ult	RISC Ultrix (DEC-5000)
+# uw2	UnixWare SVR4.2
+# vul	VAX Ultrix
+# vu2	VAX Ultrix 2.3 (e.g. for VAXstation-2000 or similar old version)
+
+
+# Extra authenticators (e.g. OTP, Kerberos, etc.).  Adds linkage for
+# auth_xxx.c and executes Makefile.xxx, where xxx is the name of the
+# authenticator.  Some authenticators are only available from third parties.
+#
+# The following extra authenticators are bundled:
+# gss	Kerberos V
+
+EXTRAAUTHENTICATORS=
+
+
+# Additional mailbox drivers.  Add linkage for xxxdriver.  Some drivers are
+# only available from third parties.
+#
+# The following extra drivers are bundled:
+# mbox	if file "mbox" exists on the home directory, automatically moves mail
+#	 from the spool directory to "mbox" and uses "mbox" as INBOX.
+
+EXTRADRIVERS=mbox
+
+
+# Plaintext password type.  Defines how plaintext password authentication is
+# done on this system.
+#
+# The following plaintext login types are bundled:
+# afs	AFS authentication database
+# dce	DCE authentication database
+# gss	Kerberos V
+# nul	plaintext authentication never permitted
+# pam	PAM authentication (note: for Linux, you should use the "lnp" port
+#	 instead of setting this...also, you may have to modify PAMLDFLAGS
+#	 in the imap-[]/src/osdep/unix/Makefile
+# pmb	PAM authentication for broken implementations such as Solaris.
+#	 you may have to modify PAMLDFLAGS
+# std	system standard (typically passwd file), determined by port
+# two	try alternative (defined by CHECKPWALT), then std
+
+PASSWDTYPE=std
+
+
+# SSL type.  Defines whether or not SSL support is on this system
+#
+# The following SSL types are bundled:
+# none	no SSL support
+# unix	SSL support using OpenSSL
+# nopwd	SSL support using OpenSSL, and plaintext authentication permitted only
+#	in SSL/TLS sessions
+# sco	link SSL before other libraries (for SCO systems)
+# unix.nopwd	same as nopwd
+# sco.nopwd	same as nopwd, plaintext authentication in SSL/TLS only
+#
+# SSLTYPE=nopwd is now the default as required by RFC 3501
+
+SSLTYPE=nopwd
+
+
+# IP protocol version
+#
+# The following IP protocol versions are defined:
+# o	IPv4 support, no DNS (truly ancient systems)
+# 4	(default) IPv4 support only
+# 6	IPv6 and IPv4 support
+
+IP=4
+IP6=6
+
+
+# The following extra compilation flags are defined.  None of these flags are
+# recommended.  If you use these, include them in the EXTRACFLAGS.
+#
+# -DDISABLE_POP_PROXY
+#	By default, the ipop[23]d servers offer POP->IMAP proxy access,
+#	which allow a POP client to access mail on an IMAP server by using the
+#	POP server as a go-between.  Setting this option disables this
+#	facility.
+#
+# -DOLDFILESUFFIX=\"xxx\"
+#	Change the default suffix appended to the backup .newsrc file from
+#	"old".
+#
+# -DSTRICT_RFC822_TIMEZONES
+#	Disable recognition of the non-standard UTC (0000), MET (+0100),
+#	EET (+0200), JST (+0900), ADT (-0300), AST (-0400), YDT (-0800),
+#	YST (-0900), and HST (-1000) symbolic timezones.
+#
+# -DBRITISH_SUMMER_TIME
+#	Enables recognition of non-standard symbolic timezone BST as +0100.
+#
+# -DBERING_STANDARD_TIME
+#	Enables recognition of non-standard symbolic timezone BST as -1100.
+#
+# -DNEWFOUNDLAND_STANDARD_TIME
+#	Enables recognition of non-standard symbolic timezone NST as -0330.
+#
+# -DNOME_STANDARD_TIME
+#	Enables recognition of non-standard symbolic timezone NST as -1100.
+#
+# -DSAMOA_STANDARD_TIME
+#	Enables recognition of non-standard symbolic timezone SST as -1100.
+#				
+# -DY4KBUGFIX
+#	Turn on the Y4K bugfix (yes, that's year 4000).  It isn't well-known,
+#	but century years evenly divisible by 4000 are *not* leap years in the
+#	Gregorian calendar.  A lot of "Y2K compilant" software does not know
+#	about this rule.  Remember to turn this on sometime in the next 2000
+#	years.
+#
+# -DUSEORTHODOXCALENDAR
+#	Use the more accurate Eastern Orthodox calendar instead of the
+#	Gregorian calendar.  The century years which are leap years happen
+#	at alternating 400 and 500 year intervals without shifts every 4000
+#	years.  The Orthodox and Gregorian calendars diverge by 1 day for
+#	gradually-increasing intervals, starting at 2800-2900, and becoming
+#	permanent at 48,300.
+#
+# -DUSEJULIANCALENDAR
+#	Use the less accurate Julian calendar instead of the Gregorian
+#	calendar.  Leap years are every 4 years, including century years.
+#	My apologies to those in the English-speaking world who object to
+#	the reform of September 2, 1752 -> September 14, 1752, since this
+#	code still uses January 1 (which Julius Ceasar decreed as the start
+#	of the year, which since 153 BCE was the day that Roman consuls
+#	took office), rather than the traditional March 25 used by the
+#	British.  As of 2005, the Julian calendar and the Gregorian calendar
+#	diverge by 15 days.
+
+EXTRACFLAGS=
+
+
+# Extra linker flags (additional/alternative libraries, etc.)
+
+EXTRALDFLAGS=
+
+
+# Special make flags (e.g. to override make environment variables)
+
+EXTRASPECIALS=
+SPECIALS=
+
+
+# Normal commands
+
+CAT=cat
+CD=cd
+LN=ln -s
+MAKE=make
+MKDIR=mkdir
+BUILDTYPE=rebuild
+RM=rm -rf
+SH=sh
+SYSTEM=unix
+TOOLS=tools
+TOUCH=touch
+
+
+# Primary build command
+
+BUILD=$(MAKE) build EXTRACFLAGS='$(EXTRACFLAGS)'\
+ EXTRALDFLAGS='$(EXTRALDFLAGS)'\
+ EXTRADRIVERS='$(EXTRADRIVERS)'\
+ EXTRAAUTHENTICATORS='$(EXTRAAUTHENTICATORS)'\
+ PASSWDTYPE=$(PASSWDTYPE) SSLTYPE=$(SSLTYPE) IP=$(IP)\
+ EXTRASPECIALS='$(EXTRASPECIALS)'
+
+
+# Make the IMAP Toolkit
+
+all:	c-client SPECIALS rebuild bundled
+
+c-client:
+	@echo Not processed yet.  In a first-time build, you must specify
+	@echo the system type so that the sources are properly processed.
+	@false
+
+
+SPECIALS:
+	echo $(SPECIALS) > SPECIALS
+
+# Note on SCO you may have to set LN to "ln".
+
+a32 a41 aix bs3 bsi d-g d54 do4 drs epx ga4 gas gh9 ghp ghs go5 gsc gsg gso gul h11 hpp hpx lnp lyn mct mnt nec nto nxt nx3 osf os4 ptx qnx sc5 sco sgi sg6 shp sl4 sl5 slx snx soc sol sos uw2: an
+	$(BUILD) BUILDTYPE=$@
+
+# If you use sv4, you may find that it works to move it to use the an process.
+# If so, you probably will want to delete the "-Dconst=" from the sv4 CFLAGS in
+# the c-client Makefile.
+
+aos art asv aux bsd cvx dpx dyn isc pyr sv4 ult vul vu2: ua
+	$(BUILD) BUILDTYPE=$@
+
+
+# Knotheads moved Kerberos and SSL locations on these platforms
+
+# Paul Vixie claims that all FreeBSD versions have working IPv6
+
+bsf:	an
+	$(TOUCH) ip6
+	$(BUILD) BUILDTYPE=$@ IP=$(IP6) \
+	PASSWDTYPE=pam \
+	SPECIALS="SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib SSLCERTS=/etc/ssl/certs SSLKEYS=/etc/ssl/private GSSINCLUDE=/usr/include GSSLIB=/usr/lib PAMLDFLAGS=-lpam"
+
+# I assume that Theo did the right thing for IPv6.  OpenBSD does not have PAM.
+
+bso:	an
+	$(TOUCH) ip6
+	$(BUILD) BUILDTYPE=$@ IP=$(IP6) \
+	SPECIALS="SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib SSLCERTS=/etc/ssl SSLKEYS=/etc/ssl/private GSSINCLUDE=/usr/include GSSLIB=/usr/lib"
+
+# Info from Joel Reicher about NetBSD SSL paths.  I assume it has PAM because pam is in NetBSD sources...
+
+neb:	an
+	$(TOUCH) ip6
+	$(BUILD) BUILDTYPE=$@ IP=$(IP6) \
+	PASSWDTYPE=pam \
+	SPECIALS="SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib SSLCERTS=/etc/openssl/certs SSLKEYS=/etc/openssl/private GSSINCLUDE=/usr/include GSSLIB=/usr/lib PAMLDFLAGS=-lpam"
+
+cyg:	an
+	$(BUILD) BUILDTYPE=cyg \
+	SPECIALS="SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib SSLCERTS=/usr/ssl/certs SSLKEYS=/usr/ssl/certs"
+
+gcs:	an
+	$(BUILD) BUILDTYPE=gso \
+	SPECIALS="SSLINCLUDE=/opt/csw/include/openssl SSLLIB=/opt/csw/lib SSLCERTS=/opt/csw/ssl/certs SSLKEYS=/opt/csw/ssl/certs"
+
+ldb:	an
+	$(BUILD) BUILDTYPE=lnp IP=$(IP6) \
+	SPECIALS="SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib SSLCERTS=/etc/ssl/certs SSLKEYS=/etc/ssl/private GSSINCLUDE=/usr/include GSSLIB=/usr/lib MAILSPOOL=/var/mail"
+
+lfd:	an
+	$(BUILD) BUILDTYPE=lnp IP=$(IP6) \
+	SPECIALS="SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib SSLCERTS=/etc/pki/tls/certs SSLKEYS=/etc/pki/tls/private GSSDIR=/usr/kerberos"
+
+ln8:	an
+	$(TOUCH) ip6
+	$(BUILD) BUILDTYPE=slx IP=$(IP6) \
+	SPECIALS="SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib SSLCERTS=/usr/lib/ssl/certs MAILSPOOL=/var/mail"
+
+
+# RHE5 does not have the IPv6 bug
+
+lr5:	an
+	$(TOUCH) ip6
+	$(BUILD) BUILDTYPE=lnp IP=$(IP6) \
+	SPECIALS="SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib SSLCERTS=/etc/pki/tls/certs SSLKEYS=/etc/pki/tls/private GSSDIR=/usr/kerberos"
+
+lmd:	an
+	$(BUILD) BUILDTYPE=lnp IP=$(IP6) \
+	SPECIALS="SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib SSLCERTS=/usr/lib/ssl/certs SSLKEYS=/usr/lib/ssl/private GSSINCLUDE=/usr/include GSSLIB=/usr/lib"
+
+# RHE3 definitely has the IPv6 bug
+
+lrh:	lrhok an
+	$(BUILD) BUILDTYPE=lnp IP=$(IP6) \
+	SPECIALS="SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib SSLCERTS=/usr/share/ssl/certs SSLKEYS=/usr/share/ssl/private GSSDIR=/usr/kerberos"
+
+lrhok:
+	@$(SH) -c '(test ! -d /etc/pki/tls ) || make lrhwarn'
+	@$(TOUCH) lrhok
+
+lrhwarn:
+	@echo You are building for OLD versions of RedHat Linux.  This build
+	@echo is NOT suitable for RedHat Enterprise 5, which stores SSL/TLS
+	@echo certificates and keys in /etc/pki/tls rather than /usr/share/ssl.
+	@echo If you want to build for modern RedHat Linux, you should use
+	@echo make lr5 instead.
+	@echo Do you want to continue this build?  Type y or n please:
+	@$(SH) -c 'read x; case "$$x" in y) exit 0;; *) exit 1;; esac'
+	@echo OK, I will remember that you really want to build for old
+	@echo RedHat Linux.  You will not see this message again.
+	@echo If you realize that you really wanted to build for modern
+	@echo RedHat Linux, then do the following commands:
+	@echo % rm lrhok
+	@echo % make clean
+	@echo % make lr5
+
+lsu:	an
+	$(BUILD) BUILDTYPE=lnp IP=$(IP6) \
+	SPECIALS="SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib SSLCERTS=/usr/share/ssl/certs SSLKEYS=/usr/share/ssl/private GSSDIR=/usr/kerberos"
+
+# iToy does not have Kerberos or PAM.  It doesn't have a
+# /System/Library/OpenSSL directory either, but the libcrypto shared library
+# has these locations so this is what we will use.
+
+osi:	an
+	$(TOUCH) ip6
+	$(BUILD) BUILDTYPE=osx IP=$(IP6) CC=arm-apple-darwin-gcc \
+	SPECIALS="SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib SSLCERTS=/System/Library/OpenSSL/certs SSLKEYS=/System/Library/OpenSSL/private"
+
+oxp:	an
+	$(TOUCH) ip6
+	$(BUILD) BUILDTYPE=osx IP=$(IP6) EXTRAAUTHENTICATORS="$(EXTRAAUTHENTICATORS) gss" \
+	PASSWDTYPE=pam \
+	EXTRACFLAGS="$(EXTRACFLAGS) -DMAC_OSX_KLUDGE=1" \
+	SPECIALS="SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib SSLCERTS=/System/Library/OpenSSL/certs SSLKEYS=/System/Library/OpenSSL/private GSSINCLUDE=/usr/include GSSLIB=/usr/lib PAMDLFLAGS=-lpam"
+
+osx:	osxok an
+	$(TOUCH) ip6
+	$(BUILD) BUILDTYPE=$@ IP=$(IP6) EXTRAAUTHENTICATORS="$(EXTRAAUTHENTICATORS) gss" \
+	SPECIALS="SSLINCLUDE=/usr/include/openssl SSLLIB=/usr/lib SSLCERTS=/System/Library/OpenSSL/certs SSLKEYS=/System/Library/OpenSSL/private GSSINCLUDE=/usr/include GSSLIB=/usr/lib"
+
+osxok:
+	@$(SH) -c '(test ! -f /usr/include/pam/pam_appl.h ) || make osxwarn'
+	@$(TOUCH) osxok
+
+osxwarn:
+	@echo You are building for OLD versions of Mac OS X.  This build is
+	@echo NOT suitable for modern versions of Mac OS X, such as Tiger,
+	@echo which use PAM-based authentication.  If you want to build for
+	@echo modern Mac OS X, you should use make oxp instead.
+	@echo Do you want to continue this build?  Type y or n please:
+	@$(SH) -c 'read x; case "$$x" in y) exit 0;; *) exit 1;; esac'
+	@echo OK, I will remember that you really want to build for old
+	@echo Mac OS X.  You will not see this message again.
+	@echo If you realize that you really wanted to build for modern
+	@echo Mac OS X, then do the following commands:
+	@echo % rm osxok
+	@echo % make clean
+	@echo % make oxp
+
+
+# Linux shadow password support doesn't build on traditional systems, but most
+# Linux systems are shadow these days.
+
+lnx:	lnxnul an
+	$(BUILD) BUILDTYPE=$@
+
+lnxnul:
+	@$(SH) -c '(test $(PASSWDTYPE) = nul) || make lnxok'
+
+lnxok:
+	@echo You are building for traditional Linux.  Most modern Linux
+	@echo systems require that you build using make slx.
+	@echo Do you want to continue this build?  Type y or n please:
+	@$(SH) -c 'read x; case "$$x" in y) exit 0;; *) exit 1;; esac'
+	@echo OK, I will remember that you really want to build for
+	@echo traditional Linux.  You will not see this message again.
+	@echo If you discover that you can not log in to the POP and IMAP
+	@echo servers, then do the following commands:
+	@echo % rm lnxok
+	@echo % make clean
+	@echo % make slx
+	@echo If slx does not work, try sl4 or sl5.  Be sure to do a
+	@echo make clean between each try!
+	@$(TOUCH) lnxok
+
+
+# SUN-OS C compiler makes you load libdl by hand...
+
+ssn sun: sunok suntools ua
+	$(BUILD) BUILDTYPE=$@
+
+suntools:
+	$(CD) tools;$(MAKE) LDFLAGS=-ldl
+
+gsu:	sunok an
+	$(BUILD) BUILDTYPE=$@
+
+s40:	sunok ua
+	$(BUILD) BUILDTYPE=$@
+
+sunok:
+	@echo You are building for the old BSD-based SUN-OS.  This is NOT
+	@echo the modern SVR4-based Solaris.  If you want to build for
+	@echo Solaris, you should use make gso or make sol or make soc.  Do
+	@echo you want to continue this build?  Type y or n please:
+	@$(SH) -c 'read x; case "$$x" in y) exit 0;; *) exit 1;; esac'
+	@echo OK, I will remember that you really want to build for the old
+	@echo BSD-based SUN-OS.  You will not see this message again.
+	@echo If the build fails and you realize that you really wanted to
+	@echo build for Solaris, then do the following commands:
+	@echo % rm sunok
+	@echo % make clean
+	@echo % make gso
+	@echo If gso does not work, try sol.  Be sure to do a make clean
+	@echo between each try!
+	@$(TOUCH) sunok
+
+
+# SVR2 doesn't have symbolic links (at least my SVR2 system doesn't)
+
+sv2:
+	$(MAKE) ua LN=ln
+	$(BUILD) BUILDTYPE=$@ LN=ln
+
+# Hard links don't quite work right in SUA, and there don't seem to be any
+# SSL includes.  However, IPv6 works.
+
+sua:
+	$(TOUCH) ip6 sslnone
+	$(MAKE) an LN=cp SSLTYPE=none
+	$(BUILD) BUILDTYPE=$@ LN=cp IP=$(IP6) SSLTYPE=none
+
+
+# Pine port names, not distinguished in c-client
+
+bs2:	an
+	$(BUILD) BUILDTYPE=bsi
+
+pt1:	an
+	$(BUILD) BUILDTYPE=ptx
+
+
+# Compatibility
+
+hxd:
+	$(BUILD) BUILDTYPE=hpx PASSWDTYPE=dce
+
+# Amiga
+
+ami am2 ama amn:
+	$(MAKE) an LN=cp SYSTEM=amiga
+	$(BUILD) BUILDTYPE=$@ LN=cp
+
+
+# Courtesy entries for Microsoft systems
+
+nt:
+	nmake /nologo /f makefile.nt
+
+ntk:
+	nmake /nologo /f makefile.ntk
+
+w2k:
+	nmake /nologo /f makefile.w2k
+
+wce:
+	nmake /nologo /f makefile.wce
+
+
+# SSL build choices
+
+sslnopwd sslunix.nopwd sslsco.nopwd:
+	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+	@echo + Building in full compliance with RFC 3501 security
+	@echo + requirements:
+	@echo ++ TLS/SSL encryption is supported
+	@echo ++ Unencrypted plaintext passwords are prohibited
+	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+sslunix sslsco:
+	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+	@echo + Building in PARTIAL compliance with RFC 3501 security
+	@echo + requirements:
+	@echo + Compliant:
+	@echo ++ TLS/SSL encryption is supported
+	@echo + Non-compliant:
+	@echo ++ Unencrypted plaintext passwords are permitted
+	@echo +
+	@echo + In order to rectify this problem, you MUST build with:
+	@echo ++ SSLTYPE=$(SSLTYPE).nopwd
+	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+	@echo
+	@echo Do you want to continue this build anyway?  Type y or n please:
+	@$(SH) -c 'read x; case "$$x" in y) exit 0;; *) (make nounenc;exit 1);; esac'
+
+nounenc:
+	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+	@echo + At your request, this build with unencrypted authentication has
+	@echo + been CANCELLED.
+	@echo + You must start over with a new make command.
+	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+
+sslnone:
+	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+	@echo + Building in NON-COMPLIANCE with RFC 3501 security requirements:
+	@echo + Non-compliant:
+	@echo ++ TLS/SSL encryption is NOT supported
+	@echo ++ Unencrypted plaintext passwords are permitted
+	@echo +
+	@echo + In order to rectify this problem, you MUST build with:
+	@echo ++ SSLTYPE=nopwd
+	@echo + You must also have OpenSSL or equivalent installed.
+	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+	@echo
+	@echo Do you want to continue this build anyway?  Type y or n please:
+	@$(SH) -c 'read x; case "$$x" in y) exit 0;; *) (make nonossl;exit 1);; esac'
+
+nonossl:
+	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+	@echo + At your request, this build with no TLS/SSL support has been
+	@echo + CANCELLED.
+	@echo + You must start over with a new make command.
+	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+
+# IP build choices
+
+ip4:
+	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+	@echo + Building with IPv4 support
+	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+ip6:
+	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+	@echo + Building with IPv6 support
+	@echo +
+	@echo + NOTE: Some versions of glibc have a bug in the getaddrinfo
+	@echo + call which does DNS name resolution.  This bug causes host
+	@echo + names to be canonicalized incorrectly, as well as doing an
+	@echo + unnecessary and performance-sapping reverse DNS call.  This
+	@echo + problem does not affect the IPv4 gethostbyname call.
+	@echo +
+	@echo + getaddrinfo works properly on Mac OS X and Windows.  However,
+	@echo + the problem has been observed on some Linux systems.
+	@echo +
+	@echo + If you answer n to the following question the build will be
+	@echo + cancelled and you must rebuild.  If you did not specify IPv6
+	@echo + yourself, try adding IP6=4 to the make command line.
+	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+	@echo
+	@echo Do you want to build with IPv6 anyway?  Type y or n please:
+	@$(SH) -c 'read x; case "$$x" in y) exit 0;; *) (make noip6;exit 1);; esac'
+	@echo OK, I will remember that you really want to build with IPv6.
+	@echo You will not see this message again.
+	@$(TOUCH) ip6
+
+noip6:
+	$(MAKE) clean
+	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+	@echo + At your request, this build with IPv6 has been CANCELLED.
+	@echo + You must start over with a new make command.
+	@echo +
+	@echo + If you wish to rebuild without IPv6 support, do one of the
+	@echo + following:
+	@echo +
+	@echo + 1. If you specified IP=6 on the make command line, omit it.
+	@echo +
+	@echo + 2. Some of the Linux builds automatically select IPv6.  If
+	@echo + you choose one of those builds, add IP6=4 to the make command
+	@echo + line.  Note that this is IP6=4, not IP=4.
+	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+# C compiler types
+
+an ua:
+	@$(MAKE) ssl$(SSLTYPE)
+	@echo Applying $@ process to sources...
+	$(TOOLS)/$@ "$(LN)" src/c-client c-client
+	$(TOOLS)/$@ "$(LN)" src/ansilib c-client
+	$(TOOLS)/$@ "$(LN)" src/charset c-client
+	$(TOOLS)/$@ "$(LN)" src/osdep/$(SYSTEM) c-client
+	$(TOOLS)/$@ "$(LN)" src/mtest mtest
+	$(TOOLS)/$@ "$(LN)" src/ipopd ipopd
+	$(TOOLS)/$@ "$(LN)" src/imapd imapd
+	$(TOOLS)/$@ "$(LN)" src/mailutil mailutil
+	$(TOOLS)/$@ "$(LN)" src/mlock mlock
+	$(TOOLS)/$@ "$(LN)" src/dmail dmail
+	$(TOOLS)/$@ "$(LN)" src/tmail tmail
+	$(LN) $(TOOLS)/$@ .
+
+build:	OSTYPE rebuild rebuildclean bundled
+
+OSTYPE:
+	@$(MAKE) ip$(IP)
+	@echo Building c-client for $(BUILDTYPE)...
+	@$(TOUCH) SPECIALS
+	echo `$(CAT) SPECIALS` $(EXTRASPECIALS) > c-client/SPECIALS
+	$(CD) c-client;$(MAKE) $(BUILDTYPE) EXTRACFLAGS='$(EXTRACFLAGS)'\
+	 EXTRALDFLAGS='$(EXTRALDFLAGS)'\
+	 EXTRADRIVERS='$(EXTRADRIVERS)'\
+	 EXTRAAUTHENTICATORS='$(EXTRAAUTHENTICATORS)'\
+	 PASSWDTYPE=$(PASSWDTYPE) SSLTYPE=$(SSLTYPE) IP=$(IP)\
+	 $(SPECIALS) $(EXTRASPECIALS)
+	echo $(BUILDTYPE) > OSTYPE
+	$(TOUCH) rebuild
+
+rebuild:
+	@$(SH) -c '(test $(BUILDTYPE) = rebuild -o $(BUILDTYPE) = `$(CAT) OSTYPE`) || (echo Already built for `$(CAT) OSTYPE` -- you must do \"make clean\" first && exit 1)'
+	@echo Rebuilding c-client for `$(CAT) OSTYPE`...
+	@$(TOUCH) SPECIALS
+	$(CD) c-client;$(MAKE) all CC=`$(CAT) CCTYPE` \
+	 CFLAGS="`$(CAT) CFLAGS`" `$(CAT) SPECIALS`
+
+rebuildclean:
+	$(SH) -c '$(RM) rebuild || true'
+
+bundled:
+	@echo Building bundled tools...
+	$(CD) mtest;$(MAKE)
+	$(CD) ipopd;$(MAKE)
+	$(CD) imapd;$(MAKE)
+	$(CD) mailutil;$(MAKE)
+	@$(SH) -c '(test -f /usr/include/sysexits.h ) || make sysexitwarn'
+	$(CD) mlock;$(MAKE) || true
+	$(CD) dmail;$(MAKE) || true
+	$(CD) tmail;$(MAKE) || true
+
+
+sysexitwarn:
+	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+	@echo + Hmm...it does not look like /usr/include/sysexits.h exists.
+	@echo + Either your system is too ancient to have the sysexits.h
+	@echo + include, or your C compiler gets it from some other location
+	@echo + than /usr/include.  If your system is too old to have the
+	@echo + sysexits.h include, you will not be able to build the
+	@echo + following programs.
+	@echo +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+clean:
+	@echo Removing old processed sources and binaries...
+	$(SH) -c '$(RM) an ua OSTYPE SPECIALS c-client mtest imapd ipopd mailutil mlock dmail tmail || true'
+	$(CD) tools;$(MAKE) clean
+
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo not war?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NOTICE	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,17 @@
+UW IMAP toolkit notices:
+
+This software was developed by the University of Washington
+(http://www.washington.edu/).
+
+The Univerity of Washington IMAP Toolkit (c-client API, dmail, imapd,
+ipop2d, ipop3d, mailutil, mlock, mtest, and tmail software; and its
+included text) is Copyright 1988-2007 by the University of Washington.
+
+The c-client library and mtest software are in part based upon code
+developed by Mark Crispin at Stanford University, and is
+
+ * Copyright 1988 Stanford University and was developed in the
+ * Symbolic Systems Resources Group of the Knowledge Systems Laboratory
+ * at Stanford University in 1987-88, and was funded by the
+ * Biomedical Research Technology Program of the National Institutes of
+ * Health under grant number RR-00785.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,74 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+			   IMAP Toolkit Environment
+			         4 April 2007
+				 Mark Crispin
+
+
+			    UNIX QUICK BUILD NOTES
+
+These quick build notes assume that you have installed OpenSSL before
+attempting to build this software, and that you do not have any non-default
+configuration parameters.
+
+If you need additional information in building this software with OpenSSL,
+please refer to the docs/SSLBUILD file for more information.
+
+If you intend to build this software with a non-default configuration
+(including building a non-compliant server without SSL support), please
+refer to the docs/BUILD file for more information.
+
+1) Look in the top-level Makefile and find your system type code.  For example,
+   modern versions of Linux will use either "slx", "lnp", or one of the
+   lnp-variants (such as "lrh").
+
+2) Type "make" followed by the system type, e.g. "make slx".
+
+3) Install the POP2 daemon (ipopd/ipop2d), the POP3 daemon (ipopd/ipop3d), and
+   the IMAP daemon (imapd/imapd) on a system directory of your choosing.
+
+4) Update /etc/services to register the pop2 service on TCP port 109, the
+   pop3 service on TCP port 110, and the imap service on TCP port 143.  Also
+   update Yellow Pages/NIS/NetInfo/etc. if appropriate on your system.
+
+5) Update /etc/inetd.conf (or install files on /etc/xinetd.d) to invoke the
+   POP2, POP3, and IMAP daemons on their associated services.
+
+6) If your system uses PAM authentication, be sure to set up /etc/pam.d/imap
+   (*not* /etc/pam.d/imapd) and /etc/pam.d/pop (*not* /etc/pam.d/ipop3d or
+   /etc/pam.d/pop3d or /etc/pam.d/popd or /etc/pam.d/pop3).
+
+7) Unless you built your system without SSL support, you will need to set
+   up SSL server certificates as described in docs/SSLBUILD.
+
+6) That's all!
+
+Read the file docs/BUILD and docs/SSLBUILD if you need more detailed
+information and/or you don't understand these quick build instructions.
+
+			     MISCELLANEOUS NOTES
+
+     mtest has been run under UNIX, DOS, Windows, NT, Macintosh, TOPS-20, and
+VMS.  It is a very primitive interface, however, and is suited mainly as a
+model of how to write a main program for c-client.  You should take a look at
+the source to figure out how to use it.  Briefly, it first asks for a mailbox
+name (either a local file path or an IMAP mailbox in the form
+"{hostname}mailbox") and then puts you in a command mode where "?" will give
+you a list of commands.
+
+     Pine is available separately on the FTP.CAC.Washington.EDU archives.
+
+     The focus of development and support is for UNIX and Win32 (including
+Windows 95/98/Millenium, Windows NT, and Windows 2000).  The other ports are
+not frequently used or tested, and may be incomplete.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SUPPORT	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,22 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+			     BUG REPORTING ADDRESS
+
+     Bug reports, comments, or questions regarding this software may
+be reported to the imap-uw@u.washington.edu mailing list (this replaces
+the old c-client@u.washington.edu mailing list).  You can subscribe to
+this list by sending a message to:
+	imap-uw-subscribe@mailman.u.washington.edu
+
+     An alternative is to use the comp.mail.imap newsgroup.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/BUILD	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,491 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+			 BUILD AND INSTALLATION NOTES
+			 Last Updated: 15 November 2007
+
+Table of Contents:
+1. UNIX Build Notes
+2. UNIX Installation Notes
+3. Win32 Build Notes
+4. Win32 Installation Notes
+5. Inactive Ports (TOPS-20, VMS)
+6. Other ports (Macintosh, DOS/Win16, Windows CE, Amiga, OS/2)
+
+
+			       UNIX BUILD NOTES
+
+     The default build on many systems with IPv4 only.  To build with IPv6,
+add "IP=6" to the make command line, e.g.
+	make lnp IP=6
+
+     The default build is to build with SSL and disabling plaintext passwords
+unless SSL/TLS encryption is in effect (SSLTYPE=nopwd).  This means that
+OpenSSL MUST be installed before building the IMAP toolkit.  Please refer to
+the SSLBUILD file for more information.
+
+     To build without SSL, add "SSLTYPE=none" to the make command line.
+Note that doing so will produce an IMAP server which is NON-COMPLIANT with
+RFC 3501.
+
+     You must build through the top-level imap-2007/Makefile, which will run
+a "process" step the first time and create the imap-2007/c-client,
+imap-2007/ipopd, and imap-2007/imapd directories in which building actually
+takes place.
+
+     Before doing a make on UNIX, you should read imap-2007/Makefile and see
+if your system type is known.  The various system types are three-letter codes.
+If your system type is known, then use this as the make option.  After the
+first time you do a make, this option is remembered in a file called OSTYPE,
+so just typing "make" suffices.
+
+     For example, if you are using a more or less modern Linux system, your
+system type is probably one of the specific distribution types (such as lrh for
+RedHat).  For more generic builds, try slx (shadow passwords only) or lnp (PAM).
+To build for RedHat, do:
+	make lrh
+
+     There are other make options, described in imap-2007/src/osdep/Makefile.
+
+     It's probably best to see if an existing port will work on your system
+before inventing a new port.  Try:
+	sv4		generic SVR4, non-ANSI compiler
+	a32		modern SVR4
+	bsd		basic 4.3 BSD, non-ANSI compiler
+	bsf		modern BSD
+
+     If you must invent a new port, you need to create an entry in
+imap-2007/Makefile and imap-2007/src/osdep/Makefile for your new port, as
+well as osdep/os_???.h and osdep/os_???.c files with the appropriate
+OS-dependent support for that system.  You also need to determine which setup
+process to use.  You should use the ua process unless you are sure that your
+compiler supports *ALL* aspects of ANSI C prototyping.  Note that some
+compilers, such as Ultrix, support some aspects of ANSI C but not others;
+c-client really beats on the full prototyping capability of ANSI C so you
+have to use the non-ANSI source tree for such systems.
+
+     If you send a new port back to us, we will make it available for others
+who use your particular system type.
+
+     The mbox driver is now enabled by default.  If the file "mbox" exists on
+the user's home directory and is in UNIX mailbox format, then when INBOX is
+opened this file will be selected as INBOX instead of the mail spool file.
+Messages will be automatically transferred from the mail spool file into the
+mbox file.  To disable this behavior, delete "mbox" from the EXTRADRIVERS list
+in the top-level Makefile and rebuild.
+
+     WARNING: The SVR2 (sv2) port is *incomplete*.  SVR2 does not appear to
+have any way to do ftruncate(), which is needed by the mbox, mbx, mmdf, mtx,
+tenex, and unix drivers.
+
+			   UNIX INSTALLATION NOTES
+
+     Binaries from the build are:
+	imap-2007/mtest/mtest		c-client testbed program
+	imap-2007/ipopd/ipop2d		POP2 daemon
+	imap-2007/ipopd/ipop3d		POP3 daemon
+	imap-2007/imapd/imapd		IMAP4rev1 daemon
+
+     mtest is normally not used except by c-client developers.
+
+STEP 1:	[x]inetd setup
+
+     The ipop2d, ipop3d, and imapd daemons should be installed in a system
+daemon directory and invoked by a listener such as xinetd or inetd.  In the
+following examples, /usr/local/etc is used).
+
+STEP 1(A): xinetd-specific setup
+
+     If your system uses xinetd, the daemons are invoked by files in your
+/etc/xinetd.d directory with names corresponding to the service names (that
+is: imap, pop2, pop3).  You will need to consult your local xinetd
+documentation to see what should go into these files.  Here is a a sample
+/etc/xinetd.d/imap file:
+
+service imap
+{
+	disable		= no
+	socket_type	= stream
+	wait		= no
+	user		= root
+	server		= /usr/local/etc/imapd
+	groups		= yes
+	flags		= REUSE IPv6
+}
+
+STEP 1(B): inetd-specific setup
+
+     If your system still uses inetd, the daemons are invoked by your
+/etc/inetd.conf file with lines such as:
+
+pop	stream	tcp	nowait	root	/usr/local/etc/ipop2d	ipop2d
+pop3	stream	tcp	nowait	root	/usr/local/etc/ipop3d	ipop3d
+imap	stream	tcp	nowait	root	/usr/local/etc/imapd	imapd
+
+     Note that different variants of UNIX have different versions of inetd,
+so you should verify the precise form of these commands (for example, some
+versions of inetd do not require the "nowait").
+
+     IMPORTANT NOTE: inetd has a limit of how many new connections it will
+allow in a certain interval, and when this limit is exceeded, it shuts down
+the server.  If you have anything beyond a small-scale server, you are
+probably going to run up against this limit.  You'll know when it happens;
+your syslog will give the misleading message "imap/tcp server failing
+(looping), service terminated" and users will complain that IMAP service is
+unavailable for the next 10 minutes.  Similarly with "pop3/tcp server
+failing"...
+
+     It must be emphasized that this is *NOT* a bug in the IMAP or POP
+servers, nor is it anything that I can "fix".  It is an inetd problem, and
+the only way to fix it is to change inetd's behavior.
+
+     By default, the parameters of this limit are (from inetd.c source code):
+
+#define TOOMANY         40              /* don't start more than TOOMANY */
+#define CNT_INTVL       60              /* servers in CNT_INTVL sec. */
+#define RETRYTIME       (60*10)         /* retry after bind or server fail */
+
+That is, no more than 40 connections (TOOMANY) in 60 seconds (CNT_INTL), and
+if exceeded, shut down the server for 10 minutes (RETRYTIME).  This was a
+good setting in the 1980s ARPAnet, but is much too small today.
+
+     Some versions of inetd allow you to see a higher maximum in the
+/etc/inetd.conf file.  Read "man inetd" and see if you see something like
+this in the text:
+
+     The wait/nowait entry is applicable to datagram sockets only [...]
+     [...]  The optional ``max'' suffix (separated from
+     ``wait'' or ``nowait'' by a dot) specifies the maximum number of server
+     instances that may be spawned from inetd within an interval of 60 sec-
+     onds. When omitted, ``max'' defaults to 40.
+
+If you see this, then edit the /etc/inetd.conf entry for imapd to be
+something like:
+
+imap	stream	tcp	nowait.100	root	/usr/local/etc/imapd	imapd
+ (or, if you use TCP wrappers)
+imap	stream	tcp	nowait.100	root	/usr/local/etc/tcpd	imapd
+
+     Otherwise, you'll need to edit the inetd source code to set TOOMANY to a
+higher value, then rebuild inetd.
+
+
+STEP 2:	services setup
+
+     You may also have to edit your /etc/services (or Yellow Pages,
+NetInfo, etc. equivalent) to register these services, such as:
+
+pop		109/tcp
+pop3		110/tcp
+imap		143/tcp
+
+
+STEP 3: PAM setup
+
+     If your system has PAM (Pluggable Authentication Modules -- most
+modern systems do) then you need to set up PAM authenticators for imap and
+pop.  The correct file names are
+	/etc/pam.d/imap
+and
+	/etc/pam.d/pop
+
+     It probably works to copy your /etc/pam.d/ftpd file to the above two
+names.
+
+     Many people get these file names wrong, and then spend a lot of time
+trying to figure out why it doesn't work.  Common mistakes are:
+	/etc/pam.d/imapd
+	/etc/pam.d/imap4
+	/etc/pam.d/imap4rev1
+	/etc/pam.d/ipop3d
+	/etc/pam.d/pop3d
+	/etc/pam.d/popd
+	/etc/pam.d/pop3
+
+
+STEP 4:	optional rimap setup
+
+     If you want to enable the rimap capability, which allows users with a
+suitable client and .rhosts file on the server to access IMAP services
+without transmitting her password in the clear over the network, you need
+to have /etc/rimapd as a link to the real copy of imapd.  Assuming you have
+imapd installed on /usr/local/etc as above:
+	% ln -s /usr/local/etc/imapd /etc/rimapd
+
+     Technical note: rimap works by having the client routine tcp_aopen()
+invoke `rsh _host_ exec /etc/rimapd' in an child process, and then returning
+pipes to that process' standard I/O instead of a TCP socket.  You can set up
+`e-mail only accounts' by making the shell be something which accepts only
+that string and not ordinary UNIX shell commands.
+
+
+STEP 4:	notes on privileges
+
+     Neither user "root", not any other UID 0 account, can log in via IMAP or
+POP.  "That's not a bug, it's a feature!"
+
+     This software is designed to run without privileges.  The mail spool
+directory must be protected 1777; that is, with world write and the sticky
+bit.  Of course, mail *files* should be protected 600!
+
+     An alternative to having the mail spool directory protected 1777, at the
+cost of some performance, is to use the external "mlock" program, available
+as part of the imap-utils package.  With mlock installed as /etc/mlock and
+setgid mail, the spool directory can be protected 775 with group mail.
+Please disregard this paragraph if you don't understand it COMPLETELY, and
+know EXACTLY what to do without question.
+
+
+STEP 5:	SVR4 specific setup
+
+     There is one "gotcha" on System V Release 4 based systems such as
+Solaris.  These systems do not use the standard UNIX mail format, but rather a
+variant of that format that depends upon a bogus "Content-Length:" message
+header.  This is widely recognized to have been a terrible mistake.  One
+symptom of the problem is that under certain circumstances, a message may get
+broken up into several messages.  I'm also aware of security bugs caused by
+programs that foolishly trust "Content-Length:" headers with evil values.
+
+    To fix your system, edit your sendmail.cf to change the Mlocal line to
+have the -E flag.  A typical entry will lool like:
+
+Mlocal, P=/usr/lib/mail.local, F=flsSDFMmnPE, S=10, R=20, A=mail.local -d $u
+
+			      WIN32 BUILD NOTES
+
+     Visual C++ 6.0 along with the current Microsoft Platform SDK
+(specifically the CORE SDK and the Internet Development SDK) is required
+to build on Windows 9x/Me/NT/2K/XP.  If you do not have the Platform SDK
+installed or in your path properly, you'll get errors when building os_nt.c,
+typically in env_nt.c, ssl_nt.c, ssl_w2k.c, or gss_shim.c.  You can download
+the Microsoft Platform SDK from Microsoft's web site.
+
+     There is also considerable debate about how new mail is to be snarfed.
+I am currently using something that seems to work with WinSMTP.  Look at
+the definition of MAILFILE in imap-2007/src/osdep/nt/mailfile.h and at the
+sysinbox() function in imap-2007/src/osdep/nt/env_nt.c to see what's there
+now, so you have a clue about how to hack it.
+
+     To build under Windows 95/98/NT, connect to the imap-2007 directory
+and do:
+	nmake -f makefile.nt
+The resulting binaries will support SSL if either schannel.dll or
+security.dll is installed in Windows, using the old, undocumented, SSL
+interfaces.  You can also use this to build under Me/2000/XP, but it is
+not the preferred build on this platform.
+
+     To build with MIT Kerberos support, connect to the imap-2007 directory
+and do:
+	nmake -f makefile.ntk
+The resulting binaries will support SSL if either schannel.dll or
+security.dll is installed in Windows, using the old, undocumented SSL
+interfaces.  They will also support MIT Kerberos.  Note, however, that
+these binaries will only run on systems which have the MIT Kerberos DLLs
+installed, and will not run otherwise.
+
+     To build under Windows Me/2000/XP, connect to the imap-2007 directory
+and do:
+	nmake -f makefile.w2k
+The resulting binaries will support SSL and Microsoft Kerberos, using the
+official, documented, Microsoft interfaces.  Note, however, that these
+binaries will not run under Windows 95, Windows 98, or Windows NT4.
+
+			   WIN32 INSTALLATION NOTES
+
+     The resulting binaries will be:
+	imap-2007\mtest\mtest.exe	(testbed client)
+	imap-2007\ipopd\ipop2d.exe	POP2 server
+	imap-2007\ipopd\ipop3d.exe	POP3 server
+	imap-2007\imapd\imapd.exe	IMAP4rev1 server
+
+     These servers are stdio servers.  I wrote a simple network listener
+for NT called inetlisn; currently it is available as:
+	ftp://ftp.cac.washington.edu/mail/nt/inetlisn.tar
+To build this, use "nmake" after connecting to the inetlisn directory.
+inetlisn takes two arguments, the first being the port number and the second
+being the binary to run to serve a connection on that port, e.g.
+	c:\bin\inetlisn 143 c:\mail_daemons\imapd
+
+     Note that NT imapd must be started as SYSTEM in order to be recognized as
+being "not logged in"; otherwise it will preauth as whatever user it is
+running as which is probably not what you want.  One way to have it run as
+system is to have inetlisn run by an AT command, e.g. if the time now is
+2:05PM, try something like:
+	AT 14:06 "c:\bin\inetlisn 143 c:\mail_daemons\imapd"
+
+     A more advanced network listener called wsinetd is available on:
+	http://wsinetd.sourceforge.net
+It is based on inetlisn, and essentially is a "completed" version of inetlisn.
+
+     Bottom line: this is not plug-and-play.  If you're not a hacker and/or
+are unwilling to invest the time to do some programming, you probably want to
+buy a commercial server product.
+
+				INACTIVE PORTS
+
+     The TOPS-20 and VMS ports were developed at one time or another, but are
+no longer actively developed.  However, from time to time I test build both
+of these to make sure that they compile without errors and that mtest runs,
+and will continue doing so as long as I have access to systems running these
+operating systems.
+
+
+			     TOPS-20 BUILD NOTES
+
+     I have provided a c-client port for TOPS-20 systems, but you're on your
+own in terms of a nice TOPS-20 like main program.  Maybe someday some nice
+person will try porting Pine to TOPS-20.  This assumes the use of KCC 6, and
+probably will not build with other compilers or older versions of KCC.
+
+     You do not use imap-2007/Makefile under TOPS-20, nor do you build any
+components other than c-client and mtest.  Merge the contents of
+imap-2007/src/c-client, imap-2007/src/charset, imap-2007/src/mtest, and
+imap-2007/src/osdep/tops-20 onto a single directory on TOPS-20 and build from
+that.  The command:
+	DO BUILD.CTL
+will build the sources.  If you don't have MIC, then SUBMIT BUILD.CTL and let
+BATCON execute it.
+
+
+			       VMS BUILD NOTES
+
+      The VMS port has been tested with imap-2007, but as I am soon going
+to lose access to a VMS system I will no longer be able able to test and
+this port will be moved to the "other ports" category".
+
+      You do not use imap-2007/Makefile under VMS, nor do you build any
+components other than c-client and mtest.  Merge the contents of
+imap-2007/src/c-client, imap-2007/src/charset, imap-2007/src/mtest, and
+imap-2007/src/osdep/vms onto a single directory on VMS and build from that.
+The command to build it is:
+	@BUILD MULTINET
+or	@BUILD NETLIB
+If you just do @BUILD it will build with dummy TCP code, and since only TCP
+based drivers are provided here this isn't too useful.
+
+     If you aren't on the Pacific coast of the US or Canada, you probably will
+need to change the wired-in timezone in the BUILD.COM file.  Apparently, the
+wonderful VMS system that DEC loves so much doesn't maintain any concept of
+time zone; the VMS C compiler returns a null pointer from gmtime()!
+
+     Otherwise you're pretty much on your own here.
+
+				 OTHER PORTS
+
+     The following ports were developed at one time or another, but are no
+longer actively developed or tested.  It is not known if they still work or
+not.
+
+  Port		Status
+  ----		------
+Macintosh	Obsolete; Mac OS X uses UNIX port
+DOS/Win16	Obsolete; modern PCs use Win32 port
+Windows CE	Never completed
+Amiga		Unknown
+OS/2		Unknown
+
+			     MACINTOSH BUILD NOTES
+
+     This port is for the old Mac OS system, not Mac OS X.
+
+     If you are building a Macintosh client, you will need MacTCP installed on
+your system as well as the MacTCP C includes and libraries.
+
+     You do not use imap-2007/Makefile on the Mac, nor do you build any
+components other than c-client and mtest.  Merge the contents of
+imap-2007/src/c-client, imap-2007/src/charset, imap-2007/src/mtest, and
+imap-2007/src/osdep/mac onto a single directory on the Mac and build from
+that.  mtext.sit.hqx is a THINK C project file and cute icon for building
+mtest, encoded with Binhex and StuffIt.
+
+     THINK C is a truly wretched product which help make me understand why
+Macintosh has lost most of its market share.  Not only does it do cretinous
+things such as barf about a cast in front of an lvalue, it also limits the size
+of code *or* data in a single file to 32K!  So much for having large character
+set tables.  Symantec says that "MacOS requires it, break up your files into
+smaller pieces" yet somehow gcc under MachTen contrives to compile C programs
+without subjecting the programmer to this idiocy.
+
+     As a result of this, I found myself obliged to comment out the #includes
+of the East Asian character sets in utf8.c in order to get it to build.  It's
+also necessary to break up some of the files, at least mail.c and imap4r1.c.
+Maybe you don't have to do this in CodeWarrior or whatever the new compiler is
+called, but I've pretty much given up on Macintosh.
+
+     If you use precompiled headers, you may get some compilation errors since
+some Apple symbols need to be redefined in order to get it to build under all
+versions of MacOS.  Try turning off the precompiled headers (so it will
+re-read the .h files) and see if it builds any better.
+
+     If you use a Mac C compiler with 2-byte ints (such as THINK C's normal
+mode) you will need to fix some bugs in the MacTCP C includes and libraries to
+prevent it from generating bad code, since those MacTCP files violate Apple's
+standards of always using explicit shorts or longs, never ints.  You could
+avoid this if you set 4-byte ints in THINK C; however, the ANSI and UNIX
+libraries in THINK C use 2-byte ints so you will also need to build 4-byte int
+versions of these.  c-client itself is 2-byte int or 4-byte int clean; it can
+be used in either mode.
+
+     The most important bug in the MacTCP files that you need to fix is in the
+file AddressXlation.h, you need to change the definition of the rtnCode member
+of the hostInfo structure to be long instead of int.  There are several other
+changes you need to make if you decide to compile dnr.c under THINK C instead
+of using the Apple-supplied object file; see me for details if you decide to
+undertake such an effort.  This is fixed in newer versions from Apple.
+
+
+			     DOS/WIN16 BUILD NOTES
+
+     If you are building a DOS client, you will need a TCP/IP stack installed
+on your DOS system along with its development environment.  The currently
+supported stacks are Beame & Whiteside, PC-NFS, Novell, PC/IP, Waterloo, and
+Winsock.  mtest and a version of Pine called PC Pine run under DOS.
+
+      You do not use imap-2007/Makefile under DOS, nor do you build any
+components other than c-client and mtest.  Merge the contents of
+imap-2007/src/c-client, imap-2007/src/charset, imap-2007/src/mtest, and
+imap-2007/src/osdep/dos onto a single directory on DOS and build from that.
+The MAKE command on DOS takes an argument identifying the TCP/IP stack in use.
+For example, do:
+	MAKE MAKEFILE OS=WSK   (or MAKE -F MAKEFILE OS=WSK)
+to build for Winsock.  
+
+     If you write a program for DOS/Win16, you will probably have to write a
+replacement cache manager (look at mm_cache()) and otherwise disable most of
+c-client's caching.  Even so, memory limitations will be an ongoing problem,
+particularly with DOS, and you will have some severe performance problems.
+It's a bit better on Win16, but in my opinion you are better off writing a
+32-bit program and telling your Win16 customers to upgrade to Windows 95 or at
+least install Win32s.
+
+
+			    WINDOWS CE BUILD NOTES
+
+     I build using Visual C++ 6.0 with the WCE extensions.  The current code
+has SH3 wired in for the compiler building.
+
+     To build under NT, connect to the imap-2007 directory and do:
+	nmake -f makefile.wce
+
+     The only binary produced is a cclient.lib file.  I haven't gotten as far
+as building mtest on WCE, mainly because I don't have a stdlib library.
+
+
+		      AMIGA BUILD AND INSTALLATION NOTES
+
+     The Amiga port was contributed.  Maybe the UNIX notes will help.
+
+
+			       OS2 BUILD NOTES
+
+     The OS2 port was contributed.  Maybe the Win32 Build Notes will help.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/CONFIG	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,181 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+		       UNIX Configuration Notes
+
+     The IMAP and POP3 servers are plug-and-play on standard UNIX
+systems.  There is no special configuration needed.  Please ignore all
+rumors to the effect that you need to create an IMAP configuration
+file.
+
+     If your system is non-standard, virtually everything that you are
+likely to want to modify can be found in the source file
+	.../src/osdep/unix/env_unix.c
+In particular, special attention should be given to the routines:
+ env_init()		initialize c-client environment variables,
+			especially the user name and home directory
+ sysinbox()		return the UNIX path of the INBOX in which
+			mail delivery will place mail
+ mailboxdir()		translate a mailbox name into the associated
+			UNIX directory for listing
+ mailboxfile()		translate a mailbox name into the associated
+			UNIX file for opening
+
+     There are also build options in the top-level makefile which you
+can give on the command line when building the software.  The most
+common build options are "SSLTYPE=unix", to build the software with SSL,
+and "SSLTYPE=nopwd", to build the software with SSL and disable plaintext
+authentication unless the session is encrypted.
+
+     You should modify these routines as necessary for local policy.
+The most common modifications are to env_init(), to modify the
+software's idea of the home directory (which is used everywhere as the
+default directory), and to sysinbox(), to modify where the software
+looks for newly-delivered mail.
+
+     Example 1: suppose your mailer delivers mail to file ".mailbox"
+in the user's home directory instead of the default UNIX mail spool
+directory.  You will want to change routine sysinbox(), changing the
+line that reads:
+
+    sprintf (tmp,"%s/%s",MAILSPOOL,myusername ());
+to be:
+    sprintf (tmp,"%s/.mailbox",myhomedir ());
+
+     Example 2: suppose you want to change c-client's idea of the
+user's mailbox directory to be the "mail" subdirectory of the user's
+home directory instead of the user's home directory.  You will want to
+change variable mailsubdir, changing the line that reads:
+
+static char *mailsubdir = NIL;	/* mail subdirectory name */
+ to be:
+static char *mailsubdir = "mail";/* mail subdirectory name */
+
+     Example 3: suppose you want to disable plaintext authentication in
+the IMAP and POP servers.  If you want to disable plaintext authentication
+in unencrypted sessions but permit it in encrypted sessions, you should use
+"SSLTYPE=nopwd" in the make command line when building the software.  For
+example, to do this on a Linux system with PAM authentication, do:
+	make lnp SSLTYPE=nopwd
+If you want to disable plaintext authentication under all circumstances
+(including SSL or TLS encrypted sessions), use "PASSWDTYPE=nul", e.g.:
+	make lnx EXTRAAUTHENTICATORS=gss PASSWDTYPE=nul
+which will make it impossible to log in except via Kerberos.
+
+     Example 4: suppose you want the IMAP and POP servers to do a chroot()
+to the user's home directory.  This is not recommended; there are known
+ways of attacking chroot() based security mechanisms.  Furthermore, if you
+do this you can not use a traditional UNIX format INBOX in the mail spool
+directory, since chroot() will prevent access to that directory.  If you
+really want to do this, you need to change variable closedBox, changing
+the line which reads:
+
+static short closedBox = NIL;	/* is a closed box */
+ to be:
+static short closedBox = T;	/* is a closed box */
+
+     Example 5: suppose you want to disable non-namespace access to the
+filesystem root and other users' names, but do not want to go to the
+extreme of chroot() and you want to allow access to a traditional UNIX
+format INBOX in the mail spool directory.  You need to change variable
+restrictBox, changing the line which reads:
+
+static short restrictBox = NIL;	/* is a restricted box */
+ to be:
+static short restrictBox = -1;	/* is a restricted box */
+
+Other values to set in restrictBox can be found in env_unix.h.
+
+     Ignore all references in env_unix.c to a configuration file; that
+code is for UW-internal use only.  It is extremely unlikely that that
+facility will work usefully for you; it is extremely likely that you
+will shoot yourself in the foot by using; and it frequently changes in
+an incompatible manner.
+
+     There are two other build-time configuration issues which you may
+need to consider: drivers and authenticators.  Both of these are set
+up in the top-level Makefile -- in particular, by the EXTRADRIVERS and
+EXTRAAUTHENTICATORS variables.
+
+     Drivers are code modules that support different mailbox storage
+technologies.  By default, all drivers are enabled.  There is little
+benefit to be gained by disabling a driver, with one exception.  The
+mbox driver implements the behavior of automatically moving new mail
+from the spool directory to the "mbox" file on the user's home
+directory, if and *only* if the "mbox" exists and is in mailbox
+format.  The mbox driver is listed under EXTRADRIVERS; if you wish to
+disable it just remove it from that list and rebuild.
+
+     Authenticators are code modules that support authentication
+technology for the server (password file lookup, Kerberos, S/Key,
+etc.).  EXTRAAUTHENTICATORS is used to add an authenticator.  This
+subject can be complex; find a wizard if you can't figure it out.
+
+     It is also possible to add your own drivers and authenticators.
+This is a topic for wizards, and is beyond the scope of this text.
+
+			NT Configuration Notes
+
+     This software is not plug-and-play on NT.  If you're not a hacker
+and/or are unwilling to invest the time to do some programming, you
+probably want to buy a commercial server for NT.
+
+     The primary issue that you need to deal with is the format of
+mail, where the INBOX is located, and where secondary folders are
+located.  As distributed, the software supports mail in the default
+format used on UNIX (unix format) as well as mbx, mtx, and tenex
+formats.  mbx format is encouraged if at all possible; mtx and tenex
+format are for compatibility with the past.  However, it all depends
+upon how and where your SMTP server delivers mail.
+
+     To change the default mailbox format, edit the symbol
+DEFAULTDRIVER in:
+	../src/osdep/nt/makefile.nt
+or
+	../src/osdep/nt/makefile.ntk
+To change the default location of INBOX, edit the file:
+	../src/osdep/nt/mailfile.h
+Virtually everything else having to do with environment that you are
+likely to want to modify can be found in the source file:
+	.../src/osdep/nt/env_nt.c
+In particular, special attention should be given to the routines:
+ env_init()		initialize c-client environment variables,
+			especially the user name and home directory
+ sysinbox()		return the NT path of the INBOX in which
+			mail delivery will place mail
+ mailboxdir()		translate a mailbox name into the associated
+			NT directory for listing
+ mailboxfile()		translate a mailbox name into the associated
+			NT file for opening
+
+     You should modify these routines as necessary.  The most common
+modifications are to env_init(), to modify the software's idea of the
+home directory (which is used everywhere as the default directory),
+and to sysinbox(), to modify where the software looks for
+newly-delivered mail.
+
+     There are two other build-time configuration issues which you may
+need to consider: drivers and authenticators.  Both of these are set
+up in the top-level Makefile -- in particular, by the EXTRADRIVERS and
+EXTRAAUTHENTICATORS variables.
+
+     Drivers are code modules that support different mailbox storage
+technologies.  By default, all drivers are enabled.  There is little
+benefit to be gained by disabling a driver.
+
+     Authenticators are code modules that support authentication
+technology for the server (password file lookup, Kerberos, S/Key,
+etc.).  EXTRAAUTHENTICATORS is used to add an authenticator.  This
+subject can be complex; find a wizard if you can't figure it out.
+
+     It is also possible to add your own drivers and authenticators.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/FAQ.html	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,4226 @@
+<!--
+ * ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ *
+-->
+
+<!--chtml set title="IMAP Toolkit Frequently Asked Questions"-->
+<!--chtml include "//imap/incs/top.inc"-->
+
+  <h2>Table of Contents</h2>
+
+  <ul>
+    <li>
+      <a href="#general">1. General/Software Feature Questions</a>
+
+      <ul>
+        <li><a href="#1.1">1.1 Can I set up a POP or IMAP server on
+        UNIX/Linux/OSF/etc.?</a></li>
+
+        <li><a href="#1.2">1.2 I am currently using qpopper as my POP3 server
+        on UNIX. Do I need to replace it with ipop3d in order to run
+        imapd?</a></li>
+
+        <li><a href="#1.3">1.3 Can I set up a POP or IMAP server on Windows
+        XP, 2000, NT, Me, 98, or 95?</a></li>
+
+        <li><a href="#1.4">1.4 Can I set up a POP or IMAP server on Windows
+        3.1 or DOS?</a></li>
+
+        <li><a href="#1.5">1.5 Can I set up a POP or IMAP server on
+        Macintosh?</a></li>
+
+        <li><a href="#1.6">1.6 Can I set up a POP or IMAP server on
+        VAX/VMS?</a></li>
+
+        <li><a href="#1.7">1.7 Can I set up a POP or IMAP server on
+        TOPS-20?</a></li>
+
+        <li><a href="#1.8">1.8 Are hierarchical mailboxes supported?</a></li>
+
+        <li><a href="#1.9">1.9 Are "dual-use" mailboxes supported?</a></li>
+
+        <li><a href="#1.10">1.10 Can I have a mailbox that has both messages
+        and sub-mailboxes?</a></li>
+
+        <li><a href="#1.11">1.11 What is the difference between "mailbox" and
+        "folder"?</a></li>
+
+        <li><a href="#1.12">1.12 What is the status of
+        internationalization?</a></li>
+
+        <li><a href="#1.13">1.13 Can I use SSL?</a></li>
+
+        <li><a href="#1.14">1.14 Can I use TLS and the STARTTLS
+        facility?</a></li>
+
+        <li><a href="#1.15">1.15 Can I use CRAM-MD5 authentication?</a></li>
+
+        <li><a href="#1.16">1.16 Can I use APOP authentication?</a></li>
+
+        <li><a href="#1.17">1.17 Can I use Kerberos V5?</a></li>
+
+        <li><a href="#1.18">1.18 Can I use PAM for plaintext
+        passwords?</a></li>
+
+        <li><a href="#1.19">1.19 Can I use Kerberos 5 for plaintext
+        passwords?</a></li>
+
+        <li><a href="#1.20">1.20 Can I use AFS for plaintext
+        passwords?</a></li>
+
+        <li><a href="#1.21">1.21 Can I use DCE for plaintext
+        passwords?</a></li>
+
+        <li><a href="#1.22">1.22 Can I use the CRAM-MD5 database for
+        plaintext passwords?</a></li>
+
+        <li><a href="#1.23">1.23 Can I disable plaintext passwords?</a></li>
+
+        <li><a href="#1.24">1.24 Can I disable plaintext passwords on
+        unencrypted sessions, but allow them on encrypted sessions?</a></li>
+
+        <li><a href="#1.25">1.25 Can I use virtual hosts?</a></li>
+
+        <li><a href="#1.26">1.26 Can I use RPOP authentication?</a></li>
+
+        <li><a href="#1.27">1.27 Can I use Kerberos V4?</a></li>
+
+        <li><a href="#1.28">1.28 Is there support for S/Key or OTP?</a></li>
+
+        <li><a href="#1.29">1.29 Is there support for NTLM or SPA?</a></li>
+
+        <li><a href="#1.30">1.30 Is there support for mh?</a></li>
+
+        <li><a href="#1.31">1.31 Is there support for qmail and the maildir
+        format?</a></li>
+
+        <li><a href="#1.32">1.32 Is there support for the Cyrus mailbox
+        format?</a></li>
+
+        <li><a href="#1.33">1.33 Is this software Y2K compliant?</a></li>
+      </ul>
+    </li>
+
+    <li>
+      <a href="#requirements">2. What Do I Need to Build This Software?</a>
+
+      <ul>
+        <li><a href="#2.1">2.1 What do I need to build this software with SSL
+        on UNIX?</a></li>
+
+        <li><a href="#2.2">2.2 What do I need to build this software with
+        Kerberos V on UNIX?</a></li>
+
+        <li><a href="#2.3">2.3 What do I need to use a C++ compiler with this
+        software to build my own application?</a></li>
+
+        <li><a href="#2.4">2.4 What do I need to build this software on
+        Windows?</a></li>
+
+        <li><a href="#2.5">2.5 What do I need to build this software on
+        DOS?</a></li>
+
+        <li><a href="#2.6">2.6 Can't I use Borland C to build this software
+        on the PC?</a></li>
+
+        <li><a href="#2.7">2.7 What do I need to build this software on the
+        Mac?</a></li>
+
+        <li><a href="#2.8">2.8 What do I need to build this software on
+        VMS?</a></li>
+
+        <li><a href="#2.9">2.9 What do I need to build this software on
+        TOPS-20?</a></li>
+
+        <li><a href="#2.10">2.10 What do I need to build this software on
+        Amiga or OS/2?</a></li>
+
+        <li><a href="#2.11">2.11 What do I need to build this software on
+        Windows CE?</a></li>
+      </ul>
+    </li>
+
+    <li>
+      <a href="#build">3. Build and Configuration Questions</a>
+
+      <ul>
+        <li><a href="#3.1">3.1 How do I configure the IMAP and POP servers on
+        UNIX?</a></li>
+
+        <li><a href="#3.2">3.2 I built and installed the servers according to
+        the BUILD instructions. It can't be that easy. Don't I need to write
+        a config file?</a></li>
+
+        <li><a href="#3.3">3.3 How do I make the IMAP and POP servers look
+        for INBOX at some place other than the mail spool directory?</a></li>
+
+        <li><a href="#3.4">3.4 How do I make the IMAP server look for
+        secondary folders at some place other than the user's home
+        directory?</a></li>
+
+        <li><a href="#3.5">3.5 How do I configure SSL?</a></li>
+
+        <li><a href="#3.6">3.6 How do I configure TLS and the STARTTLS
+        facility?</a></li>
+
+        <li><a href="#3.7">3.7 How do I build/install OpenSSL and
+        obtain/create certificates for use with SSL?</a></li>
+
+        <li><a href="#3.8">3.8 How do I configure CRAM-MD5
+        authentication?</a></li>
+
+        <li><a href="#3.9">3.9 How do I configure APOP
+        authentication?</a></li>
+
+        <li><a href="#3.10">3.10 How do I configure Kerberos V5?</a></li>
+
+        <li><a href="#3.11">3.11 How do I configure PAM for plaintext
+        passwords?</a></li>
+
+        <li><a href="#3.12">3.12 It looks like all I have to do to make the
+        server use Kerberos is to build with PAM on my Linux system, and set
+        it up in PAM for Kerberos passwords. Right?</a></li>
+
+        <li><a href="#3.13">3.13 How do I configure Kerberos 5 for plaintext
+        passwords?</a></li>
+
+        <li><a href="#3.14">3.14 How do I configure AFS for plaintext
+        passwords?</a></li>
+
+        <li><a href="#3.15">3.15 How do I configure DCE for plaintext
+        passwords?</a></li>
+
+        <li><a href="#3.16">3.16 How do I configure the CRAM-MD5 database for
+        plaintext passwords?</a></li>
+
+        <li><a href="#3.17">3.17 How do I disable plaintext
+        passwords?</a></li>
+
+        <li><a href="#3.18">3.18 How do I disable plaintext passwords on
+        unencrypted sessions, but allow them in SSL or TLS sessions?</a></li>
+
+        <li><a href="#3.19">3.19 How do I configure virtual hosts?</a></li>
+
+        <li>
+          <a href="#3.20">3.20 Why do I get compiler warning messages such
+          as:
+
+          <ul>
+            <li>passing arg 3 of `scandir' from incompatible pointer
+            type</li>
+
+            <li>Pointers are not assignment-compatible.</li>
+
+            <li>Argument #4 is not the correct type.</li>
+          </ul>during the build?</a>
+        </li>
+
+        <li>
+          <a href="#3.21">3.21 Why do I get compiler warning messages such
+          as
+
+          <ul>
+            <li>Operation between types "void(*)(int)" and "void*" is not
+            allowed.</li>
+
+            <li>Function argument assignment between types "void*" and
+            "void(*)(int)" is not allowed.</li>
+
+            <li>Pointers are not assignment-compatible.</li>
+
+            <li>Argument #5 is not the correct type.</li>
+          </ul>during the build?</a>
+        </li>
+
+        <li>
+          <a href="#3.22">3.22 Why do I get linker warning messages such
+          as:
+
+          <ul>
+            <li>mtest.c:515: the `gets' function is dangerous and should not
+            be used.</li>
+          </ul>during the build? Isn't this a security bug?</a>
+        </li>
+
+        <li>
+          <a href="#3.23">3.23 Why do I get linker warning messages such
+          as:</a>
+
+          <ul>
+            <li>auth_ssl.c:92: the `tmpnam' function is dangerous and should
+            not be used.</li>
+          </ul>during the build? Isn't this a security bug?
+        </li>
+
+        <li><a href="#3.24">3.24 OK, suppose I see a warning message about a
+        function being "dangerous and should not be used" for something other
+        than this gets() or tmpnam() call?</a></li>
+      </ul>
+    </li>
+
+    <li>
+      <a href="#operation">4. Operational Questions</a>
+
+      <ul>
+        <li><a href="#4.1">4.1 How can I enable anonymous IMAP
+        logins?</a></li>
+
+        <li><a href="#4.2">4.2 How do I set up an alert message that each
+        IMAP user will see?</a></li>
+
+        <li><a href="#4.3">4.3 How does the c-client library choose which of
+        its several mechanisms to use to establish an IMAP connection to the
+        server? I noticed that it can connect on port 143, port 993, via rsh,
+        and via ssh.</a></li>
+
+        <li><a href="#4.4">4.4 I am using a TLS-capable IMAP server, so I
+        don't need to use /ssl to get encryption. However, I want to be
+        certain that my session is TLS encrypted before I send my password.
+        How to I do this?</a></li>
+
+        <li><a href="#4.5">4.5 How do I use one of the alternative formats
+        described in the formats.txt document? In particular, I hear that mbx
+        format will give me better performance and allow shared
+        access.</a></li>
+
+        <li><a href="#4.6">4.6 How do I set up shared mailboxes?</a></li>
+
+        <li><a href="#4.7">4.7 How can I make the server syslogs go to
+        someplace other than the mail syslog?</a></li>
+      </ul>
+    </li>
+
+    <li>
+      <a href="#security">5. Security Questions</a>
+
+      <ul>
+        <li><a href="#5.1">5.1 I see that the IMAP server allows access to
+        arbitary files on the system, including /etc/passwd! How do I disable
+        this?</a></li>
+
+        <li><a href="#5.2">5.2 I've heard that IMAP servers are insecure. Is
+        this true?</a></li>
+
+        <li><a href="#5.3">5.3 How do I know that I have the most secure
+        version of the server?</a></li>
+
+        <li><a href="#5.4">5.4 I see all these strcpy() and sprintf() calls,
+        those are unsafe, aren't they?</a></li>
+
+        <li><a href="#5.5">5.5 Those /tmp lock files are protected 666, is
+        that really right?</a></li>
+      </ul>
+    </li>
+
+    <li>
+      <a href="#strange">6. <i>Why Did You Do This Strange Thing?</i>
+      Questions</a>
+
+      <ul>
+        <li><a href="#6.1">6.1 Why don't you use GNU autoconfig / automake /
+        autoblurdybloop?</a></li>
+
+        <li><a href="#6.2">6.2 Why do you insist upon a build with -g?
+        Doesn't it waste disk and memory space?</a></li>
+
+        <li><a href="#6.3">6.3 Why don't you make c-client a shared
+        library?</a></li>
+
+        <li><a href="#6.4">6.4 Why don't you use iconv() for
+        internationalization support?</a></li>
+
+        <li><a href="#6.5">6.5 Why is the IMAP server connected to the home
+        directory by default?</a></li>
+
+        <li><a href="#6.6">6.6 I have a Windows system. Why isn't the server
+        plug and play for me?</a></li>
+
+        <li><a href="#6.7">6.7 I looked at the UNIX SSL code and saw that you
+        have the SSL data payload size set to 8192 bytes. SSL allows 16K; why
+        aren't you using the full size?</a></li>
+
+        <li><a href="#6.8">6.8 Why is an mh format INBOX called #mhinbox
+        instead of just INBOX?</a></li>
+
+        <li><a href="#6.9">6.9 Why don't you support the maildir
+        format?</a></li>
+
+        <li><a href="#6.10">6.10 Why don't you support the Cyrus
+        format?</a></li>
+
+        <li><a href="#6.11">6.11 Why is it creating extra forks on my SVR4
+        system?</a></li>
+
+        <li><a href="#6.12">6.12 Why are you so fussy about the date/time
+        format in the internal <code>"From&nbsp;"</code> line in traditional
+        UNIX mailbox files? My other mail program just considers every line
+        that starts with <code>"From&nbsp;"</code> to be the start of the
+        message.</a></li>
+
+        <li><a href="#6.13">6.13 Why is traditional UNIX format the default
+        format?</a></li>
+
+        <li><a href="#6.14">6.14 Why do you write this "DON'T DELETE THIS
+        MESSAGE -- FOLDER INTERNAL DATA" message at the start of traditional
+        UNIX and MMDF format mailboxes?</a></li>
+
+        <li><a href="#6.15">6.15 Why don't you stash the mailbox metadata in
+        the first real message of the mailbox instead of writing this fake
+        FOLDER INTERNAL DATA message?</a></li>
+
+        <li><a href="#6.16">6.16 Why aren't "dual-use" mailboxes the
+        default?</a></li>
+
+        <li><a href="#6.17">6.17 Why do you use ucbcc to build on
+        Solaris?</a></li>
+
+        <li><a href="#6.18">6.18 Why should I care about some old system with
+        BSD libraries? cc is the right thing on my Solaris system!</a></li>
+
+        <li><a href="#6.19">6.19 Why do you insist upon writing .lock files
+        in the spool directory?</a></li>
+
+        <li><a href="#6.20">6.20 Why should I care about compatibility with
+        the past?</a></li>
+      </ul>
+    </li>
+
+    <li>
+      <a href="#problems">7. Problems and Annoyances</a>
+
+      <ul>
+        <li><a href="#7.1">7.1 Help! My INBOX is empty! What happened to my
+        messages?</a></li>
+
+        <li><a href="#7.2">7.2 Help! All my messages in a non-INBOX mailbox
+        have been concatenated into one message which claims to be from me
+        and has a subject of the file name of the mailbox! What's going
+        on?</a></li>
+
+        <li>
+          <a href="#7.3">7.3 Why do I get the message:
+
+          <ul>
+            <li>CREATE failed: Can't create mailbox node xxxxxxxxx: File
+            exists</li>
+          </ul>and how do I fix it?</a>
+        </li>
+
+        <li><a href="#7.4">7.4 Why can't I log in to the server? The user
+        name and password are right!</a></li>
+
+        <li><a href="#7.5">7.5 Help! My load average is soaring and I see
+        hundreds of POP and IMAP servers, many logged in as the same
+        user!</a></li>
+
+        <li><a href="#7.6">7.6 Why does mail disappear even though I set
+        "keep mail on server"?</a></li>
+
+        <li>
+          <a href="#7.7">7.7 Why do I get the message
+
+          <ul>
+            <li>Moved ##### bytes of new mail to /home/user/mbox from
+            /var/spool/mail/user</li>
+          </ul>and why did this happen?</a>
+        </li>
+
+        <li><a href="#7.8">7.8 Why isn't it showing the local host name as a
+        fully-qualified domain name?</a></li>
+
+        <li><a href="#7.9">7.9 Why is the local host name in the
+        From/Sender/Message-ID headers of outgoing mail not coming out as a
+        fully-qualified domain name?</a></li>
+
+        <li>
+          <a href="#7.10">7.10 What does the message:
+
+          <ul>
+            <li>Mailbox vulnerable - directory /var/spool/mail must have 1777
+            protection</li>
+          </ul>mean? How can I fix this?</a>
+        </li>
+
+        <li>
+          <a href="#7.11">7.11 What does the message:
+
+          <ul>
+            <li>Mailbox is open by another process, access is readonly</li>
+          </ul>mean? How do I fix this?</a>
+        </li>
+
+        <li>
+          <a href="#7.12">7.12 What does the message:
+
+          <ul>
+            <li>Can't get write access to mailbox, access is readonly</li>
+          </ul>mean?</a>
+        </li>
+
+        <li><a href="#7.13">7.13 I set my POP3 client to "delete messages
+        from server" but they never get deleted. What is wrong?</a></li>
+
+        <li>
+          <a href="#7.14">7.14 What do messages such as:
+
+          <ul>
+            <li>Message ... UID ... already has UID ...</li>
+
+            <li>Message ... UID ... less than ...</li>
+
+            <li>Message ... UID ... greater than last ...</li>
+
+            <li>Invalid UID ... in message ..., rebuilding UIDs</li>
+          </ul>mean?</a>
+        </li>
+
+        <li>
+          <a href="#7.15">7.15 What do the error messages:
+
+          <ul>
+            <li>Unable to read internal header at ...</li>
+
+            <li>Unable to find CRLF at ...</li>
+
+            <li>Unable to parse internal header at ...</li>
+
+            <li>Unable to parse message date at ...</li>
+
+            <li>Unable to parse message flags at ...</li>
+
+            <li>Unable to parse message UID at ...</li>
+
+            <li>Unable to parse message size at ...</li>
+
+            <li>Last message (at ... ) runs past end of file ...</li>
+          </ul>mean? I am using mbx format.</a>
+        </li>
+
+        <li>
+          <a href="#7.16">7.16 What do the syslog messages:
+
+          <ul>
+            <li>imap/tcp server failing (looping)</li>
+
+            <li>pop3/tcp server failing (looping)</li>
+          </ul>mean? When it happens, the listed service shuts down. How can
+          I fix this?</a>
+        </li>
+
+        <li>
+          <a href="#7.17">7.17 What does the syslog message:
+
+          <ul>
+            <li>Mailbox lock file /tmp/.600.1df3 open failure: Permission
+            denied</li>
+          </ul>mean?</a>
+        </li>
+
+        <li>
+          <a href="#7.18">7.18 What do the syslog messages:
+
+          <ul>
+            <li>Command stream end of file, while reading line user=...
+            host=...</li>
+
+            <li>Command stream end of file, while reading char user=...
+            host=...</li>
+
+            <li>Command stream end of file, while writing text user=...
+            host=...</li>
+          </ul>mean?</a>
+        </li>
+
+        <li>
+          <a href="#7.19">7.19 Why did my POP or IMAP session suddenly
+          disconnect? The syslog has the message:
+
+          <ul>
+            <li>Killed (lost mailbox lock) user=... host=...</li>
+          </ul></a>
+        </li>
+
+        <li><a href="#7.20">7.20 Why does my IMAP client show all the files
+        on the system, recursively from the UNIX root directory?</a></li>
+
+        <li><a href="#7.21">7.21 Why does my IMAP client show all of my
+        files, recursively from my UNIX home directory?</a></li>
+
+        <li><a href="#7.22">7.22 Why does my IMAP client show that I have
+        mailboxes named "#mhinbox", "#mh", "#shared", "#ftp", "#news", and
+        "#public"?</a></li>
+
+        <li><a href="#7.23">7.23 Why does my IMAP client show all my files in
+        my home directory?</a></li>
+
+        <li><a href="#7.24">7.24 Why is there a long delay before I get
+        connected to the IMAP or POP server, no matter what client I
+        use?</a></li>
+
+        <li><a href="#7.25">7.25 Why is there a long delay in Pine or any
+        other c-client based application call before I get connected to the
+        IMAP server? The hang seems to be in the c-client mail_open() call. I
+        don't have this problem with any other IMAP client. There is no delay
+        connecting to a POP3 or NNTP server with mail_open().</a></li>
+
+        <li><a href="#7.26">7.26 Why does a message sometimes get split into
+        two or more messages on my SUN system?</a></li>
+
+        <li>
+          <a href="#7.27">7.27 Why did my POP or IMAP session suddenly
+          disconnect? The syslog has the message:
+
+          <ul>
+            <li>Autologout user=&lt;...my user name...&gt; host=&lt;...my
+            imap server...&gt;</li>
+          </ul></a>
+        </li>
+
+        <li>
+          <a href="#7.28">7.28 What does the UNIX error message:
+
+          <ul>
+            <li>TLS/SSL failure: myserver: SSL negotiation failed</li>
+          </ul>mean?</a>
+        </li>
+
+        <li>
+          <a href="#7.29">7.29 What does the PC error message:
+
+          <ul>
+            <li>TLS/SSL failure: myserver: Unexpected TCP input
+            disconnect</li>
+          </ul>mean?</a>
+        </li>
+
+        <li>
+          <a href="#7.30">7.30 What does the error message:
+
+          <ul>
+            <li>TLS/SSL failure: myserver: Server name does not match
+            certificate</li>
+          </ul>mean?</a>
+        </li>
+
+        <li>
+          <a href="#7.31">7.31 What does the UNIX error message:
+
+          <ul>
+            <li>TLS/SSL failure: myserver: self-signed certificate</li>
+          </ul>mean?</a>
+        </li>
+
+        <li>
+          <a href="#7.32">7.32 What does the PC error message
+
+          <ul>
+            <li>TLS/SSL failure: myserver: Self-signed certificate or
+            untrusted authority</li>
+          </ul>mean?</a>
+        </li>
+
+        <li>
+          <a href="#7.33">7.33 What does the UNIX error message:
+
+          <ul>
+            <li>TLS/SSL failure: myserver: unable to get local issuer
+            certificate</li>
+          </ul>mean?</a>
+        </li>
+
+        <li><a href="#7.34">7.34 Why does reading certain messages hang when
+        using Netscape? It works fine with Pine!</a></li>
+
+        <li><a href="#7.35">7.35 Why does Netscape say that there's a problem
+        with the IMAP server and that I should "Contact your mail server
+        administrator."?</a></li>
+
+        <li><a href="#7.36">7.36 Why is one user creating huge numbers of
+        IMAP or POP server sessions?</a></li>
+
+        <li><a href="#7.37">7.37 Why don't I get any new mail notifications
+        from Outlook Express or Outlook after a while?</a></li>
+
+        <li><a href="#7.38">7.38 Why don't I get any new mail notifications
+        from Entourage?</a></li>
+
+        <li><a href="#7.39">7.39 Why doesn't Entourage work at all?</a></li>
+
+        <li><a href="#7.40">7.40 Why doesn't Netscape Notify (NSNOTIFY.EXE)
+        work at all?</a></li>
+
+        <li><a href="#7.41">7.41 Why can't I connect via SSL to Eudora? It
+        says the connection has been broken, and in the server syslogs I see
+        "Command stream end of file".</a></li>
+
+        <li><a href="#7.42">7.42 Sheesh. Aren't there <i>any</i> good IMAP
+        clients out there?</a></li>
+
+        <li>
+          <a href="#7.43">7.43 But wait! PC Pine (or other PC program build
+          with c-client) crashes with the message
+
+          <ul>
+            <li>incomplete SecBuffer exceeds maximum buffer size</li>
+          </ul>when I use SSL connections. This is a bug in c-client, right?</a>
+        </li>
+
+        <li><a href="#7.44">7.44 My qpopper users keep on getting the DON'T
+        DELETE THIS MESSAGE -- FOLDER INTERNAL DATA if they also use Pine or
+        IMAP. How can I fix this?</a></li>
+
+        <li><a href="#7.45">7.45 Help! I installed the servers but I can't
+        connect to them from my client!</a></li>
+
+        <li>
+          <a href="#7.46">7.46 Why do I get the message
+
+          <ul>
+            <li>Can not authenticate to SMTP server: 421 SMTP connection went
+            away!</li>
+          </ul>and why did this happen? There was also something about
+
+          <ul>
+            <li>SECURITY PROBLEM: insecure server advertised AUTH=PLAIN</li>
+          </ul></a>
+        </li>
+
+        <li>
+          <a href="#7.47">7.47 Why do I get the message
+
+          <ul>
+            <li>SMTP Authentication cancelled</li>
+          </ul>and why did this happen? There was also something about
+
+          <ul>
+            <li>SECURITY PROBLEM: insecure server advertised AUTH=PLAIN</li>
+          </ul></a>
+        </li>
+
+        <li>
+          <a href="#7.48">7.48 Why do I get the message
+
+          <ul>
+            <li>Invalid base64 string</li>
+          </ul>when I try to authenticate to a Cyrus server?
+        </li></a>
+      </ul>
+    </li>
+
+    <li>
+      <a href="#additional">8. Where to Go For Additional Information</a>
+
+      <ul>
+        <li><a href="#8.1">8.1 Where can I go to ask questions?</a></li>
+
+        <li><a href="#8.2">8.2 I have some ideas for enhancements to IMAP.
+        Where should I go?</a></li>
+
+        <li><a href="#8.3">8.3 Where can I read more about IMAP and other
+        email protocols?</a></li>
+
+        <li><a href="#8.4">8.4 Where can I find out more about setting up and
+        administering an IMAP server?</a></li>
+      </ul>
+    </li>
+  </ul><!--=======START BODY-->
+  <hr>
+
+  <h2><a name="general">1. General/Software Feature Questions</a></h2>
+  <hr>
+
+  <p><a name="1.1"><strong>1.1 Can I set up a POP or IMAP server on
+     UNIX/Linux/OSF/etc.?</strong></a></p>
+
+  <dl>
+    <dd>Yes. Refer to the UNIX specific notes in files CONFIG and BUILD.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.2"><strong>1.2 I am currently using qpopper as my POP3 server on
+     UNIX. Do I need to replace it with ipop3d in order to run
+     imapd?</strong></a></p>
+
+  <dl>
+    <dd>
+      Not necessarily.
+
+      <p>Although ipop3d interoperates with imapd better than qpopper, imapd
+      and qpopper will work together. The few qpopper/imapd interoperability
+      issues mostly affect users who use both IMAP and POP3 clients; those
+      users would probably be better served if their POP3 server is
+      ipop3d.</p>
+
+      <p>If you are happy with qpopper and just want to add imapd, you should
+      do that, and defer a decision on changing qpopper to ipop3d. That way,
+      you can get comfortable with imapd's performance, without changing
+      anything for your qpopper users.</p>
+
+      <p>Many sites have subsequently decided to change from qpopper to
+      ipop3d in order to get better POP3/IMAP interoperability. If you need
+      to do this, you'll know. There also seems to be a way to make qpopper
+      work better with imapd; see the answer to the <a href="#7.44">My
+      qpopper users keep on getting the DON'T DELETE THIS MESSAGE -- FOLDER
+      INTERNAL DATA if they also use Pine or IMAP. How can I fix this?</a>
+      question.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.3"><strong>1.3 Can I set up a POP or IMAP server on Windows XP,
+     2000, NT, Me, 98, or 95?</strong></a></p>
+
+  <dl>
+    <dd>
+      Yes. Refer to the NT specific notes in files CONFIG and BUILD. Also,
+      for DOS-based versions of Windows (Windows Me, 98, and 95) you *must*
+      set up CRAM-MD5 authentication, as described in md5.txt.
+
+      <p>There is no file access control on Windows 9x or Me, so you probably
+      will have to do modifications to env_unix.c to prevent people from
+      hacking others' mail.</p>
+
+      <p>Note, however, that the server is not plug and play the way it is
+      for UNIX.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.4"><strong>1.4 Can I set up a POP or IMAP server on Windows 3.1 or
+     DOS?</strong></a><br>
+  <a name="1.5"><strong>1.5 Can I set up a POP or IMAP server on
+     Macintosh?</strong></a><br>
+  <a name="1.6"><strong>1.6 Can I set up a POP or IMAP server on
+     VAX/VMS?</strong></a></p>
+
+  <dl>
+    <dd>Yes, it's just a small matter of programming.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.7"><strong>1.7 Can I set up a POP or IMAP server on
+     TOPS-20?</strong></a></p>
+
+  <dl>
+    <dd>
+      You have a TOPS-20 system? Cool.
+
+      <p>If IMAP2 (RFC 1176) is good enough for you, you can use MAPSER which
+      is about the ultimate gonzo pure TOPS-20 extended addressing assembly
+      language program. Unfortunately, IMAP2 is barely good enough for Pine
+      these days, and most other IMAP clients won't work with IMAP2 at all.
+      Maybe someone will hack MAPSER to do IMAP4rev1 some day.</p>
+
+      <p>We don't know if anyone wrote a POP3 server for TOPS-20. There
+      definitely was a POP2 server once upon a time.</p>
+
+      <p>Or you can port the POP and IMAP server from this IMAP toolkit to
+      it. All that you need for a first stab is to port the MTX driver.
+      That'll probably be just a couple of hours of hacking.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.8"><strong>1.8 Are hierarchical mailboxes
+     supported?</strong></a><br>
+  <a name="1.9"><strong>1.9 Are "dual-use" mailboxes
+     supported?</strong></a><br>
+  <a name="1.10"><strong>1.10 Can I have a mailbox that has both messages and
+     sub-mailboxes?</strong></a></p>
+
+  <dl>
+    <dd>
+      Yes. However, there is one important caveat.
+
+      <p>Some mailbox formats, including the default which is the traditional
+      UNIX mailbox format, are stored as a single file containing all the
+      messages. UNIX does not permit a name in the filesystem to be both a
+      file and a directory; consequently you can not have a sub-mailbox
+      within a mailbox that is in one of these formats.</p>
+
+      <p>This is not a limitation of the software; this is a limitation of
+      UNIX. For example, there are mailbox formats in which the name is a
+      directory and each message is a file within that directory; these
+      formats support sub-mailboxes within such mailboxes. However, for
+      technical reasons, the "flat file" formats are generally preferred
+      since they perform better. Read imap-2007/docs/formats.txt for more
+      information on this topic.</p>
+
+      <p>It is always permissible to create a directory that is not a
+      mailbox, and have sub-mailboxes under it. The easiest way to create a
+      directory is to create a new mailbox inside a directory that doesn't
+      already exist. For example, if you create "Mail/testbox" on UNIX, the
+      directory "Mail/" will automatically be created and then the mailbox
+      "testbox" will be created as a sub-mailbox of "Mail/".</p>
+
+      <p>It is also possible to create the name "Mail/" directly. Check the
+      documentation for your client software to see how to do this with that
+      software.</p>
+
+      <p>Of course, on Windows systems you would use "\" instead of "/".</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.11"><strong>1.11 What is the difference between "mailbox" and
+     "folder"?</strong></a></p>
+
+  <dl>
+    <dd>
+      The term "mailbox" is IMAP-speak for what a lot of software calls a
+      "folder" or a "mail folder". However, "folder" is often used in other
+      contexts to refer to a directory, for example, in the graphic user
+      interface on both Windows and Macintosh.
+
+      <p>A "mailbox" is specifically defined as a named object that contains
+      messages. It is not required to be capable of containing other types of
+      objects including other mailboxes; although some mailbox formats will
+      permit this.</p>
+
+      <p>In IMAP-speak, a mailbox which can not contain other mailboxes is
+      called a "no-inferiors mailbox". Similarly, a directory which can not
+      contain messages is not a mailbox and is called a "no-select name".</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.12"><strong>1.12 What is the status of
+     internationalization?</strong></a></p>
+
+  <dl>
+    <dd>
+      The IMAP toolkit is partially internationalized and multilingualized.
+
+      <p>Searching is supported in the following charsets: US-ASCII, UTF-8,
+      ISO-8859-1, ISO-8859-2, ISO-8859-3, ISO-8859-4, ISO-8859-5, ISO-8859-6,
+      ISO-8859-7, ISO-8859-8, ISO-8859-9, ISO-8859-10, ISO-8859-11,
+      ISO-8859-13, ISO-8859-14, ISO-8859-15, ISO-8859-16, KOI8-R, KOI8-U
+      (alias KOI8-RU), TIS-620, VISCII, ISO-2022-JP, ISO-2022-KR,
+      ISO-2022-CN, ISO-2022-JP-1, ISO-2022-JP-2, GB2312 (alias CN-GB),
+      CN-GB-12345, BIG5 (alias CN-BIG5), EUC-JP, EUC-KR, Shift_JIS,
+      Shift-JIS, KS_C_5601-1987, KS_C_5601-1992, WINDOWS_874, WINDOWS-1250,
+      WINDOWS-1251, WINDOWS-1252, WINDOWS-1253, WINDOWS-1254, WINDOWS-1255,
+      WINDOWS-1256, WINDOWS-1257, WINDOWS-1258.</p>
+
+      <p>All ISO-2022-?? charsets are treated identically, and support ASCII,
+      JIS Roman, hankaku katakana, ISO-8859-[1 - 10], TIS, GB 2312, JIS X
+      0208, JIS X 0212, KSC 5601, and planes 1 and 2 of CNS 11643.</p>
+
+      <p>EUC-JP includes support for JIS X 0212 and hankaku katakana.</p>
+
+      <p>c-client library support also exists to convert text in any of the
+      above charsets into Unicode, including headers with MIME
+      encoded-words.</p>
+
+      <p>There is no support for localization (e.g. non-English error
+      messages) at the present time, but such support is planned.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.13"><strong>1.13 Can I use SSL?</strong></a></p>
+
+  <dl>
+    <dd>Yes. See the answer to the <a href="#3.5">How do I configure SSL?</a>
+    question.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.14"><strong>1.14 Can I use TLS and the STARTTLS
+     facility?</strong></a></p>
+
+  <dl>
+    <dd>Yes. See the answer to the <a href="#3.6">How do I configure TLS and
+    the STARTTLS facility?</a> question.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.15"><strong>1.15 Can I use CRAM-MD5
+     authentication?</strong></a></p>
+
+  <dl>
+    <dd>Yes. See the answer to the <a href="#3.8">How do I configure CRAM-MD5
+    authentication?</a> question.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.16"><strong>1.16 Can I use APOP authentication?</strong></a></p>
+
+  <dl>
+    <dd>
+      Yes. See the <a href="#3.9">How do I configure APOP authentication?</a>
+      question.
+
+      <p>Note that there is no client support for APOP authentication.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.17"><strong>1.17 Can I use Kerberos V5?</strong></a></p>
+
+  <dl>
+    <dd>Yes. See the answer to the <a href="#3.10">How do I configure
+    Kerberos V5?</a> question.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.18"><strong>1.18 Can I use PAM for plaintext
+     passwords?</strong></a></p>
+
+  <dl>
+    <dd>Yes. See the answer to the <a href="#3.11">How do I configure PAM for
+    plaintext passwords?</a> question.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.19"><strong>1.19 Can I use Kerberos 5 for plaintext
+     passwords?</strong></a></p>
+
+  <dl>
+    <dd>Yes. See the answer to the <a href="#3.13">How do I configure
+    Kerberos 5 for plaintext passwords?</a> question.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.20"><strong>1.20 Can I use AFS for plaintext
+     passwords?</strong></a></p>
+
+  <dl>
+    <dd>Yes. See the answer to the <a href="#3.14">How do I configure AFS for
+    plaintext passwords?</a> question.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.21"><strong>1.21 Can I use DCE for plaintext
+     passwords?</strong></a></p>
+
+  <dl>
+    <dd>Yes. See the answer to the <a href="#3.15">How do I configure DCE for
+    plaintext passwords?</a> question.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.22"><strong>1.22 Can I use the CRAM-MD5 database for plaintext
+     passwords?</strong></a></p>
+
+  <dl>
+    <dd>Yes. See the answer to the <a href="#3.16">How do I configure the
+    CRAM-MD5 database for plaintext passwords?</a> question.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.23"><strong>1.23 Can I disable plaintext
+     passwords?</strong></a></p>
+
+  <dl>
+    <dd>Yes. See the answer to the <a href="#3.17">How do I disable plaintext
+    passwords?</a> question.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.24"><strong>1.24 Can I disable plaintext passwords on unencrypted
+     sessions, but allow them on encrypted sessions?</strong></a></p>
+
+  <dl>
+    <dd>Yes. See the answer to the <a href="#3.18">How do I disable plaintext
+    passwords on unencrypted sessions, but allow them in SSL or TLS
+    sessions?</a> question.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.25"><strong>1.25 Can I use virtual hosts?</strong></a></p>
+
+  <dl>
+    <dd>Yes. See the answer to the <a href="#3.19">How do I configure virtual
+    hosts?</a> question.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.26"><strong>1.26 Can I use RPOP authentication?</strong></a></p>
+
+  <dl>
+    <dd>There is no support for RPOP authentication.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.27"><strong>1.27 Can I use Kerberos V4?</strong></a></p>
+
+  <dl>
+    <dd>
+      Kerberos V4 is not supported. Kerberos V4 client-only contributed code
+      is available in
+      <pre>
+<a href=
+"ftp://ftp.cac.washington.edu/mail/kerberos4-patches.tar.Z">ftp://ftp.cac.washington.edu/mail/kerberos4-patches.tar.Z
+</a>
+</pre>This is a patchkit which must be applied to the IMAP toolkit according
+to the instructions in the patchkit's README. We can not promise that this
+code works.
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.28"><strong>1.28 Is there support for S/Key or
+     OTP?</strong></a></p>
+
+  <dl>
+    <dd>There is currently no support for S/Key or OTP. There may be an OTP
+    SASL authenticator available from third parties.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.29"><strong>1.29 Is there support for NTLM or
+     SPA?</strong></a></p>
+
+  <dl>
+    <dd>
+      There is currently no support for NTLM or SPA, nor are there any plans
+      to add such support. In general, I avoid vendor-specific mechanisms. I
+      also believe that these mechanisms are being deprecated by their
+      vendor.
+
+      <p>There may be an NTLM SASL authenticator available from third
+      parties.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.30"><strong>1.30 Is there support for mh?</strong></a></p>
+
+  <dl>
+    <dd>
+      Yes, but only as a legacy format. Your mh format INBOX is accessed by
+      the name "#mhinbox", and all other mh format mailboxes are accessed by
+      prefixing "#mh/" to the name, e.g. "#mh/foo". The mh support uses the
+      "Path:" entry in your .mh_profile file to identify the root directory
+      of your mh format mailboxes.
+
+      <p>Non-legacy use of mh format is not encouraged. There is no support
+      for permanent flags or unique identifiers; furthermore there are known
+      severe performance problems with the mh format.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.31"><strong>1.31 Is there support for qmail and the maildir
+     format?</strong></a></p>
+
+  <dl>
+    <dd>There is no support for qmail or the maildir format in our
+    distribution, nor are there any plans to add such support. Maildir
+    support may be available from third parties.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.32"><strong>1.32 Is there support for the Cyrus mailbox
+     format?</strong></a></p>
+
+  <dl>
+    <dd>No.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="1.33"><strong>1.33 Is this software Y2K compliant?</strong></a></p>
+
+  <dl>
+    <dd>Please read the files Y2K and calendar.txt.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><br></p>
+
+  <h2><a name="requirements">2. What Do I Need to Build This Software?</a></h2>
+  <hr>
+
+  <p><a name="2.1"><strong>2.1 What do I need to build this software with SSL on
+     UNIX?</strong></a></p>
+
+  <dl>
+    <dd>You need to build and install OpenSSL first.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="2.2"><strong>2.2 What do I need to build this software with Kerberos
+     V on UNIX?</strong></a></p>
+
+  <dl>
+    <dd>You need to build and install MIT Kerberos first.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="2.3"><strong>2.3 What do I need to use a C++ compiler with this
+     software to build my own application?</strong></a></p>
+
+  <dl>
+    <dd>
+      If you are building an application using the c-client library, use the
+      new c-client.h file instead of including the other include files. It
+      seems that c-client.h should define away all the troublesome names that
+      conflict with C++.
+
+      <p>If you use gcc, you may need to use -fno-operator-names as well.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="2.4"><strong>2.4 What do I need to build this software on
+     Windows?</strong></a></p>
+
+  <dl>
+    <dd>
+      You need Microsoft Visual C++ 6.0, Visual C++ .NET, or Visual C# .NET
+      (which you can buy from any computer store), along with the Microsoft
+      Platform SDK (which you can download from Microsoft's web site).
+
+      <p>You do not need to install the entire Platform SDK; it suffices to
+      install just the Core SDK and the Internet Development SDK.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="2.5"><strong>2.5 What do I need to build this software on
+     DOS?</strong></a></p>
+
+  <dl>
+    <dd>It's been several years since we last attempted to do this. At the
+    time, we used Microsoft C.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="2.6"><strong>2.6 Can't I use Borland C to build this software on the
+     PC?</strong></a></p>
+
+  <dl>
+    <dd>Probably not. If you know otherwise, please let us know.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="2.7"><strong>2.7 What do I need to build this software on the
+     Mac?</strong></a></p>
+
+  <dl>
+    <dd>It has been several years since we last attempted to do this. At the
+    time, we used Symantec THINK C; but today you'll need a C compiler which
+    allows segments to be more than 32K.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="2.8"><strong>2.8 What do I need to build this software on
+     VMS?</strong></a></p>
+
+  <dl>
+    <dd>You need the VMS C compiler, and either the Multinet or Netlib
+    TCP.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="2.9"><strong>2.9 What do I need to build this software on
+     TOPS-20?</strong></a></p>
+
+  <dl>
+    <dd>You need the TOPS-20 KCC compiler.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="2.10"><strong>2.10 What do I need to build this software on Amiga or
+     OS/2?</strong></a></p>
+
+  <dl>
+    <dd>We don't know.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="2.11"><strong>2.11 What do I need to build this software on Windows
+     CE?</strong></a></p>
+
+  <dl>
+    <dd>This port is incomplete. Someone needs to finish it.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><br></p>
+
+  <h2><a name="build">3. Build and Configuration Questions</a></h2>
+  <hr>
+
+  <p><a name="3.1"><strong>3.1 How do I configure the IMAP and POP servers on
+     UNIX?</strong></a><br>
+  <a name="3.2"><strong>3.2 I built and installed the servers according to the
+     BUILD instructions. It can't be that easy. Don't I need to write a
+     config file?</strong></a></p>
+
+  <dl>
+    <dd>
+      For ordinary "vanilla" UNIX systems, this software is plug and play;
+      just build it, install it, and you're done. If you have a modified
+      system, then you may want to do additional work; most of this is to a
+      single source code file (env_unix.c on UNIX systems). Read the file
+      CONFIG for more details.
+
+      <p>Yes, it's that easy. There are some additional options, such as SSL
+      or Kerberos, which require additional steps to build. See the relevant
+      questions below.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="3.3"><strong>3.3 How do I make the IMAP and POP servers look for
+     INBOX at some place other than the mail spool
+     directory?</strong></a><br>
+  <a name="3.4"><strong>3.4 How do I make the IMAP server look for secondary
+     folders at some place other than the user's home
+     directory?</strong></a></p>
+
+  <dl>
+    <dd>Please read the file CONFIG for discussion of this and other
+    issues.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="3.5"><strong>3.5 How do I configure SSL?</strong></a><br>
+  <a name="3.6"><strong>3.6 How do I configure TLS and the STARTTLS
+     facility?</strong></a></p>
+
+  <dl>
+    <dd>
+      imap-2007 supports SSL and TLS client functionality on UNIX and 32-bit
+      Windows for IMAP, POP3, SMTP, and NNTP; and SSL and TLS server
+      functionality on UNIX for IMAP and POP3.
+
+      <p>UNIX SSL build requires that a third-party software package,
+      OpenSSL, be installed on the system first. Read imap-2007/docs/SSLBUILD
+      for more information.</p>
+
+      <p>SSL is supported via undocumented Microsoft interfaces in Windows 9x
+      and NT4; and via standard interfaces in Windows 2000, Windows
+      Millenium, and Windows XP.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="3.7"><strong>3.7 How do I build/install OpenSSL and obtain/create
+     certificates for use with SSL?</strong></a></p>
+
+  <dl>
+    <dd>If you need help in doing this, try the contacts mentioned in the
+    OpenSSL README. We do not offer support for OpenSSL or certificates.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="3.8"><strong>3.8 How do I configure CRAM-MD5
+     authentication?</strong></a><br>
+  <a name="3.9"><strong>3.9 How do I configure APOP
+     authentication?</strong></a></p>
+
+  <dl>
+    <dd>
+      CRAM-MD5 authentication is enabled in the IMAP and POP3 client code on
+      all platforms. Read md5.txt to learn how to set up CRAM-MD5 and APOP
+      authentication on UNIX and NT servers.
+
+      <p>There is no support for APOP client authentication.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="3.10"><strong>3.10 How do I configure Kerberos V5?</strong></a></p>
+
+  <dl>
+    <dd>
+      imap-2007 supports client and server functionality on UNIX and 32-bit
+      Windows.
+
+      <p>Kerberos V5 is supported by default in Windows 2000 builds:</p>
+      <pre>
+ nmake -f makefile.w2k
+</pre>
+
+      <p>Other builds require that a third-party Kerberos package, e.g. MIT
+      Kerberos, be installed on the system first.</p>
+
+      <p>To build with Kerberos V5 on UNIX, include EXTRAAUTHENTICATORS=gss
+      in the make command line, e.g.</p>
+      <pre>
+ make lnp EXTRAAUTHENTICATORS=gss
+</pre>
+
+      <p>To build with Kerberos V5 on Windows 9x, Windows Millenium, and NT4,
+      use the "makefile.ntk" file instead of "makefile.nt":</p>
+      <pre>
+
+ nmake -f makefile.ntk
+</pre>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="3.11"><strong>3.11 How do I configure PAM for plaintext
+     passwords?</strong></a></p>
+
+  <dl>
+    <dd>
+      On Linux systems, use the lnp port, e.g.
+      <pre>
+ make lnp
+
+</pre>On Solaris systems and other systems with defective PAM
+implementations, build with PASSWDTYPE=pmb, e.g.
+      <pre>
+ make sol PASSWDTYPE=pmb
+</pre>On all other systems, build with PASSWDTYPE=pam, e.g
+      <pre>
+ make foo PASSWDTYPE=pam
+</pre>If you build with PASSWDTYPE=pam and authentication does not work, try
+rebuilding (after a "make clean") with PASSWDTYPE=pmb.
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="3.12"><strong>3.12 It looks like all I have to do to make the server
+     use Kerberos is to build with PAM on my Linux system, and set it up in
+     PAM for Kerberos passwords. Right?</strong></a></p>
+
+  <dl>
+    <dd>
+      Yes and no.
+
+      <p>Doing this will make plaintext password authentication use the
+      Kerberos password instead of the /etc/passwd password.</p>
+
+      <p>However, this will NOT give you Kerberos-secure authentication. See
+      the answer to the <a href="#3.10">How do I configure Kerberos V5?</a>
+      question for how to build with Kerberos-secure authentication.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="3.13"><strong>3.13 How do I configure Kerberos 5 for plaintext
+     passwords?</strong></a></p>
+
+  <dl>
+    <dd>
+      Build with PASSWDTYPE=gss, e.g.
+      <pre>
+ make sol PASSWDTYPE=gss
+</pre>However, this will NOT give you Kerberos-secure authentication. See the
+answer to the <a href="#3.10">How do I configure Kerberos V5?</a> question
+for how to build with Kerberos-secure authentication.
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="3.14"><strong>3.14 How do I configure AFS for plaintext
+     passwords?</strong></a></p>
+
+  <dl>
+    <dd>
+      Build with PASSWDTYPE=afs, e.g
+      <pre>
+ make sol PASSWDTYPE=afs
+
+</pre>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="3.15"><strong>3.15 How do I configure DCE for plaintext
+     passwords?</strong></a></p>
+
+  <dl>
+    <dd>
+      Build with PASSWDTYPE=dce, e.g
+      <pre>
+ make sol PASSWDTYPE=dce
+</pre>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="3.16"><strong>3.16 How do I configure the CRAM-MD5 database for
+     plaintext passwords?</strong></a></p>
+
+  <dl>
+    <dd>
+      The CRAM-MD5 password database is automatically used for plaintext
+      password if it exists.
+
+      <p>Note that this is NOT CRAM-MD5-secure authentication. You probably
+      want to consider disabling plaintext passwords for non-SSL/TLS
+      sessions. See the next two questions.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="3.17"><strong>3.17 How do I disable plaintext
+     passwords?</strong></a></p>
+
+  <dl>
+    <dd>
+      Server-level plaintext passwords can be disabled by setting
+      PASSWDTYPE=nul, e.g.
+      <pre>
+ make lnx EXTRAAUTHENTICATORS=gss PASSWDTYPE=nul
+</pre>Note that you must have a CRAM-MD5 database installed or specify at
+least one EXTRAAUTHENTICATOR, otherwise it will not be possible to log in to
+the server.
+
+      <p>When plaintext passwords are disabled, the IMAP server will
+      advertise the LOGINDISABLED capability and the POP3 server will not
+      advertise the USER capability.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+
+  <p><a name="3.18"><strong>3.18 How do I disable plaintext passwords on
+     unencrypted sessions, but allow them in SSL or TLS
+     sessions?</strong></a></p>
+
+  <dl>
+    <dd>
+      <p>Do not set PASSWDTYPE=nul or SSLTYPE=unix. Set SSLTYPE=nopwd
+      instead, e.g.</p>
+      <pre>
+ make lnx SSLTYPE=nopwd
+</pre>
+
+      <p>When plaintext passwords are disabled, the IMAP server will
+      advertise the LOGINDISABLED capability and the POP3 server will not
+      advertise the USER capability.</p>
+
+      <p>Plaintext passwords will always be enabled in SSL sessions; the IMAP
+      server will not advertise the LOGINDISABLED capability and the POP3
+      server will advertise the USER capability.</p>
+
+      <p>If the client does a successful start-TLS in a non-SSL session,
+      plaintext passwords will be enabled, and a new CAPABILITY or CAPA
+      command (which is required after start-TLS) will show the effect as in
+      SSL sessions.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="3.19"><strong>3.19 How do I configure virtual
+     hosts?</strong></a></p>
+
+  <dl>
+    <dd>
+      This is automatic, but with certain restrictions.
+
+      <p>The most important one is that each virtual host must have its own
+      IP address; otherwise the server has no way of knowing which virtual
+      host is desired.</p>
+
+      <p>As distributed, the software uses a global password file; hence user
+      "fred" on one virtual host is "fred" on all virtual hosts. You may want
+      to modify the checkpw() routine to implement some other policy (e.g.
+      separate password files).</p>
+
+      <p>Note that the security model assumes that all users have their own
+      unique UNIX UID number. So if you use separate password files you
+      should make certain that the UID numbers do not overlap between
+      different files.</p>
+
+      <p>More advanced virtual host support may be available as patches from
+      third parties.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="3.20"><strong>3.20 Why do I get compiler warning messages such
+     as:</strong></a></p>
+  <pre>
+ passing arg 3 of `scandir' from incompatible pointer type
+ Pointers are not assignment-compatible.
+ Argument #4 is not the correct type.
+
+</pre>
+
+  <p><strong>during the build?</strong></p>
+
+  <dl>
+    <dd>
+      You can safely ignore these messages.
+
+      <p>Over the years, the prototype for scandir() has changed, and thus is
+      variant across different UNIX platforms. In particular, the definitions
+      of the third argument (type select_t) and fourth argument (type
+      compar_t) have changed over the years, the issue being whether or not
+      the arguments to the functions pointed to by these function pointers
+      are of type const or not.</p>
+
+      <p>The way that c-client calls scandir() will tend to generate these
+      compiler warnings on newer systems such as Linux; however, it will
+      still build. The problem with fixing the call is that then it won't
+      build on older systems.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="3.21"><strong>3.21 Why do I get compiler warning messages such
+     as</strong></a></p>
+  <pre>
+ Operation between types "void(*)(int)" and "void*" is not allowed.
+ Function argument assignment between types "void*" and "void(*)(int)" is not allowed.
+ Pointers are not assignment-compatible.
+ Argument #5 is not the correct type.
+</pre>
+
+  <p><strong>during the build?</strong></p>
+
+  <dl>
+    <dd>
+      You can safely ignore these messages.
+
+      <p>All known systems have no problem with casting a function pointer
+      to/from a void* pointer, certain C compilers issue a compiler
+      diagnostic because this facility is listed as a "Common extension" by
+      the C standard:</p>
+      <pre>
+ K.5.7  Function pointer casts
+  [#1] A pointer to an object or to void may be cast to a pointer
+       to a function, allowing data to be invoked as a function (6.3.4).
+  [#2] A pointer to a function may be cast to a pointer to an
+       object or to void, allowing a function to be inspected or
+       modified (for example, by a debugger) (6.3.4).
+
+</pre>It may be just a "common extension", but this facility is relied upon
+heavily by c-client.
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="3.22"><strong>3.22 Why do I get linker warning messages such
+     as:</strong></a></p>
+  <pre>
+mtest.c:515: the `gets' function is dangerous and should not be used.
+</pre>
+
+  <p><strong>during the build? Isn't this a security bug?</strong></p>
+
+  <dl>
+    <dd>
+      You can safely ignore this message.
+
+      <p>Certain linkers, most notably on Linux, give this warning message.
+      It is indeed true that the traditional gets() function is not a safe
+      one.</p>
+
+      <p>However, the mtest program is only a demonstration program, a model
+      of a very basic application program using c-client. It is not something
+      that you would install, much less run in any security-sensitive
+      context.</p>
+
+      <p>mtest has numerous other shortcuts that you wouldn't want to do in a
+      real application program.</p>
+
+      <p>The only "security bug" with mtest would be if it was run by some
+      script in a security-sensitive context, but mtest isn't particularly
+      useful for such purposes. If you wanted to write a script to automate
+      some email task using c-client, you'd be better off using imapd instead
+      of mtest.</p>
+
+      <p>mtest only has two legitimate uses. It's a useful testbed for me
+      when debugging new versions of c-client, and it's useful as a model for
+      someone writing a simple c-client application to see how the various
+      calls work.</p>
+
+      <p>By the way, if you need a more advanced example of c-client
+      programming than mtest (and you probably will), I recommend that you
+      look at the source code for imapd and Pine.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="3.23"><strong>3.23 Why do I get linker warning messages such
+     as:</strong></a></p>
+  <pre>
+ auth_ssl.c:92: the `tmpnam' function is dangerous and should not be used.
+</pre>
+
+  <p><strong>during the build? Isn't this a security bug?</strong></p>
+
+  <dl>
+    <dd>
+      You can safely ignore this message.
+
+      <p>Certain linkers, most notably on Linux, give this warning message,
+      based upon two known issues with tmpnam():</p>
+
+      <dl>
+        <dd>there can be a buffer overflow if an inadequate buffer is
+        allocated.</dd>
+
+        <dd>there can be a timing race caused by certain incautious usage of
+        the return value.</dd>
+      </dl>
+
+      <p>Neither of these issues applies in the particular use that is made
+      of tmpnam(). More importantly, the tmpnam() call is never executed on
+      Linux systems.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="3.24"><strong>3.24 OK, suppose I see a warning message about a
+     function being "dangerous and should not be used" for something other
+     than this gets() or tmpnam() call?</strong></a></p>
+
+  <dl>
+    <dd>Please forward the details for investigation.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><br></p>
+
+  <h2><a name="operation">4. Operational Questions</a></h2>
+  <hr>
+
+  <p><a name="4.1"><strong>4.1 How can I enable anonymous IMAP
+     logins?</strong></a></p>
+
+  <dl>
+    <dd>Create the file /etc/anonymous.newsgroups. At the present time, this
+    file should be empty. This will permit IMAP logins as anonymous as well
+    as the ANONYMOUS SASL authenticator. Anonymous users have access to
+    mailboxes in the #news., #ftp/, and #public/ namespaces only.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="4.2"><strong>4.2 How do I set up an alert message that each IMAP
+     user will see?</strong></a></p>
+
+  <dl>
+    <dd>Create the file /etc/imapd.alert with the text of the message. This
+    text should be kept to one line if possible. Note that this will cause an
+    alert to every IMAP user every time they initiate an IMAP session, so it
+    should only be used for critical messages.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="4.3"><strong>4.3 How does the c-client library choose which of its
+     several mechanisms to use to establish an IMAP connection to the server?
+     I noticed that it can connect on port 143, port 993, via rsh, and via
+     ssh.</strong></a></p>
+
+  <dl>
+    <dd>
+      c-client chooses how to establish an IMAP connection via the following
+      rules:
+
+      <ul>
+        <li>If /ssl is specified, use an SSL connection. Fail otherwise.</li>
+
+        <li>Else if client is a UNIX system and "ssh server exec /etc/rimapd"
+        works, use that</li>
+
+        <li>Else if /tryssl is specified and an SSL connection works, use
+        that.</li>
+
+        <li>Else if client is a UNIX system and "rsh server exec /etc/rimapd"
+        works, use that.</li>
+
+        <li>Else use a non-SSL connection.</li>
+      </ul>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="4.4"><strong>4.4 I am using a TLS-capable IMAP server, so I don't
+     need to use /ssl to get encryption. However, I want to be certain that
+     my session is TLS encrypted before I send my password. How to I do
+     this?</strong></a></p>
+
+  <dl>
+    <dd>Use the /tls option in the mailbox name. This will cause an error
+    message and the connection to fail if the server does not negotiate
+    STARTTLS.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="4.5"><strong>4.5 How do I use one of the alternative formats
+     described in the formats.txt document? In particular, I hear that mbx
+     format will give me better performance and allow shared
+     access.</strong></a></p>
+
+  <dl>
+    <dd>
+      The rumors about mbx format being preferred are true. It is faster than
+      the traditional UNIX mailbox format and permits shared access.
+
+      <p>However, and this is <em>very important</em>, note that using an
+      alternative mailbox format is an advanced facility, and only expert
+      users should undertake it. If you don't understand any of the following
+      notes, you may not be enough of an expert yet, and are probably better
+      off not going this route until you are more comfortable with your
+      understanding.</p>
+
+      <p>Some of the formats, including mbx, are only supported by the
+      software based on the c-client library, and are not recognized by other
+      mailbox programs. The "vi" editor will corrupt any mbx format mailbox
+      that it encounters.</p>
+
+      <p>Another problem is that the certain formats, including mbx, use
+      advanced file access and locking techniques that do <em>not</em> work
+      reliably with NFS. NFS is not a real filesystem. Use IMAP instead of
+      NFS for distributed access.</p>
+
+      <p>Each of the following steps are in escalating order of involvement.
+      The further you go down this list, the more deeply committed you
+      become:</p>
+
+      <ul>
+        <li>The simplest way to create a mbx-format mailbox is to prefix the
+        name with "#driver.mbx/" when creating a mailbox through c-client.
+        For example, if you create "#driver.mbx/foo", the mailbox "foo" will
+        be created in mbx format. Only use "#driver.mbx/" when creating the
+        mailbox. At all other times, just use the name ("foo" in this
+        example); the software will automatically select the driver for mbx
+        whenever that mailbox is accessed without you doing anything
+        else.</li>
+
+        <li>You can use the "mailutil copy" command to copy an existing
+        mailbox to a new mailbox in mbx format. Read the man page provided
+        with the mailutil program for details.</li>
+
+        <li>If you create an mbx-format INBOX, by creating
+        "#driver.mbx/INBOX" (note that "INBOX" must be all uppercase), then
+        subsequent access to INBOX by any c-client based application will use
+        the mbx-format INBOX. Any mail delivered to the traditional format
+        mailbox in the spool directory (e.g. /var/spool/mail/$USER) will
+        automatically be copied into the mbx-format INBOX and the spool
+        directory copy removed.</li>
+
+        <li>You can cause any newly-created mailboxes to be in mbx-format by
+        default by changing the definition of CREATEPROTO=unixproto to be
+        CREATEPROTO=mbxproto in src/osdep/unix/Makefile, then rebuilding the
+        IMAP toolkit (do a "make clean" first). Do not change EMPTYPROTO,
+        since mbx format mailboxes are never a zero-byte file. If you use
+        Pine or the imap-utils, you should probably also rebuild them with
+        the new IMAP toolkit too.</li>
+
+        <li>You can deliver directly to the mbx-format INBOX by use of the
+        tmail or dmail programs. tmail is for direct invocation from sendmail
+        (or whatever MTA program you use); dmail is for calls from procmail.
+        Both of these programs have man pages which must be read carefully
+        before making this change.</li>
+      </ul>
+
+      <p>Most other servers (e.g. Cyrus) require use of a non-standard
+      format. A full-fledged format conversion is not significantly different
+      from what you have to do with other servers. The difference, which
+      makes format conversion procedures somewhat more complicated with this
+      server, is that there is no "all or nothing" requirement with this
+      server. There are many points in between. A format conversion can be
+      anything from a single mailbox or single user, to systemwide.</p>
+
+      <p>This is good in that you can decide how far to go, or do the steps
+      incrementally as you become more comfortable with the result. On the
+      other hand, there's no "One True Way" which can be boiled down to a
+      simple set of pedagogical instructions.</p>
+
+      <p>A number of sites have done full-fledged format conversions, and are
+      reportedly quite happy with the results. Feel free to ask in the
+      comp.mail.imap newsgroup or the imap-uw mailing list for advice or
+      help.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="4.6"><strong>4.6 How do I set up shared mailboxes?</strong></a></p>
+
+  <dl>
+    <dd>
+      At the simplest level, a shared mailbox is one which has UNIX file and
+      directory protections which permit multiple users to access it. What
+      this means is that your existing skills and tools to create and manage
+      shared files on your UNIX system apply to shared mailboxes; e.g.
+      <pre>
+ chmod 666 mailbox
+</pre>
+
+      <p>You may want to consider the use of a mailbox format which permits
+      multiple simultaneous read/write sessions, such as the mbx format. The
+      traditional UNIX format only allows one read/write session to a
+      mailbox at a time.</p>
+
+      <p>An additional convenience item are three system directories, which
+      can be set up for shared namespaces. These are: #ftp, #shared, and
+      #public, and are defined by creating the associated UNIX users and home
+      directories as described below.</p>
+
+      <p>#ftp/ refers to the anonymous ftp filesystem exported by the ftp
+      server, and is equivalent to the home directory for UNIX user "ftp".
+      For example, #ftp/foo/bar refers to the file /foo/bar in the anonymous
+      FTP filesystem, or ~ftp/foo/bar for normal users. Anonymous FTP files
+      are available to anonymous IMAP logins. By default, newly-created files
+      in #ftp/ are protected 644.</p>
+
+      <p>#public/ refers to an IMAP toolkit convention called "public" files,
+      and is equivalent to the home directory for UNIX user "imappublic". For
+      example, #public/foo/bar refers to the file ~imappublic/foo/bar. Public
+      files are available to anonymous IMAP logins. By default, newly-created
+      files in #public are created with protection 0666.</p>
+
+      <p>#shared/ refers to an IMAP toolkit convention called "shared" files,
+      and is equivalent to the home directory for UNIX user "imapshared". For
+      example, #shared/foo/bar refers to the file ~imapshared/foo/bar. Shared
+      files are <em>not</em> available to anonymous IMAP logins. By default,
+      newly-created files in #shared are created with protection 0660.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="4.7"><strong>4.7 How can I make the server syslogs go to someplace
+     other than the mail syslog?</strong></a></p>
+
+  <dl>
+    <dd>
+      The openlog() call that sets the syslog facility is in
+      <strong>src/osdep/unix/env_unix.c</strong> in routine
+      <strong>server_init()</strong>. You need to edit this file to change
+      the syslog facility from LOG_MAIL to the facility you want, then
+      rebuild. You also need to set up your /etc/syslog.conf properly.
+
+      <p>Refer to the man pages for syslog and syslogd for more information
+      on what the available syslog facilities are and how to configure
+      syslogs. If you still don't understand what to do, find a UNIX system
+      expert.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><br></p>
+
+  <h2><a name="security">5. Security Questions</a></h2>
+  <hr>
+
+  <p><a name="5.1"><strong>5.1 I see that the IMAP server allows access to
+     arbitary files on the system, including /etc/passwd! How do I disable
+     this?</strong></a></p>
+
+  <dl>
+    <dd>
+      You should not worry about this if your IMAP users are allowed shell
+      access. The IMAP server does not permit any access that the user can
+      not have via the shell.
+
+      <p>If, and only if, you deny your IMAP users shell access, you may want
+      to consider one of three choices. Note that these choices reduce IMAP
+      functionality, and may have undesirable side effects. Each of these
+      choices involves an edit to file
+      <strong>src/osdep/unix/env_unix.c</strong></p>
+
+      <p>The first (and recommended) choice is to set
+      <strong>restrictBox</strong> as described in file CONFIG. This will
+      disable access to the filesystem root, to other users' home directory,
+      and to superior directory.</p>
+
+      <p>The second (and strongly NOT recommended) choice is to set
+      <strong>closedBox</strong> as described in file CONFIG. This puts each
+      IMAP session into a so-called "chroot jail", and thus setting this
+      option is <em>extremely</em> dangerous; it can make your system much
+      less secure and open to root compromise attacks. So do not use this
+      option unless you are <em>absolutely certain</em> that you understand
+      all the issues of a "chroot jail."</p>
+
+      <p>The third choice is to rewrite routine
+      <strong>mailboxfile()</strong> to implement whatever mapping from
+      mailbox name to filesystem name (and restrictions) that you wish. This
+      is the most general choice. As a guide, you can see at the start of
+      routine <strong>mailboxfile()</strong> what the
+      <strong>restrictBox</strong> choice does.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="5.2"><strong>5.2 I've heard that IMAP servers are insecure. Is this
+     true?</strong></a></p>
+
+  <dl>
+    <dd>
+      There are no known security problems in this version of the IMAP
+      toolkit, including the IMAP and POP servers. The IMAP and POP servers
+      limit what can be done while not logged in, and as part of the login
+      process discard all privileges except those of the user.
+
+      <p>As with other software packages, there have been buffer overflow
+      vulnerabilities in past versions. All known problems of this nature are
+      fixed in this version.</p>
+
+      <p>There is every reason to believe that the bad guys are engaged in an
+      ongoing effort to find vulnerabilities in the IMAP toolkit. We look for
+      such problems, and when one is found we fix it.</p>
+
+      <p>It's unfortunate that any vulnerabilities existed in past versions,
+      and we're doing my best to keep the IMAP toolkit free of
+      vulnerabilities. No new vulnerabilities have been discovered in quite a
+      while, but efforts will not be relaxed.</p>
+
+      <p>Beware of vendors who claim that their implementations can not have
+      vulnerabilities.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="5.3"><strong>5.3 How do I know that I have the most secure version
+     of the server?</strong></a></p>
+
+  <dl>
+    <dd>
+      The best way is to keep your server software up to date. The bad guys
+      are always looking for ways to crack software, and when they find one,
+      let all their friends know.
+
+      <p>Oldtimers used to refer to a concept of <em>software rot</em>: if
+      your software hasn't been updated in a while, it would "rot" -- tend to
+      acquire problems that it didn't have when it was new.</p>
+
+      <p>The latest release version of the IMAP toolkit is always available
+      at <a href=
+      "ftp://ftp.cac.washington.edu/mail/imap.tar.Z">ftp://ftp.cac.washington.edu/mail/imap.tar.Z</a></p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="5.4"><strong>5.4 I see all these strcpy() and sprintf() calls, those
+     are unsafe, aren't they?</strong></a></p>
+
+  <dl>
+    <dd>
+      Yes and no.
+
+      <p>It can be unsafe to do these calls if you do not know that the
+      string being written will fit in the buffer. However, they are
+      perfectly safe if you do know that.</p>
+
+      <p>Beware of programmers who advocate doing a brute-force change of all
+      instances of</p>
+      <pre>
+ strcpy (s,t);
+</pre>to
+      <pre>
+ strncpy (s,t,n)[n] = '\0';
+</pre>and similar measures in the name of "fixing all possible buffer
+overflows."
+
+      <p>There are examples in which a security bug was introduced because of
+      this type of "fix", due to the programmer using the wrong value for n.
+      In one case, the programmer thought that n was larger than it actually
+      was, causing a NUL to be written out of the buffer; in another, n was
+      too small, and a security credential was truncated.</p>
+
+      <p>What is particularly ironic was that in both cases, the original
+      strcpy() was safe, because the size of the source string was known to
+      be safe.</p>
+
+      <p>With all this in mind, the software has been inspected, and it is
+      believed that all places where buffer overflows can happen have been
+      fixed. The strcpy()s that are still are in the code occur after a size
+      check was done in some other way.</p>
+
+      <p>Note that the common C idiom of</p>
+      <pre>
+ *s++ = c;
+</pre>is just as vulnerable to buffer overflows. You can't cure buffer
+overflows by outlawing certain functions, nor is it desirable to do so;
+sometimes operations like strcpy() translate into fast machine instructions
+for better performance.
+
+      <p>Nothing replaces careful study of code. That's how the bad guys find
+      bugs. Security is not accomplished by means of brute-force
+      shortcuts.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="5.5"><strong>5.5 Those /tmp lock files are protected 666, is that
+     really right?</strong></a></p>
+
+  <dl>
+    <dd>
+      Yes. Shared mailboxes won't work otherwise. Also, you get into
+      accidental denial of service problems with old lock files left lying
+      around; this happens fairly frequently.
+
+      <p>The deliberate mischief that can be caused by fiddling with the lock
+      files is small-scale; harassment level at most. There are many -- and
+      much more effective -- other ways of harassing another user on UNIX.
+      It's usually not difficult to determine the culprit.</p>
+
+      <p>Before worrying about deliberate mischief, worry first about things
+      happening by accident!</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><br></p>
+
+  <h2><a name="strange">6. <em>Why Did You Do This Strange Thing?</em>
+     Questions</a></h2>
+  <hr>
+
+  <p><a name="6.1"><strong>6.1 Why don't you use GNU autoconfig / automake /
+     autoblurdybloop?</strong></a></p>
+
+  <dl>
+    <dd>
+      Autoconfig et al are not available on all the platforms where the IMAP
+      toolkit is supported; and do not work correctly on some of the
+      platforms where they do exist. Furthermore, these programs add another
+      layer of complexity to an already complex process.
+
+      <p>Coaxing software that uses autoconfig to build properly on platforms
+      which were not specifically considered by that software wastes an
+      inordinate amount of time. When (not if) autoconfig fails to do the
+      right thing, the result is an inpenetrable morass to untangle in order
+      to find the problem and fix it.</p>
+
+      <p>The concept behind autoconfig is good, but the execution is flawed.
+      It rarely does the right thing on a platform that wasn't specifically
+      considered. Human life is too short to debug autoconfig problems,
+      especially since the current mechanism is so much easier.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="6.2"><strong>6.2 Why do you insist upon a build with -g? Doesn't it
+     waste disk and memory space?</strong></a></p>
+
+  <dl>
+    <dd>
+      From time to time a submitted port has snuck in without -g. This has
+      <em>always</em> ended up causing problems. There are only two valid
+      excuses for not using -g in a port:
+
+      <ul>
+        <li>The compiler does not support -g</li>
+
+        <li>An alternate form of -g is needed with optimization, e.g.
+        -g3.</li>
+      </ul>
+
+      <p>There will be no new ports added without -g (or a suitable
+      alternative) being set.</p>
+
+      <p>-g has not been arbitrarily added to the ports which do not
+      currently have it because we don't know if doing so would break the
+      build. However, any support issues with one of those port <em>will</em>
+      lead to the correct -g setting being determined and permanently
+      added.</p>
+
+      <p>Processors are fast enough (and disk space is cheap enough) that -g
+      should be automatic in all compilers with no way of turning it off, and
+      /bin/strip should be a symlink to /bin/true. Human life is too short to
+      deal with binaries built without -g. Such binaries should be a bad
+      memory of the days of KIPS processors and disks that costs several
+      dollars per kilobyte.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="6.3"><strong>6.3 Why don't you make c-client a shared
+     library?</strong></a></p>
+
+  <dl>
+    <dd>
+      All too often, shared libraries create far more problems than they
+      solve.
+
+      <p>Remember that you only gain the benefit of a shared library when
+      there are multiple applications which use that shared library. Even
+      without shared libraries, on most modern operating systems (and many
+      ancient ones too!) applications will share their text segments between
+      across multiple processes running the same application. This means that
+      if your system only runs one application (e.g. imapd) that uses the
+      c-client library, then you gain no benefit from making c-client a
+      shared library even if it has 100 imapd processes. You will, however
+      suffer added complexity.</p>
+
+      <p>If you have a server system that just runs imapd and ipop3d, then
+      making c-client a shared library will save just one copy of c-client no
+      matter how many IMAP/POP3 processes are running.</p>
+
+      <p>The problem with shared libraries is that you have to keep around a
+      copy of the library every time something changes in the library that
+      would affect the interface the library presents to the application. So,
+      you end up having many copies of the same shared library.</p>
+
+      <p>If you don't keep multiple copies of the shared library, then one of
+      two things happens. If there was proper versioning, then you'll get a
+      message such as "cannot open shared object file" or "minor versions
+      don't match" and the application won't run. Otherwise, the application
+      will run, but will fail in mysterious ways.</p>
+
+      <p>Several sites and third-party distributors have modified the
+      c-client makefile in order to make c-client be a shared library.
+      <em>When</em> (not <em>if</em>) a c-client based application fails in
+      mysterious ways because of a library compatibility problem, the result
+      is a bug report. A lot of time and effort ends up getting wasted
+      investigating such bug reports.</p>
+
+      <p>Memory is so cheap these days that it's not worth it. Human life is
+      too short to deal with shared library compatibility problems.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="6.4"><strong>6.4 Why don't you use iconv() for internationalization
+     support?</strong></a></p>
+
+  <dl>
+    <dd>iconv() is not ubiquitous enough.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="6.5"><strong>6.5 Why is the IMAP server connected to the home
+     directory by default?</strong></a></p>
+
+  <dl>
+    <dd>
+      The IMAP server has no way of knowing what you might call "mail" as
+      opposed to "some other file"; in fact, you can use IMAP to access any
+      file.
+
+      <p>The IMAP server also doesn't know whether your preferred
+      subdirectory for mailbox files is "mail/", ".mail/", "Mail/",
+      "Mailboxes/", or any of a zillion other possibilities. If one such name
+      were chosen, it would undoubtably anger the partisans of all the other
+      names.</p>
+
+      <p>It is possible to modify the software so that the default connected
+      directory is someplace else. Please read the file CONFIG for discussion
+      of this and other issues.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="6.6"><strong>6.6 I have a Windows system. Why isn't the server plug
+     and play for me?</strong></a></p>
+
+  <dl>
+    <dd>
+      There is no standard for how mail is stored on Windows; nor a single
+      standard SMTP server. The closest to either would be the SMTP server in
+      Microsoft's IIS.
+
+      <p>So there's no default by which to make assumptions. As the software
+      is set up, it assumes that the each user has an Windows login account
+      and private home directory, and that mail is stored on that home
+      directory as files in one of the popular UNIX formats. It also assumes
+      that there is some tool equivalent to inetd on UNIX that does the
+      TCP/IP listening and server startup.</p>
+
+      <p>Basically, unless you're an email software hacker, you probably want
+      to look elsewhere if you want IMAP/POP servers for Windows.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="6.7"><strong>6.7 I looked at the UNIX SSL code and saw that you have
+     the SSL data payload size set to 8192 bytes. SSL allows 16K; why aren't
+     you using the full size?</strong></a></p>
+
+  <dl>
+    <dd>
+      This is to avoid an interoperability problem with:
+
+      <ul>
+        <li>PC IMAP clients that use Microsoft's SChannel.DLL (SSPI) for SSL
+        support</li>
+
+        <li>Microsoft Exchange server (which also uses SChannel).</li>
+      </ul>
+
+      <p>SChannel has a bug that makes it think that the maximum SSL data
+      payload size is 16379 bytes -- 5 bytes too small. Thus, c-client has to
+      make sure that it never transmits full sized SSL packets.</p>
+
+      <p>The reason for using 8K (as opposed to, say, 16379 bytes, or 15K,
+      or...) is that it corresponds with the TCP buffer size that the
+      software uses elsewhere for input; there's a slight performance benefit
+      to having the two sizes correspond or at least be a multiple of each
+      other. Also, it keeps the size as a power of two, which might be
+      significant on some platforms.</p>
+
+      <p>There wasn't a significant difference that we could measure between
+      8K and 15K.</p>
+
+      <p>Microsoft has developed a hotfix for this bug. Look up MSKB article
+      number 300562. Contrary to the article text which implies that this is
+      a Pine issue, this bug also affects Microsoft Exchange server with
+      <em>any</em> client that transmits full-sized SSL payloads.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="6.8"><strong>6.8 Why is an mh format INBOX called #mhinbox instead
+     of just INBOX?</strong></a></p>
+
+  <dl>
+    <dd>
+      It's a long story. In brief, the mh format driver is less functional
+      than any of the other drivers. It turned out that there were some users
+      (including high-level administrators) who tried mh years ago and no
+      longer use it, but still had an mh profile left behind.
+
+      <p>When the mh driver used INBOX, it would see the mh profile, and
+      proceed to move the user's INBOX into the mh format INBOX. This caused
+      considerable confusion as some things stopped working.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="6.9"><strong>6.9 Why don't you support the maildir
+     format?</strong></a></p>
+
+  <dl>
+    <dd>
+      It is technically difficult to support maildir in IMAP while
+      maintaining acceptable performance, robustness, following the
+      requirements of the IMAP protocol specification, and following the
+      requirements of maildir.
+
+      <p>No one has succeeded in accomplishing all four together. The various
+      maildir drivers offered as patches all have these problems. The problem
+      is exacerbated because this implementation supports multiple formats;
+      consequently this implementation can't make any performance shortcuts
+      by assuming that all the world is maildir.</p>
+
+      <p>We can't do a better job than the maildir fan community has done
+      with their maildir drivers. Similarly, if the maildir fan community
+      provides the maildir driver, they take on the responsibility for
+      answering maildir-specific support questions. This is as it should be,
+      and that is why maildir support is left to the maildir fan
+      community.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="6.10"><strong>6.10 Why don't you support the Cyrus
+     format?</strong></a></p>
+
+  <dl>
+    <dd>
+      There's no point to doing so. An implementation which supports multiple
+      formats will never do as well as one which is optimized to support one
+      single format.
+
+      <p>If you want to use Cyrus mailbox format, you should use the Cyrus
+      server, which is the native implementation of that format and is
+      specifically optimized for that format. That's also why Cyrus doesn't
+      implement any other format.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="6.11"><strong>6.11 Why is it creating extra forks on my SVR4
+     system?</strong></a></p>
+
+  <dl>
+    <dd>
+      This is because your system only has fcntl() style locking and not
+      flock() style locking. fcntl() locking has a design flaw that causes a
+      close() to release any locks made by that process on the file opened on
+      that file descriptor, even if the lock was made on a different file
+      descriptor.
+
+      <p>This design flaw causes unexpected loss of lock, and consequent
+      mailbox corruption. The workaround is to do certain "dangerous
+      operations" in another fork, thus avoiding doing a close() in the
+      vulnerable fork.</p>
+
+      <p>The best way to solve this problem is to upgrade your SVR4 (Solaris,
+      AIX, HP-UX, SGI) or OSF/1 system to a more advanced operating system,
+      such as Linux or BSD. These more advanced operating systems have
+      fcntl() locking for compatibility with SVR4, but also have flock()
+      locking.</p>
+
+      <p>Beware of certain SVR4 systems, such as AIX, which have an "flock()"
+      function in their C library that is just a jacket that does an fcntl()
+      lock. This is not a true flock(), and has the same design flaw as
+      fcntl().</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="6.12"><strong>6.12 Why are you so fussy about the date/time format in
+     the internal <code>"From&nbsp;"</code> line in traditional UNIX mailbox
+     files? My other mail program just considers every line that starts with
+     <code>"From&nbsp;"</code> to be the start of the message.</strong></a></p>
+
+  <dl>
+    <dd>
+      You just answered your own question. If any line that starts with
+      <code>"From&nbsp;"</code> is treated as the start of a message, then
+      every message text line which starts with <code>"From&nbsp;"</code> has
+      to be quoted (typically by prefixing a "&gt;" character). People
+      complain about this -- "why did a &gt; get stuck in my message?"
+
+      <p>So, good mail reading software only considers a line to be a
+      <code>"From&nbsp;"</code> line if it follows the actual specification
+      for a "From&nbsp;" line. This means, among other things, that the day of
+      week is fixed-format: <code>"May&nbsp;14"</code>, but
+      <code>"May&nbsp;&nbsp;7"</code> (note the extra space) as opposed to
+      <code>"May&nbsp;7"</code>. ctime() format for the date is the most
+      common, although POSIX also allows a numeric timezone after the
+      year. For compatibility with ancient software, the seconds are optional,
+      the timezone may appear before the year, the old 3-letter timezones are
+      also permitted, and "remote from xxx" may appear after the whole
+      thing.</p>
+
+      <p>Unfortunately, some software written by novices use other formats.
+      The most common error is to have a variable-width day of month, perhaps
+      in the erroneous belief that RFC 2822 (or RFC 822) defines the format of
+      the date/time in the <code>"From&nbsp;"</code> line (it doesn't; no RFC
+      describes internal formats). I've seen a few other goofs, such as a
+      single-digit second, but these are less common.</p>
+
+      <p>If you are writing your own software that writes mailbox files, and
+      you really aren't all that savvy with all the ins and outs and ancient
+      history, you should seriously consider using the c-client library (e.g.
+      routine mail_append()) instead of doing the file writes yourself. If
+      you must do it yourself, use ctime(), as in:</p>
+      <pre>
+ fprintf (mbx,"From %s@%h %s",user,host,ctime (time (0)));
+</pre>rather than try to figure out a good format yourself. ctime() is the
+most traditional format and nobody will flame you for using it.
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="6.13"><strong>6.13 Why is traditional UNIX format the default
+     format?</strong></a></p>
+
+  <dl>
+    <dd>Compatibility with the past 30 or so years of UNIX history. This
+    server is the only one that completely interoperates with legacy UNIX
+    mail tools.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="6.14"><strong>6.14 Why do you write this "DON'T DELETE THIS MESSAGE
+     -- FOLDER INTERNAL DATA" message at the start of traditional UNIX and
+     MMDF format mailboxes?</strong></a></p>
+
+  <dl>
+    <dd>
+      This pseudo-message serves two purposes.
+
+      <p>First, it establishes the mailbox format even when the mailbox has
+      no messages. Otherwise, a mailbox with no messages is a zero-byte file,
+      which could be one of several formats.</p>
+
+      <p>Second, it holds mailbox metadata used by IMAP: the UID validity,
+      the last assigned UID, and mailbox keywords. Without this metadata,
+      which must be preserved even when the mailbox has no messages, the
+      traditional UNIX format wouldn't be able to support the full
+      capabilities of IMAP.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="6.15"><strong>6.15 Why don't you stash the mailbox metadata in the
+     first real message of the mailbox instead of writing this fake FOLDER
+     INTERNAL DATA message?</strong></a></p>
+
+  <dl>
+    <dd>
+      In fact, that is what is done if the mailbox is non-empty and does not
+      already have a FOLDER INTERNAL DATA message.
+
+      <p>One problem with doing that is that if some external program removes
+      the first message, the metadata is lost and must be recreated, thus
+      losing any prior UID or keyword list status that IMAP clients may
+      depend upon.</p>
+
+      <p>Another problem is that this doesn't help if the last message is
+      deleted. This will result in an empty mailbox, and the necessity to
+      create a FOLDER INTERNAL DATA message.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="6.16"><strong>6.16 Why aren't "dual-use" mailboxes the
+     default?</strong></a></p>
+
+  <dl>
+    <dd>Compatibility with the past 30 or so years of UNIX history, not to
+    mention compatibility with user expectations when using shell tools.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="6.17"><strong>6.17 Why do you use ucbcc to build on
+     Solaris?</strong></a></p>
+
+  <dl>
+    <dd>
+      It is a long, long story about why cc is set to ucbcc. You need to
+      invoke the C compiler so that it links with the SVR4 libraries and not
+      the BSD libraries, otherwise readdir() will return the wrong
+      information.
+
+      <p>Of all the names in the most common path, ucbcc is the only name to
+      be found (on /usr/ccs/bin) that points to a suitable compiler. cc is
+      likely to be /usr/ucb/cc which is absolutely not the compiler that you
+      want. The real SVR4 cc is probably something like /opt/SUNWspro/bin/cc
+      which is rarely in anyone's path by default.</p>
+
+      <p>ucbcc is probably a link to acc, e.g. /opt/SUNWspro/SC4.0/bin/acc,
+      and is the UCB C compiler using the SVR4 libraries.</p>
+
+      <p>If ucbcc isn't on your system, then punt on the SUN C compiler and
+      use gcc instead (the gso port instead of the sol port).</p>
+
+      <p>If, in spite of all the above warnings, you choose to change "ucbcc"
+      to "cc", you will probably find that the -O2 needs to be changed to -O.
+      If you don't get any error messages with -O2, that's a pretty good
+      indicator that you goofed and are running the compiler that will link
+      with the BSD libraries.</p>
+
+      <p>To recap:</p>
+
+      <ul>
+        <li>The sol port is designed to be built using the UCB compiler using
+        the SVR4 libraries. This compiler is "ucbcc", which is lunk to acc.
+        You use -O2 as one of the CFLAGS.</li>
+
+        <li>If you build the sol port with the UCB compiler using the BSD
+        libraries, you will get no error messages but you will get bad
+        binaries (the most obvious symptom is dropping the first two
+        characters return filenames from the imapd LIST command. This
+        compiler also uses -O2, and is very often what the user gets from
+        "cc". <strong>BEWARE</strong></li>
+
+        <li>If you build the sol port with the real SVR4 compiler, which is
+        often hidden away or unavailable on many systems, then you will get
+        errors from -O2 and you need to change that to -O. But you will get a
+        good binary. However, you should try it with -O2 first, to make sure
+        that you got this compiler and not the UCB compiler using BSD
+        libraries.</li>
+      </ul>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="6.18"><strong>6.18 Why should I care about some old system with BSD
+     libraries? cc is the right thing on my Solaris system!</strong></a></p>
+
+  <dl>
+    <dd>
+      Because there still are sites that use such systems. On those systems,
+      the assumption that "cc" does the right thing will lead to corrupt
+      binaries with no error message or other warning that anything is amiss.
+
+      <p>Too many sites have fallen victim to this problem.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="6.19"><strong>6.19 Why do you insist upon writing .lock files in the
+     spool directory?</strong></a></p>
+
+  <dl>
+    <dd>Compatibility with the past 30 years of UNIX software which deals
+    with the spool directory, especially software which delivers mail.
+    Otherwise, it is possible to lose mail.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="6.20"><strong>6.20 Why should I care about compatibility with the
+     past?</strong></a></p>
+
+  <dl>
+    <dd>This is one of those questions in which the answer never convinces
+    those who ask it. Somehow, everybody who ever asks this question ends up
+    answering it for themselves as they get older, with the very answer that
+    they rejected years earlier.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><br></p>
+
+  <h2><a name="problems">7. Problems and Annoyances</a></h2>
+  <hr>
+
+  <p><a name="7.1"><strong>7.1 Help! My INBOX is empty! What happened to my
+     messages?</strong></a></p>
+
+  <dl>
+    <dd>
+      If you are seeing "0 messages" when you open INBOX and you know you
+      have messages there (and perhaps have looked at your mail spool file
+      and see that messages are there), then probably there is something
+      wrong with the very first line of your mail spool file. Make sure that
+      the first five bytes of the file are "From ", followed by an email
+      address and a date/time in ctime() format, e.g.:
+      <pre>
+ From fred@foo.bar Mon May  7 20:54:30 2001
+</pre>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.2"><strong>7.2 Help! All my messages in a non-INBOX mailbox have
+     been concatenated into one message which claims to be from me and has a
+     subject of the file name of the mailbox! What's going
+     on?</strong></a></p>
+
+  <dl>
+    <dd>
+      Something wrong with the very first line of the mailbox. Make sure that
+      the first five bytes of the file are "From ", followed by an email
+      address and a date/time in ctime() format, e.g.:
+      <pre>
+ From fred@foo.bar Mon May  7 20:54:30 2001
+</pre>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.3"><strong>7.3 Why do I get the message:</strong> <tt>CREATE
+     failed: Can't create mailbox node xxxxxxxxx: File exists</tt>
+     <strong>and how do I fix it?</strong></a></p>
+
+  <dl>
+    <dd>See the answer to the <a href="#1.8">Are hierarchical mailboxes
+    supported?</a> question.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.4"><strong>7.4 Why can't I log in to the server? The user name and
+     password are right!</strong></a></p>
+
+  <dl>
+    <dd>
+      There are a myriad number of possible answers to this question. The
+      only way to say for sure what is wrong is run the server under a
+      debugger such as gdb while root (yes, you must be root) with a
+      breakpoint at routines checkpw() and loginpw(), then single-step until
+      you see which test rejected you. The server isn't going to give any
+      error messages other than "login failed" in the name of not giving out
+      any unnecessary information to unauthorized individuals.
+
+      <p>Here are some of the more common reasons why login may fail:</p>
+
+      <ul>
+        <li>You didn't really give the correct user name and/or
+        password.</li>
+
+        <li>Your client doesn't send the LOGIN command correctly; for
+        example, IMAP2 clients won't send a password containing a "*"
+        correctly to an IMAP4 server.</li>
+
+        <li>If you have set up a CRAM-MD5 database, remember that the
+        password used is the one in the CRAM-MD5 database, and furthermore
+        that there must also be an entry in /etc/passwd (but the /etc/passwd
+        password is not used).</li>
+
+        <li>If you are using PAM, have you created a service file for the
+        server in /etc/pam.d?</li>
+
+        <li>If you are using shadow passwords, have you used an appropriate
+        port when building? In particular, note that "lnx" is for Linux
+        systems without shadow passwords; you probably want "slx" or "lnp"
+        instead.</li>
+
+        <li>If your system has account or password expirations, check to see
+        that the expiration date hasn't passed.</li>
+
+        <li>You can't log in as root or any other UID 0 user. This is for
+        your own safety, not to mention the fact that the servers use UID 0
+        as meaning "not logged in".</li>
+      </ul>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.5"><strong>7.5 Help! My load average is soaring and I see hundreds
+     of POP and IMAP servers, many logged in as the same
+     user!</strong></a></p>
+
+  <dl>
+    <dd>
+      Certain inferior losing GUI mail reading programs have a "synchronize
+      all mailboxes at startup" (IMAP) or "check for new mail every second"
+      (POP) feature which causes a rapid and unchecked spawning of servers.
+
+      <p>This is not a problem in the server; the client is really asking for
+      all those server sessions. Unfortunately, there isn't much that the POP
+      and IMAP servers can do about it; they don't spawned themselves.</p>
+
+      <p>Some sites have added code to record the number of server sessions
+      spawned per user per hour, and disable login for a user who has
+      exceeded a predetermined rate. This doesn't stop the servers from being
+      spawned; it just means that a server session will commit suicide a bit
+      faster.</p>
+
+      <p>Another possibility is to detect excessive server spawning activity
+      at the level where the server is spawned, which would be inetd or
+      possibly tcpd. The problem here is that this is a hard time to
+      quantify. 50 sessions in a minute from a multi-user timesharing system
+      may be perfectly alright, whereas 10 sessions a minute from a PC may be
+      too much.</p>
+
+      <p>The real solution is to fix the client configuration, by disabling
+      those evil features. Also tell the vendors of those clients how you
+      feel about distributing denial-of-service attack tools in the guise of
+      mail reading programs.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.6"><strong>7.6 Why does mail disappear even though I set "keep
+     mail on server"?</strong></a><br>
+  <a name="7.7"><strong>7.7 Why do I get the message</strong> <tt>Moved #####
+     bytes of new mail to /home/user/mbox from /var/spool/mail/user</tt>
+     <strong>and why did this happen?</strong></a></p>
+
+  <dl>
+    <dd>
+      This is probably caused by the mbox driver. If the file "mbox" exists
+      on the user's home directory and is in UNIX mailbox format, then when
+      INBOX is opened this file will be selected as INBOX instead of the mail
+      spool file. Messages will be automatically transferred from the mail
+      spool file into the mbox file.
+
+      <p>To disable this behavior, delete "mbox" from the EXTRADRIVERS list
+      in the top-level Makefile and rebuild. Note that if you do this, users
+      won't be able to access the messages that have already been moved to
+      mbox unless they open mbox instead of INBOX.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.8"><strong>7.8 Why isn't it showing the local host name as a
+     fully-qualified domain name?</strong></a><br>
+  <a name="7.9"><strong>7.9 Why is the local host name in the
+     From/Sender/Message-ID headers of outgoing mail not coming out as a
+     fully-qualified domain name?</strong></a></p>
+
+  <dl>
+    <dd>
+      Your UNIX system is misconfigured. The entry for your system in
+      /etc/hosts must have the fully-qualified domain name first, e.g.
+      <pre>
+ 105.69.1.234	myserver.example.com myserver
+</pre>
+
+      <p>A common mistake of novice system administrators is to have the
+      short name first, e.g.</p>
+      <pre>
+ 105.69.1.234	myserver myserver.example.com
+
+</pre>
+
+      <p>or to omit the fully qualified domain name entirely, e.g.</p>
+      <pre>
+ 105.69.1.234	myserver
+</pre>
+
+      <p>The result of this is that when the IMAP toolkit does a
+      gethostbyname() call to get the fully-qualified domain name, it would
+      get "myserver" instead of "myserver.example.com".</p>
+
+      <p>On some systems, a configuration file (typically named
+      /etc/svc.conf, /etc/netsvc.conf, or /etc/nsswitch.conf) can be used to
+      configure the system to use the domain name system (DNS) instead of
+      /etc/hosts, so it doesn't matter if /etc/hosts is misconfigured.</p>
+
+      <p>Check the man pages for gethostbyname, hosts, svc, and/or netsvc for
+      more information.</p>
+
+      <p>Unfortunately, certain vendors, most notably SUN, have failed to
+      make this clear in their documentation. Most of SUN's documentation
+      assumes a corporate network that is not connected to the Internet.</p>
+
+      <p>net.folklore once (late 1980s) held that the proper procedure was to
+      append the results of getdomainname() to the name returned by
+      gethostname(), and some versions of sendmail configuration files were
+      distributed that did this. This was incorrect; the string returned from
+      getdomainname() is the Yellow Pages (a.k.a NIS) domain name, which is a
+      completely different (albeit unfortunately named) entity from an
+      Internet domain. These were often fortuitously the same string, except
+      when they weren't. Frequently, this would result in host names with
+      spuriously doubled domain names, e.g.</p>
+      <pre>
+ myserver.example.com.example.com
+
+</pre>
+
+      <p>This practice has been thoroughly discredited for many years, but
+      folklore dies hard.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.10"><strong>7.10 What does the message:</strong> <tt>Mailbox
+     vulnerable - directory /var/spool/mail must have 1777 protection</tt>
+     <strong>mean? How can I fix this?</strong></a></p>
+
+  <dl>
+    <dd>
+      In order to update a mailbox in the default UNIX format, it is
+      necessary to create a lock file to prevent the mailer from delivering
+      mail while an update is in progress. Some systems use a directory
+      protection of 775, requiring that all mail handling programs be setgid
+      mail; or of 755, requiring that all mail handling programs be setuid
+      root.
+
+      <p>The IMAP toolkit does not run with any special privileges, and I
+      plan to keep it that way. It is antithetical to the concept of a
+      toolkit if users can't write their own programs to use it. Also, I've
+      had enough bad experiences with security bugs while running privileged;
+      the IMAP and POP servers have to be root when not logged in, in order
+      to be able to log themselves in. I don't want to go any deeper down
+      that slippery slope.</p>
+
+      <p>Directory protection 1777 is secure enough on most well-managed
+      systems. If you can't trust your users with a 1777 mail spool (petty
+      harassment is about the limit of the abuse exposure), then you have
+      much worse problems then that.</p>
+
+      <p>If you absolutely insist upon requiring privileges to create a lock
+      file, external file locking can be done via a setgid mail program named
+      /etc/mlock (this is defined by LOCKPGM in the c-client Makefile). If
+      the toolkit is unable to create a &lt;...mailbox...&gt;.lock file in
+      the directory by itself, it will try to call mlock to do it. I do not
+      recommend doing this for performance reasons.</p>
+
+      <p>A sample mlock program is included as part of imap-2007. We have
+      tried to make this sample program secure, but it has not been
+      thoroughly audited.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.11"><strong>7.11 What does the message:</strong> <tt>Mailbox is
+     open by another process, access is readonly</tt> <strong>mean? How do I
+     fix this?</strong></a></p>
+
+  <dl>
+    <dd>
+      A problem occurred in applying a lock to a /tmp lock file. Either some
+      other program has the mailbox open and won't relenquish it, or
+      something is wrong with the protection of /tmp or the lock.
+
+      <p>Make sure that the /tmp directory is protected 1777. Some security
+      scripts incorrectly set the protection of the /tmp directory to 775,
+      which disables /tmp for all non-privileged programs.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.12"><strong>7.12 What does the message:</strong> <tt>Can't get
+     write access to mailbox, access is readonly</tt>
+     <strong>mean?</strong></a></p>
+
+  <dl>
+    <dd>The mailbox file is write-protected against you.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.13"><strong>7.13 I set my POP3 client to "delete messages from
+     server" but they never get deleted. What is wrong?</strong></a></p>
+
+  <dl>
+    <dd>
+      Make sure that your mailbox is not read-only: that the mailbox is owned
+      by you and write enabled (protection 0600), and that the /tmp directory
+      is longer world-writeable. /tmp must be world-writeable because lots of
+      applications use it for scratch space. To fix this, do
+      <pre>
+
+ chmod 1777 /tmp
+</pre>as root.
+
+      <p>Make sure that your POP3 client issues a QUIT command when it
+      finishes. The POP3 protocol specifies that deletions are discarded
+      unless a proper QUIT is done.</p>
+
+      <p>Make sure that you are not opening multiple POP3 sessions to the
+      same mailbox. It is a requirement of the POP3 protocol than only one
+      POP3 session be in effect to a mailbox at a time, however some,
+      poorly-written POP3 clients violate this. Also, some background "check
+      for new mail" tasks also cause a violation. See the answer to the
+      <a href="#7.19">What does the syslog message: Killed (lost mailbox
+      lock) user=... host=... mean?</a> question for more details.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.14"><strong>7.14 What do messages such as:</strong></a></p>
+  <pre>
+ Message ... UID ... already has UID ...
+ Message ... UID ... less than ...
+ Message ... UID ... greater than last ...
+ Invalid UID ... in message ..., rebuilding UIDs
+</pre>
+
+  <p><strong>mean?</strong></p>
+
+  <dl>
+    <dd>
+      Something happened to corrupt the unique identifier regime in the
+      mailbox. In traditional UNIX-format mailboxes, this can happen if the
+      user deleted the "DO NOT DELETE" internal message.
+
+      <p>This problem is relatively harmless; a new valid unique identifier
+      regime will be created. The main effect is that any references to the
+      old UIDs will no longer be useful.</p>
+
+      <p>So, unless it is a chronic problem or you feel like debugging, you
+      can safely ignore these messages.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.15"><strong>7.15 What do the error messages:</strong></a></p>
+  <pre>
+ Unable to read internal header at ...
+ Unable to find CRLF at ...
+ Unable to parse internal header at ...
+ Unable to parse message date at ...
+ Unable to parse message flags at ...
+ Unable to parse message UID at ...
+ Unable to parse message size at ...
+ Last message (at ... ) runs past end of file ...
+</pre>
+
+  <p><strong>mean? I am using mbx format.</strong></p>
+
+  <dl>
+    <dd>
+      The mbx-format mailbox is corrupted and needs to be repaired.
+
+      <p>You should make an effort to find out why the corruption happened.
+      Was there an obvious system problem (crash or disk failure)? Did the
+      user accidentally access the file via NFS? Mailboxes don't get
+      corrupted by themselves; something caused the problem.</p>
+
+      <p>Some people have developed automated scripts, but if you're
+      comfortable using emacs it's pretty easy to fix it manually. Do
+      <em>not</em> use vi or any other editor unless you are certain that
+      editor can handle binary!!!</p>
+
+      <p>If you are not comfortable with emacs, or if the file is too large
+      to read with emacs, see the "step-by-step" technique later on for
+      another way of doing it.</p>
+
+      <p>After the word "at" in the error message is the byte position it got
+      to when it got unhappy with the file, e.g. if you see:</p>
+      <pre>
+ Unable to parse internal header at 43921: ne bombastic blurdybloop
+</pre>The problem occurs at the 43,931 byte in the file. That's the point you
+need to fix. c-client is expecting an internal header at that byte number,
+looking something like:
+      <pre>
+ 6-Jan-1998 17:42:24 -0800,1045;000000100001-00000001
+</pre>The format of this internal line is:
+      <pre>
+ dd-mmm-yyyy hh:mm:ss +zzzz,ssss;ffffffffFFFF-UUUUUUUU
+</pre>The only thing that is variable is the "ssss" field, it can be as many
+digits as needed. All other fields (inluding the "dd") are fixed width. So,
+the easiest thing to do is to look forward in the file for the next internal
+header, and delete everything from the error point to that internal header.
+
+      <p>Here's what to do if you want to be smarter and do a little bit more
+      work. Generally, you're in the middle of a message, and there's nothing
+      wrong with that message. The problem happened in the *previous*
+      message. So, search back to the previous internal header. Now, remember
+      that "ssss" field? That's the size of that message.</p>
+
+      <p>Mark where you are in the file, move the cursor to the line after
+      the internal header, and skip that many bytes ("ssss") forward. If
+      you're at the point of the error in the file, then that message is
+      corrupt. If you're at a different point, then perhaps the previous
+      message is corrupt and has a too long size count that "ate" into this
+      message.</p>
+
+      <p>Basically, what you need to do is make sure that all those size
+      counts are right, and that moving "ssss" bytes from the line after the
+      internal header will land you at another internal header.</p>
+
+      <p>Usually, once you know what you're looking at, it's pretty easy to
+      work out the corruption, and the best remedial action. Repair scripts
+      will make the problem go away but may not always do the smartest/best
+      salvage of the user's data. Manual repair is more flexible and usually
+      preferable.</p>
+
+      <p>Here is a step-by-step technique for fixing corrupt mbx files that's
+      a bit cruder than the procedure outlined above, but works for any size
+      file.</p>
+
+      <p>In this example, suppose that the corrupt file is INBOX, the error
+      message is</p>
+      <pre>
+ Unable to find CRLF at 132551754
+</pre>and the size of the INBOX file is 132867870 bytes.
+
+      <p>The first step is to split the mailbox file at the point of the
+      error:</p>
+
+      <ul>
+        <li>Rename the INBOX file to some other name, such as INBOX.bad.</li>
+
+        <li>Copy the first 132,551,754 bytes of INBOX.bad to another file,
+        such as INBOX.new.</li>
+
+        <li>Extract the trailing 316,116 bytes (132867870-132551754) of
+        INBOX.bad into another file, such as INBOX.tail.</li>
+
+        <li>You no longer need INBOX.bad. Delete it.</li>
+      </ul>In other words, use the number from the "Unable to find CRLF at"
+      as the point to split INBOX into two new files, INBOX.new and
+      INBOX.tail.
+
+      <p>Now, remove the erroneous data:</p>
+
+      <ul>
+        <li>Verify that you can open INBOX.new in IMAP or Pine.</li>
+
+        <li>The last message of INBOX.new is probably corrupted. Copy it to
+        another file, such as badmsg.1, then delete and expunge that last
+        message from INBOX.new</li>
+
+        <li>Locate the first occurance of text in INBOX.tail which looks like
+        an internal header, as described above.</li>
+
+        <li>Remove all the text which occurs prior to that point, and place
+        it into another file, such as badmsg.2. Note that in the case of a
+        single digit date, there is a leading space which must not be removed
+        (e.g. " 6-Nov-2001" not "6-Nov-2001").</li>
+      </ul>
+
+      <p>Reassemble the mailbox:</p>
+
+      <ul>
+        <li>Append INBOX.tail to INBOX.new.</li>
+
+        <li>You no longer need INBOX.tail. Delete it.</li>
+
+        <li>Verify that you can open INBOX.new in IMAP or Pine.</li>
+      </ul>
+
+      <p>Reinstall INBOX.new as INBOX:</p>
+
+      <ul>
+        <li>Check to see if you have received any new messages while
+        repairing INBOX.</li>
+
+        <li>If you haven't received any new messages while repairing INBOX,
+        just rename INBOX.new to INBOX.</li>
+
+        <li>If you have received new messages, be sure to copy the new
+        messages from INBOX to INBOX.new before doing the rename.</li>
+      </ul>
+
+      <p>You now have a working INBOX, as well as two files with corrupted
+      data (badmsg.1 and badmsg.2). There may be some useful data in the two
+      badmsg files that you might want to try salvaging; otherwise you can
+      delete the two badmsg files.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.16"><strong>7.16 What do the syslog messages:</strong></a></p>
+  <pre>
+
+ imap/tcp server failing (looping)
+ pop3/tcp server failing (looping)
+</pre>
+
+  <p><strong>mean? When it happens, the listed service shuts down. How can I
+  fix this?</strong></p>
+
+  <dl>
+    <dd>
+      The error message "server failing (looping), service terminated" is not
+      from either the IMAP or POP servers. Instead, it comes from inetd, the
+      daemon which listens for TCP connections to a number of servers,
+      including the IMAP and POP servers.
+
+      <p>inetd has a limit of 40 new server sessions per minute for any
+      particular service. If more than 40 sessions are initiated in a minute,
+      inetd will issue the "failing (looping), service terminated" message
+      and shut down the service for 10 minutes. inetd does this to prevent
+      system resource consumption by a client which is spawning infinite
+      numbers of servers. It should be noted that this is a denial of
+      service; however for some systems the alternative is a crash which
+      would be a worse denial of service!</p>
+
+      <p>For larger server systems, the limit of 40 is much too low. The
+      limit was established many years ago when a system typically only ran a
+      few dozen servers.</p>
+
+      <p>On some versions of inetd, such as the one distributed with most
+      versions of Linux, you can modify the <strong>/etc/inetd.conf</strong>
+      file to have a larger number of servers by appending a period followed
+      by a number after the <strong>nowait</strong> word for the server
+      entry. For example, if your existing /etc/inetd.conf line reads:</p>
+      <pre>
+ imap    stream  tcp     nowait  root    /usr/etc/imapd imapd
+</pre>try changing it to be:
+      <pre>
+ imap    stream  tcp     nowait.100  root    /usr/etc/imapd imapd
+</pre>Another example (using TCP wrappers):
+      <pre>
+ imap    stream  tcp     nowait  root    /usr/sbin/tcpd  imapd
+</pre>try changing it to be:
+      <pre>
+ imap    stream  tcp     nowait.100  root    /usr/sbin/tcpd  imapd
+
+</pre>to increase the limit to 100 sessions/minute.
+
+      <p>Before making this change, please read the information in "man
+      inetd" to determine whether or not your inetd has this feature. If it
+      does not, and you make this change, the likely outcome is that you will
+      disable IMAP service entirely.</p>
+
+      <p>Another way to fix this problem is to edit the inetd.c source code
+      (provided by your UNIX system vendor) to set higher limits, rebuild
+      inetd, install the new binary, and reboot your system. This should only
+      be done by a UNIX system expert. In the inetd.c source code, the limits
+      <strong>TOOMANY</strong> (normally 40) is the maximum number of new
+      server sessions permitted per minute, and <strong>RETRYTIME</strong>
+      (normally 600) is the number of seconds inetd will shut down the server
+      after it exceeds TOOMANY.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.17"><strong>7.17 What does the syslog message:</strong>
+     <tt>Mailbox lock file /tmp/.600.1df3 open failure: Permission
+     denied</tt> <strong>mean?</strong></a></p>
+
+  <dl>
+    <dd>
+      This usually means that some "helpful" security script person has
+      protected /tmp so that it is no longer world-writeable. /tmp must be
+      world-writeable because lots of applications use it for scratch space.
+      To fix this, do
+      <pre>
+ chmod 1777 /tmp
+
+</pre>as root.
+
+      <p>If that isn't the answer, check the protection of the named file. If
+      it is something other than 666, then either someone is hacking or some
+      "helpful" person modified the code to have a different default lock
+      file protection.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.18"><strong>7.18 What do the syslog messages:</strong></a></p>
+  <pre>
+ Command stream end of file, while reading line user=... host=...
+ Command stream end of file, while reading char user=... host=...
+ Command stream end of file, while writing text user=... host=...
+</pre>
+
+  <p><strong>mean?</strong></p>
+
+  <dl>
+    <dd>
+      This message occurs when the session is disconnected without a proper
+      LOGOUT (IMAP) or QUIT (POP) command being received by the server first.
+
+      <p>In many cases, this is perfectly normal; many client implementations
+      are impolite and do this. Some programmers think this sort of rudeness
+      is "more efficient".</p>
+
+      <p>The condition could, however, indicate a client or network
+      connectivity problem. The server has no way of knowing whether there's
+      a problem or just a rude client, so it issues this message instead of a
+      Logout.</p>
+
+      <p>Certain inferior losing clients disconnect abruptly after a failed
+      login, and instead of saying that the login failed, just say that they
+      can't access the mailbox. They then complain to the system manager, who
+      looks in the syslog and finds this message. Not very helpful, eh? See
+      the answer to the <a href="#7.4">Why can't I log in to the server? The
+      user name and password are right!</a> question.</p>
+
+      <p>If the user isn't reporting a problem, you can probably ignore this
+      message.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.19"><strong>7.19 Why did my POP or IMAP session suddenly
+     disconnect? The syslog has the message:</strong> <tt>Killed (lost
+     mailbox lock) user=... host=...</tt></a></p>
+
+  <dl>
+    <dd>
+      This message only happens when either the traditional UNIX mailbox
+      format or MMDF format is in use. This format only allows one session to
+      have the mailbox open read/write at a time.
+
+      <p>The servers assume that if a second session attempts to open the
+      mailbox, that means that the first session is probably owned by an
+      abandoned client. The common scenario here is a user who leaves his
+      client running at the office, and then tries to read his mail from
+      home. Through an internal mechanism called <em>kiss of death</em>, the
+      second session requests the first session to kill itself. When the
+      first session receives the "kiss of death", it issues the "Killed (lost
+      mailbox lock)" syslog message and terminates. The second session then
+      seizes read/write access, and becomes the new "first" session.</p>
+
+      <p>Certain poorly-designed clients routinely open multiple sessions to
+      the same mailbox; the users of those clients tend to get this message a
+      lot.</p>
+
+      <p>Another cause of this message is a background "check for new mail"
+      task which does its work by opening a POP session to server every few
+      seconds. They do this because POP doesn't have a way to announce new
+      mail.</p>
+
+      <p>The solution to both situations is to replace the client with a good
+      online IMAP client such as Pine. Life is too short to waste on POP
+      clients and poorly-designed IMAP clients.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.20"><strong>7.20 Why does my IMAP client show all the files on the
+     system, recursively from the UNIX root directory?</strong></a><br>
+  <a name="7.21"><strong>7.21 Why does my IMAP client show all of my files,
+     recursively from my UNIX home directory?</strong></a></p>
+
+  <dl>
+    <dd>
+      A well-written client should only show one level of hierarchy and then
+      stop, awaiting explicit user action before going lower. However, some
+      poorly-designed clients will recursively list all files, which may be a
+      very long list (especially if you have symbolic links to directories
+      that create a loop in the filesystem graph!).
+
+      <p>This behavior has also been observed in some third-party c-client
+      drivers, including maildir drivers. Consequently, this problem has even
+      been observed in Pine. It is important to understand that this is not a
+      problem in Pine or c-client; it is a problem in the third-party driver.
+      A Pine built without that third-party driver will not have this
+      problem.</p>
+
+      <p>See also the answer to <a href="#7.73">Why does my IMAP client show
+      all my files in my home directory?</a></p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.22"><strong>7.22 Why does my IMAP client show that I have
+     mailboxes named "#mhinbox", "#mh", "#shared", "#ftp", "#news", and
+     "#public"?</strong></a></p>
+
+  <dl>
+    <dd>
+      These are IMAP namespace names. They represent other hierarchies in
+      which messages may exist. These hierarchies may not necessarily exist
+      on a server, but the namespace name is still in the namespace list in
+      order to mark it as reserved.
+
+      <p>A few poorly-designed clients display all namespace names as if they
+      were top-level mailboxes in a user's list of mailboxes, whether or not
+      they actually exist. This is a flaw in those clients.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.23"><strong>7.23 Why does my IMAP client show all my files in my
+     home directory?</strong></a></p>
+
+  <dl>
+    <dd>
+      As distributed, the IMAP server is connected to your home directory by
+      default. It has no way of knowing what you might call "mail" as opposed
+      to "some other file"; in fact, you can use IMAP to access any file.
+
+      <p>Most clients have an option to configure your connected directory on
+      the IMAP server. For example, in Pine you can specify this as the
+      "Path" in your folder-collection, e.g.</p>
+      <pre>
+ Nickname  : Secondary Folders
+ Server    : imap.example.com
+ Path      : mail/
+ View      : 
+</pre>In this example, the user is connected to the "mail" subdirectory of
+his home directory.
+
+      <p>Other servers call this the "folder prefix" or similar term.</p>
+
+      <p>It is possible to modify the IMAP server so that all users are
+      automatically connected to some other directory, e.g. a subdirectory of
+      the user's home directory. Read the file CONFIG for more details.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.24"><strong>7.24 Why is there a long delay before I get connected
+     to the IMAP or POP server, no matter what client I use?</strong></a></p>
+
+  <dl>
+    <dd>
+      There are two common occurances of this problem:
+
+      <ul>
+        <li>You are running a system (e.g. certain versions of Linux) which
+        by default attempts to connect to an "IDENT" protocol (port 113)
+        server on your client. However, a firewall or NAT box is blocking
+        connections to that port, so the connection attempt times out.
+
+          <p>The IDENT protocol is a well-known bad idea that does not
+          deliver any real security but causes incredible problems. The idea
+          is that this will give the server a record of the user name, or at
+          least what some program listening on port 113 says is the user
+          name. So, if somebody coming from port nnnnn on a system does
+          something bad, IDENT may give you the userid of the bad guy.</p>
+
+          <p>The problem is, IDENT is only meaningful on a timesharing system
+          which has an administrator who is privileged and users who are not.
+          It is of no value on a personal system which has no separate
+          concept of "system administrator" vs. "unprivileged user".</p>
+
+          <p>On either type of system, security-minded people either turn
+          IDENT off or replace it with an IDENT server that lies. Among other
+          things, IDENT gives spammers the ability to harvest email addresses
+          from anyone who connects to a web page.</p>
+
+          <p>This problem has been showing up quite frequently on systems
+          which use xinetd instead of inetd. Look for files named
+          /etc/xinetd.conf, /etc/xinetd.d/imapd, /etc/inetd.d/ipop2d, and
+          /etc/xinetd.d/ipop3d. In those files, look for lines containing
+          "USERID", e.g.</p>
+          <pre>
+ log_on_success += USERID
+</pre>Hunt down such lines, and delete them ruthlessly from all files in
+which they occur. Don't be shy about it.
+        </li>
+
+        <li>The DNS is taking a long time to do a reverse DNS (PTR record)
+        lookup of the IP address of your client. This is a problem in your
+        DNS, which either you or you ISP need to resolve. Ideally, the DNS
+        should return the client's name; but if it can't it should at least
+        return an error quickly.</li>
+      </ul>
+
+      <p>As you may have noticed, neither of these are actual problems in the
+      IMAP or POP servers; they are configuration issues with either your
+      system or your network infrastructure. If this is all new to you, run
+      (don't walk) to the nearest technical bookstore and get yourself a good
+      pedagogical text on system administration for the type of system you
+      are running.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.25"><strong>7.25 Why is there a long delay in Pine or any other
+     c-client based application call before I get connected to the IMAP
+     server? The hang seems to be in the c-client mail_open() call. I don't
+     have this problem with any other IMAP client. There is no delay
+     connecting to a POP3 or NNTP server with mail_open().</strong></a></p>
+
+  <dl>
+    <dd>
+      By default, the c-client library attempts to make a connection through
+      rsh (and ssh, if you enable that). If the command:
+      <pre>
+ rsh imapserver exec /etc/rimapd
+
+</pre>(or ssh if that is enabled) returns with a "* PREAUTH" response, it
+will use the resulting rsh session as the IMAP session and not require an
+authentication step on the server.
+
+      <p>Unfortunately, rsh has a design error that treats "TCP connection
+      refused" as "temporary failure, try again"; it expects the "rsh not
+      allowed" case to be implemented as a successful connection followed by
+      an error message and close the connection.</p>
+
+      <p>It must be emphasized that this is a bug in rsh. It is <em>not</em>
+      a bug in the IMAP toolkit.</p>
+
+      <p>The use of rsh can be disabled in any the following ways:</p>
+
+      <ul>
+        <li>You can disable it for this particular session by either:
+
+          <ul>
+            <li>setting an explicit port number in the mailbox name, e.g.
+              <pre>
+ {imapserver.foo.com:143}INBOX
+</pre>
+            </li>
+
+            <li>using SSL (the /ssl switch)</li>
+          </ul>
+        </li>
+
+        <li>You can disable rsh globally by setting the rsh timeout value to
+        0 with the call:
+          <pre>
+ mail_parameters (NIL,SET_RSHTIMEOUT,0);
+</pre>
+        </li>
+      </ul>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.26"><strong>7.26 Why does a message sometimes get split into two
+     or more messages on my SUN system?</strong></a></p>
+
+  <dl>
+    <dd>
+      This is caused by an interaction of two independent design problems in
+      SUN mail software. The first problem is that the "forward message"
+      option in SUN's <em>mail tool</em> program includes the internal "From
+      " header line in the text that it forwarded. This internal header line
+      is specific to traditional UNIX mailbox files and is not suitable for
+      use in forwarded messages.
+
+      <p>The second problem is that the mail delivery agent assumes that mail
+      reading programs will not use the traditional UNIX mailbox format but
+      instead an incompatible variant that depends upon a
+      <em>Content-Length:</em> message header. Content-Length is widely
+      recognized to have been a terrible mistake, and is no longer
+      recommended for use in mail (it is used in other facilities that use
+      MIME).</p>
+
+      <p>One symptom of the problem is that under certain circumstances, a
+      message may get broken up into several messages. I'm also aware of
+      security bugs caused by programs that foolishly trust "Content-Length:"
+      headers with evil values.</p>
+
+      <p>To fix the mailer on your system, edit your sendmail.cf to change
+      the <strong>Mlocal</strong> line to have the <strong>-E</strong> flag.
+      A typical entry will lool like:</p>
+      <pre>
+ Mlocal,	P=/usr/lib/mail.local, F=flsSDFMmnPE, S=10, R=20,
+		A=mail.local -d $u
+</pre>This fix will also work around the problem with mail tool, because it
+will insert a "&gt;" before the internal header line to prevent it from being
+interpreted by mail reading software as an internal header line.
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.27"><strong>7.27 Why did my POP or IMAP session suddenly
+     disconnect? The syslog has the message:</strong></a></p>
+  <pre>
+ Autologout user=&lt;...my user name...&gt; host=&lt;...my client system...&gt;
+
+</pre>
+
+  <dl>
+    <dd>
+      This is a problem in your client.
+
+      <p>In the case of IMAP, it failed to communicate with the IMAP server
+      for over 30 minutes; in the case of POP, it failed to communicate with
+      the POP server for over 10 minutes.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.28"><strong>7.28 What does the UNIX error message:</strong>
+     <tt>TLS/SSL failure: myserver: SSL negotiation failed</tt>
+     <strong>mean?</strong></a><br>
+  <a name="7.29"><strong>7.29 What does the PC error message:</strong>
+     <tt>TLS/SSL failure: myserver: Unexpected TCP input disconnect</tt>
+     <strong>mean?</strong></a></p>
+
+  <dl>
+    <dd>
+      This usually means that an attempt to negotiate TLS encryption via the
+      STARTTLS command failed, because the server advertises STARTTLS
+      functionality, but doesn't actually have it (e.g. because no
+      certificates are installed).
+
+      <p>Use the /notls option in the mailbox name to disable TLS
+      negotiation.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.30"><strong>7.30 What does the error message:</strong> <tt>TLS/SSL
+     failure: myserver: Server name does not match certificate</tt>
+     <strong>mean?</strong></a></p>
+
+  <dl>
+    <dd>
+      An SSL or TLS session encryption failed because the server name in the
+      server's certificate does not match the name that you gave it. This
+      could indicate that the server is not really the system you think that
+      it is, but can be also be called if you gave a nickname for the server
+      or name that was not fully-qualified. You must use the fully-qualified
+      domain name for the server in order to validate its certificate
+
+      <p>Use the /novalidate-cert option in the mailbox name to disable
+      validation of the certificate.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.31"><strong>7.31 What does the UNIX error message:</strong>
+     <tt>TLS/SSL failure: myserver: self-signed certificate</tt>
+     <strong>mean?</strong></a><br>
+  <a name="7.32"><strong>7.32 What does the PC error message:</strong>
+     <tt>TLS/SSL failure: myserver: Self-signed certificate or untrusted
+     authority</tt> <strong>mean?</strong></a></p>
+
+  <dl>
+    <dd>
+      An SSL or TLS session encryption failed because your server's
+      certificate is "self-signed"; that is, it is not signed by any
+      Certificate Authority (CA) and thus can not be validated. A CA-signed
+      certificate costs money, and some smaller sites either don't want to
+      pay for it or haven't gotten one yet. The bad part about this is that
+      this means there is no guarantee that the server is really the system
+      you think that it is.
+
+      <p>Use the /novalidate-cert option in the mailbox name to disable
+      validation of the certificate.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.33"><strong>7.33 What does the UNIX error message:</strong>
+     <tt>TLS/SSL failure: myserver: unable to get local issuer
+     certificate</tt> <strong>mean?</strong></a></p>
+
+  <dl>
+    <dd>
+      An SSL or TLS session encryption failed because your system does not
+      have the Certificate Authority (CA) certificates installed on OpenSSL's
+      certificates directory. On most systems, this directory is
+      /usr/local/ssl/certs). As a result, it is not possible to validate the
+      server's certificate.
+
+      <p>If CA certificates are properly installed, you should see
+      factory.pem and about a dozen other .pem names such as
+      thawteCb.pem.</p>
+
+      <p>As a workaround, you can use the /novalidate-cert option in the
+      mailbox name to disable validation of the certificate; however, note
+      that you are then vulnerable to various security attacks by bad
+      guys.</p>
+
+      <p>The correct fix is to copy all the files from the certs/ directory
+      in the OpenSSL distribution to the /usr/local/ssl/certs (or whatever)
+      directory. Note that you need to do this after building OpenSSL,
+      because the OpenSSL build creates a number of needed symbolic links.
+      For some bizarre reason, the OpenSSL "make install" doesn't do this for
+      you, so you must do it manually.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.34"><strong>7.34 Why does reading certain messages hang when using
+     Netscape? It works fine with Pine!</strong></a></p>
+
+  <dl>
+    <dd>
+      There are two possible causes.
+
+      <p>Check the mail syslog. If you see the message "Killed (lost mailbox
+      lock)" for the impacted user(s), read the FAQ entry regarding that
+      message.</p>
+
+      <p>Check the affected mailbox to see if there are embedded NUL
+      characters in the message. NULs in message texts are a technical
+      violation of both the message format and IMAP specifications. Most
+      clients don't care, but apparently Netscape does.</p>
+
+      <p>You can work around this by rebuilding imapd with the
+      <strong>NETSCAPE_BRAIN_DAMAGE</strong> option set (see
+      src/imapd/Makefile); this will cause imapd to convert all NULs to 0x80
+      characters. A better solution is to enable the feature in your MTA to
+      MIME-convert messages with binary content. See the documentation for
+      your MTA for how to do this.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.35"><strong>7.35 Why does Netscape say that there's a problem with
+     the IMAP server and that I should "Contact your mail server
+     administrator."?</strong></a></p>
+
+  <dl>
+    <dd>
+      Certain versions of Netscape do this when you click the Manage Mail
+      button, which uses an undocumented feature of Netscape's proprietary
+      IMAP server.
+
+      <p>You can work around this by rebuilding imapd with the
+      <strong>NETSCAPE_BRAIN_DAMAGE</strong> option set (see
+      src/imapd/Makefile) to a URL that points either to an alternative IMAP
+      client (e.g. Pine) or perhaps to a homebrew mail account management
+      page.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.36"><strong>7.36 Why is one user creating huge numbers of IMAP or
+     POP server sessions?</strong></a></p>
+
+  <dl>
+    <dd>The user is probably using Outlook Express, Eudora, or a similar
+    program. See the answer to the <a href="#7.5">Help! My load average is
+    soaring and I see hundreds of POP and IMAP servers, many logged in as the
+    same user!</a> question.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.37"><strong>7.37 Why don't I get any new mail notifications from
+     Outlook Express or Outlook after a while?</strong></a></p>
+
+  <dl>
+    <dd>
+      This is a known bug in Outlook Express. Microsoft is aware of the
+      problem and its cause. They have informed us that they do not have any
+      plans to fix it at the present time.
+
+      <p>The problem is also reported in Outlook 2000, but not verified.</p>
+
+      <p>Outlook Express uses the IMAP IDLE command to avoid having to "ping"
+      the server every few minutes for new mail. Unfortunately, Outlook
+      Express overlooks the part in the IDLE specification which requires
+      that a client terminate and restart the IDLE before the IMAP 30 minute
+      inactivity autologout timer triggers.</p>
+
+      <p>When this happens, Outlook Express displays "Not connected" at the
+      bottom of the window. Since it's no longer connected to the IMAP
+      server, it isn't going to notice any new mail.</p>
+
+      <p>As soon as the user does anything that would cause an IMAP
+      operation, Outlook Express will reconnect and new mail will flow again.
+      If the user does something that causes an IMAP operation at least every
+      29 minutes, the problem won't happen.</p>
+
+      <p>Modern versions of imapd attempt to work around the problem by
+      automatically reporting fake new mail after 29 minutes. This causes
+      Outlook Express to exit the IDLE state; as soon as this happens imapd
+      revokes the fake new mail. As long as this behavior isn't known to
+      cause problems with other clients, this workaround will remain in
+      imapd.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.38"><strong>7.38 Why don't I get any new mail notifications from
+     Entourage?</strong></a></p>
+
+  <dl>
+    <dd>
+      This is a known bug in Entourage.
+
+      <p>You built an older version of imapd with the
+      <strong>MICROSOFT_BRAIN_DAMAGE</strong> option set, in order to disable
+      support for the IDLE command. However, Entourage won't get new mail
+      unless IDLE command support exists.</p>
+
+      <p>Note: the MICROSOFT_BRAIN_DAMAGE option no longer exists in modern
+      versions, as the Outlook Express problem which it attempted to solve
+      has been worked around in another way.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.39"><strong>7.39 Why doesn't Entourage work at
+     all?</strong></a></p>
+
+  <dl>
+    <dd>
+      It's hard to know. Entourage breaks almost every rule in the book for
+      IMAP. It is highly instructive to do a packet trace on Entourage, as an
+      example of how <em>not</em> to use IMAP. It does things like STATUS
+      (MESSAGES) on the currently selected mailbox and re-fetching the same
+      static data over and over again.
+
+      <p>It seems that every time we understand what it is doing wrong in
+      Entourage and come up with a workaround, we learn about something else
+      that's broken.</p>
+
+      <p>Try building imapd with the <strong>ENTOURAGE_BRAIN_DAMAGE</strong>
+      option set, in order to disable the diagnostic that occurs when doing
+      STATUS on the currently selected mailbox.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.40"><strong>7.40 Why doesn't Netscape Notify (NSNOTIFY.EXE) work
+     at all?</strong></a></p>
+
+  <dl>
+    <dd>
+      This is a bug in NSNOTIFY; it doesn't handle unsolicited data from the
+      server correctly.
+
+      <p>Fortunately, there is no reason to use this program with IMAP;
+      NSNOTIFY is a polling program to let you know when new mail has
+      appeared in your maildrop. This is necessary with POP; but since IMAP
+      dynamically announces new mail in the session you're better off (and
+      will actually cause less load on the server!) keeping your mail reading
+      program's IMAP session open and let IMAP do the notifying for you.</p>
+
+      <p>Consequently, the recommended fix for the NSNOTIFY problem is to
+      delete the NSNOTIFY binary.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.41"><strong>7.41 Why can't I connect via SSL to Eudora? It says
+     the connection has been broken, and in the server syslogs I see "Command
+     stream end of file".</strong></a></p>
+
+  <dl>
+    <dd>There is a report that you can fix the problem by going into Eudora's
+    advanced network configuration menu and increasing the network buffer
+    size to 8192.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.42"><strong>7.42 Sheesh. Aren't there <em>any</em> good IMAP
+     clients out there?</strong></a></p>
+
+  <dl>
+    <dd>
+      Yes!
+
+      <p>Pine is a <em>wonderful</em> client. It's fast, it uses IMAP well,
+      and it generates text mail (life is too short to waste on HTML mail).
+      Also, there are some really wonderful things in progress in the Pine
+      world.</p>
+
+      <p>There are some good GUI clients out there, mostly from smaller
+      vendors. Without naming names, look for the vendors who are active in
+      the IMAP protocol development community, and their products.</p>
+
+      <p>Netscape, Eudora, and Outlook <em>can</em> be configured with enough
+      effort to be good citizens and work well for users, <em>but</em> they
+      can also be badly misconfigured, and often the misconfiguration is the
+      default.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.43"><strong>7.43 But wait! PC Pine (or other PC program build with
+     c-client) crashes with the message</strong> <tt>incomplete SecBuffer
+     exceeds maximum buffer size</tt> <strong>when I use SSL connections.
+     This is a bug in c-client, right?</strong></a></p>
+
+  <dl>
+    <dd>
+      It's a bug in the Microsoft SChannel.DLL, which implements SSL.
+      Microsoft admits it (albeit with an unstatement: "it's not fully RFC
+      compliant"). The problem is that SChannel indicates that the maximum
+      SSL packet data size is 5 bytes smaller than the actual maximum. Thus,
+      any IMAP server which transmits a maximum sized SSL packet will not
+      work with PC Pine or any other program which uses SChannel.
+
+      <p>It can take a while for the problem to show up. The client has to do
+      something that causes at least 16K of contiguous data. Many clients do
+      partial fetching, which tends to reduce the number of cases where this
+      can happen. However, <em>all</em> software which uses SChannel to
+      support SSL is affected by this bug.</p>
+
+      <p>This problem does not affect UNIX code, since OpenSSL is used on
+      UNIX.</p>
+
+      <p>This problem most recently showed up with the CommunigatePro IMAP
+      server. They have an update which trims down their maximum contiguous
+      data to less than 16K, in order to work around the problem.</p>
+
+      <p>This problem has also shown up with the Exchange IMAP server with
+      UNIX clients (including Pine built with an older version of c-client)
+      which sends full-sized 16K SSL packets. Modern c-client works around
+      the problem by trimming down its maximum outgoing SSL packet size to
+      8K.</p>
+
+      <p>Microsoft has developed a hotfix for this bug. Look up MSKB article
+      number 300562. Contrary to the article text which implies that this is
+      a Pine issue, this bug also affect Microsoft Exchange server with *any*
+      UNIX based client that transmits full-sized SSL payloads.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.44"><strong>7.44 My qpopper users keep on getting the DON'T DELETE
+     THIS MESSAGE -- FOLDER INTERNAL DATA if they also use Pine or IMAP. How
+     can I fix this?</strong></a></p>
+
+  <dl>
+    <dd>
+      This is an incompatibility between qpopper and the c-client library
+      used by Pine, imapd, and ipop[23]d.
+
+      <p>Assuming that you want to continue using qpopper, look into
+      qpopper's <strong>--enable-uw-kludge-flag</strong> configuration flag,
+      which is documented as "check for and hide UW 'Folder Internal Data'
+      messages".</p>
+
+      <p>The other alternative is to switch from qpopper to ipop3d.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.45"><strong>7.45 Help! I installed the servers but I can't connect
+     to them from my client!</strong></a></p>
+
+  <dl>
+    <dd>
+      Review the installation instructions carefully. Make sure that you have
+      not skipped any of the steps. Make sure that you have made the correct
+      entries in the configuration files; pay careful attention to the exact
+      spelling of the service names and the path names. Make sure as well
+      that you have properly restarted inetd.
+
+      <p>If you have a system with Yellow Pages/NIS such as Solaris, have you
+      updated the service names there as well as in /etc/services?</p>
+
+      <p>If you have a system with TCP wrappers, have you properly updated
+      the TCP wrapper files (e.g. /etc/hosts.allow and /etc/hosts.deny) for
+      the servers?</p>
+
+      <p>If you have a system which uses xinetd instead of inetd, have you
+      made sure that you have made the correct corresponding xinetd changes
+      for those services?</p>
+
+      <p>Try telneting to the server port (143 for IMAP, 110 for POP3). If
+      you get a "refused" error, that probably means that you don't have the
+      service set up in inetd.conf. If the connection opens and then closes
+      with no message, the service is set up, but either the path name of the
+      server binary in inetd.conf is wrong or your TCP wrappers are
+      configured to deny access.</p>
+
+      <p>If you don't know how to make the corresponding changes to these
+      files, seek the help of a local expert for your system.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.46"><strong>7.46 Why do I get the message</strong> <tt>Can not
+     authenticate to SMTP server: 421 SMTP connection went away!</tt>
+     <strong>and why did this happen? There was also something about</strong>
+     <tt>SECURITY PROBLEM: insecure server advertised AUTH=PLAIN</tt></a></p>
+
+  <dl>
+    <dd>
+      Some versions of qmail, including that running on mail.smtp.yahoo.com,
+      disconnect the SMTP session if you fail to authenticate prior to
+      attempting to transmit mail. An attempt to authenticate was made, but
+      it failed because the server had already disconnected.
+
+      <p>To work around this, you need to specify /user=... in the host name
+      specification.</p>
+
+      <p>The SECURITY PROBLEM came about because the server advertised the
+      AUTH=PLAIN SASL authentication mechanism outside of a TLS-encrypted
+      session, in violation of RFC 4616. This message is just a warning, and
+      in fact occurred after the server had disconnected.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.47"><strong>7.47 Why do I get the message</strong> <tt>SMTP
+     Authentication cancelled</tt> <strong>and why did this happen? There was
+     also something about</strong> <tt>SECURITY PROBLEM: insecure server
+     advertised AUTH=PLAIN</tt></a></p>
+
+  <dl>
+    <dd>
+      This is a bug in the SMTP server.
+
+      <p>Some versions of qmail, including that running on
+      mail.smtp.yahoo.com, have a bug in their implementation of SASL in
+      their SMTP server, which renders it non-compliant with the
+      standard.</p>
+
+      <p>If the client does not provide an initial response in the command
+      line for an authentication mechanism whose profile does not have an
+      initial challenge, qmail issues a bogus response:</p>
+      <pre>
+ 334 ok, go on
+</pre>The problem is the "ok, go on". This violates RFC 4954's requirement
+that the text part in a 334 response be a BASE64 encoded string; in other
+words, it is a protocol syntax error.
+
+      <p>In the case of AUTH=PLAIN, RFC 4422 (page 7) requires that the
+      encoded string have no data. In other words, the appropropiate
+      standards-compliant server response is "334" followed by a SPACE and a
+      CRLF.</p>
+
+      <p>The SECURITY PROBLEM came about because the server advertised the
+      AUTH=PLAIN SASL authentication mechanism outside of a TLS-encrypted
+      session, in violation of RFC 4616. This message is just a warning, and
+      is not related the "Authentication cancelled" problem.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="7.48"><strong>7.48 Why do I get the message</strong> <tt>Invalid
+     base64 string</tt> <strong>when I try to authenticate to a Cyrus
+     server?</strong></a></p>
+
+  <dl>
+    <dd>
+      This slightly misleading message is the way that a Cyrus server
+      indicates that an authentication exchange was cancelled. It is not
+      indicative of a bug or protocol violation.
+
+      <p>The most common reason that this happens is if the Cyrus server
+      offers Kerberos authentication, c-client is built with Kerberos
+      support, but your client system is not within the Kerberos realm. In
+      this case, the client code will try to authenticate via Kerberos, fail
+      to get the Kerberos credentials, cancel the authentication attempt, and
+      try the next available authentication technology.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><br></p>
+
+  <h2><a name="additional">8. Where to Go For Additional Information</a></h2>
+  <hr>
+
+  <p><a name="8.1"><strong>8.1 Where can I go to ask questions?</strong></a><br>
+  <a name="8.2"><strong>8.2 I have some ideas for enhancements to IMAP. Where
+     should I go?</strong></a></p>
+
+  <dl>
+    <dd>
+      If you have questions about the IMAP protocol, or want to participate
+      in discussions of future directions of the IMAP protocol, the
+      appropriate mailing list is imap-protocol@u.washington.edu. You can
+      subscribe to this list via <a href=
+      "mailto:imap-protocol-request@u.washington.edu"><tt>imap-protocol-request@u.washington.edu</tt></a>
+
+      <p>If you have questions about this software, you can send me email
+      directly or use the imap-uw@u.washington.edu mailing list. You can
+      subscribe to this list via <a href=
+      "mailto:imap-uw-request@u.washington.edu"><tt>imap-uw-request@u.washington.edu</tt></a></p>
+
+      <p>If you have general questions about the use of IMAP software
+      (not specific to the UW IMAP toolkit) use the
+      imap-use@u.washington.edu mailing list. You can subscribe to
+      this list via <a href=
+      "mailto:imap-use-request@u.washington.edu"><tt>imap-use-request@u.washington.edu</tt></a></p>
+
+      <p>You must be a subscriber to post to these lists.  As an
+      alternative, you can use the
+      <strong>comp.mail.imap</strong> newsgroup.</p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="8.3"><strong>8.3 Where can I read more about IMAP and other email
+     protocols?</strong></a></p>
+
+  <dl>
+    <dd>We recommend <em>Internet Email Protocols: A Developer's Guide</em>,
+    by Kevin Johnson, published by Addison Wesley, ISBN 0-201-43288-9.</dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+  <hr>
+
+  <p><a name="8.4"><strong>8.4 Where can I find out more about setting up and
+     administering an IMAP server?</strong></a></p>
+
+  <dl>
+    <dd>
+      We recommend <em>Managing IMAP</em>, by Dianna Mullet &amp; Kevin
+      Mullet, published by O'Reilly, ISBN 0-596-00012-X.
+
+      <p>This book also has an excellent comparison of the UW and Cyrus IMAP
+      servers.<br></p>
+    </dd>
+  </dl>
+
+  <p><a href="#top">Back to top</a></p>
+
+  <p>Last Updated: 15 November 2007</p>
+
+<!--chtml include "//imap/incs/bottom.inc"-->
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/FAQ.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,2993 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+                    IMAP Toolkit Frequently Asked Questions
+
+Table of Contents
+
+     * 1. General/Software Feature Questions
+          + 1.1 Can I set up a POP or IMAP server on UNIX/Linux/OSF/etc.?
+          + 1.2 I am currently using qpopper as my POP3 server on UNIX.
+            Do I need to replace it with ipop3d in order to run imapd?
+          + 1.3 Can I set up a POP or IMAP server on Windows XP, 2000,
+            NT, Me, 98, or 95?
+          + 1.4 Can I set up a POP or IMAP server on Windows 3.1 or DOS?
+          + 1.5 Can I set up a POP or IMAP server on Macintosh?
+          + 1.6 Can I set up a POP or IMAP server on VAX/VMS?
+          + 1.7 Can I set up a POP or IMAP server on TOPS-20?
+          + 1.8 Are hierarchical mailboxes supported?
+          + 1.9 Are "dual-use" mailboxes supported?
+          + 1.10 Can I have a mailbox that has both messages and
+            sub-mailboxes?
+          + 1.11 What is the difference between "mailbox" and "folder"?
+          + 1.12 What is the status of internationalization?
+          + 1.13 Can I use SSL?
+          + 1.14 Can I use TLS and the STARTTLS facility?
+          + 1.15 Can I use CRAM-MD5 authentication?
+          + 1.16 Can I use APOP authentication?
+          + 1.17 Can I use Kerberos V5?
+          + 1.18 Can I use PAM for plaintext passwords?
+          + 1.19 Can I use Kerberos 5 for plaintext passwords?
+          + 1.20 Can I use AFS for plaintext passwords?
+          + 1.21 Can I use DCE for plaintext passwords?
+          + 1.22 Can I use the CRAM-MD5 database for plaintext passwords?
+          + 1.23 Can I disable plaintext passwords?
+          + 1.24 Can I disable plaintext passwords on unencrypted
+            sessions, but allow them on encrypted sessions?
+          + 1.25 Can I use virtual hosts?
+          + 1.26 Can I use RPOP authentication?
+          + 1.27 Can I use Kerberos V4?
+          + 1.28 Is there support for S/Key or OTP?
+          + 1.29 Is there support for NTLM or SPA?
+          + 1.30 Is there support for mh?
+          + 1.31 Is there support for qmail and the maildir format?
+          + 1.32 Is there support for the Cyrus mailbox format?
+          + 1.33 Is this software Y2K compliant?
+     * 2. What Do I Need to Build This Software?
+          + 2.1 What do I need to build this software with SSL on UNIX?
+          + 2.2 What do I need to build this software with Kerberos V on
+            UNIX?
+          + 2.3 What do I need to use a C++ compiler with this software
+            to build my own application?
+          + 2.4 What do I need to build this software on Windows?
+          + 2.5 What do I need to build this software on DOS?
+          + 2.6 Can't I use Borland C to build this software on the PC?
+          + 2.7 What do I need to build this software on the Mac?
+          + 2.8 What do I need to build this software on VMS?
+          + 2.9 What do I need to build this software on TOPS-20?
+          + 2.10 What do I need to build this software on Amiga or OS/2?
+          + 2.11 What do I need to build this software on Windows CE?
+     * 3. Build and Configuration Questions
+          + 3.1 How do I configure the IMAP and POP servers on UNIX?
+          + 3.2 I built and installed the servers according to the BUILD
+            instructions. It can't be that easy. Don't I need to write a
+            config file?
+          + 3.3 How do I make the IMAP and POP servers look for INBOX at
+            some place other than the mail spool directory?
+          + 3.4 How do I make the IMAP server look for secondary folders
+            at some place other than the user's home directory?
+          + 3.5 How do I configure SSL?
+          + 3.6 How do I configure TLS and the STARTTLS facility?
+          + 3.7 How do I build/install OpenSSL and obtain/create
+            certificates for use with SSL?
+          + 3.8 How do I configure CRAM-MD5 authentication?
+          + 3.9 How do I configure APOP authentication?
+          + 3.10 How do I configure Kerberos V5?
+          + 3.11 How do I configure PAM for plaintext passwords?
+          + 3.12 It looks like all I have to do to make the server use
+            Kerberos is to build with PAM on my Linux system, and set it
+            up in PAM for Kerberos passwords. Right?
+          + 3.13 How do I configure Kerberos 5 for plaintext passwords?
+          + 3.14 How do I configure AFS for plaintext passwords?
+          + 3.15 How do I configure DCE for plaintext passwords?
+          + 3.16 How do I configure the CRAM-MD5 database for plaintext
+            passwords?
+          + 3.17 How do I disable plaintext passwords?
+          + 3.18 How do I disable plaintext passwords on unencrypted
+            sessions, but allow them in SSL or TLS sessions?
+          + 3.19 How do I configure virtual hosts?
+          + 3.20 Why do I get compiler warning messages such as:
+               o passing arg 3 of `scandir' from incompatible pointer
+                 type
+               o Pointers are not assignment-compatible.
+               o Argument #4 is not the correct type.
+            during the build?
+          + 3.21 Why do I get compiler warning messages such as
+               o Operation between types "void(*)(int)" and "void*" is
+                 not allowed.
+               o Function argument assignment between types "void*" and
+                 "void(*)(int)" is not allowed.
+               o Pointers are not assignment-compatible.
+               o Argument #5 is not the correct type.
+            during the build?
+          + 3.22 Why do I get linker warning messages such as:
+               o mtest.c:515: the `gets' function is dangerous and should
+                 not be used.
+            during the build? Isn't this a security bug?
+          + 3.23 Why do I get linker warning messages such as:
+               o auth_ssl.c:92: the `tmpnam' function is dangerous and
+                 should not be used.
+            during the build? Isn't this a security bug?
+          + 3.24 OK, suppose I see a warning message about a function
+            being "dangerous and should not be used" for something other
+            than this gets() or tmpnam() call?
+     * 4. Operational Questions
+          + 4.1 How can I enable anonymous IMAP logins?
+          + 4.2 How do I set up an alert message that each IMAP user will
+            see?
+          + 4.3 How does the c-client library choose which of its several
+            mechanisms to use to establish an IMAP connection to the
+            server? I noticed that it can connect on port 143, port 993,
+            via rsh, and via ssh.
+          + 4.4 I am using a TLS-capable IMAP server, so I don't need to
+            use /ssl to get encryption. However, I want to be certain
+            that my session is TLS encrypted before I send my password.
+            How to I do this?
+          + 4.5 How do I use one of the alternative formats described in
+            the formats.txt document? In particular, I hear that mbx
+            format will give me better performance and allow shared
+            access.
+          + 4.6 How do I set up shared mailboxes?
+          + 4.7 How can I make the server syslogs go to someplace other
+            than the mail syslog?
+     * 5. Security Questions
+          + 5.1 I see that the IMAP server allows access to arbitary
+            files on the system, including /etc/passwd! How do I disable
+            this?
+          + 5.2 I've heard that IMAP servers are insecure. Is this true?
+          + 5.3 How do I know that I have the most secure version of the
+            server?
+          + 5.4 I see all these strcpy() and sprintf() calls, those are
+            unsafe, aren't they?
+          + 5.5 Those /tmp lock files are protected 666, is that really
+            right?
+     * 6. Why Did You Do This Strange Thing? Questions
+          + 6.1 Why don't you use GNU autoconfig / automake /
+            autoblurdybloop?
+          + 6.2 Why do you insist upon a build with -g? Doesn't it waste
+            disk and memory space?
+          + 6.3 Why don't you make c-client a shared library?
+          + 6.4 Why don't you use iconv() for internationalization
+            support?
+          + 6.5 Why is the IMAP server connected to the home directory by
+            default?
+          + 6.6 I have a Windows system. Why isn't the server plug and
+            play for me?
+          + 6.7 I looked at the UNIX SSL code and saw that you have the
+            SSL data payload size set to 8192 bytes. SSL allows 16K; why
+            aren't you using the full size?
+          + 6.8 Why is an mh format INBOX called #mhinbox instead of just
+            INBOX?
+          + 6.9 Why don't you support the maildir format?
+          + 6.10 Why don't you support the Cyrus format?
+          + 6.11 Why is it creating extra forks on my SVR4 system?
+          + 6.12 Why are you so fussy about the date/time format in the
+            internal "From " line in traditional UNIX mailbox files? My
+            other mail program just considers every line that starts with
+            "From " to be the start of the message.
+          + 6.13 Why is traditional UNIX format the default format?
+          + 6.14 Why do you write this "DON'T DELETE THIS MESSAGE --
+            FOLDER INTERNAL DATA" message at the start of traditional
+            UNIX and MMDF format mailboxes?
+          + 6.15 Why don't you stash the mailbox metadata in the first
+            real message of the mailbox instead of writing this fake
+            FOLDER INTERNAL DATA message?
+          + 6.16 Why aren't "dual-use" mailboxes the default?
+          + 6.17 Why do you use ucbcc to build on Solaris?
+          + 6.18 Why should I care about some old system with BSD
+            libraries? cc is the right thing on my Solaris system!
+          + 6.19 Why do you insist upon writing .lock files in the spool
+            directory?
+          + 6.20 Why should I care about compatibility with the past?
+     * 7. Problems and Annoyances
+          + 7.1 Help! My INBOX is empty! What happened to my messages?
+          + 7.2 Help! All my messages in a non-INBOX mailbox have been
+            concatenated into one message which claims to be from me and
+            has a subject of the file name of the mailbox! What's going
+            on?
+          + 7.3 Why do I get the message:
+               o CREATE failed: Can't create mailbox node xxxxxxxxx: File
+                 exists
+            and how do I fix it?
+          + 7.4 Why can't I log in to the server? The user name and
+            password are right!
+          + 7.5 Help! My load average is soaring and I see hundreds of
+            POP and IMAP servers, many logged in as the same user!
+          + 7.6 Why does mail disappear even though I set "keep mail on
+            server"?
+          + 7.7 Why do I get the message
+               o Moved ##### bytes of new mail to /home/user/mbox from
+                 /var/spool/mail/user
+            and why did this happen?
+          + 7.8 Why isn't it showing the local host name as a
+            fully-qualified domain name?
+          + 7.9 Why is the local host name in the From/Sender/Message-ID
+            headers of outgoing mail not coming out as a fully-qualified
+            domain name?
+          + 7.10 What does the message:
+               o Mailbox vulnerable - directory /var/spool/mail must have
+                 1777 protection
+            mean? How can I fix this?
+          + 7.11 What does the message:
+               o Mailbox is open by another process, access is readonly
+            mean? How do I fix this?
+          + 7.12 What does the message:
+               o Can't get write access to mailbox, access is readonly
+            mean?
+          + 7.13 I set my POP3 client to "delete messages from server"
+            but they never get deleted. What is wrong?
+          + 7.14 What do messages such as:
+               o Message ... UID ... already has UID ...
+               o Message ... UID ... less than ...
+               o Message ... UID ... greater than last ...
+               o Invalid UID ... in message ..., rebuilding UIDs
+            mean?
+          + 7.15 What do the error messages:
+               o Unable to read internal header at ...
+               o Unable to find CRLF at ...
+               o Unable to parse internal header at ...
+               o Unable to parse message date at ...
+               o Unable to parse message flags at ...
+               o Unable to parse message UID at ...
+               o Unable to parse message size at ...
+               o Last message (at ... ) runs past end of file ...
+            mean? I am using mbx format.
+          + 7.16 What do the syslog messages:
+               o imap/tcp server failing (looping)
+               o pop3/tcp server failing (looping)
+            mean? When it happens, the listed service shuts down. How can
+            I fix this?
+          + 7.17 What does the syslog message:
+               o Mailbox lock file /tmp/.600.1df3 open failure:
+                 Permission denied
+            mean?
+          + 7.18 What do the syslog messages:
+               o Command stream end of file, while reading line user=...
+                 host=...
+               o Command stream end of file, while reading char user=...
+                 host=...
+               o Command stream end of file, while writing text user=...
+                 host=...
+            mean?
+          + 7.19 Why did my POP or IMAP session suddenly disconnect? The
+            syslog has the message:
+               o Killed (lost mailbox lock) user=... host=...
+          + 7.20 Why does my IMAP client show all the files on the
+            system, recursively from the UNIX root directory?
+          + 7.21 Why does my IMAP client show all of my files,
+            recursively from my UNIX home directory?
+          + 7.22 Why does my IMAP client show that I have mailboxes named
+            "#mhinbox", "#mh", "#shared", "#ftp", "#news", and "#public"?
+          + 7.23 Why does my IMAP client show all my files in my home
+            directory?
+          + 7.24 Why is there a long delay before I get connected to the
+            IMAP or POP server, no matter what client I use?
+          + 7.25 Why is there a long delay in Pine or any other c-client
+            based application call before I get connected to the IMAP
+            server? The hang seems to be in the c-client mail_open()
+            call. I don't have this problem with any other IMAP client.
+            There is no delay connecting to a POP3 or NNTP server with
+            mail_open().
+          + 7.26 Why does a message sometimes get split into two or more
+            messages on my SUN system?
+          + 7.27 Why did my POP or IMAP session suddenly disconnect? The
+            syslog has the message:
+               o Autologout user=<...my user name...> host=<...my imap
+                 server...>
+          + 7.28 What does the UNIX error message:
+               o TLS/SSL failure: myserver: SSL negotiation failed
+            mean?
+          + 7.29 What does the PC error message:
+               o TLS/SSL failure: myserver: Unexpected TCP input
+                 disconnect
+            mean?
+          + 7.30 What does the error message:
+               o TLS/SSL failure: myserver: Server name does not match
+                 certificate
+            mean?
+          + 7.31 What does the UNIX error message:
+               o TLS/SSL failure: myserver: self-signed certificate
+            mean?
+          + 7.32 What does the PC error message
+               o TLS/SSL failure: myserver: Self-signed certificate or
+                 untrusted authority
+            mean?
+          + 7.33 What does the UNIX error message:
+               o TLS/SSL failure: myserver: unable to get local issuer
+                 certificate
+            mean?
+          + 7.34 Why does reading certain messages hang when using
+            Netscape? It works fine with Pine!
+          + 7.35 Why does Netscape say that there's a problem with the
+            IMAP server and that I should "Contact your mail server
+            administrator."?
+          + 7.36 Why is one user creating huge numbers of IMAP or POP
+            server sessions?
+          + 7.37 Why don't I get any new mail notifications from Outlook
+            Express or Outlook after a while?
+          + 7.38 Why don't I get any new mail notifications from
+            Entourage?
+          + 7.39 Why doesn't Entourage work at all?
+          + 7.40 Why doesn't Netscape Notify (NSNOTIFY.EXE) work at all?
+          + 7.41 Why can't I connect via SSL to Eudora? It says the
+            connection has been broken, and in the server syslogs I see
+            "Command stream end of file".
+          + 7.42 Sheesh. Aren't there any good IMAP clients out there?
+          + 7.43 But wait! PC Pine (or other PC program build with
+            c-client) crashes with the message
+               o incomplete SecBuffer exceeds maximum buffer size
+            when I use SSL connections. This is a bug in c-client, right?
+          + 7.44 My qpopper users keep on getting the DON'T DELETE THIS
+            MESSAGE -- FOLDER INTERNAL DATA if they also use Pine or
+            IMAP. How can I fix this?
+          + 7.45 Help! I installed the servers but I can't connect to
+            them from my client!
+          + 7.46 Why do I get the message
+               o Can not authenticate to SMTP server: 421 SMTP connection
+                 went away!
+            and why did this happen? There was also something about
+               o SECURITY PROBLEM: insecure server advertised AUTH=PLAIN
+          + 7.47 Why do I get the message
+               o SMTP Authentication cancelled
+            and why did this happen? There was also something about
+               o SECURITY PROBLEM: insecure server advertised AUTH=PLAIN
+          + 7.48 Why do I get the message
+               o Invalid base64 string
+            when I try to authenticate to a Cyrus server?
+     * 8. Where to Go For Additional Information
+          + 8.1 Where can I go to ask questions?
+          + 8.2 I have some ideas for enhancements to IMAP. Where should
+            I go?
+          + 8.3 Where can I read more about IMAP and other email
+            protocols?
+          + 8.4 Where can I find out more about setting up and
+            administering an IMAP server?
+     _________________________________________________________________
+
+1. General/Software Feature Questions
+     _________________________________________________________________
+
+   1.1 Can I set up a POP or IMAP server on UNIX/Linux/OSF/etc.?
+
+          Yes. Refer to the UNIX specific notes in files CONFIG and
+          BUILD.
+     _________________________________________________________________
+
+   1.2 I am currently using qpopper as my POP3 server on UNIX. Do I need
+   to replace it with ipop3d in order to run imapd?
+
+          Not necessarily.
+
+          Although ipop3d interoperates with imapd better than qpopper,
+          imapd and qpopper will work together. The few qpopper/imapd
+          interoperability issues mostly affect users who use both IMAP
+          and POP3 clients; those users would probably be better served
+          if their POP3 server is ipop3d.
+
+          If you are happy with qpopper and just want to add imapd, you
+          should do that, and defer a decision on changing qpopper to
+          ipop3d. That way, you can get comfortable with imapd's
+          performance, without changing anything for your qpopper users.
+
+          Many sites have subsequently decided to change from qpopper to
+          ipop3d in order to get better POP3/IMAP interoperability. If
+          you need to do this, you'll know. There also seems to be a way
+          to make qpopper work better with imapd; see the answer to the
+          My qpopper users keep on getting the DON'T DELETE THIS MESSAGE
+          -- FOLDER INTERNAL DATA if they also use Pine or IMAP. How can
+          I fix this? question.
+     _________________________________________________________________
+
+   1.3 Can I set up a POP or IMAP server on Windows XP, 2000, NT, Me, 98,
+   or 95?
+
+          Yes. Refer to the NT specific notes in files CONFIG and BUILD.
+          Also, for DOS-based versions of Windows (Windows Me, 98, and
+          95) you *must* set up CRAM-MD5 authentication, as described in
+          md5.txt.
+
+          There is no file access control on Windows 9x or Me, so you
+          probably will have to do modifications to env_unix.c to prevent
+          people from hacking others' mail.
+
+          Note, however, that the server is not plug and play the way it
+          is for UNIX.
+     _________________________________________________________________
+
+   1.4 Can I set up a POP or IMAP server on Windows 3.1 or DOS?
+   1.5 Can I set up a POP or IMAP server on Macintosh?
+   1.6 Can I set up a POP or IMAP server on VAX/VMS?
+
+          Yes, it's just a small matter of programming.
+     _________________________________________________________________
+
+   1.7 Can I set up a POP or IMAP server on TOPS-20?
+
+          You have a TOPS-20 system? Cool.
+
+          If IMAP2 (RFC 1176) is good enough for you, you can use MAPSER
+          which is about the ultimate gonzo pure TOPS-20 extended
+          addressing assembly language program. Unfortunately, IMAP2 is
+          barely good enough for Pine these days, and most other IMAP
+          clients won't work with IMAP2 at all. Maybe someone will hack
+          MAPSER to do IMAP4rev1 some day.
+
+          We don't know if anyone wrote a POP3 server for TOPS-20. There
+          definitely was a POP2 server once upon a time.
+
+          Or you can port the POP and IMAP server from this IMAP toolkit
+          to it. All that you need for a first stab is to port the MTX
+          driver. That'll probably be just a couple of hours of hacking.
+     _________________________________________________________________
+
+   1.8 Are hierarchical mailboxes supported?
+   1.9 Are "dual-use" mailboxes supported?
+   1.10 Can I have a mailbox that has both messages and sub-mailboxes?
+
+          Yes. However, there is one important caveat.
+
+          Some mailbox formats, including the default which is the
+          traditional UNIX mailbox format, are stored as a single file
+          containing all the messages. UNIX does not permit a name in the
+          filesystem to be both a file and a directory; consequently you
+          can not have a sub-mailbox within a mailbox that is in one of
+          these formats.
+
+          This is not a limitation of the software; this is a limitation
+          of UNIX. For example, there are mailbox formats in which the
+          name is a directory and each message is a file within that
+          directory; these formats support sub-mailboxes within such
+          mailboxes. However, for technical reasons, the "flat file"
+          formats are generally preferred since they perform better. Read
+          imap-2007/docs/formats.txt for more information on this topic.
+
+          It is always permissible to create a directory that is not a
+          mailbox, and have sub-mailboxes under it. The easiest way to
+          create a directory is to create a new mailbox inside a
+          directory that doesn't already exist. For example, if you
+          create "Mail/testbox" on UNIX, the directory "Mail/" will
+          automatically be created and then the mailbox "testbox" will be
+          created as a sub-mailbox of "Mail/".
+
+          It is also possible to create the name "Mail/" directly. Check
+          the documentation for your client software to see how to do
+          this with that software.
+
+          Of course, on Windows systems you would use "\" instead of "/".
+     _________________________________________________________________
+
+   1.11 What is the difference between "mailbox" and "folder"?
+
+          The term "mailbox" is IMAP-speak for what a lot of software
+          calls a "folder" or a "mail folder". However, "folder" is often
+          used in other contexts to refer to a directory, for example, in
+          the graphic user interface on both Windows and Macintosh.
+
+          A "mailbox" is specifically defined as a named object that
+          contains messages. It is not required to be capable of
+          containing other types of objects including other mailboxes;
+          although some mailbox formats will permit this.
+
+          In IMAP-speak, a mailbox which can not contain other mailboxes
+          is called a "no-inferiors mailbox". Similarly, a directory
+          which can not contain messages is not a mailbox and is called a
+          "no-select name".
+     _________________________________________________________________
+
+   1.12 What is the status of internationalization?
+
+          The IMAP toolkit is partially internationalized and
+          multilingualized.
+
+          Searching is supported in the following charsets: US-ASCII,
+          UTF-8, ISO-8859-1, ISO-8859-2, ISO-8859-3, ISO-8859-4,
+          ISO-8859-5, ISO-8859-6, ISO-8859-7, ISO-8859-8, ISO-8859-9,
+          ISO-8859-10, ISO-8859-11, ISO-8859-13, ISO-8859-14,
+          ISO-8859-15, ISO-8859-16, KOI8-R, KOI8-U (alias KOI8-RU),
+          TIS-620, VISCII, ISO-2022-JP, ISO-2022-KR, ISO-2022-CN,
+          ISO-2022-JP-1, ISO-2022-JP-2, GB2312 (alias CN-GB),
+          CN-GB-12345, BIG5 (alias CN-BIG5), EUC-JP, EUC-KR, Shift_JIS,
+          Shift-JIS, KS_C_5601-1987, KS_C_5601-1992, WINDOWS_874,
+          WINDOWS-1250, WINDOWS-1251, WINDOWS-1252, WINDOWS-1253,
+          WINDOWS-1254, WINDOWS-1255, WINDOWS-1256, WINDOWS-1257,
+          WINDOWS-1258.
+
+          All ISO-2022-?? charsets are treated identically, and support
+          ASCII, JIS Roman, hankaku katakana, ISO-8859-[1 - 10], TIS, GB
+          2312, JIS X 0208, JIS X 0212, KSC 5601, and planes 1 and 2 of
+          CNS 11643.
+
+          EUC-JP includes support for JIS X 0212 and hankaku katakana.
+
+          c-client library support also exists to convert text in any of
+          the above charsets into Unicode, including headers with MIME
+          encoded-words.
+
+          There is no support for localization (e.g. non-English error
+          messages) at the present time, but such support is planned.
+     _________________________________________________________________
+
+   1.13 Can I use SSL?
+
+          Yes. See the answer to the How do I configure SSL? question.
+     _________________________________________________________________
+
+   1.14 Can I use TLS and the STARTTLS facility?
+
+          Yes. See the answer to the How do I configure TLS and the
+          STARTTLS facility? question.
+     _________________________________________________________________
+
+   1.15 Can I use CRAM-MD5 authentication?
+
+          Yes. See the answer to the How do I configure CRAM-MD5
+          authentication? question.
+     _________________________________________________________________
+
+   1.16 Can I use APOP authentication?
+
+          Yes. See the How do I configure APOP authentication? question.
+
+          Note that there is no client support for APOP authentication.
+     _________________________________________________________________
+
+   1.17 Can I use Kerberos V5?
+
+          Yes. See the answer to the How do I configure Kerberos V5?
+          question.
+     _________________________________________________________________
+
+   1.18 Can I use PAM for plaintext passwords?
+
+          Yes. See the answer to the How do I configure PAM for plaintext
+          passwords? question.
+     _________________________________________________________________
+
+   1.19 Can I use Kerberos 5 for plaintext passwords?
+
+          Yes. See the answer to the How do I configure Kerberos 5 for
+          plaintext passwords? question.
+     _________________________________________________________________
+
+   1.20 Can I use AFS for plaintext passwords?
+
+          Yes. See the answer to the How do I configure AFS for plaintext
+          passwords? question.
+     _________________________________________________________________
+
+   1.21 Can I use DCE for plaintext passwords?
+
+          Yes. See the answer to the How do I configure DCE for plaintext
+          passwords? question.
+     _________________________________________________________________
+
+   1.22 Can I use the CRAM-MD5 database for plaintext passwords?
+
+          Yes. See the answer to the How do I configure the CRAM-MD5
+          database for plaintext passwords? question.
+     _________________________________________________________________
+
+   1.23 Can I disable plaintext passwords?
+
+          Yes. See the answer to the How do I disable plaintext
+          passwords? question.
+     _________________________________________________________________
+
+   1.24 Can I disable plaintext passwords on unencrypted sessions, but
+   allow them on encrypted sessions?
+
+          Yes. See the answer to the How do I disable plaintext passwords
+          on unencrypted sessions, but allow them in SSL or TLS sessions?
+          question.
+     _________________________________________________________________
+
+   1.25 Can I use virtual hosts?
+
+          Yes. See the answer to the How do I configure virtual hosts?
+          question.
+     _________________________________________________________________
+
+   1.26 Can I use RPOP authentication?
+
+          There is no support for RPOP authentication.
+     _________________________________________________________________
+
+   1.27 Can I use Kerberos V4?
+
+          Kerberos V4 is not supported. Kerberos V4 client-only
+          contributed code is available in
+
+ftp://ftp.cac.washington.edu/mail/kerberos4-patches.tar.Z
+
+          This is a patchkit which must be applied to the IMAP toolkit
+          according to the instructions in the patchkit's README. We can
+          not promise that this code works.
+     _________________________________________________________________
+
+   1.28 Is there support for S/Key or OTP?
+
+          There is currently no support for S/Key or OTP. There may be an
+          OTP SASL authenticator available from third parties.
+     _________________________________________________________________
+
+   1.29 Is there support for NTLM or SPA?
+
+          There is currently no support for NTLM or SPA, nor are there
+          any plans to add such support. In general, I avoid
+          vendor-specific mechanisms. I also believe that these
+          mechanisms are being deprecated by their vendor.
+
+          There may be an NTLM SASL authenticator available from third
+          parties.
+     _________________________________________________________________
+
+   1.30 Is there support for mh?
+
+          Yes, but only as a legacy format. Your mh format INBOX is
+          accessed by the name "#mhinbox", and all other mh format
+          mailboxes are accessed by prefixing "#mh/" to the name, e.g.
+          "#mh/foo". The mh support uses the "Path:" entry in your
+          .mh_profile file to identify the root directory of your mh
+          format mailboxes.
+
+          Non-legacy use of mh format is not encouraged. There is no
+          support for permanent flags or unique identifiers; furthermore
+          there are known severe performance problems with the mh format.
+     _________________________________________________________________
+
+   1.31 Is there support for qmail and the maildir format?
+
+          There is no support for qmail or the maildir format in our
+          distribution, nor are there any plans to add such support.
+          Maildir support may be available from third parties.
+     _________________________________________________________________
+
+   1.32 Is there support for the Cyrus mailbox format?
+
+          No.
+     _________________________________________________________________
+
+   1.33 Is this software Y2K compliant?
+
+          Please read the files Y2K and calendar.txt.
+     _________________________________________________________________
+
+2. What Do I Need to Build This Software?
+     _________________________________________________________________
+
+   2.1 What do I need to build this software with SSL on UNIX?
+
+          You need to build and install OpenSSL first.
+     _________________________________________________________________
+
+   2.2 What do I need to build this software with Kerberos V on UNIX?
+
+          You need to build and install MIT Kerberos first.
+     _________________________________________________________________
+
+   2.3 What do I need to use a C++ compiler with this software to build
+   my own application?
+
+          If you are building an application using the c-client library,
+          use the new c-client.h file instead of including the other
+          include files. It seems that c-client.h should define away all
+          the troublesome names that conflict with C++.
+
+          If you use gcc, you may need to use -fno-operator-names as
+          well.
+     _________________________________________________________________
+
+   2.4 What do I need to build this software on Windows?
+
+          You need Microsoft Visual C++ 6.0, Visual C++ .NET, or Visual
+          C# .NET (which you can buy from any computer store), along with
+          the Microsoft Platform SDK (which you can download from
+          Microsoft's web site).
+
+          You do not need to install the entire Platform SDK; it suffices
+          to install just the Core SDK and the Internet Development SDK.
+     _________________________________________________________________
+
+   2.5 What do I need to build this software on DOS?
+
+          It's been several years since we last attempted to do this. At
+          the time, we used Microsoft C.
+     _________________________________________________________________
+
+   2.6 Can't I use Borland C to build this software on the PC?
+
+          Probably not. If you know otherwise, please let us know.
+     _________________________________________________________________
+
+   2.7 What do I need to build this software on the Mac?
+
+          It has been several years since we last attempted to do this.
+          At the time, we used Symantec THINK C; but today you'll need a
+          C compiler which allows segments to be more than 32K.
+     _________________________________________________________________
+
+   2.8 What do I need to build this software on VMS?
+
+          You need the VMS C compiler, and either the Multinet or Netlib
+          TCP.
+     _________________________________________________________________
+
+   2.9 What do I need to build this software on TOPS-20?
+
+          You need the TOPS-20 KCC compiler.
+     _________________________________________________________________
+
+   2.10 What do I need to build this software on Amiga or OS/2?
+
+          We don't know.
+     _________________________________________________________________
+
+   2.11 What do I need to build this software on Windows CE?
+
+          This port is incomplete. Someone needs to finish it.
+     _________________________________________________________________
+
+3. Build and Configuration Questions
+     _________________________________________________________________
+
+   3.1 How do I configure the IMAP and POP servers on UNIX?
+   3.2 I built and installed the servers according to the BUILD
+   instructions. It can't be that easy. Don't I need to write a config
+   file?
+
+          For ordinary "vanilla" UNIX systems, this software is plug and
+          play; just build it, install it, and you're done. If you have a
+          modified system, then you may want to do additional work; most
+          of this is to a single source code file (env_unix.c on UNIX
+          systems). Read the file CONFIG for more details.
+
+          Yes, it's that easy. There are some additional options, such as
+          SSL or Kerberos, which require additional steps to build. See
+          the relevant questions below.
+     _________________________________________________________________
+
+   3.3 How do I make the IMAP and POP servers look for INBOX at some
+   place other than the mail spool directory?
+   3.4 How do I make the IMAP server look for secondary folders at some
+   place other than the user's home directory?
+
+          Please read the file CONFIG for discussion of this and other
+          issues.
+     _________________________________________________________________
+
+   3.5 How do I configure SSL?
+   3.6 How do I configure TLS and the STARTTLS facility?
+
+          imap-2007 supports SSL and TLS client functionality on UNIX and
+          32-bit Windows for IMAP, POP3, SMTP, and NNTP; and SSL and TLS
+          server functionality on UNIX for IMAP and POP3.
+
+          UNIX SSL build requires that a third-party software package,
+          OpenSSL, be installed on the system first. Read
+          imap-2007/docs/SSLBUILD for more information.
+
+          SSL is supported via undocumented Microsoft interfaces in
+          Windows 9x and NT4; and via standard interfaces in Windows
+          2000, Windows Millenium, and Windows XP.
+     _________________________________________________________________
+
+   3.7 How do I build/install OpenSSL and obtain/create certificates for
+   use with SSL?
+
+          If you need help in doing this, try the contacts mentioned in
+          the OpenSSL README. We do not offer support for OpenSSL or
+          certificates.
+     _________________________________________________________________
+
+   3.8 How do I configure CRAM-MD5 authentication?
+   3.9 How do I configure APOP authentication?
+
+          CRAM-MD5 authentication is enabled in the IMAP and POP3 client
+          code on all platforms. Read md5.txt to learn how to set up
+          CRAM-MD5 and APOP authentication on UNIX and NT servers.
+
+          There is no support for APOP client authentication.
+     _________________________________________________________________
+
+   3.10 How do I configure Kerberos V5?
+
+          imap-2007 supports client and server functionality on UNIX and
+          32-bit Windows.
+
+          Kerberos V5 is supported by default in Windows 2000 builds:
+
+ nmake -f makefile.w2k
+
+          Other builds require that a third-party Kerberos package, e.g.
+          MIT Kerberos, be installed on the system first.
+
+          To build with Kerberos V5 on UNIX, include
+          EXTRAAUTHENTICATORS=gss in the make command line, e.g.
+
+ make lnp EXTRAAUTHENTICATORS=gss
+
+          To build with Kerberos V5 on Windows 9x, Windows Millenium, and
+          NT4, use the "makefile.ntk" file instead of "makefile.nt":
+
+
+ nmake -f makefile.ntk
+     _________________________________________________________________
+
+   3.11 How do I configure PAM for plaintext passwords?
+
+          On Linux systems, use the lnp port, e.g.
+
+ make lnp
+
+          On Solaris systems and other systems with defective PAM
+          implementations, build with PASSWDTYPE=pmb, e.g.
+
+ make sol PASSWDTYPE=pmb
+
+          On all other systems, build with PASSWDTYPE=pam, e.g
+
+ make foo PASSWDTYPE=pam
+
+          If you build with PASSWDTYPE=pam and authentication does not
+          work, try rebuilding (after a "make clean") with
+          PASSWDTYPE=pmb.
+     _________________________________________________________________
+
+   3.12 It looks like all I have to do to make the server use Kerberos is
+   to build with PAM on my Linux system, and set it up in PAM for
+   Kerberos passwords. Right?
+
+          Yes and no.
+
+          Doing this will make plaintext password authentication use the
+          Kerberos password instead of the /etc/passwd password.
+
+          However, this will NOT give you Kerberos-secure authentication.
+          See the answer to the How do I configure Kerberos V5? question
+          for how to build with Kerberos-secure authentication.
+     _________________________________________________________________
+
+   3.13 How do I configure Kerberos 5 for plaintext passwords?
+
+          Build with PASSWDTYPE=gss, e.g.
+
+ make sol PASSWDTYPE=gss
+
+          However, this will NOT give you Kerberos-secure authentication.
+          See the answer to the How do I configure Kerberos V5? question
+          for how to build with Kerberos-secure authentication.
+     _________________________________________________________________
+
+   3.14 How do I configure AFS for plaintext passwords?
+
+          Build with PASSWDTYPE=afs, e.g
+
+ make sol PASSWDTYPE=afs
+     _________________________________________________________________
+
+   3.15 How do I configure DCE for plaintext passwords?
+
+          Build with PASSWDTYPE=dce, e.g
+
+ make sol PASSWDTYPE=dce
+     _________________________________________________________________
+
+   3.16 How do I configure the CRAM-MD5 database for plaintext passwords?
+
+          The CRAM-MD5 password database is automatically used for
+          plaintext password if it exists.
+
+          Note that this is NOT CRAM-MD5-secure authentication. You
+          probably want to consider disabling plaintext passwords for
+          non-SSL/TLS sessions. See the next two questions.
+     _________________________________________________________________
+
+   3.17 How do I disable plaintext passwords?
+
+          Server-level plaintext passwords can be disabled by setting
+          PASSWDTYPE=nul, e.g.
+
+ make lnx EXTRAAUTHENTICATORS=gss PASSWDTYPE=nul
+
+          Note that you must have a CRAM-MD5 database installed or
+          specify at least one EXTRAAUTHENTICATOR, otherwise it will not
+          be possible to log in to the server.
+
+          When plaintext passwords are disabled, the IMAP server will
+          advertise the LOGINDISABLED capability and the POP3 server will
+          not advertise the USER capability.
+
+   3.18 How do I disable plaintext passwords on unencrypted sessions, but
+   allow them in SSL or TLS sessions?
+
+          Do not set PASSWDTYPE=nul or SSLTYPE=unix. Set SSLTYPE=nopwd
+          instead, e.g.
+
+ make lnx SSLTYPE=nopwd
+
+          When plaintext passwords are disabled, the IMAP server will
+          advertise the LOGINDISABLED capability and the POP3 server will
+          not advertise the USER capability.
+
+          Plaintext passwords will always be enabled in SSL sessions; the
+          IMAP server will not advertise the LOGINDISABLED capability and
+          the POP3 server will advertise the USER capability.
+
+          If the client does a successful start-TLS in a non-SSL session,
+          plaintext passwords will be enabled, and a new CAPABILITY or
+          CAPA command (which is required after start-TLS) will show the
+          effect as in SSL sessions.
+     _________________________________________________________________
+
+   3.19 How do I configure virtual hosts?
+
+          This is automatic, but with certain restrictions.
+
+          The most important one is that each virtual host must have its
+          own IP address; otherwise the server has no way of knowing
+          which virtual host is desired.
+
+          As distributed, the software uses a global password file; hence
+          user "fred" on one virtual host is "fred" on all virtual hosts.
+          You may want to modify the checkpw() routine to implement some
+          other policy (e.g. separate password files).
+
+          Note that the security model assumes that all users have their
+          own unique UNIX UID number. So if you use separate password
+          files you should make certain that the UID numbers do not
+          overlap between different files.
+
+          More advanced virtual host support may be available as patches
+          from third parties.
+     _________________________________________________________________
+
+   3.20 Why do I get compiler warning messages such as:
+ passing arg 3 of `scandir' from incompatible pointer type
+ Pointers are not assignment-compatible.
+ Argument #4 is not the correct type.
+
+   during the build?
+
+          You can safely ignore these messages.
+
+          Over the years, the prototype for scandir() has changed, and
+          thus is variant across different UNIX platforms. In particular,
+          the definitions of the third argument (type select_t) and
+          fourth argument (type compar_t) have changed over the years,
+          the issue being whether or not the arguments to the functions
+          pointed to by these function pointers are of type const or not.
+
+          The way that c-client calls scandir() will tend to generate
+          these compiler warnings on newer systems such as Linux;
+          however, it will still build. The problem with fixing the call
+          is that then it won't build on older systems.
+     _________________________________________________________________
+
+   3.21 Why do I get compiler warning messages such as
+ Operation between types "void(*)(int)" and "void*" is not allowed.
+ Function argument assignment between types "void*" and "void(*)(int)" is not a
+llowed.
+ Pointers are not assignment-compatible.
+ Argument #5 is not the correct type.
+
+   during the build?
+
+          You can safely ignore these messages.
+
+          All known systems have no problem with casting a function
+          pointer to/from a void* pointer, certain C compilers issue a
+          compiler diagnostic because this facility is listed as a
+          "Common extension" by the C standard:
+
+ K.5.7  Function pointer casts
+  [#1] A pointer to an object or to void may be cast to a pointer
+       to a function, allowing data to be invoked as a function (6.3.4).
+  [#2] A pointer to a function may be cast to a pointer to an
+       object or to void, allowing a function to be inspected or
+       modified (for example, by a debugger) (6.3.4).
+
+          It may be just a "common extension", but this facility is
+          relied upon heavily by c-client.
+     _________________________________________________________________
+
+   3.22 Why do I get linker warning messages such as:
+mtest.c:515: the `gets' function is dangerous and should not be used.
+
+   during the build? Isn't this a security bug?
+
+          You can safely ignore this message.
+
+          Certain linkers, most notably on Linux, give this warning
+          message. It is indeed true that the traditional gets() function
+          is not a safe one.
+
+          However, the mtest program is only a demonstration program, a
+          model of a very basic application program using c-client. It is
+          not something that you would install, much less run in any
+          security-sensitive context.
+
+          mtest has numerous other shortcuts that you wouldn't want to do
+          in a real application program.
+
+          The only "security bug" with mtest would be if it was run by
+          some script in a security-sensitive context, but mtest isn't
+          particularly useful for such purposes. If you wanted to write a
+          script to automate some email task using c-client, you'd be
+          better off using imapd instead of mtest.
+
+          mtest only has two legitimate uses. It's a useful testbed for
+          me when debugging new versions of c-client, and it's useful as
+          a model for someone writing a simple c-client application to
+          see how the various calls work.
+
+          By the way, if you need a more advanced example of c-client
+          programming than mtest (and you probably will), I recommend
+          that you look at the source code for imapd and Pine.
+     _________________________________________________________________
+
+   3.23 Why do I get linker warning messages such as:
+ auth_ssl.c:92: the `tmpnam' function is dangerous and should not be used.
+
+   during the build? Isn't this a security bug?
+
+          You can safely ignore this message.
+
+          Certain linkers, most notably on Linux, give this warning
+          message, based upon two known issues with tmpnam():
+
+                there can be a buffer overflow if an inadequate buffer is
+                allocated.
+                there can be a timing race caused by certain incautious
+                usage of the return value.
+
+          Neither of these issues applies in the particular use that is
+          made of tmpnam(). More importantly, the tmpnam() call is never
+          executed on Linux systems.
+     _________________________________________________________________
+
+   3.24 OK, suppose I see a warning message about a function being
+   "dangerous and should not be used" for something other than this
+   gets() or tmpnam() call?
+
+          Please forward the details for investigation.
+     _________________________________________________________________
+
+4. Operational Questions
+     _________________________________________________________________
+
+   4.1 How can I enable anonymous IMAP logins?
+
+          Create the file /etc/anonymous.newsgroups. At the present time,
+          this file should be empty. This will permit IMAP logins as
+          anonymous as well as the ANONYMOUS SASL authenticator.
+          Anonymous users have access to mailboxes in the #news., #ftp/,
+          and #public/ namespaces only.
+     _________________________________________________________________
+
+   4.2 How do I set up an alert message that each IMAP user will see?
+
+          Create the file /etc/imapd.alert with the text of the message.
+          This text should be kept to one line if possible. Note that
+          this will cause an alert to every IMAP user every time they
+          initiate an IMAP session, so it should only be used for
+          critical messages.
+     _________________________________________________________________
+
+   4.3 How does the c-client library choose which of its several
+   mechanisms to use to establish an IMAP connection to the server? I
+   noticed that it can connect on port 143, port 993, via rsh, and via
+   ssh.
+
+          c-client chooses how to establish an IMAP connection via the
+          following rules:
+
+          + If /ssl is specified, use an SSL connection. Fail otherwise.
+          + Else if client is a UNIX system and "ssh server exec
+            /etc/rimapd" works, use that
+          + Else if /tryssl is specified and an SSL connection works, use
+            that.
+          + Else if client is a UNIX system and "rsh server exec
+            /etc/rimapd" works, use that.
+          + Else use a non-SSL connection.
+     _________________________________________________________________
+
+   4.4 I am using a TLS-capable IMAP server, so I don't need to use /ssl
+   to get encryption. However, I want to be certain that my session is
+   TLS encrypted before I send my password. How to I do this?
+
+          Use the /tls option in the mailbox name. This will cause an
+          error message and the connection to fail if the server does not
+          negotiate STARTTLS.
+     _________________________________________________________________
+
+   4.5 How do I use one of the alternative formats described in the
+   formats.txt document? In particular, I hear that mbx format will give
+   me better performance and allow shared access.
+
+          The rumors about mbx format being preferred are true. It is
+          faster than the traditional UNIX mailbox format and permits
+          shared access.
+
+          However, and this is very important, note that using an
+          alternative mailbox format is an advanced facility, and only
+          expert users should undertake it. If you don't understand any
+          of the following notes, you may not be enough of an expert yet,
+          and are probably better off not going this route until you are
+          more comfortable with your understanding.
+
+          Some of the formats, including mbx, are only supported by the
+          software based on the c-client library, and are not recognized
+          by other mailbox programs. The "vi" editor will corrupt any mbx
+          format mailbox that it encounters.
+
+          Another problem is that the certain formats, including mbx, use
+          advanced file access and locking techniques that do not work
+          reliably with NFS. NFS is not a real filesystem. Use IMAP
+          instead of NFS for distributed access.
+
+          Each of the following steps are in escalating order of
+          involvement. The further you go down this list, the more deeply
+          committed you become:
+
+          + The simplest way to create a mbx-format mailbox is to prefix
+            the name with "#driver.mbx/" when creating a mailbox through
+            c-client. For example, if you create "#driver.mbx/foo", the
+            mailbox "foo" will be created in mbx format. Only use
+            "#driver.mbx/" when creating the mailbox. At all other times,
+            just use the name ("foo" in this example); the software will
+            automatically select the driver for mbx whenever that mailbox
+            is accessed without you doing anything else.
+          + You can use the "mailutil copy" command to copy an existing
+            mailbox to a new mailbox in mbx format. Read the man page
+            provided with the mailutil program for details.
+          + If you create an mbx-format INBOX, by creating
+            "#driver.mbx/INBOX" (note that "INBOX" must be all
+            uppercase), then subsequent access to INBOX by any c-client
+            based application will use the mbx-format INBOX. Any mail
+            delivered to the traditional format mailbox in the spool
+            directory (e.g. /var/spool/mail/$USER) will automatically be
+            copied into the mbx-format INBOX and the spool directory copy
+            removed.
+          + You can cause any newly-created mailboxes to be in mbx-format
+            by default by changing the definition of
+            CREATEPROTO=unixproto to be CREATEPROTO=mbxproto in
+            src/osdep/unix/Makefile, then rebuilding the IMAP toolkit (do
+            a "make clean" first). Do not change EMPTYPROTO, since mbx
+            format mailboxes are never a zero-byte file. If you use Pine
+            or the imap-utils, you should probably also rebuild them with
+            the new IMAP toolkit too.
+          + You can deliver directly to the mbx-format INBOX by use of
+            the tmail or dmail programs. tmail is for direct invocation
+            from sendmail (or whatever MTA program you use); dmail is for
+            calls from procmail. Both of these programs have man pages
+            which must be read carefully before making this change.
+
+          Most other servers (e.g. Cyrus) require use of a non-standard
+          format. A full-fledged format conversion is not significantly
+          different from what you have to do with other servers. The
+          difference, which makes format conversion procedures somewhat
+          more complicated with this server, is that there is no "all or
+          nothing" requirement with this server. There are many points in
+          between. A format conversion can be anything from a single
+          mailbox or single user, to systemwide.
+
+          This is good in that you can decide how far to go, or do the
+          steps incrementally as you become more comfortable with the
+          result. On the other hand, there's no "One True Way" which can
+          be boiled down to a simple set of pedagogical instructions.
+
+          A number of sites have done full-fledged format conversions,
+          and are reportedly quite happy with the results. Feel free to
+          ask in the comp.mail.imap newsgroup or the imap-uw mailing
+          list for advice or help.
+     _________________________________________________________________
+
+   4.6 How do I set up shared mailboxes?
+
+          At the simplest level, a shared mailbox is one which has UNIX
+          file and directory protections which permit multiple users to
+          access it. What this means is that your existing skills and
+          tools to create and manage shared files on your UNIX system
+          apply to shared mailboxes; e.g.
+
+ chmod 666 mailbox
+
+          You may want to consider the use of a mailbox format which
+          permits multiple simultaneous read/write sessions, such as the
+          mbx format. The traditional UNIX format only allows one
+          read/write session to a mailbox at a time.
+
+          An additional convenience item are three system directories,
+          which can be set up for shared namespaces. These are: #ftp,
+          #shared, and #public, and are defined by creating the
+          associated UNIX users and home directories as described below.
+
+          #ftp/ refers to the anonymous ftp filesystem exported by the
+          ftp server, and is equivalent to the home directory for UNIX
+          user "ftp". For example, #ftp/foo/bar refers to the file
+          /foo/bar in the anonymous FTP filesystem, or ~ftp/foo/bar for
+          normal users. Anonymous FTP files are available to anonymous
+          IMAP logins. By default, newly-created files in #ftp/ are
+          protected 644.
+
+          #public/ refers to an IMAP toolkit convention called "public"
+          files, and is equivalent to the home directory for UNIX user
+          "imappublic". For example, #public/foo/bar refers to the file
+          ~imappublic/foo/bar. Public files are available to anonymous
+          IMAP logins. By default, newly-created files in #public are
+          created with protection 0666.
+
+          #shared/ refers to an IMAP toolkit convention called "shared"
+          files, and is equivalent to the home directory for UNIX user
+          "imapshared". For example, #shared/foo/bar refers to the file
+          ~imapshared/foo/bar. Shared files are not available to
+          anonymous IMAP logins. By default, newly-created files in
+          #shared are created with protection 0660.
+     _________________________________________________________________
+
+   4.7 How can I make the server syslogs go to someplace other than the
+   mail syslog?
+
+          The openlog() call that sets the syslog facility is in
+          src/osdep/unix/env_unix.c in routine server_init(). You need to
+          edit this file to change the syslog facility from LOG_MAIL to
+          the facility you want, then rebuild. You also need to set up
+          your /etc/syslog.conf properly.
+
+          Refer to the man pages for syslog and syslogd for more
+          information on what the available syslog facilities are and how
+          to configure syslogs. If you still don't understand what to do,
+          find a UNIX system expert.
+     _________________________________________________________________
+
+5. Security Questions
+     _________________________________________________________________
+
+   5.1 I see that the IMAP server allows access to arbitary files on the
+   system, including /etc/passwd! How do I disable this?
+
+          You should not worry about this if your IMAP users are allowed
+          shell access. The IMAP server does not permit any access that
+          the user can not have via the shell.
+
+          If, and only if, you deny your IMAP users shell access, you may
+          want to consider one of three choices. Note that these choices
+          reduce IMAP functionality, and may have undesirable side
+          effects. Each of these choices involves an edit to file
+          src/osdep/unix/env_unix.c
+
+          The first (and recommended) choice is to set restrictBox as
+          described in file CONFIG. This will disable access to the
+          filesystem root, to other users' home directory, and to
+          superior directory.
+
+          The second (and strongly NOT recommended) choice is to set
+          closedBox as described in file CONFIG. This puts each IMAP
+          session into a so-called "chroot jail", and thus setting this
+          option is extremely dangerous; it can make your system much
+          less secure and open to root compromise attacks. So do not use
+          this option unless you are absolutely certain that you
+          understand all the issues of a "chroot jail."
+
+          The third choice is to rewrite routine mailboxfile() to
+          implement whatever mapping from mailbox name to filesystem name
+          (and restrictions) that you wish. This is the most general
+          choice. As a guide, you can see at the start of routine
+          mailboxfile() what the restrictBox choice does.
+     _________________________________________________________________
+
+   5.2 I've heard that IMAP servers are insecure. Is this true?
+
+          There are no known security problems in this version of the
+          IMAP toolkit, including the IMAP and POP servers. The IMAP and
+          POP servers limit what can be done while not logged in, and as
+          part of the login process discard all privileges except those
+          of the user.
+
+          As with other software packages, there have been buffer
+          overflow vulnerabilities in past versions. All known problems
+          of this nature are fixed in this version.
+
+          There is every reason to believe that the bad guys are engaged
+          in an ongoing effort to find vulnerabilities in the IMAP
+          toolkit. We look for such problems, and when one is found we
+          fix it.
+
+          It's unfortunate that any vulnerabilities existed in past
+          versions, and we're doing my best to keep the IMAP toolkit free
+          of vulnerabilities. No new vulnerabilities have been discovered
+          in quite a while, but efforts will not be relaxed.
+
+          Beware of vendors who claim that their implementations can not
+          have vulnerabilities.
+     _________________________________________________________________
+
+   5.3 How do I know that I have the most secure version of the server?
+
+          The best way is to keep your server software up to date. The
+          bad guys are always looking for ways to crack software, and
+          when they find one, let all their friends know.
+
+          Oldtimers used to refer to a concept of software rot: if your
+          software hasn't been updated in a while, it would "rot" -- tend
+          to acquire problems that it didn't have when it was new.
+
+          The latest release version of the IMAP toolkit is always
+          available at ftp://ftp.cac.washington.edu/mail/imap.tar.Z
+     _________________________________________________________________
+
+   5.4 I see all these strcpy() and sprintf() calls, those are unsafe,
+   aren't they?
+
+          Yes and no.
+
+          It can be unsafe to do these calls if you do not know that the
+          string being written will fit in the buffer. However, they are
+          perfectly safe if you do know that.
+
+          Beware of programmers who advocate doing a brute-force change
+          of all instances of
+
+ strcpy (s,t);
+
+          to
+
+ strncpy (s,t,n)[n] = '\0';
+
+          and similar measures in the name of "fixing all possible buffer
+          overflows."
+
+          There are examples in which a security bug was introduced
+          because of this type of "fix", due to the programmer using the
+          wrong value for n. In one case, the programmer thought that n
+          was larger than it actually was, causing a NUL to be written
+          out of the buffer; in another, n was too small, and a security
+          credential was truncated.
+
+          What is particularly ironic was that in both cases, the
+          original strcpy() was safe, because the size of the source
+          string was known to be safe.
+
+          With all this in mind, the software has been inspected, and it
+          is believed that all places where buffer overflows can happen
+          have been fixed. The strcpy()s that are still are in the code
+          occur after a size check was done in some other way.
+
+          Note that the common C idiom of
+
+ *s++ = c;
+
+          is just as vulnerable to buffer overflows. You can't cure
+          buffer overflows by outlawing certain functions, nor is it
+          desirable to do so; sometimes operations like strcpy()
+          translate into fast machine instructions for better
+          performance.
+
+          Nothing replaces careful study of code. That's how the bad guys
+          find bugs. Security is not accomplished by means of brute-force
+          shortcuts.
+     _________________________________________________________________
+
+   5.5 Those /tmp lock files are protected 666, is that really right?
+
+          Yes. Shared mailboxes won't work otherwise. Also, you get into
+          accidental denial of service problems with old lock files left
+          lying around; this happens fairly frequently.
+
+          The deliberate mischief that can be caused by fiddling with the
+          lock files is small-scale; harassment level at most. There are
+          many -- and much more effective -- other ways of harassing
+          another user on UNIX. It's usually not difficult to determine
+          the culprit.
+
+          Before worrying about deliberate mischief, worry first about
+          things happening by accident!
+     _________________________________________________________________
+
+6. Why Did You Do This Strange Thing? Questions
+     _________________________________________________________________
+
+   6.1 Why don't you use GNU autoconfig / automake / autoblurdybloop?
+
+          Autoconfig et al are not available on all the platforms where
+          the IMAP toolkit is supported; and do not work correctly on
+          some of the platforms where they do exist. Furthermore, these
+          programs add another layer of complexity to an already complex
+          process.
+
+          Coaxing software that uses autoconfig to build properly on
+          platforms which were not specifically considered by that
+          software wastes an inordinate amount of time. When (not if)
+          autoconfig fails to do the right thing, the result is an
+          inpenetrable morass to untangle in order to find the problem
+          and fix it.
+
+          The concept behind autoconfig is good, but the execution is
+          flawed. It rarely does the right thing on a platform that
+          wasn't specifically considered. Human life is too short to
+          debug autoconfig problems, especially since the current
+          mechanism is so much easier.
+     _________________________________________________________________
+
+   6.2 Why do you insist upon a build with -g? Doesn't it waste disk and
+   memory space?
+
+          From time to time a submitted port has snuck in without -g.
+          This has always ended up causing problems. There are only two
+          valid excuses for not using -g in a port:
+
+          + The compiler does not support -g
+          + An alternate form of -g is needed with optimization, e.g.
+            -g3.
+
+          There will be no new ports added without -g (or a suitable
+          alternative) being set.
+
+          -g has not been arbitrarily added to the ports which do not
+          currently have it because we don't know if doing so would break
+          the build. However, any support issues with one of those port
+          will lead to the correct -g setting being determined and
+          permanently added.
+
+          Processors are fast enough (and disk space is cheap enough)
+          that -g should be automatic in all compilers with no way of
+          turning it off, and /bin/strip should be a symlink to
+          /bin/true. Human life is too short to deal with binaries built
+          without -g. Such binaries should be a bad memory of the days of
+          KIPS processors and disks that costs several dollars per
+          kilobyte.
+     _________________________________________________________________
+
+   6.3 Why don't you make c-client a shared library?
+
+          All too often, shared libraries create far more problems than
+          they solve.
+
+          Remember that you only gain the benefit of a shared library
+          when there are multiple applications which use that shared
+          library. Even without shared libraries, on most modern
+          operating systems (and many ancient ones too!) applications
+          will share their text segments between across multiple
+          processes running the same application. This means that if your
+          system only runs one application (e.g. imapd) that uses the
+          c-client library, then you gain no benefit from making c-client
+          a shared library even if it has 100 imapd processes. You will,
+          however suffer added complexity.
+
+          If you have a server system that just runs imapd and ipop3d,
+          then making c-client a shared library will save just one copy
+          of c-client no matter how many IMAP/POP3 processes are running.
+
+          The problem with shared libraries is that you have to keep
+          around a copy of the library every time something changes in
+          the library that would affect the interface the library
+          presents to the application. So, you end up having many copies
+          of the same shared library.
+
+          If you don't keep multiple copies of the shared library, then
+          one of two things happens. If there was proper versioning, then
+          you'll get a message such as "cannot open shared object file"
+          or "minor versions don't match" and the application won't run.
+          Otherwise, the application will run, but will fail in
+          mysterious ways.
+
+          Several sites and third-party distributors have modified the
+          c-client makefile in order to make c-client be a shared
+          library. When (not if) a c-client based application fails in
+          mysterious ways because of a library compatibility problem, the
+          result is a bug report. A lot of time and effort ends up
+          getting wasted investigating such bug reports.
+
+          Memory is so cheap these days that it's not worth it. Human
+          life is too short to deal with shared library compatibility
+          problems.
+     _________________________________________________________________
+
+   6.4 Why don't you use iconv() for internationalization support?
+
+          iconv() is not ubiquitous enough.
+     _________________________________________________________________
+
+   6.5 Why is the IMAP server connected to the home directory by default?
+
+          The IMAP server has no way of knowing what you might call
+          "mail" as opposed to "some other file"; in fact, you can use
+          IMAP to access any file.
+
+          The IMAP server also doesn't know whether your preferred
+          subdirectory for mailbox files is "mail/", ".mail/", "Mail/",
+          "Mailboxes/", or any of a zillion other possibilities. If one
+          such name were chosen, it would undoubtably anger the partisans
+          of all the other names.
+
+          It is possible to modify the software so that the default
+          connected directory is someplace else. Please read the file
+          CONFIG for discussion of this and other issues.
+     _________________________________________________________________
+
+   6.6 I have a Windows system. Why isn't the server plug and play for
+   me?
+
+          There is no standard for how mail is stored on Windows; nor a
+          single standard SMTP server. The closest to either would be the
+          SMTP server in Microsoft's IIS.
+
+          So there's no default by which to make assumptions. As the
+          software is set up, it assumes that the each user has an
+          Windows login account and private home directory, and that mail
+          is stored on that home directory as files in one of the popular
+          UNIX formats. It also assumes that there is some tool
+          equivalent to inetd on UNIX that does the TCP/IP listening and
+          server startup.
+
+          Basically, unless you're an email software hacker, you probably
+          want to look elsewhere if you want IMAP/POP servers for
+          Windows.
+     _________________________________________________________________
+
+   6.7 I looked at the UNIX SSL code and saw that you have the SSL data
+   payload size set to 8192 bytes. SSL allows 16K; why aren't you using
+   the full size?
+
+          This is to avoid an interoperability problem with:
+
+          + PC IMAP clients that use Microsoft's SChannel.DLL (SSPI) for
+            SSL support
+          + Microsoft Exchange server (which also uses SChannel).
+
+          SChannel has a bug that makes it think that the maximum SSL
+          data payload size is 16379 bytes -- 5 bytes too small. Thus,
+          c-client has to make sure that it never transmits full sized
+          SSL packets.
+
+          The reason for using 8K (as opposed to, say, 16379 bytes, or
+          15K, or...) is that it corresponds with the TCP buffer size
+          that the software uses elsewhere for input; there's a slight
+          performance benefit to having the two sizes correspond or at
+          least be a multiple of each other. Also, it keeps the size as a
+          power of two, which might be significant on some platforms.
+
+          There wasn't a significant difference that we could measure
+          between 8K and 15K.
+
+          Microsoft has developed a hotfix for this bug. Look up MSKB
+          article number 300562. Contrary to the article text which
+          implies that this is a Pine issue, this bug also affects
+          Microsoft Exchange server with any client that transmits
+          full-sized SSL payloads.
+     _________________________________________________________________
+
+   6.8 Why is an mh format INBOX called #mhinbox instead of just INBOX?
+
+          It's a long story. In brief, the mh format driver is less
+          functional than any of the other drivers. It turned out that
+          there were some users (including high-level administrators) who
+          tried mh years ago and no longer use it, but still had an mh
+          profile left behind.
+
+          When the mh driver used INBOX, it would see the mh profile, and
+          proceed to move the user's INBOX into the mh format INBOX. This
+          caused considerable confusion as some things stopped working.
+     _________________________________________________________________
+
+   6.9 Why don't you support the maildir format?
+
+          It is technically difficult to support maildir in IMAP while
+          maintaining acceptable performance, robustness, following the
+          requirements of the IMAP protocol specification, and following
+          the requirements of maildir.
+
+          No one has succeeded in accomplishing all four together. The
+          various maildir drivers offered as patches all have these
+          problems. The problem is exacerbated because this
+          implementation supports multiple formats; consequently this
+          implementation can't make any performance shortcuts by assuming
+          that all the world is maildir.
+
+          We can't do a better job than the maildir fan community has
+          done with their maildir drivers. Similarly, if the maildir fan
+          community provides the maildir driver, they take on the
+          responsibility for answering maildir-specific support
+          questions. This is as it should be, and that is why maildir
+          support is left to the maildir fan community.
+     _________________________________________________________________
+
+   6.10 Why don't you support the Cyrus format?
+
+          There's no point to doing so. An implementation which supports
+          multiple formats will never do as well as one which is
+          optimized to support one single format.
+
+          If you want to use Cyrus mailbox format, you should use the
+          Cyrus server, which is the native implementation of that format
+          and is specifically optimized for that format. That's also why
+          Cyrus doesn't implement any other format.
+     _________________________________________________________________
+
+   6.11 Why is it creating extra forks on my SVR4 system?
+
+          This is because your system only has fcntl() style locking and
+          not flock() style locking. fcntl() locking has a design flaw
+          that causes a close() to release any locks made by that process
+          on the file opened on that file descriptor, even if the lock
+          was made on a different file descriptor.
+
+          This design flaw causes unexpected loss of lock, and consequent
+          mailbox corruption. The workaround is to do certain "dangerous
+          operations" in another fork, thus avoiding doing a close() in
+          the vulnerable fork.
+
+          The best way to solve this problem is to upgrade your SVR4
+          (Solaris, AIX, HP-UX, SGI) or OSF/1 system to a more advanced
+          operating system, such as Linux or BSD. These more advanced
+          operating systems have fcntl() locking for compatibility with
+          SVR4, but also have flock() locking.
+
+          Beware of certain SVR4 systems, such as AIX, which have an
+          "flock()" function in their C library that is just a jacket
+          that does an fcntl() lock. This is not a true flock(), and has
+          the same design flaw as fcntl().
+     _________________________________________________________________
+
+   6.12 Why are you so fussy about the date/time format in the internal
+   "From " line in traditional UNIX mailbox files? My other mail program
+   just considers every line that starts with "From " to be the start of
+   the message.
+
+          You just answered your own question. If any line that starts
+          with "From " is treated as the start of a message, then every
+          message text line which starts with "From " has to be quoted
+          (typically by prefixing a ">" character). People complain about
+          this -- "why did a > get stuck in my message?"
+
+          So, good mail reading software only considers a line to be a
+          "From " line if it follows the actual specification for a
+          "From " line. This means, among other things, that the day of
+          week is fixed-format: "May 14", but "May  7" (note the extra
+          space) as opposed to "May 7". ctime() format for the date is
+          the most common, although POSIX also allows a numeric timezone
+          after the year. For compatibility with ancient software, the
+          seconds are optional, the timezone may appear before the year,
+          the old 3-letter timezones are also permitted, and "remote from
+          xxx" may appear after the whole thing.
+
+          Unfortunately, some software written by novices use other
+          formats. The most common error is to have a variable-width day
+          of month, perhaps in the erroneous belief that RFC 2822 (or RFC
+          822) defines the format of the date/time in the "From " line
+          (it doesn't; no RFC describes internal formats). I've seen a
+          few other goofs, such as a single-digit second, but these are
+          less common.
+
+          If you are writing your own software that writes mailbox files,
+          and you really aren't all that savvy with all the ins and outs
+          and ancient history, you should seriously consider using the
+          c-client library (e.g. routine mail_append()) instead of doing
+          the file writes yourself. If you must do it yourself, use
+          ctime(), as in:
+
+ fprintf (mbx,"From %s@%h %s",user,host,ctime (time (0)));
+
+          rather than try to figure out a good format yourself. ctime()
+          is the most traditional format and nobody will flame you for
+          using it.
+     _________________________________________________________________
+
+   6.13 Why is traditional UNIX format the default format?
+
+          Compatibility with the past 30 or so years of UNIX history.
+          This server is the only one that completely interoperates with
+          legacy UNIX mail tools.
+     _________________________________________________________________
+
+   6.14 Why do you write this "DON'T DELETE THIS MESSAGE -- FOLDER
+   INTERNAL DATA" message at the start of traditional UNIX and MMDF
+   format mailboxes?
+
+          This pseudo-message serves two purposes.
+
+          First, it establishes the mailbox format even when the mailbox
+          has no messages. Otherwise, a mailbox with no messages is a
+          zero-byte file, which could be one of several formats.
+
+          Second, it holds mailbox metadata used by IMAP: the UID
+          validity, the last assigned UID, and mailbox keywords. Without
+          this metadata, which must be preserved even when the mailbox
+          has no messages, the traditional UNIX format wouldn't be able
+          to support the full capabilities of IMAP.
+     _________________________________________________________________
+
+   6.15 Why don't you stash the mailbox metadata in the first real
+   message of the mailbox instead of writing this fake FOLDER INTERNAL
+   DATA message?
+
+          In fact, that is what is done if the mailbox is non-empty and
+          does not already have a FOLDER INTERNAL DATA message.
+
+          One problem with doing that is that if some external program
+          removes the first message, the metadata is lost and must be
+          recreated, thus losing any prior UID or keyword list status
+          that IMAP clients may depend upon.
+
+          Another problem is that this doesn't help if the last message
+          is deleted. This will result in an empty mailbox, and the
+          necessity to create a FOLDER INTERNAL DATA message.
+     _________________________________________________________________
+
+   6.16 Why aren't "dual-use" mailboxes the default?
+
+          Compatibility with the past 30 or so years of UNIX history, not
+          to mention compatibility with user expectations when using
+          shell tools.
+     _________________________________________________________________
+
+   6.17 Why do you use ucbcc to build on Solaris?
+
+          It is a long, long story about why cc is set to ucbcc. You need
+          to invoke the C compiler so that it links with the SVR4
+          libraries and not the BSD libraries, otherwise readdir() will
+          return the wrong information.
+
+          Of all the names in the most common path, ucbcc is the only
+          name to be found (on /usr/ccs/bin) that points to a suitable
+          compiler. cc is likely to be /usr/ucb/cc which is absolutely
+          not the compiler that you want. The real SVR4 cc is probably
+          something like /opt/SUNWspro/bin/cc which is rarely in anyone's
+          path by default.
+
+          ucbcc is probably a link to acc, e.g.
+          /opt/SUNWspro/SC4.0/bin/acc, and is the UCB C compiler using
+          the SVR4 libraries.
+
+          If ucbcc isn't on your system, then punt on the SUN C compiler
+          and use gcc instead (the gso port instead of the sol port).
+
+          If, in spite of all the above warnings, you choose to change
+          "ucbcc" to "cc", you will probably find that the -O2 needs to
+          be changed to -O. If you don't get any error messages with -O2,
+          that's a pretty good indicator that you goofed and are running
+          the compiler that will link with the BSD libraries.
+
+          To recap:
+
+          + The sol port is designed to be built using the UCB compiler
+            using the SVR4 libraries. This compiler is "ucbcc", which is
+            lunk to acc. You use -O2 as one of the CFLAGS.
+          + If you build the sol port with the UCB compiler using the BSD
+            libraries, you will get no error messages but you will get
+            bad binaries (the most obvious symptom is dropping the first
+            two characters return filenames from the imapd LIST command.
+            This compiler also uses -O2, and is very often what the user
+            gets from "cc". BEWARE
+          + If you build the sol port with the real SVR4 compiler, which
+            is often hidden away or unavailable on many systems, then you
+            will get errors from -O2 and you need to change that to -O.
+            But you will get a good binary. However, you should try it
+            with -O2 first, to make sure that you got this compiler and
+            not the UCB compiler using BSD libraries.
+     _________________________________________________________________
+
+   6.18 Why should I care about some old system with BSD libraries? cc is
+   the right thing on my Solaris system!
+
+          Because there still are sites that use such systems. On those
+          systems, the assumption that "cc" does the right thing will
+          lead to corrupt binaries with no error message or other warning
+          that anything is amiss.
+
+          Too many sites have fallen victim to this problem.
+     _________________________________________________________________
+
+   6.19 Why do you insist upon writing .lock files in the spool
+   directory?
+
+          Compatibility with the past 30 years of UNIX software which
+          deals with the spool directory, especially software which
+          delivers mail. Otherwise, it is possible to lose mail.
+     _________________________________________________________________
+
+   6.20 Why should I care about compatibility with the past?
+
+          This is one of those questions in which the answer never
+          convinces those who ask it. Somehow, everybody who ever asks
+          this question ends up answering it for themselves as they get
+          older, with the very answer that they rejected years earlier.
+     _________________________________________________________________
+
+7. Problems and Annoyances
+     _________________________________________________________________
+
+   7.1 Help! My INBOX is empty! What happened to my messages?
+
+          If you are seeing "0 messages" when you open INBOX and you know
+          you have messages there (and perhaps have looked at your mail
+          spool file and see that messages are there), then probably
+          there is something wrong with the very first line of your mail
+          spool file. Make sure that the first five bytes of the file are
+          "From ", followed by an email address and a date/time in
+          ctime() format, e.g.:
+
+ From fred@foo.bar Mon May  7 20:54:30 2001
+     _________________________________________________________________
+
+   7.2 Help! All my messages in a non-INBOX mailbox have been
+   concatenated into one message which claims to be from me and has a
+   subject of the file name of the mailbox! What's going on?
+
+          Something wrong with the very first line of the mailbox. Make
+          sure that the first five bytes of the file are "From ",
+          followed by an email address and a date/time in ctime() format,
+          e.g.:
+
+ From fred@foo.bar Mon May  7 20:54:30 2001
+     _________________________________________________________________
+
+   7.3 Why do I get the message: CREATE failed: Can't create mailbox node
+   xxxxxxxxx: File exists and how do I fix it?
+
+          See the answer to the Are hierarchical mailboxes supported?
+          question.
+     _________________________________________________________________
+
+   7.4 Why can't I log in to the server? The user name and password are
+   right!
+
+          There are a myriad number of possible answers to this question.
+          The only way to say for sure what is wrong is run the server
+          under a debugger such as gdb while root (yes, you must be root)
+          with a breakpoint at routines checkpw() and loginpw(), then
+          single-step until you see which test rejected you. The server
+          isn't going to give any error messages other than "login
+          failed" in the name of not giving out any unnecessary
+          information to unauthorized individuals.
+
+          Here are some of the more common reasons why login may fail:
+
+          + You didn't really give the correct user name and/or password.
+          + Your client doesn't send the LOGIN command correctly; for
+            example, IMAP2 clients won't send a password containing a "*"
+            correctly to an IMAP4 server.
+          + If you have set up a CRAM-MD5 database, remember that the
+            password used is the one in the CRAM-MD5 database, and
+            furthermore that there must also be an entry in /etc/passwd
+            (but the /etc/passwd password is not used).
+          + If you are using PAM, have you created a service file for the
+            server in /etc/pam.d?
+          + If you are using shadow passwords, have you used an
+            appropriate port when building? In particular, note that
+            "lnx" is for Linux systems without shadow passwords; you
+            probably want "slx" or "lnp" instead.
+          + If your system has account or password expirations, check to
+            see that the expiration date hasn't passed.
+          + You can't log in as root or any other UID 0 user. This is for
+            your own safety, not to mention the fact that the servers use
+            UID 0 as meaning "not logged in".
+     _________________________________________________________________
+
+   7.5 Help! My load average is soaring and I see hundreds of POP and
+   IMAP servers, many logged in as the same user!
+
+          Certain inferior losing GUI mail reading programs have a
+          "synchronize all mailboxes at startup" (IMAP) or "check for new
+          mail every second" (POP) feature which causes a rapid and
+          unchecked spawning of servers.
+
+          This is not a problem in the server; the client is really
+          asking for all those server sessions. Unfortunately, there
+          isn't much that the POP and IMAP servers can do about it; they
+          don't spawned themselves.
+
+          Some sites have added code to record the number of server
+          sessions spawned per user per hour, and disable login for a
+          user who has exceeded a predetermined rate. This doesn't stop
+          the servers from being spawned; it just means that a server
+          session will commit suicide a bit faster.
+
+          Another possibility is to detect excessive server spawning
+          activity at the level where the server is spawned, which would
+          be inetd or possibly tcpd. The problem here is that this is a
+          hard time to quantify. 50 sessions in a minute from a
+          multi-user timesharing system may be perfectly alright, whereas
+          10 sessions a minute from a PC may be too much.
+
+          The real solution is to fix the client configuration, by
+          disabling those evil features. Also tell the vendors of those
+          clients how you feel about distributing denial-of-service
+          attack tools in the guise of mail reading programs.
+     _________________________________________________________________
+
+   7.6 Why does mail disappear even though I set "keep mail on server"?
+   7.7 Why do I get the message Moved ##### bytes of new mail to
+   /home/user/mbox from /var/spool/mail/user and why did this happen?
+
+          This is probably caused by the mbox driver. If the file "mbox"
+          exists on the user's home directory and is in UNIX mailbox
+          format, then when INBOX is opened this file will be selected as
+          INBOX instead of the mail spool file. Messages will be
+          automatically transferred from the mail spool file into the
+          mbox file.
+
+          To disable this behavior, delete "mbox" from the EXTRADRIVERS
+          list in the top-level Makefile and rebuild. Note that if you do
+          this, users won't be able to access the messages that have
+          already been moved to mbox unless they open mbox instead of
+          INBOX.
+     _________________________________________________________________
+
+   7.8 Why isn't it showing the local host name as a fully-qualified
+   domain name?
+   7.9 Why is the local host name in the From/Sender/Message-ID headers
+   of outgoing mail not coming out as a fully-qualified domain name?
+
+          Your UNIX system is misconfigured. The entry for your system in
+          /etc/hosts must have the fully-qualified domain name first,
+          e.g.
+
+ 105.69.1.234   myserver.example.com myserver
+
+          A common mistake of novice system administrators is to have the
+          short name first, e.g.
+
+ 105.69.1.234   myserver myserver.example.com
+
+          or to omit the fully qualified domain name entirely, e.g.
+
+ 105.69.1.234   myserver
+
+          The result of this is that when the IMAP toolkit does a
+          gethostbyname() call to get the fully-qualified domain name, it
+          would get "myserver" instead of "myserver.example.com".
+
+          On some systems, a configuration file (typically named
+          /etc/svc.conf, /etc/netsvc.conf, or /etc/nsswitch.conf) can be
+          used to configure the system to use the domain name system
+          (DNS) instead of /etc/hosts, so it doesn't matter if /etc/hosts
+          is misconfigured.
+
+          Check the man pages for gethostbyname, hosts, svc, and/or
+          netsvc for more information.
+
+          Unfortunately, certain vendors, most notably SUN, have failed
+          to make this clear in their documentation. Most of SUN's
+          documentation assumes a corporate network that is not connected
+          to the Internet.
+
+          net.folklore once (late 1980s) held that the proper procedure
+          was to append the results of getdomainname() to the name
+          returned by gethostname(), and some versions of sendmail
+          configuration files were distributed that did this. This was
+          incorrect; the string returned from getdomainname() is the
+          Yellow Pages (a.k.a NIS) domain name, which is a completely
+          different (albeit unfortunately named) entity from an Internet
+          domain. These were often fortuitously the same string, except
+          when they weren't. Frequently, this would result in host names
+          with spuriously doubled domain names, e.g.
+
+ myserver.example.com.example.com
+
+          This practice has been thoroughly discredited for many years,
+          but folklore dies hard.
+     _________________________________________________________________
+
+   7.10 What does the message: Mailbox vulnerable - directory
+   /var/spool/mail must have 1777 protection mean? How can I fix this?
+
+          In order to update a mailbox in the default UNIX format, it is
+          necessary to create a lock file to prevent the mailer from
+          delivering mail while an update is in progress. Some systems
+          use a directory protection of 775, requiring that all mail
+          handling programs be setgid mail; or of 755, requiring that all
+          mail handling programs be setuid root.
+
+          The IMAP toolkit does not run with any special privileges, and
+          I plan to keep it that way. It is antithetical to the concept
+          of a toolkit if users can't write their own programs to use it.
+          Also, I've had enough bad experiences with security bugs while
+          running privileged; the IMAP and POP servers have to be root
+          when not logged in, in order to be able to log themselves in. I
+          don't want to go any deeper down that slippery slope.
+
+          Directory protection 1777 is secure enough on most well-managed
+          systems. If you can't trust your users with a 1777 mail spool
+          (petty harassment is about the limit of the abuse exposure),
+          then you have much worse problems then that.
+
+          If you absolutely insist upon requiring privileges to create a
+          lock file, external file locking can be done via a setgid mail
+          program named /etc/mlock (this is defined by LOCKPGM in the
+          c-client Makefile). If the toolkit is unable to create a
+          <...mailbox...>.lock file in the directory by itself, it will
+          try to call mlock to do it. I do not recommend doing this for
+          performance reasons.
+
+          A sample mlock program is included as part of imap-2007. We
+          have tried to make this sample program secure, but it has not
+          been thoroughly audited.
+     _________________________________________________________________
+
+   7.11 What does the message: Mailbox is open by another process, access
+   is readonly mean? How do I fix this?
+
+          A problem occurred in applying a lock to a /tmp lock file.
+          Either some other program has the mailbox open and won't
+          relenquish it, or something is wrong with the protection of
+          /tmp or the lock.
+
+          Make sure that the /tmp directory is protected 1777. Some
+          security scripts incorrectly set the protection of the /tmp
+          directory to 775, which disables /tmp for all non-privileged
+          programs.
+     _________________________________________________________________
+
+   7.12 What does the message: Can't get write access to mailbox, access
+   is readonly mean?
+
+          The mailbox file is write-protected against you.
+     _________________________________________________________________
+
+   7.13 I set my POP3 client to "delete messages from server" but they
+   never get deleted. What is wrong?
+
+          Make sure that your mailbox is not read-only: that the mailbox
+          is owned by you and write enabled (protection 0600), and that
+          the /tmp directory is longer world-writeable. /tmp must be
+          world-writeable because lots of applications use it for scratch
+          space. To fix this, do
+
+
+ chmod 1777 /tmp
+
+          as root.
+
+          Make sure that your POP3 client issues a QUIT command when it
+          finishes. The POP3 protocol specifies that deletions are
+          discarded unless a proper QUIT is done.
+
+          Make sure that you are not opening multiple POP3 sessions to
+          the same mailbox. It is a requirement of the POP3 protocol than
+          only one POP3 session be in effect to a mailbox at a time,
+          however some, poorly-written POP3 clients violate this. Also,
+          some background "check for new mail" tasks also cause a
+          violation. See the answer to the What does the syslog message:
+          Killed (lost mailbox lock) user=... host=... mean? question for
+          more details.
+     _________________________________________________________________
+
+   7.14 What do messages such as:
+ Message ... UID ... already has UID ...
+ Message ... UID ... less than ...
+ Message ... UID ... greater than last ...
+ Invalid UID ... in message ..., rebuilding UIDs
+
+   mean?
+
+          Something happened to corrupt the unique identifier regime in
+          the mailbox. In traditional UNIX-format mailboxes, this can
+          happen if the user deleted the "DO NOT DELETE" internal
+          message.
+
+          This problem is relatively harmless; a new valid unique
+          identifier regime will be created. The main effect is that any
+          references to the old UIDs will no longer be useful.
+
+          So, unless it is a chronic problem or you feel like debugging,
+          you can safely ignore these messages.
+     _________________________________________________________________
+
+   7.15 What do the error messages:
+ Unable to read internal header at ...
+ Unable to find CRLF at ...
+ Unable to parse internal header at ...
+ Unable to parse message date at ...
+ Unable to parse message flags at ...
+ Unable to parse message UID at ...
+ Unable to parse message size at ...
+ Last message (at ... ) runs past end of file ...
+
+   mean? I am using mbx format.
+
+          The mbx-format mailbox is corrupted and needs to be repaired.
+
+          You should make an effort to find out why the corruption
+          happened. Was there an obvious system problem (crash or disk
+          failure)? Did the user accidentally access the file via NFS?
+          Mailboxes don't get corrupted by themselves; something caused
+          the problem.
+
+          Some people have developed automated scripts, but if you're
+          comfortable using emacs it's pretty easy to fix it manually. Do
+          not use vi or any other editor unless you are certain that
+          editor can handle binary!!!
+
+          If you are not comfortable with emacs, or if the file is too
+          large to read with emacs, see the "step-by-step" technique
+          later on for another way of doing it.
+
+          After the word "at" in the error message is the byte position
+          it got to when it got unhappy with the file, e.g. if you see:
+
+ Unable to parse internal header at 43921: ne bombastic blurdybloop
+
+          The problem occurs at the 43,931 byte in the file. That's the
+          point you need to fix. c-client is expecting an internal header
+          at that byte number, looking something like:
+
+ 6-Jan-1998 17:42:24 -0800,1045;000000100001-00000001
+
+          The format of this internal line is:
+
+ dd-mmm-yyyy hh:mm:ss +zzzz,ssss;ffffffffFFFF-UUUUUUUU
+
+          The only thing that is variable is the "ssss" field, it can be
+          as many digits as needed. All other fields (inluding the "dd")
+          are fixed width. So, the easiest thing to do is to look forward
+          in the file for the next internal header, and delete everything
+          from the error point to that internal header.
+
+          Here's what to do if you want to be smarter and do a little bit
+          more work. Generally, you're in the middle of a message, and
+          there's nothing wrong with that message. The problem happened
+          in the *previous* message. So, search back to the previous
+          internal header. Now, remember that "ssss" field? That's the
+          size of that message.
+
+          Mark where you are in the file, move the cursor to the line
+          after the internal header, and skip that many bytes ("ssss")
+          forward. If you're at the point of the error in the file, then
+          that message is corrupt. If you're at a different point, then
+          perhaps the previous message is corrupt and has a too long size
+          count that "ate" into this message.
+
+          Basically, what you need to do is make sure that all those size
+          counts are right, and that moving "ssss" bytes from the line
+          after the internal header will land you at another internal
+          header.
+
+          Usually, once you know what you're looking at, it's pretty easy
+          to work out the corruption, and the best remedial action.
+          Repair scripts will make the problem go away but may not always
+          do the smartest/best salvage of the user's data. Manual repair
+          is more flexible and usually preferable.
+
+          Here is a step-by-step technique for fixing corrupt mbx files
+          that's a bit cruder than the procedure outlined above, but
+          works for any size file.
+
+          In this example, suppose that the corrupt file is INBOX, the
+          error message is
+
+ Unable to find CRLF at 132551754
+
+          and the size of the INBOX file is 132867870 bytes.
+
+          The first step is to split the mailbox file at the point of the
+          error:
+
+          + Rename the INBOX file to some other name, such as INBOX.bad.
+          + Copy the first 132,551,754 bytes of INBOX.bad to another
+            file, such as INBOX.new.
+          + Extract the trailing 316,116 bytes (132867870-132551754) of
+            INBOX.bad into another file, such as INBOX.tail.
+          + You no longer need INBOX.bad. Delete it.
+
+          In other words, use the number from the "Unable to find CRLF
+          at" as the point to split INBOX into two new files, INBOX.new
+          and INBOX.tail.
+
+          Now, remove the erroneous data:
+
+          + Verify that you can open INBOX.new in IMAP or Pine.
+          + The last message of INBOX.new is probably corrupted. Copy it
+            to another file, such as badmsg.1, then delete and expunge
+            that last message from INBOX.new
+          + Locate the first occurance of text in INBOX.tail which looks
+            like an internal header, as described above.
+          + Remove all the text which occurs prior to that point, and
+            place it into another file, such as badmsg.2. Note that in
+            the case of a single digit date, there is a leading space
+            which must not be removed (e.g. " 6-Nov-2001" not
+            "6-Nov-2001").
+
+          Reassemble the mailbox:
+
+          + Append INBOX.tail to INBOX.new.
+          + You no longer need INBOX.tail. Delete it.
+          + Verify that you can open INBOX.new in IMAP or Pine.
+
+          Reinstall INBOX.new as INBOX:
+
+          + Check to see if you have received any new messages while
+            repairing INBOX.
+          + If you haven't received any new messages while repairing
+            INBOX, just rename INBOX.new to INBOX.
+          + If you have received new messages, be sure to copy the new
+            messages from INBOX to INBOX.new before doing the rename.
+
+          You now have a working INBOX, as well as two files with
+          corrupted data (badmsg.1 and badmsg.2). There may be some
+          useful data in the two badmsg files that you might want to try
+          salvaging; otherwise you can delete the two badmsg files.
+     _________________________________________________________________
+
+   7.16 What do the syslog messages:
+
+ imap/tcp server failing (looping)
+ pop3/tcp server failing (looping)
+
+   mean? When it happens, the listed service shuts down. How can I fix
+   this?
+
+          The error message "server failing (looping), service
+          terminated" is not from either the IMAP or POP servers.
+          Instead, it comes from inetd, the daemon which listens for TCP
+          connections to a number of servers, including the IMAP and POP
+          servers.
+
+          inetd has a limit of 40 new server sessions per minute for any
+          particular service. If more than 40 sessions are initiated in a
+          minute, inetd will issue the "failing (looping), service
+          terminated" message and shut down the service for 10 minutes.
+          inetd does this to prevent system resource consumption by a
+          client which is spawning infinite numbers of servers. It should
+          be noted that this is a denial of service; however for some
+          systems the alternative is a crash which would be a worse
+          denial of service!
+
+          For larger server systems, the limit of 40 is much too low. The
+          limit was established many years ago when a system typically
+          only ran a few dozen servers.
+
+          On some versions of inetd, such as the one distributed with
+          most versions of Linux, you can modify the /etc/inetd.conf file
+          to have a larger number of servers by appending a period
+          followed by a number after the nowait word for the server
+          entry. For example, if your existing /etc/inetd.conf line
+          reads:
+
+ imap    stream  tcp     nowait  root    /usr/etc/imapd imapd
+
+          try changing it to be:
+
+ imap    stream  tcp     nowait.100  root    /usr/etc/imapd imapd
+
+          Another example (using TCP wrappers):
+
+ imap    stream  tcp     nowait  root    /usr/sbin/tcpd  imapd
+
+          try changing it to be:
+
+ imap    stream  tcp     nowait.100  root    /usr/sbin/tcpd  imapd
+
+          to increase the limit to 100 sessions/minute.
+
+          Before making this change, please read the information in "man
+          inetd" to determine whether or not your inetd has this feature.
+          If it does not, and you make this change, the likely outcome is
+          that you will disable IMAP service entirely.
+
+          Another way to fix this problem is to edit the inetd.c source
+          code (provided by your UNIX system vendor) to set higher
+          limits, rebuild inetd, install the new binary, and reboot your
+          system. This should only be done by a UNIX system expert. In
+          the inetd.c source code, the limits TOOMANY (normally 40) is
+          the maximum number of new server sessions permitted per minute,
+          and RETRYTIME (normally 600) is the number of seconds inetd
+          will shut down the server after it exceeds TOOMANY.
+     _________________________________________________________________
+
+   7.17 What does the syslog message: Mailbox lock file /tmp/.600.1df3
+   open failure: Permission denied mean?
+
+          This usually means that some "helpful" security script person
+          has protected /tmp so that it is no longer world-writeable.
+          /tmp must be world-writeable because lots of applications use
+          it for scratch space. To fix this, do
+
+ chmod 1777 /tmp
+
+          as root.
+
+          If that isn't the answer, check the protection of the named
+          file. If it is something other than 666, then either someone is
+          hacking or some "helpful" person modified the code to have a
+          different default lock file protection.
+     _________________________________________________________________
+
+   7.18 What do the syslog messages:
+ Command stream end of file, while reading line user=... host=...
+ Command stream end of file, while reading char user=... host=...
+ Command stream end of file, while writing text user=... host=...
+
+   mean?
+
+          This message occurs when the session is disconnected without a
+          proper LOGOUT (IMAP) or QUIT (POP) command being received by
+          the server first.
+
+          In many cases, this is perfectly normal; many client
+          implementations are impolite and do this. Some programmers
+          think this sort of rudeness is "more efficient".
+
+          The condition could, however, indicate a client or network
+          connectivity problem. The server has no way of knowing whether
+          there's a problem or just a rude client, so it issues this
+          message instead of a Logout.
+
+          Certain inferior losing clients disconnect abruptly after a
+          failed login, and instead of saying that the login failed, just
+          say that they can't access the mailbox. They then complain to
+          the system manager, who looks in the syslog and finds this
+          message. Not very helpful, eh? See the answer to the Why can't
+          I log in to the server? The user name and password are right!
+          question.
+
+          If the user isn't reporting a problem, you can probably ignore
+          this message.
+     _________________________________________________________________
+
+   7.19 Why did my POP or IMAP session suddenly disconnect? The syslog
+   has the message: Killed (lost mailbox lock) user=... host=...
+
+          This message only happens when either the traditional UNIX
+          mailbox format or MMDF format is in use. This format only
+          allows one session to have the mailbox open read/write at a
+          time.
+
+          The servers assume that if a second session attempts to open
+          the mailbox, that means that the first session is probably
+          owned by an abandoned client. The common scenario here is a
+          user who leaves his client running at the office, and then
+          tries to read his mail from home. Through an internal mechanism
+          called kiss of death, the second session requests the first
+          session to kill itself. When the first session receives the
+          "kiss of death", it issues the "Killed (lost mailbox lock)"
+          syslog message and terminates. The second session then seizes
+          read/write access, and becomes the new "first" session.
+
+          Certain poorly-designed clients routinely open multiple
+          sessions to the same mailbox; the users of those clients tend
+          to get this message a lot.
+
+          Another cause of this message is a background "check for new
+          mail" task which does its work by opening a POP session to
+          server every few seconds. They do this because POP doesn't have
+          a way to announce new mail.
+
+          The solution to both situations is to replace the client with a
+          good online IMAP client such as Pine. Life is too short to
+          waste on POP clients and poorly-designed IMAP clients.
+     _________________________________________________________________
+
+   7.20 Why does my IMAP client show all the files on the system,
+   recursively from the UNIX root directory?
+   7.21 Why does my IMAP client show all of my files, recursively from my
+   UNIX home directory?
+
+          A well-written client should only show one level of hierarchy
+          and then stop, awaiting explicit user action before going
+          lower. However, some poorly-designed clients will recursively
+          list all files, which may be a very long list (especially if
+          you have symbolic links to directories that create a loop in
+          the filesystem graph!).
+
+          This behavior has also been observed in some third-party
+          c-client drivers, including maildir drivers. Consequently, this
+          problem has even been observed in Pine. It is important to
+          understand that this is not a problem in Pine or c-client; it
+          is a problem in the third-party driver. A Pine built without
+          that third-party driver will not have this problem.
+
+          See also the answer to Why does my IMAP client show all my
+          files in my home directory?
+     _________________________________________________________________
+
+   7.22 Why does my IMAP client show that I have mailboxes named
+   "#mhinbox", "#mh", "#shared", "#ftp", "#news", and "#public"?
+
+          These are IMAP namespace names. They represent other
+          hierarchies in which messages may exist. These hierarchies may
+          not necessarily exist on a server, but the namespace name is
+          still in the namespace list in order to mark it as reserved.
+
+          A few poorly-designed clients display all namespace names as if
+          they were top-level mailboxes in a user's list of mailboxes,
+          whether or not they actually exist. This is a flaw in those
+          clients.
+     _________________________________________________________________
+
+   7.23 Why does my IMAP client show all my files in my home directory?
+
+          As distributed, the IMAP server is connected to your home
+          directory by default. It has no way of knowing what you might
+          call "mail" as opposed to "some other file"; in fact, you can
+          use IMAP to access any file.
+
+          Most clients have an option to configure your connected
+          directory on the IMAP server. For example, in Pine you can
+          specify this as the "Path" in your folder-collection, e.g.
+
+ Nickname  : Secondary Folders
+ Server    : imap.example.com
+ Path      : mail/
+ View      :
+
+          In this example, the user is connected to the "mail"
+          subdirectory of his home directory.
+
+          Other servers call this the "folder prefix" or similar term.
+
+          It is possible to modify the IMAP server so that all users are
+          automatically connected to some other directory, e.g. a
+          subdirectory of the user's home directory. Read the file CONFIG
+          for more details.
+     _________________________________________________________________
+
+   7.24 Why is there a long delay before I get connected to the IMAP or
+   POP server, no matter what client I use?
+
+          There are two common occurances of this problem:
+
+          + You are running a system (e.g. certain versions of Linux)
+            which by default attempts to connect to an "IDENT" protocol
+            (port 113) server on your client. However, a firewall or NAT
+            box is blocking connections to that port, so the connection
+            attempt times out.
+            The IDENT protocol is a well-known bad idea that does not
+            deliver any real security but causes incredible problems. The
+            idea is that this will give the server a record of the user
+            name, or at least what some program listening on port 113
+            says is the user name. So, if somebody coming from port nnnnn
+            on a system does something bad, IDENT may give you the userid
+            of the bad guy.
+            The problem is, IDENT is only meaningful on a timesharing
+            system which has an administrator who is privileged and users
+            who are not. It is of no value on a personal system which has
+            no separate concept of "system administrator" vs.
+            "unprivileged user".
+            On either type of system, security-minded people either turn
+            IDENT off or replace it with an IDENT server that lies. Among
+            other things, IDENT gives spammers the ability to harvest
+            email addresses from anyone who connects to a web page.
+            This problem has been showing up quite frequently on systems
+            which use xinetd instead of inetd. Look for files named
+            /etc/xinetd.conf, /etc/xinetd.d/imapd, /etc/inetd.d/ipop2d,
+            and /etc/xinetd.d/ipop3d. In those files, look for lines
+            containing "USERID", e.g.
+ log_on_success += USERID
+            Hunt down such lines, and delete them ruthlessly from all
+            files in which they occur. Don't be shy about it.
+          + The DNS is taking a long time to do a reverse DNS (PTR
+            record) lookup of the IP address of your client. This is a
+            problem in your DNS, which either you or you ISP need to
+            resolve. Ideally, the DNS should return the client's name;
+            but if it can't it should at least return an error quickly.
+
+          As you may have noticed, neither of these are actual problems
+          in the IMAP or POP servers; they are configuration issues with
+          either your system or your network infrastructure. If this is
+          all new to you, run (don't walk) to the nearest technical
+          bookstore and get yourself a good pedagogical text on system
+          administration for the type of system you are running.
+     _________________________________________________________________
+
+   7.25 Why is there a long delay in Pine or any other c-client based
+   application call before I get connected to the IMAP server? The hang
+   seems to be in the c-client mail_open() call. I don't have this
+   problem with any other IMAP client. There is no delay connecting to a
+   POP3 or NNTP server with mail_open().
+
+          By default, the c-client library attempts to make a connection
+          through rsh (and ssh, if you enable that). If the command:
+
+ rsh imapserver exec /etc/rimapd
+
+          (or ssh if that is enabled) returns with a "* PREAUTH"
+          response, it will use the resulting rsh session as the IMAP
+          session and not require an authentication step on the server.
+
+          Unfortunately, rsh has a design error that treats "TCP
+          connection refused" as "temporary failure, try again"; it
+          expects the "rsh not allowed" case to be implemented as a
+          successful connection followed by an error message and close
+          the connection.
+
+          It must be emphasized that this is a bug in rsh. It is not a
+          bug in the IMAP toolkit.
+
+          The use of rsh can be disabled in any the following ways:
+
+          + You can disable it for this particular session by either:
+               o setting an explicit port number in the mailbox name,
+                 e.g.
+ {imapserver.foo.com:143}INBOX
+               o using SSL (the /ssl switch)
+          + You can disable rsh globally by setting the rsh timeout value
+            to 0 with the call:
+ mail_parameters (NIL,SET_RSHTIMEOUT,0);
+     _________________________________________________________________
+
+   7.26 Why does a message sometimes get split into two or more messages
+   on my SUN system?
+
+          This is caused by an interaction of two independent design
+          problems in SUN mail software. The first problem is that the
+          "forward message" option in SUN's mail tool program includes
+          the internal "From " header line in the text that it forwarded.
+          This internal header line is specific to traditional UNIX
+          mailbox files and is not suitable for use in forwarded
+          messages.
+
+          The second problem is that the mail delivery agent assumes that
+          mail reading programs will not use the traditional UNIX mailbox
+          format but instead an incompatible variant that depends upon a
+          Content-Length: message header. Content-Length is widely
+          recognized to have been a terrible mistake, and is no longer
+          recommended for use in mail (it is used in other facilities
+          that use MIME).
+
+          One symptom of the problem is that under certain circumstances,
+          a message may get broken up into several messages. I'm also
+          aware of security bugs caused by programs that foolishly trust
+          "Content-Length:" headers with evil values.
+
+          To fix the mailer on your system, edit your sendmail.cf to
+          change the Mlocal line to have the -E flag. A typical entry
+          will lool like:
+
+ Mlocal,        P=/usr/lib/mail.local, F=flsSDFMmnPE, S=10, R=20,
+                A=mail.local -d $u
+
+          This fix will also work around the problem with mail tool,
+          because it will insert a ">" before the internal header line to
+          prevent it from being interpreted by mail reading software as
+          an internal header line.
+     _________________________________________________________________
+
+   7.27 Why did my POP or IMAP session suddenly disconnect? The syslog
+   has the message:
+ Autologout user=<...my user name...> host=<...my client system...>
+
+          This is a problem in your client.
+
+          In the case of IMAP, it failed to communicate with the IMAP
+          server for over 30 minutes; in the case of POP, it failed to
+          communicate with the POP server for over 10 minutes.
+     _________________________________________________________________
+
+   7.28 What does the UNIX error message: TLS/SSL failure: myserver: SSL
+   negotiation failed mean?
+   7.29 What does the PC error message: TLS/SSL failure: myserver:
+   Unexpected TCP input disconnect mean?
+
+          This usually means that an attempt to negotiate TLS encryption
+          via the STARTTLS command failed, because the server advertises
+          STARTTLS functionality, but doesn't actually have it (e.g.
+          because no certificates are installed).
+
+          Use the /notls option in the mailbox name to disable TLS
+          negotiation.
+     _________________________________________________________________
+
+   7.30 What does the error message: TLS/SSL failure: myserver: Server
+   name does not match certificate mean?
+
+          An SSL or TLS session encryption failed because the server name
+          in the server's certificate does not match the name that you
+          gave it. This could indicate that the server is not really the
+          system you think that it is, but can be also be called if you
+          gave a nickname for the server or name that was not
+          fully-qualified. You must use the fully-qualified domain name
+          for the server in order to validate its certificate
+
+          Use the /novalidate-cert option in the mailbox name to disable
+          validation of the certificate.
+     _________________________________________________________________
+
+   7.31 What does the UNIX error message: TLS/SSL failure: myserver:
+   self-signed certificate mean?
+   7.32 What does the PC error message: TLS/SSL failure: myserver:
+   Self-signed certificate or untrusted authority mean?
+
+          An SSL or TLS session encryption failed because your server's
+          certificate is "self-signed"; that is, it is not signed by any
+          Certificate Authority (CA) and thus can not be validated. A
+          CA-signed certificate costs money, and some smaller sites
+          either don't want to pay for it or haven't gotten one yet. The
+          bad part about this is that this means there is no guarantee
+          that the server is really the system you think that it is.
+
+          Use the /novalidate-cert option in the mailbox name to disable
+          validation of the certificate.
+     _________________________________________________________________
+
+   7.33 What does the UNIX error message: TLS/SSL failure: myserver:
+   unable to get local issuer certificate mean?
+
+          An SSL or TLS session encryption failed because your system
+          does not have the Certificate Authority (CA) certificates
+          installed on OpenSSL's certificates directory. On most systems,
+          this directory is /usr/local/ssl/certs). As a result, it is not
+          possible to validate the server's certificate.
+
+          If CA certificates are properly installed, you should see
+          factory.pem and about a dozen other .pem names such as
+          thawteCb.pem.
+
+          As a workaround, you can use the /novalidate-cert option in the
+          mailbox name to disable validation of the certificate; however,
+          note that you are then vulnerable to various security attacks
+          by bad guys.
+
+          The correct fix is to copy all the files from the certs/
+          directory in the OpenSSL distribution to the
+          /usr/local/ssl/certs (or whatever) directory. Note that you
+          need to do this after building OpenSSL, because the OpenSSL
+          build creates a number of needed symbolic links. For some
+          bizarre reason, the OpenSSL "make install" doesn't do this for
+          you, so you must do it manually.
+     _________________________________________________________________
+
+   7.34 Why does reading certain messages hang when using Netscape? It
+   works fine with Pine!
+
+          There are two possible causes.
+
+          Check the mail syslog. If you see the message "Killed (lost
+          mailbox lock)" for the impacted user(s), read the FAQ entry
+          regarding that message.
+
+          Check the affected mailbox to see if there are embedded NUL
+          characters in the message. NULs in message texts are a
+          technical violation of both the message format and IMAP
+          specifications. Most clients don't care, but apparently
+          Netscape does.
+
+          You can work around this by rebuilding imapd with the
+          NETSCAPE_BRAIN_DAMAGE option set (see src/imapd/Makefile); this
+          will cause imapd to convert all NULs to 0x80 characters. A
+          better solution is to enable the feature in your MTA to
+          MIME-convert messages with binary content. See the
+          documentation for your MTA for how to do this.
+     _________________________________________________________________
+
+   7.35 Why does Netscape say that there's a problem with the IMAP server
+   and that I should "Contact your mail server administrator."?
+
+          Certain versions of Netscape do this when you click the Manage
+          Mail button, which uses an undocumented feature of Netscape's
+          proprietary IMAP server.
+
+          You can work around this by rebuilding imapd with the
+          NETSCAPE_BRAIN_DAMAGE option set (see src/imapd/Makefile) to a
+          URL that points either to an alternative IMAP client (e.g.
+          Pine) or perhaps to a homebrew mail account management page.
+     _________________________________________________________________
+
+   7.36 Why is one user creating huge numbers of IMAP or POP server
+   sessions?
+
+          The user is probably using Outlook Express, Eudora, or a
+          similar program. See the answer to the Help! My load average is
+          soaring and I see hundreds of POP and IMAP servers, many logged
+          in as the same user! question.
+     _________________________________________________________________
+
+   7.37 Why don't I get any new mail notifications from Outlook Express
+   or Outlook after a while?
+
+          This is a known bug in Outlook Express. Microsoft is aware of
+          the problem and its cause. They have informed us that they do
+          not have any plans to fix it at the present time.
+
+          The problem is also reported in Outlook 2000, but not verified.
+
+          Outlook Express uses the IMAP IDLE command to avoid having to
+          "ping" the server every few minutes for new mail.
+          Unfortunately, Outlook Express overlooks the part in the IDLE
+          specification which requires that a client terminate and
+          restart the IDLE before the IMAP 30 minute inactivity
+          autologout timer triggers.
+
+          When this happens, Outlook Express displays "Not connected" at
+          the bottom of the window. Since it's no longer connected to the
+          IMAP server, it isn't going to notice any new mail.
+
+          As soon as the user does anything that would cause an IMAP
+          operation, Outlook Express will reconnect and new mail will
+          flow again. If the user does something that causes an IMAP
+          operation at least every 29 minutes, the problem won't happen.
+
+          Modern versions of imapd attempt to work around the problem by
+          automatically reporting fake new mail after 29 minutes. This
+          causes Outlook Express to exit the IDLE state; as soon as this
+          happens imapd revokes the fake new mail. As long as this
+          behavior isn't known to cause problems with other clients, this
+          workaround will remain in imapd.
+     _________________________________________________________________
+
+   7.38 Why don't I get any new mail notifications from Entourage?
+
+          This is a known bug in Entourage.
+
+          You built an older version of imapd with the
+          MICROSOFT_BRAIN_DAMAGE option set, in order to disable support
+          for the IDLE command. However, Entourage won't get new mail
+          unless IDLE command support exists.
+
+          Note: the MICROSOFT_BRAIN_DAMAGE option no longer exists in
+          modern versions, as the Outlook Express problem which it
+          attempted to solve has been worked around in another way.
+     _________________________________________________________________
+
+   7.39 Why doesn't Entourage work at all?
+
+          It's hard to know. Entourage breaks almost every rule in the
+          book for IMAP. It is highly instructive to do a packet trace on
+          Entourage, as an example of how not to use IMAP. It does things
+          like STATUS (MESSAGES) on the currently selected mailbox and
+          re-fetching the same static data over and over again.
+
+          It seems that every time we understand what it is doing wrong
+          in Entourage and come up with a workaround, we learn about
+          something else that's broken.
+
+          Try building imapd with the ENTOURAGE_BRAIN_DAMAGE option set,
+          in order to disable the diagnostic that occurs when doing
+          STATUS on the currently selected mailbox.
+     _________________________________________________________________
+
+   7.40 Why doesn't Netscape Notify (NSNOTIFY.EXE) work at all?
+
+          This is a bug in NSNOTIFY; it doesn't handle unsolicited data
+          from the server correctly.
+
+          Fortunately, there is no reason to use this program with IMAP;
+          NSNOTIFY is a polling program to let you know when new mail has
+          appeared in your maildrop. This is necessary with POP; but
+          since IMAP dynamically announces new mail in the session you're
+          better off (and will actually cause less load on the server!)
+          keeping your mail reading program's IMAP session open and let
+          IMAP do the notifying for you.
+
+          Consequently, the recommended fix for the NSNOTIFY problem is
+          to delete the NSNOTIFY binary.
+     _________________________________________________________________
+
+   7.41 Why can't I connect via SSL to Eudora? It says the connection has
+   been broken, and in the server syslogs I see "Command stream end of
+   file".
+
+          There is a report that you can fix the problem by going into
+          Eudora's advanced network configuration menu and increasing the
+          network buffer size to 8192.
+     _________________________________________________________________
+
+   7.42 Sheesh. Aren't there any good IMAP clients out there?
+
+          Yes!
+
+          Pine is a wonderful client. It's fast, it uses IMAP well, and
+          it generates text mail (life is too short to waste on HTML
+          mail). Also, there are some really wonderful things in progress
+          in the Pine world.
+
+          There are some good GUI clients out there, mostly from smaller
+          vendors. Without naming names, look for the vendors who are
+          active in the IMAP protocol development community, and their
+          products.
+
+          Netscape, Eudora, and Outlook can be configured with enough
+          effort to be good citizens and work well for users, but they
+          can also be badly misconfigured, and often the misconfiguration
+          is the default.
+     _________________________________________________________________
+
+   7.43 But wait! PC Pine (or other PC program build with c-client)
+   crashes with the message incomplete SecBuffer exceeds maximum buffer
+   size when I use SSL connections. This is a bug in c-client, right?
+
+          It's a bug in the Microsoft SChannel.DLL, which implements SSL.
+          Microsoft admits it (albeit with an unstatement: "it's not
+          fully RFC compliant"). The problem is that SChannel indicates
+          that the maximum SSL packet data size is 5 bytes smaller than
+          the actual maximum. Thus, any IMAP server which transmits a
+          maximum sized SSL packet will not work with PC Pine or any
+          other program which uses SChannel.
+
+          It can take a while for the problem to show up. The client has
+          to do something that causes at least 16K of contiguous data.
+          Many clients do partial fetching, which tends to reduce the
+          number of cases where this can happen. However, all software
+          which uses SChannel to support SSL is affected by this bug.
+
+          This problem does not affect UNIX code, since OpenSSL is used
+          on UNIX.
+
+          This problem most recently showed up with the CommunigatePro
+          IMAP server. They have an update which trims down their maximum
+          contiguous data to less than 16K, in order to work around the
+          problem.
+
+          This problem has also shown up with the Exchange IMAP server
+          with UNIX clients (including Pine built with an older version
+          of c-client) which sends full-sized 16K SSL packets. Modern
+          c-client works around the problem by trimming down its maximum
+          outgoing SSL packet size to 8K.
+
+          Microsoft has developed a hotfix for this bug. Look up MSKB
+          article number 300562. Contrary to the article text which
+          implies that this is a Pine issue, this bug also affect
+          Microsoft Exchange server with *any* UNIX based client that
+          transmits full-sized SSL payloads.
+     _________________________________________________________________
+
+   7.44 My qpopper users keep on getting the DON'T DELETE THIS MESSAGE --
+   FOLDER INTERNAL DATA if they also use Pine or IMAP. How can I fix
+   this?
+
+          This is an incompatibility between qpopper and the c-client
+          library used by Pine, imapd, and ipop[23]d.
+
+          Assuming that you want to continue using qpopper, look into
+          qpopper's --enable-uw-kludge-flag configuration flag, which is
+          documented as "check for and hide UW 'Folder Internal Data'
+          messages".
+
+          The other alternative is to switch from qpopper to ipop3d.
+     _________________________________________________________________
+
+   7.45 Help! I installed the servers but I can't connect to them from my
+   client!
+
+          Review the installation instructions carefully. Make sure that
+          you have not skipped any of the steps. Make sure that you have
+          made the correct entries in the configuration files; pay
+          careful attention to the exact spelling of the service names
+          and the path names. Make sure as well that you have properly
+          restarted inetd.
+
+          If you have a system with Yellow Pages/NIS such as Solaris,
+          have you updated the service names there as well as in
+          /etc/services?
+
+          If you have a system with TCP wrappers, have you properly
+          updated the TCP wrapper files (e.g. /etc/hosts.allow and
+          /etc/hosts.deny) for the servers?
+
+          If you have a system which uses xinetd instead of inetd, have
+          you made sure that you have made the correct corresponding
+          xinetd changes for those services?
+
+          Try telneting to the server port (143 for IMAP, 110 for POP3).
+          If you get a "refused" error, that probably means that you
+          don't have the service set up in inetd.conf. If the connection
+          opens and then closes with no message, the service is set up,
+          but either the path name of the server binary in inetd.conf is
+          wrong or your TCP wrappers are configured to deny access.
+
+          If you don't know how to make the corresponding changes to
+          these files, seek the help of a local expert for your system.
+     _________________________________________________________________
+
+   7.46 Why do I get the message Can not authenticate to SMTP server: 421
+   SMTP connection went away! and why did this happen? There was also
+   something about SECURITY PROBLEM: insecure server advertised
+   AUTH=PLAIN
+
+          Some versions of qmail, including that running on
+          mail.smtp.yahoo.com, disconnect the SMTP session if you fail to
+          authenticate prior to attempting to transmit mail. An attempt
+          to authenticate was made, but it failed because the server had
+          already disconnected.
+
+          To work around this, you need to specify /user=... in the host
+          name specification.
+
+          The SECURITY PROBLEM came about because the server advertised
+          the AUTH=PLAIN SASL authentication mechanism outside of a
+          TLS-encrypted session, in violation of RFC 4616. This message
+          is just a warning, and in fact occurred after the server had
+          disconnected.
+     _________________________________________________________________
+
+   7.47 Why do I get the message SMTP Authentication cancelled and why
+   did this happen? There was also something about SECURITY PROBLEM:
+   insecure server advertised AUTH=PLAIN
+
+          This is a bug in the SMTP server.
+
+          Some versions of qmail, including that running on
+          mail.smtp.yahoo.com, have a bug in their implementation of SASL
+          in their SMTP server, which renders it non-compliant with the
+          standard.
+
+          If the client does not provide an initial response in the
+          command line for an authentication mechanism whose profile does
+          not have an initial challenge, qmail issues a bogus response:
+
+ 334 ok, go on
+
+          The problem is the "ok, go on". This violates RFC 4954's
+          requirement that the text part in a 334 response be a BASE64
+          encoded string; in other words, it is a protocol syntax error.
+
+          In the case of AUTH=PLAIN, RFC 4422 (page 7) requires that the
+          encoded string have no data. In other words, the appropropiate
+          standards-compliant server response is "334" followed by a
+          SPACE and a CRLF.
+
+          The SECURITY PROBLEM came about because the server advertised
+          the AUTH=PLAIN SASL authentication mechanism outside of a
+          TLS-encrypted session, in violation of RFC 4616. This message
+          is just a warning, and is not related the "Authentication
+          cancelled" problem.
+     _________________________________________________________________
+
+   7.48 Why do I get the message Invalid base64 string when I try to
+   authenticate to a Cyrus server?
+
+          This slightly misleading message is the way that a Cyrus server
+          indicates that an authentication exchange was cancelled. It is
+          not indicative of a bug or protocol violation.
+
+          The most common reason that this happens is if the Cyrus server
+          offers Kerberos authentication, c-client is built with Kerberos
+          support, but your client system is not within the Kerberos
+          realm. In this case, the client code will try to authenticate
+          via Kerberos, fail to get the Kerberos credentials, cancel the
+          authentication attempt, and try the next available
+          authentication technology.
+     _________________________________________________________________
+
+8. Where to Go For Additional Information
+     _________________________________________________________________
+
+   8.1 Where can I go to ask questions?
+   8.2 I have some ideas for enhancements to IMAP. Where should I go?
+
+          If you have questions about the IMAP protocol, or want to
+          participate in discussions of future directions of the IMAP
+          protocol, the appropriate mailing list is
+          imap-protocol@u.washington.edu. You can subscribe to this
+          list via imap-protocol-request@u.washington.edu
+
+          If you have questions about this software, you can send me
+          email directly or use the imap-uw@u.washington.edu mailing
+          list. You can subscribe to this list via
+          imap-uw-request@u.washington.edu
+
+          If you have general questions about the use of IMAP software
+          (not specific to the UW IMAP toolkit) use the
+          imap-use@u.washington.edu mailing list. You can subscribe to
+          this list via imap-use-request@u.washington.edu
+
+          You must be a subscriber to post to these lists.  As an
+          alternative, you can use the comp.mail.imap newsgroup.
+          _________________________________________________________________
+
+   8.3 Where can I read more about IMAP and other email protocols?
+
+          We recommend Internet Email Protocols: A Developer's Guide, by
+          Kevin Johnson, published by Addison Wesley, ISBN 0-201-43288-9.
+     _________________________________________________________________
+
+   8.4 Where can I find out more about setting up and administering an
+   IMAP server?
+
+          We recommend Managing IMAP, by Dianna Mullet & Kevin Mullet,
+          published by O'Reilly, ISBN 0-596-00012-X.
+
+          This book also has an excellent comparison of the UW and Cyrus
+          IMAP servers.
+
+   Last Updated: 15 November 2007
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/IPv6.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,131 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+The following information about configuring inetd and xinetd for IPv6 was
+contributed by a user.  I have not checked it for accuracy or completeness,
+but have included it as-is in the hope that it may be useful:
+
+---------------------------------------------------------------------------
+One thing you might consider adding to the docs are hints for setting up
+inetd or xinetd to simultaneously listen on BOTH IPv4 and IPv6 for
+different OS.
+
+Some OS want to see separate IPv4-only and IPv6-only listening sockets
+configured in inetd.conf or xinetd.conf.  Others will accept IPv4
+connections on lines configured for IPv6 and actually generate errors if
+you have both configured when inetd or xinetd start up.  It's not clear to
+me whether this difference is due to how inetd or xinetd are built or
+whether it's due to the kernel's IP stack implementation.  I suspect it's
+really the latter.  Below are some examples:
+
+Here's a fragment of /usr/local/etc/xinetd.conf for a FreeBSD 4.9 server:
+
+service imap
+{
+        socket_type     = stream
+        protocol        = tcp
+        wait            = no
+        user            = root
+        server          = /usr/local/libexec/imapd
+}
+service imap
+{
+        flags           = IPv6
+        socket_type     = stream
+        protocol        = tcp
+        wait            = no
+        user            = root
+        server          = /usr/local/libexec/imapd
+}
+service imaps
+{
+        socket_type     = stream
+        protocol        = tcp
+        wait            = no
+        user            = root
+        server          = /usr/local/libexec/imapd
+}
+service imaps
+{
+        flags           = IPv6
+        socket_type     = stream
+        protocol        = tcp
+        wait            = no
+        user            = root
+        server          = /usr/local/libexec/imapd
+}
+
+Note that you have to specify a nearly identical paragraph for each
+service which differs only by the 'flags = IPv6'.  An equivalent
+inetd.conf would look something like:
+
+imap  stream  tcp     nowait  root    /usr/local/libexec/imapd        imapd
+imap  stream  tcp6    nowait  root    /usr/local/libexec/imapd        imapd
+imaps stream  tcp     nowait  root    /usr/local/libexec/imapd        imapd
+imaps stream  tcp6    nowait  root    /usr/local/libexec/imapd        imapd
+
+The man pages for inetd suggest that if you use a single entry with
+'tcp46' replacing either 'tcp' or 'tcp6' the system will listen on both
+types of addresses.  At least for the case of FreeBSD this is actually
+incorrect.
+
+Now if you were to use the above xinetd.conf on Fedora Linux, it would
+complain.  What does work under Linux is to create a single service
+paragraph for each service which will accept connections on both IPv4 and
+IPv6:
+
+In /etc/xinetd.d/imap:
+
+service imap
+{
+        flags       = IPv6
+        disable     = no
+        socket_type = stream
+        wait        = no
+        user        = root
+        server      = /usr/local/sbin/imapd
+}
+
+In /etc/xinetd.d/imaps:
+
+service imaps
+{
+        flags       = IPv6
+        disable     = no
+        socket_type = stream
+        wait        = no
+        user        = root
+        server      = /usr/local/sbin/imapd
+}
+
+The man page for xinetd says the IPv6 flag means xinetd will listen ONLY
+on IPv6.  However the actual behaviour (for Fedora Linux) is to listen on
+both IPv4 and IPv6.
+
+All of the above also applies to ipop3d.  Anyway, this might save some
+folks a little bit of head scratching time.
+---------------------------------------------------------------------------
+Addendum from the original submitter:
+---------------------------------------------------------------------------
+I've since learned that the discrepancy really is a function of the OS.
+It seems those systems that force you to create separate IPv4 and IPv6
+listeners in inetd (or xinetd) are the same systems that also disable
+IPv4-mapped IPv6 addresses by default.  This is a boot-time configuration
+option.  If you enable IPv4-mapped IPv6 addresses, then the 'tcp46' option
+in inetd works and the simplified config would look like:
+
+imap4   stream  tcp46   nowait  root    /usr/local/libexec/imapd        imapd
+imaps   stream  tcp46   nowait  root    /usr/local/libexec/imapd        imapd
+
+In FreeBSD, enabling IPv4-mapped addresses is done by adding
+ipv6_ipv4mapping="YES" to /etc/rc.conf (in addition to ipv6_enable="YES").
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/RELNOTES	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,787 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+Updated: 16 December 2008
+
+imap-2007e is a maintenance release, consisting primarily of bugfixes to
+problems discovered in the release that affected a small number of users
+plus a security fix for users of the RFC822BUFFER routines.
+
+
+Updated: 29 October 2008
+
+imap-2007d is a maintenance release, consisting primarily of bugfixes to
+problems discovered in the release that affected a small number of users
+plus a security fix for users of tmail or dmail.
+
+
+Updated: 25 March 2008
+
+imap-2007b is a maintenance release, consisting primarily of bugfixes to
+problems discovered in the release that affected a small number of users.
+
+
+Updated: 2 January 2008
+
+imap-2007a is a maintenance release, consisting primarily of bugfixes to
+problems discovered in the release that affected a small number of users.
+
+
+Updated: 20 December 2007
+
+imap-2007 is a release corresponding with the release of Alpine 1.0.
+The primary focus of the imap-2007 release is bugfixes and reliability
+improvements.  This includes:
+ . fixes to problems discovered between the Alpine 0.99999 pre-release
+    and Alpine 1.0
+ . fixes to the mix driver to timing race problems uncovered by Timo
+    Sirainen's imaptest suite.  imap-2007 using the mix format is
+    believed to pass imaptest completely.
+
+A new function, utf8_csvalidmap(), has been added for the benefit of
+Alpine to use in examining UTF-8 text and determining efficiently
+whether it can be downgraded to a legacy charset.  If you develop an
+MUA, this may be useful for you too, although you'll have to read the
+source code to see how to use it.  The purpose of the "not-CJK" bit is
+to prevent messages being downgraded to a CJK charset if all they have
+in that charset are some special punctuation.
+
+
+Updated: 5 September 2007
+
+imap-2006k is a maintenance release, consisting primarily of bugfixes to
+problems discovered in the release that affected a small number of users.
+
+The primary focus of this maintenance release is to correct deadlock
+issues.  There were two major causes of the deadlocks:
+ . a change in imap-2006i attempted to resolve a glibc mutex-based
+   deadlock in imapd's signal handler, but ended up worsening the problem.
+ . a bug in the mbx driver, introduced as part of the UIDPLUS work in 2006,
+   applied an mbx-style lock briefly on a traditional UNIX format mailbox.
+   If the traditional UNIX format mailbox was already locked by some other
+   process, the result would be a deadlock of both processes.
+
+imapd's signal handling logic is rewritten to avoid the mutex issue, and
+the mbx driver is fixed so that mbx-style locks are only applied to mbx
+format mailboxes.
+
+imapd now supports the WITHIN extension.
+
+
+Updated: 14 June 2007
+
+imap-2006j is a maintenance release, consisting primarily of bugfixes to
+problems discovered in the release that affected a small number of users.
+
+
+Updated: 5 June 2007
+
+imap-2006i is a maintenance release, consisting primarily of bugfixes to
+problems discovered in the release that affected a small number of users.
+
+imapd now supports the CHILDREN and ESEARCH extensions.
+
+imapd's attempt to return COPYUID/APPENDUID information for a traditional
+UNIX (and MMDF) format mailbox when the mailbox is open by another process
+has been declared to be a failure and is now revoked.  It was subject to a
+timing race, loss of which involved an expensive reset of the mailbox's UID
+regime.  Any imapd COPY or APPEND to a traditional UNIX or MMDF format that
+is open by some other process will now no longer return COPYUID/APPEND.
+Although this is technically in violation of RFC 4315, there is a loophole
+in that document and the timing race/performance problem is worse.
+
+
+Updated: 4 April 2007
+
+imap-2006h is a maintenance release, consisting primarily of bugfixes to
+problems discovered in the release that affected a small number of users.
+
+
+Updated: 30 March 2007
+
+imap-2006g is a maintenance release, consisting primarily of bugfixes to
+problems discovered in the release that affected a small number of users.
+
+
+Updated: 30 January 2007
+
+imap-2006f is a maintenance release, consisting primarily of bugfixes to
+problems discovered in the release that affected a small number of users.
+
+For the benefit of multi-threaded applications, use of strtok() has been
+abolished in the c-client library.  imapd and ipop3d stuff use it though.
+The TOPS-20 and VAX/VMS ports still use strtok() since they don't use UNIX
+threads.
+
+This version has been test-built on Linux, Mac OS X, NeXT, Windows XP,
+TOPS-20, and VAX/VMS.  This will probably be the last test-build on VAX/VMS
+since the system I use for that purpose is being shut down.  I have no way
+to test-build on DOS, legacy Mac OS (OS 9 and earlier), OS/2, or Windows CE;
+and the builds on those systems are probably broken.
+
+
+Updated: 26 January 2007
+
+imap-2006e is a maintenance release, consisting primarily of bugfixes to
+problems discovered in the release that affected a small number of users.
+
+
+Updated: 6 December 2006
+
+imap-2006d is a maintenance release, consisting primarily of bugfixes to
+problems discovered in the release that affected a small number of users.
+
+The decomposition mapping, title-case mapping, and character widths tables
+have been updated to comply with the Unicode 5.0 standard.
+
+Prototypes for the utf8aux.c functions have been moved to a new utf8aux.h.
+
+The general c-client modules now include c-client.h instead of the individual
+files.  Use of c-client.h instead of individual include files insulates
+against future shuffling of include files.
+
+
+Updated: 23 October 2006
+
+imap-2006c is a maintenance release, consisting primarily of bugfixes to
+problems discovered in the release that affected a small number of users.
+
+By popular request, if a user has a mix (or other dual-use) format INBOX,
+it will no longer be listed as \NoInferiors.  It's a bad idea to depend
+upon this due to the case ambiguity issue, but it's there.
+
+
+Updated: 26 September 2006
+
+imap-2006b is a maintenance release, consisting entirely of bugfixes to
+problems discovered in the release that affected a small number of users.
+
+
+Updated: 15 September 2006
+
+imap-2006a is a maintenance release, consisting entirely of bugfixes to
+problems discovered in the release that affected a small number of users.
+
+If it is necessary to build IPv4-only on one of the ports that has IPv6
+preconfigured (ldb, lfd, lmd, lrh, lsu, osx, oxp), this can be done by
+using IP6=4.  You can't do IP=4 in the build command directly since these
+ports set IP themselves; however, now instead of setting IP=6 they now set
+IP=$(IP6).
+
+
+Updated: 30 August 2006
+
+imap-2006 is a major release.  Programs written for imap-2004g should
+build with this version with minor or no modification.  imap-2005 was not
+released except as development snapshots.
+
+imap-2006 contains major extensions to its Unicode support.  Searching and
+sorting are now done with strings canonicalized to titlecase and decomposed
+form.  Among other things, this means that Latin letters with diacriticals
+will now sort with the basic Latin letter, and case-independent searching of
+such letters (e.g., German umlauts) now works.  Previously, sorting was done
+strictly by Unicode codepoint, and case-independence only worked with ASCII.
+
+imapd now supports the UIDPLUS extension for mailboxes in unix, mmdf, mbx, mx,
+and mix formats.  UID EXPUNGE is fully implemented.  Note that UIDPLUS is not
+supported in the little-used drivers (mh, mtx, tenex) in which meaningful
+APPENDUID/COPYUID data can not be returned.  Refer to bugs.txt for more
+details.
+
+The new mix format is a dual-use mailbox format designed for performance and
+reliability with large mailboxes.  mix is documented in file mixfmt.txt.
+
+SSL/TLS certificate validation on UNIX now checks the alternative names in the
+certificate if the CN does not match.
+
+The new /tls-sslv23 flag in a mailbox name causes a TLS session to use the
+(incorrect) SSLv23 client method instead of the TLSv1 client method.  Some
+broken servers use the SSLv23 server method, and this flag works around that
+problem.  WARNING: use of this flag will cause TLS negotiation to fail with
+a server which uses the proper TLSv1 server method.  Additionally, there are
+known security risks in SSLv2; so users should be suspicious if this switch
+suddenly becomes necesary.
+
+The silly mailbox flag combination /ssl/tls is now rejected as an invalid
+remote specification.  Previous versions tried to negotiate TLS over an SSL
+session; even if the server permitted such a thing it couldn't work.
+
+The memory management of several drivers has been redesigned to consume less
+memory and hopefully be faster.
+
+The private.data member of the MESSAGECACHE (elt) has been replaced with
+a union that contains private.spare.data and private.spare.ptr, the latter
+being a pointer.
+
+A new FT_RETURNSTRINGSTRUCT flag has been added for mail_fetch_body() and
+mail_fetch_text() calls.  If this flag is set, *and* if the function returns
+NIL, then the requested string data is available on a stringstruct on
+stream->private.string.  This is a special hack for the IMAP and POP servers
+and is subject to incompatible change.  The result is a major performance
+improvement in the servers with the mbx driver, particularly with large
+messages.
+
+
+Updated: 15 September 2005
+
+imap-2004g is a maintenance release, and consists solely of a bugfix to
+quoted string handling in the mailbox name parsing routine.
+
+
+Updated: 15 August 2005
+
+imap-2004f is a maintenance release, and consists solely of a bugfix to
+the TCP code.
+
+Also included is a new version of the UNIX SSL/TLS routines that allows the
+SSL/TLS certificate validation client code to validate alternative names in
+server certificates.  This code has not been thoroughly regression-tested but
+is believed to work.  To use this new code instead of the old support:
+	cd imap-2004f/src/osdep/unix
+	mv ssl_unix.c ssl_unix.old
+	mv ssl_unix.new ssl_unix.c
+Then rebuild.
+
+
+Updated: 21 June 2005
+
+imap-2004e is a maintenance release, consisting entirely of bugfixes.
+
+There are no user-visible functional enhancements in this version.
+
+
+Updated: 20 April 2005
+
+imap-2004d is a maintenance release, released concurrently with Pine
+4.63, and consists primarily of bugfixes
+
+There is now a workaround for RedHat breaking flock().  However, since
+RedHat has said that they don't support flock(), there is no guarantee
+that they won't break it in the future.  So you may want to consider some
+other Linux distribution or BSD instead.  See:
+	https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=123415
+for the gruesome details.
+
+There are no user-visible functional enhancements in this version.
+
+
+Updated: 18 January 2005
+
+imap-2004c is a maintenance release, released concurrently with Pine
+4.62, including fixes to quoted-printable encoding and CRAM-MD5
+authentication.
+
+NNTP proxy in imapd now supports the LIST and LSUB commands.
+
+There are no other user-visible functional enhancements in this version.
+
+
+Updated: 29 November 2004
+
+imap-2004b is a maintenance release, consisting primarily of bugfixes.
+Programs written for imap-2004a will build with this version without
+modifification.
+
+There are new ports for Solaris with Blastwave Community Open Source
+Software (gcs) and Mandrake Linux (lmd).
+
+SET_SNARFINTERVAL now controls how frequently local drivers will move new
+mail from the mail spool as well as from a maildrop.  Maildrops are still
+tied to a minimum interval of 1 minute, but there is now no minimum for the
+spool file.
+
+Character set conversions now map non-breaking space to space if the
+destination character set doesn't have nbsp.  JIS Roman yen sign is now
+mapped to Unicode yen sign.
+
+There are no user-visible functional enhancements in this version.
+
+
+Updated: 8 July 2004
+
+imap-2004a is a maintenance release, consisting primarily of critical
+bugfixes.  Programs written for imap-2004 will build with this version
+without modification.
+
+imapd now has a supported NNTP proxy capability.  If the file /etc/imapd.nntp
+exists, the contents of that file are used as the host name of an NNTP
+server which will be used whenever a #news. name is used.  For example, if
+/etc/imapd.nntp contains nntp.example.com, and the IMAP client SELECTs or
+EXAMINEs the name #news.comp.mail.imap, what will actually be opened in
+imapd is {nntp.example.com/nntp}comp.mail.imap
+
+The OSF/1 port (Digital UNIX, Tru64) now uses flocksim instead of flcksafe.
+Some cretin decided to delete the winning flock() call and make flock() use
+the losing fcntl() call instead.
+
+The unix[nt] and mmdf drivers now prevent mail_append() from writing Status:,
+X-Status:, X-UID, X-IMAP[base]:, and X-Keywords: header lines to a
+traditional UNIX or MMDF format mailbox.  If any such lines are in the
+text supplied to mail_append(), they will be quoted by prefixing with
+"X-Original-" (e.g. Status: will become X-Original-Status:).
+
+There are no user-visible functional enhancements in this version.
+
+
+Updated: 10 May 2004
+
+imap-2004 is a major release.  Programs written for imap-2002e should
+build with this version with minor modification.  imap-2003 was not
+released except as development snapshots.
+
+mailutil has three new commands: delete, rename, and prune.
+
+IPv6 support now exists for UNIX and W2K.  It is the default in W2K builds.
+On UNIX, add "IP=6" to the make command line.  Windows IPv6 support is
+only for W2K builds.
+
+The NNTP driver now supports NNTP SASL and TLS.
+
+The ldb (Debian) and lrh (RedHat) ports now look for mlock on
+/usr/sbin/mlock instead of /etc/mlock.
+
+imapd now supports the LITERAL+ and SASL-IR initial-response extensions.
+
+The IMAP driver has some additional checks to reduce the amount of network
+traffic, including executing "silly searches" (searches of sequence numbers
+only) locally.
+
+The IMAP, POP, SMTP, and NNTP drivers now have diagnostic code to provide
+better information about servers which violate SASL's empty challenge
+requirements (e.g. with the PLAIN mechanism).
+
+There is a new mail_fetch_overview_sequence() function which is like
+mail_fetch_overview() but takes a sequence number string as an argument.
+There should have been a flags argument and FT_UID bit as in all the other
+mail_fetch_???() functions but compatibility with the past... :-(
+
+The overview_t callback (from mail_fetch_overview()) now has a fourth
+argument which contains the message sequence number (as opposed to the UID
+which is in the second argument).  It turned out that some applications were
+calling mail_msgno() (which can be moderately expensive) to get the sequence
+number, and c-client already knew it.
+
+Many declarations which are completely internal to a driver have been removed
+from the driver .h file, and in those cases where there are no external
+declarations left the .h file has been eliminated entirely.  As part of this,
+the mbox driver routines are now incorporated with the unix driver routines
+as opposed to being a separate file.  The mbox driver still needs to be lunk
+in order to get the mbox functionality.
+
+
+Updated: 27 August 2003
+
+imap-2002e is a minor release, released concurrently with Pine 4.58, and
+contains primarily bugfixes.  Programs written for imap-2002d will build
+with this version without modification.
+
+The NNTP client code now tries to perform better with legacy NNTP servers
+which do not comply with the current NNTP protocol specification draft, most
+notably Netscape Collabra.
+
+Delivery notifications now work reliably with SMTP servers that support it.
+
+The following changes are primarily of concern to developers and power users:
+
+There is a "limited advertise" option in env_unix.c which, if set, will only
+advertise the user's own namespace and the #shared/ namespace.
+
+It is now possible to build the IMAP toolkit with a separate SSL KEY file
+from the certificate file (SSLKEYS vs. SSLCERTS).
+
+A new BODY structure element, sparep, is available for the main program to
+use as a pointer for its own purposes; as well as a SET_FREEBODYSPAREP
+function, similar to SET_FREEENVELOPESPAREP, SET_FREEELTSPAREP, etc.
+
+
+Updated: 28 May 2003
+
+imap-2002d is a minor release, released concurrently with Pine 4.56, and
+contains primarily bugfixes.  Programs written for imap-2002 should build
+with this version without modification, with one exception.  That exception
+is the ngbogus envelope flag, which stopped being used in imap-2002c and is
+now gone for good.
+
+The NNTP newsgroup listing code now tries to use wildmats on the NNTP server,
+which should result in better performance especially on slow lines.  It is
+also once again permitted to log in on NNTP servers when /loser is set.
+
+imapd now supports the UNSELECT command.
+
+A new envelope flag, imapenvonly, indicates that the envelope in a
+MESSAGE/RFC822 BODY structure only has the IMAP envelope components and
+not the additional components from c-client: Newsgroups, Followup-To,
+and References.
+
+
+Updated: 7 April 2003
+
+imap-2002c is a minor release, released concurrently with Pine 4.55, and
+contains primarily bugfixes.  Programs written for imap-2002 will build
+with this version without modification.
+
+The POP3 driver will, with new servers that support CAPA, use the LIST
+command to get the elt->rfc822_size and the TOP command to get the message
+header, instead of fetching the entire message.  Note that it is a bad idea
+to do this with old servers, since they may misimplement LIST and TOP.  The
+result is a substantial performance improvement.
+
+Subject extraction for comparisons in SORT and THREAD are now done in full
+compliance with the rules laid out in the specification.  This only makes
+a difference if "re:" was part of a MIME quoted-word.
+
+The new experimental #move namespace allows download-and-delete from a source
+mailbox to a destination mailbox.  Immediately following #move is a delimiter
+character which must not appear in the source mailbox name, then the source
+mailbox name, then the delimiter again, then the destination mailbox name.
+For example:
+	#move+{pop3.foo.com/pop3}+INBOX
+will download messages from "pop3.foo.com" into your local INBOX.
+
+The NNTP driver now uses the LIST EXTENSIONS command as described in the
+current NNTP protocol specification draft, and will prefer to use OVER over
+XOVER, HDR over XHDR, etc.
+
+The SET_NNTPRANGE function of mail_parameters() can be used to limit the
+number of articles recognized by the NNTP driver, resulting in a substantial
+performance improvement with NNTP servers that may have hundreds of thousands
+of old articles in the spool.  If set non-zero, then only the last n article
+numbers will be considered.  If you are on a slow link, you may want to set
+this to 1000 or less.
+
+Besides the normally tested UNIX and 32-bit Microsoft platforms, this release
+has also been tested and will once build under TOPS-20 and VAX/VMS.  I also
+fixed a bug which would keep it from building on 16-bit DOS, but I don't know
+if it will build on that platform or not since I no longer have a system with
+the old DOS C compiler.  It has not been tested on Macintosh (note however
+that Mac OS X is a type of UNIX and should build), Amiga, or OS/2, and probably
+no longer builds on those platforms.
+
+
+Updated: 7 January 2003
+
+imap-2002b is a maintenace release, released concurrently with Pine 4.52,
+and contains only bugfixes.  Programs written for imap-2002 will build with
+this version without modification.
+
+Drivers which do not announce new mail are now indicated by the DR_NONEWMAIL
+driver flag.  Driver which do not announce new mail when read-only are now
+indicated by the DR_NONEWMAILRONLY flag.
+
+There are no user-visible functional enhancements in this version.
+
+
+Updated: 10 December 2002
+
+imap-2002a is a maintenance release, consisting entirely of critical
+bugfixes.  Programs written for imap-2002 will build with this version
+without modification.
+
+There are no functional enhancements in this version.
+
+
+Updated: 28 October 2002
+
+imap-2002 is a major release.  Programs written for imap-2001 will probably
+build with this version without modification, with one exception.  That
+exception is if the program uses [GS]ET_DISABLEAUTOMATICSHAREDNAMESPACES,
+which has been renamed to [GS]ET_DISABLEAUTOSHAREDNS in order to placate
+some compilers which don't like very long names.
+
+SSLTYPE=nopwd is now the default, in accordance with current IESG security
+requirements.  In order to build the IMAP toolkit without SSL/TLS you must
+now use SSLTYPE=none.  At initial build time, you will be told if the SSLTYPE
+setting is in compliance with IESG security requirements, and if it is not
+you will be asked to confirm to continue the build.
+
+ORDEREDSUBJECT threading has been changed in accordance with draft 12 of the
+IMAP threading specification.  Previously, each non-root message in an
+ORDEREDSUBJECT thread has been a child of the message immediately preceeding
+it in the thread.  Draft 12 changes this so that the second message in the
+thread is the child of the first (root) message, and all subsequent messages
+are siblings of the first message.  This is significant in MUAs which display
+the thread structure graphically; the new definition is much saner than the
+old one since it does not nest endlessly due to parent/child relationships
+that may not exist.  This also impacts imapd, since imapd's THREAD command
+will return a thread structure.
+
+RFC 1730 server support, which was disabled in imap-2001, is now fully
+removed from imapd.  imapd still supports IMAP2bis, specifically the FIND
+command, since there are still a few IMAP2 clients out there.
+
+The IMAP client routines in the c-client library continue to support recognize
+RFC 1730 servers, but do not implement the deprecated features of RFC 1730.
+
+The Frequently Asked Questions file is now in HTML format, although a text
+version (generated from the HTML version with Lynx) is also provided.
+
+A new program, mailutil, is now bundled with the IMAP toolkit.  mailutil
+replaces the old chkmail, imapcopy, imapmove, imapxfer, mbxcopy, mbxcreat,
+and mbxcvt programs that were distributed in the imap-utils.  In addition,
+the tmail, dmail, and mlock programs from the imap-utils are now also
+bundled with the IMAP toolkit.
+
+In addition to the usual bugfixes, the following c-client functionalities
+are new in imap-2002:
+
+The SET_DISABLE822TZTEXT parameter allows a client to suppress generation of
+the "human friendly" time zone text in RFC822 dates.  This placates netnews
+and some broken SMTP servers which think that long timezone names from Windows
+are an attempt at a buffer overflow attack.
+
+The restrictBox option in env_unix.c sets "restricted box" functionality,
+which disables access to the root (leading "/"), access to other user's
+directories (leading "~"), and access to superior directories via "..".
+
+Content-Location is now supported by the "location" member of the BODY
+structure.  Note that there is a bug in the IMAP client code in older
+versions of the c-client library that causes it to handle BODYSTRUCTURE
+extension data improperly if that data is a literal.  The new functionality
+for Content-Location may trigger this bug.  The fix is either to upgrade
+the IMAP client program to the imap-2002 version of c-client or to remove
+the Content-Location support from imapd.
+
+There are now 8 spare bits for application use in both the elts and the
+mail streams.
+
+mail_search() now returns a value (previously it was void).  If mail_search()
+returns NIL, then the supplied charset was invalid or the IMAP server
+returned NO (probably because the supplied charset was invalid).
+
+New utf8_charset() routine to look up a charset and return c-client's
+database about that charset if found.  Among other things, this will give
+you the scripts supported by that charset and its Unicode conversion table.
+
+New FT_NOLOOKAHEAD flag for mail_fetch_structure() disables fetching of
+any envelopes other than the one specified.  Otherwise, it will try to do
+anticipatory fetching (up to IMAPLOOKAHEAD).
+
+New GET_FETCHLOOKAHEAD allows better control of mail_fetch_structure()
+lookahead.  Instead of looking IMAPLOOKAHEAD messages forward from the
+specified message, it will use a supplied SEARCHSET to generate message
+sequences and ranges.  It will stop at IMAPLOOKAHEAD messages or at the
+completion of a range which exceeds IMAPLOOKAHEAD.  The search set only
+applies to the next mail_fetch_structure() on that stream, and is cleared
+once it is used.  Call with
+  SEARCHSET **set = (SEARCHSET **)
+    mail_parameters (stream,GET_FETCHLOOKAHEAD,(void *) stream);
+  *set = pointer to desired search set
+
+New mail_shortdate() routine returns an date in the format expected by
+SEARCHPGMs.
+
+
+Updated: 2 November 2001
+
+imap-2001a is a maintenance release, consisting primarily of bugfixes
+including some critical bugfixes to crash and denial of service problems.
+Programs written for imap-2001 will build with this version without
+modification.
+
+The following new facilities have also been added:
+
+The new /norsh switch in mailbox names provides a more intuitive way of
+disabling rsh-IMAP than the existing :143 or setting the rsh-timeout to 0.
+
+Passwords are no longer returned in mm_dlog() callbacks unless the
+application sets the SET_DEBUGSENSITIVE parameter.
+
+The SET_NETFSSTATBUG parameter allows an application to force the
+traditional UNIX mailbox driver to close and reopen the mailbox at ping
+time.  This is EXTREMELY inefficient, and should only be used to access
+files stored on AFS and old NFS systems.
+
+The ISO 8859 and Windows conversion tables have been updated to comply
+with Unicode 3.1, and the KOI8-R table has been verified as compliant with
+Unicode 3.1.
+
+The SPECIALS mechanism for passing parameters to the lowest level Makefile
+has been updated to be more general.  See the next item for why you might
+care.
+
+New lrh port to build on Red Hat Linux 7.2, with pre-set definitions for
+the places where Red Hat has placed Kerberos and SSL.  It's actually just
+the lnp port with SPECIALS defined accordingly.  You may want to use it as
+a model if your system needs such definitions.  Note that SPECIALS is
+primarily for IMAP toolkit (and Pine) purposes, and that user settings
+should use EXTRASPECIALS instead.
+
+
+Updated: 22 June 2001
+
+imap-2001 is a major release.  Programs written for imap-2000 will probably
+build with this version without modification.
+
+The FAQ document has been significantly expanded.  Be sure to read it for
+more information.
+
+In addition to the usual bugfixes, the following features are new in
+imap-2001:
+
+SSL is now fully integrated into the IMAP toolkit; the old "alt" kludges to
+be able to produce a "sanitized" version of the IMAP toolkit to comply with
+late unlamented US export regulations are now completely gone.
+
+Full client and server TLS support is also in this release.
+
+The server certificate must be signed by a trusted certificate authority and
+the name in the certificate match the user's entry for the server host name;
+this means that the user must enter a fully-qualified host name.
+
+To build with SSL/TLS on UNIX, you now use "SSLTYPE=unix" instead of the
+former "SPECIALAUTHENTICATORS=ssl".  To build with SSL/TLS on UNIX and disable
+the use of plaintext passwords except when under SSL/TLS, use "SSLTYPE=nopwd"
+instead of "SSLTYPE=unix".
+
+RFC 1730 (IMAP4 as opposed to IMAP4rev1) support is turned off by default in
+imapd.  No clients should still be using RFC 1730 protocol.  Look at the imapd
+Makefile for how to re-enable RFC 1730 support.  Note that this code may be
+removed in the future, so if you think you need it you had better let me know.
+
+There are some new options (turned off by default) which attempt to work around
+problems in certain clients.  See the FAQ file for more details.
+
+
+Updated: 24 January 2001
+
+imap-2000c is a maintenance release, consisting primarily of bugfixes.
+
+
+Updated: 9 January 2001
+
+imap-2000b is a maintenance release, consisting primarily of bugfixes.
+
+
+Updated: 9 November 2000
+
+imap-2000a is a maintenance release, consisting primarily of bugfixes.
+
+
+Updated: 19 September 2000
+
+imap-2000 is a major release.  There are major internal and external changes
+from earlier versions (imap-4.x and imap-3.x series).  Programs written for
+imap-4.x will probably build with this version without modification.  It is
+extremely unlikely that a program written for imap-3.x or earlier series will
+build with this version without modifications.  Drivers written for earlier
+versions will definitely need to be rewritten.
+
+In addition to the usual bugfixes, the following features are new in imap-2000:
+
+SSL support is now available.  For UNIX, it is necessary to install some
+version of OpenSSL; see imap-2000/docs/SSLBUILD for more information.  SSL
+support is now automatic for the NT, NTK, and W2K ports.  SSL use is indicated
+by the /ssl switch in the mailbox name.
+
+With SSL connections, the server certificate is validated by the client code
+on UNIX, and Windows 2000 unless /novalidate-cert is specified.  Server
+certificates are currently is not validated on Windows 9x, Windows Millenium,
+or Windows NT 4; this is an artifact of the operating system and not the port
+(e.g. client code using the NT port will validate certificates if running on
+Windows 2000).  On UNIX, the server certificate must be signed by a trusted
+certificate authority.  On Windows 2000, the certificate must be signed by a
+trusted certificate authority and match the user's entry for the server host
+name; this means that the user must enter a fully-qualified host name.
+
+Calendar reclama for the benefit of old broken non-Y2K compliant software.
+Two digit years from 00 to 69 will be interpreted as 2000 through 2069.  In
+addition, three digit years from 100 to 105 will be interpreted as 2000
+through 2005.
+
+Support for REFERENCES threading (in addition to the previously-existing
+ORDEREDSUBJECT threading).
+
+Support for the IMAP MULTIAPPEND extension.  This allows much faster uploading
+of multiple messages to an IMAP server.
+
+Support for the LOGINDISABLED IMAP capability.  If the IMAP server sends
+LOGINDISABLED as a capability, the client code will never attempt to send an
+IMAP LOGIN command.
+
+Support for SASL authentication identity vs. authorization identity.  If the
+authentication method does not support this concept (e.g. AUTH=CRAM-MD5,
+AUTH=LOGIN, LOGIN command), the "*" character in the user name may be used to
+indicate a separate authentication identity; for example, "fred*joe" indicates
+authorization identity "fred", authentication identity "joe".
+
+
+UNIX-specific Changes:
+
+Support for SASL authentication identity vs. authorization identity in the
+IMAP and POP3 servers.  If the user indicated by the authentication identity
+is in the "mailadm" group, he may specify any authorization identity and get
+logged in as the authorization identity user.
+
+If the IMAP and POP3 servers are build with PASSWDTYPE=nul, it will send
+LOGINDISABLED as a capability and also disable the AUTH=LOGIN and AUTH=PLAIN
+SASL authenticators.
+
+New MAILSUBDIR build option to change the default mailbox directory from the
+user's home directory to a subdirectory of the user's home directory.  See
+imap-2000/Makefile for more information.
+
+New CHROOT_SERVER build option for closed server systems only.  If defined, a
+chroot() call to the user's home directory is done as part of the login
+process.  See imap-2000/Makefile for more information.
+
+New ADVERTISE_THE_WORLD build option which will add an IMAP namespace that
+points to the root.  Not for the faint of heart.
+
+UNIX format mailboxes no longer require the pseudo-message, nor will a
+pseudo-message be added to a mailbox that does not have one.  A new
+X-IMAPbase: header will be written in the first message.  This is rather less
+efficient and robust than the pseudo-message (which remains the encouraged
+mechanism; UNIX format mailboxes will always be created with it), but perhaps
+will pacify some people who get upset by the pseudo-message.
+
+When building with MIT Kerberos it will try to detect and use libk5crypto.a
+instead of libcrypto.a.
+
+The mbx driver is more aggressive about cleaning up expunged messages that
+couldn't be purged because of shared access to the mailbox at the time of
+expunge.  Now, every checkpoint will try to purge such messages; and a
+checkpoint is attempted at close time.
+
+
+Windows-specific Changes:
+
+New W2K port for Windows 2000.  In addition to supporting SSL using the
+official SSPI interface (the NT and NTK ports invoke SChannel.DLL directly),
+the W2K port also supports Microsoft Kerberos.  Note that the NT and NTK ports
+will work on Windows 2000, but the W2K port will not work on NT4, Windows
+9x, or Windows Millenium.
+
+There is now a #user namespace, equivalent to the "~" namespace on UNIX.
+
+
+
+Changes for Developers:
+
+New c-client.h file which acts as a master include.  c-client based
+applications should now include c-client.h instead of the individual c-client
+files (mail.h, misc.h, etc.).  It is believed that c-client.h will work in C++
+applications.
+
+New GET_FREEENVELOPESPAREP/SET_FREEENVELOPESPAREP and
+GET_FREEELTSPAREP/SET_FREEELTSPAREP function callbacks to free the "sparep"
+member of the envelope and cache elements, respectively.
+
+New OP_MULNEWSRC flag to mail_open() to use multiple newsrc files, and new
+GET_NEWSRCQUERY/SET_NEWSRCQUERY function callbacks to get the name of the
+newsrc file for news access.
+
+New "secret" nntp_article() function to do the NNTP ARTICLE command; this is
+generally useful only when chasing news URLs.
+
+New GET_HIDEDOTFILES/SET_HIDEDOTFILES feature to suppress file names that
+start with "." in mail_list() results.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/SSLBUILD	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,267 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+		  SSL/TLS BUILD AND INSTALLATION NOTES FOR UNIX
+			 Last Updated: 15 November 2007
+
+PREREQUISITES BEFORE STARTING:
+ 1) Review the information in imap-2007/docs/BUILD.
+ 2) Obtain a copy of OpenSSL.  OpenSSL is available from third parties.  We
+    do not provide OpenSSL.
+ 3) Make sure that you know how to build OpenSSL properly on the standard
+    /usr/local/ssl directory.  In particular, /usr/local/ssl/include (and
+    /usr/local/ssl/include/openssl) and /usr/local/ssl/lib must be set up
+    from the OpenSSL build.  If you have a non-standard installation, then
+    you must modify the imap-2007/src/osdep/unix/Makefile file to point
+    to the appropriate locations.
+ 4) Make sure that you know how to obtain appropriate certificates on your
+    system.
+
+NOTE: We can NOT provide you with support in building/installing OpenSSL, or
+in obtaining certificates.  If you need help in doing this, try the contacts
+mentioned in the OpenSSL README.
+
+
+SSL BUILD:
+
+     By default, the IMAP toolkit builds with SSL and disabling plaintext
+passwords unless SSL/TLS encryption is in effect (SSLTYPE=nopwd).  This
+produces an IMAP server which is compliant with RFC 3501 security
+requirements.
+
+     To build with SSL but allow plaintext passwords in insecure sessions,
+add "SSLTYPE=unix" to the make command line.  Note that doing so will
+produce an IMAP server which is NON-COMPLIANT with RFC 3501.
+
+     To build without SSL, add "SSLTYPE=none" to the make command line.
+Note that doing so will produce an IMAP server which is NON-COMPLIANT
+with RFC 3501.
+
+     There are other make options relevant to SSL, described in
+ imap-2007/src/osdep/unix/Makefile
+The most important of these are SSLDIR, SSLCRYPTO, and SSLRSA.
+
+     SSLDIR is set to /usr/local/ssl by default.  This is the normal
+installation directory for OpenSSL.  If your system uses a different directory
+you will need to change this.
+
+     SSLCRYPTO is set to -lcrypto by default.  Older versions of MIT Kerberos
+also have a libcrypto and will cause a library name conflict.  If you are
+using an older version of Kerberos, you may need to change SSLCRYPTO to
+$(SSLLIB)/libcrypto.a
+
+     SSLRSA is set empty by default.  It can be set to specify the RSAREF
+libraries, which you once had to use with OpenSSL to use RSA algorithms
+legally if you are in the USA, due to patent issues.  Since RSA Security Inc.
+released the RSA algorithm into the public domain on September 6, 2000, there
+is no longer any reason to do this.
+
+
+SSL INSTALLATION:
+
+     Binaries from the build are:
+	imap-2007/mtest/mtest		c-client testbed program
+	imap-2007/ipopd/ipop2d		POP2 daemon
+	imap-2007/ipopd/ipop3d		POP3 daemon
+	imap-2007/imapd/imapd		IMAP4rev1 daemon
+
+     mtest is normally not used except by c-client developers.
+
+STEP 1:	inetd setup
+
+
+     The ipop2d, ipop3d, and imapd daemons should be installed in a system
+daemon directory and invoked by a listener such as xinetd or inetd.  In the
+following examples, /usr/local/etc is used).
+
+STEP 1(A): xinetd-specific setup
+
+     If your system uses xinetd, the daemons are invoked by files in your
+/etc/xinetd.d directory with names corresponding to the service names (that
+is: imap, imaps, pop2, pop3, pop3s).  You will need to consult your local
+xinetd documentation to see what should go into these files.  Here is a a
+sample /etc/xinetd.d/imaps file:
+
+service imaps
+{
+	disable		= no
+	socket_type	= stream
+	wait		= no
+	user		= root
+	server		= /usr/local/etc/imapd
+	groups		= yes
+	flags		= REUSE IPv6
+}
+
+STEP 1(B): inetd-specific setup
+
+     If your system still uses inetd, the daemons are invoked by your
+/etc/inetd.conf file with lines such as:
+
+pop	stream	tcp	nowait	root	/usr/local/etc/ipop2d	ipop2d
+pop3	stream	tcp	nowait	root	/usr/local/etc/ipop3d	ipop3d
+imap	stream	tcp	nowait	root	/usr/local/etc/imapd	imapd
+pop3s	stream	tcp	nowait	root	/usr/local/etc/ipop3d	ipop3d
+imaps	stream	tcp	nowait	root	/usr/local/etc/imapd	imapd
+
+     Please refer to imap-2007/docs/BUILD for an important note about inetd's
+limit on the number of new connections.  If that note applies to you, and you
+can configure the number of connection in /etc/inetd.conf as described in
+imap-2007/docs/build, here is the sample /etc/inetd.conf entry with SSL:
+
+pop3	stream	tcp	nowait.100	root	/usr/local/etc/ipop3d	ipop3d
+pop3s	stream	tcp	nowait.100	root	/usr/local/etc/ipop3d	ipop3d
+imap	stream	tcp	nowait.100	root	/usr/local/etc/imapd	imapd
+imaps	stream	tcp	nowait.100	root	/usr/local/etc/imapd	imapd
+ (or, if you use TCP wrappers)
+pop3	stream	tcp	nowait.100	root	/usr/local/etc/tcpd	ipop3d
+imap	stream	tcp	nowait.100	root	/usr/local/etc/tcpd	imapd
+pop3s	stream	tcp	nowait.100	root	/usr/local/etc/ipop3d	ipop3d
+imaps	stream	tcp	nowait.100	root	/usr/local/etc/imapd	imapd
+
+NOTE: do *NOT* use TCP wrappers (tcpd) for the imaps and pop3s services!  I
+don't know why, but it doesn't work with TCP wrappers.
+
+
+STEP 2:	services setup
+
+     You may also have to edit your /etc/services (or Yellow Pages,
+NetInfo, etc. equivalent) to register these services, such as:
+
+pop		109/tcp
+pop3		110/tcp
+imap		143/tcp
+imaps		993/tcp
+pop3s		995/tcp
+
+NOTE: The SSL IMAP service *MUST* be called "imaps", and the SSL POP3 service
+*MUST* be called "pop3s".
+
+
+STEP 3: PAM setup
+
+     If your system has PAM (Pluggable Authentication Modules -- most
+modern systems do) then you need to set up PAM authenticators for imap and
+pop.  The correct file names are
+	/etc/pam.d/imap
+and
+	/etc/pam.d/pop
+
+     It probably works to copy your /etc/pam.d/ftpd file to the above two
+names.
+
+     Many people get these file names wrong, and then spend a lot of time
+trying to figure out why it doesn't work.  Common mistakes are:
+	/etc/pam.d/imapd
+	/etc/pam.d/imap4
+	/etc/pam.d/imap4rev1
+	/etc/pam.d/imaps
+	/etc/pam.d/ipop3d
+	/etc/pam.d/pop3d
+	/etc/pam.d/popd
+	/etc/pam.d/pop3
+	/etc/pam.d/pop3s
+
+
+STEP 4:	certificates setup
+
+NOTE: We can NOT provide you with support in obtaining certificates.  If you
+need help in doing this, try the contacts mentioned in the OpenSSL README.
+
+WARNING: Do NOT install servers built with SSL support unless you also plan to
+install proper certificates!  It is NOT supported to run SSL-enabled servers
+on a system without the proper certificates.
+
+     You must set up certificates on /usr/local/ssl/certs (this may be
+different if you have a non-standard installation of OpenSSL; for example,
+FreeBSD has modified OpenSSL to use /usr/local/certs).  You should install
+both the certificate authority certificates from the SSL distribution after
+building OpenSSL, plus your own certificates.  The latter should have been
+purchased from a certificate authority, although self-signed certificates are
+permissible.  A sample certificate file is at the end of this document.
+
+     Install the resulting certificate file on /usr/local/ssl/certs, with a
+file name consisting of the server name and a suffix of ".pem".  For example,
+install the imapd certificate on /usr/local/ssl/certs/imapd.pem and the ipop3d
+certificate on /usr/local/ssl/certs/ipop3d.pem.  These files should be
+protected against random people accessing them.  It is permissible for
+imapd.pem and ipop3d.pem to be links to the same file.
+
+     The imapd.pem and ipop3d.pem must contain a private key and a
+certificate.  The private key must not be encrypted.
+
+     The following command to openssl can be used to create a self-signed
+certificate with a 10-year expiration:
+	req -new -x509 -nodes -out imapd.pem -keyout imapd.pem -days 3650
+
+			*** IMPORTANT ***
+     We DO NOT recommend, encourage, or sanction the use of self-signed
+certificates.  Nor will we be responsible for any problems (including security
+problems!) which result from your use of a self-signed certificate.  Use of
+self-signed certificates should be limited to testing only.  Buy a real
+certificate from a certificate authority!
+
+			*** IMPORTANT ***
+
+     If you have a multihomed system with multiple domain names (and hence
+separate certificates for each domain name), you can append the IP address
+to the service name.  For example, the IMAP certificate for [12.34.56.78]
+would be /usr/local/ssl/certs/imapd-12.34.56.78.pem and so on.  You only need
+to use this feature if you need to use multiple certificates (because different
+DNS names are used).
+
+
+SAMPLE CERTIFICATE FILE
+
+     Here is a sample certificate file.  Do *NOT* use this on your own
+machine; it is simply an example of what one would look like.
+
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDHkqs4YDbakYxRkYXIpY7xLXDQwULR5LW7xWVzuWmmZJOtzwlP
+7mN87g+aaiQzwXUVndaCw3Zm6cOG4mytf20jPZq0tvWnjEB3763sorpfpOe/4Vsn
+VBFjyQY6YdqYXNmjmzff5gTAecEXOcJ8CrPsaK+nkhw7bHUHX2X+97oMNQIDAQAB
+AoGBAMd3YkZAc9LUsig8iDhYsJuAzUb4Qi7Cppj73EBjyqKR18BaM3Z+T1VoIpQ1
+DeXkr39heCrN7aNCdTh1SiXGPG6+fkGj9HVw7LmjwXclp4UZwWp3fVbSAWfe3VRe
+LM/6p65qogEYuBRMhbSmsn9rBgz3tYVU0lDMZvWxQmUWWg7BAkEA6EbMJeCVdAYu
+nQsjwf4vhsHJTChKv/He6kT93Yr/rvq5ihIAPQK/hwcmWf05P9F6bdrA6JTOm3xu
+TvJsT/rIvQJBANv0yczI5pUQszw4s+LTzH+kZSb6asWp316BAMDedX+7ID4HaeKk
+e4JnBK//xHKVP7xmHuioKYtRlsnuHpWVtNkCQQDPru2+OE6pTRXEqT8xp3sLPJ4m
+ECi18yfjxAhRXIU9CUV4ZJv98UUbEJOEBtx3aW/UZbHyw4rwj5N511xtLsjpAkA9
+p1XRYxbO/clfvf0ePYP621fHHzZChaUo1jwh07lXvloBSQ6zCqvcF4hG1Qh5ncAp
+zO4pBMnwVURRAb/s6fOxAkADv2Tilu1asafmqVzpnRsdfBZx2Xt4oPtquR9IN0Q1
+ewRxOC13KZwoAWtkS7l0mY19WD27onF6iAaF7beuK/Va
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIECTCCA3KgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBujELMAkGA1UEBhMCVVMx
+EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1NlYXR0bGUxHzAdBgNVBAoT
+FkJsdXJkeWJsb29wIEluZHVzdHJpZXMxFjAUBgNVBAsTDUlTIERlcGFydG1lbnQx
+ITAfBgNVBAMTGEJvbWJhc3RpYyBULiBCbHVyZHlibG9vcDEoMCYGCSqGSIb3DQEJ
+ARYZYm9tYmFzdGljQGJsdXJkeWJsb29wLmNvbTAeFw0wMDA2MDYwMDUxMTRaFw0x
+MDA2MDQwMDUxMTRaMIG6MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv
+bjEQMA4GA1UEBxMHU2VhdHRsZTEfMB0GA1UEChMWQmx1cmR5Ymxvb3AgSW5kdXN0
+cmllczEWMBQGA1UECxMNSVMgRGVwYXJ0bWVudDEhMB8GA1UEAxMYQm9tYmFzdGlj
+IFQuIEJsdXJkeWJsb29wMSgwJgYJKoZIhvcNAQkBFhlib21iYXN0aWNAYmx1cmR5
+Ymxvb3AuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHkqs4YDbakYxR
+kYXIpY7xLXDQwULR5LW7xWVzuWmmZJOtzwlP7mN87g+aaiQzwXUVndaCw3Zm6cOG
+4mytf20jPZq0tvWnjEB3763sorpfpOe/4VsnVBFjyQY6YdqYXNmjmzff5gTAecEX
+OcJ8CrPsaK+nkhw7bHUHX2X+97oMNQIDAQABo4IBGzCCARcwHQYDVR0OBBYEFD+g
+lcPrnpsSvIdkm/eol4sYYg09MIHnBgNVHSMEgd8wgdyAFD+glcPrnpsSvIdkm/eo
+l4sYYg09oYHApIG9MIG6MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv
+bjEQMA4GA1UEBxMHU2VhdHRsZTEfMB0GA1UEChMWQmx1cmR5Ymxvb3AgSW5kdXN0
+cmllczEWMBQGA1UECxMNSVMgRGVwYXJ0bWVudDEhMB8GA1UEAxMYQm9tYmFzdGlj
+IFQuIEJsdXJkeWJsb29wMSgwJgYJKoZIhvcNAQkBFhlib21iYXN0aWNAYmx1cmR5
+Ymxvb3AuY29tggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAwEEk
+JXpVXVaFTuG2VJGIzPOxQ+X3V1Cl86y4gM1bDbqlilOUdByUEG4YfSb8ILIn+eXk
+WzMAw63Ww5t0/jkO5JRs6i1SUt0Oy80DryNRJYLBVBi499WEduro8GCVD8HuSkDC
+yL1Rdq8qlNhWPsggcbhuhvpbEz4pAfzPkrWMBn4=
+-----END CERTIFICATE-----
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/Y2K	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,145 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+QUESTION: Is c-client Y2K compliant?
+
+ANSWER:
+
+     There are no known Y2K issues in c-client; nor have there ever
+been any known Y2K issues in c-client from its inception.
+
+     Some older versions of c-client don't like the two-digit year
+"00", although the only impact of this is that messages with that year
+will sort before any other messages.  Nobody should be using two-digit
+years in email messages any more (use "2000" instead of "00").
+
+     You may wish to read the document calendar.txt for more
+information about the Y3.3K/Y4K, Y20K, and Y4)K issues.  Assuming that
+c-client is still around in 2000-40,000 years, someone will have to
+deal with these.
+
+     Within the plausible lifetimes of people today, there are three
+known date-related issues in c-client which will have to be addressed
+in the future.  If I am still alive when the first problem hits, I
+will be nearly 82 years old, and won't be maintaining c-client any
+more.
+
+
+Y2038:
+
+     c-client, like most UNIX software, has Y2038 issues.  On Tuesday,
+January 19, 2038 at 03:14:08 Coordinated Universal Time (also known as
+UTC, UT, or historically GMT), the clock on 32-bit UNIX systems will
+wrap around to a negative number; that is, from 0x7fffffff to
+0x80000000.
+
+     c-client uses an unsigned long for its 32-bit time; however the C
+library on most UNIX systems uses a signed long and will interpret
+that time as being Friday, December 13, 1901 at 20:45:52 UTC.
+
+     Fixing this problem will require changing the C library to use
+either unsigned longs or a wider (e.g. 64-bit) value for time.  Lots
+of work will need to be done on 32-bit UNIX systems as 2038
+approaches.  History suggests that most of the work will be done in
+the autumn of 2037... ;-) It's not known if anything is necessary to
+do to c-client other than just rebuild it with the new C library.
+
+     Going to 32-bit unsigned longs means that there will be a Y2106
+bug that someone will have to fix.  Hopefully nobody will even think
+of using 32-bit systems by then.
+
+
+Y2070:
+
+     c-client assumes that 2-digit years with values of 70 or greater
+are in the 20th century, and that 2-digit years with values of 69 or
+less are in the 21st century.  Time for UNIX began on January 1, 1970
+and email on ARPAnet happened between the first TENEX systems shortly
+after that; consequently there is no ambiguity with email data with
+2-digit years prior to the year 2070.  This is used only when parsing
+a 2-digit year.  c-client never generates one.
+
+     Fixing this problem requires convincing people not to use 2-digit
+years.  This is a lesson that people should have figured out 70 years
+earlier with Y2K.  Consequently, this may be a "non-problem."
+Otherwise, look in mail_parse_date() for the comment "two digit year"
+and change the statement as desired.  [Note: do not change the
+definition of BASEYEAR since the UNIX port assumes that this matches
+when time began in the operating system.]
+
+
+Y2098:
+
+     On January 1, 2098, the year in per-message internal dates will
+expire, since a 7-bit field is allocated for the year.  c-client will
+mistakenly think that the day is January 1, 1970.
+
+     Fortunately, it is easy to fix this problem.  Just increase the
+width of "year" in MESSAGECACHE in mail.h.  If you make it 8 bits,
+it'll be good until January 1, 2216; 9 bits makes it good until 2482.
+10 bits will push it back that you'd worry about the Y2800 question
+before having to increase it again.  If you ignore Y2800, 11 bits will
+push it it back to having to worry about Y4K first.
+
+
+Y2800:
+
+     At this year, you will need to decide whether to keep the Gregorian
+calendar, which is one day slow every 20,000 years, or go to the more
+accurate Eastern Orthodox calendar which is one day slow every 45,000
+years.  The Gregorian and Eastern Orthodox calendars diverge at this
+year.
+
+     There hasn't been any statement about how the international
+community will deal with the situation of the Orthodox calendar being
+one day ahead of the Gregorian calendar between 2800 and 2900.  This
+will happen again between 3200 and 3300, and at gradually increasing
+intervals until 48,300 when the shift becomes permanent (assuming no
+Y20K or Y40K fixes).
+
+     If you wish to make the transition to the Eastern Orthodox calendar,
+rebuild c-client with -DUSEORTHODOXCALENDAR=1.  You can then ignore Y4K
+and Y20K!
+    
+
+Y3.3K/Y4K:
+
+     Some time around the year 3300, the calendar has gotten one day
+behind.  To remedy this, a little-known rule in the Gregorian calendar
+is that years that are evenly divisible by 4000 are not leap years.
+Unlike the other rules, this rule hasn't had effect yet, and won't for
+another 2000 years.
+
+     To fix the Y4K problem, just rebuild c-client with -DY4KBUGFIX=1.
+
+
+Y20K:
+
+     Those of you who stuck with the Gregorian calendar have a
+problem; the calendar is now one day slow.  The Pope has not made any
+statement about how this problem will be fixed.  Maybe they'll declare
+that 20,004 is also not a leap year or something.
+
+     There is no fix for this problem in c-client.
+
+
+Y40K:
+
+     Greeks, Serbs, Russians, and other Eastern Orthodox have spent
+the past 38,000 years laughing at westerners' increasingly futile
+efforts to keep the Gregorian calendar in order.  The day of reckoning
+has come; the Orthodox calendar is now one day slow.  The Patriarch of
+Istanbul (nee Constantinople) has not made any statement about how this
+will be fixed.
+
+     There is no fix for this problem in c-client.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/bugs.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,234 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+	   KNOWN BUGS/MISFEATURES/DEFICIENCIES IN THE IMAP TOOLKIT
+			Last Updated: 15 November 2007
+
+The following are known problems/deficiencies in the imap-2007 toolkit:
+
+ . Possible problems for some installations:
+   . In some versions of Redhat Linux, SVR4-style timezone name lookup
+      doesn't work properly due to a bug in glibc.  The workaround is to
+      edit os_lnx.c to include tz_bsd.c instead of tz_sv4.c.  Note that
+      other versions of Linux don't support BSD-style timezone name
+      lookup, so don't make this change unless it's needed on your system.
+   . In some systems, the OpenSSL distribution is installed other than at
+      the standard /usr/local/ssl location.  If this is the case on your
+      system and you want to build with SSL support, you will need to set
+      the SSLDIR variable, either by including a setting of EXTRASPECIALS
+      in the make command line, e.g.
+       build lnp SPECIALAUTHENTICATORS=ssl EXTRASPECIALS="SSLDIR=/usr/ssl"
+      or by editing .../src/osdep/unix/Makefile
+   . /tmp, /usr/tmp or /var/tmp (if present), and the mail spool directory
+      must be protected 1777 (world write with sticky bit); otherwise
+      mailbox locking and updates won't work.  An alternative to 1777 on
+      the mail spool directory is to install the mlock program that is
+      bundled with the IMAP toolkit.
+   . Multiple access protection locking does not work if the mailbox or
+      /tmp are NFS mounted.
+   . Shared access mailbox formats (mbx, mtx, mx, and tenex) do not work
+      well with NFS and such usage is not supported.  mmdf and unix formats
+      are supported for use over NFS; however there won't be any multiple
+      access locking protection.
+   . Server startup delays may occur if a reverse DNS (IP address to name)
+      lookup on the client's IP address does not complete in an expeditious
+      fashion.  This is actually a DNS problem and should be fixed in the
+      DNS and/or the server's host table.  A workaround exists (see the
+      top-level Makefile for details) but is not recommended and can not
+      be used at all with Kerberos.
+   . At the insistance of the security gurus, SSL certification validation
+      is now on by default.  This means that you must now use the new
+      /novalidate-cert switch if establishing an SSL connection to a server
+      with a self-signed certificate; i.e. if "imap.example.com" has a
+      self-signed certificate, you must use a mailbox name such as
+       {imap.example.com/ssl/novalidate-cert}INBOX
+      to get an SSL session instead of just
+       {imap.example.com/ssl}INBOX
+   . GCC 8.x and above on SGI systems does not correctly pass/return
+      structures which are smaller than 16 bytes and are not 8 bytes.  The
+      problem is that structures are padded at the wrong end; e.g. a 4 byte
+      structure is loaded into the lower 4 bytes of the register when it
+      should be loaded into the upper 4 bytes of the register.  This affects
+      IRIX 6 the most because it is a 64-bit system and 4 byte structures are
+      common.  This compiler bug impacts the use of inet_ntoa() in c-client
+      and causes syslog messages to show IP addresses as 255.255.255.255
+      instead of the correct values.  The fix is either to use SGI's C compiler
+      instead of GCC or link with an implementation of inet_ntoa() that was
+      built with GCC instead of the standard SGI C library version.
+   . By default, the UNIX SSL build assumes that RSAREF is not needed, because
+      RSA Security Inc. released the RSA public key encryption algorithm into
+      the public domain on September 6, 2000.  There is no longer any need to
+      use RSAREF, and since RSAREF is slower than OpenSSL's RSA routines
+      there's good reason not to.  If for some reason you still want to use
+      RSAREF, you will need to edit .../src/osdep/unix/Makefile to
+      change SSLRSA to load libRSAglue and librsaref.
+   . By default, the UNIX SSL build assumes that no name conflict exists
+      between OpenSSL and Kerberos 5.  If you are using an older version
+      of Kerberos, you may need to edit .../src/osdep/unix/Makefile
+      to change SSLCRYPTO so that it loads the OpenSSL libcrypto library
+      explicitly as libcrypto.a.
+   . By default, host names are canonicalized via gethostbyname() and
+      gethostbyaddr() for everything except for SSL certificate validation.
+      This can represent a security bug due to DNS spoofing, but is more
+      likely to deliver results that users expect and also may be necessary
+      to get Kerberos to work.  Set variable "trustdns" in mail.c to NIL if
+      you want to disable this.
+
+ . Bugs:
+   . It doesn't work to have a "}" character as a user name in /user= in a
+      mailbox name, even if the user name is quoted.  In other words,
+       {example.com/user="foo}bar"}zap
+      won't work; foo will be interpreted as an unterminated quoted string
+      and the remote mailbox name will be
+       bar"}zap.
+   . The experimental mx driver has performance problems and shouldn't be used
+   . docs/internal.txt is out of date (again)
+
+ . UIDPLUS bugs/limitations:
+   . Not supported in all local file formats (see below).
+   . There are two known issues with UIDPLUS in the mmdf and unix formats:
+     (a) If the destination mailbox is currently selected (whether in this
+         or another session), no COPYUID or APPENDUID is returned.  The other
+         choice was to assign a UID based upon the uid_last value and hope
+         that the session selecting the mailbox would pick it up and update
+         uid_last.  The problem was a timing race if another message was
+         copied/appended to that mailbox before the selecting session updated
+         the mailbox.  If the timing race is lost, then all UID in the mailbox
+         would be reassigned by the selecting session, thus making the
+         returned APPENDUID/COPYUID data useless and causing a performance
+         problem.
+          Earlier versions did the "hope for the best" method.  This was
+         revoked in favor of not returning COPYUID/APPENDUID.
+          Although this violates RFC 4315, there is a loophole which, although
+         for other purposes, permits this behavior.
+     (b) There is a known failure if the destination mailbox is currently
+         selected by legacy software (e.g. older versions of the IMAP
+         server, Pine, etc.).  In this case, all UIDs end up being
+         reassigned by the legacy software.
+
+ . Annoyances:
+   . Friendly host names (e.g. "server" instead of "server.foo.com") can't be
+      used in a mailbox name with SSL certificate validation; you have to enter
+      the fully-qualified domain name.  This is a requirement established by
+      the security gurus.
+
+ . IMAP client limitations:
+   . No SASL protection mechanisms (SASL authentication mechanisms are
+      supported)
+
+ . NNTP client limitations:
+   . Non-standard IMAP SCAN extension not supported
+
+ . POP client limitations:
+   . No SASL protection mechanisms (SASL authentication mechanisms are
+      supported)
+   . No POP3 UID support
+   . Non-standard IMAP SCAN extension not supported
+
+ . SMTP client limitations:
+   . No SASL protection mechanisms (SASL authentication mechanisms are
+      supported)
+   . No support for use of TURN, ETRN, and pipelining.
+   . No support for enhanced status codes
+
+ . UNIX limitations:
+   . IPv6 is supported but is not the default on most platforms; you have to
+      use IP=6 in the make command
+   . Supported local file formats: mbx, mh, mmdf, mix, mtx, mx, news, phile,
+      tenex, unix
+   . Supported SASL mechanisms: CRAM-MD5, PLAIN, LOGIN, ANONYMOUS, GSSAPI
+   . Sticky UIDs are not supported in the mh, mtx, and tenex drivers
+   . Creation of keywords is not supported in the mh, mtx, and tenex drivers
+   . Copy and append of keywords only works in the mbx driver.
+   . Flat file formats (mbx, mmdf, mtx, phile, tenex, unix) do not permit
+      mailboxes to have inferior names
+   . SSL temporary key should be seeded better than it is.
+   . UIDPLUS support is limited to the unix, mmdf, mbx, mx, and mix formats.
+   . Non-standard IMAP SCAN extension not support for mh and news formats.
+
+ . Amiga limitations:
+   . Supported local file formats: mbx, mh, mmdf, mix, mtx, mx, news, phile,
+      tenex, unix
+   . Supported SASL mechanisms: CRAM-MD5, PLAIN, LOGIN, ANONYMOUS
+   . Sticky UIDs are not supported in the mh, mtx, and tenex drivers
+   . Creation of keywords is not supported in the mh, mtx, and tenex drivers
+   . Copy and append of keywords only works in the mbx driver.
+   . Flat file formats (mbx, mmdf, mtx, phile, tenex, unix) do not permit
+      mailboxes to have inferior names
+   . UIDPLUS support is limited to the unix, mmdf, mbx, mx, and mix formats.
+   . Non-standard IMAP SCAN extension not supported for mh and news formats.
+
+ . Win32 (Win9x/NT/Windows 2000) limitations:
+   . IPv6 is supported in W2K builds but is not the default; you have to use
+      IP=6 in the nmake command
+   . Supported local file formats: mbx, mtx, tenex, unix
+   . Supported SASL mechanisms: CRAM-MD5, PLAIN, LOGIN, ANONYMOUS, GSSAPI
+   . No server SSL or TLS support.
+   . No server authentication for GSSAPI
+   . No server authentication for CRAM-MD5 on NT-based Windows (NT/2K/XP);
+      it does work on DOS-based Windows (9x/Me).
+   . Sticky UIDs are not supported in the mtxnt and tenexnt drivers
+   . Creation of keywords is not supported in the mtxnt and tenexnt drivers
+   . Copy and append of keywords only works in the mbxnt driver.
+   . No support for TCP open timeouts
+   . Flat file formats (mbx, mtx, tenex, unix) do not permit mailboxes to have
+      inferior names
+   . UIDPLUS support is limited to the unix and mbx formats.
+
+ . Win16 (Win3.1)/DOS limitations:
+   . IPv6 not supported
+   . Supported local file formats: bezerk, mtx
+   . Supported SASL mechanisms: CRAM-MD5, LOGIN, ANONYMOUS
+   . Supported TCPs: B&W, Novell, PC-NFs, PC/TCP, Waterloo, Winsock
+   . Sticky UIDs are not supported on local files
+   . Creation of keywords are not supported on local files
+   . Bezerk driver is read-only and does not handle LF-only newlines well
+   . No support for any TCP timeouts on Waterloo DOS
+   . No support for TCP open timeouts on Winsock and generic DOS
+   . Flat file formats (bezerk, mtx) do not permit mailboxes to have inferior
+      names
+   . Does not work well unless a mailgets routine is armed when fetching
+      texts.
+
+ . Mac limitations:
+   . IPv6 not supported
+   . No local file drivers
+   . Supported SASL mechanisms: CRAM-MD5, LOGIN, ANONYMOUS
+   . Does not output human-friendly time zone string
+
+ . TOPS-20 limitations:
+   . IPv6 not supported
+   . No local file drivers
+   . Supported SASL mechanisms: CRAM-MD5, LOGIN, ANONYMOUS
+   . No support for any TCP timeouts
+
+ . VMS limitations:
+   . IPv6 not supported
+   . No local file drivers
+   . Supported SASL mechanisms: CRAM-MD5, LOGIN, ANONYMOUS
+   . Supported TCPs: Multinet, Netlib
+   . No support for any TCP timeouts on VMS Netlib
+   . No support for TCP open timeouts on VMS Multinet
+   . Time zone must be configured at build time
+   . Does not output human-friendly time zone string
+
+ . Windows CE limitations:
+   . IPv6 not yet supported
+   . No local file drivers
+   . Supported SASL mechanisms: CRAM-MD5, LOGIN, ANONYMOUS
+   . No support for TCP open timeouts
+   . Not finished, only builds c-client library
+
+ . OS/2 limitations:
+   . IPv6 not supported
+   . Not finished, does not build
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/calendar.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,332 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+			 ALL ABOUT CALENDARS
+
+     Although one can never be sure of what will happen at some future
+time, there is strong historical precedent for presuming that the
+present Gregorian calendar will still be in effect within the useful
+lifetime of the IMAP toolkit.  We have therefore chosen to adhere to
+these precedents.
+ 
+     The purpose of a calendar is to reckon time in advance, to show
+how many days have to elapse until a certain event takes place in the
+future, such as the harvest or the release of a new version of Pine.
+The earliest calendars, naturally, were crude and tended to be based
+upon the seasons or the lunar cycle.
+ 
+
+ANCIENT CALENDARS
+
+     The calendar of the Assyrians, for example, was based upon the
+phases of the moon.  They knew that a lunation (the time from one full
+moon to the next) was 29 1/2 days long, so their lunar year had a
+duration of 354 days.  This fell short of the solar year by about 11
+days.  (The exact time for the solar year is approximately 365 days, 5
+hours, 48 minutes, and 46 seconds.)  After 3 years, such a lunar
+calendar would be off by a whole month, so the Assyrians added an extra
+month from time to time to keep their calendar in synchronization with
+the seasons.
+ 
+     The best approximation that was possible in antiquity was a 19-year
+period, with 7 of these 19 years having 13 months (leap months).  This
+scheme was adopted as the basis for the lunar calendar used by the
+Hebrews.  The Arabs also used this calendar until Mohammed forbade
+shifting from 12 months to 13 months; this causes the Muslim holy month
+of Ramadan to move backwards through the seasons, completing a cycle
+every 32 1/2 years.
+ 
+     When Rome emerged as a world power, the difficulties of making a
+calendar were well known, but the Romans complicated their lives because
+of their superstition that even numbers were unlucky.  Hence their
+months were 29 or 31 days long, with the exception of February, which
+had 28 days.  Every second year, the Roman calendar included an extra
+month called Mercedonius of 22 or 23 days to keep up with the solar
+year.
+
+
+JULIAN CALENDAR
+
+     Even this algorithm was very poor, so that in 45 BCE, Caesar,
+advised by the astronomer Sosigenes, ordered a sweeping reform.  By
+imperial decree, the year 46 BCE was made 445 days long to bring the
+calendar back in step with the seasons.  The new calendar, similar to
+the one we now use was called the Julian calendar (named after Julius
+Caesar).
+
+     Months in the Julian calendar were 30 or 31 days in length and
+every fourth year was made a leap year (having 366 days) by adding a day
+to the end of the year.  This leap year rule was not consistantly
+applied until 8 CE.  The year-ending month of February, never a popular
+month, was presently shortened so that Julius Caesar and Emperor
+Augustus could each have long months named after them.
+
+     Caesar also decreed that the year would start with the first of
+January, which since 153 BCE was the day that Roman consuls took office,
+and not the vernal equinox in late March.  Not everyone accepted that
+part of his reform, as we shall see.
+
+ 
+GREGORIAN CALENDAR
+
+     Caesar's year was 11 1/2 minutes short of the calculations
+recommended by Sosigenes and eventually the date of the vernal equinox
+began to drift.  Roger Bacon became alarmed and sent a note to Pope
+Clement IV, who apparently was not impressed.  Pope Sixtus IV later
+became convinced that another reform was needed and called the German
+astronomer, Regiomontanus, to Rome to advise him.  Unfortunately,
+Regiomontanus died of the plague shortly thereafter and the plans died
+as well.
+ 
+     In 1545, the Council of Trent authorized Pope Gregory XIII to
+reform the calendar once more.  Most of the mathematical work was done
+by Father Christopher Clavius, S.J.  The immediate correction that was
+adopted was that Thursday, October 4, 1582 was to be the last day of the
+Julian calendar.  The next day was Friday, with the date of October 15.
+For long range accuracy, a formula suggested by the Vatican librarian
+Aloysius Giglio was adopted.  It said that every fourth year is a leap
+year except for century years that are not divisible by 400.  Thus 1700,
+1800 and 1900 would not be leap years, but 2000 would be a leap year
+since 2000 is divisible by 400.  This rule eliminates 3 leap years every
+4 centuries, making the calendar sufficiently correct for most ordinary
+purposes.  This calendar is known as the Gregorian calendar and is the
+one that we now use today.
+
+     It is interesting to note that in 1582, all the Protestant princes
+ignored the papal decree and so many countries continued to use the
+Julian calendar until either 1698 or 1752.  Britain and its American
+colonies went from Wednesday, September 2, 1752 to Thursday, September
+14.  Prior to the changeover, the British used March 25 as the start of
+the new year.
+
+     In Russia, it needed the revolution to introduce the Gregorian
+calendar in 1918.  Turkey didn't adopt it until 1927.
+
+
+NUMBERING OF YEARS
+
+     The numbering of the year is generally done according to an "era",
+such as the year of a ruler's reign.
+
+     In about 525, a monk named Dionysius Exiguus suggested that the
+calculated year of Jesus' birth be designated as year 1 in the Julian
+calendar.  This suggestion was adopted over the next 500 years and
+subsequently followed in the Gregorian calendar.
+
+     For the benefit of those who seek religious significance to the
+calendar millenium, note that year 1 is too late by at least 4 years.
+Herod the Great, named in the Christian Bible as having all children in
+Bethlehem put to death in an attempt to kill the infant Jesus, died in 4
+BCE.
+
+     Nothing particularly significant of an historic or religious nature
+happened in Gregorian year 1; however it has become a worldwide standard
+as the "common era."  In modern times, the terms "CE" (common era) and
+"BCE" (before common era) are preferred over the earlier (and, as we
+have seen, less accurate) "AD" (anno Domini, "the year of the Lord") and
+"BC" (before Christ).
+
+     The Hebrew lunar calendar begins at 3760 BCE, the year of creation
+in Jewish tradition.  The Muslim lunar calendar begins on July 16, 622,
+when Mohammed fled from Mecca to Medina.
+
+     The Japanese, Taiwanese, and North Koreans use the Gregorian
+calendar, but number the year by political era.  In Japan, an era
+begins when an emperor succeeds to the throne; year 1 of the Heisei
+era was 1989 when Emperor Akihito ascended to the throne (the first
+few days of 1989 was year 64 of the Shouwa era).  In Taiwan, year 1 is
+the first full year after the founding of the Republic of China in 1911.
+In North Korea, year 1 is the year of the Juche (self-reliance) ideal,
+corresponding to the birth year of founder Kim Il-Sung (1912).  Thus,
+year 2000 is Heisei 12 (Japan), 89th year of the Republic (Taiwan),
+and Juche 89 (North Korea).
+
+
+FURTHER MODIFICATIONS TO THE GREGORIAN CALENDAR
+
+     Despite the great accuracy of the Gregorian calendar, it still
+falls behind very slightly every few years.  The most serious problem
+is that the earth's rotation is slowing gradually.  If you are very
+concerned about this problem, we suggest that you tune in short wave
+radio station WWV or the Global Positioning System, which broadcasts
+official time signals for use in the United States.  About once every
+3 years, they declare a leap second at which time you should be
+careful to adjust your system clock.  If you have trouble picking up
+their signals, we suggest you purchase an atomic clock (not part of
+the IMAP toolkit).
+
+     Another problem is that the Gregorian calendar represents a year
+of 365.2425 days, whereas the actual time taken for the earth to
+rotate around the Sun is 365.2421991 days.  Thus, the Gregorian calendar
+is actually 26 seconds slow each year, resulting in the calendar
+being one day behind every 3,300 or so years (a Y3.3K problem).
+
+     Consequently, the Gregorian calendar has been modified with a
+further rule, which is that years evenly divisible by 4000 are not
+leap years.  Thus, the year 4000 will not be a leap year.  Or, at
+least we assume that's what will happen assuming that the calendar
+remains unchanged for the next 2000 years.
+
+     The modified Gregorian calendar represents a year of 365.24225
+days.  Thus, the modified Gregorian calendar is actually 4 seconds
+slow each year, resulting in the calendar being one day slow every
+20,000 or so years.  So there will be a Y20K problem.
+
+     There is some dispute whether the modified Gregorian calendar was
+officially adopted, or if it's just a proposal.  Other options (see
+below) exist; fortunately no decision needs to be made for several
+centuries yet.
+
+     There is code in c-client to support the modified Gregorian
+calendar, although it is currently disabled.  Sometime in the next
+2000 years, someone will need to enable this code so that c-client is
+Y4K compiliant.  Then, 18,000 years from now, someone will have to
+tear into c-client's code to fix the Y20K bug.
+
+
+EASTERN ORTHODOX MODIFICATION OF THE GREGORIAN CALENDAR
+
+     The Eastern Orthodox church in 1923 established its own rules to
+correct the Julian calendar.  In their calendar, century years modulo
+900 must result in value of 200 or 600 to be considered a leap year.
+Both the Orthodox and Gregorian calendar agree that the years 2000 and
+2400 will be leap years, and the years 1900, 2100, 2200, 2300, 2500,
+2600, 2700 are not.  However, the year 2800 will be a leap year in the
+Gregorian calendar but not in the Orthodox calendar; similarly, the
+year 2900 will be a leap year in the Orthodox calendar but not in the
+Gregorian calendar.  Both calendars will agree that 3000 and
+3100 are leap years, but will disagree again in 3200 and 3300.
+
+     There is code in c-client to support the Orthodox calendar.  It
+can be enabled by adding -DUSEORTHODOXCALENDAR=1 to the c-client
+CFLAGS, e.g.
+	make xxx EXTRACFLAGS="-DUSEORTHODOXCALENDAR=1"
+
+     The Orthodox calendar represents a year of 365.24222222... days.
+Thus, the Orthodox calendar is actually 2 seconds slow each year,
+resulting in the calendar being one day slow every 40,000 or so years.
+The Eastern Orthodox church has not yet made any statements on how the
+Y40K bug will be fixed.
+
+
+OTHER ISSUES AFFECTING THE CALENDAR IN THE FUTURE
+
+     The effect of leap seconds also needs to be considered when
+looking at the Y3.3K/Y4K, Y20K, and Y40K problems.  Leap seconds put
+the clock back in line with the Earth's rotation, whereas leap years
+put the calendar back in line with the Earth's revolution.  Since leap
+seconds slow down the clock (and hence the calendar), they actually
+bring the day of reckoning for the Gregorian and Orthodox calendars
+sooner.
+
+     Another factor is that the next ice age (technically, the end of
+the current interglacial period; we are in the middle of an ice age
+now!) is due around Y25K.  It is not known what perturbations this will
+cause on the Earth's rotation and revolution, nor what calendar
+adjustments will be necessary at that time.
+
+     Hence my use of "or so" in predicting the years that the calendar
+will fall behind.  The actual point may be anywhere from decades (in the
+case of Y3.3K) to millenia (in the case of Y40K) off from these predictions.
+
+
+MEANINGS OF DAY NAMES
+
+     The names of days of the week from a combination of Roman and
+Germanic names for celestial bodies:
+. Sunday	Latin "dies solis" => "Sun's day"
+. Monday	Latin "dies lunae" => "Moon's day"
+. Tuesday	Germanic "Tiw's day" => "Mars' day"
+. Wednesday	Germanic "Woden's day" => "Mercury's day"
+. Thursday	Germanic "Thor's day" => "Jupiter's day"
+. Friday	Germanic "Frigg's day" => "Venus' day"
+. Saturday	Latin "dies Saturni" => "Saturn's day"
+
+
+MEANINGS OF MONTH NAMES
+
+     The names of the months are from the Roman calendar:
+. January	Janus, protector of doorways
+. February	Februalia, a time for sacrifice to atone for sins
+. March		Mars, god of war
+. April		Latin "aperire" => "to open" buds
+. May		Maia, goddess of plant growth
+. June		Latin "juvenis" => "youth"
+. July		Julius Caesar
+. August	Augustus Caesar
+. September	Latin "septem" => "seven"
+. October	Latin "octo" => "eight"
+. November	Latin "novem" => "nine"
+. December	Latin "decem" => "ten"
+
+     As you'll notice, the last four months are numbered 7 to 10, which
+is an artifact of the time when the new year started in March.
+
+
+INTERESTING FORMULAE
+
+     There's another reason why the historical starting of the new year
+is significant.  Starting with March, the length of months follows a
+mathematical series:
+	31 30 31 30 31 31 30 31 30 31 31 28
+
+     This means that you can calculate the day of week for any
+arbitrary day/month/year of the Gregorian calendar with the following
+formula (note all divisions are integral):
+        _                                      _
+       |     7 + 31*(m - 1)       y    y     y  |
+ dow = | d + -------------- + y + - - --- + --- | MOD 7
+       |_          12             4   100   400_|
+where
+ d   := day of month (1..31)
+ m   := month in old style (March = 1..February = 12)
+ y   := year in old style
+ dow := day of week (Tuesday = 0..Monday = 6)
+
+     To convert from new style month/year to old style:
+  if (m > 2) m -= 2;		/* Mar-Dec: subtract 2 from month */
+  else m += 10,y--;		/* Jan-Feb: months 11 & 12 of previous year */
+
+     Here's another fun formula.  To find the number of days between two
+days, calculate a pair of calendar days with the formula (again, all
+divisions are integral), using new style month/year this time:
+                        m
+                    m + -
+                        8             y    y     y
+ d + 30 * (m - 1) + ----- + y * 365 + - - --- + --- - ld
+                      2               4   100   400
+
+where:
+ d   := day of month (1..31)
+ m   := month in new style (January = 1..December = 12)
+ y   := year in new style
+ ld  := leap day correction factor:
+	0 for January and February in non-leap years
+	1 for January and February in leap years
+	2 for all other months in all years        
+
+     In C code, the leap day correction factor is calculated as:
+  (m < 3) ? !(y % 4) && ((y % 100) || !(y % 400)) : 2
+
+     It's up to you to figure out how to adapt these formulas for the
+Y4K bugfix and the Orthodox calendar.  If you're really clever, try to
+use these formulae to implement the C library ctime(), gmtime(), and
+mktime() functions.  Most C library implementations use a table of the
+number of days in a month.  You don't need it.
+
+
+ACKNOWLEDGEMENT:
+
+The original version is from an old Digital Equipment Corporation SPR
+answer for VMS.  Modifications for c-client, and additional information
+added by Mark Crispin.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/commndmt.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,101 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+[I wrote this tongue-in-cheek, but there's a lot here that people who
+ build IMAP clients should take careful note.  Most existing clients
+ violate at least one, generally several, of these commandments.
+ These are based on known user-visible problems that occur with various
+ commonly used clients.  Put another way, behind each commandment is a
+ plethora of user (and server administrator) complaints caused by a
+ violator.]
+
+	   Ten Commandments of How to Write an IMAP client
+			     Mark Crispin
+
+1. Thou shalt not assume that it is alright to open multiple IMAP
+sessions selected on the same mailbox simultaneously, lest thou face
+the righteous wrath of mail stores that doth not permit such access.
+Instead, thou shalt labor mightily, even unto having to use thy brain
+to thinketh the matter through, such that thy client use existing
+sessions that are already open.
+
+2. Thou shalt not abuse the STATUS command by using it to check for
+new mail on a mailbox that you already have selected in an IMAP
+session; for that session hath already told thou about new mail
+without thy having to ask.
+
+3. Thou shalt remember the 30 minute inactivity timeout, and remember
+to speak to the IMAP server before that timeout expires.  If thou
+useth the IDLE command, thou shalt send DONE from the IDLE before 29
+minutes hath passed, and issue a new IDLE.  If thou maketh no use of
+IDLE, then thou shalt send NOOP every few minutes, and the server
+shalt tell you about new mail, and there will be much rejoicing in the
+land.
+
+4. Thou shalt not assume that all names are both the name of a mailbox
+and the name of a upper level of hierarchy that contains mailboxes;
+lest thou face the righteous wrath of mail stores in which a mailbox
+is a file and a level of hierarchy is a directory.  Thou shalt pay
+diligent attention to the \NoSelect and \NoInferiors flags, so that
+your users may praise you with great praise.
+
+5. Thou shalt learn and understand the unique features of IMAP, such
+as the unsolicited data model, the strict ascending rule of UIDs, how
+UIDs map to sequence numbers, the ENVELOPE and BODYSTRUCTURE
+structures; so that thou may use the IMAP protocol effectively.  For a
+POP client hacked to babble IMAP protocol is still no more than a POP
+client.
+
+6. Thou shalt remember untagged data sent by the server, and when thou
+needest data thou shalt consult your memory before asking the server.
+For those who must analyze thy protocol transactions are weak of
+stomach, and are likely to lose their recent meal should they see thou
+repeatedly re-fetch static data.
+
+7. Thou shalt labor with great effort to work within the IMAP
+deleted/expunge model, even if thy own model is that of a trashcan;
+for interoperability is paramount and a trashcan model can be done
+entirely in the user interface.
+
+8. Thou shalt not fear to open multiple IMAP sessions to the server;
+but thou shalt use this technique with wisdom.  For verily it is true;
+if thou doth desire to monitor continuously five mailboxes for new
+mail, it is better to have five IMAP sessions continuously open on the
+mailboxes.  It is generally not good to do a succession of five SELECT
+or STATUS commands on a periodic basis; and it is truly wretched to
+open and close five sessions to do a STATUS or SELECT on a periodic
+basis.  The cost of opening and closing a session is great, especially
+if that session is SSL/TLS protected; and the cost of a STATUS or
+SELECT can also be great.  By comparison, the cost of an open session
+doing an IDLE or getting a NOOP every few minutes is small.  Great
+praise shall be given to thy wisdom in doing what is less costly
+instead of "common sense."
+
+9. Thou shalt not abuse subscriptions, for verily the LIST command is
+the proper way to discover mailboxes on the server.  Thou shalt not
+subscribe names to the user's subscription list without explicit
+instructions from the user; nor shalt thou assume that only subscribed
+names are valid.  Rather, thou shalt treat subscribed names as akin to
+a bookmarks, or perhaps akin to how Windows shows the "My Documents"
+folder -- a set of names that are separate from the hierarchy, for
+they are such.
+
+10. Thou shalt use the LIST "*" wildcard only with great care.  If
+thou doth not fully comprehend the danger of "*", thou shalt use only
+"%" and forget about the existance of "*".
+
+Honor these commandments, and keep them holy in thy heart, so that thy
+users shalt maximize their pleasure, and the server administrators
+shalt sing thy praises and recommend thy work as a model for others to
+emulate.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/draft/README	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,19 @@
+Last Updated: 6 March 2008
+
+This directory contains Internet Drafts which, at the time of release of
+this software, were not yet been published as RFCs.  These documents are
+expected to be released as RFCs in the near future.
+
+This software adheres to the specification in these documents, which
+are included for informational purposes.  Note, however, that these
+documents must be considered preliminary in nature and will be superceded
+by the successor RFC.
+
+File Name	I-D Name
+---------	--------
+sort.txt	draft-ietf-imapext-sort-20.txt
+		;; SORT and THREAD commands
+		;; Status: approved, blocked waiting for i18n
+
+i18n.txt	draft-ietf-imapext-i18n-15.txt
+		;; internationalization in IMAP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/draft/i18n.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1140 @@
+
+
+
+
+
+
+Network Working Group                                       Chris Newman
+Internet-Draft                                          Sun Microsystems
+Intended Status: Proposed Standard                      Arnt Gulbrandsen
+                                                  Oryx Mail Systems GmhH
+                                                         Alexey Melnikov
+                                                           Isode Limited
+                                                        February 1, 2008
+
+         Internet Message Access Protocol Internationalization
+                     draft-ietf-imapext-i18n-15.txt
+
+
+Status of this Memo
+    By submitting this Internet-Draft, each author represents that any
+    applicable patent or other IPR claims of which he or she is aware
+    have been or will be disclosed, and any of which he or she becomes
+    aware will be disclosed, in accordance with Section 6 of BCP 79.
+
+    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".
+
+    The list of current Internet-Drafts can be accessed at
+    http://www.ietf.org/ietf/1id-abstracts.txt.  The list of Internet-
+    Draft Shadow Directories can be accessed at
+    http://www.ietf.org/shadow.html.
+
+    This Internet-Draft expires in August 2008.
+
+
+Copyright Notice
+
+    Copyright (C) The IETF Trust (2008).
+
+
+Abstract
+
+    Internet Message Access Protocol (IMAP) version 4rev1 has basic
+    support for non-ASCII characters in mailbox names and search
+    substrings.  It also supports non-ASCII message headers and content
+    encoded as specified by Multipurpose Internet Mail Extensions
+    (MIME).  This specification defines a collection of IMAP extensions
+
+
+
+Newman & Co                Expires August 2008                FF[Page 1]
+
+
+
+
+
+Internet-draft                                             February 2008
+
+
+    which improve international support including comparator negotiation
+    for search, sort and thread, language negotiation for international
+    error text, and translations for namespace prefixes.
+
+
+Table of Contents
+
+    1.  Conventions Used in this Document . . . . . . . . . . . . . .  2
+    2.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .  3
+    3.  LANGUAGE Extension  . . . . . . . . . . . . . . . . . . . . .  3
+    3.1 LANGUAGE Extension Requirements . . . . . . . . . . . . . . .  3
+    3.2 LANGUAGE Command  . . . . . . . . . . . . . . . . . . . . . .  4
+    3.3 LANGUAGE Response . . . . . . . . . . . . . . . . . . . . . .  6
+    3.4 TRANSLATION Extension to the NAMESPACE Response . . . . . . .  6
+    3.5 Formal Syntax . . . . . . . . . . . . . . . . . . . . . . . .  6
+    4.  I18NLEVEL=1 and I18NLEVEL=2 Extensions  . . . . . . . . . . .  7
+    4.1 Introduction and Overview . . . . . . . . . . . . . . . . . .  8
+    4.2 Requirements common to both I18NLEVEL=1 and I18NLEVEL=2 . . .
+    4.3 I18NLEVEL=1 Extension Requirements  . . . . . . . . . . . . .  8
+    4.4 I18NLEVEL=2 Extension Requirements  . . . . . . . . . . . . .  8
+    4.5 Compatibility Notes
+    4.6 Comparators and Charsets  . . . . . . . . . . . . . . . . . .  9
+    4.7 COMPARATOR Command  . . . . . . . . . . . . . . . . . . . . .  9
+    4.8 COMPARATOR Response . . . . . . . . . . . . . . . . . . . . . 10
+    4.9 BADCOMPARATOR Response Code . . . . . . . . . . . . . . . . .
+    4.10 Formal Syntax  . . . . . . . . . . . . . . . . . . . . . . . 10
+    5.  Other IMAP Internationalization Issues  . . . . . . . . . . . 11
+    5.1 UTF-8 Userids and Passwords . . . . . . . . . . . . . . . . . 11
+    5.2 UTF-8 Mailbox Names . . . . . . . . . . . . . . . . . . . . . 11
+    5.3 UTF-8 Domains, Addresses and Mail Headers . . . . . . . . . . 11
+    6.  IANA Considerations . . . . . . . . . . . . . . . . . . . . . 12
+    7.  Security Considerations . . . . . . . . . . . . . . . . . . . 12
+    8.  Acknowledgements  . . . . . . . . . . . . . . . . . . . . . . 12
+    9.  Relevant Standards for i18n IMAP Implementations  . . . . . . 13
+        Normative References  . . . . . . . . . . . . . . . . . . . . 13
+        Informative References  . . . . . . . . . . . . . . . . . . . 14
+        Authors' Addresses  . . . . . . . . . . . . . . . . . . . . . 15
+        Intellectual Property and Copyright Statements  . . . . . . . 16
+
+
+Conventions Used in This Document
+
+    The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+    "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+    document are to be interpreted as described in [RFC2119].
+
+    The formal syntax use the Augmented Backus-Naur Form (ABNF)
+    [RFC4234] notation including the core rules defined in Appendix A.
+
+
+
+Newman & Co                Expires August 2008                FF[Page 2]
+
+
+
+
+
+Internet-draft                                             February 2008
+
+
+    The UTF8-related productions are defined in [RFC3629].
+
+    In examples, "C:" and "S:" indicate lines sent by the client and
+    server respectively.  If a single "C:" or "S:" label applies to
+    multiple lines, then the line breaks between those lines are for
+    editorial clarity only and are not part of the actual protocol
+    exchange.
+
+
+2.  Introduction
+
+    This specification defines two IMAP4rev1 [RFC3501] extensions to
+    enhance international support.  These extensions can be advertised
+    and implemented separately.
+
+    The LANGUAGE extension allows the client to request a suitable
+    language for protocol error messages and in combination with the
+    NAMESPACE extension [RFC2342] enables namespace translations.
+
+    The I18NLEVEL=2 extension allows the client to request a suitable
+    collation which will modify the behavior of the base specification's
+    SEARCH command as well as the SORT and THREAD extensions [SORT].
+    This leverages the collation registry [RFC4790].
+
+
+3.  LANGUAGE Extension
+
+    IMAP allows server responses to include human-readable text that in
+    many cases needs to be presented to the user.  But that text is
+    limited to US-ASCII by the IMAP specification [RFC3501] in order to
+    preserve backwards compatibility with deployed IMAP implementations.
+    This section specifies a way for an IMAP client to negotiate which
+    language the server should use when sending human-readable text.
+
+    The LANGUAGE extension only provides a mechanism for altering fixed
+    server strings such as response text and NAMESPACE folder names.
+    Assigning localized language aliases to shared mailboxes would be
+    done with a separate mechanism such as the proposed METADATA
+    extension (see [METADATA]).
+
+
+3.1 LANGUAGE Extension Requirements
+
+    IMAP servers that support this extension MUST list the keyword
+    LANGUAGE in their CAPABILITY response as well as in the greeting
+    CAPABILITY data.
+
+    A server that advertises this extension MUST use the language "i-
+
+
+
+Newman & Co                Expires August 2008                FF[Page 3]
+
+
+
+
+
+Internet-draft                                             February 2008
+
+
+    default" as described in [RFC2277] as its default language until
+    another supported language is negotiated by the client. A server
+    MUST include "i-default" as one of its supported languages.
+
+    Clients and servers that support this extension MUST also support
+    the NAMESPACE extension [RFC2342].
+
+    The LANGUAGE command is valid in all states. Clients are urged to
+    issue LANGUAGE before authentication, since some servers send
+    valuable user information as part of authentication (e.g. "password
+    is correct, but expired").  If a security layer (such as SASL or
+    TLS) is subsequently negotiated by the client, it MUST re-issue the
+    LANGUAGE command in order to make sure that no previous active
+    attack (if any) on LANGUAGE negotiation has effect on subsequent
+    error messages. (See Section 7 for a more detailed explanation of
+    the attack.)
+
+
+
+3.2 LANGUAGE Command
+
+    Arguments: Optional language range arguments.
+
+    Response:  A possible LANGUAGE response (see section 3.3).
+               A possible NAMESPACE response (see section 3.4).
+
+    Result:    OK - Command completed
+               NO - Could not complete command
+               BAD - arguments invalid
+
+    The LANGUAGE command requests that human-readable text emitted by
+    the server be localized to a language matching one of the language
+    range argument as described by section 2 of [RFC4647].
+
+    If the command succeeds, the server will return human-readable
+    responses in the first supported language specified.  These
+    responses will be in UTF-8 [RFC3629].  The server MUST send a
+    LANGUAGE response specifying the language used, and the change takes
+    effect immediately after the LANGUAGE response.
+
+    If the command fails, the server continues to return human-readable
+    responses in the language it was previously using.
+
+    The special "default" language range argument indicates a request to
+    use a language designated as preferred by the server administrator.
+    The preferred language MAY vary based on the currently active user.
+
+    If a language range does not match a known language tag exactly but
+
+
+
+Newman & Co                Expires August 2008                FF[Page 4]
+
+
+
+
+
+Internet-draft                                             February 2008
+
+
+    does match a language by the rules of [RFC4647], the server MUST
+    send an untagged LANGUAGE response indicating the language selected.
+
+    If there aren't any arguments, the server SHOULD send an untagged
+    LANGUAGE response listing the languages it supports.  If the server
+    is unable to enumerate the list of languages it supports it MAY
+    return a tagged NO response to the enumeration request.
+
+        < The server defaults to using English i-default responses until
+          the user explicitly changes the language. >
+
+        C: A001 LOGIN KAREN PASSWORD
+        S: A001 OK LOGIN completed
+
+        < Client requested MUL language, which no server supports. >
+
+        C: A002 LANGUAGE MUL
+        S: A002 NO Unsupported language MUL
+
+        < A LANGUAGE command with no arguments is a request to enumerate
+          the list of languages the server supports. >
+
+        C: A003 LANGUAGE
+        S: * LANGUAGE (EN DE IT i-default)
+        S: A003 OK Supported languages have been enumerated
+
+        C: B001 LANGUAGE
+        S: B001 NO Server is unable to enumerate supported languages
+
+        < Once the client changes the language, all responses will be in
+          that language starting after the LANGUAGE response. Note that
+          this includes the NAMESPACE response. Because RFCs are in US-
+          ASCII, this document uses an ASCII transcription rather than
+          UTF-8 text, e.g. ue in the word "ausgefuehrt" >
+
+        C: C001 LANGUAGE DE
+        S: * LANGUAGE (DE)
+        S: * NAMESPACE (("" "/")) (("Other Users/" "/" "TRANSLATION"
+              ("Andere Ben&APw-tzer/"))) (("Public Folders/" "/"
+              "TRANSLATION" ("Gemeinsame Postf&AM8-cher/")))
+        S: C001 OK Sprachwechsel durch LANGUAGE-Befehl ausgefuehrt
+
+        < If a server does not support the requested primary language,
+          responses will continue to be returned in the current language
+          the server is using. >
+
+        C: D001 LANGUAGE FR
+        S: D001 NO Diese Sprache ist nicht unterstuetzt
+
+
+
+Newman & Co                Expires August 2008                FF[Page 5]
+
+
+
+
+
+Internet-draft                                             February 2008
+
+
+        C: D002 LANGUAGE DE-IT
+        S: * LANGUAGE (DE-IT)
+        S: * NAMESPACE (("" "/"))(("Other Users/" "/" "TRANSLATION"
+              ("Andere Ben&APw-tzer/"))) (("Public Folders/" "/"
+              "TRANSLATION" ("Gemeinsame Postf&AM8-cher/")))
+        S: D002 OK Sprachwechsel durch LANGUAGE-Befehl ausgefuehrt
+        C: D003 LANGUAGE "default"
+        S: * LANGUAGE (DE)
+        S: D003 OK Sprachwechsel durch LANGUAGE-Befehl ausgefuehrt
+
+        < Server does not speak French, but does speak English. User
+          speaks Canadian French and Canadian English. >
+
+        C: E001 LANGUAGE FR-CA EN-CA
+        S: * LANGUAGE (EN)
+        S: E001 OK Now speaking English
+
+
+
+3.3 LANGUAGE Response
+
+    Contents:  A list of one or more language tags.
+
+    The LANGUAGE response occurs as a result of a LANGUAGE command.  A
+    LANGUAGE response with a list containing a single language tag
+    indicates that the server is now using that language.  A LANGUAGE
+    response with a list containing multiple language tags indicates the
+    server is communicating a list of available languages to the client,
+    and no change in the active language has been made.
+
+
+3.4 TRANSLATION Extension to the NAMESPACE Response
+
+    If localized representations of the namespace prefixes are available
+    in the selected language, the server SHOULD include these in the
+    TRANSLATION extension to the NAMESPACE response.
+
+    The TRANSLATION extension to the NAMESPACE response returns a single
+    string, containing the modified UTF-7 [RFC3501] encoded translation
+    of the namespace prefix.  It is the responsibility of the client to
+    convert between the namespace prefix and the translation of the
+    namespace prefix when presenting mailbox names to the user.
+
+    In this example a server supports the IMAP4 NAMESPACE command. It
+    uses no prefix to the user's Personal Namespace, a prefix of "Other
+    Users" to its Other Users' Namespace and a prefix of "Public
+    Folders" to its only Shared Namespace.  Since a client will often
+    display these prefixes to the user, the server includes a
+
+
+
+Newman & Co                Expires August 2008                FF[Page 6]
+
+
+
+
+
+Internet-draft                                             February 2008
+
+
+    translation of them that can be presented to the user.
+
+        C: A001 LANGUAGE DE-IT
+        S: * NAMESPACE (("" "/")) (("Other Users/" "/" "TRANSLATION"
+              ("Andere Ben&APw-tzer/"))) (("Public Folders/" "/"
+              "TRANSLATION" ("Gemeinsame Postf&AM8-cher/")))
+        S: A001 OK LANGUAGE-Befehl ausgefuehrt
+
+
+3.5 Formal Syntax
+
+    The following syntax specification inherits ABNF [RFC4234] rules
+    from IMAP4rev1 [RFC3501], IMAP4 Namespace [RFC2342], Tags for the
+    Identifying Languages [RFC4646], UTF-8 [RFC3629] and Collected
+    Extensions to IMAP4 ABNF [RFC4466].
+
+    command-any     =/ language-cmd
+        ; LANGUAGE command is valid in all states
+
+    language-cmd    = "LANGUAGE" *(SP lang-range-quoted)
+
+    response-payload  =/ language-data
+
+    language-data     = "LANGUAGE" SP "(" lang-tag-quoted *(SP
+                      lang-tag-quoted) ")"
+
+    namespace-trans   = SP DQUOTE "TRANSLATION" DQUOTE SP "(" string ")"
+        ; the string is encoded in Modified UTF-7.
+        ; this is a subset of the syntax permitted by
+        ; the Namespace-Response-Extension rule in [RFC4466]
+
+    lang-range-quoted = astring
+        ; Once any literal wrapper or quoting is removed, this
+        ; follows the language-range rule in [RFC4647]
+
+    lang-tag-quoted = astring
+        ; Once any literal wrapper or quoting is removed, this follows
+        ; the Language-Tag rule in [RFC4646]
+
+    resp-text       = ["[" resp-text-code "]" SP ] UTF8-TEXT-CHAR
+                      *(UTF8-TEXT-CHAR / "[")
+        ; After the server is changed to a language other than
+        ; i-default, this resp-text rule replaces the resp-text
+        ; rule from [RFC3501].
+
+    UTF8-TEXT-CHAR  = %x20-5A / %x5C-7E / UTF8-2 / UTF8-3 / UTF8-4
+        ; UTF-8 excluding 7-bit control characters and "["
+
+
+
+
+Newman & Co                Expires August 2008                FF[Page 7]
+
+
+
+
+
+Internet-draft                                             February 2008
+
+
+4.  I18NLEVEL=1 and I18NLEVEL=2 Extensions
+
+
+4.1 Introduction and Overview
+
+    IMAP4rev1 [RFC3501] includes the SEARCH command which can be used to
+    locate messages matching criteria including human-readable text.
+    The SORT extension [SORT] to IMAP allows the client to ask the
+    server to determine the order of messages based on criteria
+    including human-readable text.  These mechanisms require the ability
+    to support non-English search and sort functions.
+
+    Section 4 defines two IMAP extensions for internationalizing IMAP
+    SEARCH, SORT and THREAD [SORT] using the comparator framework
+    [RFC4790].
+
+    The I18NLEVEL=1 extension updates SEARCH/SORT/THREAD to use
+    i;unicode-casemap comparator, as defined in [UCM]. See Sections 4.2
+    and 4.3 for more details.
+
+    The I18NLEVEL=2 extension is a superset of the I18NLEVEL=1
+    extension. It adds to I18NLEVEL=1 extension the ability to determine
+    the active comparator (see definition below) and negotiate use of
+    comparators using the COMPARATOR command. It also adds the
+    COMPARATOR response that indicates the active comparator and
+    possibly other available comparators. See Sections 4.2 and 4.4 for
+    more details.
+
+
+4.2 Requirements common to both I18NLEVEL=1 and I18NLEVEL=2
+
+    The term "default comparator" refers to the comparator which is used
+    by SEARCH and SORT absent any negotiation using the COMPARATOR (see
+    Section 4.7) command.  The term "active comparator" refers to the
+    comparator which will be used within a session e.g. by SEARCH and
+    SORT.  The COMPARATOR command is used to change the active
+    comparator.
+
+    The active comparator applies to the following SEARCH keys: "BCC",
+    "BODY", "CC", "FROM", "SUBJECT", "TEXT", "TO" and "HEADER".  If the
+    server also advertises the "SORT" extension, then the active
+    comparator applies to the following SORT keys: "CC", "FROM",
+    "SUBJECT" and "TO".  If the server advertises THREAD=ORDEREDSUBJECT,
+    then the active comparator applies to the ORDEREDSUBJECT threading
+    algorithm.  If the server advertises THREAD=REFERENCES, then the
+    active comparator applies to the subject field comparisons done by
+    REFERENCES threading algorithm.  Future extensions may choose to
+    apply the active comparator to their SEARCH keys.
+
+
+
+Newman & Co                Expires August 2008                FF[Page 8]
+
+
+
+
+
+Internet-draft                                             February 2008
+
+
+    For SORT and THREAD, the pre-processing necessary to extract the
+    base subject text from a Subject header occurs prior to the
+    application of a comparator.
+
+    A server that advertises I18NLEVEL=1 or I18NLEVEL=2 extension MUST
+    implement the i;unicode-casemap comparator, as defined in [UCM].
+
+    A server that advertises I18NLEVEL=1 or I18NLEVEL=2 extension MUST
+    support UTF-8 as a SEARCH charset.
+
+
+4.3 I18NLEVEL=1 Extension Requirements
+
+    An IMAP server that satisfies all requirements specified in sections
+    4.2 and 4.6 (and doesn't support/advertise any other I18NLEVEL=<n>
+    extension, where n > 1) MUST list the keyword I18NLEVEL=1 in its
+    CAPABILITY data once IMAP enters the authenticated state, and MAY
+    list that keyword in other states.
+
+
+
+4.4 I18NLEVEL=2 Extension Requirements
+
+    IMAP server that satisfies all requirements specified in sections
+    4.2, 4.4, 4.6-4.10 (and doesn't support/advertise any other
+    I18NLEVEL=<n> extension, where n > 2) MUST list the keyword
+    I18NLEVEL=2 in its CAPABILITY data once IMAP enters the
+    authenticated state, and MAY list that keyword in other states.
+
+    A server that advertises this extension MUST implement the
+    i;unicode-casemap comparator, as defined in [UCM]. It MAY implement
+    other comparators from the IANA registry established by [RFC4790].
+    See also section 4.5 of this document.
+
+    A server that advertises this extension SHOULD use i;unicode-casemap
+    as the default comparator. (Note that i;unicode-casemap is the
+    default comparator for I18NLEVEL=1, but not necessarily the default
+    for I18NLEVEL=2.) The selection of the default comparator MAY be
+    adjustable by the server administrator, and MAY be sensitive to the
+    current user.  Once the IMAP connection enters authenticated state,
+    the default comparator MUST remain static for the remainder of that
+    connection.
+
+    Note that since SEARCH uses the substring operation, IMAP servers
+    can only implement collations that offer the substring operation
+    (see [RFC4790 section 4.2.2). Since SORT uses ordering operation
+    (and by implication equality), IMAP servers which advertise the SORT
+    extension can only implement collations that offer all three
+
+
+
+Newman & Co                Expires August 2008                FF[Page 9]
+
+
+
+
+
+Internet-draft                                             February 2008
+
+
+    operations (see [RFC4790] sections 4.2.2-4).
+
+    If the active collation does not provide the operations needed by an
+    IMAP command, the server MUST respond with a tagged BAD.
+
+
+4.5 Compatibility Notes
+
+    Several server implementations deployed prior to the publication of
+    this specification comply with I18NLEVEL=1 (see section 4.3), but do
+    not advertise that.  Other legacy servers use the i;ascii-casemap
+    (see [RFC4790]) comparator.
+
+    There is no good way for a client to know which comparator that a
+    legacy server uses.  If the client has to assume the worst, it may
+    end up doing expensive local operations to obtain i;unicode-casemap
+    comparisons even though the server implements it.
+
+    Legacy server implementations which comply with I18NLEVEL=1 should
+    be updated to advertise I18NLEVEL=1.  All server implementations
+    should eventually be updated to comply with the I18NLEVEL=2
+    extension.
+
+
+4.6 Comparators and Character Encodings
+
+    RFC 3501, section 6.4.4 says:
+
+               In all search keys that use strings, a message matches
+               the key if the string is a substring of the field.  The
+               matching is case-insensitive.
+
+    When performing the SEARCH operation, the active comparator is
+    applied instead of the case-insensitive matching specified above.
+
+    An IMAP server which performs collation operations (e.g., as part of
+    commands such as SEARCH, SORT, THREAD) does so according to the
+    following procedure:
+
+    (a) MIME encoding (for example see [RFC2047] for headers and
+        [RFC2045] for body parts) MUST be removed in the texts being
+        collated.
+
+        If MIME encoding removal fails for a message (e.g., a body part
+        of the message has an unsupported Content-Transfer-Encoding,
+        uses characters not allowed by the Content-Transfer-Encoding,
+        etc.), the collation of this message is undefined by this
+        specification, and is handled in an implementation-dependent
+
+
+
+Newman & Co                Expires August 2008               FF[Page 10]
+
+
+
+
+
+Internet-draft                                             February 2008
+
+
+        manner.
+
+    (b) The decoded text from (a) MUST be converted to the charset
+        expected by the active comparator.
+
+    (c) For the substring operation:
+        If step (b) failed (e.g., the text is in an unknown charset,
+        contains a sequence which is not valid according in that
+        charset, etc.), the original decoded text from (a) (i.e.,
+        before the charset conversion attempt) is collated using the
+        i;octet comparator (see [RFC4790]).
+
+        If step (b) was successful, the converted text from (b) is
+        collated according to the active comparator.
+
+
+        For the ordering operation:
+
+        All strings that were successfully converted by step (b) are
+        separated from all strings that failed step (b). Strings in
+        each group are collated independently.  All strings successfully
+        converted by step (b) are then validated by the active
+        comparator. Strings that pass validation are collated using the
+        active comparator. All strings that either fail step (b) or fail
+        the active collation's validity operation are collated (after
+        applying step (a)) using the i;octet comparator (see [RFC4790]).
+        The resulting sorted list is produced by appending all collated
+        "failed" strings after all strings collated using the active
+        comparator.
+
+
+        Example: The following example demonstrates ordering of 4
+        different strings using i;unicode-casemap [UCM] comparator.
+        Strings are represented using hexadecimal notation used by
+        ABNF [RFC4234].
+
+        (1) %xD0 %xC0 %xD0 %xBD %xD0 %xB4 %xD1 %x80 %xD0 %xB5
+            %xD0 %xB9 (labeled with charset=UTF-8)
+        (2) %xD1 %x81 %xD0 %x95 %xD0 %xA0 %xD0 %x93 %xD0 %x95
+            %xD0 %x99 (labeled with charset=UTF-8)
+        (3) %xD0 %x92 %xD0 %xB0 %xD1 %x81 %xD0 %xB8 %xD0 %xBB
+            %xD0 %xB8 %xFF %xB9 (labeled with charset=UTF-8)
+        (4) %xE1 %xCC %xC5 %xCB %xD3 %xC5 %xCA (labeled with
+            charset=KOI8-R)
+
+        Step (b) will convert string # 4 to the following
+        sequence of octets (in UTF-8):
+
+
+
+
+Newman & Co                Expires August 2008               FF[Page 11]
+
+
+
+
+
+Internet-draft                                             February 2008
+
+
+        %xD0 %x90 %xD0 %xBB %xD0 %xB5 %xD0 %xBA %xD1 %x81 %xD0
+        %xB5 %xD0 %xB9
+
+        and will reject strings (1) and (3), as they contain
+        octets not allowed in charset=UTF-8.
+        After that, using the i;unicode-casemap collation,
+        string (4) will collate before string (2). Using the
+        i;octet collation on the original strings, string (3)
+        will collate before string (1). So the final ordering
+        is as follows: (4) (2) (3) (1).
+
+    If the substring operation (e.g., IMAP SEARCH) of the active
+    comparator returns the "undefined" result (see section 4.2.3 of
+    [RFC4790]) for either the text specified in the SEARCH command or
+    the message text, then the operation is repeated on the result of
+    step (a) using the i;octet comparator.
+
+    The ordering operation (e.g., IMAP SORT and THREAD) SHOULD collate
+    the following together: strings encoded using unknown or invalid
+    character encodings, strings in unrecognized charsets, and invalid
+    input (as defined by the active collation).
+
+
+
+4.7 COMPARATOR Command
+
+    Arguments: Optional comparator order arguments.
+
+    Response:  A possible COMPARATOR response (see Section 4.8).
+
+    Result:    OK - Command completed
+               NO - No matching comparator found
+               BAD - arguments invalid
+
+    The COMPARATOR command is valid in authenticated and selected
+    states.
+
+    The COMPARATOR command is used to determine or change the active
+    comparator.  When issued with no arguments, it results in a
+    COMPARATOR response indicating the currently active comparator.
+
+    When issued with one or more comparator argument, it changes the
+    active comparator as directed. (If more than one installed
+    comparator is matched by an argument, the first argument wins.) The
+    COMPARATOR response lists all matching comparators if more than one
+    matches the specified patterns.
+
+    The argument "default" refers to the server's default comparator.
+
+
+
+Newman & Co                Expires August 2008               FF[Page 12]
+
+
+
+
+
+Internet-draft                                             February 2008
+
+
+    Otherwise each argument is an collation specification as defined in
+    the Internet Application Protocol Comparator Registry [RFC4790].
+
+        < The client requests activating a Czech comparator if possible,
+          or else a generic international comparator which it considers
+          suitable for Czech. The server picks the first supported
+          comparator. >
+
+        C: A001 COMPARATOR "cz;*" i;basic
+        S: * COMPARATOR i;basic
+        S: A001 OK Will use i;basic for collation
+
+
+4.8 COMPARATOR Response
+
+    Contents:  The active comparator.
+               An optional list of available matching comparators
+
+    The COMPARATOR response occurs as a result of a COMPARATOR command.
+    The first argument in the comparator response is the name of the
+    active comparator.  The second argument is a list of comparators
+    which matched any of the arguments to the COMPARATOR command and is
+    present only if more than one match is found.
+
+
+4.9 BADCOMPARATOR response code
+
+    This response code SHOULD be returned as a result of server failing
+    an IMAP command (returning NO), when the server knows that none of
+    the specified comparators match the requested comparator(s).
+
+
+4.10 Formal Syntax
+
+    The following syntax specification inherits ABNF [RFC4234] rules
+    from IMAP4rev1 [RFC3501], and Internet Application Protocol
+    Comparator Registry [RFC4790].
+
+        command-auth      =/ comparator-cmd
+
+        resp-text-code    =/ "BADCOMPARATOR"
+
+        comparator-cmd    = "COMPARATOR" *(SP comp-order-quoted)
+
+      response-payload  =/ comparator-data
+
+        comparator-data   = "COMPARATOR" SP comp-sel-quoted [SP "("
+                        comp-id-quoted *(SP comp-id-quoted) ")"]
+
+
+
+Newman & Co                Expires August 2008               FF[Page 13]
+
+
+
+
+
+Internet-draft                                             February 2008
+
+
+        comp-id-quoted  = astring
+            ; Once any literal wrapper or quoting is removed, this
+            ; follows the collation-id rule from [RFC4790]
+
+        comp-order-quoted = astring
+            ; Once any literal wrapper or quoting is removed, this
+            ; follows the collation-order rule from [RFC4790]
+
+        comp-sel-quoted   = astring
+            ; Once any literal wrapper or quoting is removed, this
+            ; follows the collation-selected rule from [RFC4790]
+
+
+5.  Other IMAP Internationalization Issues
+
+    The following sections provide an overview of various other IMAP
+    internationalization issues.  These issues are not resolved by this
+    specification, but could be resolved by other standards work, such
+    as that being done by the EAI group (see [IMAP-EAI]).
+
+
+5.1 Unicode Userids and Passwords
+
+    IMAP4rev1 currently restricts the userid and password fields of the
+    LOGIN command to US-ASCII. The "userid" and "password" fields of the
+    IMAP LOGIN command are restricted to US-ASCII only until a future
+    standards track RFC states otherwise.  Servers are encouraged to
+    validate both fields to make sure they conform to the formal syntax
+    of UTF-8 and to reject the LOGIN command if that syntax is violated.
+    Servers MAY reject the use of any 8-bit in the "userid" or
+    "password" field.
+
+    When AUTHENTICATE is used, some servers may support userids and
+    passwords in Unicode [RFC3490] since SASL (see [RFC4422]) allows
+    that. However, such userids cannot be used as part of email
+    addresses.
+
+
+5.2 UTF-8 Mailbox Names
+
+    The modified UTF-7 mailbox naming convention described in section
+    5.1.3 of RFC 3501 is best viewed as an transition from the status
+    quo in 1996 when modified UTF-7 was first specified.  At that time,
+    there was widespread unofficial use of local character sets such as
+    ISO-8859-1 and Shift-JIS for non-ASCII mailbox names, with resultant
+    non-interoperability.
+
+    The requirements in section 5.1 of RFC 3501 are very important if
+
+
+
+Newman & Co                Expires August 2008               FF[Page 14]
+
+
+
+
+
+Internet-draft                                             February 2008
+
+
+    we're ever going to be able to deploy UTF-8 mailbox names. Servers
+    are encouraged to enforce them.
+
+
+5.3 UTF-8 Domains, Addresses and Mail Headers
+
+    There is now an IETF standard for Internationalizing Domain Names in
+    Applications [RFC3490].  While IMAP clients are free to support this
+    standard, an argument can be made that it would be helpful to simple
+    clients if the IMAP server could perform this conversion (the same
+    argument would apply to MIME header encoding [RFC2047]).  However,
+    it would be unwise to move forward with such work until the work in
+    progress to define the format of international email addresses is
+    complete.
+
+
+6.  IANA Considerations
+
+    The IANA is requested to add LANGUAGE, I18NLEVEL=1 and I18NLEVEL=2
+    to the IMAP4 Capabilities Registry.  [Note to IANA:
+    http://www.iana.org/assignments/imap4-capabilities]
+
+
+7.  Security Considerations
+
+    The LANGUAGE extension makes a new command available in "Not
+    Authenticated" state in IMAP.  Some IMAP implementations run with
+    root privilege when the server is in "Not Authenticated" state and
+    do not revoke that privilege until after authentication is complete.
+    Such implementations are particularly vulnerable to buffer overflow
+    security errors at this stage and need to implement parsing of this
+    command with extra care.
+
+    A LANGUAGE command issued prior to activation of a security layer is
+    subject to an active attack which suppresses or modifies the
+    negotiation and thus makes STARTTLS or authentication error messages
+    more difficult to interpret.  This is not a new attack as the error
+    messages themselves are subject to active attack.  Clients MUST re-
+    issue the LANGUAGE command once a security layer is active, so this
+    does not impact subsequent protocol operations.
+
+    LANGUAGE, I18NLEVEL=1 and I18NLEVEL=2 extensions use the UTF-8
+    charset, thus the security considerations for UTF-8 [RFC3629] are
+    relevent.  However, neither uses UTF-8 for identifiers so the most
+    serious concerns do not apply.
+
+
+8.  Acknowledgements
+
+
+
+Newman & Co                Expires August 2008               FF[Page 15]
+
+
+
+
+
+Internet-draft                                             February 2008
+
+
+    The LANGUAGE extension is based on a previous Internet draft by Mike
+    Gahrns, a substantial portion of the text in that section was
+    written by him.  Many people have participated in discussions about
+    an IMAP Language extension in the various fora of the IETF and
+    Internet working groups, so any list of contributors is bound to be
+    incomplete.  However, the authors would like to thank Andrew McCown
+    for early work on the original proposal, John Myers for suggestions
+    regarding the namespace issue, along with Jutta Degener, Mark
+    Crispin, Mark Pustilnik, Larry Osterman, Cyrus Daboo, Martin Duerst,
+    Timo Sirainen, Ben Campbell and Magnus Nystrom for their many
+    suggestions that have been incorporated into this document.
+
+    Initial discussion of the I18NLEVEL=2 extension involved input from
+    Mark Crispin and other participants of the IMAP Extensions WG.
+
+
+9.  Relevant Standards for i18n IMAP Implementations
+
+    This is a non-normative list of standards to consider when
+    implementing i18n aware IMAP software.
+
+      o The LANGUAGE and I18NLEVEL=2 extensions to IMAP (this
+        specification).
+      o The 8-bit rules for mailbox naming in section 5.1 of RFC 3501.
+      o The Mailbox International Naming Convention in section 5.1.3 of
+        RFC 3501.
+      o MIME [RFC2045] for message bodies.
+      o MIME header encoding [RFC2047] for message headers.
+      o The IETF EAI working group.
+      o MIME Parameter Value and Encoded Word Extensions [RFC2231] for
+        filenames.  Quality IMAP server implementations will
+        automatically combine multipart parameters when generating the
+        BODYSTRUCTURE. There is also some deployed non-standard use of
+        MIME header encoding inside double-quotes for filenames.
+      o IDNA [RFC3490] and punycode [RFC3492] for domain names
+        (currently only relevant to IMAP clients).
+      o The UTF-8 charset [RFC3629].
+      o The IETF policy on Character Sets and Languages [RFC2277].
+
+
+Normative References
+
+    [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
+               Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+    [RFC2277]  Alvestrand, "IETF Policy on Character Sets and
+               Languages", BCP 18, RFC 2277, January 1998.
+
+
+
+
+Newman & Co                Expires August 2008               FF[Page 16]
+
+
+
+
+
+Internet-draft                                             February 2008
+
+
+    [RFC2342]  Gahrns, Newman, "IMAP4 Namespace", RFC 2342, May 1998.
+
+    [RFC3501]  Crispin, "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
+               4rev1", RFC 3501, March 2003.
+
+    [RFC3629]  Yergeau, "UTF-8, a transformation format of ISO 10646",
+               STD 63, RFC 3629, November 2003.
+
+    [RFC4234]  Crocker, Overell, "Augmented BNF for Syntax
+               Specifications: ABNF", RFC 4234, Brandenburg
+               Internetworking, Demon Internet Ltd, October 2005.
+
+    [RFC4422]  Melnikov, Zeilenga, "Simple Authentication and Security
+               Layer (SASL)", RFC 4422, June 2006.
+
+    [RFC4466]  Melnikov, Daboo, "Collected Extensions to IMAP4 ABNF",
+               RFC 4466, Isode Ltd., April 2006.
+
+    [RFC4646]  Philips, Davis, "Tags for Identifying Languages", BCP 47,
+               RFC 4646, September 2006.
+
+    [RFC4647]  Philips, Davis, "Matching of Language Tags", BCP 47, RFC
+               4647, September 2006.
+
+    [RFC4790]  Newman, Duerst, Gulbrandsen, "Internet Application
+               Protocol Comparator Registry", RFC 4790, February 2007.
+
+    [SORT]     Crispin, M. and K. Murchison, "INTERNET MESSAGE ACCESS
+               PROTOCOL - SORT AND THREAD EXTENSION", draft-ietf-
+               imapext-sort-19 (work in progress), November 2006.
+
+    [UCM]      Crispin, "i;unicode-casemap - Simple Unicode Collation
+               Algorithm", RFC 5051, October 2007.
+
+    [RFC2045]  Freed, Borenstein, "Multipurpose Internet Mail Extensions
+               (MIME) Part One: Format of Internet Message Bodies", RFC
+               2045, November 1996.
+
+    [RFC2047]  Moore, "MIME (Multipurpose Internet Mail Extensions) Part
+               Three: Message Header Extensions for Non-ASCII Text", RFC
+               2047, November 1996.
+
+
+Informative References
+
+
+    [RFC2231]  Freed, Moore, "MIME Parameter Value and Encoded Word
+               Extensions: Character Sets, Languages, and
+
+
+
+Newman & Co                Expires August 2008               FF[Page 17]
+
+
+
+
+
+Internet-draft                                             February 2008
+
+
+               Continuations", RFC 2231, November 1997.
+
+    [RFC3490]  Faltstrom, Hoffman, Costello, "Internationalizing Domain
+               Names in Applications (IDNA)", RFC 3490, March 2003.
+
+    [RFC3492]  Costello, "Punycode: A Bootstring encoding of Unicode for
+               Internationalized Domain Names in Applications (IDNA)",
+               RFC 3492, March 2003.
+
+    [METADATA] Daboo, C., "IMAP METADATA Extension", draft-daboo-imap-
+               annotatemore-12 (work in progress), December 2007.
+
+    [IMAP-EAI] Resnick, Newman, "IMAP Support for UTF-8", draft-ietf-
+               eai-imap-utf8 (work in progress), May 2006.
+
+
+
+Authors' Addresses
+
+    Chris Newman
+    Sun Microsystems
+    3401 Centrelake Dr., Suite 410
+    Ontario, CA 91761
+    US
+
+    Email: chris.newman@sun.com
+
+
+    Arnt Gulbrandsen
+    Oryx Mail Systems GmbH
+    Schweppermannstr. 8
+    D-81671 Muenchen
+    Germany
+
+    Email: arnt@oryx.com
+
+    Fax: +49 89 4502 9758
+
+
+    Alexey Melnikov
+    Isode Limited
+    5 Castle Business Village, 36 Station Road,
+    Hampton, Middlesex, TW12 2BX, UK
+
+    Email: Alexey.Melnikov@isode.com
+
+
+
+
+
+
+Newman & Co                Expires August 2008               FF[Page 18]
+
+
+
+
+
+Internet-draft                                             February 2008
+
+
+Intellectual Property Statement
+
+    The IETF takes no position regarding the validity or scope of any
+    Intellectual Property Rights or other rights that might be claimed to
+    pertain to the implementation or use of the technology described in
+    this document or the extent to which any license under such rights
+    might or might not be available; nor does it represent that it has
+    made any independent effort to identify any such rights.  Information
+    on the procedures with respect to rights in RFC documents can be found
+    in BCP 78 and BCP 79.
+
+    Copies of IPR disclosures made to the IETF Secretariat and any
+    assurances of licenses to be made available, or the result of an
+    attempt made to obtain a general license or permission for the use of
+    such proprietary rights by implementers or users of this specification
+    can be obtained from the IETF on-line IPR repository at
+    http://www.ietf.org/ipr.
+
+    The IETF invites any interested party to bring to its attention any
+    copyrights, patents or patent applications, or other proprietary
+    rights that may cover technology that may be required to implement
+    this standard.  Please address the information to the IETF at
+    ietf-ipr@ietf.org.
+
+
+Full Copyright Statement
+
+    Copyright (C) The IETF Trust (2008).  This document is subject to
+    the rights, licenses and restrictions contained in BCP 78, and
+    except as set forth therein, the authors retain all their rights.
+
+    This document and the information contained herein are provided on
+    an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE
+    REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE
+    IETF TRUST AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL
+    WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY
+    WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE
+    ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS
+    FOR A PARTICULAR PURPOSE.
+
+
+Acknowledgment
+
+    Funding for the RFC Editor function is currently provided by the
+    Internet Society.
+
+
+
+
+
+
+Newman & Co                Expires August 2008               FF[Page 19]
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/draft/sort.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,885 @@
+IMAP Extensions Working Group                                 M. Crispin
+Internet-Draft                                              K. Murchison
+Intended status: Proposed Standard                        March 10, 2008
+Expires: September 10, 2008
+Document: internet-drafts/draft-ietf-imapext-sort-20.txt
+
+     INTERNET MESSAGE ACCESS PROTOCOL - SORT AND THREAD EXTENSIONS
+
+Status of this Memo
+
+   By submitting this Internet-Draft, each author represents that
+   any applicable patent or other IPR claims of which he or she is
+   aware have been or will be disclosed, and any of which he or she
+   becomes aware will be disclosed, in accordance with Section 6 of
+   BCP 79.
+
+   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."
+
+   The list of current Internet-Drafts can be accessed at
+   http://www.ietf.org/ietf/1id-abstracts.txt
+
+   The list of Internet-Draft Shadow Directories can be accessed at
+   http://www.ietf.org/shadow.html.
+
+   A revised version of this draft document will be submitted to the RFC
+   editor as a Proposed Standard for the Internet Community.  Discussion
+   and suggestions for improvement are requested, and should be sent to
+   ietf-imapext@IMC.ORG.
+
+   Distribution of this memo is unlimited.
+
+Abstract
+
+   This document describes the base-level server-based sorting and
+   threading extensions to the [IMAP] protocol.  These extensions
+   provide substantial performance improvements for IMAP clients which
+   offer sorted and threaded views.
+
+1. Introduction
+
+   The SORT and THREAD extensions to the [IMAP] protocol provide a means
+   of server-based sorting and threading of messages, without requiring
+   that the client download the necessary data to do so itself.  This is
+   particularly useful for online clients as described in [IMAP-MODELS].
+
+   A server which supports the base-level SORT extension indicates this
+   with a capability name which starts with "SORT".  Future,
+   upwards-compatible extensions to the SORT extension will all start
+   with "SORT", indicating support for this base level.
+
+   A server which supports the THREAD extension indicates this with one
+   or more capability names consisting of "THREAD=" followed by a
+   supported threading algorithm name as described in this document.
+   This provides for future upwards-compatible extensions.
+
+   A server which implements the SORT and/or THREAD extensions MUST
+   collate strings in accordance with the requirements of I18NLEVEL=1,
+   as described in [IMAP-I18N], and SHOULD implement and advertise the
+   I18NLEVEL=1 extension.  Alternatively, a server MAY implement
+   I18NLEVEL=2 (or higher) and comply with the rules of that level.
+
+      Discussion: the SORT and THREAD extensions predate [IMAP-I18N] by
+      several years.  At the time of this writing, all known server
+      implementations of SORT and THREAD comply with the rules of
+      I18NLEVEL=1, but do not necessarily advertise it.  As discussed
+      in [IMAP-I18N] section 4.5, all server implementations should
+      eventually be updated to comply with the I18NLEVEL=2 extension.
+
+   Historical note: the REFERENCES threading algorithm is based on the
+   [THREADING] algorithm written used in "Netscape Mail and News"
+   versions 2.0 through 3.0.  
+
+2. Terminology
+
+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+   document are to be interpreted as described in [KEYWORDS].
+
+   The word "can" (not "may") is used to refer to a possible
+   circumstance or situation, as opposed to an optional facility of the
+   protocol.
+
+   "User" is used to refer to a human user, whereas "client" refers to
+   the software being run by the user.
+
+   In examples, "C:" and "S:" indicate lines sent by the client and
+   server respectively.
+
+2.1 Base Subject
+
+   Subject sorting and threading use the "base subject," which has
+   specific subject artifacts removed.  Due to the complexity of these
+   artifacts, the formal syntax for the subject extraction rules is
+   ambiguous.  The following procedure is followed to determine the
+   "base subject", using the [ABNF] formal syntax rules described in
+   section 5:
+
+        (1) Convert any RFC 2047 encoded-words in the subject to
+        UTF-8 as described in "internationalization
+        considerations."  Convert all tabs and continuations to
+        space.  Convert all multiple spaces to a single space.
+
+        (2) Remove all trailing text of the subject that matches
+        the subj-trailer ABNF, repeat until no more matches are
+        possible.
+
+        (3) Remove all prefix text of the subject that matches the
+        subj-leader ABNF.
+
+        (4) If there is prefix text of the subject that matches the
+        subj-blob ABNF, and removing that prefix leaves a non-empty
+        subj-base, then remove the prefix text.
+
+        (5) Repeat (3) and (4) until no matches remain.
+
+   Note: it is possible to defer step (2) until step (6), but this
+   requires checking for subj-trailer in step (4).
+
+        (6) If the resulting text begins with the subj-fwd-hdr ABNF
+        and ends with the subj-fwd-trl ABNF, remove the
+        subj-fwd-hdr and subj-fwd-trl and repeat from step (2).
+
+        (7) The resulting text is the "base subject" used in the
+        SORT.
+
+   All servers and disconnected (as described in [IMAP-MODELS]) clients
+   MUST use exactly this algorithm to determine the "base subject".
+   Otherwise there is potential for a user to get inconsistent results
+   based on whether they are running in connected or disconnected mode.
+
+2.2 Sent Date
+
+   As used in this document, the term "sent date" refers to the date and
+   time from the Date: header, adjusted by time zone to normalize to
+   UTC.  For example, "31 Dec 2000 16:01:33 -0800" is equivalent to the
+   UTC date and time of "1 Jan 2001 00:01:33 +0000".
+
+   If the time zone is invalid, the date and time SHOULD be treated as
+   UTC.  If the time is also invalid, the time SHOULD be treated as
+   00:00:00.  If there is no valid date or time, the date and time
+   SHOULD be treated as 00:00:00 on the earliest possible date.
+
+   This differs from the date-related criteria in the SEARCH command
+   (described in [IMAP] section 6.4.4), which use just the date and not
+   the time, and are not adjusted by time zone.
+
+   If the sent date can not be determined (a Date: header is missing or
+   can not be parsed), the INTERNALDATE for that message is used as the
+   sent date.
+
+   When comparing two sent dates that match exactly, the order in which
+   the two messages appear in the mailbox (that is, by sequence number)
+   is used as a tie-breaker to determine the order.
+
+3. Additional Commands
+
+   These commands are extension to the [IMAP] base protocol.
+
+   The section headings are intended to correspond with where they would
+   be located in the main document if they were part of the base
+   specification.
+
+BASE.6.4.SORT. SORT Command
+
+   Arguments:  sort program
+               charset specification
+               searching criteria (one or more)
+
+   Data:       untagged responses: SORT
+
+   Result:     OK - sort completed
+               NO - sort error: can't sort that charset or
+                    criteria
+               BAD - command unknown or arguments invalid
+
+      The SORT command is a variant of SEARCH with sorting semantics for
+      the results.  Sort has two arguments before the searching criteria
+      argument; a parenthesized list of sort criteria, and the searching
+      charset.
+
+      The charset argument is mandatory (unlike SEARCH) and indicates
+      the [CHARSET] of the strings that appear in the searching
+      criteria.  The US-ASCII and UTF-8 charsets MUST be implemented.
+      All other charsets are optional.
+
+      There is also a UID SORT command which returns unique identifiers
+      instead of message sequence numbers.  Note that there are separate
+      searching criteria for message sequence numbers and UIDs; thus the
+      arguments to UID SORT are interpreted the same as in SORT.  This
+      is analogous to the behavior of UID SEARCH, as opposed to UID
+      COPY, UID FETCH, or UID STORE.
+
+      The SORT command first searches the mailbox for messages that
+      match the given searching criteria using the charset argument for
+      the interpretation of strings in the searching criteria.  It then
+      returns the matching messages in an untagged SORT response, sorted
+      according to one or more sort criteria.
+
+      Sorting is in ascending order.  Earlier dates sort before later
+      dates; smaller sizes sort before larger sizes; and strings are
+      sorted according to ascending values established by their
+      collation algorithm (see under "Internationalization
+      Considerations").
+
+      If two or more messages exactly match according to the sorting
+      criteria, these messages are sorted according to the order in
+      which they appear in the mailbox.  In other words, there is an
+      implicit sort criterion of "sequence number".
+
+      When multiple sort criteria are specified, the result is sorted in
+      the priority order that the criteria appear.  For example,
+      (SUBJECT DATE) will sort messages in order by their base subject
+      text; and for messages with the same base subject text will sort
+      by their sent date.
+
+      Untagged EXPUNGE responses are not permitted while the server is
+      responding to a SORT command, but are permitted during a UID SORT
+      command.
+
+      The defined sort criteria are as follows.  Refer to the Formal
+      Syntax section for the precise syntactic definitions of the
+      arguments.  If the associated RFC-822 header for a particular
+      criterion is absent, it is treated as the empty string.  The empty
+      string always collates before non-empty strings.
+
+      ARRIVAL
+         Internal date and time of the message.  This differs from the
+         ON criteria in SEARCH, which uses just the internal date.
+
+      CC
+         [IMAP] addr-mailbox of the first "cc" address.
+
+      DATE
+         Sent date and time, as described in section 2.2.
+
+      FROM
+         [IMAP] addr-mailbox of the first "From" address.
+
+      REVERSE
+         Followed by another sort criterion, has the effect of that
+         criterion but in reverse (descending) order.
+            Note: REVERSE only reverses a single criterion, and does not
+            affect the implicit "sequence number" sort criterion if all
+            other criteria are identicial.  Consequently, a sort of
+            REVERSE SUBJECT is not the same as a reverse ordering of a
+            SUBJECT sort.  This can be avoided by use of additional
+            criteria, e.g. SUBJECT DATE vs. REVERSE SUBJECT REVERSE
+            DATE.  In general, however, it's better (and faster, if the
+            client has a "reverse current ordering" command) to reverse
+            the results in the client instead of issuing a new SORT.
+
+      SIZE
+         Size of the message in octets.
+
+      SUBJECT
+         Base subject text.
+
+      TO
+         [IMAP] addr-mailbox of the first "To" address.
+
+   Example:    C: A282 SORT (SUBJECT) UTF-8 SINCE 1-Feb-1994
+               S: * SORT 2 84 882
+               S: A282 OK SORT completed
+               C: A283 SORT (SUBJECT REVERSE DATE) UTF-8 ALL
+               S: * SORT 5 3 4 1 2
+               S: A283 OK SORT completed
+               C: A284 SORT (SUBJECT) US-ASCII TEXT "not in mailbox"
+               S: * SORT
+               S: A284 OK SORT completed
+
+BASE.6.4.THREAD. THREAD Command
+
+Arguments:  threading algorithm
+            charset specification
+            searching criteria (one or more)
+
+Data:       untagged responses: THREAD
+
+Result:     OK - thread completed
+            NO - thread error: can't thread that charset or
+                 criteria
+            BAD - command unknown or arguments invalid
+
+      The THREAD command is a variant of SEARCH with threading semantics
+      for the results.  Thread has two arguments before the searching
+      criteria argument; a threading algorithm, and the searching
+      charset.
+
+      The charset argument is mandatory (unlike SEARCH) and indicates
+      the [CHARSET] of the strings that appear in the searching
+      criteria.  The US-ASCII and UTF-8 charsets MUST be implemented.
+      All other charsets are optional.
+
+      There is also a UID THREAD command which returns unique
+      identifiers instead of message sequence numbers.  Note that there
+      are separate searching criteria for message sequence numbers and
+      UIDs; thus the arguments to UID THREAD are interpreted the same as
+      in THREAD.  This is analogous to the behavior of UID SEARCH, as
+      opposed to UID COPY, UID FETCH, or UID STORE.
+
+      The THREAD command first searches the mailbox for messages that
+      match the given searching criteria using the charset argument for
+      the interpretation of strings in the searching criteria.  It then
+      returns the matching messages in an untagged THREAD response,
+      threaded according to the specified threading algorithm.
+
+      All collation is in ascending order.  Earlier dates collate before
+      later dates and strings are collated according to ascending values
+      established by their collation algorithm (see under
+      "Internationalization Considerations").
+
+      Untagged EXPUNGE responses are not permitted while the server is
+      responding to a THREAD command, but are permitted during a UID
+      THREAD command.
+
+      The defined threading algorithms are as follows:
+
+      ORDEREDSUBJECT
+
+         The ORDEREDSUBJECT threading algorithm is also referred to as
+         "poor man's threading."  The searched messages are sorted by
+         base subject and then by the sent date.  The messages are then
+         split into separate threads, with each thread containing
+         messages with the same base subject text.  Finally, the threads
+         are sorted by the sent date of the first message in the thread.
+
+         The first message of each thread are siblings of each other
+         (the "root").  The second message of a thread is the child of
+         the first message, and subsequent messages of the thread are
+         siblings of the second message and hence children of the
+         message at the root.  Hence, there are no grandchildren in
+         ORDEREDSUBJECT threading.
+
+         Children in ORDEREDSUBJECT threading do not have descendents.
+         Client implementations SHOULD treat descendents of a child in
+         a server response as being siblings of that child.
+
+      REFERENCES
+
+         The REFERENCES threading algorithm threads the searched
+         messages by grouping them together in parent/child
+         relationships based on which messages are replies to others.
+         The parent/child relationships are built using two methods:
+         reconstructing a message's ancestry using the references
+         contained within it; and checking the original (not base)
+         subject of a message to see if it is a reply to (or forward of)
+         another message.
+
+            Note: "Message ID" in the following description refers to a
+            normalized form of the msg-id in [RFC-2822].  The actual
+            text in an RFC 2822 may use quoting, resulting in multiple
+            ways of expressing the same Message ID.  Implementations of
+            the REFERENCES threading algorithm MUST normalize any msg-id
+            in order to avoid false non-matches due to differences in
+            quoting.
+
+            For example, the msg-id
+               <"01KF8JCEOCBS0045PS"@xxx.yyy.com>
+            and the msg-id
+               <01KF8JCEOCBS0045PS@xxx.yyy.com>
+            MUST be interpreted as being the same Message ID.
+
+         The references used for reconstructing a message's ancestry are
+         found using the following rules:
+
+            If a message contains a References header line, then use the
+            Message IDs in the References header line as the references.
+
+            If a message does not contain a References header line, or
+            the References header line does not contain any valid
+            Message IDs, then use the first (if any) valid Message ID
+            found in the In-Reply-To header line as the only reference
+            (parent) for this message.
+
+               Note: Although [RFC-2822] permits multiple Message IDs in
+               the In-Reply-To header, in actual practice this
+               discipline has not been followed.  For example,
+               In-Reply-To headers have been observed with message
+               addresses after the Message ID, and there are no good
+               heuristics for software to determine the difference.
+               This is not a problem with the References header however.
+
+            If a message does not contain an In-Reply-To header line, or
+            the In-Reply-To header line does not contain a valid Message
+            ID, then the message does not have any references (NIL).
+
+         A message is considered to be a reply or forward if the base
+         subject extraction rules, applied to the original subject,
+         remove any of the following: a subj-refwd, a "(fwd)"
+         subj-trailer, or a subj-fwd-hdr and subj-fwd-trl.
+
+         The REFERENCES algorithm is significantly more complex than
+         ORDEREDSUBJECT and consists of six main steps.  These steps are
+         outlined in detail below.
+
+         (1) For each searched message:
+
+            (A) Using the Message IDs in the message's references, link
+            the corresponding messages (those whose Message-ID header
+            line contains the given reference Message ID) together as
+            parent/child.  Make the first reference the parent of the
+            second (and the second a child of the first), the second the
+            parent of the third (and the third a child of the second),
+            etc.  The following rules govern the creation of these
+            links:
+
+               If a message does not contain a Message-ID header line,
+               or the Message-ID header line does not contain a valid
+               Message ID, then assign a unique Message ID to this
+               message.
+
+               If two or more messages have the same Message ID, then
+               only use that Message ID in the first (lowest sequence
+               number) message, and assign a unique Message ID to each
+               of the subsequent messages with a duplicate of that
+               Message ID.
+
+               If no message can be found with a given Message ID,
+               create a dummy message with this ID.  Use this dummy
+               message for all subsequent references to this ID.
+
+               If a message already has a parent, don't change the
+               existing link.  This is done because the References
+               header line may have been truncated by a MUA.  As a
+               result, there is no guarantee that the messages
+               corresponding to adjacent Message IDs in the References
+               header line are parent and child.
+
+               Do not create a parent/child link if creating that link
+               would introduce a loop.  For example, before making
+               message A the parent of B, make sure that A is not a
+               descendent of B.
+
+                  Note: Message ID comparisons are case-sensitive.
+
+            (B) Create a parent/child link between the last reference
+            (or NIL if there are no references) and the current message.
+            If the current message already has a parent, it is probably
+            the result of a truncated References header line, so break
+            the current parent/child link before creating the new
+            correct one.  As in step 1.A, do not create the parent/child
+            link if creating that link would introduce a loop.  Note
+            that if this message has no references, that it will now
+            have no parent.
+
+               Note: The parent/child links created in steps 1.A and 1.B
+               MUST be kept consistent with one another at ALL times.
+
+         (2) Gather together all of the messages that have no parents
+         and make them all children (siblings of one another) of a dummy
+         parent (the "root").  These messages constitute the first
+         (head) message of the threads created thus far.
+
+         (3) Prune dummy messages from the thread tree.  Traverse each
+         thread under the root, and for each message:
+
+            If it is a dummy message with NO children, delete it.
+
+            If it is a dummy message with children, delete it, but
+            promote its children to the current level.  In other words,
+            splice them in with the dummy's siblings.
+
+            Do not promote the children if doing so would make them
+            children of the root, unless there is only one child.
+
+         (4) Sort the messages under the root (top-level siblings only)
+         by sent date as described in section 2.2.  In the case of a
+         dummy message, sort its children by sent date and then use the
+         first child for the top-level sort.
+
+         (5) Gather together messages under the root that have the same
+         base subject text.
+
+            (A) Create a table for associating base subjects with
+            messages, called the subject table.
+
+            (B) Populate the subject table with one message per each
+            base subject.  For each child of the root:
+
+               (i) Find the subject of this thread, by using the base
+               subject from either the current message or its first
+               child if the current message is a dummy.  This is the
+               thread subject.
+
+               (ii) If the thread subject is empty, skip this message.
+
+               (iii) Look up the message associated with the thread
+               subject in the subject table.
+
+               (iv) If there is no message in the subject table with the
+               thread subject, add the current message and the thread
+               subject to the subject table.
+
+               Otherwise, if the message in the subject table is not a
+               dummy, AND either of the following criteria are true:
+
+                  The current message is a dummy, OR
+
+                  The message in the subject table is a reply or forward
+                  and the current message is not.
+
+            then replace the message in the subject table with the
+            current message.
+
+            (C) Merge threads with the same thread subject.  For each
+            child of the root:
+
+               (i) Find the message's thread subject as in step 5.B.i
+               above.
+
+               (ii) If the thread subject is empty, skip this message.
+
+               (iii) Lookup the message associated with this thread
+               subject in the subject table.
+
+               (iv) If the message in the subject table is the current
+               message, skip this message.
+
+               Otherwise, merge the current message with the one in the
+               subject table using the following rules:
+
+                  If both messages are dummies, append the current
+                  message's children to the children of the message in
+                  the subject table (the children of both messages
+                  become siblings), and then delete the current message.
+
+                  If the message in the subject table is a dummy and the
+                  current message is not, make the current message a
+                  child of the message in the subject table (a sibling
+                  of its children).
+
+                  If the current message is a reply or forward and the
+                  message in the subject table is not, make the current
+                  message a child of the message in the subject table (a
+                  sibling of its children).
+
+                  Otherwise, create a new dummy message and make both
+                  the current message and the message in the subject
+                  table children of the dummy.  Then replace the message
+                  in the subject table with the dummy message.
+
+                     Note: Subject comparisons are case-insensitive, as
+                     described under "Internationalization
+                     Considerations."
+
+         (6) Traverse the messages under the root and sort each set of
+         siblings by sent date as described in section 2.2.  Traverse
+         the messages in such a way that the "youngest" set of siblings
+         are sorted first, and the "oldest" set of siblings are sorted
+         last (grandchildren are sorted before children, etc).  In the
+         case of a dummy message (which can only occur with top-level
+         siblings), use its first child for sorting.
+
+   Example:    C: A283 THREAD ORDEREDSUBJECT UTF-8 SINCE 5-MAR-2000
+               S: * THREAD (166)(167)(168)(169)(172)(170)(171)
+                  (173)(174 (175)(176)(178)(181)(180))(179)(177
+                  (183)(182)(188)(184)(185)(186)(187)(189))(190)
+                  (191)(192)(193)(194 195)(196 (197)(198))(199)
+                  (200 202)(201)(203)(204)(205)(206 207)(208)
+               S: A283 OK THREAD completed
+               C: A284 THREAD ORDEREDSUBJECT US-ASCII TEXT "gewp"
+               S: * THREAD
+               S: A284 OK THREAD completed
+               C: A285 THREAD REFERENCES UTF-8 SINCE 5-MAR-2000
+               S: * THREAD (166)(167)(168)(169)(172)((170)(179))
+                  (171)(173)((174)(175)(176)(178)(181)(180))
+                  ((177)(183)(182)(188 (184)(189))(185 186)(187))
+                  (190)(191)(192)(193)((194)(195 196))(197 198)
+                  (199)(200 202)(201)(203)(204)(205 206 207)(208)
+               S: A285 OK THREAD completed
+
+        Note: The line breaks in the first and third server
+        responses are for editorial clarity and do not appear in
+        real THREAD responses.
+
+4. Additional Responses
+
+   These responses are extensions to the [IMAP] base protocol.
+
+   The section headings of these responses are intended to correspond
+   with where they would be located in the main document.
+
+BASE.7.2.SORT. SORT Response
+
+   Data:       zero or more numbers
+
+      The SORT response occurs as a result of a SORT or UID SORT
+      command.  The number(s) refer to those messages that match the
+      search criteria.  For SORT, these are message sequence numbers;
+      for UID SORT, these are unique identifiers.  Each number is
+      delimited by a space.
+
+   Example:    S: * SORT 2 3 6
+
+BASE.7.2.THREAD. THREAD Response
+
+   Data:       zero or more threads
+
+      The THREAD response occurs as a result of a THREAD or UID THREAD
+      command.  It contains zero or more threads.  A thread consists of
+      a parenthesized list of thread members.
+
+      Thread members consist of zero or more message numbers, delimited
+      by spaces, indicating successive parent and child.  This continues
+      until the thread splits into multiple sub-threads, at which point
+      the thread nests into multiple sub-threads with the first member
+      of each subthread being siblings at this level.  There is no limit
+      to the nesting of threads.
+
+      The messages numbers refer to those messages that match the search
+      criteria.  For THREAD, these are message sequence numbers; for UID
+      THREAD, these are unique identifiers.
+
+   Example:    S: * THREAD (2)(3 6 (4 23)(44 7 96))
+
+      The first thread consists only of message 2.  The second thread
+      consists of the messages 3 (parent) and 6 (child), after which it
+      splits into two subthreads; the first of which contains messages 4
+      (child of 6, sibling of 44) and 23 (child of 4), and the second of
+      which contains messages 44 (child of 6, sibling of 4), 7 (child of
+      44), and 96 (child of 7).  Since some later messages are parents
+      of earlier messages, the messages were probably moved from some
+      other mailbox at different times.
+
+      -- 2
+
+      -- 3
+         \-- 6
+             |-- 4
+             |   \-- 23
+             |
+             \-- 44
+                  \-- 7
+                      \-- 96
+
+   Example:    S: * THREAD ((3)(5))
+
+      In this example, 3 and 5 are siblings of a parent which does not
+      match the search criteria (and/or does not exist in the mailbox);
+      however they are members of the same thread.
+
+5. Formal Syntax of SORT and THREAD Commands and Responses
+
+   The following syntax specification uses the Augmented Backus-Naur
+   Form (ABNF) notation as specified in [ABNF].  It also uses [ABNF]
+   rules defined in [IMAP].
+
+sort            = ["UID" SP] "SORT" SP sort-criteria SP search-criteria
+
+sort-criteria   = "(" sort-criterion *(SP sort-criterion) ")"
+
+sort-criterion  = ["REVERSE" SP] sort-key
+
+sort-key        = "ARRIVAL" / "CC" / "DATE" / "FROM" / "SIZE" /
+                  "SUBJECT" / "TO"
+
+thread          = ["UID" SP] "THREAD" SP thread-alg SP search-criteria
+
+thread-alg      = "ORDEREDSUBJECT" / "REFERENCES" / thread-alg-ext
+
+thread-alg-ext  = atom
+                    ; New algorithms MUST be registered with IANA
+
+search-criteria = charset 1*(SP search-key)
+
+charset         = atom / quoted
+                    ; CHARSET values MUST be registered with IANA
+
+sort-data       = "SORT" *(SP nz-number)
+
+thread-data     = "THREAD" [SP 1*thread-list]
+
+thread-list     = "(" (thread-members / thread-nested) ")"
+
+thread-members  = nz-number *(SP nz-number) [SP thread-nested]
+
+thread-nested   = 2*thread-list
+
+   The following syntax describes base subject extraction rules (2)-(6):
+
+subject         = *subj-leader [subj-middle] *subj-trailer
+
+subj-refwd      = ("re" / ("fw" ["d"])) *WSP [subj-blob] ":"
+
+subj-blob       = "[" *BLOBCHAR "]" *WSP
+
+subj-fwd        = subj-fwd-hdr subject subj-fwd-trl
+
+subj-fwd-hdr    = "[fwd:"
+
+subj-fwd-trl    = "]"
+
+subj-leader     = (*subj-blob subj-refwd) / WSP
+
+subj-middle     = *subj-blob (subj-base / subj-fwd)
+                    ; last subj-blob is subj-base if subj-base would
+                    ; otherwise be empty
+
+subj-trailer    = "(fwd)" / WSP
+
+subj-base       = NONWSP *(*WSP NONWSP)
+                    ; can be a subj-blob
+
+BLOBCHAR        = %x01-5a / %x5c / %x5e-ff
+                    ; any CHAR8 except '[' and ']'
+
+NONWSP          = %x01-08 / %x0a-1f / %x21-ff
+                    ; any CHAR8 other than WSP
+
+6. Security Considerations
+
+   The SORT and THREAD extensions do not raise any security
+   considerations that are not present in the base [IMAP] protocol, and
+   these issues are discussed in [IMAP].  Nevertheless, it is important
+   to remember that [IMAP] protocol transactions, including message
+   data, are sent in the clear over the network unless protection from
+   snooping is negotiated, either by the use of STARTTLS, privacy
+   protection is negotiated in the AUTHENTICATE command, or some other
+   protection mechanism.
+
+   Although not a security consideration, it is important to recognize
+   that sorting by REFERENCES can lead to misleading threading trees.
+   For example, a message with false References: header data will cause
+   a thread to be incorporated into another thread.
+
+   The process of extracting the base subject may lead to incorrect
+   collation if the extracted data was significant text as opposed to
+   a subject artifact.
+
+7. Internationalization Considerations
+
+   As stated in the introduction, the rules of I18NLEVEL=1 as described
+   in [IMAP-I18N] MUST be followed; that is, the SORT and THREAD
+   extensions MUST collate strings according to the i;unicode-casemap
+   collation described in [UNICASEMAP].  Servers SHOULD also advertise
+   the I18NLEVEL=1 extension.  Alternatively, a server MAY implement
+   I18NLEVEL=2 (or higher) and comply with the rules of that level.
+
+   As discussed in [IMAP-I18N] section 4.5, all server implementations
+   should eventually be updated to support the [IMAP-I18N] I18NLEVEL=2
+   extension.
+
+   Translations of the "re" or "fw"/"fwd" tokens are not specified for
+   removal in the base subject extraction process.  An attempt to add
+   such translated tokens would result in a geometrically complex, and
+   ultimately unimplementable, task.
+
+   Instead, note that [RFC-2822] section 3.6.5 recommends that "re:"
+   (from the Latin "res", in the matter of) be used to identify a reply.
+   Although it is evident that, from the multiple forms of token to
+   identify a forwarded message, there is considerable variation found
+   in the wild, the variations are (still) manageable.  Consequently, it
+   is suggested that "re:" and one of the variations of the tokens for
+   forward supported by the base subject extraction rules be adopted for
+   Internet mail messages, since doing so makes it a simple display time
+   task to localize the token language for the user.
+
+8. IANA Considerations
+
+   [IMAP] capabilities are registered by publishing a standards track or
+   IESG approved experimental RFC.  This document constitutes
+   registration of the SORT and THREAD capabilities in the [IMAP]
+   capabilities registry.
+
+   This document creates a new [IMAP] threading algorithms registry,
+   which registers threading algorithms by publishing a standards track
+   or IESG approved experimental RFC.  This document constitutes
+   registration of the ORDEREDSUBJECT and REFERENCES algorithms in that
+   registry.
+
+9. Normative References
+
+   The following documents are normative to this document:
+
+   [ABNF]                Crocker, D. and Overell, P. "Augmented BNF
+                         for Syntax Specifications: ABNF", RFC 5234
+                         January 2008
+
+   [CHARSET]             Freed, N. and Postel, J. "IANA Character Set
+                         Registration Procedures", RFC 2978, October
+                         2000.
+
+   [IMAP]                Crispin, M. "Internet Message Access Protocol -
+                         Version 4rev1", RFC 3501, March 2003.
+
+   [IMAP-I18N]           Newman, C. and Gulbrandsen, A. "Internet
+                         Message Access Protocol Internationalization",
+                         Work in Progress.
+
+   [KEYWORDS]            Bradner, S. "Key words for use in RFCs to
+                         Indicate Requirement Levels", BCP 14, RFC 2119,
+                         March 1997.
+
+   [RFC-2822]            Resnick, P. "Internet Message Format", RFC
+                         2822, April 2001.
+
+   [UNICASEMAP]          Crispin, M. "i;unicode-casemap - Simple Unicode
+                         Collation Algorithm", RFC 5051.
+
+10. Informative References
+
+   The following documents are informative to this document:
+
+   [IMAP-MODELS]         Crispin, M. "Distributed Electronic Mail Models
+                         in IMAP4", RFC 1733, December 1994.
+
+   [THREADING]           Zawinski, J. "Message Threading",
+                         http://www.jwz.org/doc/threading.html,
+                         1997-2002.
+
+Appendices
+
+Author's Address
+
+   Mark R. Crispin
+   Networks and Distributed Computing
+   University of Washington
+   4545 15th Avenue NE
+   Seattle, WA  98105-4527
+
+   Phone: +1 (206) 543-5762
+
+   EMail: MRC@CAC.Washington.EDU
+
+   Kenneth Murchison
+   Carnegie Mellon University
+   5000 Forbes Avenue
+   Cyert Hall 285
+   Pittsburgh, PA  15213
+
+   Phone: +1 (412) 268-2638
+   Email: murch@andrew.cmu.edu
+
+Full Copyright Statement
+
+   Copyright (C) The IETF Trust (2008).
+
+   This document is subject to the rights, licenses and restrictions
+   contained in BCP 78, and except as set forth therein, the authors
+   retain all their rights.
+
+   This document and the information contained herein are provided on an
+   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
+   THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
+   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   Intellectual Property Rights or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; nor does it represent that it has
+   made any independent effort to identify any such rights.  Information
+   on the procedures with respect to rights in RFC documents can be
+   found in BCP 78 and BCP 79.
+
+   Copies of IPR disclosures made to the IETF Secretariat and any
+   assurances of licenses to be made available, or the result of an
+   attempt made to obtain a general license or permission for the use of
+   such proprietary rights by implementers or users of this
+   specification can be obtained from the IETF on-line IPR repository at
+   http://www.ietf.org/ipr.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights that may cover technology that may be required to implement
+   this standard.  Please address the information to the IETF at ietf-
+   ipr@ietf.org.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is currently provided by the
+   Internet Society.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/drivers.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,189 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+		   c-client Driver Characteristics
+			     Mark Crispin
+			   11 December 2006
+
+
+     Drivers are code modules that support different mailbox storage
+technologies.  A mailbox storage technology may be implemented by
+ 1) files and directories on the local system
+ 2) a database
+ 3) a network protocol.
+
+     In the case of files and directories on the local system, a
+driver supports a particular mailbox format.  Mailbox formats are
+discussed in more detail in the file formats.txt.
+
+     As of the date this document was written, there was no bundled
+support for any databases in c-client.  However, it should not be
+particularly difficult to write a driver that communicates with a
+database.
+
+     Network protocols supported by c-client drivers are the Internet
+Mail Access Protocol (all versions: IMAP4rev1, IMAP4, IMAP2bis, and
+IMAP2); the Post Office Protocol (version 3); and the Network News
+Transport Protocol (NNTP).  In addition, c-client also supports NNTP
+and the Simple Mail Transport Protocol (SMTP) for mailbox transport.
+
+     By default, all drivers are enabled.  There is little benefit to
+be gained by disabling a driver, with one exception.  The mbox driver
+implements the behavior of automatically moving new mail from the
+spool directory to the "mbox" file on the user's home directory, if
+and *only* if the "mbox" exists and is in mailbox format.  The mbox
+driver is listed under EXTRADRIVERS; if you wish to disable it just
+remove it from that list and rebuild.
+
+I. Special name "INBOX"
+
+The following rules to select INBOX and its format apply in
+the order given if "black box mode" is not in effect:
+ 1) mbox format is selected if file ~/mbox exists, and is in unix
+    format or is zero-length.
+ 2) mx format is selected if file ~/INBOX/.mxindex exists.
+ 3) mbx format is selected if file ~/INBOX exists and is in mbx format.
+ 4) tenex format is selected if:
+    a) file ~/mail.txt exists, and is in tenex format or is zero-length.
+    b) file ~/INBOX exists and is in tenex format.
+ 5) mtx format is selected if:
+    a) file ~/INBOX.MTX exists, and is in mtx format or is zero-length.
+    b) file ~/INBOX exists and is in mtx format.
+ 6) mmdf format is selected if the spool directory file exists and is
+    in mmdf format.
+ 7) unix format is selected if the spool directory file exists and is
+    in unix format.   
+ 8) the dummy driver is selected if the spool directory file does not
+    exist, or exists and is empty.
+
+If "black box mode" is not in effect, messages are automatically
+transferred ("snarfed") from the spool directory to an INBOX in mbox,
+mx, mbx, tenex, and mtx formats.
+
+The following rules to select INBOX and its format apply in the order
+given if "black box mode" is in effect:
+ 1) mx format is selected if file ~/INBOX/.mxindex exists.
+ 2) mbx format is selected if file ~/INBOX exists and is in mbx format.
+ 3) tenex format is selected if file ~/INBOX exists and is in tenex format.
+ 4) mtx format is selected if file ~/INBOX exists and is in mtx format.
+ 5) mmdf format is selected if file ~/INBOX exists and is in mmdf format.
+ 6) unix format is selected if file ~/INBOX exists and is in unix format.
+ 7) the dummy driver is selected if ~/INBOX does not exist, or exists
+    and is empty.
+
+II. Special Name #mhinbox
+
+#mhinbox always refers to the directory "inbox" in the MH path, which
+is declared in the ~/.mh_profile file.  Messages are automatically
+transferred from the spool directory to #mhinbox mailbox.
+
+
+III. Special Prefix "#mh/"
+
+Any name prefixed with "#mh/" always refers to a directory in the MH
+path, which is declared in the ~/.mh_profile file.  For example, the name
+"#mh/foo" refers to directory "foo" in the MH path.
+
+
+IV. Special prefix "#news."
+
+Any name prefixed with "#news" always refers to a newsgroup.  For
+example, the name "#news.comp.mail.misc" refers to newsgroup
+"comp.mail.misc".
+
+
+V. All Other Names
+
+The driver is selected by generating a file name from the mailbox
+name, and then examining the data of the object with the resulting
+name.  The formats are checked in order: mx, mbx, tenex, mtx, mmdf,
+unix, and phile.  The dummy driver is selected if the file is empty.
+
+The file name is generated according to certain rules, based upon the
+prefix of the mailbox name.  On UNIX, the following rules apply:
+
+Prefix		Interpretation of Suffix
+------		------------------------
+/		[black box] preceeds a user name; "/foo/bar" means
+		 "black box user foo's mailbox bar"
+		[not black box] preceeds an absolute path name.
+~		[not black box] preceeds a user name; "~foo/bar" means
+		 "UNIX user foo's mailbox bar"
+#ftp/		preceeds UNIX user ftp's mailbox name
+#public/	preceeds UNIX user imappublic's mailbox name
+#shared/	preceeds UNIX user imapshared's mailbox name
+
+All other names are interpreted in the context of the UNIX user's home
+directory (not black box), the black box user's black box directory
+(black box), or UNIX user ftp's home directory (anonymous).
+
+The strings "..", "//", and /~ are forbidden in names in:
+ black box mode
+ #ftp, #public, or #shared names
+ anonymous users
+
+Anonymous users may only access:
+ INBOX (belonging to UNIX user ftp)
+ files in or below UNIX user ftp's home directory
+ #ftp, #news, and #public namespace
+
+VI. Driver Comparison
+
+The following information about the local file drivers is an
+elaboration of a table compiled by Osma Ahvenlampi.
+
+Driver	CA	CE	UID	Kwd	Sub	NFS	Performance	Layout
+------	--	--	---	---	---	---	-----------	------
+unix	no	no	yes	yes	no	limited	fair		file
+ ;;; traditional UNIX format
+mbox	no	no	yes	yes	no	limited	fair		file
+ ;;; traditional UNIX format, INBOX only, using ~/mbox with automatic
+ ;;; moving from the mail spool directory.
+mmdf	no	no	yes	yes	no	limited	fair		file
+ ;;; default on SCO systems
+mbx	yes	yes	yes	yes	no	no	very good	prefile
+ ;;; best performing local file driver; preferred format at UW
+tenex	yes	no	no	limited	no	no	good		prefile
+ ;;; compatible with UNIX MM
+mtx	yes	no	no	limited	no	no	very good	prefile
+ ;;; PC Pine standard format; compatible with TOPS-20; identical to tenex
+ ;;; but instead CRLF newlines instead of LF
+mx	yes	buggy	yes	yes	yes	no	poor		ixdir
+ ;;; fullest function; *not* recommended due to performance problems and bugs;
+ ;;; to be redesigned/rewritten
+mh	yes	no	no	no	yes	yes	very poor	dir
+ ;;; compatible with mh; #mhinbox for INBOX, #mh/ prefix for all other names
+news	yes	no	yes	no	yes	yes	very poor	ixdir
+ ;;; local news spool access; #news. prefix for all names
+phile	no	no	no	no	no	yes	good		file
+ ;;; reads arbitrary file as a single readonly message
+
+IMPORTANT: the "performance" ratings are relative to other drivers,
+and not necessarily to other software which implements those formats.
+They relate to the driver's performance in typical operations such as
+an IMAP "FETCH ALL".
+
+Key to headings:
+	CA:	concurrent read/write access
+	CE:	expunge permitted in concurrent read/write access
+	UID:	sticky UIDs
+	Kwd:	keyword flags
+	Sub:	subfolders
+	NFS:	usable over network filesystems (NFS, AFS, etc.)
+	Layout:	file - single file
+		prefile - file with preallocated space for state
+		dir - directory, messages are files
+		ixdir - directory, messages are files, with helper index
+
+In addition, drivers imap, nntp, and pop3 support IMAP4rev1, NNTP, and
+POP3 protocols respectively.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/formats.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,217 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+		    Mailbox Format Characteristics
+			     Mark Crispin
+			   11 December 2006
+
+
+     When a mailbox storage technology uses local files and
+directories directly, the file(s) and directories are layed out in a
+mailbox format.
+
+I. Flat-File Formats
+
+     In these formats, a mailbox and all the messages inside are a
+single file on the filesystem.  The mailbox name is the name of the
+file in the filesystem, relative to the user's "mail home directory."
+
+     A flat-file format mailbox is always a file, never a directory.
+This means that it is impossible to have a flat-file format mailbox
+that has inferior mailbox names under it (so-called "dual-usage"
+mailboxes).  For some inexplicable reason, some people want this.
+
+     The mail home directory is usually the same as the user login
+home directory if that concept is meaningful; otherwise, it is some
+other default directory (e.g. "C:\My Documents" on Windows 98).  This
+can be redefined by modifying the c-client source code or in an
+application via the SET_HOMEDIR mail_parameters() call.
+
+     For example, a mailbox named "project" is likely to be found in
+the file "project" in the user's home directory.  Similarly, a mailbox
+named "test/trial1" (assuming a UNIX system) is likely to be found in
+the file "trial1" in the subdirectory "test" in the user's home
+directory.
+
+     Note that the name "INBOX" has special semantics and rules, as
+described in the file naming.txt.
+
+     The following flat-file formats are supported by c-client as of
+the time of this writing:
+
+. unix	This is the traditional UNIX mailbox format, in use for nearly
+	30 years.  It uses a line starting with "From " to indicate
+	start of message, and stores the message status inside the
+	RFC822 message header.
+
+	unix is not particularly efficient; the entire mailbox file
+	must be read when the mailbox is open, and when reading message
+	texts it is necessary to convert the newline convention to
+	Internet standard CR LF form.  unix preserves UIDs, and allows
+	the creation of keywords.
+
+	Only one process may have a unix-format mailbox open
+	read/write at a time.
+
+. mmdf	This is the format used by the MMDF mailer.  It uses a line
+	consisting of 4 <CTRL/A> (0x01) characters to indicate start
+	and end of message.  Optionally, there may also be a unix
+	format "From " line.  It otherwise has the same
+	characteristics as unix format.
+
+. mbx	This is the current preferred mailbox format.  It can be
+	handled quite efficiently by c-client, without the problems
+	that exist with unix and mmdf formats.  Messages are stored
+	in Internet standard CR LF format.
+
+	mbx permits shared access, including shared expunge.  It
+	preserves UIDs, and allows the creation of keywords.
+
+. mtx	This is supported for compatibility with the past.  This is
+	the old Tenex/TOPS-20 mail.txt format.  It can be handled
+	quite efficiently by c-client, and has most of the
+	characteristics of mbx format.
+
+	mtx is deficient in that it does not support shared expunge;
+	it has no means to store UIDs; and it has no way to define
+	keywords except through an external configuration file.
+
+. tenex	This is supported for compatibility with the past.  This is
+	the old Columbia MM format.  This is similar to mtx format,
+	only it uses UNIX-style bare-LF newlines instead of CR LF
+	newlines, thus incurring a performance penalty for newline
+	conversion.
+
+. phile	This is not strictly a format.  Any file which is not in a
+	recognized format is in phile format, which treats the entire
+	contents of the file as a single message.
+
+
+II. File/Message Formats
+
+     In these formats, a mailbox is a directory, and each the messages
+inside are separate files inside the directory.  The file names of
+these files are generally the text form of a number, which also
+matches the UID of the message.
+
+     In the case of mx, the mailbox name is the name of the directory
+in the filesystem, relative to the user's "mail home directory."  In
+the case of news and mh, the mailbox name is in a separate namespace
+as described in the file naming.txt.
+
+     A file/message format mailbox is always a directory.  This means
+that it is possible to have a file/message format mailbox that has
+inferior mailbox names under it (so-called "dual-usage" mailboxes).
+For some inexplicable reason, some people want this.
+
+     Note that the name "INBOX" has special semantics and rules, as
+described in the file naming.txt.
+
+     The following file/message formats are supported by c-client as of
+the time of this writing:
+
+. mx	This is an experimental format, and may be removed in a future
+	release.  An mx format mailbox has a .mxindex file which holds
+	the message status and unique identifiers.  Messages are
+	stored in Internet standard CF LF form, so the file size of
+	the message file equals the size of the message.
+
+	mx is somewhat inefficient; the entire directory must be read
+	and each file stat()'d.  We found it intolerable for a
+	moderate sized mailbox (2000 messages) and have more or less
+	abandoned it.	
+
+. mh	This is supported for compatibility with the past.  This is
+	the format used by the old mh program.
+
+	mh is very inefficient; the entire directory must be read
+	and each file stat()'d, and in order to determine the size
+	of a message, the entire file must be read and newline
+	conversion performed.
+
+	mh is deficient in that it does not support any permanent
+	flags or keywords; and has no means to store UIDs (because
+	the mh "compress" command renames all the files, that's
+	why).
+
+. news	This is an export of the local filesystem's news spool, e.g.
+	/var/spool/news.  Access to mailboxes in news format is read
+	only; however, message "deleted" status is preserved in a
+	.newsrc file in the user's home directory.  There is no other
+	status or keywords.
+
+	news is very inefficient; the entire directory must be
+	read and each file stat()'d, and in order to determine the
+	size of a message, the entire file must be read and newline
+	conversion performed.
+
+	news is deficient in that it does not support permanent flags
+	other than deleted; does not support keywords; and has no
+	expunge.
+
+
+Soapbox on File/Message Formats
+
+     If it sounds from the above descriptions that we're not putting
+too much effort into file/message formats, you are correct.
+
+     There's a general reason why file/message formats are a bad idea.
+Just about every filesystem in existance serializes file creation and
+deletions because these manipulate the free space map.  This turns out
+to be an enormous problem when you start creating/deleting more than a
+few messages per second; you spend all your time thrashing in the
+filesystem.
+
+     It is also extremely slow to do a text search through a
+file/message format mailbox.  All of those open()s and close()s really
+add up to major filesystem thrashing.
+
+
+What about Cyrus and Maildir?
+
+     Both formats are vulnerable to the filesystem thrashing outlined
+above.
+
+     The Cyrus format used by CMU's Cyrus server (and Esys' server)
+has a special associated flat file in each directory that contains
+extensive data (including pre-parsed ENVELOPEs and BODYSTRUCTUREs)
+about the messages.  Put another way, it's a (considerably) more
+featureful form of mx.  It also uses certain operating system
+facilities (e.g. file/memory mapping) which are not available on older
+systems, at a cost of much more limited portability than c-client.
+These considerably ameliorate the fundamental problems with
+file/message formats; in fact, Cyrus is halfway to being a database.
+Rather than support Cyrus format in c-client, you should run Cyrus or
+Esys if you want that format.
+
+     The Maildir format used by qmail has all of the performance
+disadvantages of mh noted above, with the additional problem that the
+files are renamed in order to change their status so you end up having
+to rescan the directory frequently to locate the current names
+(particularly in a shared mailbox scenario).  It doesn't scale, and it
+represents a support nightmare; it is therefore not supported in the
+official distribution.  Maildir support code for c-client is available
+from third parties; but, if you use it, it is entirely at your own
+risk (read: don't complain about how poorly it performs or bugs).
+
+
+So what does this all mean?
+
+     A database (such as used by Exchange) is really a much better
+approach if you want to move away from flat files.  mx and especially
+Cyrus take a tenative step in that direction; mx failed mostly because
+it didn't go anywhere near far enough.  Cyrus goes much further, and
+scores remarkable benefits from doing so.
+
+     However, a well-designed pure database without the overhead of
+separate files would do even better.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/imaprc.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,613 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+		       .imaprc secrets revealed!
+		      Mark Crispin, June 17, 2002
+
+The following information describes the format of the /etc/c-client.cf
+and ~/.imaprc file.  The Columbia MM ~/.mminit file is also read by
+c-client; however, the only command that ~/.mminit has in common is
+set keywords.
+
+**********************************************************************
+*		     DANGER!  BEWARE!  TAKE CARE!		     *
+**********************************************************************
+*								     *
+*  These files, and this documentation, are for internal UW usage    *
+* only.  This capability is for UW experimental tinkering, and most  *
+* emphatically *not* for sorcerer's apprentices at other sites who   *
+* feel that if a config file capability exists, they must write a    *
+* config file whether or not there is any need for one.		     *
+*								     *
+*  This information is subject to change without notice.  Commands   *
+* may be added, removed, or altered.  The behavior of comamnds may   *
+* change.  Do not use any of this information without consulting me  *
+* first.  c-client's defaults have been carefully chosen to be right *
+* for general-purpose and most special-purpose configurations.  If   *
+* you tinker with these defaults, all hell may break loose.	     *
+*								     *
+*  This is not an idle threat.  There have been several instances of *
+* people who ignored these warnings and have gotten burned.	     *
+*								     *
+*  Don't even trust this file to work.  Many of the things which can *
+* be changed by this file can also be changed by the application,    *
+* and it is totally unpredictable which will take precedence.  It    *
+* all depends upon how the application is coded.  Not only that, you *
+* may cause the application to crash.                                *
+*								     *
+*  In other words, keep your cotton-pickin' hands off my defaults.   *
+* If it crashes and erases your mail, I don't want to hear about it. *
+* Consider 'em ``mandatory defaults''.  Got a nice ring, eh?  :-) If *
+* you must tinker with defaults, play with the .pinerc and pine.conf *
+* files in Pine.  It's got options galore, all supported for you to  *
+* have fun.  They're also documented; so well documented, it takes   *
+* two strong men to carry around all the documentation.	 ;-) ;-)     *
+*								     *
+*  Joking aside, you really shouldn't be fooling around with this    *
+* capability.  It's dangerous, and you can shoot yourself in the     *
+* foot easily.  If you need custom changes, you are better off with  *
+* local source code modifications.  Seriously.			     *
+*								     *
+*  One last warning: don't believe anything that you read in this    *
+* document.  Every effort has been made to ensure that this document *
+* is incomplete and inaccurate, and I take no responsibility for any *
+* glimmers of correct information that may, by some fluke, be here.  *
+*								     *
+**********************************************************************
+
+The files are read in order: /etc/c-client.cf, ~/.mminit, ~/.imaprc,
+and an entry in a later file overrides the setting of an earlier file
+except as noted below.  This ordering and overriding behavior may
+change without notice.
+
+Almost all of these facilities can also be set via the mail_parameters()
+call in the program.  Whether the file overrides mail_parameters(), or
+mail_parameters() overrides the file, is indeterminate.  It will vary
+from program to program, and it may be one way in one version and the
+other way in the next version.  It's completely unpredictable, and so
+anything you do with these files has to be in complete knowledge of what
+the version of each program you're running is going to do.  This is
+because the files do something for testing, but the real capability for
+configurability is put in the program instead.  Are you getting the
+feeling that you shouldn't be messing with these files yet?
+
+The very first line of the file MUST start with the exact string "I
+accept the risk".  This ensures that you have checked the file for
+correctness against this version of the IMAP toolkit.  This enable
+string may change without notice in future versions, and the new
+string may or may not be accurately described in an updated version of
+this file.  So any time you install software that uses the IMAP
+toolkit, you need to check the new version against these files (if you
+have insisted upon creating them in spite of all warnings).  If two
+pieces of software use different versions of the IMAP toolkit with
+incompatible requirements, one of them won't work.  Re-read the
+warning above about why you should not use these files.
+
+Subsequent lines are read from the file one at a time.  Case does not
+matter.  Unrecognized commands are ignored.
+
+1) set new-folder-format
+   sets what format new mailboxes are created in.  This also controls
+   default delivery via tmail and dmail.
+
+   a) set new-folder-format same-as-inbox
+      Folder is created using the same mailbox format as INBOX.  If
+      INBOX is empty, it defaults to system standard.
+
+   b) set new-folder-format system-standard
+      This is the default.  Folder is created using the wired-in system
+      standard format, which on most UNIX systems is ordinary UNIX
+      /bin/mail format.  On SCO systems, this is MMDF.
+
+   c) set new-folder-format <driver name>
+      Folder is created using the given driver name, e.g. mbx, unix,
+      mmdf, etc.
+
+   There is no protection against setting this to a silly value (e.g.
+   news, nntp, dummy) and doing so is a great way to screw things up.
+   Setting this to mh does not do what you think it does.  Setting this
+   to tenex or mtx isn't particularly useful.
+
+2) set empty-folder-format
+   sets what format data is written into an empty mailbox file using
+   mail_copy() or mail_append().  This also controls default delivery
+   via tmail.
+
+   a) set empty-folder-format same-as-inbox
+      Data is written using the same mailbox format as INBOX.  If
+      INBOX is empty, it defaults to system standard.
+
+   b) set empty-folder-format system-standard
+      This is the default.  Data is written using the wired-in system
+      standard format, which on most UNIX systems is ordinary UNIX
+      /bin/mail format.  On SCO systems, this is MMDF.
+
+   c) set-empty-folder-format <driver name>
+      Data is written using the given driver name, e.g. tenex, unix,
+      mmdf, etc.
+
+   There is no protection against setting this to a silly value (e.g.
+   news, nntp, dummy) and doing so is a great way to screw things up.
+   Setting this to mh, mbx, or mx does not work.
+
+3) set keywords <word1>, <word2>, ... <wordn>
+   Sets the list of keyword flags (supported by tenex and mtx) to the
+   given list.  Up to 30 flags may be given.  Since these names
+   correspond to numeric bits, the order of the keywords can not be
+   changed, nor can keywords be removed or inserted (you can append
+   new keywords, up to the limit of 30).
+
+   Set keywords is a deprecated command.  It may not appear in
+   future versions, or it may appear in a changed form.  It exists
+   only for compatibility with MM, and should only appear in ~/.mminit
+   and not in the other files.  It is likely to disappear entirely in
+   IMAP4.
+
+   There is no protection against setting these to silly values, and
+   doing so is a great way to cause a crash.
+
+4) set from-widget header-only
+   Sets smart insertion of the > character in front of lines that
+   begin with ``From ''.  Only such lines that are also in UNIX mbox
+   header file format will have a > character inserted.  The default
+   is to insert the > character in front of all lines which begin with
+   ``From '', for the benefit of legacy tools that get confused
+   otherwise.
+
+5) set black-box-directory <directory name>
+   Sets the directory in which the user's data can be found.  A user's
+   folders can be found in a subdirectory of the black box directory
+   named with the user's username.  For example, if the blackbox
+   directory is /usr/spool/folders/, user jones' data can be found
+   in /usr/spool/folders/jones/.  The user's black-box directory is
+   the location of folders, .mminit, .imaprc, .newsrc, and all other
+   files used by c-client; internally, it sets c-client's idea of the
+   user's ``home directory'', overriding /etc/passwd.
+
+   This command may not appear in ~/.mminit or ~/.imaprc
+
+   In black-box mode, it is not permitted to access any folders
+   outside of the user's personal blackbox directory.  The breakouts
+   ``/'', ``~'', and ``..'' are not permitted.
+
+   In order to make this work without crashing, you must set another
+   option which is not listed in this document.
+
+   There is no protection against setting this to a silly value, and
+   doing so is a great way to cause a crash.
+
+6) set local-host <host name>
+   Sets c-client's idea of the local host name.
+
+   There is no protection against setting this to a silly value, and
+   doing so is a great way to cause a crash.
+
+7) set news-active-file <file name>
+   Sets the location of the news active file, if it is not in the
+   standard place.
+
+   It is recommended to use a courtesy symbolic link instead.
+
+   There is no protection against setting this to a silly value, and
+   doing so is a great way to cause a crash.
+
+8) set news-spool-directory <directory name>
+   Sets the location of the news spool, if it is not in the standard
+   place.
+
+   It is recommended to use a courtesy symbolic link instead.
+
+   There is no protection against setting this to a silly value, and
+   doing so is a great way to cause a crash.
+
+9) set news-state-file <file name>
+   Sets the location of the news state file (normally $(USER)/.newsrc).
+
+   This is not very useful in /etc/c-client.cf because it is a file name.
+   Setting this in /etc/c-client.cf would set all users to the same file
+   as their newsrc, which is probably not what you want.
+
+   There is no protection against setting this to a silly value, and
+   doing so is a great way to cause a crash.
+
+10) set system-inbox <file name>
+   Sets the location of the "system inbox", if it is not in the standard
+   place.  This is the default location of INBOX, or the mail drop point
+   from which mail is snarfed (e.g. in tenex, mtx, mbox, mh formats).
+
+   This is not very useful in /etc/c-client.cf because it is a file name.
+   Setting this in /etc/c-client.cf would set all users to the same file
+   as their system inbox, which is probably not what you want.
+
+   There is no protection against setting this to a silly value, and
+   doing so is a great way to cause a crash.
+
+11) set tcp-open-timeout <number>
+    Sets the number of seconds that the TCP routines will block on opening
+    a TCP connection before timing out.  If a timeout occurs, the connection
+    attempt is aborted.
+
+    The default is zero, meaning use the operating system default (75
+    seconds on most UNIX systems).
+
+    There is no protection against setting this to an excessively small
+    value, such as 1, and doing so is a great way to cause users extreme
+    grief.
+
+12) set tcp-read-timeout <number>
+    Sets the number of seconds that the TCP routines will block on reading
+    data before calling the timeout routine.  If no timeout routine is set
+    by the program, the connection will be aborted on a timeout.
+
+    The default is zero, meaning infinite.
+
+    There is no protection against setting this to an excessively small
+    value, such as 1, and doing so is a great way to cause users extreme
+    grief.
+
+13) set tcp-write-timeout <number>
+    Sets the number of seconds that the TCP routines will block on sending
+    data before calling the timeout routine.  If no timeout routine is set
+    by the program, the connection will be aborted on a timeout.
+
+    The default is zero, meaning infinite.
+
+    There is no protection against setting this to an excessively small
+    value, such as 1, and doing so is a great way to cause users extreme
+    grief.
+
+14) set rsh-timeout <number>
+    Sets the number of seconds that the rsh routines will block on opening
+    an rimapd connection before timing out.  If a timeout occurs, the
+    rsh connection attempt is aborted.  A zero timeout will disable rsh.
+
+    The default is 15 seconds.
+
+    There is no protection against setting this to an excessively small
+    value, such as 1, and doing so is a great way to cause users extreme
+    grief.
+
+15) set maximum-login-trials <number>
+    Sets the number of iterations of asking the user, via mm_login(), for
+    a user name and password, before cancelling the attempt.
+
+    The default is 3.
+
+    There is no protection against setting this to zero, and doing so is
+    a great way to cause users extreme grief.
+
+16) set lookahead <number>
+    Sets the number of envelopes that are looked ahead in IMAP, in
+    mail_fetchstructure().  This is based on the guess that in such
+    operations as drawing browser lines, if you get data for message n
+    you are likely to want it for message n+1, n+2,... in short order.
+    Lookahead preloads the c-client  cache and saves unnecessary RTTs.
+
+    The default is 20, a good number for a browser on a 24x80 screen, and
+    small enough to usually have no significant real-time difference from
+    a single message fetch.
+
+    Setting it to 0 turns off lookahead.
+
+    There is no protection against setting this ridiculously high and
+    incurring performance penalties as a result.
+
+17) set prefetch <number>
+    Sets the number of envelops which are automatically fetched for the
+    messages which match in a search.  This is based on the guess that
+    in a browser that is "zoomed" on the results of a search, you are
+    likely to want the envelope data for each of those messages in
+    short order.  Prefetching reloads the c-client cache, saves
+    unnecessary RTTs, and avoids loading undesired envelopes due to
+    lookahead (see above).
+
+    The default is 20.
+
+    Setting it to 0 turns off prefetch.
+
+    There is no protection against setting this ridiculously high and
+    incurring performance penalties as a result.
+
+18) set close-on-error <number>
+    If non-zero, IMAP connections are closed if an EXAMINE or SELECT
+    command fails.  Otherwise, they are left half-open, and can be used
+    again to select some other mailbox.  The mailbox name in the stream
+    is set to {serverhost}<no_mailbox>
+
+    The default is zero (do not close on error).
+
+19) set imap-port <number>
+    Set the TCP/IP contact port to use for IMAP.  This overrides the
+    wired-in setting and the setting from /etc/services, and can in
+    turn be overridden by an explicit user specification in the mailbox
+    name, e.g. {serverhost:143}foo
+
+    The default is zero (use setting from /etc/services or the wired-in
+    setting (143).
+
+    There is no protection against setting this to a silly value, and
+    doing so is a great way to cause users extreme grief.
+
+20) set pop3-port <number>
+    Set the TCP/IP contact port to use for POP3.  This overrides the
+    wired-in setting and the setting from /etc/services, and can in
+    turn be overridden by an explicit user specification in the mailbox
+    name, e.g. {serverhost:110/pop3}
+
+    The default is zero (use setting from /etc/services or the wired-in
+    setting (110).
+
+    There is no protection against setting this to a silly value, and
+    doing so is a great way to cause users extreme grief.
+
+21) set uid-lookahead <number>
+    Sets the number of UIDs that are looked ahead in IMAP in mail_uid().
+    Lookahead preloads the c-client cache and saves unnecessary RTTs.
+
+    The default is 1000, small enough to usually have no significant
+    real-time difference from a single message UID fetch.
+
+    Setting it to 0 turns off lookahead.
+
+    There is no protection against setting this ridiculously high and
+    incurring performance penalties as a result.
+
+22) set mailbox-protection <number>
+    Set the default protection for newly-created mailbox files.
+
+    The default is 384.
+
+    There is no protection against setting this to a silly value, and
+    doing so is a great way to screw things up massively.
+
+23) set directory-protection <number>
+    Set the default protection for newly-created directories.
+
+    The default is 448.
+
+    There is no protection against setting this to a silly value, and
+    doing so is a great way to screw things up massively.
+
+24) set lock-protection <number>
+    Set the default protection for lock files
+
+    The default is 438, which is necessary if locks are to be respected
+    by processes running as other UIDs.
+
+    There is no protection against setting this to a silly value, and
+    contrary to what you may think just about any value other than 438
+    turns out to be a silly value.
+
+25) set disable-fcntl-locking <number>
+    This only applies to SVR4 systems.
+
+    If non-zero, fnctl() locking is not attempted.  In the past, this
+    was used to avoid locking NFS files.  If NFS is involved, the evil
+    lockd/statd daemons get invoked.  These daemons supposedly work over
+    NFS, but really don't.
+
+    You probably don't really want to do this, though, because now the
+    flock() emulator (which calls fcntl()) now checks to see if the file
+    is accessed via NFS and no-ops the lock.  This is compatible with
+    BSD.
+
+    Disabling fcntl() locking loses a great deal of locking protection
+    on local files as well as NFS files (which now never have locking
+    protection).
+
+    The default is zero (fcntl() locking is enabled).
+
+26) set lock-EACCES-error <number>
+    If non-zero, a warning message is given if an attempt to create a
+    lock file fails.  Otherwise, EACCES is treated as a "silent failure",
+    and it proceeds without trying to use the lock file.  This is for
+    the benefit of users on systems with paranoid /usr/spool/mail
+    protections which don't let users create /usr/spool/mail/$(USER).lock
+    files; these unfortunate users would be harassed with a flood of
+    error messages otherwise.  The problem is that on SVR4, if EACCES
+    remains disabled and fcntl() locking is also disabled, then there is
+    no locking at all which is doubleplus-ungood.
+
+    If the site is paranoid on /usr/spool/mail protections AND if there
+    is no fcntl() locking (SVR4) or usable flock() locking (e.g. NFS),
+    then there is no way to win.  Find a different system to use.
+
+    The default is non-zero (report EACCESS as an error).
+
+27) set list-maximum-level <number>
+    Sets the maximum depth of recursion that a * wildcard list will go
+    down the directory tree.  0 means that no recursion is permitted,
+    and * becomes like %.
+
+    The default is 20.
+
+    There is no protection against setting this to a ridiculously high
+    value.  Since LIST will follow symbolic links, it can effectively
+    recurse infinitely, until the name strings get large enough that
+    some name limit is exceeded.
+
+28) set anonymous-home-directory <directory name>
+   Sets the location of the anonymous home directory, if it is not in
+   the standard  place.
+
+   It is recommended to use a courtesy symbolic link instead.
+
+   There is no protection against setting this to a silly value, and
+   doing so is a great way to cause a crash.
+
+29) set chroot-server <number>
+   This option is for closed server systems only.  If defined, a chroot()
+   call to the user's home directory is done as part of the login
+   process.  This has the effect of preventing access to any files
+   outside of the user's home directory (including shared mailboxes).
+
+   Shared mailboxes with other users can't possibly work with this
+   option, because there is no way to export lock information to other
+   users.
+
+   This should be done ONLY on systems which do not permit users to
+   have shell access
+
+   This option should NEVER(!!) be set if users are allowed shell access.
+   Doing so actually makes the system *less* secure, since the user could
+   create an etc subdirectory which would be treated as real /etc by such
+   programs as /bin/su.
+
+   The default is zero (don't do chroot).
+
+   This option is strongly *NOT* recommended.
+
+30) set disable-automatic-shared-namespaces <number>
+   Never look up the "ftp", "imappublic", and "imapshared" users as
+   posssible home directories for the #ftp, #public, and #shared
+   namespaces.  On some systems (reportedly including AIX 4.3.3)
+   getpwnam() of an unknown user name is horrendously slow.
+
+   Note that this does not remove the #ftp, #public, and #shared
+   namespaces, and they can still be set up by other means.
+
+   The default is zero (shared namespaces are automatic).
+
+31) set advertise-the-world <number>
+   Include the UNIX root as a shared namespace.  This is generally a bad
+   idea, since certain IMAP clients (names withheld to protect the guilty)
+   will take this as license to download the entire filesystem tree.
+
+   The default is zero (don't advertise the world).
+
+32) set mail-subdirectory <subdirectory name>
+   Change the default connected directory from the user's home directory
+   to the named subdirectory of the user's home directory.  For example,
+   setting MAILSUBDIR="mail" will cause the POP2 and IMAP servers to
+   connect to the user's ~/mail subdirectory.  This is equivalent to
+   the env_unix.c edit described in Example 2 of the CONFIG file.
+
+   Note that if the subdirectory does not exist, the result is undefined.
+   It is probably an extremely bad idea to set this unless you can
+   guarantee that the subdirectory exists for all users.  If you can not
+   guarantee this, then you should leave the default as the user's home
+   directory and allow them to configure a personal default in their IMAP
+   client.
+
+   The default is not to use any subdirectory.
+
+33) set allow-user-config <number>
+   Allow users to use ~/.imaprc and ~/.mminit files.
+
+   The default is zero (don't allow user config files).
+
+34) set allow-reverse-dns <number>
+   By default, the servers (ipop[23]d and imapd) will do gethostbyaddr()
+   on the local and remote sockets so that imapd can identify itself
+   properly (this is important when the same CPU hosts multiple virtual
+   hosts on different IP addresss) and also includes the client's name
+   when it writes to the syslog.  There are also client gethostbyaddr()
+   calls, used primarily by authentication mechanisms.
+
+   Setting this option to zero disables all gethostbyaddr() calls.  The
+   returned "host name" string for the socket is just the bracketed
+   [12.34.56.78] form, as if the reverse DNS lookup failed.
+
+   WARNING: Some authentication mechanisms, e.g. Kerberos V, depend upon
+   the host names being right, and if you set this option, it won't work.
+
+   You should only do this if you are encountering server performance
+   problems due to a misconfigured DNS, e.g. long startup delays or
+   client timeouts.
+
+   The default is non-zero (allow reverse DNS).
+
+35) set disable-plaintext <number>
+   Disable plaintext password authentication (LOGIN command, AUTH=LOGIN,
+   and AUTH=PLAIN).
+
+   The default is zero (allow plaintext authentication).
+
+36) set trust-dns <number>
+   By default, host names are canonicalized via gethostbyname() for
+    everything except for SSL certificate validation.
+
+   This can represent a security bug due to DNS spoofing, but is more
+    likely to deliver results that users expect.  It also may be necessary
+    for SASL authentication to work right (e.g. generating a correct name
+    for a Kerberos service principal) if the name entered by the user is a
+    CNAME or not a fully-qualified domain name.
+
+   If trust-dns is set to zero, no host name canonicalization is done.
+    The user's actual entered name is used for SASL authentication and
+    will appear in the mailbox name of the open stream.
+
+   The default is non-zero (do DNS canonicalization).
+
+37) set sasl-uses-ptr-name <number>
+   By default, if trust-dns is set, the host names used in authentication
+    (e.g. to generate a Kerberos service principal) are canonicalized via
+    gethostbyaddr() instead of by gethostbyname().  If gethostbyaddr()
+    fails the gethostbyname() canonicalization is used.
+
+   This represents an additional security bug due to DNS spoofing, over and
+    above trust-dns.  It also adds an additional DNS query to starting a
+    session.
+
+   It is necessary for sites which implement a server cluster with multiple
+    A records for a cluster name (instead of a CNAME) but each cluster
+    member has a unique PTR record which it expects for a Kerberos service
+    principal.
+
+   If sasl-uses-ptr-name is set to zero and trust-dns is set non-zero, the
+    gethostbyname() canonicalized name is used for SASL authentication.
+
+   The setting of sasl-uses-ptr-name is irrelevant if trust-dns is set to
+    zero.
+
+   The default is non-zero (use name from PTR record for SASL).
+
+38) set network-filesystem-stat-bug <number>
+   By default, traditional UNIX mailbox files are only closed and reopened
+    at checkpoint and expunge time.  This ensures that, prior to rewriting
+    the file, that any cached stat() data from a network filesystem is
+    updated with current data.
+
+   Very old versions of NFS, and reputedly also AFS, can get into a state
+    in which the cached stat() data stays out-of-date, even across a
+    close and reopen of the file.
+
+   If network-filesystem-stat-bug is set non-zero, then the mailbox file
+    is closed and reopened at ping time as a workaround for this bug in
+    these network filesystems.  This means that in imapd, the mailbox
+    file is closed and reopened for every IMAP command.  This is obviously
+    something that should be avoided unless absolutely necessary.
+
+   NFS and AFS are terrible ways to distribute mail.  You use use IMAP
+    servers with a local disk instead.
+
+   The default is zero (only close/reopen at checkpoint and expunge time).
+
+   Setting this option is a great way to ruin your system's performance.
+
+39) set restrict-mailbox-access <option> <option> ... <option>
+   This option is for closed server systems only.  It is less extreme
+   than chroot-server, and allows selective restriction of what mailbox
+   named users can use.  The existing options are:
+    root	access not permitted to names starting with "/"
+    otherusers	access not permitted to other users' names; this should
+		 normally be used in conjunction with "root", otherwise
+		 another user's names can be accessed via a root name.
+    all		all of the above
+   Setting any combination of options also disables access to superior
+   directories via "..".
+
+   This should be done ONLY on systems which do not permit users to
+   have shell access
+
+   The default is no restrictions.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/internal.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,2988 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+	  Documentation of c-client Functions and Interfaces
+
+REVISED: 19 August 1996
+
+				  Credits
+
+     The original version of this document was written by Mark Crispin at
+the University of Washington, and described the version of c-client that
+supported the IMAP2 (RFC 1176) and IMAP2bis (unpublished) protocols.
+
+     This version is a substantial rewrite of that document, and was
+written by Mark Crispin with funding from Sun Microsystems, Incorporated.
+Sun's generous support of this work is gratefully acknowledged.
+
+
+				 Road Map
+
+     This document is organized into the following sections.  Except as
+noted, an implementor of an application that uses c-client needs to be
+familiar with all of these sections.  Someone who plans to write a new
+mailbox driver for c-client (or otherwise modify it) needs to be familiar
+with all sections, no exception.
+
+History
+	History of how c-client came about.
+
+Overview
+	Read this before designing an application that uses c-client.
+
+c-client Structures
+	Documentation of several important c-client structs which are
+	used in, and returned by, c-client calls.
+
+String Structures
+	Documentation of the concept of a "string structure", which
+	provides random access to strings without requiring that the
+	string be in memory.
+
+c-client Support Functions
+	Documentation of support functions for c-client; these deal
+	with c-client functionality.
+
+	Only mail_parameters() is of interest to most application
+	developers.  Advanced application developers, particularly
+	for limited memory systems, may also need to know about the
+	readfn_t, mailgets_t, mailcache_t, and tcptimeout_t function
+	pointer types, and possibly also the mail_valid_net_parse()
+	function.
+
+Mailbox Access Functions
+	Documentation of functions which deal with mailboxes;
+	listing, subscribing, creating, deleting, renaming, status
+	inquiries, opening, and closing mailboxes.
+
+Handle Functions
+	Documentation of mail stream handles, which provide protection
+	for an advanced application which may have multiple pointers to
+	a single mail stream.  If a stream has a handle on it, closing
+	the stream does not release its memory, so pointers to it in
+	the application remain valid.  Freeing the last handle will free
+	the entire stream.
+
+	This is only of interest for advanced application developers.
+
+Message Data Fetching Functions
+	Documentation on message data fetching in an open mailbox,
+	including parsed representations of RFC-822 and MIME headers
+	and message text.  Also how to fetch message attributes (flags,
+	internal date, sizes).
+
+Message Status Manipulation Functions
+	Documentation on altering message flags in an open mailbox.
+
+Mailbox Searching
+	Documentation on searching an open mailbox for messages which
+	match certain criteria (e.g. "messages sent July 4 from Jones
+	with text `Paris'").
+
+Miscellaneous Mailbox and Message Functions
+	Documentation on other operations that would be used by an
+	application but that don't fit into any of the above categories.
+
+Date/Time Handling Functions
+	Documentation on functions that deal with date/time strings.
+
+	This is only of interest for advanced application developers
+	and for implementors of new c-client drivers.
+
+Utility Functions
+	Documentation on internal utility functions.
+
+	This is primarily of interest for implementors of new c-client
+	drivers, but advanced application developers may also use some
+	of these functions.
+
+Data Structure Instantiation/Destruction functions
+	Documentation on creating and destroy c-client structures.
+
+	This is primarily of interest for implementors of new c-client
+	drivers.  However, application developers will need some of
+	these functions to create and destroy structures which are used
+	as arguments to various application functions.
+
+Authentication Functions
+	Documentation on support for network protocol authentication
+	functions.
+
+	This is only of interest for implementors of new c-client
+	drivers which deal with authentication mechanisms.
+
+Network Access Functions
+	Documentation on creating and destroy c-client structures.
+
+	This is primarily of interest for implementors of new c-client
+	drivers which deal with a network.  However, advanced
+	application developers may need to use this information if they
+	wish to insert their own layer into a network session.
+
+Subscription Management Functions
+	Documentation on managing the local (client-based) subscription
+	database file.
+
+	This is primarily of interest to advanced application developers.
+
+Miscellaneous Utility Functions
+	Documentation on various useful utility functions, such as "make
+	a copy of this string."
+
+SMTP Functions
+	Documentation on posting email messages via SMTP protocol.
+
+NNTP Functions
+	Documentation on posting netnews messages via NNTP protocol.
+
+RFC 822 Support Functions
+	Documentation on public RFC-822/MIME functions.
+
+	This is primarily of interest for implementors of new c-client
+	drivers and advanced application developers.
+
+Operating System-Dependent Public Interface
+	Documentation on OS-dependent functions.  With the exception of
+	fs_get(), fs_give(), and fs_resize(), which should be called
+	instead of malloc(), free(), and realloc(), these functions are
+	primarily of interest for implementors of new c-client drivers.
+
+Main Program Callbacks
+	Documentation of functions which the main program must provide
+	as callbacks from c-client.
+
+Driver Interface
+	Documentation of the driver dispatch vector and the functions
+	which a driver must supply.
+
+	This is primarily of interest for implementors of new c-client
+	drivers.
+
+Driver Support Functions
+	Documentation of support functions which are called by drivers.
+
+	This is primarily of interest for implementors of new c-client
+	drivers.
+				  History
+
+     The c-client API was originally written by Mark Crispin at Stanford
+University as a set of routines to support IMAP and SMTP from a main
+program which would handle the user interface.  In its original form, it
+was written as the low-level routines that were to be used as part of a
+Macintosh client.
+
+     The first IMAP client, MM-D (for "MM on Xerox D machines" -- MM was a
+popular DEC-20 mail program) was written in Interlisp for Xerox Lisp
+machines.  At that time, there was no name for the embryonic Mac client,
+but since it was the first one to be written in C instead of Lisp, it was
+given a development name of "C client".  This name became "c-client"
+because that is the name of the subdirectory on UNIX where the source files
+were stored.
+
+     To exercise the routines, a minimal main program which uses c-client,
+mtest, was written.  mtest has subsequently been extended so that it runs
+on every platform that c-client is ported.
+
+     The real Mac client, was eventually written by Frank Gilmurrary and
+Bill Yeager at Stanford using the autumn 1988 version of c-client and named
+"MacMS".  In the winter of 1988-89, Mark Crispin, who had changed jobs to
+the University of Washington, developed MS as an MM-like text-based program
+for UNIX and MailManager as a GUI-based program for NeXT machines.
+
+     The realization sunk in that this API needed its own name.  As early
+as spring 1989, there were at least four programs (mtest, MS, MailManager,
+and MacMS) that used it.  The name c-client thus became permanent.
+
+     In its history, c-client has undergone two major redesigns, both by
+Mark Crispin who is now on the staff at the University of Washington.
+
+     The first major redesign added the following:
+	1) ANSI C calling conventions throughout to assist in function
+	   argument type checking.
+	2) Vectoring mail access calls through "driver" methods; thus
+	   providing transparent access to multiple types of mail
+	   stores with the same call.
+	3) MIME support.
+
+     The second major redesign was part of the IMAP4 project.  Many
+c-client functions were extended with additional arguments and options.
+The driver interface was also made simpler, with more work done by
+driver-independent code.
+
+			       Overview
+
+     The most important file for the author of an application using the
+c-client is mail.h.  mail.h defines several important structures of
+data which are passed between the main program and the c-client.
+Although some functions (e.g. mail_fetchtext_body()) return the data
+fetched, for certain other data items (e.g. flags) you need to get the
+data as a structure reference.  mail.h also defines a large number of
+useful constants and structures.
+
+     When a function in mail.h exists to reference data, it MUST be
+used instead of referencing the structures directly.  This is because
+in some cases the data is not actually fetched until a reference (via
+the function call) is made.  For example, although the MESSAGECACHE
+element for a message can be obtained by indexing the proper cache
+element in the stream, there is no guarantee that the item in fact
+exists unless mail_fetchstructure_full() is called for that message.
+Less costly functions. also exist to create and load a MESSAGECACHE
+element.
+
+     The main program will probably also need to include smtp.h,
+misc.h, and osdep.h, but this usage should be solely to receive
+function prototypes.  Any other definitions in those files should be
+considered private to that module.
+
+     Two important predefined symbols are NIL and T.  NIL is any sort
+of "false"; T is any sort of "true".  NIL is also used to null-specify
+certain optional arguments.
+
+			* * * IMPORTANT * * *
+
+     Any multi-threaded application should test stream->lock prior to
+calling any c-client stream functions.  Any attempt to call a
+mail_xxx() function while one is already in progress on the same
+stream will cause the application to fail in unpredictable ways.
+
+     Note that this check is insufficient in a preemptive-scheduling
+multi-tasking application due to the possibility of a timing race.
+Such applications must be written so that only one process accesses
+the stream, or to have a higher level lock.
+
+     Since MAIL operations will not finish until they are completed, a
+single-tasking application does not have to worry about this problem,
+except in the callback invoked from MAIL (e.g. mm_exists(), etc.) in which
+case the stream is *always* locked.
+
+			  c-client Structures
+
+     c-client has a large number of structures which are used for
+multiple functions.  The most important of these are described here.
+
+     The MAILSTREAM structure is used to reference open mailboxes.
+Applications may reference the following:
+
+char *mailbox;			mailbox name
+unsigned short use;		stream use count, this is incremented
+unsigned short sequence;	stream sequence, this is incremented
+				 each time a stream is reused (i.e.
+				 mail_open() is called to open a
+				 different mailbox on this stream)
+unsigned int rdonly : 1;	stream is open read-only
+unsigned int anonymous : 1;	stream is open with anonymous access
+unsigned int halfopen : 1;	stream is half-open; it can be
+				 reopened or used for functions that
+				 don't need a open mailbox such as
+				 mail_create() but no message data
+				 can be fetched
+unsigned int perm_seen : 1;	Seen flag can be set permanently
+unsigned int perm_deleted : 1;	Deleted flag can be set permanently
+unsigned int perm_flagged : 1;	Flagged flag can be set permanently
+unsigned int perm_answered :1;	Answered flag can be set permanently
+unsigned int perm_draft : 1;	Draft flag can be set permanently
+unsigned int kwd_create : 1;	new user flags can be created by
+				 referencing then in mail_setflag() or
+				 mail_clearflag().  Note: this can
+				 change during a session (e.g. if
+				 there is a limit on the number of
+				 keywords), so check after creating a
+				 new flag to see if any more can be
+				 created before letting the user try
+				 to do so
+unsigned long perm_user_flags;	corresponding user flags can be set
+				 permanently.  This is a bit mask
+				 which matches the entries in
+				 stream->user_flags[]
+unsigned long gensym;		generated unique value.  Always
+				 referenced with stream->gensys++
+unsigned long nmsgs;		number of messages in current mailbox
+unsigned long recent;		number of recent messages in current
+				 mailbox
+unsigned long uid_validity;	UID validity value; this is used to
+				 verify that recorded UIDs match the
+				 UIDs that the stream has.  If the
+				 mailbox does not have matching UIDs
+				 (e.g. the UIDs were lost or not
+				 recorded) then the UID validity value
+				 will be different
+unsigned long uid_last;		highest currently assigned UID in the
+				 current mailbox; a new UID will be
+				 assigned with ++stream->uid_last
+char *user_flags[NUSERFLAGS];	pointers to user flag names in bit
+				 order from stream->perm_user_flags or
+				 elt->user_flags
+
+     The following MAILSTREAM values are only used internally:
+
+DRIVER *dtb;			dispatch table for this driver
+void *local;			pointer to driver local data
+unsigned int lock : 1;		stream lock flag (an operation is in
+				 progress; used as a bug trap to
+				 detect recursion back to c-client
+				 from callback routines).
+unsigned int debug : 1;		debugging information should be logged
+				 via mm_dlog().
+unsigned int silent : 1;	don't do main program callbacks on
+				 this stream (used when a stream is
+				 opened internally)
+unsigned int scache : 1;	short caching; don't cache information
+				 in memory
+
+     The following MAILSTREAM values are only used by the cache
+manager routine (see the documentation about mailcache_t above):
+
+unsigned long cachesize;	size of c-client message cache
+union {
+  void **c;			to get at the cache in general
+  MESSAGECACHE **s;		message cache array
+  LONGCACHE **l;		long cache array
+} cache;
+
+     The following MAILSTREAM values are for the convenience of
+drivers that use short caching and want to be able to garbage collect
+any values that they returned:
+
+unsigned long msgno;		message number of `current' message
+ENVELOPE *env;			pointer to `current' message envelope
+BODY *body;			pointer to `current' message body
+char *text;			pointer to `current' text
+
+
+     The MESSAGECACHE structure (commonly called an "elt" as a
+nickname for "cache ELemenT") contains information about messages.
+Applications may use the following:
+
+unsigned long msgno;		message number.  If the elt is locked
+				 (by elt->lockcount++), then the elt
+				 pointer can be stored (e.g. with the
+				 data for a window which draws this
+				 message) and elt->msgno will change
+				 automatically whenever expunges are
+				 done so the window will always view
+				 the correct message.  If elt->msgno
+				 becomes 0, then the message has been
+				 expunged, but the elt won't be freed
+				 until the elt lock count is
+				 decremented (by mail_free_elt()).
+unsigned long uid;		message unique ID
+unsigned int hours: 5;		internal date hours (0-23)
+unsigned int minutes: 6;	internal date minutes (0-59)
+unsigned int seconds: 6;	internal date seconds (0-59)
+unsigned int zoccident : 1;	non-zero if internal date time zone is
+				 west of UTC
+unsigned int zhours : 4;	internal date time zone hours from UTC
+				 (0-12)
+unsigned int zminutes: 6;	internal date time zone minutes (0-59)
+unsigned int seen : 1;		message Seen flag
+unsigned int deleted : 1;	message Deleted flag
+unsigned int flagged : 1; 	message Flagged flag
+unsigned int answered : 1;	message Answered glag
+unsigned int draft : 1;		message Draft flag
+unsigned int valid : 1;		flags are valid in this elt; an elt
+				 that was newly created but never
+				 loaded with flags won't have this set.
+unsigned int recent : 1;	message recent flag
+unsigned int searched : 1;	message matches search criteria in
+				 most recent mail_search_full() call
+unsigned int spare : 1;		reserved for application use
+unsigned int spare2 : 1;	reserved for application use
+unsigned int spare3 : 1;	reserved for application use
+unsigned int lockcount : 8;	non-zero if multiple references to
+				 this elt.  Refer to the msgno member
+				 for more information.
+unsigned int day : 5;		internal date day of month (1-31)
+unsigned int month : 4;		internal date month of year (1-12)
+unsigned int year : 7;		internal date year since BASEYEAR
+				 (currently 1970; was 1969 in older
+				 versions so use BASEYEAR instead of
+				 having the base year wired in)
+unsigned long user_flags;	message user flags; this is a bit mask
+				 which matches the entries in
+				 stream->user_flags[]
+unsigned long rfc822_size;	size of message in octets
+
+     The following MESSAGECACHE values are only used internally by
+drivers:
+
+unsigned int sequence : 1;	message is in sequence from either
+				 mail_sequence() or mail_uid_sequence()
+unsigned long data1;		first data item
+unsigned long data2;		second data item
+unsigned long data3;		third data item
+unsigned long data4;		fourth data item
+
+
+     The ADDRESS structure is a parsed form of a linked list of RFC 822
+addresses.  It contains the following information:
+
+char *personal;			personal name phrase
+char *adl;			at-domain-list (also called "source
+				 route")
+char *mailbox;			mailbox name
+char *host;			domain name of mailbox's host
+char *error;			error in address from smtp_mail(); if
+				 an error is returned from smtp_mail()
+				 for one of the recipient addresses
+				 the SMTP server's error text for that
+				 recipient can be found here.  If it
+				 is null then there was no error (or
+				 an error was found with a prior
+				 recipient
+ADDRESS *next;			pointer to next address in list
+
+
+     The ENVELOPE structure is a parsed form of the RFC 822 header.
+Its member names correspond to the RFC 822 field names.  It contains
+the following information:
+
+char *remail;			remail header if any
+ADDRESS *return_path;		error return address
+char *date;			message composition date string
+ADDRESS *from;			from address list
+ADDRESS *sender;		sender address list
+ADDRESS *reply_to;		reply address list
+char *subject;			message subject string
+ADDRESS *to;			primary recipient list
+ADDRESS *cc;			secondary recipient list
+ADDRESS *bcc;			blind secondary recipient list
+char *in_reply_to;		replied message ID
+char *message_id;		message ID
+char *newsgroups;		USENET newsgroups
+char *followup_to;		USENET reply newsgroups
+char *references;		USENET references
+
+
+     The BODY structure is a parsed form of a linked list of the MIME
+structure of a message.  It contains the following information.
+
+unsigned short type;		body primary type code.  This is an
+				 index into the body_types vector of
+				 body type names.  The following body
+				 types are pre-defined:
+	TYPETEXT		unformatted text
+	TYPEMULTIPART		multiple part
+	TYPEMESSAGE		encapsulated message
+	TYPEAPPLICATION		application data
+	TYPEAUDIO		audio
+	TYPEIMAGE		static image (GIF, JPEG, etc.)
+	TYPEVIDEO		video
+	TYPEOTHER		unknown
+				Additional types up to TYPEMAX are
+				 dynamically defined if they are
+				 encountered by c-client.
+unsigned short encoding;	body transfer encoding.  This is an
+				 index into the body_encodings vector
+				 of body encoding names.  The
+				 following body encodings are
+				 pre-defined:
+	ENC7BIT			7 bit SMTP semantic data
+	ENC8BIT			8 bit SMTP semantic data
+	ENCBINARY		8 bit binary data
+	ENCBASE64		base-64 encoded data
+	ENCQUOTEDPRINTABLE	human-readable 8-as-7 bit data
+	ENCOTHER		unknown
+				Additional encodings up to ENCMAX are
+				 dynamically defined if they are
+				 encountered by c-client.
+char *subtype;			body subtype string
+PARAMETER *parameter;		parameter list
+char *id;			body content identifier
+char *description;		body content description
+unsigned char *contents.text;	when composing a message that is NOT
+				 of TYPEMULTIPART, non-binary text of
+				 the content is stored here.  Note that
+				 this happens even when the text is
+				 of TYPEMESSAGE.  Text of encoding
+				 ENC8BIT may be converted to
+				 ENCQUOTEDPRINTABLE when it is sent.
+				 This should not be referenced for any
+				 other reason; in particular, this is
+				 NOT the way for an application to
+				 access content data (use
+				 mail_fetchbody_full() instead).
+BINARY *contents.binary;	when composing a message that is NOT
+				 of TYPEMULTIPART, binary content (of
+				 encoding ENCBINARY) is stored here.
+				 It will be converted to ENCBASE64 when
+				 it is sent.
+				 This should not be referenced for any
+				 other reason; in particular, this is
+				 NOT the way for an application to
+				 access content data (use
+				 mail_fetchbody_full() instead).
+PART *contents.part;		for body parts of TYPEMULTIPART, this
+				 contains the list of body parts in
+				 this multipart
+MESSAGE contents.msg;		for body parts of TYPEMESSAGE with
+				 subtype "RFC822", this contains the
+				 encapsulated message
+unsigned long size.lines;	size in lines
+unsigned long size.bytes;	size in octets.  This MUST be set when
+				composing a message if the encoding is
+				ENC8BIT or ENCBINARY.
+char *md5;			body content MD5 checksum
+
+     The following BODY information is used only by c-client
+internally.  The use of this data is driver-specific and it can not be
+relied-upon by applications.
+
+unsigned char *contents.text;	drivers can store a pointer to the
+				 body contents as text here.		
+unsigned long size.ibytes;	internal size of the body content (prior
+				 to newline conversion, etc.) in octets
+
+
+     The MESSAGE structure is a parsed form of a MESSAGE/RFC822 MIME
+body part.  It contains the following information:
+
+ENVELOPE *env;			encapsulated message RFC 822 header
+BODY *body;			encapsulated message MIME structure
+
+     The following MESSAGE information is used only by c-client
+internally.  The use of this data is driver-specific and it can not be
+relied-upon by applications.
+
+char *hdr;			encapsulated message header
+unsigned long hdrsize;		message header size
+char *text;			message in RFC 822 form
+unsigned long offset;		offset of text from header
+
+
+     The PARAMETER structure is a parsed form of a linked list of
+attribute/value pairs.  It contains the following information:
+
+char *attribute;		attribute name
+char *value;			value
+PARAMETER *next;		next parameter in list
+
+
+     The PART structure is a parsed form of a linked list of MIME body
+parts.  It contains the following information:
+
+BODY body;			body information for this part
+PART *next;			next body part
+
+     The following PART information is used only by c-client
+internally.  The use of this data is driver-specific and it can not be
+relied-upon by applications.
+
+unsigned long offset;		offset from body origin
+
+
+    The NETMBX structure is a parsed form of a network mailbox name:
+
+char host[NETMAXHOST];		remote host name
+char user[NETMAXUSER];		remote user name if specified
+char mailbox[NETMAXMBX];	remote mailbox name
+char service[NETMAXSRV];	remote service name (IMAP4, NNTP, etc.)
+unsigned long port;		TCP/IP port number if specified
+unsigned int anoflag : 1;	anonymous access requested
+unsigned int dbgflag : 1;	protocol debugging telemetry, via
+				 mm_dlog(), requested
+
+
+     The STRINGLIST structure is a list of strings (which may have
+embedded NULs) and their lengths:
+
+char *text;			string text
+unsigned long size;		string length
+STRINGLIST *next;		next string in list
+
+			  String Structures
+
+     A string structure is analogous to a char*, and is used in some
+functions as an input argument.  It represents a string of data in a
+way that does not necessarily require the entire string to be in
+memory at once.  This is essential for small machines with
+highly-restricted memory limits (e.g. DOS).
+
+		       String Structure Access
+
+     To use a string structure, the caller needs to know a string
+driver and needs to know the driver-dependent data used by that string
+structure.  A simple string driver is mail_string, a string driver
+that takes an in-memory char* string as the driver-dependent data.
+The DOS port uses string drivers that take a struct holding a file
+descriptor and a file offset.  Often the user of a string driver is
+the same module that defined it, so usually the programmer knows about
+its conventions.
+
+     The following calls are used to access a string structure:
+
+void INIT (STRING *s,STRINGDRIVER *d,void *data,unsigned long size);
+	s	pointer to the string structure to be initialized
+	d	pointer to the string driver
+	data	pointer to driver-dependent data, from which the
+		 driver can determine string data
+	size	size of the string
+ This call initializes the string stucture.
+
+
+unsigned long SIZE (STRING *s);
+	s	pointer to the string structure
+ This call returns the number of characters remaining in the string
+after the current string character pointer.
+
+
+char CHR (STRING *s);
+	s	pointer to the string structure
+ This call returns the character at the current string character
+pointer.
+
+
+char SNX (STRING *s);
+	s	pointer to the string structure
+ This call returns the character at the current string character
+pointer, and increments the string character pointer.
+
+
+unsigned long GETPOS (STRING *s);
+	s	pointer to the string structure
+ This returns the value of the current string character pointer.
+
+
+void SETPOS (STRING *s,unsigned long i);
+	s	pointer to the string structure
+	i	new string pointer value
+ This method sets the string character pointer to the given value.
+
+
+		      String Structure Internals
+
+     A string structure holds the following data:
+
+void *data;		used by the string driver as it likes
+unsigned long data1;	used by the string driver as it likes
+unsigned long size;	static, holds the total length of the string
+			 from the INIT call
+char *chunk;		current chunk of in-memory data; this is used
+			 for buffering to avoid unnecessary calls to
+			 the string driver's next method.
+unsigned long chunksize; size of an in-memory data chunk
+unsigned long offset;	position of first character of the chunk in
+			 the overall string
+char *curpos;		current position; this is what CHR() will
+			 access
+unsigned long cursize;	number of characters remaining in the current
+			 string
+STRINGDRIVER *dtb;	the string driver for this string structure
+
+
+     A string structure is manipulated by a string driver, which has
+the following access methods:
+
+void (*init) (STRING *s,void *data,unsigned long size);
+	s	pointer to the string structure to be initialized
+	data	pointer to driver-dependent data, from which the
+		 driver can determine string data
+	size	size of the string
+ This method initializes the string stucture.  It can use the data,
+data1, and chunksize values as it likes.  The remaining values must be
+set up as follows:
+	size		static, copied from the size argument
+	chunk		pointer to a buffer loaded with initial data
+	chunksize	size of the buffer
+	offset		0
+	curpos		copied from chunk
+	cursize		copied from chunksize
+	dtb		STRINGDRIVER identity pointer
+
+
+char (*next) (STRING *s);
+	s	pointer to the string structure
+ This method returns the character at the current string character
+pointer, and increments the string character pointer.  This method
+is likely to call the setpos method if the desired character is not in
+the current chunk.
+
+
+void (*setpos) (STRING *s,unsigned long i);
+	s	pointer to the string structure
+	i	new string pointer value
+ This method sets the string character pointer to the given value.  If
+the pointer is not in the current chunk, then a new chunk is loaded
+and the associated values (chunk, offset, curpos, cursize) are
+adjusted accordingly.
+
+		      c-client Support Functions
+
+
+void mail_string_init (STRING *s,void *data,unsigned long size);
+char mail_string_next (STRING *s);
+void mail_string_setpos (STRING *s,unsigned long i);
+
+     These three functions are the init, next, and setpos string
+structure access methods for the build-in mail_string string driver.
+mail_string is a basic string driver for a char* string.  See the
+documentation below on "String Structures" for more information.
+
+
+void mail_link (DRIVER *driver);
+	driver	pointer to the driver to be added
+
+     This function adds the specified driver to the list of mailbox
+drivers.  Initially there are no drivers lunk, so all programs which
+intend to use c-client need to have at least one call to this function.
+
+     A function which uses IMAP4 would have a statement such as:
+	mail_link (&imapdriver);	/* link in IMAP driver */
+early in the program's initialization.  Normally, this is done by the
+statement
+	#include "linkage.c"
+which will include the "system standard driver linkage" defined when
+c-client was built.  By using linkage.c instead of explicit mail_link()
+calls, you are guaranteed that you will have a consistant linkage among
+all software built on this system.
+
+
+void auth_link (AUTHENTICATOR *auth);
+	auth	pointer to the authenticator to be added
+
+     This function adds the specified authenticator to the list of
+authenticators.  Initially there are no authenticators lunk.  Normally,
+this is done by linkage.c so you don't need to call this routine
+explicitly.
+
+
+void *mail_parameters (MAILSTREAM *stream,long function,void *value);
+	stream	stream to poll or NIL
+	function function code
+	value	new value for function codes that change a parameter
+
+     This function fetches or changes the settings of various c-client
+operational parameters depending upon the function.  If the stream is
+specified, only the action for the underlying driver for that stream is
+taken; however, the scope of the operational parameters is global so
+there is generally no reason for the stream argument ever to be
+non-NIL.
+
+     The function codes ENABLE_DRIVER and DISABLE_DRIVER take a driver
+pointer as a value.  These functions enable and disable mailbox
+processing by that driver.  By default, all drivers are enabled.
+
+     The remaining function codes are in a pair named GET_xxx to
+fetch an operational parameter and SET_xxx to set the parameter:
+
+ GET_DRIVERS / SET_DRIVERS
+	 The list of currently lunk drivers.
+
+ GET_GETS / SET_GETS
+	 If non-NIL, points to a function for reading message text.
+	Defaults to NIL.
+	 This function is called with three arguments; a function
+	pointer to a "reading function", a stream for the reading
+	function, and a size in octets.  The reading function is
+	in turn called with the stream, a size in octets, and a
+	pointer to a readin buffer.
+	 This function returns with a char* string, which will be
+	returned by the mail_fetchheader(), mail_fetchtext(), or
+	mail_fetchbody() function which triggered the message text
+	reading.
+	 The purpose is to permit reading of large strings, without
+	requiring an in-memory buffer for the entire string.  The idea
+	is that this function can store the data in some form other
+	than a char* (e.g. a temporary file) and the main program will
+	recognize that it should get the text from there instead of
+	from the results from mail_fetch....().
+	 This is only supported on DOS and Win16; on other platforms it
+	is inconsistent whether or not it works.
+
+ GET_CACHE / SET_CACHE
+	 Points to the c-client cache manager function.  Defaults to
+	mm_cache().
+
+ GET_SMTPVERBOSE / SET_SMTPVERBOSE
+	 If non-NIL, points to a function that accepts a char* string.
+	This function is called any time the SMTP routines receive a
+	response code less than 100.  The argument is the text of the
+	response code
+
+ GET_RFC822OUTPUT / SET_RFC822OUTPUT
+	 If non-NIL, points to an alternate rfc822_output() function.
+	rfc822_output() will call this function and return instead of
+	doing its normal action.  See the description of
+	rfc822_output() for more information.	
+
+ GET_USERNAME / SET_USERNAME
+	 The logged-in user name.
+
+ GET_HOMEDIR / SET_HOMEDIR
+	 The home directory path name.
+
+ GET_LOCALHOST / SET_LOCALHOST
+	 The local host name.
+
+ GET_SYSINBOX / SET_SYSINBOX
+	 The "system INBOX" (where mail is delivered) path name.
+
+ GET_OPENTIMEOUT / SET_OPENTIMEOUT
+	 TCP/IP open timeout in seconds.  Defaults to 0 (system
+	default timeout, usually 75 seconds on Unix).
+	
+ GET_READTIMEOUT / SET_READTIMEOUT
+	 TCP/IP read timeout in seconds.  Defaults to 0 (no timeout).
+
+ GET_WRITETIMEOUT / SET_WRITETIMEOUT
+	 TCP/IP write timeout in seconds.  Defaults to 0 (no timeout).
+
+ GET_CLOSETIMEOUT / SET_CLOSETIMEOUT
+	 TCP/IP close timeout in seconds.  Defaults to 0 (no timeout).
+
+ GET_TIMEOUT / SET_TIMEOUT
+	 If non-NIL, points to the function called when a TCP/IP
+	timeout occurs.  This function is called with the number of
+	seconds since the start of the TCP operation.  If it returns
+	non-zero, the TCP/IP operation is continued; if it returns
+	non-zero, the TCP/IP connection is aborted.
+
+ GET_RSHTIMEOUT / SET_RSHTIMEOUT
+	 rsh connection timeout in seconds.  Defaults to 15 seconds.
+
+ GET_MAXLOGINTRIALS / SET_MAXLOGINTRIALS
+	 The maximum number of login attempts permitted in an IMAP or
+	POP connection.  Defaults to 3.
+
+ GET_LOOKAHEAD / SET_LOOKAHEAD
+	 The number of subsequent envelopes prefetched in IMAP when an
+	envelope is fetched.  Defaults to 20.
+
+ GET_IMAPPORT / SET_IMAPPORT
+	 The IMAP port number.  Defaults to 143.
+
+ GET_PREFETCH / SET_PREFETCH
+	 The number of envelopes prefetched in IMAP from the results
+	of a SEARCH.  Defaults to 20.
+
+ GET_CLOSEONERROR / SET_CLOSEONERROR
+	 If non-NIL, close an opening IMAP connection if the SELECT
+	command fails instead of returning a half-open stream.
+	Defaults to NIL.
+
+ GET_POP3PORT / SET_POP3PORT
+	 The POP3 port number.  Defaults to 110.
+
+ GET_UIDLOOKAHEAD / SET_UIDLOOKAHEAD
+	 The number of UIDs premapped when a message number is
+	translated to a UID.  Defaults to 1000.
+
+ GET_MBXPROTECTION / SET_MBXPROTECTION
+	 Default file protection for newly created mailboxes.
+	Defaults to 0600.
+
+ GET_DIRPROTECTION / SET_DIRPROTECTION
+	 Default file protection for newly created directories.
+	Defaults to 0700.
+
+ GET_LOCKPROTECTION / SET_LOCKPROTECTION
+	 Default file protection for locks.  Defaults to 0666.
+	WARNING: don't blithely change this.  If other processes
+	can't get access to a lock then they will have trouble in
+	locking properly.
+
+ GET_FROMWIDGET / SET_FROMWIDGET
+	 If non-NIL, APPEND in the Unix mbox format will insert a
+	">" character in front of all lines which begin with the
+	string "From ".  If NIL, it will only do so if the entire
+	line looks like a message delimiter (that is, the date is
+	also in correct format).  Defaults to T.
+
+ GET_NEWSACTIVE / SET_NEWSACTIVE
+	 Netnews active file path name.
+
+ GET_NEWSSPOOL / SET_NEWSSPOOL
+	 Netnews spool directory path name.
+
+ GET_NEWSRC / SET_NEWSRC
+	 Netnews newsgroup reading status file (.newsrc) path name.
+
+ GET_EXTENSION / SET_EXTENSION
+	 If non-NIL, points to a string holding the extension for all
+	mailbox files.  This is only supported on DOS and Win16.
+
+ GET_DISABLEFCNTLLOCK / SET_DISABLEFCNTLLOCK
+	 If non-NIL, disables fcntl() locking on SVR4.  This is done
+	if fcntl() tends to hang for no good reason.  Now that the
+	fcntl() code checks for NFS files and no-ops the locking,
+	this problem usually doesn't happen much any more.  Defaults
+	to NIL.
+
+ GET_LOCKEACCESERROR / SET_LOCKEACCESERROR
+	 If non-NIL, give a warning if an attempt to create a .lock
+	file gets an EACCES ("Permission denied") error.  This usually
+	means that somebody protected the system inbox directory (e.g.
+	/var/mail) instead of making it public-write with the sticky
+	bit.  Defaults to non-NIL, since this is usually bad news.
+
+ GET_LISTMAXLEVEL / SET_LISTMAXLEVEL
+	 The maximum depth of recusion that LIST will go on a *
+	wildcard.  Defaults to 20.
+
+ GET_ANONYMOUSHOME / SET_ANONYMOUSHOME
+	 The anonymous use home directory name.
+
+
+typedef long (*readfn_t) (void *stream,unsigned long size,char *buffer);
+	stream	a designator suitable
+	size	a number of octets to read
+	buffer	a buffer of at least size octets for readin
+
+     This function reads the given number of octets into the buffer,
+using the given stream.  What sort of object the stream is depends upon
+the function and its caller, so you must make sure that the readfn is
+suitable for the caller's purpose.  Common uses include support of the
+mailgets function (see below) and of reading from local files on systems
+with limited address space.
+
+
+typedef char *(*mailgets_t) (readfn_t f,void *stream,unsigned long size);
+	f	the readfn to use
+	stream	stream argument for the readfn
+	size	total number of octets to read
+
+     This is the argument to the SET_GETS mail_parameter() call.  This
+function must read size octets from the stream, using the readfn f.  It
+may call f multiple times to accomplish this; this will read the data in
+a serial fashion.  So, for example, if size is a megabyte and there is
+only 4K of available buffer space, it can call f 256 times to satisfy
+the request.  There is no way to back up in the reading, so any
+processing or saving of the data must be done when it is read.
+
+     The function mm_gets() in mail.c is a sample mailgets function; it
+reads the first MAXMESSAGESIZE of data into memory and discards the
+rest.
+
+
+typedef void *(*mailcache_t) (MAILSTREAM *stream,unsigned long msgno,long op);
+	stream	stream to cache manage
+	msgno	message to cache manage in the stream
+	op	cache management operation
+
+     This function manages the c-client cache.  Normally, a program will
+use the default c-client cache manager routine mm_cache().  However, a
+main program may want to supply its own cache manager, e.g. it may want
+to store the data on a disk file instead of in memory on DOS and Win16
+where memory is tight.
+
+     If you write your own cache manager, you need to examine the
+default mm_cache() manager closely, as well as paying close attention to
+what goes into an elt (a MESSAGECACHE element).  It is highly likely
+that if you roll elts out to disk, you will want to set stream->scache
+and *NOT* use long elts (because long elts have ENVELOPE and BODY
+pointers that you would have to know how to write to disk and read back).
+
+     The cache management functions are one of the following:
+
+ CH_INIT	 Initialize the entire cache for the stream.  This is
+		called only when creating a new stream or when freeing
+		it.  The msgno argument is ignored.
+
+ CH_SIZE	 Make sure that the cache is at least large enough to
+		support msgno.  This is a request to grow the cache if
+		necessary, not shrink it.
+
+ CH_MAKELELT	 Return a long elt for msgno, creating it if necessary.
+		This is the underlying support function for mail_lelt().
+
+ CH_LELT	 Return the long elt for msgno, or NIL if it does not
+		already exist.
+
+ CH_MAKEELT	 Return an elt for msgno, creating it if necessary.
+		This is the underlying support function for mail_elt().
+
+ CH_ELT		 Return the elt for msgno, or NIL if it does not already
+		exist.
+
+ CH_FREE	 Free the [l]elt for msgno.
+
+ CH_EXPUNGE	 Free the [l]elt for msgno, and reclaim its position.
+		All subsequent elts are renumbered with their elt->msgno
+		decremented by 1.  [Hence msgno+1 becomes msgno, etc.]
+		This supports message expunging from the cache.
+
+
+typedef long (*tcptimeout_t) (long time);
+	time	total time spent since TCP operation started
+
+     This function is called when a TCP operation times out.  It is set
+by the SET_TIMEOUT mail_parameter().  The function can return non-zero
+to continue the TCP operation (e.g. after outputting a "do you still
+want to wait" prompt) or zero if it wants the TCP operation to abort and
+close.  If the TCP operation aborts, it will likely cause the upper
+level IMAP, SMTP, etc. stream to abort and close as well.
+
+
+DRIVER *mail_valid (MAILSTREAM *stream,char *mailbox,char *purpose);
+	stream	if non-NIL, stream to use for validation
+	mailbox	mailbox name to validate
+	purpose	filled in as xxx in "Can't xxx" in error messages
+
+     This function validates the given mailbox name.  It successful, it
+returns the driver that can open that name if successful, otherwise it
+returns NIL.  If stream is non-NIL, the mailbox name must be valid for
+the type of mailbox associated with that stream (e.g. an NNTP name can
+not be used with an IMAP stream).  If purpose is non-NIL, an error
+message is passed via mm_log() when an error occurs.
+
+
+DRIVER *mail_valid_net (char *name,DRIVER *drv,char *host,char *mailbox);
+	name	mailbox name to validate
+	drv	driver name to validate against
+	host	buffer to return host name if non-NIL
+	mailbox	buffer to return remote mailbox name if non-NIL
+
+     This function is an alternative to mail_valid_net_parse().  It
+validates the given mailbox name as a network name and makes sure that
+its service name is the same as the driver in drv.  If successful, it
+returns drv, and copies the host and mailbox strings as needed.
+Otherwise it returns NIL.
+
+
+long mail_valid_net_parse (char *name,NETMBX *mb);
+	name	mailbox name to parse
+	mb	pointer to NETMBX structure to return
+
+     This function parses a network mailbox name.  If the name is a
+network mailbox name, it returns non-NIL, with the NETMBX structure
+loaded with the results form the parse.
+
+		       Mailbox Access Functions
+
+void mail_list (MAILSTREAM *stream,char *ref,char *pat);
+void mail_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+	stream	if non-NIL, stream to use
+	ref	mailbox reference string
+	pat	mailbox pattern string
+	contents contents to search
+
+     This function returns a list of mailboxes via the mm_list()
+callback.  The reference is applied to the pattern in an implementation
+dependent fashion, and the resulting string is used to search for
+matching mailbox names.  "*" is a wildcard which matches zero or more
+characters; "%" is a variant which does not descend a hierarchy level.
+Read the IMAP specification for more information.
+
+     mail_scan() is a variant which takes a string to search for in the
+text of the mailbox.  The string is a free-text string, without regard
+for message boundaries, and thus the choice of strings must be made
+with care.
+
+
+void mail_lsub (MAILSTREAM *stream,char *ref,char *pat);
+	stream	if non-NIL, stream to use
+	ref	mailbox reference string
+	pat	mailbox pattern string
+
+     This function returns a list of subscribed mailboxes via the
+mm_lsub() callback.  The reference is applied to the pattern in an
+implementation dependent fashion, and the resulting string is used to
+search for matching mailbox names in the subscription list.  "*" is a
+wildcard which matches zero or more characters; "%" is a variant which
+does not descend a hierarchy level.  Read the IMAP specification for
+more information.
+
+
+long mail_subscribe (MAILSTREAM *stream,char *mailbox);
+	stream	if non-NIL, stream to use
+	mailbox	mailbox name
+
+     This function adds the given name to the subscription list.  It
+returns T if successful, NIL if unsuccessful.  If unsuccessful, an
+error message is returned via the mm_log() callback.
+
+
+long mail_unsubscribe (MAILSTREAM *stream,char *mailbox);
+	stream	if non-NIL, stream to use
+	mailbox	mailbox name
+
+     This function removes the given name from the subscription list.
+It returns T if successful, NIL if unsuccessful.  If unsuccessful, an
+error message is returned via the mm_log() callback.
+
+
+long mail_create (MAILSTREAM *stream,char *mailbox);
+	stream	if non-NIL, stream to use
+	mailbox	mailbox name
+
+     This function creates a mailbox with the given name.  It returns T
+if successful, NIL if unsuccessful.  If unsuccessful, an error message
+is returned via the mm_log() callback.
+
+     It is an error to create INBOX or a mailbox name which already
+exists.
+
+
+long mail_delete (MAILSTREAM *stream,char *mailbox);
+	stream	if non-NIL, stream to use
+	mailbox	mailbox name
+
+     This function deletes the named mailbox.  It returns T if
+successful, NIL if unsuccessful.  If unsuccessful, an error message is
+returned via the mm_log() callback.
+
+     It is an error to delete INBOX or a mailbox name which does not
+already exist.
+
+
+long mail_rename (MAILSTREAM *stream,char *old,char *newname);
+	stream	if non-NIL, stream to use
+	old	existing mailbox name
+	newname	new (not yet existing) mailbox name
+
+     This function renames the old mailbox to the new mailbox name.
+It returns T if successful, NIL if unsuccessful.  If unsuccessful, an
+error message is returned via the mm_log() callback.
+
+     It is an error to reanme a mailbox that does not exist, or rename
+a mailbox to a name that already exists.  It is permitted to rename
+INBOX; a new empty INBOX is created in its place.
+
+
+long mail_status (MAILSTREAM *stream,char *mbx,long flags);
+	stream	if non-NIL, stream to use
+	mbx	mailbox name
+	flags	option flags
+
+     This function returns the status of the given mailbox name via the
+mm_status() callback.  It returns T if successful, NIL if unsuccessful.
+If unsuccessful, an error message is returned via the mm_log()
+callback.
+
+     The options are a bit mask with one or more of the following,
+indicating the data which should be returned.
+	SA_MESSAGES	number of messages in the mailbox
+	SA_RECENT	number of recent messages in the mailbox
+	SA_UNSEEN	number of unseen messages in the mailbox
+	SA_UIDNEXT	next UID value to be assigned
+	SA_UIDVALIDITY	UID validity value
+
+     Note that, depending upon implementation, some of these values may
+be more costly to get than others.  For example, calculating the
+number of unseen messages may require opening the mailbox and scanning
+all of the message flags.  A mail_status() call should thus be used
+with option flags specifying only the data that is actually needed.
+
+
+MAILSTREAM *mail_open (MAILSTREAM *oldstream,char *name,long options);
+	oldstream if non-NIL, stream to recycle
+	name	mailbox name to open
+	options	option flags.
+
+     This function opens the mailbox and if successful returns a stream
+suitable for use by the other MAIL functions.
+
+     If oldstream is non-NIL, an attempt is made to reuse oldstream as
+the stream for this mailbox; this is useful when you want to open
+another mailbox to the same IMAP or NNTP server without having to open
+a new connection.  Doing this will close the previously open mailbox.
+
+     The options are a bit mask with one or more of the following:
+	OP_DEBUG	Log IMAP protocol telemetry through mm_debug()
+	OP_READONLY	Open mailbox read-only.
+	OP_ANONYMOUS	Don't use or update a .newsrc file for news.
+	OP_SHORTCACHE	Don't cache envelopes or body structures
+	OP_SILENT	Don't pass mailbox events (internal use only)
+	OP_PROTOTYPE	Return the "prototype stream" for the driver
+			 associated with this mailbox instead of
+			 opening the stream
+	OP_HALFOPEN	For IMAP and NNTP names, open a connection
+			 to the server but don't open a mailbox.
+	OP_EXPUNGE	Silently expunge the oldstream before recycling
+
+ NIL is returned if this function fails for any reason.
+
+
+MAILSTREAM *mail_close (MAILSTREAM *stream);
+MAILSTREAM *mail_close_full (MAILSTREAM *stream,long options);
+	stream	stream to close
+	options	option flags
+     This function closes the MAIL stream and frees all resources
+associated with it that it may have created (subject to any handles
+existing).
+
+     The options for mail_close_full() are a bit mask with one or more
+of the following:
+	CL_EXPUNGE	Silently expunge before closing
+
+     This function always returns NIL, so it can be used as:
+	stream = mail_close (stream);
+
+			   Handle Functions
+
+     Handles are used when an entity that wishes to access the stream
+may survive the stream without knowing that it outlived it.  For
+example, an object reading a message may have a handle to a stream,
+but the message selection object that spawned it (and which owns the
+stream) may have gone away.  A stream can be closed or recycled while
+handles are pointing at it, but it is not completely freed until all
+handles are gone.  A stream may have an arbitrary number of handles.
+
+
+MAILHANDLE *mail_makehandle (MAILSTREAM *stream);
+	stream	stream to make handle to
+
+     This function creates and returns a handle to the stream.
+
+
+void mail_free_handle (MAILHANDLE **handle);
+	handle	pointer to handle to release
+
+     This function frees the handle and notifies the stream that it has
+one fewer handle.  If this is the last handle on the stream and the
+stream has been closed, then the stream is freed.
+
+
+MAILSTREAM *mail_stream (MAILHANDLE *handle);
+	handle	handle to look up
+
+     This function returns the stream associated with the handle if and
+only if the stream still represents the same MAIL connection associated
+with the handle.  Otherwise, NIL is returned (meaning that there is no
+active stream associated with this handle).
+
+		    Message Data Fetching Functions
+
+[Note!!  There is an important difference between a "sequence" and a
+ "msgno".  A sequence is a string representing one or more messages in
+ IMAP4-style sequence format ("n", "n:m", or combination of these
+ delimited by commas), whereas a msgno is an int representing a single
+ message.] 
+
+void mail_fetchfast (MAILSTREAM *stream,char *sequence);
+void mail_fetchfast_full (MAILSTREAM *stream,char *sequence,long flags);
+	stream	stream to fetch on
+	sequence IMAP-format set of message sequence numbers
+	flags	option flags
+
+     This function causes a cache load of all the "fast" information
+(internal date, RFC 822 size, and flags) for the given sequence.  Since
+all this information is also fetched by mail_fetchstructure(), this
+function is generally not used unless the OP_SHORTCACHE option in the
+mail_open() call is used.
+
+     The options for mail_fetchfast_full() are a bit mask with one or
+more of the following:
+	FT_UID		The sequence argument contains UIDs instead of
+			 sequence numbers
+
+
+void mail_fetchflags (MAILSTREAM *stream,char *sequence);
+void mail_fetchflags_full (MAILSTREAM *stream,char *sequence,long flags);
+
+     This function causes a fetch of the flags for the given sequence.
+This main reason for using this function is to update the flags in the
+local cache in case some other process changed the flags (multiple
+simultaneous write access is allowed to the flags) as part of a "check
+entire mailbox" (as opposed to "check for new messages") operation.
+
+ The options for mail_fetchflags_full() are a bit mask with one or more
+of the following:
+	FT_UID		The sequence argument contains UIDs instead of
+			 sequence numbers
+
+
+ENVELOPE *mail_fetchenvelope (MAILSTREAM *stream,unsigned long msgno);
+ENVELOPE *mail_fetchstructure (MAILSTREAM *stream,unsigned long msgno,
+			       BODY **body);
+ENVELOPE *mail_fetchstructure_full (MAILSTREAM *stream,unsigned long msgno,
+				    BODY **body,long flags);
+	stream	stream to fetch on
+	msgno	message sequence number
+	body	pointer to where to return BODY structure if non-NIL
+	flags	option flags
+     This function causes a fetch of all the structured information
+(envelope, internal date, RFC 822 size, flags, and body structure) for
+the given msgno and, in the case of IMAP, up to MAPLOOKAHEAD (a
+parameter in IMAP2.H) subsequent messages which are not yet in the
+cache.  No fetch is done if the envelope for the given msgno is already
+in the cache.  The ENVELOPE and the BODY for this msgno is returned.
+It is possible for the BODY to be NIL, in which case no information is
+available about the structure of the message body.
+
+     The options for mail_fetchstructure_full() are a bit mask with one
+or more of the following:
+	FT_UID		The msgno argument is a UID 
+
+     This is the primary function for fetching non-text information
+about messages, and should be called before any attempt to reference
+cache information about this message via mail_elt().
+
+
+char *mail_fetchheader (MAILSTREAM *stream,unsigned long msgno);
+char *mail_fetchheader_full (MAILSTREAM *stream,unsigned long msgno,
+			     STRINGLIST *lines,unsigned long *len,long flags);
+	stream	stream to fetch on
+	msgno	message sequence number
+	lines	list of header lines to fetch
+	len	returned length in octets
+	flags	option flags
+
+     This function causes a fetch of the complete, unfiltered RFC 822
+format header of the specified message as a text string and returns
+that text string.
+
+     If the lines argument is non-NIL, it contains a list of header
+field names to use in subsetting the header text.  Only those lines
+which have that header field name are returned, unless FT_NOT is set in
+which case only those lines which do not have that header field name
+are returned.
+
+     If the len argument is non-NIL, it holds a pointer in which the
+length of the string in octets is returned.  This is useful in cases
+where there may be an embedded null in the string.
+
+     This function always returns a valid string pointer; if no header
+exists or if it can not be fetched (e.g. by a deceased IMAP stream) an
+empty string is returned.
+
+     The options for mail_fetchheader_full() are a bit mask with one or
+more of the following:
+	FT_UID		The msgno argument is a UID 
+	FT_NOT		The returned header lines are those that are
+			 not in the lines argument
+	FT_INTERNAL	The return string is in "internal" format,
+			 without any attempt to canonicalize to CRLF
+			  newlines
+	FT_PREFETCHTEXT	The RFC822.TEXT should be pre-fetched at the
+			 same time.  This avoids an extra RTT on an
+			 IMAP connection if a full message text is
+			 desired (e.g. in a "save to local file"
+			 operation)
+		 
+
+char *mail_fetchtext (MAILSTREAM *stream,unsigned long msgno);
+char *mail_fetchtext_full (MAILSTREAM *stream,unsigned long msgno,
+			   unsigned long *len,long flags);
+	stream	stream to fetch on
+	msgno	message sequence number
+	len	returned length in octets
+	flags	option flags
+
+     This function causes a fetch of the non-header text of the
+specified message as a text string and returns that text string.  No
+attempt is made to segregate individual body parts.
+
+     If the len argument is non-NIL, it holds a pointer in which the
+length of the string in octets is returned.  This is useful in cases
+where there may be an embedded null in the string.
+
+     This function always returns a valid string pointer; if no header
+exists or if it can not be fetched (e.g. by a deceased IMAP stream) an
+empty string is returned.
+
+      The options for mail_fetchtext_full() are a bit mask with one or
+more of the following:
+	FT_UID		The msgno argument is a UID 
+	FT_PEEK		Do not set the \Seen flag if it not already set
+	FT_INTERNAL	The return string is in "internal" format,
+			 without any attempt to canonicalize to CRLF
+			  newlines
+
+
+char *mail_fetchbody (MAILSTREAM *stream,unsigned long msgno,char *sec,
+		      unsigned long *len);
+char *mail_fetchbody_full (MAILSTREAM *stream,unsigned long msgno,char *sec,
+			   unsigned long *len,long flags);
+	stream	stream to fetch on
+	msgno	message sequence number
+	sec	section specifier
+	len	returned length in octets
+	flags	option flags
+
+      This function causes a fetch of the particular section of the
+body of the specified message as a text string and returns that text
+string.  The section specification is a string of integers delimited by
+period which index into a body part list as per the IMAP4
+specification.  Body parts are not decoded by this function; see
+rfc822_base64() and rfc822_quotedprintable().
+
+     If the len argument is non-NIL, it holds a pointer in which the
+length of the string in octets is returned.  This is useful in cases
+where there may be an embedded null in the string.
+
+      This function may return NIL on error.
+
+      The options for mail_fetchbody_full() are a bit mask with one or
+more of the following:
+	FT_UID		The msgno argument is a UID 
+	FT_PEEK		Do not set the \Seen flag if it not already set
+	FT_INTERNAL	The return string is in "internal" format,
+			 without any attempt to canonicalize to CRLF
+			  newlines
+
+
+unsigned long mail_uid (MAILSTREAM *stream,unsigned long msgno);
+	stream	stream to fetch on
+	msgno	message sequence number
+
+      This function returns the UID for the given message sequence
+number.
+
+
+void mail_fetchfrom (char *s,MAILSTREAM *stream,unsigned long msgno,
+		     long length);
+	s	destination string
+	stream	stream to fetch on
+	msgno	message sequence number
+	length	maximum field length
+
+     This function writes a "from" string of the specified length for
+the specified message, suitable for display to the user in a menu line,
+into the string pointed to by s.
+
+      If the personal name of the first address in the envelope's from
+item is non-NIL, it is used; otherwise a string is created by appending
+the mailbox of the first address, an "@", and the host of the first
+address.  The string is trimmed or padded with trailing spaces as
+necessary to make its length match the length argument.
+
+
+void mail_fetchsubject (char *s,MAILSTREAM *stream,unsigned long msgno,
+			long length);
+	s	destination string
+	stream	stream to fetch on
+	msgno	message sequence number
+	length	maximum field length
+
+      This function returns a "subject" string of the specified length
+for the specified message, suitable for display to the user in a menu
+line.
+
+       The envelope's subject item is copied and trimmed as necessary
+to make its length be no more what the caller requested.  Unlike
+mail_fetchfrom(), this function can return a string of shorter length
+than what the caller requested.
+
+
+LONGCACHE *mail_lelt (MAILSTREAM *stream,unsigned long msgno);
+MESSAGECACHE *mail_elt (MAILSTREAM *stream,unsigned long msgno);
+	stream	stream to access
+	msgno	message sequence number
+
+     This function returns the cache entry for the specified message.
+Although it will create a cache entry if it does not already exist,
+that functionality is for internal use only.  This function should
+never be called without having first called mail_fetchfast() or
+mail_fetchstructure() on the message first.
+
+     A cache entry holds the internal date/time, flags, and RFC 822
+size of a message.  It holds other data as well, but that is for
+internal use only.
+
+     mail_lelt() is a variant that returns a `long' cache entry, which
+consists of an cache entry (as a structure, not a pointer), an envelope
+pointer, and a body pointer.  This is used in conjunction with the elt
+lock count functionality, to allow an application to associate the
+cached envelope and body of a message with an open window even if the
+message is subsequently expunged or if the stream is closed.
+
+     Unless your application wants to look at cached envelopes and
+bodies even after the message is expunged or the stream is closed, it
+should not use mail_lelt().  Instead, it should use a returned elt from
+mail_elt() and use the elt->msgsno as the argument to
+mail_fetchstructure().
+
+	BEWARE: the behavior of mail_lelt() is undefined if the
+	stream is open with OP_SHORTCACHE.  mail_lelt() is extremely
+	special purpose, and should only be used in sophisticated
+	special purpose applications after discussing its use with
+	the c-client author.  If you think you need this function,
+	you are probably mistaken.  In almost all cases, you should
+	use mail_elt() and mail_fetchstructure() instead.
+
+		 Message Status Manipulation Functions
+
+void mail_setflag (MAILSTREAM *stream,char *sequence,char *flag);
+void mail_setflag_full (MAILSTREAM *stream,char *sequence,char *flag,
+			long flags);
+	stream	stream to use
+	sequence IMAP-format set of message sequence numbers
+	flag	IMAP-format flag string
+	flags	option flags
+
+    This function causes a store to add the specified flag to the flags
+set for the messages in the specified sequence.  If there is any
+problem in setting flags, a message will be passed to the application
+via the mm_log() facility.
+
+     The options for mail_setflag_full() are a bit mask with one or
+more of the following:
+	ST_UID		The sequence argument contains UIDs instead of
+			 sequence numbers
+	ST_SILENT	Do not update the local cache with the new
+			 value of the flags.  This is useful to save
+			 network bandwidth, at the cost of invalidating
+			 the cache.
+
+
+void mail_clearflag (MAILSTREAM *stream,char *sequence,char *flag);
+void mail_clearflag_full (MAILSTREAM *stream,char *sequence,char *flag,
+			  long flags);
+	stream	stream to use
+	sequence IMAP-format set of message sequence numbers
+	flag	IMAP-format flag string
+	flags	option flags
+
+     This function causes a store to delete the specified flag from the
+flags set for the messages in the specified sequence.  If there is any
+problem in clearing flags, a message will be passed to the application
+via the mm_log() facility.
+
+     The options for mail_setflag_full() are a bit mask with one or
+more of the following:
+	ST_UID		The sequence argument contains UIDs instead of
+			 sequence numbers
+	ST_SILENT	Do not update the local cache with the new
+			 value of the flags.  This is useful to save
+			 network bandwidth, at the cost of invalidating
+			 the cache.
+
+			   Mailbox Searching
+
+void mail_search (MAILSTREAM *stream,char *criteria);
+void mail_search_full (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,
+		       long flags);
+	stream	stream to search
+	charset	MIME character set to use when searching strings
+	pgm	search program
+	flags	option flags
+
+     This function causes a mailbox search, using the given MIME
+charset (NIL means the default, US-ASCII) and the given search program.
+A search program is a structure that holds the following data:
+
+SEARCHSET *msgno;	a set of message sequence numbers
+SEARCHSET *uid;		a set of unique identifiers
+SEARCHOR *or;		OR result of two search programs
+SEARCHPGMLIST *not;	AND result of list of NOT'ed search programs
+SEARCHHEADER *header;	message headers
+STRINGLIST *bcc;	string(s) appear in bcc list
+STRINGLIST *body;	string(s) appear in message body text
+STRINGLIST *cc;		string(s) appear in cc list
+STRINGLIST *from;	string(s) appear in from
+STRINGLIST *keyword;	user flag string(s) set
+STRINGLIST *unkeyword;	user flag strings() not set
+STRINGLIST *subject;	string(s) appear in subject
+STRINGLIST *text;	string(s) appear in message header or body
+STRINGLIST *to;		string(s) appear in to list
+unsigned long larger;	larger than this many octets
+unsigned long smaller;	smaller than this many octes
+	The following dates are in form:
+		((year - BASEYEAR) << 9) + (month << 5) + day
+unsigned short sentbefore;
+			sent before this date
+unsigned short senton;	sent on this date
+unsigned short sentsince;
+			sent since this date
+unsigned short before;	received before this date
+unsigned short on;	received on this date
+unsigned short since;	received since this date
+unsigned int answered : 1;
+			message answered
+unsigned int unanswered : 1;
+			message not answered
+unsigned int deleted : 1;
+			message deleted
+unsigned int undeleted : 1;
+			message not deleted
+unsigned int draft : 1;	message is a draft
+unsigned int undraft : 1;
+			message is not a draft
+unsigned int flagged : 1;
+			message flagged as urgent
+unsigned int unflagged : 1;
+			message not flagged as urgent
+unsigned int recent : 1;
+			message recent since last parse of mailbox
+unsigned int old : 1;	message not recent since last parse of mailbox
+unsigned int seen : 1;	message read
+unsigned int unseen : 1;
+			message not read
+
+     The following auxillary structures are used by search programs:
+	SEARCHHEADER:	header line searching
+char *line;		header line field name
+char *text;		text header line
+SEARCHHEADER *next;	next SEARCHHEADER in list (AND'ed)
+
+	SEARCHSET:	message number set
+unsigned long first;	first number in set
+unsigned long last;	if non-zero, last number in set
+SEARCHSET *next;	next SEARCHSET in list (AND'ed)
+
+	SEARCHOR:	two search programs, OR'ed together
+SEARCHPGM *first;	first program
+SEARCHPGM *second;	second program
+SEARCHOR *next;		next SEARCHOR in list
+
+	SEARCHPGMLIST:	list of search programs
+SEARCHPGM *pgm;		search program (AND'd with others in list)
+SEARCHPGMLIST *next;	next SEARCHPGM in list
+
+     mail_search(), the older interface, accepts a search criteria
+argument as a character string in IMAP2 (RFC-1176) format.  Do not try
+to use any IMAP4 search criteria with this interface.
+
+     The application's mm_searched() function is called for each
+message that matches the search criteria.  In addition, after the
+search is completed, the "fast" information (see mail_fetchfast_full()
+and envelopes of the searched messages are fetched (this is called
+pre-fetching).
+
+     If there is any problem in searching, a message will be passed to
+the application via the mm_log() facility.
+
+     The flags for mail_search_full() are a bit mask with one or more
+of the following:
+	SE_UID		Return UIDs instead of sequence numbers
+	SE_FREE		Return the search program to free storage after
+			 finishing
+	SE_NOPREFETCH	Don't prefetch searched messages.
+
+
+unsigned long *mail_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
+			  SORTPGM *pgm,long flags);
+	stream	stream to sort
+	charset	MIME character set to use when sorting strings
+	spg	search program
+	pgm	sort program
+	flags	option flags
+
+
+     This function is a variant of mail_search_full().  It accepts an
+additional argument, a sort program, which specifies one or more sort
+rules to be applied to the result.  If the searching and sorting are
+successful, it returns a 0-terminated vector of message sequence
+numbers (or UIDs if SE_UID is set).  This vector is created out of
+free storage, and must be freed with fs_give() when finished with it.
+
+     A sort program is a structure that holds the following data:
+unsigned int reverse : 1;
+			reverse sorting of this key
+short function;		sort rule, one of the following:
+		SORTDATE	message Date
+		SORTARRIVAL	arrival date
+		SORTFROM	mailbox in first From address
+		SORTSUBJECT	message Subject
+		SORTTO		mailbox in first To address 
+		SORTCC		mailbox in first cc address 
+		SORTSIZE	size of message in octets
+SORTPGM *next;		next sort program to be applied if two or more
+			 messages collate identically with this rule
+
+     The flags for mail_search_full() are a bit mask with one or more
+of the following:
+	SE_UID		Return UIDs instead of sequence numbers
+	SE_FREE		Return the search program to free storage after
+			 finishing
+	SE_NOPREFETCH	Don't prefetch searched messages.
+	SO_FREE		Return the sort program to free storage after
+			 finishing
+
+	      Miscellaneous Mailbox and Message Functions
+
+long mail_ping (MAILSTREAM *stream);
+	stream	string to ping
+
+     The function pings the stream to see if it is still active.  It may
+discover new mail; this is the preferred method for a periodic "new mail
+check" as well as a "keep alive" for servers which have an inactivity
+timeout.  It returns T if the stream is still alive, NIL otherwise.
+
+     If new mail is found, the application's mm_exists() function is
+called with the newly-determined number of messages in the mailbox.
+
+
+void mail_check (MAILSTREAM *stream);
+	stream	stream to checkpoint
+
+      This function causes a mailstore-defined checkpoint of the
+mailbox.  This may include such things as a writeback to disk, a check
+for flag changes in a shared mailbox, etc.  It is not a "check for new
+mail"; mail_ping() performs this function (as potentially does any other
+function).  The status of the check is passed to the application via the
+mm_log() facility.
+
+
+void mail_expunge (MAILSTREAM *stream);
+	stream	string to expunge
+
+     This function causes an expunge (permanent removal of messages
+which are marked as deleted) of the mailbox.  The application's
+mm_expunged() function is called for each message that has been
+expunged.  The application's mm_exists() function is called at the start
+and end of the expunge to ensure synchronization.  The status of the
+expunge is passed to the application via the mm_log() facility.
+
+      Note that the decrementing of msgno's for subsequent messages
+happens immediately; for example, if three consequtive messages starting
+at msgno 5 are expunged, mm_expunged() will be called with a msgno of 5
+three times.
+
+
+long mail_copy (MAILSTREAM *stream,char *sequence,char *mailbox);
+long mail_move (MAILSTREAM *stream,char *sequence,char *mailbox);
+long mail_copy_full (MAILSTREAM *stream,char *sequence,char *mailbox,
+		     long options);
+	stream	stream to copy
+	sequence IMAP-format set of message numbers
+	mailbox	destination mailbox name
+	options	option flags
+
+     This function causes the messages in the specified sequence to be
+copied to the specified mailbox.  T is returned if the copy is
+successful.  mail_move() is equivalent to setting CP_MOVE in the options.
+
+     If there is any problem in copying, a message will be passed to
+the application via the mm_log() facility and the function returns NIL.
+No copying is actually done in this case.
+
+      Note that the mailbox must be on the same host as the stream and
+is a mailbox of the type of the source mailbox only.
+
+     The flags for mail_search_full() are a bit mask with one or more
+of the following:
+	CP_UID		The sequence argument contains UIDs instead of
+			 sequence numbers
+	CP_MOVE		Delete the messages from the current mailbox
+			 after copying to the destination.
+
+
+long mail_append (MAILSTREAM *stream,char *mailbox,STRING *message);
+long mail_append_full (MAILSTREAM *stream,char *mailbox,char *flags,char *date,
+		       STRING *message);
+	stream	stream to use if non-NIL (in the IMAP case)
+	mailbox	destination mailbox name
+	flags	flags to set on message if non-NIL
+	date	internal date (received date) to set on message if non-NIL
+	message	string structure of message to write
+
+     This function writes the message in the string structure to the
+destination mailbox, along with the flags and date if specified.  This
+is useful in those cases where you can't use mail_copy(), e.g. when
+copying from one server to another; you can always fetch the message
+and then mail_append() it to the destination.  It may also be useful
+for maintaining an outbox of your outgoing mail.
+
+
+void mail_gc (MAILSTREAM *stream,long gcflags);
+	stream	stream to GC if non-NIL (else GC's all streams)
+	flags	option flags
+
+      This function garbage collects (purges) the cache of entries of
+a specific type.  Some drivers do not allow purging of particular
+cache types, and an attempt to do so is ignored.
+
+      The flags for mail_gc() are a bit mask with one or more of the
+following:
+	GC_ELT		message cache elements
+	GC_ENV		ENVELOPEs and BODYs
+	GC_TEXTS	cached texts
+
+		     Date/Time Handling Functions
+
+
+char *mail_date (char *string,MESSAGECACHE *elt);
+	string	destination string
+	elt	message cache element containing date
+
+      This function accepts a message cache element that contains date
+information, and writes an IMAP-4 date string, that is, one in form:
+	dd-mmm-yyyy hh:mm:ss +zzzz
+based upon the data in the elt.  The destination string must be large
+enough to hold this string.
+
+
+char *mail_cdate (char *string,MESSAGECACHE *elt);
+	string	destination string
+	elt	message cache element containing date
+
+      This function accepts a message cache element that contains date
+information, and writes a ctime() format date string, that is, one in
+form:
+	www mmm dd hh:mm:ss yyyy\n
+based upon the data in the elt.  The destination string must be large
+enough to hold this string.
+
+
+long mail_parse_date (MESSAGECACHE *elt,char *string);
+	elt	message cache element to store parsed date
+	string	source date string
+
+      This function parses the date/time stored in the given string,
+in format:
+	[www,] date [[hh:mm[:ss][-zzz| +zzzz]
+where the date can be any of:
+	mm/dd/yy, mm/dd/yyyy, dd-mmm-yy, dd-mmm-yyyy, dd mmm yy, dd mmm yyyy
+and stores the result of the parse in the elt.  If the parse is
+successful, T is returned, else NIL.
+
+
+unsigned long mail_longdate (MESSAGECACHE *elt);
+	elt	message cache element containing date.
+
+      This function accepts a message cache element that contains date
+information, and returns the number of days since the base time of the
+imap-4 toolkit.  At present, this is the same as the Unix time() value
+for that date/time, and hence can be used for functions such as utime().
+
+			  Utility Functions
+
+void mail_debug (MAILSTREAM *stream);
+	stream	stream to debug
+
+      This function enables telemetry logging for this stream.  All
+telemetry is passed to the application via the mm_dlog() facility.
+
+
+void mail_nodebug (MAILSTREAM *stream);
+	stream	stream to disable debugging
+
+     This function disables telemetry logging for this stream.
+
+
+long mail_sequence (MAILSTREAM *stream,char *sequence);
+	stream	stream to set the sequence bits
+	sequence IMAP-format message set string
+
+     This function parses the given sequence string for message
+numbers, sets the sequence bit in the stream's message cache element
+of all messages in the sequence (and turns it off in all other message
+cache elements).  If the parse is successful, T is returned, else NIL.
+
+
+long mail_uid_sequence (MAILSTREAM *stream,char *sequence);
+	stream	stream to set the sequence bits
+	sequence IMAP-format message set string
+
+     This function parses the given sequence string for unique
+identifiers, sets the sequence bit in the stream's message cache
+element of all messages in the sequence (and turns it off in all other
+message cache elements).  If the parse is successful, T is returned,
+else NIL.
+
+
+long mail_parse_flags (MAILSTREAM *stream,char *flag,unsigned long *uf);
+	stream	stream (used to get user flags)
+	flag	IMAP-format flag string to parse
+	uf	returned location of user flags
+
+     The function parses the given flag string, and returns the system
+flags as its return value and the user flags in the location pointed
+to by the uf argument.  If there is an error in parse, a log message
+is issued via mm_log() and this function returns NIL.
+
+
+unsigned long mail_filter (char *text,unsigned long len,STRINGLIST *lines,
+			   long flags);
+	text	RFC 822 text to filter
+	len	length in octets in the text argument
+	lines	string list of header file names to filter
+	flags	option flags
+
+     This function supports the header lines filtering function of
+mail_fetchheader_full().  The lines argument contains a list of header
+field names to use in subsetting the header text.  Only those lines
+which have that header field name are returned, unless FT_NOT is set
+in which case only those lines which do not have that header field
+name are returned.
+
+     The options for mail_filter() are a bit mask with one or more of
+the following:
+	FT_NOT		The returned header lines are those that are
+			 not in the lines argument
+
+
+long mail_search_msg (MAILSTREAM *stream,unsigned long msgno,char *charset,
+		      SEARCHPGM *pgm);
+	stream	stream to search
+	msgno	message number of message to inspect
+	charset	character set of search strings
+	pgm	search program to test
+
+     This function implements mail_search_full() locally in cases when
+it is not done by a server (e.g. local mail files, NNTP/POP).  It
+inspects the given message on that stream to see if it matches the
+criteria or not.  If it matches, T is returned, else NIL.
+
+
+SEARCHPGM *mail_criteria (char *criteria);
+	criteria IMAP2-format search criteria string
+
+     This function accepts an IMAP2-format search criteria string and
+parses it.  If the parse is successful, it returns a search program
+suitable for use in mail_search_full().
+	WARNING: This function does not accept IMAP4 search criteria.
+	The source string must be writeable (this restriction was also
+	in the old IMAP2 c-client).
+
+	   Data Structure Instantiation/Destruction functions
+
+     These functions are used to obtain structures from free storage and
+to release them.
+
+ENVELOPE *mail_newenvelope (void);
+ADDRESS *mail_newaddr (void);
+BODY *mail_newbody (void);
+BODY *mail_initbody (BODY *body);
+PARAMETER *mail_newbody_parameter (void);
+PART *mail_newbody_part (void);
+STRINGLIST *mail_newstringlist (void);
+SEARCHPGM *mail_newsearchpgm (void);
+SEARCHHEADER *mail_newsearchheader (char *line);
+SEARCHSET *mail_newsearchset (void);
+SEARCHOR *mail_newsearchor (void);
+SEARCHPGMLIST *mail_newsearchpgmlist (void);
+SORTPGM *mail_newsortpgm (void);
+
+     These functions, all named mail_new...(), create a new structure of
+the given type and initialize all of its elements to zero or empty.
+
+void mail_free_body (BODY **body);
+void mail_free_body_parameter (PARAMETER **parameter);
+void mail_free_body_part (PART **part);
+void mail_free_cache (MAILSTREAM *stream);
+void mail_free_elt (MESSAGECACHE **elt);
+void mail_free_lelt (LONGCACHE **lelt);
+void mail_free_envelope (ENVELOPE **env);
+void mail_free_address (ADDRESS **address);
+void mail_free_stringlist (STRINGLIST **string);
+void mail_free_searchpgm (SEARCHPGM **pgm);
+void mail_free_searchheader (SEARCHHEADER **hdr);
+void mail_free_searchset (SEARCHSET **set);
+void mail_free_searchor (SEARCHOR **orl);
+void mail_free_searchpgmlist (SEARCHPGMLIST **pgl);
+void mail_free_sortpgm (SORTPGM **pgm);
+
+     These functions, all named mail_free_...(), take a pointer to a
+structure pointer, free all contained strings and structures within the
+structure, and finally free the structure itself and set its pointer to
+NIL.  For example, mail_free_envelope() frees all the ADDRESS structures
+contained in the envelope.
+
+     Normally, mail_free_elt() and mail_free_lelt() are used only if the
+main program has a private pointer to cache elements.  If so, it is
+expected to increment the cache element's lockcount when it makes a
+private pointer, and to call this function when it is finished with it.
+
+		       Authentication Functions
+
+char *mail_auth (char *mechanism,authresponse_t resp,int argc,char *argv[]);
+	mechanism authentication mechanism name
+	resp	callback function for providing responses
+	argc	main() function argc value
+	argv	main() function argv value
+
+     This server function searches the list of authenticators that was
+established by auth_link() for an authenticator with the given name.  If
+an authenticator is found, authentication is initialized.  The function
+pointed to by resp is called as the authenticator requires responses.
+
+
+AUTHENTICATOR *mail_lookup_auth (unsigned int i);
+	i	position in authenticator list
+
+     This function returns the nth authenticator in the list, where n is
+the value of it.
+
+
+unsigned int mail_lookup_auth_name (char *mechanism);
+	mechanism authentication mechanism name
+
+     This function searches the list of authenticators for an
+authenticator with the given name, and returns its position in the
+authenticator list.
+
+
+     The functions below are provided by c-client client drivers or by
+servers to support the protocol-dependent parts of authentication.
+
+typedef void *(*authchallenge_t) (void *stream,unsigned long *len);
+	stream	stream to read challenge
+	len	pointer to returned length in octets
+
+     This driver function is called by an authenticator to read a
+challenge from the given protocol stream in a protocol-dependent way.
+It returns that challenge in binary and its length in octets to the
+authenticator.
+
+
+typedef long (*authrespond_t) (void *stream,char *s,unsigned long size);
+	stream	stream to send response
+	s	response string
+	size	length of response string in octets
+
+     This driver function is called by an authenticator to send a
+challenge response to the given stream in a protocol-dependent way.
+It returns T if successful, NIL if failure.
+
+
+typedef char *(*authresponse_t) (void *challenge,unsigned long clen,
+				 unsigned long *rlen);
+	challenge challenge string
+	clen	length of challenge string in octets
+	rlen	pointer to returned length of response string
+
+     This server function is called with a challenge string of clen
+octets.  It sends, according to whatever protocol (IMAP, POP, etc.) it
+uses, and returns the received response and response length in octets.
+
+
+typedef long (*authclient_t) (authchallenge_t challenger,
+			      authrespond_t responder,NETMBX *mb,void *s,
+			      unsigned long trial);
+	challenger pointer to protocol-dependent challenge reader function
+	responder pointer to protocol-dependent response sender function
+	mb	NETMBX struct of the mailbox desired to open
+	s	stream for protocol-dependent routines to use
+	trial	number of authentication attempts remaining
+
+     This client authenticator function negotiates reading challenges
+and sending responses for a particular authenticator (Kerberos, etc.)
+over the protocol, and returns T if authenticated or NIL if failed.
+
+
+typedef char *(*authserver_t) (authresponse_t responder,int argc,char *argv[]);
+	responder pointer to protocol-dependent responder function
+	argc	main() function argc value
+	argv	main() function argv value
+
+    This server authenticator function negotiates sending challenges and
+reading responses for a particular authenticator (Kerberos, etc.), and
+returns either the authenticated user name or NIL if authentication
+failed.
+
+		       Network Access Functions
+
+     These functions provide a layer of indirection between the TCP
+routines and upper level routines.  This makes it possible to insert
+additional code (e.g. privacy or checksum handling).
+
+NETSTREAM *net_open (char *host,char *service,unsigned long port);
+	host	host name
+	service	contact service name
+	port	contact port number
+
+     This function opens a TCP connection to the given host and service
+or port.
+
+
+NETSTREAM *net_aopen (NETMBX *mb,char *service,char *usrbuf);
+	NETMBX	parsed mailbox specification
+	service	stream to open (at present, only /etc/rimapd is used)
+	usrbuf	buffer to return login user name
+
+     This function attempts to open a preauthenticated connection to the
+given mailbox and service.  It will return the login user name of the
+preauthenticated connection, as well as an open network stream, if
+successful.
+
+
+char *net_getline (NETSTREAM *stream);
+	stream	network stream to read
+
+     This routine reads a text line from the stream.  It calls
+stream->dtb->getline, which normally points to tcp_getline() but can be
+set to some other function.
+
+
+long net_getbuffer (void *stream,unsigned long size,char *buffer);
+	stream	network stream to read
+	size	length of data in octets
+	buffer	buffer of at least size octets
+
+     This routine reads data from the stream.  It calls
+stream->dtb->getbuffer, which normally points to tcp_getbuffer() but can
+be set to some other function.
+
+
+long net_soutr (NETSTREAM *stream,char *string);
+	stream	network stream to write
+	string	null-terminated string to output
+
+     This routine writes a null-terminated string to the stream.  It
+calls stream->dtb->soutr, which normally points to tcp_soutr() but can
+be set to some other function.
+
+
+long net_sout (NETSTREAM *stream,char *string,unsigned long size);
+	stream	network stream to write
+	string	string to output
+	size	length of string in octets
+
+     This routine writes a string of length size to the stream.  It
+calls stream->dtb->sout, which normally points to tcp_sout() but can be
+set to some other function.
+
+
+void net_close (NETSTREAM *stream);
+	stream	stream to close
+
+     This routine closes the stream.  It calls stream->dtb->close, which
+normally points to tcp_close() but can point to some other function.
+
+
+char *net_host (NETSTREAM *stream);
+	stream	stream to inspect
+
+     This routine returns the remote host name of the stream.  It calls
+stream->dtb->host, which normally points to tcp_host() but can point
+to some other function.
+
+
+unsigned long net_port (NETSTREAM *stream);
+	stream	stream to inspect
+
+     This routine returns the remote port number of the stream.  It calls
+stream->dtb->port, which normally points to tcp_port() but can point
+to some other function.
+
+
+char *net_localhost (NETSTREAM *stream);
+	stream	stream to inspect
+
+     This routine returns the local host name of the stream.  It calls
+stream->dtb->localhost, which normally points to tcp_localhost() but can
+point to some other function.
+
+		  Subscription Management Functions
+
+long sm_subscribe (char *mailbox);
+	mailbox	mailbox name to subscribe
+
+     This function adds the given mailbox name to the local subscription
+list, and returns T if successful, NIL if failure.
+
+
+long sm_unsubscribe (char *mailbox);
+	mailbox	mailbox name to unsubscribe
+
+     This function removes the given mailbox name from the local
+subscription list, and returns T if successful, NIL if failure.
+
+char *sm_read (void **sdb);
+	sdb	data to use in subsequent calls, or NIL if first call
+
+     This function returns the local subscription list as null
+terminated strings.  Each call returns the next element in the list.
+The first call should be with sdb pointing to a NIL pointer; this will
+be filled in for subsequent calls.  At the last call, NIL will be
+returned.
+
+		    Miscellaneous Utility Functions
+
+char *ucase (char *string);
+	string	string to convert
+
+     This function converts each lowercase character of the specified
+string to uppercase and returns the string.
+
+
+char *lcase (char *string);
+	string	string to convert
+
+     This function converts each uppercase character of the specified
+string to lowercase and returns the string.
+
+
+char *cpystr (char *string);
+	string	string to copy
+
+ This function makes a copy of the string from free storage and returns
+the copy.
+
+
+long find_rightmost_bit (long *valptr);
+	valptr	pointer to value to search
+
+      This function returns -1 if the 32-bit value pointed to by valptr
+is non-zero, otherwise it returns the bit number (0 = LSB, 31 = MSB) of
+the right-most bit in that value.  This is used to convert from the bits
+in the cache's userflags item to an index into the stream's userFlags
+array of flag texts.
+
+
+long min (long i,long j);
+	i	first argument
+	j	second argument
+
+      This function returns the minimum of the two integers.
+
+long max (long i,long j);
+	i	first argument
+	j	second argument
+
+     This function returns the maximum of the two integers.
+
+long search (char *s,long c,char *pat,long patc);
+	s	string to search
+	c	size of string
+	pat	pattern to search in string
+	patc	size of pattern
+
+      This function does a fast case-independent search for the given
+pattern in pat (length patc) in base string s, and returns T if the
+pattern is found in the string.
+
+
+long pmatch (char *s,char *pat,delim);
+long pmatch_full (char *s,char *pat,delim);
+	s	string to match
+	pat	wildcard (* and %) to match in pattern
+	delim	hierarchy delimiter
+
+      This function returns T if the given wildcard pattern matches the
+string in s with hierarchy delimiter delim.  Otherwise NIL is returned.
+
+
+long dmatch (char *s,char *pat,char delim);
+	s	string to match
+	pat	wildcard (* and %) to match in pattern
+	delim	hierarchy delimiter
+
+     This function returns T if the given wildcard pattern matches the
+directory.  If not, then none of the elements in the directory are
+considered for recursive checking with pmatch_full().
+
+			     SMTP Functions
+
+SMTPSTREAM *smtp_open (char **hostlist,long debug);
+	hostlist vector of SMTP server host names to try
+	debug	non-zero if want protocol telemetry debugging
+
+      This function opens an SMTP connection to a one of the hosts in the
+host list and if successful returns a stream suitable for use by the
+other SMTP functions.  The hosts are tried in order until a connection is
+successfully opened.  If debug is non-NIL, protocol telemetry is logged
+via mm_dlog().  NIL is returned if this function fails to open a
+connection to any of the hosts in the list.
+
+void smtp_close (SMTPSTREAM *stream);
+	stream	stream to close
+
+     This function closes the SMTP stream and frees all resources
+associated with it that it may have created.
+
+long smtp_mail (SMTPSTREAM *stream,char *type,ENVELOPE *msg,BODY *body);
+	stream	stream to transmit mail
+	type	mail type (MAIL, SEND, SAML, SOML)
+	msg	message envelope
+	body	message body
+
+      This function negotiates an SMTP transaction of the specified type
+(one of "MAIL", "SEND", "SAML", or "SOML") to deliver the specified
+message.  This function returns T if success or NIL if there is any
+failure.  The text reason for the failure is in stream->reply item; if
+it is associated with a recipient it is also in that address'
+address->error item.
+
+
+void smtp_debug (SMTPSTREAM *stream);
+	stream	stream to enable debugging telemetry
+
+      This function enables SMTP protocol telemetry logging for this
+stream.  All SMTP protocol operations are passed to the application via
+the mm_dlog() facility.
+
+
+void smtp_nodebug (SMTPSTREAM *stream);
+	stream	stream to disable debugging telemetry
+
+      This function disables SMTP protocol telemetry logging for this
+stream.
+
+
+typedef void (*smtpverbose_t) (char *buffer);
+	buffer	pointer to verbose reply buffer
+
+     This is the argument to the SET_SMTPVERBOSE mail_parmameter() call.
+If this function pointer is non-NIL, then if a verbose SMTP response
+(with SMTP code less than 100) is received, this function is called with
+that response text as its argument.
+
+			     NNTP Functions
+
+NNTPSTREAM *nntp_open (char **hostlist,long debug);
+	hostlist vector of NNTP server host names to try
+	debug	non-zero if want protocol telemetry debugging
+
+      This function opens an NNTP connection to a one of the hosts in the
+host list and if successful returns a stream suitable for use by the
+other MTP functions.  The hosts are tried in order until a connection is
+successfully opened.  If debug is non-NIL, protocol telemetry is logged
+via mm_dlog().  NIL is returned if this function fails to open a
+connection to any of the hosts in the list.
+
+
+void nntp_close (NNTPSTREAM *stream);
+	stream	stream to close
+
+     This function closes the NNTP stream and frees all resources
+associated with it that it may have created.
+
+
+long nntp_mail (NNTPSTREAM *stream,ENVELOPE *msg,BODY *body);
+	stream	stream to transmit mail
+	msg	message envelope
+	body	message body
+
+      This function negotiates an NNTP posting transaction to deliver
+the specified news message.  This function returns T if success or NIL
+if there is any failure.  The text reason for the failure is in
+stream->reply item; if it is associated with a recipient it is also in
+that address' address->error item.
+
+		      RFC 822 Support Functions
+
+     Although rfc822.c contains several additional functions besides
+these, only the functions documented here should be used by
+applications.  The other functions are for internal use only.
+
+
+void rfc822_header (char *header,ENVELOPE *env,BODY *body);
+	header	buffer to write RFC 822 header
+	env	message ENVELOPE (used to obtain RFC 822 information)
+	body	message BODY (used to obtain MIME information)
+
+     This function writes an RFC 822 format header into header based
+on the information in the envelope and body.  The header buffer must
+be large enough to contain the full text of the resulting header.
+
+
+void rfc822_write_address (char *dest,ADDRESS *adr);
+	dest	buffer to write address list
+	adr	RFC 822 ADDRESS list
+
+     This function writes an RFC 822 format address list into dest
+based on the information in adr.  The dest buffer must be large enough
+to contain the full text of the resulting address list.
+
+void rfc822_parse_msg (ENVELOPE **en,BODY **bdy,char *s,unsigned long i,
+		       STRING *b,char *host,char *tmp);
+	en	destination pointer where message ENVELOPE will be stored
+	bdy	destination pointer where message BODY will be stored
+	s	RFC 822 header to parse (character string)
+	i	length of RFC 822 header
+	b	stringstruct of message body
+	host	default host name if an address lacks an @host.
+	temp	scratch buffer, must be long enough to hold unwound
+		 header lines (a buffer that is i octets long is OK)
+
+     This function parses the RFC 822 header pointed to by s with body
+pointed to by string structure b into the specified destination
+envelope and body pointers, using host as the default host name and
+tmp as a scratch buffer.  New ENVELOPE and BODY structures are
+created; when finished with them the application must free them with
+mail_free_envelope() and mail_free_body().  Any parsing errors are
+noted via the mm_log() mechanism using log type PARSE.
+
+
+void rfc822_parse_adrlist (ADDRESS **lst,char *string,char *host);
+	lst	destination pointer where ADDRESS will be stored
+	string	string of addresses to parse
+	host	default host name if an address lacks an @host.
+
+     This function parses the address list in the given string into an
+address list in lst.  Any addresses missing a host name are have the
+host name defaulted from the host argument.  If the destination list
+is non-empty it appends the new addresses to the list.  Any parsing
+errors are noted via the mm_log() mechanism using log type PARSE.
+
+long rfc822_output (char *t,ENVELOPE *env,BODY *body,soutr_t f,void *s,
+		    long ok8bit);
+	t	scratch buffer, large enough to hold message header
+	env	message ENVELOPE
+	body	message BODY
+	f	I/O function to write to
+	s	stream for I/O function f
+	ok8bit	non-zero if OK to output 8-bit data
+
+     This function writes the message described with the given
+envelope and body.  Any body part contents of type ENCBINARY is
+converted to ENCBASE64 before sending.  If ok8bit is NIL, any message
+data of type ENC8BIT is converted to ENCQUOTEDPRINTABLE before
+sending; if ok8bit is non-NIL then ENC8BIT data is sent as-is.  T is
+returned if the function succeeds, else NIL is returned.
+
+     The function f is typically net_soutr(), but it can be any
+function which matches
+  typedef long (*soutr_t) (void *stream,char *string);
+where stream holds sufficient information to enable the output routine
+to know where to output to, and the string is a null-terminated string
+to output.  This function returns either T or NIL, and that value is
+passed up to rfc822_output() for its return.
+
+
+void *rfc822_base64 (char *src,unsigned long srcl,unsigned long *len);
+	src	source string
+	srcl	size of source string in octets
+	len	pointer to where destination string length in octets
+		 will be returned
+
+     This function decodes a BASE64 body part given a source string
+and its length.  The decoded body part as a sequence of binary octets
+is returned, and its length is returned in len.
+
+
+char *rfc822_qprint (char *src,unsigned long srcl,unsigned long *len);
+	src	source string
+	srcl	size of source string in octets
+	len	pointer to where destination string length in octets
+		 will be returned
+
+     This function decodes a QUOTED-PRINTABLE body part given a source
+string and its length.  The decoded body part as an 8-bit character
+string is returned, and its length is returned in len.
+
+	     Operating System-Dependent Public Interface
+
+     These functions are in OS-dependent code, and are rewritten each
+time c-client is ported to a new operating system.
+
+
+void rfc822_date (char *date);
+	date	buffer to write the date, must be large enough
+
+     This function is called to get the current date and time in an
+RFC 822 format string into the given buffer.
+
+
+void *fs_get (size_t size);
+	size	number of octets requested
+
+      This function allocates and returns a block of free storage of
+the specified size.  Unlike malloc(), there is no failure return; this
+function must return with the requested storage.
+
+
+void fs_resize (void **block,size_t size);
+	block	pointer to pointer to block to be resized
+	size	new size in octets
+
+     This function resizes the free storage block, updating the
+pointer if necessary.  Unlike realloc(), there is no failure return;
+this function must return with the requested storage.
+
+
+void fs_give (void **block);
+	block	pointer to pointer to block to free
+
+      This function releases a block of free storage allocated by
+fs_get().  It also erases the block pointer, so it isn't necessary to
+do this in the application.
+
+
+void fatal (char *string);
+	string	message string
+
+      This function is called when an "impossible" error is detected
+and the client wishes to crash.  The string should contain a reason.
+
+
+char *strcrlfcpy (char **dst,long *dstl,char *src,long srcl);
+	dst	pointer to destination string pointer
+	dstl	pointer to destination string size
+	src	source strin
+	srcl	source string size
+
+      This function is called to copy into a destination string dst of
+size dstl (resized if necessary), a CRLF newline form string from
+local format string src of size srcl.
+
+
+TCPSTREAM *tcp_open (char *host,long port);
+TCPSTREAM *tcp_aopen (char *host,char *service);
+char *tcp_getline (TCPSTREAM *stream);
+long tcp_getbuffer (TCPSTREAM *stream,long size,char *buffer);
+long tcp_soutr (TCPSTREAM *stream,char *string);
+void tcp_close (TCPSTREAM *stream);
+char *tcp_host (TCPSTREAM *stream);
+unsigned long tcp_port (TCPSTREAM *stream);
+char *tcp_localhost (TCPSTREAM *stream);
+
+     These functions are TCP-specific versions of the more general
+net_xxx() functions.  These should not be called directly by
+applications.
+
+
+char *tcp_clienthost (char *dst);
+	dst	destination string buffer
+
+     This function should be called only by a server called by inetd
+or similar mechanism which maps standard input to a network socket.
+It returns the host name of the other end (e.g. the client of a
+server) using the given string buffer, or NIL if it can't get this
+information.
+
+			Main Program Callbacks
+
+     All applications which use the c-client must have the following
+callbacks to handle events from c-client.  Note that in any callback
+which involves a mail stream, the stream is locked and you can not
+recursively call c-client from the callback.  This may also be true in
+callbacks which do not have a stream; in general, the rule is "do not
+call c-client, especially any mail_xxx() function, from a c-client
+callback".
+
+
+void mm_flags (MAILSTREAM *stream,unsigned long number);
+	stream	stream where event happened
+	number	message number
+
+     This function is called when c-client manipulates the flags for
+the given message number.  This alerts the application that it may
+need to inspect that message's flags to see if there are any
+interesting changes.
+
+
+void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status);
+	stream	stream where event happened
+	mailbox	mailbox name for this status
+	status	MAILSTATUS structure with message status
+
+     This function is called when c-client reports status of a mailbox
+(generally as the result of a mail_status() function call).  The
+returned MAILSTATUS structure has the following members:
+
+long flags;			validity flags.  These are the same as
+				 the SA_xxx option flags in the
+				 mail_status() call, and they indicate
+				 which of the other members of the
+				 MAILSTATUS structure have usable data
+				 (i.e. if SA_MESSAGES is not set, do
+				 not believe status->messages!!).
+unsigned long messages;		number of messages if SA_MESSAGES
+unsigned long recent;		number of recent messages if SA_RECENT
+unsigned long unseen;		number of unseen messages if SA_UNSEEN
+unsigned long uidnext;		next UID to be assigned if SA_UIDNEXT
+unsigned long uidvalidity;	UID validity value if SA_UIDVALIDITY
+
+
+void mm_searched (MAILSTREAM *stream,unsigned long number);
+	stream	stream where event happened
+	number	message number
+
+     This function is called to notify the main program that this
+message number matches a search (generally as the result of a
+mail_search_full() function call).
+
+
+void mm_exists (MAILSTREAM *stream,unsigned long number);
+	stream	stream where event happened
+	number	message number
+
+     This function is called to notify the main program that there are
+this many messages in the mailbox.  It is also used to notify the main
+program of new mail, by announcing a higher number than the main
+program was previously aware.
+
+
+void mm_expunged (MAILSTREAM *stream,unsigned long number);
+	stream	stream where event happened
+	number	message number
+
+     This function is called to notify the main program that this
+message number has been expunged from the mail file and that all
+subsequent messages are now referenced by a message number one less
+than before.  This implicitly decrements the number of messages in the
+mailbox.
+
+
+void mm_list (MAILSTREAM *stream,char delim,char *name,long attrib);
+	stream	stream where event happened
+	delim	hierarchy delimiter
+	name	mailbox name
+	attrib	mailbox attributes
+
+     This function is called to notify the main program that this
+mailbox name matches a mailbox listing request (generally as the
+result of a mail_list() function call).  The hierarchy delimiter is a
+character that separates out levels of hierarchy in mailbox names.
+The attributes are a bit mask with one of the following:
+	LATT_NOINFERIORS
+			it is not possible for there to be any
+			 hierarchy inferiors to this name (that is,
+			 this name followed by the hierarchy delimiter
+			 and additional name characters).
+	LATT_NOSELECT	this is not a mailbox name, just a hierarchy
+			 level, and it may not be opened by mail_open()
+	LATT_MARKED	this mailbox may have recent messages
+	LATT_UNMARKED	this mailbox does not have any recent messages
+
+
+void mm_lsub (MAILSTREAM *stream,char delim,char *name,long attrib);
+	stream	stream where event happened
+	delim	hierarchy delimiter
+	name	mailbox name
+	attrib	mailbox attributes
+
+
+     This function is called to notify the main program that this
+mailbox name matches a subscribed mailbox listing request (generally
+as the result of a mail_lsub() function call).  The hierarchy
+delimiter is a character that separates out levels of hierarchy in
+mailbox names.  The attributes are a bit mask with one of the
+following:
+	LATT_NOINFERIORS
+			it is not possible for there to be any
+			 hierarchy inferiors to this name (that is,
+			 this name followed by the hierarchy delimiter
+			 and additional name characters).
+	LATT_NOSELECT	this is not a mailbox name, just a hierarchy
+			 level, and it may not be opened by mail_open()
+	LATT_MARKED	this mailbox may have recent messages
+	LATT_UNMARKED	this mailbox does not have any recent messages
+
+
+void mm_notify (MAILSTREAM *stream,char *string,long errflg);
+	stream	stream where event happened
+	string	message string
+	errflg	message error level
+
+     This function is called to deliver a stream-oriented message
+event.  This is the mechanism by which any IMAP response codes for any
+application (e.g. TRYCREATE) are delivered to the application.
+No newline is included in the string, so this function has to output
+its own.
+
+     The message error level is one of the following:
+
+	NIL	normal operation.  The text is `babble' that may be
+		interesting to the user, e.g. the greeting message
+		from a server.
+
+	WARN	A warning event.  This event should be displayed to
+		the user.  Examples: a mailbox rewrite failed because
+		of disk full, but the previous mailbox contents were
+		recovered.
+
+	ERROR	An error event.  This event should be displayed to
+		the user, or at least logged someplace.  This type of
+		error shouldn't happen, and so should be called to the
+		attention of support staff.  Whatever happened has
+		probably disrupted the user's work.  Examples: an
+		untagged BAD from an IMAP server.
+
+
+void mm_log (char *string,long errflg);
+	string	message string
+	errflg	message error level
+
+      This function is called to deliver a log message.  No newline is
+included in the string, so this function has to output its own.  In
+general, it is intended that these messages are logged someplace, and
+possibly shown to the user.
+
+     The message error level is one of the following:
+
+	NIL	normal operation.  The text is `babble' that may be
+		interesting to the user, e.g. "Expunged 3 messages".
+
+	PARSE	An RFC 822 parsing error.  Since bogus headers are
+		all-too-common in the real world, these can often be
+		ignored on the "garbage in, garbage out" princple.
+		However, since surprising results can be yielded when
+		trying to parse garbage, this message should be logged
+		somewhere so it can be figured out what happened.
+
+	WARN	A warning event.  This event should be displayed to
+		the user.  It occurs when an error condition has
+		happened, but c-client knows what to do to recover.
+		Examples: "Can't open read-write, so opening
+		read-only", "Empty mailbox", "Login failed, try
+		again", "Waiting for mailbox to become unlocked",
+		"IMAP protocol error".  Although a user should be
+		told about a warning, it's generally not necessary
+		to interrupt the flow of her work (e.g. it's alright
+		to display the warning in a scrolling window, but
+		not necessary to require the user to do anything).
+
+	ERROR	An error event.  This event should be displayed to
+		the user, or at least logged someplace.  This is a
+		serious error condition occured that aborted the
+		requested operation and possibly also aborted the mail
+		stream.  This ranges from normal error conditions such
+		as "Can't open mailbox", "too many login failures, go
+		away" to bizarre conditions such as "Apparent new mail
+		appeared in the mailbox that doesn't look like mail,
+		program aborting".  Errors must be called to the
+		user's attention, and probably should require some
+		sort of acknowledgement (e.g. answering a modal panel)
+		before the application proceeds.
+
+
+void mm_dlog (char *string);
+	string message string
+
+      This function is called to deliver a debugging telemetry
+message.  No newline is included in the string, so this function has
+to output its own.  This is called only when debugging is enabled.
+
+
+void mm_login (NETMBX *mb,char *user,char *pwd,long trial);
+	mb	parsed mailbox specification
+	user	pointer to where to return user name
+	pwd	pointer to where to return password
+	trial	number of prior login attempts
+
+      This function is called to get a user name and password for the
+given network mailbox.  It stores the user name and password in the
+strings pointed to by the appropriate arguments.  The trial argument
+is the number of attempts to perform the login and is initially zero
+(e.g. for a default username and password login functionality).  It is
+incremented for each subsequent trial until the maximum number of
+trials are made.
+
+
+void mm_critical (MAILSTREAM *stream);
+	stream	stream where event happened
+
+      This function is called to alert the application that c-client
+is about to run some critical code on that stream that may result in a
+clobbered mail file if it is interrupted.  It may be desirable to
+disable CTRL/C, etc. during this time.
+
+
+void mm_nocritical (MAILSTREAM *stream);
+	stream	stream where event happened
+
+      This function is called to alert the application that c-client
+is no longer running critical code on that stream that may result in a
+clobbered mail file if it is interrupted.
+
+
+long mm_diskerror (MAILSTREAM *stream,long errcode,long serious);
+	stream	stream where event happened
+	errcode	OS error code for disk error
+	serious	non-zero if c-client can not undo the operation (and
+		 thus must retry to avoid mail file damage)
+
+      This function is called to alert the application that the
+c-client has encountered an unrecoverable write error when trying to
+update the mail file.  errcode contains the system error code.  If
+serious is non-zero, then it is probable that the disk copy of the
+mailbox has been damaged.
+
+     The return value from this function is the abort flag; if serious
+is zero and the abort flag is non-zero, the operation is aborted.  If
+the abort flag is zero or if serious was non-zero, a return from this
+function will retry the failing operation.
+
+
+void mm_fatal (char *string);
+	string	message string
+
+      This function is called from the fatal() routine in the
+operating system code to notify the main program that it is about to
+crash.  The string contains a reason.  At the very minimum, the main
+program should do something like
+ mm_log (string,ERROR);
+and then return.  No newline is included in the string, so this
+function has to output its own.
+
+			     Driver interface
+
+     When writing a new driver for the c-client, you must provide a
+DRIVER stucture giving a dispatch vector between MAIL and the driver.
+The DRIVER dispatch vector is described in mail.h.
+
+char *name;
+     Name by which the driver is known to c-client.
+
+unsigned long flags;
+     Attribute flags for this driver:
+	DR_DISABLE	This driver is currently disabled.
+	DR_LOCAL	This driver deals with local mailboxes; if
+			 this is off it deals with mailboxes over a
+			 network.
+	DR_MAIL		This driver supports e-mail messages.
+	DR_NEWS		This driver supports netnews messages
+	DR_READONLY	This driver only allows read-only access;
+			 mail_setflag(), mail_expunge(), etc. are
+			 no-ops.
+	DR_NOFAST	This driver does not implement mail_fetchfast()
+			 in a fast way (e.g. it may have to fetch the
+			 entire message text over a network to
+			 calculate sizes).
+	DR_NAMESPACE	This driver accepts and uses namespace format
+			 names.
+	DR_LOWMEM	This driver is designed for systems with very
+			 limited amounts of memory (e.g. DOS) and
+			 support routines called by this driver should
+			 try not to use much memory.
+
+DRIVER *next;
+     Pointer to the next driver which this application supports (or NIL if
+this is the last driver).  Drivers are lunk together via the mail_link()
+function.
+
+DRIVER *driver_valid (char *mailbox);
+     This function returns a pointer to the driver's DRIVER dispatch
+vector iff this driver accepts the given name as a valid mailbox for this
+driver.  Otherwise, it returns the value of the next driver's
+driver_valid() or NIL if there is no next driver.  In other words, calling
+driver_valid() for the first driver will return the driver dispatch vector
+for the driver which supports this type of mailbox.
+
+void *driver_parameters (long function,void *value);
+     This function implements mail_parameters() for this driver.
+
+void driver_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+     This function implements mail_scan() for this driver.
+
+void driver_list (MAILSTREAM *stream,char *ref,char *pat);
+     This function implements mail_list() for this driver.
+
+void driver_lsub (MAILSTREAM *stream,char *ref,char *pat);
+     This function implements mail_lsub() for this driver.
+
+long driver_subscribe (MAILSTREAM *stream,char *mailbox);
+     This function implements mail_subscribe() for this driver.
+
+long driver_unsubscribe (MAILSTREAM *stream,char *mailbox);
+     This function implements mail_unsubscribe() for this driver.
+
+long driver_create (MAILSTREAM *stream,char *mailbox);
+     This function implements mail_create() for this driver.
+
+long driver_delete (MAILSTREAM *stream,char *mailbox);
+     This function implements mail_delete() for this driver.
+
+long driver_rename (MAILSTREAM *stream,char *old,char *new);
+     This function implements mail_rename() for this driver.
+
+long driver_status (MAILSTREAM *stream,char *mailbox,long flags);
+     This function implements mail_status() for this driver.
+
+MAILSTREAM *driver_open (MAILSTREAM *stream);
+     This function opens the mailbox identified by the given stream.  It
+may use the data on the stream and create additional data on stream->local
+as necessary.  It should return the given stream unless it failed to open
+the mailbox, in which case it should return NIL.
+
+void driver_close (MAILSTREAM *stream,long options);
+     This function implements mail_close() for this driver.
+
+void driver_fetchfast (MAILSTREAM *stream,char *sequence,long flags);
+     This function implements mail_fetchfast() for this driver.
+
+void driver_fetchflags (MAILSTREAM *stream,char *sequence,long flags);
+     This function implements mail_fetchflags() for this driver.
+
+ENVELOPE *driver_fetchstructure (MAILSTREAM *stream,unsigned long msgno,
+				 BODY **body,long flags);
+     This function implements mail_fetchstructure() for this driver.
+
+char *driver_fetchheader (MAILSTREAM *stream,unsigned long msgno,
+			  STRINGLIST *lines,unsigned long *len,long flags);
+     This function implements mail_fetchheader() for this driver.
+
+char *driver_fetchtext (MAILSTREAM *stream,unsigned long msgno,
+			unsigned long *len,long flags);
+     This function implements mail_fetchtext() for this driver.
+
+char *driver_fetchbody (MAILSTREAM *stream,unsigned long msgno,char *section,
+			unsigned long *len,long flags);
+     This function implements mail_fetchbody() for this driver.
+
+void driver_setflag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
+     This function implements mail_setflag() for this driver.
+
+void driver_clearflag (MAILSTREAM *stream,char *sequence,char *flag,
+		       long flags);
+     This function implements mail_clearflag() for this driver.
+
+void driver_search (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,
+		    long flags);
+     This function implements mail_search() for this driver.
+
+unsigned long *driver_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
+			    SORTPGM *pgm,long flags);
+     This function implements mail_sort() for this driver.
+
+void *driver_thread (MAILSTREAM *stream,char *seq,long function,long flag);
+     This dispatch is reserved for a future threading capability.
+
+long driver_ping (MAILSTREAM *stream);
+      This function implements mail_ping() for this driver.
+
+void driver_check (MAILSTREAM *stream);
+      This function implements mail_check() for this driver.
+
+void driver_expunge (MAILSTREAM *stream);
+      This function implements mail_expunge() for this driver.
+
+long driver_copy (MAILSTREAM *stream,char *sequence,char *mailbox,
+		  long options);
+      This function implements mail_copy() for this driver.
+
+long driver_append (MAILSTREAM *stream,char *mailbox,char *flags,char *date,
+		    STRING *message);
+      This function implements mail_append() for this driver.
+
+void driver_gc (MAILSTREAM *stream,long gcflags);
+      This function implements mail_gc() for this driver.
+
+			 Driver Support Functions
+
+void mail_searched (MAILSTREAM *stream,unsigned long msgno);
+	stream	stream where event happened
+	msgno	message number
+
+     This function is called by the driver to notify c-client that this
+message number matches a search.  It invokes the main program's
+mm_searched() function.
+
+void mail_exists (MAILSTREAM *stream,unsigned long nmsgs);
+	stream	stream where event happened
+	nmsgs	number of messages
+
+     This function is called by the driver to notify c-client that this
+message number exists (i.e. there are this many messages in the mailbox).
+It invokes the main program's mm_exists() function.
+
+void mail_recent (MAILSTREAM *stream,unsigned long recent);
+	stream	stream where event happened
+	recent	number of messages
+
+      This function is called by the driver to notify c-client that this
+many messages are "recent" (i.e. arrived in the mailbox since the previous
+time the mailbox was opened).
+
+void mail_expunged (MAILSTREAM *stream,unsigned long msgno);
+	stream	stream where event happened
+	msgno	number of messages
+
+      This function is called by the driver to notify MAIL that this
+message number has been expunged from the mail file and that all subsequent
+messages are now referenced by a message number one less than before.  It
+invokes the main program's mm_expunged() function.
+
+void mail_lock (MAILSTREAM *stream);
+	stream	stream where event happened
+      This function sets the stream lock.  It is an error to set the stream
+lock if the stream is already locked.
+
+      This is mainly used to catch errors due to a callback function
+(e.g. mm_exists) inadvertantly recursing back to the MAIL routines and
+establishing an infinite recursion.  Normally, drivers will set the lock
+prior to calling one of the callback functions above or, more likely, in
+the beginning of the driver's non-reentrant "do operation" section.  In the
+IMAP4 driver, the stream lock is set when entering imap_send() and cleared
+on exit.
+
+void mail_unlock (MAILSTREAM *stream);
+	stream	stream where event happened
+
+     This function releases the stream lock.  It is an error to release the
+stream lock if the stream is not locked.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/locking.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,417 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+	 UNIX Advisory File Locking Implications on c-client
+		    Mark Crispin, 28 November 1995
+
+
+	THIS DOCUMENT HAS BEEN UPDATED TO REFLECT THE FACT THAT
+	LINUX SUPPORTS BOTH flock() AND fcntl() AND THAT OSF/1
+	HAS BEEN BROKEN SO THAT IT ONLY SUPPORTS fcntl().
+	-- JUNE 15, 2004
+
+	THIS DOCUMENT HAS BEEN UPDATED TO REFLECT THE CODE IN THE
+	IMAP-4 TOOLKIT AS OF NOVEMBER 28, 1995.  SOME STATEMENTS
+	IN THIS DOCUMENT DO NOT APPLY TO EARLIER VERSIONS OF THE
+	IMAP TOOLKIT.
+
+INTRODUCTION
+
+     Advisory locking is a mechanism by which cooperating processes
+can signal to each other their usage of a resource and whether or not
+that usage is critical.  It is not a mechanism to protect against
+processes which do not cooperate in the locking.
+
+     The most basic form of locking involves a counter.  This counter
+is -1 when the resource is available.  If a process wants the lock, it
+executes an atomic increment-and-test-if-zero.  If the value is zero,
+the process has the lock and can execute the critical code that needs
+exclusive usage of a resource.  When it is finished, it sets the lock
+back to -1.  In C terms:
+
+  while (++lock)		/* try to get lock */
+    invoke_other_threads ();	/* failed, try again */
+   .
+   .	/* critical code  here */
+   .
+  lock = -1;			/* release lock */
+
+     This particular form of locking appears most commonly in
+multi-threaded applications such as operating system kernels.  It
+makes several presumptions:
+ (1) it is alright to keep testing the lock (no overflow)
+ (2) the critical resource is single-access only
+ (3) there is shared writeable memory between the two threads
+ (4) the threads can be trusted to release the lock when finished
+
+     In applications programming on multi-user systems, most commonly
+the other threads are in an entirely different process, which may even
+be logged in as a different user.  Few operating systems offer shared
+writeable memory between such processes.
+
+     A means of communicating this is by use of a file with a mutually
+agreed upon name.  A binary semaphore can be passed by means of the
+existance or non-existance of that file, provided that there is an
+atomic means to create a file if and only if that file does not exist.
+In C terms:
+
+				/* try to get lock */
+  while ((fd = open ("lockfile",O_WRONLY|O_CREAT|O_EXCL,0666)) < 0)
+    sleep (1);			/* failed, try again */
+  close (fd);			/* got the lock */
+   .
+   .	/* critical code  here */
+   .
+  unlink ("lockfile"); 		/* release lock */
+
+     This form of locking makes fewer presumptions, but it still is
+guilty of presumptions (2) and (4) above.  Presumption (2) limits the
+ability to have processes sharing a resource in a non-conflicting
+fashion (e.g. reading from a file).  Presumption (4) leads to
+deadlocks should the process crash while it has a resource locked.
+
+     Most modern operating systems provide a resource locking system
+call that has none of these presumptions.  In particular, a mechanism
+is provided for identifying shared locks as opposed to exclusive
+locks.  A shared lock permits other processes to obtain a shared lock,
+but denies exclusive locks.  In other words:
+
+	current state		want shared	want exclusive
+	-------------		-----------	--------------
+	 unlocked		 YES		 YES
+	 locked shared		 YES		 NO
+	 locked exclusive	 NO		 NO
+
+     Furthermore, the operating system automatically relinquishes all
+locks held by that process when it terminates.
+
+     A useful operation is the ability to upgrade a shared lock to
+exclusive (provided there are no other shared users of the lock) and
+to downgrade an exclusive lock to shared.  It is important that at no
+time is the lock ever removed; a process upgrading to exclusive must
+not relenquish its shared lock.
+
+     Most commonly, the resources being locked are files.  Shared
+locks are particularly important with files; multiple simultaneous
+processes can read from a file, but only one can safely write at a
+time.  Some writes may be safer than others; an append to the end of
+the file is safer than changing existing file data.  In turn, changing
+a file record in place is safer than rewriting the file with an
+entirely different structure.
+
+
+FILE LOCKING ON UNIX
+
+     In the oldest versions of UNIX, the use of a semaphore lockfile
+was the only available form of locking.  Advisory locking system calls
+were not added to UNIX until after the BSD vs. System V split.  Both
+of these system calls deal with file resources only.
+
+     Most systems only have one or the other form of locking.  AIX
+and newer versions of OSF/1 emulate the BSD form of locking as a jacket
+into the System V form.  Ultrix and Linux implement both forms.
+
+BSD
+
+     BSD added the flock() system call.  It offers capabilities to
+acquire shared lock, acquire exclusive lock, and unlock.  Optionally,
+the process can request an immediate error return instead of blocking
+when the lock is unavailable.
+
+
+FLOCK() BUGS
+
+     flock() advertises that it permits upgrading of shared locks to
+exclusive and downgrading of exclusive locks to shared, but it does so
+by releasing the former lock and then trying to acquire the new lock.
+This creates a window of vulnerability in which another process can
+grab the exclusive lock.  Therefore, this capability is not useful,
+although many programmers have been deluded by incautious reading of
+the flock() man page to believe otherwise.  This problem can be
+programmed around, once the programmer is aware of it.
+
+     flock() always returns as if it succeeded on NFS files, when in
+fact it is a no-op.  There is no way around this.
+
+     Leaving aside these two problems, flock() works remarkably well,
+and has shown itself to be robust and trustworthy.
+
+SYSTEM V/POSIX
+
+     System V added new functions to the fnctl() system call, and a
+simple interface through the lockf() subroutine.  This was
+subsequently included in POSIX.  Both offer the facility to apply the
+lock to a particular region of the file instead of to the entire file.
+lockf() only supports exclusive locks, and calls fcntl() internally;
+hence it won't be discussed further.
+
+     Functionally, fcntl() locking is a superset of flock(); it is
+possible to implement a flock() emulator using fcntl(), with one minor
+exception: it is not possible to acquire an exclusive lock if the file
+is not open for write.
+
+     The fcntl() locking functions are: query lock station of a file
+region, lock/unlock a region, and lock/unlock a region and block until
+have the lock.  The locks may be shared or exclusive.  By means of the
+statd and lockd daemons, fcntl() locking is available on NFS files.
+
+     When statd is started at system boot, it reads its /etc/state
+file (which contains the number of times it has been invoked) and
+/etc/sm directory (which contains a list of all remote sites which are
+client or server locking with this site), and notifies the statd on
+each of these systems that it has been restarted.  Each statd then
+notifies the local lockd of the restart of that system.
+
+     lockd receives fcntl() requests for NFS files.  It communicates
+with the lockd at the server and requests it to apply the lock, and
+with the statd to request it for notification when the server goes
+down.  It blocks until all these requests are completed.
+
+     There is quite a mythos about fcntl() locking.
+
+     One religion holds that fcntl() locking is the best thing since
+sliced bread, and that programs which use flock() should be converted
+to fcntl() so that NFS locking will work.  However, as noted above,
+very few systems support both calls, so such an exercise is pointless
+except on Ultrix and Linux.
+
+     Another religion, which I adhere to, has the opposite viewpoint.
+
+
+FCNTL() BUGS
+
+     For all of the hairy code to do individual section locking of a
+file, it's clear that the designers of fcntl() locking never
+considered some very basic locking operations.  It's as if all they
+knew about locking they got out of some CS textbook with not
+investigation of real-world needs.
+
+     It is not possible to acquire an exclusive lock unless the file
+is open for write.  You could have append with shared read, and thus
+you could have a case in which a read-only access may need to go
+exclusive.  This problem can be programmed around once the programmer
+is aware of it.
+
+     If the file is opened on another file designator in the same
+process, the file is unlocked even if no attempt is made to do any
+form of locking on the second designator.  This is a very bad bug.  It
+means that an application must keep track of all the files that it has
+opened and locked.
+
+     If there is no statd/lockd on the NFS server, fcntl() will hang
+forever waiting for them to appear.  This is a bad bug.  It means that
+any attempt to lock on a server that doesn't run these daemons will
+hang.  There is no way for an application to request flock() style
+``try to lock, but no-op if the mechanism ain't there''.
+
+     There is a rumor to the effect that fcntl() will hang forever on
+local files too if there is no local statd/lockd.  These daemons are
+running on mailer.u, although they appear not to have much CPU time.
+A useful experiment would be to kill them and see if imapd is affected
+in any way, but I decline to do so without an OK from UCS!  ;-) If
+killing statd/lockd can be done without breaking fcntl() on local
+files, this would become one of the primary means of dealing with this
+problem.
+
+     The statd and lockd daemons have quite a reputation for extreme
+fragility.  There have been numerous reports about the locking
+mechanism being wedged on a systemwide or even clusterwide basis,
+requiring a reboot to clear.  It is rumored that this wedge, once it
+happens, also blocks local locking.  Presumably killing and restarting
+statd would suffice to clear the wedge, but I haven't verified this.
+
+     There appears to be a limit to how many locks may be in use at a
+time on the system, although the documentation only mentions it in
+passing.  On some of their systems, UCS has increased lockd's ``size
+of the socket buffer'', whatever that means.
+
+C-CLIENT USAGE
+
+     c-client uses flock().  On System V systems, flock() is simulated
+by an emulator that calls fcntl().
+
+
+BEZERK AND MMDF
+
+     Locking in the traditional UNIX formats was largely dictated by
+the status quo in other applications; however, additional protection
+is added against inadvertantly running multiple instances of a
+c-client application on the same mail file.
+
+     (1) c-client attempts to create a .lock file (mail file name with
+``.lock'' appended) whenever it reads from, or writes to, the mail
+file.  This is an exclusive lock, and is held only for short periods
+of time while c-client is actually doing the I/O.  There is a 5-minute
+timeout for this lock, after which it is broken on the presumption
+that it is a stale lock.  If it can not create the .lock file due to
+an EACCES (protection failure) error, it once silently proceeded
+without this lock; this was for systems which protect /usr/spool/mail
+from unprivileged processes creating files.  Today, c-client reports
+an error unless it is built otherwise.  The purpose of this lock is to
+prevent against unfavorable interactions with mail delivery.
+
+     (2) c-client applies a shared flock() to the mail file whenever
+it reads from the mail file, and an exclusive flock() whenever it
+writes to the mail file.  This lock is freed as soon as it finishes
+reading.  The purpose of this lock is to prevent against unfavorable
+interactions with mail delivery.
+
+     (3) c-client applies an exclusive flock() to a file on /tmp
+(whose name represents the device and inode number of the file) when
+it opens the mail file.  This lock is maintained throughout the
+session, although c-client has a feature (called ``kiss of death'')
+which permits c-client to forcibly and irreversibly seize the lock
+from a cooperating c-client application that surrenders the lock on
+demand.  The purpose of this lock is to prevent against unfavorable
+interactions with other instances of c-client (rewriting the mail
+file).
+
+     Mail delivery daemons use lock (1), (2), or both.  Lock (1) works
+over NFS; lock (2) is the only one that works on sites that protect
+/usr/spool/mail against unprivileged file creation.  Prudent mail
+delivery daemons use both forms of locking, and of course so does
+c-client.
+
+     If only lock (2) is used, then multiple processes can read from
+the mail file simultaneously, although in real life this doesn't
+really change things.  The normal state of locks (1) and (2) is
+unlocked except for very brief periods.
+
+
+TENEX AND MTX
+
+     The design of the locking mechanism of these formats was
+motivated by a design to enable multiple simultaneous read/write
+access.  It is almost the reverse of how locking works with
+bezerk/mmdf.
+
+     (1) c-client applies a shared flock() to the mail file when it
+opens the mail file.  It upgrades this lock to exclusive whenever it
+tries to expunge the mail file.  Because of the flock() bug that
+upgrading a lock actually releases it, it will not do so until it has
+acquired an exclusive lock (2) first.  The purpose of this lock is to
+prevent against expunge taking place while some other c-client has the
+mail file open (and thus knows where all the messages are).
+
+     (2) c-client applies a shared flock() to a file on /tmp (whose
+name represents the device and inode number of the file) when it
+parses the mail file.  It applies an exclusive flock() to this file
+when it appends new mail to the mail file, as well as before it
+attempts to upgrade lock (1) to exclusive.  The purpose of this lock
+is to prevent against data being appended while some other c-client is
+parsing mail in the file (to prevent reading of incomplete messages).
+It also protects against the lock-releasing timing race on lock (1).
+
+OBSERVATIONS
+
+     In a perfect world, locking works.  You are protected against
+unfavorable interactions with the mailer and against your own mistake
+by running more than one instance of your mail reader.  In tenex/mtx
+formats, you have the additional benefit that multiple simultaneous
+read/write access works, with the sole restriction being that you
+can't expunge if there are any sharers of the mail file.
+
+     If the mail file is NFS-mounted, then flock() locking is a silent
+no-op.  This is the way BSD implements flock(), and c-client's
+emulation of flock() through fcntl() tests for NFS files and
+duplicates this functionality.  There is no locking protection for
+tenex/mtx mail files at all, and only protection against the mailer
+for bezerk/mmdf mail files.  This has been the accepted state of
+affairs on UNIX for many sad years.
+
+     If you can not create .lock files, it should not affect locking,
+since the flock() locks suffice for all protection.  This is, however,
+not true if the mailer does not check for flock() locking, or if the
+the mail file is NFS-mounted.
+
+     What this means is that there is *no* locking protection at all
+in the case of a client using an NFS-mounted /usr/spool/mail that does
+not permit file creation by unprivileged programs.  It is impossible,
+under these circumstances, for an unprivileged program to do anything
+about it.  Worse, if EACCES errors on .lock file creation are no-op'ed
+, the user won't even know about it.  This is arguably a site
+configuration error.
+
+     The problem with not being able to create .lock files exists on
+System V as well, but the failure modes for flock() -- which is
+implemented via fcntl() -- are different.
+
+     On System V, if the mail file is NFS-mounted and either the
+client or the server lacks a functioning statd/lockd pair, then the
+lock attempt would have hung forever if it weren't for the fact that
+c-client tests for NFS and no-ops the flock() emulator in this case.
+Systemwide or clusterwide failures of statd/lockd have been known to
+occur which cause all locks in all processes to hang (including
+local?).  Without the special NFS test made by c-client, there would
+be no way to request BSD-style no-op behavior, nor is there any way to
+determine that this is happening other than the system being hung.
+
+     The additional locking introduced by c-client was shown to cause
+much more stress on the System V locking mechanism than has
+traditionally been placed upon it.  If it was stressed too far, all
+hell broke loose.  Fortunately, this is now past history.
+
+TRADEOFFS
+
+     c-client based applications have a reasonable chance of winning
+as long as you don't use NFS for remote access to mail files.  That's
+what IMAP is for, after all.  It is, however, very important to
+realize that you can *not* use the lock-upgrade feature by itself
+because it releases the lock as an interim step -- you need to have
+lock-upgrading guarded by another lock.
+
+     If you have the misfortune of using System V, you are likely to
+run into problems sooner or later having to do with statd/lockd.  You
+basically end up with one of three unsatisfactory choices:
+	1) Grit your teeth and live with it.
+	2) Try to make it work:
+	   a) avoid NFS access so as not to stress statd/lockd.
+	   b) try to understand the code in statd/lockd and hack it
+	      to be more robust.
+	   c) hunt out the system limit of locks, if there is one,
+	      and increase it.  Figure on at least two locks per
+	      simultaneous imapd process and four locks per Pine
+	      process.  Better yet, make the limit be 10 times the
+	      maximum number of processes.
+	   d) increase the socket buffer (-S switch to lockd) if
+	      it is offered.  I don't know what this actually does,
+	      but giving lockd more resources to do its work can't
+	      hurt.  Maybe.
+	3) Decide that it can't possibly work, and turn off the 
+	   fcntl() calls in your program.
+	4) If nuking statd/lockd can be done without breaking local
+	   locking, then do so.  This would make SVR4 have the same
+	   limitations as BSD locking, with a couple of additional
+	   bugs.
+	5) Check for NFS, and don't do the fcntl() in the NFS case.
+	   This is what c-client does.
+
+     Note that if you are going to use NFS to access files on a server
+which does not have statd/lockd running, your only choice is (3), (4),
+or (5).  Here again, IMAP can bail you out.
+
+     These problems aren't unique to c-client applications; they have
+also been reported with Elm, Mediamail, and other email tools.
+
+     Of the other two SVR4 locking bugs:
+
+     Programmer awareness is necessary to deal with the bug that you
+can not get an exclusive lock unless the file is open for write.  I
+believe that c-client has fixed all of these cases.
+
+     The problem about opening a second designator smashing any
+current locks on the file has not been addressed satisfactorily yet.
+This is not an easy problem to deal with, especially in c-client which
+really doesn't know what other files/streams may be open by Pine.
+
+     Aren't you so happy that you bought an System V system?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/md5.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,91 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+		       MD5 Based Authentication
+			     Mark Crispin
+			   1 November 1999
+
+
+     The IMAP toolkit makes available two MD5 based authentication
+mechanisms, CRAM-MD5 and APOP.  CRAM-MD5 is described in RFC 2195, and
+is a SASL (RFC 2222) authentication mechanism.  APOP is described in
+RFC 1939, the standard document for the POP3 protocol.
+
+     These mechanisms use the same general idea.  The server issues a
+challenge; the client responds with an MD5 checksum of the challenge
+plus the password; the server in compares the client's response with
+its own calculated value of the checksum.  If the client's response
+matches the server's calulated value, the client is authenticated.
+
+     Unlike plaintext passwords, this form of authentication is
+believed to be secure against the session being monitored; "sniffing"
+the session will not disclose the password nor will it provide usable
+information to authenticate in another session without knowing the
+password.
+
+     The key disadvantage with this form of authentication is that the
+server must know a plaintext form of the password.  In traditional
+UNIX authentication, the server only knows an encrypted form of the
+password.  Consequently, the authentication database for this form of
+authentication must be kept strictly confidential; a bad guy who
+acquires access to this database can access any account in the
+database.
+
+     CRAM-MD5 client support is implemented unconditionally; any
+client application built with the IMAP toolkit will use CRAM-MD5 with
+any server which advertises CRAM-MD5 SASL support.
+
+     CRAM-MD5 and APOP server support is implemented if, and only if,
+the CRAM-MD5 authentication database exists.  By default, the CRAM-MD5
+authentication database is in a UNIX file called
+	/etc/cram-md5.pwd
+It is recommended that this file be protected 0400.
+
+	NOTE: FAILURE TO PROTECT THIS FILE AGAINST UNAUTHORIZED
+	ACCESS WILL COMPROMSE CRAM-MD5 AND APOP AUTHENTICATION
+	FOR ALL USERS LISTED IN THIS DATABASE.
+
+     If the CRAM-MD5 authentication database exists, then plaintext
+password authentication (e.g. the LOGIN command) will also use the
+CRAM-MD5 passwords instead of UNIX passwords.  Alternatively, it is
+possible to build the IMAP toolkit so that plaintext password
+authentication is disabled entirely, by using PASSWDTYPE=nul, e.g.
+	make aix PASSWDTYPE=nul
+
+
+     The CRAM-MD5 authentication database file consists of a series of
+text lines, consisting of a UNIX user name, a single tab, and the
+password.  A line starting with a "#" character is ignored, as are any
+lines which are not in valid format.  For example:
+
+------------------------------Sample------------------------------
+# CRAM-MD5 authentication database
+# Entries are in form <user><tab><password>
+# Lines starting with "#" are comments
+
+bill	hubba-hubba
+hillary	nysenator
+monica	beret
+tripp	wired
+kenstarr	inquisitor
+reno	waco
+jessie	thebody
+billgates	ruleworld
+------------------------------Sample------------------------------
+
+     Every entry in the CRAM-MD5 authentication database must have a
+corresponding entry in the /etc/passwd file.  It is STRONGLY
+RECOMMENDED that the CRAM-MD5 password NOT be the same as the
+/etc/passwd password.  It is permitted for the /etc/passwd password to
+be disabled; /etc/passwd is just used to get the UID, GID, and home
+directory information.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/mixfmt.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,363 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+Last update: 18 December 2006
+
+INTRODUCTION
+
+This file is the descendant of a design document used to specify the
+mix format.  An attempt is being made to keep this document more or
+less current with the way the mix format actually works.
+
+
+1. Mix mailbox naming
+
+Mailbox names correspond to directory names; thus mix format mailboxes
+are "dual-use" (lack both \NoInferiors and \NoSelect).  This will
+satisfy some long-standing requests.
+
+
+2. Mailbox files
+
+A mix format mailbox is a directory with regular files with filenames
+of:
+	.mixmeta	mailbox metadata file
+	.mixindex	message index file (message static data)
+	.mixstatus	message status file (message dynamic data)
+	.mix########	(where ######### is a <hex8>) secondary message
+			 data files.
+	.mix		primary message data file (used in experimental
+			 versions, supported for compatibility only)
+
+2.1 Metadata, index, and status files
+
+The mailbox metadata, index, and status files contain a sequence of
+CRLF-terminated lines.  These files have an update sequence, which is
+a strictly-ascending sequence value.  Any time the file is changed,
+the update sequence is increased; this allows easy detection of
+whether the file has been changed by another process.  For now, this
+update sequence is a modseq (see below).
+
+2.1.1 Metadata file
+
+The mailbox metadata file is called ".mixmeta".  It contains a series
+of CRLF-terminated lines.  The first character of the line is a key that
+identifies the payload of the line, and the remainder of the line is the
+payload.
+	Key	Payload
+	---	-------
+	 S	<hex8>			;; update sequence
+	 V	<hex8>			;; UIDVALIDITY
+	 L	<hex8>			;; UIDLAST
+	 N	<hex8>			;; current new message file
+	 K	[atom 0*(SP atom)]	;; keyword list
+
+All other keys are reserved for future assignment and must be ignored
+(and may be discarded) by software which does not recognize them.  The
+mailbox metadata file is rewritten as part of new mail delivery (so
+APPENDUID/COPYUID can work) and when new keywords are added.
+
+2.1.2 Message static index file
+
+The mailbox message static index file is called ".mixindex".  It contains
+a series of CRLF-terminated lines.  The first character of the line is a
+key that identifies the payload of the line, and the remainder of the line
+is the payload.
+	Key	Payload
+	---	-------
+	 S	<hex8>			;; update sequence
+	 :	<uid>:<date>:<size>:<file>:<pos>:<isiz>:<hsiz>
+	 				;; per-message record
+
+The per-message records contain the following data:
+	<uid>  = <hex8>			;; message UID
+	<date> = <yyyymmddhhmmss+zzzz>	;; internal date
+	<size> = <hex8>			;; rfc822.size
+	<file> = <hex8>			;; message data file (0 = .mix file)
+	<pos>  = <hex8>			;; message position in file
+	<isiz> = <hex8>			;; message internal data size
+	<hsiz> = <hex8>			;; header size (offset to body)
+
+All other keys, and subsequent fields in per-message records, are
+reserved for future assignment and must be ignored (and may be
+discarded) by software which does not recognize them.  The mailbox
+metadata file is appended by new mail delivery and rewritten by
+expunge "burping", and otherwise is not altered.
+
+2.1.3 Message dynamic status file
+
+The mailbox message dynamic status file is called ".mixstatus".  It contains
+a series of CRLF-terminated lines.  The first character of the line is a
+key that identifies the payload of the line, and the remainder of the line
+is the payload.
+   	Key	Payload
+	---	-------
+	 S	<hex8>			;; update sequence
+	 :	<uid>:<uf>:<sf>:<mod>:	;; per-message record
+
+The per-message records contain the following data:
+	<uid>  = <hex8>			;; message UID
+	<keys> = <hex8>			;; keyword flags
+	<flag> = <hex4>			;; system flags
+	<mod>  = <hex8>			;; date/time last modified (modseq)
+
+All other keys, and subsequent fields in per-message records, are
+reserved for future assignment and must be ignored (and may be
+discarded) by software which does not recognize them.  The mailbox
+dynamic idex file is rewritten by flag changes (or any future change
+that alters dynamic data) and is re-read when a session sees that the
+mtime has changed (atime and ctime are not used).
+
+The modseq is an unsigned 32-bit date/time, along with a guarantee
+that this value can not go backwards.  It currently corresponds to the
+time from time(); however, since it is unsigned, it won't run out until
+the year 2106.  In the future, this may be used as a basic for implementing
+the IMAP CONDSTORE extension.
+
+2.2 Message data files
+
+A mix message file is a regular file with filename starting with
+".mix" followed by a <hex8> suffix which indicates the file number.  It
+contains a series of CRLF-terminated lines.  By special dispensation, the
+filename ".mix" is used for file number 0, which was used in experimental
+versions of mix as a "primary" file (this concept no longer exists).
+
+A file number is set to the current modseq when it is created.  If a copy
+or append causes the file to exceed the compiled-in file size limit, a new
+file is started and the metadata is updated accordingly.
+
+Preceeding each message is per-message record with the following format:
+   	Key	Payload
+	---	-------
+					;; per-message record
+	:	:<code>:<uid>:<date>:<size>:
+
+The per-message records contain the following data:
+	<code> = "msg"			;; fixed code
+	<uid>  = <hex8>			;; message UID
+	<date> = <yyyymmddhhmmss+zzzz>	;; internal date
+	<size> = <hex8>			;; rfc822.size
+The message data begins on the next line
+
+Subsequent fields are reserved for future assignment and must be ignored.
+
+
+3. New mail delivery
+
+To deliver a new message, it is necessary to share lock the destination
+metadata file, then get an exclusive lock on the destination index and
+status files.  Once this is done, the new message data is appended to the
+new message file.  The metadata (UIDLAST value), index, and status
+files are all updated to add the new message.
+
+Then all the destination mailbox files are closed.
+
+
+4. Mailbox pinging
+
+The index and status files are share locked.  Initially, sequences are
+remembered as zero, so at open time they are always "altered".
+
+The sequence from the index file is checked; if it is altered the index
+file is read and processed as follows:
+ . If expunge is permitted, then any messages that are not in the index
+   are reported as having been expunged via mm_expunged().
+ . new messages are announced via mm_exists()/mm_recent().
+
+Next, the sequence from the status file is checked.  If it is altered,
+the status file is read and the status updated for any message which is
+new or has an altered modseq in the status file.  Altered modseq messages
+are announced via mm_flags().
+
+Then the index and status files are closed.
+
+
+4. Flag alteration
+
+The status file is exclusive locked.
+
+The sequence from the status file is checked.  If it is altered, the
+status file is read and the status updated for any message which is
+new or has an altered modseq in the status file.  Altered modseq
+messages are announced via mm_flags().
+
+The alterations are then applied for all requested messages, updating
+the modseq for each requestedmessage which changes flags as a result
+of the alteration (alterations which do not result in a change do not
+alter the modseq).  Then the status file is rewritten with a new
+sequence, but only if flags of at least one message was changed.
+
+Then the status file is closed.
+
+
+5. Checkpoint and expunge
+
+Checkpoint is identical to expunge, however it skips the step of expunging
+deleted messages.
+
+The index and status files are locked exclusive.  If expunging, all
+deleted messages are expunged from the index and announced via
+mm_expunged().  The message data is notremoved at this time.
+
+If a checkpoint was requested, or if any messages were expunged, or if
+it remembered that a "burp" was needed, then:
+ . the metadata file is locked exclusive.  If this fails, remember that
+   a burp is needed.  Otherwise perform a burp:
+   . calculate the file byte ranges occupied by expunged messages
+   . for each file needing "burping", open and slide down subsequent file
+     data on top of the expunged messages
+ . update the index and status files
+
+Then the index and status files are closed.
+
+5.1 More details on expunging and "burping"
+
+Shared expunge presents a problem due to the requirements of the IMAP
+protocol.  You can't "burp" away a message until you are certain that
+no sharers have a pointer to any longer.  Consequently, for the nonce
+"burping" out expunged data be defered to an exclusive expunge as in
+mbx format.
+
+If shared burping is ever implemented, then care will be needed not to
+burp data that a session still relies upon.  It's easy enough to burp
+the index files; just create new index files, deleting the old, and
+require that you look for a new one appearing at mailbox ping time
+(when it's safe).  The data files are a problem, since we
+intentionally don't want to keep them open and do want to avoid quota
+problems by overwriting in place.  Also, when you burp you have to
+change the pointers in the index file.
+
+Bottom line: shared burping is too hairy right now, so the first
+version will do exclusive-only burping and not worry about it.  If
+shared burping is really needed, then that routine will need to be
+rewritten.
+
+Shared burping has been a problem for every other IMAP server.  Most
+get it wrong, and cause terrible confusion to clients (including
+client crashes).
+
+
+6. Message data file file roll out strategy
+
+The current new message file is finalized, and a new one started, when
+an append or copy is done that would cause the file to grow to larger
+than a preconfigured size (MIXDATAROLL).  A multi-message copy or
+append is written into its entirety to a single new message file.  In
+the case of multi-copy, the new message file is switched when the sum
+of the sizes of all messages to be copied would cause the current new
+message file to exceed MIXDATAROLL.  In the case of multi-append, only
+the first message is considered; this is due to technical limitations.
+
+7. Error detection
+
+Mix detects bad data in the metadata, index, and status files; and
+declares the stream dead.  It does not unilaterally reassign
+UIDVALIDITY the way that the flat file formats do.
+
+When mix reads a header from the message file, it also reads the
+per-message record and verifies that there is a per-message record there.
+This is a simple test for message file corruption.  It doesn't declare
+the stream dead; it simply issues an error message and returns a
+zero-length string for the message header.  This makes it possible for
+the user to fix the mailbox simply by deleting and expunging any messages
+that are in this state.
+
+
+8. Reconstruct tool
+
+[None of this is implemented yet.]
+
+The layout of these files is designed to make the reconstruct tool be
+as simple as possible.  Much of the need for the reconstruct tool is
+eliminated since the mix format has a much more limited scope of
+writing than the flat file formats; thus there is "less collateral
+damage."
+
+If the metadata file is lost or corrupted, then all keywords are lost;
+if the mailbox has any keywords used in the .mixstatus file, it'll be
+necessary to create some placeholder names.  Otherwise, a new
+UIDVALIDITY can be assigned, and a good UIDLAST value calculated by
+the reconstruct tool.  Since this file is very small, it's not likely
+to be damaged.
+
+If the index file is lost or corrupted, it is possible to reconstruct
+it with no loss by reading all the data files.  However, this could
+cause expunged but not yet burped messages to reappear.
+
+If the status file is lost or corrupted, then flags are lost and
+will revert to a default state of no flags set.  Just deleting the
+corrupted file is good enough.
+
+The reconstruct tool can use the per-message record in the message
+file to locate messages if the recorded sizes and/or messages are
+corrupt.  If that happens, it will need to rebuild the index file
+(with associated changes to the metadata file to change the
+UIDVALIDITY).  That should probably be a manual operation and not be
+part of the default operation or auto-reconstruct.
+
+
+9. Locking strategy
+
+The mix format does not use the traditional c-client /tmp file locking.
+
+The metadata file is open and locked whenever the mailbox is open.
+Normally this is a shared lock, but it will be upgraded to exclusive
+if the mailbox is expunged.  As a guard (since there is no true
+lock-upgrade/downgrade on UNIX), the index exclusive lock must be
+acquired first before upgrading to exclusive.
+
+The index file is shared locked when reading the index, and exclusive
+locked (and read) when appending new messages to the index or when
+expunging (note that expunging also requires an exclusive lock on
+metadata).  Normally, the index file is not open or locked.
+
+The status file is shared locked when reading status, and exclusive
+locked (and read) when updating status.  Normally, the status file is
+not open or locked.
+
+It isn't necessary to lock any of the data files as long as we only
+have exclusive burping.
+
+
+10. Memory usage
+
+The mix format returns a file stringstruct, which is the modern
+c-client behavior.  This prevents imapd from growing to enormous sizes
+due to a godzillagram (how it affects other programs depends upon what
+they do with the returned stringstruct).
+
+
+11. Future extensions
+
+Cached ENVELOPE, BODYSTRUCTURE.  Cyrus does, and this will eliminate
+most of the reason to access the data files.  Possibly cached overviews,
+ala NNTP, instead?
+
+
+Support for ANNOTATION.
+
+
+12. RENAME issues
+
+Mix currently makes no attempt to address the IMAP RENAME problem.
+This occurs when a mailbox is deleted, and another mailbox is renamed
+with that name in place, no attempt is made to reassign UIDVALIDITY
+for this mailbox and all the inferior mailboxes.  This potentially can
+cause problems for a disconnected-use client that has cached status
+for the old mailbox which had that name.
+
+The RENAME problem is a well known flaw in the IMAP protocol.  Few
+servers correctly handle it (among other things, not only do all the
+UIDVALIDITY values have to be changed but this has to be done
+atomically!).  It was a mistake to add RENAME into IMAP, but it's much
+too late to remove it now.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/naming.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,143 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+		       Mailbox Name Conventions
+			     Mark Crispin
+			    5 October 2005
+
+
+Please refer to the file drivers.txt for related information.
+
+
+I. Special names
+
+Special names appear by themselves.
+
+I.a. INBOX
+
+The name INBOX is special and refers to primary incoming message
+mailbox on the local system.
+
+
+I.b. #mhinbox (UNIX only)
+
+The name #mhinbox is special and refers to the primary incoming mh
+format mailbox on the local system.  Don't worry about this if you
+don't know what mh format is.
+
+
+II.  Special prefixes
+
+All names which start with a "#" have a "special prefix" which
+identifies an alternative namespace.  Special prefixes appear in front
+of some additional text which constitutes a suffix.
+
+II.a. #mh/ (UNIX only)
+
+The prefix #mh/ is special and refers to the mh format mailbox named
+with the suffix.  For example, #mh/foo refers to the mh format mailbox
+named foo.  Don't worry about this if you don't know what mh format is.
+
+
+II.b. #news. (UNIX only)
+
+The prefix #news. is special and refers to the newsgroup named with
+the suffix.  For example, #news.comp.mail.misc refers to the newsgroup
+named comp.mail.misc.
+
+
+II.c. #ftp/ (UNIX only)
+
+The prefix #ftp/ is special and refers to the anonymous ftp filesystem
+named with the suffix.  For example, #ftp/foo/bar refers to the file
+/foo/bar in the anonymous FTP filesystem.  Anonymous FTP files are
+available to anonymous IMAP logins.
+
+
+II.d. #public/ (UNIX only)
+
+The prefix #public/ is special and refers to the public files
+filesystem named with the suffix.  For example, #public/foo/bar refers
+to the file /foo/bar in the public filesystem.  Public files are
+available to anonymous IMAP logins.
+
+
+II.e. #shared/ (UNIX only)
+
+The prefix #shared/ is special and refers to the shared files
+filesystem named with the suffix.  For example, #shared/foo/bar
+frefers to the file /foo/bar in the shared filesystem.
+
+
+III. Remote names
+
+All names which start with "{" are remote names, and are in the form
+	"{" remote_system_name [":" port] [flags] "}" [mailbox_name]
+where:
+ remote_system_name	Internet domain name or bracketed IP address
+			 of server.
+ port			optional TCP port number, default is the
+			 default port for that service		
+ flags			optional flags, one of the following:
+  "/service=" service	mailbox access service, default is "imap"
+  "/user=" user		remote user name for login on the server
+  "/authuser=" user	remote authentication user; if specified this
+			 is the user name whose password is used (e.g.
+			 administrator)
+  "/anonymous"		remote access as anonymous user
+  "/debug"		record protocol telemetry in application's
+			 debug log
+  "/secure"		do not transmit a plaintext password over
+			 the network
+  "/imap", "/imap2", "/imap2bis", "/imap4", "/imap4rev1"
+			equivalent to /service=imap
+  "/pop3"		equivalent to /service=pop3
+  "/nntp"		equivalent to /service=nntp
+  "/norsh"		do not use rsh or ssh to establish a preauthenticated
+			 IMAP session
+  "/ssl"		use the Secure Socket Layer to encrypt the session
+  "/validate-cert"	validate certificates from TLS/SSL server (this is the
+			 default behavior)
+  "/novalidate-cert"	do not validate certificates from TLS/SSL server,
+			 needed if server uses self-signed certificates
+  "/tls"		force use of start-TLS to encrypt the session, and
+			 reject connection to servers that do not support it
+  "/tls-sslv23"		use the depreciated SSLv23 client when negotiating
+			 TLS to the server.  This is necessary with some
+			 broken servers which (incorrectly) think that TLS
+			 is just another way of doing SSL.
+  "/notls"		do not do start-TLS to encrypt the session, even
+			 with servers that support it
+  "/readonly"		request read-only mailbox open (IMAP only; ignored
+			 on NNTP, and an error with SMTP and POP3)
+  "/loser"		disable various protocol features and perform various
+			 client-side workarounds; for example, it disables
+			 the SEARCH command in IMAP and does client-side
+			 searching instead.  The precise measures taken by
+			 /loser depend upon the protocol and are subject to
+			 change over time.  /loser is intended for use with
+			 defective servers which do not implement the
+			 protocol specification correctly.  It should be used
+			 only as a last resort since it will seriously
+			 degrade performance.
+ mailbox_name		remote mailbox name, default is INBOX
+
+For example:
+	{imap.foo.com}INBOX
+opens an IMAP connection to system imap.foo.com and selects INBOX.
+
+
+IV. All other names
+
+All other names are treated as local file names, relative to the
+user's home directory.  Read drivers.txt for more details.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/README	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,70 @@
+The following documents are necessary to understand the syntax rules
+most of the remaining documents.  Note that some documents refer to
+RFC 2234 which has been replaced by RFC 5234:
+   rfc5234.txt	Augmented BNF for Syntax Specifications - ABNF
+   rfc4466.txt	Collected Extensions to IMAP4 ABNF
+
+
+The following documents specify the IMAP protocol:
+   rfc3501.txt	Internet Message Access Protocol - Version 4rev1
+
+
+The following documents provide additional information which is useful
+in understanding the IMAP protocol:
+   rfc1733.txt	Distributed Electronic Mail Models in IMAP4
+   rfc2180.txt	IMAP4 Multi-Accessed Mailbox Practice
+   rfc2683.txt	IMAP4 Implementation Recommendations
+   rfc4549.txt	Synchronization Operations for Disconnected IMAP4 Clients
+
+
+The following documents describe extensions to the IMAP protocol.
+Items marked with "*" are supported in this distribution:
+   rfc4314.txt	ACL
+ * rfc3516.txt	BINARY
+   rfc4469.txt	CATENATE
+ * rfc3348.txt	CHILDREN
+   rfc4978.txt	COMPRESS
+   rfc4551.txt	CONDSTORE
+   rfc5161.txt	ENABLE
+ * rfc4731.txt	ESEARCH
+   rfc2971.txt	ID
+ * rfc2177.txt	IDLE
+ * rfc2088.txt	LITERAL+
+ * rfc2221.txt	LOGIN-REFERRALS
+ * rfc2193.txt	MAILBOX-REFERRALS
+ * rfc3502.txt	MULTIAPPEND
+ * rfc2342.txt	NAMESPACE
+   rfc5162.txt	QRESYNC
+   rfc2087.txt	QUOTA
+ * rfc4959.txt	SASL-IR
+ * rfc4315.txt	UIDPLUS
+ * rfc3691.txt	UNSELECT
+   rfc4467.txt	URLAUTH
+ * rfc5032.txt	WITHIN
+
+
+The following documents describe SASL:
+   rfc4422.txt	Simple Authentication and Security Layer (SASL)
+and the SASL mechanisms supported in this distribution:
+   rfc4505.txt	ANONYMOUS
+   rfc2195.txt	CRAM-MD5
+   rfc4752.txt	GSSAPI
+   rfc4616.txt	PLAIN
+
+
+The following documents relate to internationalization issues:
+   rfc4790.txt	Internet Application Protocol Collation Registry
+   rfc5051.txt	i;unicode-casemap - Simple Unicode Collation Algorithm
+
+
+The following documents are primarily of historic interest:
+   rfc1732.txt	IMAP4 Compatibility with IMAP2 and IMAP2bis
+   rfc2061.txt	IMAP4 Compatibility with IMAP2bis
+   rfc2062.txt	Internet Message Access Protocol - Obsolete Syntax
+
+
+The following documents discuss matters which are related to IMAP:
+   rfc3503.txt	MDN Profile for IMAP
+   rfc3656.txt	MUPDATE Distributed Mailbox Database Protocol
+   rfc4468.txt	Message Submission BURL Extension
+   rfc5092.txt	IMAP URL Scheme
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc1732.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,283 @@
+
+
+
+
+
+
+Network Working Group                                         M. Crispin
+Request for Comments: 1732                      University of Washington
+Category: Informational                                    December 1994
+
+
+              IMAP4 COMPATIBILITY WITH IMAP2 AND IMAP2BIS
+
+
+Status of this Memo
+
+   This memo provides information for the Internet community.  This memo
+   does not specify an Internet standard of any kind.  Distribution of
+   this memo is unlimited.
+
+Introduction
+
+   This is a summary of hints and recommendations to enable an IMAP4
+   implementation to interoperate with implementations that conform to
+   earlier specifications.  None of these hints and recommendations are
+   required by the IMAP4 specification; implementors must decide for
+   themselves whether they want their implementation to fail if it
+   encounters old software.
+
+   IMAP4 has been designed to be upwards compatible with earlier
+   specifications.  For the most part, IMAP4 facilities that were not in
+   earlier specifications should be invisible to clients unless the
+   client asks for the facility.
+
+   In some cases, older servers may support some of the capabilities
+   listed as being "new in IMAP4" as experimental extensions to the
+   IMAP2 protocol described in RFC 1176.
+
+   This information may not be complete; it reflects current knowledge
+   of server and client implementations as well as "folklore" acquired
+   in the evolution of the protocol.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin                                                         [Page 1]
+
+RFC 1732                 IMAP4 - Compatibility             December 1994
+
+
+IMAP4 client interoperability with old servers
+
+   In general, a client should be able to discover whether an IMAP2
+   server supports a facility by trial-and-error; if an attempt to use a
+   facility generates a BAD response, the client can assume that the
+   server does not support the facility.
+
+   A quick way to check whether a server implementation supports the
+   IMAP4 specification is to try the CAPABILITY command.  An OK response
+   that includes the IMAP4 capability value indicates a server that
+   supports IMAP4; a BAD response or one without the IMAP4 capability
+   value indicates an older server.
+
+   The following is a list of facilities that are only in IMAP4, and
+   suggestions for how new clients might interoperate with old servers:
+
+   CAPABILITY command
+            A BAD response to this command indicates that the server
+            implements IMAP2 (or IMAP2bis) and not IMAP4.
+
+   AUTHENTICATE command.
+            Use the LOGIN command.
+
+   LSUB and LIST commands
+            Try the RFC 1176 FIND command.
+
+   * in a sequence
+            Use the number of messages in the mailbox from the EXISTS
+            unsolicited response.
+
+   SEARCH extensions (character set, additional criteria)
+            Reformulate the search request using only the searching
+            options listed in search_old in the IMAP4 grammar.  This may
+            entail doing multiple searches to achieve the desired
+            results.
+
+   BODYSTRUCTURE fetch data item
+            Try to fetch the non-extensible BODY data item.
+
+   body section number 0
+            Fetch the entire message and extract the header.
+
+   RFC822.HEADER.LINES and RFC822.HEADER.LINES.NOT fetch data items
+            Use RFC822.HEADER and remove the unwanted information.
+
+   BODY.PEEK[section], RFC822.PEEK, and RFC822.TEXT.PEEK fetch data
+            items Use the corresponding non-PEEK versions and manually
+            clear the \Seen flag as necessary.
+
+
+
+Crispin                                                         [Page 2]
+
+RFC 1732                 IMAP4 - Compatibility             December 1994
+
+
+   UID fetch data item and the UID commands
+            No equivalent capabilitity exists in older servers.
+
+   FLAGS.SILENT, +FLAGS.SILENT, and -FLAGS.SILENT store data items
+            Use the corresponding non-SILENT versions and ignore the
+            untagged FETCH responses which com eback.
+
+
+   The following IMAP4 facilities were introduced in the experimental
+   IMAP2bis revisions to RFC-1176, and may be present in a server that
+   does not support the CAPABILITY command:
+
+   CREATE, DELETE, and RENAME commands
+            To test whether these commands are present, try a CREATE
+            INBOX command.  If the response is NO, these commands are
+            supported by the server.  If the response is BAD, they are
+            not.  Older servers without the CREATE capability may sup-
+            port implicit creation of a mailbox by a COPY command with a
+            non-existant name as the destination.
+
+   APPEND command
+            To test whether this command is present, try to append a
+            zero-length stream to a mailbox name that is known not to
+            exist (or at least, highly unlikely to exist) on the remote
+            system.
+
+   SUBSCRIBE and UNSUBSCRIBE commands
+            Try the form of these commands with the optional MAILBOX
+            keyword.
+
+   EXAMINE command
+            Use the SELECT command instead.
+
+   flags and internal date argument to APPEND command
+            Try the APPEND without any flag list and internal date argu-
+            ments.
+
+   BODY, BODY[section], and FULL fetch data items
+            Use RFC822.TEXT and ALL instead.  Server does not support
+            MIME.
+
+   PARTIAL command
+            Use the appropriate FETCH command and ignore the unwanted
+            data.
+
+
+   IMAP4 client implementations must accept all responses and data for-
+   mats documented in the IMAP4 specification, including those labeled
+
+
+
+Crispin                                                         [Page 3]
+
+RFC 1732                 IMAP4 - Compatibility             December 1994
+
+
+   as obsolete.  This includes the COPY and STORE unsolicited responses
+   and the old format of dates and times.  In particular, client imple-
+   mentations must not treat a date/time as a fixed format string; nor
+   may they assume that the time begins at a particular octet.
+
+   IMAP4 client implementations must not depend upon the presence of any
+   server extensions that are not in the base IMAP4 specification.
+
+   The experimental IMAP2bis version specified that the TRYCREATE spe-
+   cial information token is sent as a separate unsolicited OK response
+   instead of inside the NO response.
+
+   The FIND BBOARDS, FIND ALL.BBOARDS, and BBOARD commands of RFC 1176
+   are removed from IMAP4.  There is no equivalent to the bboard com-
+   mands, which provided a separate namespace with implicit restrictions
+   on what may be done in that namespace.
+
+   Older server implementations may automatically create the destination
+   mailbox on COPY if that mailbox does not already exist.  This was how
+   a new mailbox was created in older specifications.  If the server
+   does not support the CREATE command (see above for how to test for
+   this), it will probably create a mailbox on COPY.
+
+   Older server implementations may not preserve flags or internal dates
+   on COPY.  Some server implementations may not permit the preservation
+   of certain flags on COPY or their setting with APPEND as site policy.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin                                                         [Page 4]
+
+RFC 1732                 IMAP4 - Compatibility             December 1994
+
+
+IMAP4 server interoperability with old clients
+
+   In general, there should be no interoperation problem between a
+   server conforming to the IMAP4 specification and a well-written
+   client that conforms to an earlier specification.  Known problems are
+   noted below:
+
+      Poor wording in the description of the CHECK command in earlier
+      specifications implied that a CHECK command is the way to get the
+      current number of messages in the mailbox.  This is incorrect.  A
+      CHECK command does not necessarily result in an EXISTS response.
+      Clients must remember the most recent EXISTS value sent from the
+      server, and should not generate unnecessary CHECK commands.
+
+      An incompatibility exists with COPY in IMAP4.  COPY in IMAP4
+      servers does not automatically create the destination mailbox if
+      that mailbox does not already exist.  This may cause problems with
+      old clients that expect automatic mailbox creation in COPY.
+
+      The PREAUTH unsolicited response is new in IMAP4.  It is highly
+      unlikely that an old client would ever see this response.
+
+      The format of dates and times has changed due to the impending end
+      of the century.  Clients that fail to accept a four-digit year or
+      a signed four-digit timezone value will not work properly with
+      IMAP4.
+
+      An incompatibility exists with the use of "\" in quoted strings.
+      This is best avoided by using literals instead of quoted strings
+      if "\" or <"> is embedded in the string.
+
+Security Considerations
+
+   Security issues are not discussed in this memo.
+
+Author's Address:
+
+   Mark R. Crispin
+   Networks and Distributed Computing, JE-30
+   University of Washington
+   Seattle, WA  98195
+
+   Phone: (206) 543-5762
+
+   EMail: MRC@CAC.Washington.EDU
+
+
+
+
+
+
+Crispin                                                         [Page 5]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc1733.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,171 @@
+
+
+
+
+
+
+Network Working Group                                         M. Crispin
+Request for Comments: 1733                      University of Washington
+Category: Informational                                    December 1994
+
+
+              DISTRIBUTED ELECTRONIC MAIL MODELS IN IMAP4
+
+
+Status of this Memo
+
+   This memo provides information for the Internet community.  This memo
+   does not specify an Internet standard of any kind.  Distribution of
+   this memo is unlimited.
+
+
+Distributed Electronic Mail Models
+
+   There are three fundamental models of client/server email: offline,
+   online, and disconnected use.  IMAP4 can be used in any one of these
+   three models.
+
+   The offline model is the most familiar form of client/server email
+   today, and is used by protocols such as POP-3 (RFC 1225) and UUCP.
+   In this model, a client application periodically connects to a
+   server.  It downloads all the pending messages to the client machine
+   and deletes these from the server.  Thereafter, all mail processing
+   is local to the client.  This model is store-and-forward; it moves
+   mail on demand from an intermediate server (maildrop) to a single
+   destination machine.
+
+   The online model is most commonly used with remote filesystem
+   protocols such as NFS.  In this model, a client application
+   manipulates mailbox data on a server machine.  A connection to the
+   server is maintained throughout the session.  No mailbox data are
+   kept on the client; the client retrieves data from the server as is
+   needed.  IMAP4 introduces a form of the online model that requires
+   considerably less network bandwidth than a remote filesystem
+   protocol, and provides the opportunity for using the server for CPU
+   or I/O intensive functions such as parsing and searching.
+
+   The disconnected use model is a hybrid of the offline and online
+   models, and is used by protocols such as PCMAIL (RFC 1056).  In this
+   model, a client user downloads some set of messages from the server,
+   manipulates them offline, then at some later time uploads the
+   changes.  The server remains the authoritative repository of the
+   messages.  The problems of synchronization (particularly when
+   multiple clients are involved) are handled through the means of
+   unique identifiers for each message.
+
+
+
+Crispin                                                         [Page 1]
+
+RFC 1733                     IMAP4 - Model                 December 1994
+
+
+   Each of these models have their own strengths and weaknesses:
+
+      Feature                               Offline Online  Disc
+      -------                               ------- ------  ----
+      Can use multiple clients               NO      YES     YES
+      Minimum use of server connect time     YES     NO      YES
+      Minimum use of server resources        YES     NO      NO
+      Minimum use of client disk resources   NO      YES     NO
+      Multiple remote mailboxes              NO      YES     YES
+      Fast startup                           NO      YES     NO
+      Mail processing when not online        YES     NO      YES
+
+   Although IMAP4 has its origins as a protocol designed to accommodate
+   the online model, it can support the other two models as well.  This
+   makes possible the creation of clients that can be used in any of the
+   three models.  For example, a user may wish to switch between the
+   online and disconnected models on a regular basis (e.g. owing to
+   travel).
+
+   IMAP4 is designed to transmit message data on demand, and to provide
+   the facilities necessary for a client to decide what data it needs at
+   any particular time.  There is generally no need to do a wholesale
+   transfer of an entire mailbox or even of the complete text of a
+   message.  This makes a difference in situations where the mailbox is
+   large, or when the link to the server is slow.
+
+   More specifically, IMAP4 supports server-based RFC 822 and MIME
+   processing.  With this information, it is possible for a client to
+   determine in advance whether it wishes to retrieve a particular
+   message or part of a message.  For example, a user connected to an
+   IMAP4 server via a dialup link can determine that a message has a
+   2000 byte text segment and a 40 megabyte video segment, and elect to
+   fetch only the text segment.
+
+   In IMAP4, the client/server relationship lasts only for the duration
+   of the TCP connection.  There is no registration of clients.  Except
+   for any unique identifiers used in disconnected use operation, the
+   client initially has no knowledge of mailbox state and learns it from
+   the IMAP4 server when a mailbox is selected.  This initial transfer
+   is minimal; the client requests additional state data as it needs.
+
+   As noted above, the choice for the location of mailbox data depends
+   upon the model chosen.  The location of message state (e.g. whether
+   or not a message has been read or answered) is also determined by the
+   model, and is not necessarily the same as the location of the mailbox
+   data.  For example, in the online model message state can be co-
+   located with mailbox data; it can also be located elsewhere (on the
+   client or on a third agent) using unique identifiers to achieve
+
+
+
+Crispin                                                         [Page 2]
+
+RFC 1733                     IMAP4 - Model                 December 1994
+
+
+   common reference across sessions.  The latter is particularly useful
+   with a server that exports public data such as netnews and does not
+   maintain per-user state.
+
+   The IMAP4 protocol provides the generality to implement these
+   different models.  This is done by means of server and (especially)
+   client configuration, and not by requiring changes to the protocol or
+   the implementation of the protocol.
+
+
+Security Considerations
+
+   Security issues are not discussed in this memo.
+
+
+Author's Address:
+
+   Mark R. Crispin
+   Networks and Distributed Computing, JE-30
+   University of Washington
+   Seattle, WA  98195
+
+   Phone: (206) 543-5762
+
+   EMail: MRC@CAC.Washington.EDU
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin                                                         [Page 3]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc2061.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,171 @@
+
+
+
+
+
+
+Network Working Group                                         M. Crispin
+Request for Comments: 2061                      University of Washington
+Category: Informational                                    December 1996
+
+
+                   IMAP4 COMPATIBILITY WITH IMAP2BIS
+
+Status of this Memo
+
+   This memo provides information for the Internet community.  This memo
+   does not specify an Internet standard of any kind.  Distribution of
+   this memo is unlimited.
+
+Introduction
+
+   The Internet Message Access Protocol (IMAP) has been through several
+   revisions and variants in its 10-year history.  Many of these are
+   either extinct or extremely rare; in particular, several undocumented
+   variants and the variants described in RFC 1064, RFC 1176, and RFC
+   1203 fall into this category.
+
+   One variant, IMAP2bis, is at the time of this writing very common and
+   has been widely distributed with the Pine mailer.  Unfortunately,
+   there is no definite document describing IMAP2bis.  This document is
+   intended to be read along with RFC 1176 and the most recent IMAP4
+   specification (RFC 2060) to assist implementors in creating an IMAP4
+   implementation to interoperate with implementations that conform to
+   earlier specifications.  Nothing in this document is required by the
+   IMAP4 specification; implementors must decide for themselves whether
+   they want their implementation to fail if it encounters old software.
+
+   At the time of this writing, IMAP4 has been updated from the version
+   described in RFC 1730.  An implementor who wishes to interoperate
+   with both RFC 1730 and RFC 2060 should refer to both documents.
+
+   This information is not complete; it reflects current knowledge of
+   server and client implementations as well as "folklore" acquired in
+   the evolution of the protocol.  It is NOT a description of how to
+   interoperate with all variants of IMAP, but rather with the old
+   variant that is most likely to be encountered.  For detailed
+   information on interoperating with other old variants, refer to RFC
+   1732.
+
+IMAP4 client interoperability with IMAP2bis servers
+
+   A quick way to check whether a server implementation supports the
+   IMAP4 specification is to try the CAPABILITY command.  An OK response
+   will indicate which variant(s) of IMAP4 are supported by the server.
+
+
+
+Crispin                      Informational                      [Page 1]
+
+RFC 2061                  IMAP4 Compatibility              December 1996
+
+
+   If the client does not find any of its known variant in the response,
+   it should treat the server as IMAP2bis.  A BAD response indicates an
+   IMAP2bis or older server.
+
+   Most IMAP4 facilities are in IMAP2bis.  The following exceptions
+   exist:
+
+   CAPABILITY command
+            The absense of this command indicates IMAP2bis (or older).
+
+   AUTHENTICATE command.
+            Use the LOGIN command.
+
+   LSUB, SUBSCRIBE, and UNSUBSCRIBE commands
+            No direct functional equivalent.  IMAP2bis had a concept
+            called "bboards" which is not in IMAP4.  RFC 1176 supported
+            these with the BBOARD and FIND BBOARDS commands.  IMAP2bis
+            augmented these with the FIND ALL.BBOARDS, SUBSCRIBE BBOARD,
+            and UNSUBSCRIBE BBOARD commands.  It is recommended that
+            none of these commands be implemented in new software,
+            including servers that support old clients.
+
+   LIST command
+            Use the command FIND ALL.MAILBOXES, which has a similar syn-
+            tax and response to the FIND MAILBOXES command described in
+            RFC 1176.  The FIND MAILBOXES command is unlikely to produce
+            useful information.
+
+   * in a sequence
+            Use the number of messages in the mailbox from the EXISTS
+            unsolicited response.
+
+   SEARCH extensions (character set, additional criteria)
+            Reformulate the search request using only the RFC 1176 syn-
+            tax.  This may entail doing multiple searches to achieve the
+            desired results.
+
+   BODYSTRUCTURE fetch data item
+            Use the non-extensible BODY data item.
+
+   body sections HEADER, TEXT, MIME, HEADER.FIELDS, HEADER.FIELDS.NOT
+            Use body section numbers only.
+
+   BODY.PEEK[section]
+            Use BODY[section] and manually clear the \Seen flag as
+            necessary.
+
+
+
+
+
+Crispin                      Informational                      [Page 2]
+
+RFC 2061                  IMAP4 Compatibility              December 1996
+
+
+   FLAGS.SILENT, +FLAGS.SILENT, and -FLAGS.SILENT store data items
+            Use the corresponding non-SILENT versions and ignore the
+            untagged FETCH responses which come back.
+
+   UID fetch data item and the UID commands
+            No functional equivalent.
+
+   CLOSE command
+            No functional equivalent.
+
+
+   In IMAP2bis, the TRYCREATE special information token is sent as a
+   separate unsolicited OK response instead of inside the NO response.
+
+   IMAP2bis is ambiguous about whether or not flags or internal dates
+   are preserved on COPY.  It is impossible to know what behavior is
+   supported by the server.
+
+IMAP4 server interoperability with IMAP2bis clients
+
+   The only interoperability problem between an IMAP4 server and a
+   well-written IMAP2bis client is an incompatibility with the use of
+   "\" in quoted strings.  This is best avoided by using literals
+   instead of quoted strings if "\" or <"> is embedded in the string.
+
+Security Considerations
+
+   Security issues are not discussed in this memo.
+
+Author's Address
+
+   Mark R. Crispin
+   Networks and Distributed Computing
+   University of Washington
+   4545 15th Aveneue NE
+   Seattle, WA  98105-4527
+
+   Phone: (206) 543-5762
+   EMail: MRC@CAC.Washington.EDU
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin                      Informational                      [Page 3]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc2062.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,451 @@
+
+
+
+
+
+
+Network Working Group                                         M. Crispin
+Request for Comments: 2062                      University of Washington
+Category: Informational                                    December 1996
+
+
+           Internet Message Access Protocol - Obsolete Syntax
+
+Status of this Memo
+
+   This memo provides information for the Internet community.  This memo
+   does not specify an Internet standard of any kind.  Distribution of
+   this memo is unlimited.
+
+Abstract
+
+   This document describes obsolete syntax which may be encountered by
+   IMAP4 implementations which deal with older versions of the Internet
+   Mail Access Protocol.  IMAP4 implementations MAY implement this
+   syntax in order to maximize interoperability with older
+   implementations.
+
+   This document repeats information from earlier documents, most
+   notably RFC 1176 and RFC 1730.
+
+Obsolete Commands and Fetch Data Items
+
+   The following commands are OBSOLETE.  It is NOT required to support
+   any of these commands or fetch data items in new server
+   implementations.  These commands are documented here for the benefit
+   of implementors who may wish to support them for compatibility with
+   old client implementations.
+
+   The section headings of these commands are intended to correspond
+   with where they would be located in the main document if they were
+   not obsoleted.
+
+6.3.OBS.1.      FIND ALL.MAILBOXES Command
+
+   Arguments:  mailbox name with possible wildcards
+
+   Data:       untagged responses: MAILBOX
+
+   Result:     OK - find completed
+               NO - find failure: can't list that name
+               BAD - command unknown or arguments invalid
+
+
+
+
+
+
+Crispin                      Informational                      [Page 1]
+
+RFC 2062                     IMAP4 Obsolete                December 1996
+
+
+      The FIND ALL.MAILBOXES command returns a subset of names from the
+      complete set of all names available to the user.  It returns zero
+      or more untagged MAILBOX replies.  The mailbox argument to FIND
+      ALL.MAILBOXES is similar to that for LIST with an empty reference,
+      except that the characters "%" and "?" match a single character.
+
+   Example:    C: A002 FIND ALL.MAILBOXES *
+               S: * MAILBOX blurdybloop
+               S: * MAILBOX INBOX
+               S: A002 OK FIND ALL.MAILBOXES completed
+
+6.3.OBS.2.      FIND MAILBOXES Command
+
+   Arguments:  mailbox name with possible wildcards
+
+   Data:       untagged responses: MAILBOX
+
+   Result:     OK - find completed
+               NO - find failure: can't list that name
+               BAD - command unknown or arguments invalid
+
+      The FIND MAILBOXES command returns a subset of names from the set
+      of names that the user has declared as being "active" or
+      "subscribed".  It returns zero or more untagged MAILBOX replies.
+      The mailbox argument to FIND MAILBOXES is similar to that for LSUB
+      with an empty reference, except that the characters "%" and "?"
+      match a single character.
+
+   Example:    C: A002 FIND MAILBOXES *
+               S: * MAILBOX blurdybloop
+               S: * MAILBOX INBOX
+               S: A002 OK FIND MAILBOXES completed
+
+6.3.OBS.3.      SUBSCRIBE MAILBOX Command
+
+   Arguments:  mailbox name
+
+   Data:       no specific data for this command
+
+   Result:     OK - subscribe completed
+               NO - subscribe failure: can't subscribe to that name
+               BAD - command unknown or arguments invalid
+
+      The SUBSCRIBE MAILBOX command is identical in effect to the
+      SUBSCRIBE command.  A server which implements this command must be
+      able to distinguish between a SUBSCRIBE MAILBOX command and a
+      SUBSCRIBE command with a mailbox name argument of "MAILBOX".
+
+
+
+
+Crispin                      Informational                      [Page 2]
+
+RFC 2062                     IMAP4 Obsolete                December 1996
+
+
+   Example:    C: A002 SUBSCRIBE MAILBOX #news.comp.mail.mime
+               S: A002 OK SUBSCRIBE MAILBOX to #news.comp.mail.mime
+               completed
+               C: A003 SUBSCRIBE MAILBOX
+               S: A003 OK SUBSCRIBE to MAILBOX completed
+
+
+6.3.OBS.4.      UNSUBSCRIBE MAILBOX Command
+
+   Arguments:  mailbox name
+
+   Data:       no specific data for this command
+
+   Result:     OK - unsubscribe completed
+               NO - unsubscribe failure: can't unsubscribe that name
+               BAD - command unknown or arguments invalid
+
+      The UNSUBSCRIBE MAILBOX command is identical in effect to the
+      UNSUBSCRIBE command.  A server which implements this command must
+      be able to distinguish between a UNSUBSCRIBE MAILBOX command and
+      an UNSUBSCRIBE command with a mailbox name argument of "MAILBOX".
+
+   Example:    C: A002 UNSUBSCRIBE MAILBOX #news.comp.mail.mime
+               S: A002 OK UNSUBSCRIBE MAILBOX from #news.comp.mail.mime
+               completed
+               C: A003 UNSUBSCRIBE MAILBOX
+               S: A003 OK UNSUBSCRIBE from MAILBOX completed
+
+6.4.OBS.1       PARTIAL Command
+
+   Arguments:  message sequence number
+               message data item name
+               position of first octet
+               number of octets
+
+   Data:       untagged responses: FETCH
+
+   Result:     OK - partial completed
+               NO - partial error: can't fetch that data
+               BAD - command unknown or arguments invalid
+
+      The PARTIAL command is equivalent to the associated FETCH command,
+      with the added functionality that only the specified number of
+      octets, beginning at the specified starting octet, are returned.
+      Only a single message can be fetched at a time.  The first octet
+      of a message, and hence the minimum for the starting octet, is
+      octet 1.
+
+
+
+
+Crispin                      Informational                      [Page 3]
+
+RFC 2062                     IMAP4 Obsolete                December 1996
+
+
+      The following FETCH items are valid data for PARTIAL: RFC822,
+      RFC822.HEADER, RFC822.TEXT, BODY[<section>], as well as any .PEEK
+      forms of these.
+
+      Any partial fetch that attempts to read beyond the end of the text
+      is truncated as appropriate.  If the starting octet is beyond the
+      end of the text, an empty string is returned.
+
+      The data are returned with the FETCH response.  There is no
+      indication of the range of the partial data in this response.  It
+      is not possible to stream multiple PARTIAL commands of the same
+      data item without processing and synchronizing at each step, since
+      streamed commands may be executed out of order.
+
+      There is no requirement that partial fetches follow any sequence.
+      For example, if a partial fetch of octets 1 through 10000 breaks
+      in an awkward place for BASE64 decoding, it is permitted to
+      continue with a partial fetch of 9987 through 19987, etc.
+
+      The handling of the \Seen flag is the same as in the associated
+      FETCH command.
+
+   Example:    C: A005 PARTIAL 4 RFC822 1 1024
+               S: * 1 FETCH (RFC822 {1024}
+               S: Return-Path: <gray@cac.washington.edu>
+               S: ...
+               S: .........  FLAGS (\Seen))
+               S: A005 OK PARTIAL completed
+
+6.4.5.OBS.1     Obsolete FETCH Data Items
+
+   The following FETCH data items are obsolete:
+
+      BODY[<...>0]   A body part number of 0 is the [RFC-822] header of
+                     the message.  BODY[0] is functionally equivalent to
+                     BODY[HEADER], differing in the syntax of the
+                     resulting untagged FETCH data (BODY[0] is
+                     returned).
+
+      RFC822.HEADER.LINES <header_list>
+                     Functionally equivalent to BODY.PEEK[HEADER.LINES
+                     <header_list>], differing in the syntax of the
+                     resulting untagged FETCH data (RFC822.HEADER is
+                     returned).
+
+
+
+
+
+
+
+Crispin                      Informational                      [Page 4]
+
+RFC 2062                     IMAP4 Obsolete                December 1996
+
+
+      RFC822.HEADER.LINES.NOT <header_list>
+                     Functionally equivalent to
+                     BODY.PEEK[HEADER.LINES.NOT <header_list>],
+                     differing in the syntax of the resulting untagged
+                     FETCH data (RFC822.HEADER is returned).
+
+      RFC822.PEEK    Functionally equivalent to BODY.PEEK[], except for
+                     the syntax of the resulting untagged FETCH data
+                     (RFC822 is returned).
+
+      RFC822.TEXT.PEEK
+                     Functionally equivalent to BODY.PEEK[TEXT], except
+                     for the syntax of the resulting untagged FETCH data
+                     (RFC822.TEXT is returned).
+
+Obsolete Responses
+
+   The following responses are OBSOLETE.  Except as noted below, these
+   responses MUST NOT be transmitted by new server implementations.
+   Client implementations SHOULD accept these responses.
+
+   The section headings of these responses are intended to correspond
+   with where they would be located in the main document if they were
+   not obsoleted.
+
+7.2.OBS.1.      MAILBOX Response
+
+   Data:       name
+
+      The MAILBOX response MUST NOT be transmitted by server
+      implementations except in response to the obsolete FIND MAILBOXES
+      and FIND ALL.MAILBOXES commands.  Client implementations that do
+      not use these commands MAY ignore this response.  It is documented
+      here for the benefit of implementors who may wish to support it
+      for compatibility with old client implementations.
+
+      This response occurs as a result of the FIND MAILBOXES and FIND
+      ALL.MAILBOXES commands.  It returns a single name that matches the
+      FIND specification.  There are no attributes or hierarchy
+      delimiter.
+
+   Example:    S: * MAILBOX blurdybloop
+
+
+
+
+
+
+
+
+
+Crispin                      Informational                      [Page 5]
+
+RFC 2062                     IMAP4 Obsolete                December 1996
+
+
+7.3.OBS.1.      COPY Response
+
+   Data:       none
+
+      The COPY response MUST NOT be transmitted by new server
+      implementations.  Client implementations MUST ignore the COPY
+      response.  It is documented here for the benefit of client
+      implementors who may encounter this response from old server
+      implementations.
+
+      In some experimental versions of this protocol, this response was
+      returned in response to a COPY command to indicate on a
+      per-message basis that the message was copied successfully.
+
+   Example:    S: * 44 COPY
+
+7.3.OBS.2.      STORE Response
+
+   Data:       message data
+
+      The STORE response MUST NOT be transmitted by new server
+      implementations.  Client implementations MUST treat the STORE
+      response as equivalent to the FETCH response.  It is documented
+      here for the benefit of client implementors who may encounter this
+      response from old server implementations.
+
+      In some experimental versions of this protocol, this response was
+      returned instead of FETCH in response to a STORE command to report
+      the new value of the flags.
+
+   Example:    S: * 69 STORE (FLAGS (\Deleted))
+
+Formal Syntax of Obsolete Commands and Responses
+
+   Each obsolete syntax rule that is suffixed with "_old" is added to
+   the corresponding name in the formal syntax.  For example,
+   command_auth_old adds the FIND command to command_auth.
+
+   command_auth_old ::= find
+
+   command_select_old
+                   ::= partial
+
+   date_year_old   ::= 2digit
+                       ;; (year - 1900)
+
+   date_time_old   ::= <"> date_day_fixed "-" date_month "-" date_year
+                       SPACE time "-" zone_name <">
+
+
+
+Crispin                      Informational                      [Page 6]
+
+RFC 2062                     IMAP4 Obsolete                December 1996
+
+
+   find            ::= "FIND" SPACE ["ALL."] "MAILBOXES" SPACE
+                       list_mailbox
+
+   fetch_att_old   ::= "RFC822.HEADER.LINES" [".NOT"] SPACE header_list /
+                       fetch_text_old
+
+   fetch_text_old  ::= "BODY" [".PEEK"] section_old /
+                       "RFC822" [".HEADER" / ".TEXT" [".PEEK"]]
+
+   msg_data_old    ::= "COPY" / ("STORE" SPACE msg_att)
+
+   partial         ::= "PARTIAL" SPACE nz_number SPACE fetch_text_old SPACE
+                       number SPACE number
+
+   section_old     ::= "[" (number ["." number]) "]"
+
+   subscribe_old   ::= "SUBSCRIBE" SPACE "MAILBOX" SPACE mailbox
+
+   unsubscribe_old ::= "UNSUBSCRIBE" SPACE "MAILBOX" SPACE mailbox
+
+   zone_name       ::= "UT" / "GMT" / "Z" /                ;; +0000
+                       "AST" / "EDT" /                     ;; -0400
+                       "EST" / "CDT" /                     ;; -0500
+                       "CST" / "MDT" /                     ;; -0600
+                       "MST" / "PDT" /                     ;; -0700
+                       "PST" / "YDT" /                     ;; -0800
+                       "YST" / "HDT" /                     ;; -0900
+                       "HST" / "BDT" /                     ;; -1000
+                       "BST" /                             ;; -1100
+                       "A" / "B" / "C" / "D" / "E" / "F" / ;; +1 to +6
+                       "G" / "H" / "I" / "K" / "L" / "M" / ;; +7 to +12
+                       "N" / "O" / "P" / "Q" / "R" / "S" / ;; -1 to -6
+                       "T" / "U" / "V" / "W" / "X" / "Y"   ;; -7 to -12
+
+Security Considerations
+
+   Security issues are not discussed in this memo.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin                      Informational                      [Page 7]
+
+RFC 2062                     IMAP4 Obsolete                December 1996
+
+
+Author's Address
+
+   Mark R. Crispin
+   Networks and Distributed Computing
+   University of Washington
+   4545 15th Aveneue NE
+   Seattle, WA  98105-4527
+
+   Phone: (206) 543-5762
+   EMail: MRC@CAC.Washington.EDU
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin                      Informational                      [Page 8]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc2087.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,283 @@
+
+
+
+
+
+
+Network Working Group                                           J. Myers
+Request for Comments: 2087                               Carnegie Mellon
+Category: Standards Track                                   January 1997
+
+
+                         IMAP4 QUOTA extension
+
+Status of this Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+1.   Abstract
+
+   The QUOTA extension of the Internet Message Access Protocol [IMAP4]
+   permits administrative limits on resource usage (quotas) to be
+   manipulated through the IMAP protocol.
+
+Table of Contents
+
+   1.   Abstract........................................... 1
+   2.   Conventions Used in this Document.................. 1
+   3.   Introduction and Overview.......................... 2
+   4.   Commands........................................... 2
+   4.1. SETQUOTA Command................................... 2
+   4.2. GETQUOTA Command................................... 2
+   4.3. GETQUOTAROOT Command............................... 3
+   5.   Responses.......................................... 3
+   5.1. QUOTA Response..................................... 3
+   5.2. QUOTAROOT Response................................. 4
+   6.   Formal syntax...................................... 4
+   7.   References......................................... 5
+   8.   Security Considerations............................ 5
+   9.   Author's Address................................... 5
+
+
+2.   Conventions Used in this Document
+
+   In examples, "C:" and "S:" indicate lines sent by the client and
+   server respectively.
+
+
+
+
+
+
+
+
+Myers                       Standards Track                     [Page 1]
+
+RFC 2087                         QUOTA                      January 1997
+
+
+3.   Introduction and Overview
+
+   The QUOTA extension is present in any IMAP4 implementation which
+   returns "QUOTA" as one of the supported capabilities to the
+   CAPABILITY command.
+
+   An IMAP4 server which supports the QUOTA capability may support
+   limits on any number of resources.  Each resource has an atom name
+   and an implementation-defined interpretation which evaluates to an
+   integer.  Examples of such resources are:
+
+      Name       Interpretation
+
+      STORAGE    Sum of messages' RFC822.SIZE, in units of 1024 octets
+      MESSAGE    Number of messages
+
+
+   Each mailbox has zero or more implementation-defined named "quota
+   roots".  Each quota root has zero or more resource limits.  All
+   mailboxes that share the same named quota root share the resource
+   limits of the quota root.
+
+   Quota root names do not necessarily have to match the names of
+   existing mailboxes.
+
+4.   Commands
+
+4.1. SETQUOTA Command
+
+   Arguments:  quota root
+               list of resource limits
+
+   Data:       untagged responses: QUOTA
+
+   Result:     OK - setquota completed
+               NO - setquota error: can't set that data
+               BAD - command unknown or arguments invalid
+
+   The SETQUOTA command takes the name of a mailbox quota root and a
+   list of resource limits. The resource limits for the named quota root
+   are changed to be the specified limits.  Any previous resource limits
+   for the named quota root are discarded.
+
+   If the named quota root did not previously exist, an implementation
+   may optionally create it and change the quota roots for any number of
+   existing mailboxes in an implementation-defined manner.
+
+
+
+
+
+Myers                       Standards Track                     [Page 2]
+
+RFC 2087                         QUOTA                      January 1997
+
+
+   Example:    C: A001 SETQUOTA "" (STORAGE 512)
+               S: * QUOTA "" (STORAGE 10 512)
+               S: A001 OK Setquota completed
+
+4.2. GETQUOTA Command
+
+   Arguments:  quota root
+
+   Data:       untagged responses: QUOTA
+
+   Result:     OK - getquota completed
+               NO - getquota  error:  no  such  quota  root,  permission
+               denied
+               BAD - command unknown or arguments invalid
+
+   The GETQUOTA command takes the name of a quota root and returns the
+   quota root's resource usage and limits in an untagged QUOTA response.
+
+   Example:    C: A003 GETQUOTA ""
+               S: * QUOTA "" (STORAGE 10 512)
+               S: A003 OK Getquota completed
+
+4.3. GETQUOTAROOT Command
+
+   Arguments:  mailbox name
+
+   Data:       untagged responses: QUOTAROOT, QUOTA
+
+   Result:     OK - getquota completed
+               NO - getquota error: no such mailbox, permission denied
+               BAD - command unknown or arguments invalid
+
+   The GETQUOTAROOT command takes the name of a mailbox and returns the
+   list of quota roots for the mailbox in an untagged QUOTAROOT
+   response.  For each listed quota root, it also returns the quota
+   root's resource usage and limits in an untagged QUOTA response.
+
+   Example:    C: A003 GETQUOTAROOT INBOX
+               S: * QUOTAROOT INBOX ""
+               S: * QUOTA "" (STORAGE 10 512)
+               S: A003 OK Getquota completed
+
+
+
+
+
+
+
+
+
+
+Myers                       Standards Track                     [Page 3]
+
+RFC 2087                         QUOTA                      January 1997
+
+
+5.   Responses
+
+5.1. QUOTA Response
+
+   Data:       quota root name
+               list of resource names, usages, and limits
+
+      This response occurs as a result of a GETQUOTA or GETQUOTAROOT
+      command. The first string is the name of the quota root for which
+      this quota applies.
+
+      The name is followed by a S-expression format list of the resource
+      usage and limits of the quota root.  The list contains zero or
+      more triplets.  Each triplet conatins a resource name, the current
+      usage of the resource, and the resource limit.
+
+      Resources not named in the list are not limited in the quota root.
+      Thus, an empty list means there are no administrative resource
+      limits in the quota root.
+
+      Example:    S: * QUOTA "" (STORAGE 10 512)
+
+5.2. QUOTAROOT Response
+
+   Data:       mailbox name
+               zero or more quota root names
+
+      This response occurs as a result of a GETQUOTAROOT command.  The
+      first string is the mailbox and the remaining strings are the
+      names of the quota roots for the mailbox.
+
+      Example:    S: * QUOTAROOT INBOX ""
+                  S: * QUOTAROOT comp.mail.mime
+
+6.   Formal syntax
+
+   The following syntax specification uses the augmented Backus-Naur
+   Form (BNF) notation as specified in RFC 822 with one exception; the
+   delimiter used with the "#" construct is a single space (SP) and not
+   one or more commas.
+
+   Except as noted otherwise, all alphabetic characters are case-
+   insensitive.  The use of upper or lower case characters to define
+   token strings is for editorial clarity only.  Implementations MUST
+   accept these strings in a case-insensitive fashion.
+
+
+
+
+
+
+Myers                       Standards Track                     [Page 4]
+
+RFC 2087                         QUOTA                      January 1997
+
+
+   getquota        ::= "GETQUOTA" SP astring
+
+   getquotaroot    ::= "GETQUOTAROOT" SP astring
+
+   quota_list      ::= "(" #quota_resource ")"
+
+   quota_resource  ::= atom SP number SP number
+
+   quota_response  ::= "QUOTA" SP astring SP quota_list
+
+   quotaroot_response
+                   ::= "QUOTAROOT" SP astring *(SP astring)
+
+   setquota        ::= "SETQUOTA" SP astring SP setquota_list
+
+   setquota_list   ::= "(" 0#setquota_resource ")"
+
+   setquota_resource ::= atom SP number
+
+7.   References
+
+   [IMAP4] Crispin, M., "Internet Message Access Protocol - Version 4",
+   RFC 1730, University of Washington, December 1994.
+
+   [RFC-822] Crocker, D., "Standard for    the Format of ARPA Internet
+   Text Messages", STD 11, RFC 822.
+
+8.   Security Considerations
+
+   Implementors should be careful to make sure the implementation of
+   these commands does not violate the site's security policy. The
+   resource usage of other users is likely to be considered confidential
+   information and should not be divulged to unauthorized persons.
+
+9.   Author's Address
+
+   John G. Myers
+   Carnegie-Mellon University
+   5000 Forbes Ave.
+   Pittsburgh PA, 15213-3890
+
+   EMail: jgm+@cmu.edu
+
+
+
+
+
+
+
+
+
+Myers                       Standards Track                     [Page 5]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc2088.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,115 @@
+
+
+
+
+
+
+Network Working Group                                           J. Myers
+Request for Comments: 2088                               Carnegie Mellon
+Cateogry: Standards Track                                   January 1997
+
+
+                    IMAP4 non-synchronizing literals
+
+Status of this Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+1.   Abstract
+
+   The Internet Message Access Protocol [IMAP4] contains the "literal"
+   syntactic construct for communicating strings.  When sending a
+   literal from client to server, IMAP4 requires the client to wait for
+   the server to send a command continuation request between sending the
+   octet count and the string data.  This document specifies an
+   alternate form of literal which does not require this network round
+   trip.
+
+2.   Conventions Used in this Document
+
+   In examples, "C:" and "S:" indicate lines sent by the client and
+   server respectively.
+
+3.   Specification
+
+   The non-synchronizing literal is added an alternate form of literal,
+   and may appear in communication from client to server instead of the
+   IMAP4 form of literal.  The IMAP4 form of literal, used in
+   communication from client to server, is referred to as a
+   synchronizing literal.
+
+   Non-synchronizing literals may be used with any IMAP4 server
+   implementation which returns "LITERAL+" as one of the supported
+   capabilities to the CAPABILITY command.  If the server does not
+   advertise the LITERAL+ capability, the client must use synchronizing
+   literals instead.
+
+   The non-synchronizing literal is distinguished from the original
+   synchronizing literal by having a plus ('+') between the octet count
+   and the closing brace ('}').  The server does not generate a command
+   continuation request in response to a non-synchronizing literal, and
+
+
+
+Myers                       Standards Track                     [Page 1]
+
+RFC 2088                        LITERAL                     January 1997
+
+
+   clients are not required to wait before sending the octets of a non-
+   synchronizing literal.
+
+   The protocol receiver of an IMAP4 server must check the end of every
+   received line for an open brace ('{') followed by an octet count, a
+   plus ('+'), and a close brace ('}') immediately preceeding the CRLF.
+   If it finds this sequence, it is the octet count of a non-
+   synchronizing literal and the server MUST treat the specified number
+   of following octets and the following line as part of the same
+   command.  A server MAY still process commands and reject errors on a
+   line-by-line basis, as long as it checks for non-synchronizing
+   literals at the end of each line.
+
+   Example:    C: A001 LOGIN {11+}
+               C: FRED FOOBAR {7+}
+               C: fat man
+               S: A001 OK LOGIN completed
+
+4.   Formal Syntax
+
+   The following syntax specification uses the augmented Backus-Naur
+   Form (BNF) notation as specified in [RFC-822] as modified by [IMAP4].
+   Non-terminals referenced but not defined below are as defined by
+   [IMAP4].
+
+   literal         ::= "{" number ["+"] "}" CRLF *CHAR8
+                       ;; Number represents the number of CHAR8 octets
+
+6.   References
+
+   [IMAP4] Crispin, M., "Internet Message Access Protocol - Version 4",
+   draft-crispin-imap-base-XX.txt, University of Washington, April 1996.
+
+   [RFC-822] Crocker, D., "Standard for the Format of ARPA Internet Text
+   Messages", STD 11, RFC 822.
+
+7.   Security Considerations
+
+   There are no known security issues with this extension.
+
+8.   Author's Address
+
+   John G. Myers
+   Carnegie-Mellon University
+   5000 Forbes Ave.
+   Pittsburgh PA, 15213-3890
+
+   Email: jgm+@cmu.edu
+
+
+
+Myers                       Standards Track                     [Page 2]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc2177.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,227 @@
+
+
+
+
+
+
+Network Working Group                                           B. Leiba
+Request for Comments: 2177               IBM T.J. Watson Research Center
+Category: Standards Track                                      June 1997
+
+
+                           IMAP4 IDLE command
+
+Status of this Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+1.   Abstract
+
+   The Internet Message Access Protocol [IMAP4] requires a client to
+   poll the server for changes to the selected mailbox (new mail,
+   deletions).  It's often more desirable to have the server transmit
+   updates to the client in real time.  This allows a user to see new
+   mail immediately.  It also helps some real-time applications based on
+   IMAP, which might otherwise need to poll extremely often (such as
+   every few seconds).  (While the spec actually does allow a server to
+   push EXISTS responses aysynchronously, a client can't expect this
+   behaviour and must poll.)
+
+   This document specifies the syntax of an IDLE command, which will
+   allow a client to tell the server that it's ready to accept such
+   real-time updates.
+
+2.   Conventions Used in this Document
+
+   In examples, "C:" and "S:" indicate lines sent by the client and
+   server respectively.
+
+   The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY"
+   in this document are to be interpreted as described in RFC 2060
+   [IMAP4].
+
+3.   Specification
+
+   IDLE Command
+
+   Arguments:  none
+
+   Responses:  continuation data will be requested; the client sends
+               the continuation data "DONE" to end the command
+
+
+
+Leiba                       Standards Track                     [Page 1]
+
+RFC 2177                   IMAP4 IDLE command                  June 1997
+
+
+
+   Result:     OK - IDLE completed after client sent "DONE"
+               NO - failure: the server will not allow the IDLE
+                    command at this time
+              BAD - command unknown or arguments invalid
+
+   The IDLE command may be used with any IMAP4 server implementation
+   that returns "IDLE" as one of the supported capabilities to the
+   CAPABILITY command.  If the server does not advertise the IDLE
+   capability, the client MUST NOT use the IDLE command and must poll
+   for mailbox updates.  In particular, the client MUST continue to be
+   able to accept unsolicited untagged responses to ANY command, as
+   specified in the base IMAP specification.
+
+   The IDLE command is sent from the client to the server when the
+   client is ready to accept unsolicited mailbox update messages.  The
+   server requests a response to the IDLE command using the continuation
+   ("+") response.  The IDLE command remains active until the client
+   responds to the continuation, and as long as an IDLE command is
+   active, the server is now free to send untagged EXISTS, EXPUNGE, and
+   other messages at any time.
+
+   The IDLE command is terminated by the receipt of a "DONE"
+   continuation from the client; such response satisfies the server's
+   continuation request.  At that point, the server MAY send any
+   remaining queued untagged responses and then MUST immediately send
+   the tagged response to the IDLE command and prepare to process other
+   commands. As in the base specification, the processing of any new
+   command may cause the sending of unsolicited untagged responses,
+   subject to the ambiguity limitations.  The client MUST NOT send a
+   command while the server is waiting for the DONE, since the server
+   will not be able to distinguish a command from a continuation.
+
+   The server MAY consider a client inactive if it has an IDLE command
+   running, and if such a server has an inactivity timeout it MAY log
+   the client off implicitly at the end of its timeout period.  Because
+   of that, clients using IDLE are advised to terminate the IDLE and
+   re-issue it at least every 29 minutes to avoid being logged off.
+   This still allows a client to receive immediate mailbox updates even
+   though it need only "poll" at half hour intervals.
+
+
+
+
+
+
+
+
+
+
+
+Leiba                       Standards Track                     [Page 2]
+
+RFC 2177                   IMAP4 IDLE command                  June 1997
+
+
+   Example:    C: A001 SELECT INBOX
+               S: * FLAGS (Deleted Seen)
+               S: * 3 EXISTS
+               S: * 0 RECENT
+               S: * OK [UIDVALIDITY 1]
+               S: A001 OK SELECT completed
+               C: A002 IDLE
+               S: + idling
+               ...time passes; new mail arrives...
+               S: * 4 EXISTS
+               C: DONE
+               S: A002 OK IDLE terminated
+               ...another client expunges message 2 now...
+               C: A003 FETCH 4 ALL
+               S: * 4 FETCH (...)
+               S: A003 OK FETCH completed
+               C: A004 IDLE
+               S: * 2 EXPUNGE
+               S: * 3 EXISTS
+               S: + idling
+               ...time passes; another client expunges message 3...
+               S: * 3 EXPUNGE
+               S: * 2 EXISTS
+               ...time passes; new mail arrives...
+               S: * 3 EXISTS
+               C: DONE
+               S: A004 OK IDLE terminated
+               C: A005 FETCH 3 ALL
+               S: * 3 FETCH (...)
+               S: A005 OK FETCH completed
+               C: A006 IDLE
+
+4.   Formal Syntax
+
+   The following syntax specification uses the augmented Backus-Naur
+   Form (BNF) notation as specified in [RFC-822] as modified by [IMAP4].
+   Non-terminals referenced but not defined below are as defined by
+   [IMAP4].
+
+   command_auth    ::= append / create / delete / examine / list / lsub /
+                       rename / select / status / subscribe / unsubscribe
+                       / idle
+                       ;; Valid only in Authenticated or Selected state
+
+   idle            ::= "IDLE" CRLF "DONE"
+
+
+
+
+
+
+Leiba                       Standards Track                     [Page 3]
+
+RFC 2177                   IMAP4 IDLE command                  June 1997
+
+
+5.   References
+
+   [IMAP4] Crispin, M., "Internet Message Access Protocol - Version
+   4rev1", RFC 2060, December 1996.
+
+6.   Security Considerations
+
+   There are no known security issues with this extension.
+
+7.   Author's Address
+
+   Barry Leiba
+   IBM T.J. Watson Research Center
+   30 Saw Mill River Road
+   Hawthorne, NY  10532
+
+   Email: leiba@watson.ibm.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Leiba                       Standards Track                     [Page 4]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc2180.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,787 @@
+
+
+
+
+
+
+Network Working Group                                          M. Gahrns
+Request for Comments: 2180                                     Microsoft
+Category: Informational                                        July 1997
+
+
+                 IMAP4 Multi-Accessed Mailbox Practice
+
+Status of this Memo
+
+   This memo provides information for the Internet community.  This memo
+   does not specify an Internet standard of any kind.  Distribution of
+   this memo is unlimited.
+
+1. Abstract
+
+   IMAP4[RFC-2060] is rich client/server protocol that allows a client
+   to access and manipulate electronic mail messages on a server.
+   Within the protocol framework, it is possible to have differing
+   results for particular client/server interactions. If a protocol does
+   not allow for this, it is often unduly restrictive.
+
+   For example, when multiple clients are accessing a mailbox and one
+   attempts to delete the mailbox, an IMAP4 server may choose to
+   implement a solution based upon server architectural constraints or
+   individual preference.
+
+   With this flexibility comes greater client responsibility.  It is not
+   sufficient for a client to be written based upon the behavior of a
+   particular IMAP server.  Rather the client must be based upon the
+   behavior allowed by the protocol.
+
+   By documenting common IMAP4 server practice for the case of
+   simultaneous client access to a mailbox, we hope to ensure the widest
+   amount of inter-operation between IMAP4 clients and servers.
+
+   The behavior described in this document reflects the practice of some
+   existing servers or behavior that the consensus of the IMAP mailing
+   list has deemed to be reasonable.  The behavior described within this
+   document is believed to be [RFC-2060] compliant. However, this
+   document is not meant to define IMAP4 compliance, nor is it an
+   exhaustive list of valid IMAP4 behavior. [RFC-2060] must always be
+   consulted to determine IMAP4 compliance, especially for server
+   behavior not described within this document.
+
+
+
+
+
+
+
+
+Gahrns                       Informational                      [Page 1]
+
+RFC 2180         IMAP4 Multi-Accessed Mailbox Practice         July 1997
+
+
+2. Conventions used in this document
+
+   In examples,"C1:", "C2:" and "C3:" indicate lines sent by 3 different
+   clients (client #1, client #2 and client #3) that are connected to a
+   server.  "S1:", "S2:" and "S3:" indicated lines sent by the server to
+   client #1, client #2 and client #3 respectively.
+
+   A shared mailbox, is a mailbox that can be used by multiple users.
+
+   A multi-accessed mailbox, is a mailbox that has multiple clients
+   simultaneously accessing it.
+
+   A client is said to have accessed a mailbox after a successful SELECT
+   or EXAMINE command.
+
+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+   "SHOULD", "SHOULD NOT", "RECOMMENDED",  "MAY", and "OPTIONAL" in this
+   document are to be interpreted as described in [RFC-2119].
+
+
+3. Deletion/Renaming of a multi-accessed mailbox
+
+   If an external agent or multiple clients are accessing a mailbox,
+   care must be taken when handling the deletion or renaming of the
+   mailbox. Following are some strategies an IMAP server may choose to
+   use when dealing with this situation.
+
+
+3.1. The server MAY fail the DELETE/RENAME command of a multi-accessed
+     mailbox
+
+   In some cases, this behavior may not be practical.  For example, if a
+   large number of clients are accessing a shared mailbox, the window in
+   which no clients have the mailbox accessed may be small or non-
+   existent, effectively rendering the mailbox undeletable or
+   unrenamable.
+
+   Example:
+
+   <Client #1 and Client #2 have mailbox FOO accessed. Client #1 tries
+   to DELETE the mailbox and is refused>
+
+             C1: A001 DELETE FOO
+             S1: A001 NO Mailbox FOO is in use by another user.
+
+
+
+
+
+
+
+Gahrns                       Informational                      [Page 2]
+
+RFC 2180         IMAP4 Multi-Accessed Mailbox Practice         July 1997
+
+
+3.2. The server MAY allow the DELETE command of a multi-accessed
+     mailbox, but keep the information in the mailbox available for
+     those clients that currently have access to the mailbox.
+
+   When all clients have finished accessing the mailbox, it is
+   permanently removed.  For clients that do not already have access to
+   the mailbox, the 'ghosted' mailbox would not be available.  For
+   example, it would not be returned to these clients in a subsequent
+   LIST or LSUB command and would not be a valid mailbox argument to any
+   other IMAP command until the reference count of clients accessing the
+   mailbox reached 0.
+
+   In some cases, this behavior may not be desirable. For example if
+   someone created a mailbox with offensive or sensitive information,
+   one might prefer to have the mailbox deleted and all access to the
+   information contained within removed immediately, rather than
+   continuing to allow access until the client closes the mailbox.
+
+   Furthermore, this behavior, may prevent 'recycling' of the same
+   mailbox name until all clients have finished accessing the original
+   mailbox.
+
+   Example:
+
+   <Client #1 and Client #2 have mailbox FOO selected. Client #1 DELETEs
+   mailbox FOO>
+
+             C1: A001 DELETE FOO
+             S1: A001 OK Mailbox FOO is deleted.
+
+   <Client #2 is still able to operate on the deleted mailbox>
+
+             C2: B001 STORE 1 +FLAGS (\Seen)
+             S2: * 1 FETCH FLAGS (\Seen)
+             S2: B001 OK STORE completed
+
+   <Client #3 which did not have access to the mailbox prior to the
+   deletion by client #1 does not have access to the mailbox>
+
+             C3: C001 STATUS FOO (MESSAGES)
+             S3: C001 NO Mailbox does not exist
+
+   <Nor is client #3 able to create a mailbox with the name FOO, while
+   the reference count is non zero>
+
+             C3: C002 CREATE FOO
+             S3: C002 NO Mailbox FOO is still in use. Try again later.
+
+
+
+
+Gahrns                       Informational                      [Page 3]
+
+RFC 2180         IMAP4 Multi-Accessed Mailbox Practice         July 1997
+
+
+   <Client #2 closes its access to the mailbox, no other clients have
+   access to the mailbox FOO and reference count becomes 0>
+
+             C2: B002 CLOSE
+             S2: B002 OK CLOSE Completed
+
+   <Now that the reference count on FOO has reached 0, the mailbox name
+   can be recycled>
+
+             C3: C003 CREATE FOO
+             S3: C003 OK CREATE Completed
+
+
+3.3. The server MAY allow the DELETE/RENAME of a multi-accessed
+     mailbox, but disconnect all other clients who have the mailbox
+     accessed by sending a untagged BYE response.
+
+   A server may often choose to disconnect clients in the DELETE case,
+   but may choose to implement a "friendlier" method for the RENAME
+   case.
+
+   Example:
+
+   <Client #1 and Client #2 have mailbox FOO accessed. Client #1 DELETEs
+   the mailbox FOO>
+
+             C1: A002 DELETE FOO
+             S1: A002 OK DELETE completed.
+
+   <Server disconnects all other users of the mailbox>
+             S2: * BYE Mailbox FOO has been deleted.
+
+
+3.4. The server MAY allow the RENAME of a multi-accessed mailbox by
+     simply changing the name attribute on the mailbox.
+
+   Other clients that have access to the mailbox can continue issuing
+   commands such as FETCH that do not reference the mailbox name.
+   Clients would discover the renaming the next time they referred to
+   the old mailbox name.  Some servers MAY choose to include the
+   [NEWNAME] response code in their tagged NO response to a command that
+   contained the old mailbox name, as a hint to the client that the
+   operation can succeed if the command is issued with the new mailbox
+   name.
+
+
+
+
+
+
+
+Gahrns                       Informational                      [Page 4]
+
+RFC 2180         IMAP4 Multi-Accessed Mailbox Practice         July 1997
+
+
+   Example:
+
+   <Client #1 and Client #2 have mailbox FOO accessed. Client #1 RENAMEs
+   the mailbox.>
+
+             C1: A001 RENAME FOO BAR
+             S1: A001 OK RENAME completed.
+
+   <Client #2 is still able to do operations that do not reference the
+   mailbox name>
+
+             C2: B001 FETCH 2:4 (FLAGS)
+             S2: * 2 FETCH . . .
+             S2: * 3 FETCH . . .
+             S2: * 4 FETCH . . .
+             S2: B001 OK FETCH completed
+
+   <Client #2 is not able to do operations that reference the mailbox
+   name>
+
+             C2: B002 APPEND FOO {300} C2: Date: Mon, 7 Feb 1994
+             21:52:25 0800 (PST) C2: . . .  S2: B002 NO [NEWNAME FOO
+             BAR] Mailbox has been renamed
+
+
+4. Expunging of messages on a multi-accessed mailbox
+
+   If an external agent or multiple clients are accessing a mailbox,
+   care must be taken when handling the EXPUNGE of messages.  Other
+   clients accessing the mailbox may be in the midst of issuing a
+   command that depends upon message sequence numbers.  Because an
+   EXPUNGE response can not be sent while responding to a FETCH, STORE
+   or SEARCH command, it is not possible to immediately notify the
+   client of the EXPUNGE.  This can result in ambiguity if the client
+   issues a FETCH, STORE or SEARCH operation on a message that has been
+   EXPUNGED.
+
+
+4.1. Fetching of expunged messages
+
+   Following are some strategies an IMAP server may choose to use when
+   dealing with a FETCH command on expunged messages.
+
+
+
+
+
+
+
+
+
+Gahrns                       Informational                      [Page 5]
+
+RFC 2180         IMAP4 Multi-Accessed Mailbox Practice         July 1997
+
+
+   Consider the following scenario:
+
+   - Client #1 and Client #2 have mailbox FOO selected.
+   - There are 7 messages in the mailbox.
+   - Messages 4:7 are marked for deletion.
+   - Client #1 issues an EXPUNGE, to expunge messages 4:7
+
+
+4.1.1. The server MAY allow the EXPUNGE of a multi-accessed mailbox but
+       keep the messages available to satisfy subsequent FETCH commands
+       until it is able to send an EXPUNGE response to each client.
+
+   In some cases, the behavior of keeping "ghosted" messages may not be
+   desirable.  For example if a message contained offensive or sensitive
+   information, one might prefer to instantaneously remove all access to
+   the information, regardless of whether another client is in the midst
+   of accessing it.
+
+   Example:  (Building upon the scenario outlined in 4.1.)
+
+   <Client #2 is still able to access the expunged messages because the
+   server has kept a 'ghosted' copy of the messages until it is able to
+   notify client #2 of the EXPUNGE>
+
+             C2: B001 FETCH 4:7 RFC822
+             S2: * 4 FETCH RFC822 . . . (RFC822 info returned)
+             S2: * 5 FETCH RFC822 . . . (RFC822 info returned)
+             S2: * 6 FETCH RFC822 . . . (RFC822 info returned)
+             S2: * 7 FETCH RFC822 . . . (RFC822 info returned)
+             S2: B001 OK FETCH Completed
+
+   <Client #2 issues a command where it can get notified of the EXPUNGE>
+
+             C2: B002 NOOP
+             S2: * 4 EXPUNGE
+             S2: * 4 EXPUNGE
+             S2: * 4 EXPUNGE
+             S2: * 4 EXPUNGE
+             S2: * 3 EXISTS
+             S2: B002 OK NOOP Complete
+
+   <Client #2 no longer has access to the expunged messages>
+
+             C2: B003 FETCH 4:7 RFC822
+             S2: B003 NO Messages 4:7 are no longer available.
+
+
+
+
+
+
+Gahrns                       Informational                      [Page 6]
+
+RFC 2180         IMAP4 Multi-Accessed Mailbox Practice         July 1997
+
+
+4.1.2 The server MAY allow the EXPUNGE of a multi-accessed mailbox,
+      and on subsequent FETCH commands return FETCH responses only for
+      non-expunged messages and a tagged NO.
+
+   After receiving a tagged NO FETCH response, the client SHOULD issue a
+   NOOP command so that it will be informed of any pending EXPUNGE
+   responses.  The client may then either reissue the failed FETCH
+   command, or by examining the EXPUNGE response from the NOOP and the
+   FETCH response from the FETCH, determine that the FETCH failed
+   because of pending expunges.
+
+   Example:  (Building upon the scenario outlined in 4.1.)
+
+   <Client #2 attempts to FETCH a mix of expunged and non-expunged
+   messages.  A FETCH response is returned only for then non-expunged
+   messages along with a tagged NO>
+
+             C2: B001 FETCH 3:5 ENVELOPE
+             S2: * 3 FETCH ENVELOPE . . . (ENVELOPE info returned)
+             S2: B001 NO Some of the requested messages no longer exist
+
+   <Upon receiving a tagged NO FETCH response, Client #2 issues a NOOP
+   to be informed of any pending EXPUNGE responses>
+
+             C2: B002 NOOP
+             S2: * 4 EXPUNGE
+             S2: * 4 EXPUNGE
+             S2: * 4 EXPUNGE
+             S2: * 4 EXPUNGE
+             S2: * 3 EXISTS
+             S2: B002 OK NOOP Completed.
+
+   <By receiving a FETCH response for message 3, and an EXPUNGE response
+   that indicates messages 4:7 have been expunged, the client does not
+   need to re-issue the FETCH>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Gahrns                       Informational                      [Page 7]
+
+RFC 2180         IMAP4 Multi-Accessed Mailbox Practice         July 1997
+
+
+4.1.3 The server MAY allow the EXPUNGE of a multi-accessed mailbox, and
+      on subsequent FETCH commands return the usual FETCH responses for
+      non-expunged messages, "NIL FETCH Responses" for expunged
+      messages, and a tagged OK response.
+
+   If all of the messages in the subsequent FETCH command have been
+   expunged, the server SHOULD return only a tagged NO.  In this case,
+   the client SHOULD issue a NOOP command so that it will be informed of
+   any pending EXPUNGE responses.  The client may then either reissue
+   the failed FETCH command, or by examining the EXPUNGE response from
+   the NOOP, determine that the FETCH failed because of pending
+   expunges.
+
+   "NIL FETCH responses" are a representation of empty data as
+   appropriate for the FETCH argument specified.
+
+   Example:
+
+   * 1 FETCH (ENVELOPE (NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL))
+   * 1 FETCH (FLAGS ())
+   * 1 FETCH (INTERNALDATE "00-Jan-0000 00:00:00 +0000")
+   * 1 FETCH (RFC822 "")
+   * 1 FETCH (RFC822.HEADER "")
+   * 1 FETCH (RFC822.TEXT "")
+   * 1 FETCH (RFC822.SIZE 0)
+   * 1 FETCH (BODY ("TEXT" "PLAIN" NIL NIL NIL "7BIT" 0 0)
+   * 1 FETCH (BODYSTRUCTURE ("TEXT" "PLAIN" NIL NIL NIL "7BIT" 0 0)
+   * 1 FETCH (BODY[<section>] "")
+   * 1 FETCH (BODY[<section>]<partial> "")
+
+   In some cases, a client may not be able to distinguish between "NIL
+   FETCH responses" received because a message was expunged and those
+   received because the data actually was NIL.  For example, a  * 5
+   FETCH (FLAGS ()) response could be received if no flags were set on
+   message 5, or because message 5 was expunged. In a case of potential
+   ambiguity, the client SHOULD issue a command such as NOOP to force
+   the sending of the EXPUNGE responses to resolve any ambiguity.
+
+   Example:  (Building upon the scenario outlined in 4.1.)
+
+   <Client #2 attempts to access a mix of expunged and non-expunged
+   messages.  Normal data is returned for non-expunged message, "NIL
+   FETCH responses" are returned for expunged messages>
+
+
+
+
+
+
+
+
+Gahrns                       Informational                      [Page 8]
+
+RFC 2180         IMAP4 Multi-Accessed Mailbox Practice         July 1997
+
+
+             C2: B002 FETCH 3:5 ENVELOPE
+             S2: * 3 FETCH ENVELOPE . . . (ENVELOPE info returned)
+             S2: * 4 FETCH ENVELOPE (NIL NIL NIL NIL NIL NIL NIL NIL
+                   NIL NIL)
+             S2: * 5 FETCH ENVELOPE (NIL NIL NIL NIL NIL NIL NIL NIL
+                   NIL NIL)
+             S2: B002 OK FETCH Completed
+
+   <Client #2 attempts to FETCH only expunged messages and receives a
+   tagged NO response>
+
+             C2: B002 FETCH 4:7 ENVELOPE
+             S2: B002 NO Messages 4:7 have been expunged.
+
+
+4.1.4 To avoid the situation altogether, the server MAY fail the
+      EXPUNGE of a multi-accessed mailbox
+
+   In some cases, this behavior may not be practical.  For example, if a
+   large number of clients are accessing a shared mailbox, the window in
+   which no clients have the mailbox accessed may be small or non-
+   existent, effectively rendering the message unexpungeable.
+
+
+4.2. Storing of expunged messages
+
+   Following are some strategies an IMAP server may choose to use when
+   dealing with a STORE command on expunged messages.
+
+
+4.2.1 If the ".SILENT" suffix is used, and the STORE completed
+      successfully for all the non-expunged messages, the server SHOULD
+      return a tagged OK.
+
+   Example:  (Building upon the scenario outlined in 4.1.)
+
+   <Client #2 tries to silently STORE flags on expunged and non-
+   expunged messages.  The server sets the flags on the non-expunged
+   messages and returns OK>
+
+             C2: B001 STORE 1:7 +FLAGS.SILENT (\SEEN)
+             S2: B001 OK
+
+
+
+
+
+
+
+
+
+Gahrns                       Informational                      [Page 9]
+
+RFC 2180         IMAP4 Multi-Accessed Mailbox Practice         July 1997
+
+
+4.2.2. If the ".SILENT" suffix is not used, and only expunged messages
+       are referenced, the server SHOULD return only a tagged NO.
+
+   Example:  (Building upon the scenario outlined in 4.1.)
+
+   <Client #2 tries to STORE flags only on expunged messages>
+
+             C2: B001 STORE 5:7 +FLAGS (\SEEN)
+             S2: B001 NO  Messages have been expunged
+
+
+4.2.3. If the ".SILENT" suffix is not used, and a mixture of expunged
+       and non-expunged messages are referenced, the server MAY set the
+       flags and return a FETCH response for the non-expunged messages
+       along with a tagged NO.
+
+   After receiving a tagged NO STORE response, the client SHOULD issue a
+   NOOP command so that it will be informed of any pending EXPUNGE
+   responses.  The client may then either reissue the failed STORE
+   command, or by examining the EXPUNGE responses from the NOOP and
+   FETCH responses from the STORE, determine that the STORE failed
+   because of pending expunges.
+
+   Example:  (Building upon the scenario outlined in 4.1.)
+
+   <Client #2 tries to STORE flags on a mixture of expunged and non-
+   expunged messages>
+
+             C2: B001 STORE 1:7 +FLAGS (\SEEN)
+             S2: * FETCH 1 FLAGS (\SEEN)
+             S2: * FETCH 2 FLAGS (\SEEN)
+             S2: * FETCH 3 FLAGS (\SEEN)
+             S2: B001 NO Some of the messages no longer exist.
+
+             C2: B002 NOOP
+             S2: * 4 EXPUNGE
+             S2: * 4 EXPUNGE
+             S2: * 4 EXPUNGE
+             S2: * 4 EXPUNGE
+             S2: * 3 EXISTS
+             S2: B002 OK NOOP Completed.
+
+   <By receiving FETCH responses for messages 1:3, and an EXPUNGE
+   response that indicates messages 4:7 have been expunged, the client
+   does not need to re-issue the STORE>
+
+
+
+
+
+
+Gahrns                       Informational                     [Page 10]
+
+RFC 2180         IMAP4 Multi-Accessed Mailbox Practice         July 1997
+
+
+4.2.4. If the ".SILENT" suffix is not used, and a mixture of expunged
+       and non-expunged messages are referenced, the server MAY return
+       an untagged NO and not set any flags.
+
+   After receiving a tagged NO STORE response, the client SHOULD issue a
+   NOOP command so that it will be informed of any pending EXPUNGE
+   responses.  The client would then re-issue the STORE command after
+   updating its message list per any EXPUNGE response.
+
+   If a large number of clients are accessing a shared mailbox, the
+   window in which there are no pending expunges may be small or non-
+   existent, effectively disallowing a client from setting the flags on
+   all messages at once.
+
+   Example:  (Building upon the scenario outlined in 4.1.)
+
+   <Client #2 tries to STORE flags on a mixture of expunged and non-
+   expunged messages>
+
+             C2: B001 STORE 1:7 +FLAGS (\SEEN)
+             S2: B001 NO  Some of the messages no longer exist.
+
+   <Client #2 issues a NOOP to be informed of the EXPUNGED messages>
+
+             C2: B002 NOOP
+             S2: * 4 EXPUNGE
+             S2: * 4 EXPUNGE
+             S2: * 4 EXPUNGE
+             S2: * 4 EXPUNGE
+             S2: * 3 EXISTS
+             S2: B002 OK NOOP Completed.
+
+   <Client #2 updates its message list and re-issues the STORE on only
+   those messages that have not been expunged>
+
+             C2: B003 STORE 1:3 +FLAGS (\SEEN) S2: * FETCH 1 FLAGS
+             (\SEEN) S2: * FETCH 2 FLAGS (\SEEN) S2: * FETCH 3 FLAGS
+             (\SEEN) S2: B003 OK  STORE Completed
+
+
+4.3. Searching of expunged messages
+
+   A server MAY simply not return a search response for messages that
+   have been expunged and it has not been able to inform the client
+   about.  If a client was expecting a particular message to be returned
+   in a search result, and it was not, the client SHOULD issue a NOOP
+   command to see if the message was expunged by another client.
+
+
+
+
+Gahrns                       Informational                     [Page 11]
+
+RFC 2180         IMAP4 Multi-Accessed Mailbox Practice         July 1997
+
+
+4.4 Copying of expunged messages
+
+   COPY is the only IMAP4 sequence number command that is safe to allow
+   an EXPUNGE response on.  This is because a client is not permitted to
+   cascade several COPY commands together. A client is required to wait
+   and confirm that the copy worked before issuing another one.
+
+4.4.1 The server MAY disallow the COPY of messages in a multi-access
+      mailbox that contains expunged messages.
+
+   Pending EXPUNGE response(s) MUST be returned to the COPY command.
+
+   Example:
+
+             C: A001 COPY 2,4,6,8 FRED
+             S: * 4 EXPUNGE
+             S: A001 NO COPY rejected, because some of the requested
+                messages were expunged
+
+   Note: Non of the above messages are copied because if a COPY command
+   is unsuccessful, the server MUST restore the destination mailbox to
+   its state before the COPY attempt.
+
+
+4.4.2 The server MAY allow the COPY of messages in a multi-access
+      mailbox that contains expunged messages.
+
+   Pending EXPUNGE response(s) MUST be returned to the COPY command.
+   Messages that are copied are messages corresponding to sequence
+   numbers before any EXPUNGE response.
+
+   Example:
+
+             C: A001 COPY 2,4,6,8 FRED
+             S: * 3 EXPUNGE
+             S: A001 OK COPY completed
+
+   In the above example, the messages that are copied to FRED are
+   messages 2,4,6,8 at the start of the COPY command.  These are
+   equivalent to messages 2,3,5,7 at the end of the COPY command.  The
+   EXPUNGE response can't take place until after the messages from the
+   COPY command are identified (because of the "no expunge while no
+   commands in progress" rule).
+
+
+
+
+
+
+
+
+Gahrns                       Informational                     [Page 12]
+
+RFC 2180         IMAP4 Multi-Accessed Mailbox Practice         July 1997
+
+
+   Example:
+
+             C: A001 COPY 2,4,6,8 FRED
+             S: * 4 EXPUNGE
+             S: A001 OK COPY completed
+
+   In the above example, message 4 was copied before it was expunged,
+   and MUST appear in the destination mailbox FRED.
+
+
+5. Security Considerations
+
+   This document describes behavior of servers that use the IMAP4
+   protocol, and as such, has the same security considerations as
+   described in [RFC-2060].
+
+   In particular, some described server behavior does not allow for the
+   immediate deletion of information when a mailbox is accessed by
+   multiple clients.  This may be a consideration when dealing with
+   sensitive information where immediate deletion would be preferred.
+
+
+6. References
+
+   [RFC-2060], Crispin, M., "Internet Message Access Protocol - Version
+   4rev1", RFC 2060, University of Washington, December 1996.
+
+   [RFC-2119], Bradner, S., "Key words for use in RFCs to Indicate
+   Requirement Levels", RFC 2119, Harvard University, March 1997.
+
+
+7.  Acknowledgments
+
+   This document is the result of discussions on the IMAP4 mailing list
+   and is meant to reflect consensus of this group.  In particular,
+   Raymond Cheng, Mark Crispin, Jim Evans, Erik Forsberg, Steve Hole,
+   Mark Keasling, Barry Leiba, Syd Logan, John Mani, Pat Moran, Larry
+   Osterman, Chris Newman, Bart Schaefer, Vladimir Vulovic, and Jack De
+   Winter were active participants in this discussion or made
+   suggestions to this document.
+
+
+
+
+
+
+
+
+
+
+
+Gahrns                       Informational                     [Page 13]
+
+RFC 2180         IMAP4 Multi-Accessed Mailbox Practice         July 1997
+
+
+8. Author's Address
+
+   Mike Gahrns
+   Microsoft
+   One Microsoft Way
+   Redmond, WA, 98072
+
+   Phone: (206) 936-9833
+   EMail: mikega@microsoft.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Gahrns                       Informational                     [Page 14]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc2193.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,507 @@
+
+
+
+
+
+
+Network Working Group                                        M. Gahrns
+Request for Comments: 2193                                   Microsoft
+Category: Standards Track                               September 1997
+
+
+                        IMAP4 Mailbox Referrals
+
+Status of this Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+1. Abstract
+
+   When dealing with large amounts of users, messages and geographically
+   dispersed IMAP4 [RFC-2060] servers, it is often desirable to
+   distribute messages amongst different servers within an organization.
+   For example an administrator may choose to store user's personal
+   mailboxes on a local IMAP4 server, while storing shared mailboxes
+   remotely on another server.  This type of configuration is common
+   when it is uneconomical to store all data centrally due to limited
+   bandwidth or disk resources.
+
+   Mailbox referrals allow clients to seamlessly access mailboxes that
+   are distributed across several IMAP4 servers.
+
+   A referral mechanism can provide efficiencies over the alternative
+   "proxy method", in which the local IMAP4 server contacts the remote
+   server on behalf of the client, and then transfers the data from the
+   remote server to itself, and then on to the client.  The referral
+   mechanism's direct client connection to the remote server is often a
+   more efficient use of bandwidth, and does not require the local
+   server to impersonate the client when authenticating to the remote
+   server.
+
+2. Conventions used in this document
+
+   In examples, "C:" and "S:" indicate lines sent by the client and
+   server respectively.
+
+   A home server, is an IMAP4 server that contains the user's inbox.
+
+   A remote mailbox is a mailbox that is not hosted on the user's home
+   server.
+
+
+
+
+Gahrns                      Standards Track                     [Page 1]
+
+RFC 2193                IMAP4 Mailbox Referrals           September 1997
+
+
+   A remote server is a server that contains remote mailboxes.
+
+   A shared mailbox, is a mailbox that multiple users have access to.
+
+   An IMAP mailbox referral is when the server directs the client to
+   another IMAP mailbox.
+
+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+   "SHOULD", "SHOULD NOT", "RECOMMENDED",  "MAY", and "OPTIONAL" in this
+   document are to be interpreted as described in [RFC-2119].
+
+3. Introduction and Overview
+
+   IMAP4 servers that support this extension MUST list the keyword
+   MAILBOX-REFERRALS in their CAPABILITY response.  No client action is
+   needed to invoke the MAILBOX-REFERRALS capability in a server.
+
+   A MAILBOX-REFERRALS capable IMAP4 server MUST NOT return referrals
+   that result in a referrals loop.
+
+   A referral response consists of a tagged NO response and a REFERRAL
+   response code.  The REFERRAL response code MUST contain as an
+   argument a one or more valid URLs separated by a space as defined in
+   [RFC-1738]. If a server replies with multiple URLs for a particular
+   object, they MUST all be of the same type. In this case, the URL MUST
+   be an IMAP URL as defined in [RFC-2192].  A client that supports the
+   REFERRALS extension MUST be prepared for a URL of any type, but it
+   need only be able to process IMAP URLs.
+
+   A server MAY respond with multiple IMAP mailbox referrals if there is
+   more than one replica of the mailbox.  This allows the implementation
+   of a load balancing or failover scheme. How a server keeps multiple
+   replicas of a mailbox in sync is not addressed by this document.
+
+   If the server has a preferred order in which the client should
+   attempt to access the URLs, the preferred URL SHOULD be listed in the
+   first, with the remaining URLs presented in descending order of
+   preference.  If multiple referrals are given for a mailbox, a server
+   should be aware that there are synchronization issues for a client if
+   the UIDVALIDITY of the referred mailboxes are different.
+
+   An IMAP mailbox referral may be given in response to an IMAP command
+   that specifies a mailbox as an argument.
+
+
+
+
+
+
+
+
+Gahrns                      Standards Track                     [Page 2]
+
+RFC 2193                IMAP4 Mailbox Referrals           September 1997
+
+
+   Example:
+
+      A001 NO [REFERRAL IMAP://user;AUTH=*@SERVER2/REMOTE]Remote Mailbox
+
+   NOTE: user;AUTH=* is specified as required by [RFC-2192] to avoid a
+   client falling back to anonymous login.
+
+   Remote mailboxes and their inferiors, that are accessible only via
+   referrals SHOULD NOT appear in LIST and LSUB responses issued against
+   the user's home server.  They MUST appear in RLIST and RLSUB
+   responses issued against the user's home server. Hierarchy referrals,
+   in which a client would be required to connect to the remote server
+   to issue a LIST to discover the inferiors of a mailbox are not
+   addressed in this document.
+
+   For example, if shared mailboxes were only accessible via referrals
+   on a remote server, a RLIST "" "#SHARED/%" command would return the
+   same response if issued against the user's home server or the remote
+   server.
+
+   Note: Mailboxes that are available on the user's home server do not
+   need to be available on the remote server.  In addition, there may be
+   additional mailboxes available on the remote server, but they will
+   not accessible to the client via referrals unless they appear in the
+   LIST response to the RLIST command against the user's home server.
+
+   A MAILBOX-REFERRALS capable client will issue the RLIST and RLSUB
+   commands in lieu of LIST and LSUB.  The RLIST and RLSUB commands
+   behave identically to their LIST and LSUB counterparts, except remote
+   mailboxes are returned in addition to local mailboxes in the LIST and
+   LSUB responses.  This avoids displaying to a non MAILBOX-REFERRALS
+   enabled client inaccessible remote mailboxes.
+
+4.1. SELECT, EXAMINE, DELETE, SUBSCRIBE, UNSUBSCRIBE, STATUS and APPEND
+     Referrals
+
+   An IMAP4 server MAY respond to the SELECT, EXAMINE, DELETE,
+   SUBSCRIBE, UNSUBSCRIBE, STATUS or APPEND command with one or more
+   IMAP mailbox referrals to indicate to the client that the mailbox is
+   hosted on a remote server.
+
+   When a client processes an IMAP mailbox referral, it will open a new
+   connection or use an existing connection to the remote server so that
+   it is able to issue the commands necessary to process the remote
+   mailbox.
+
+
+
+
+
+
+Gahrns                      Standards Track                     [Page 3]
+
+RFC 2193                IMAP4 Mailbox Referrals           September 1997
+
+
+   Example:  <IMAP4 connection to home server>
+
+      C: A001 DELETE "SHARED/FOO"
+      S: A001 NO [REFERRAL IMAP://user;AUTH=*@SERVER2/SHARED/FOO]
+             Remote mailbox. Try SERVER2.
+
+      <Client established a second connection to SERVER2 and
+      issues the DELETE command on the referred mailbox>
+
+      S: * OK IMAP4rev1 server ready
+      C: B001 AUTHENTICATE KERBEROS_V4
+      <authentication exchange>
+      S: B001 OK user is authenticated
+
+      C: B002 DELETE "SHARED/FOO"
+      S: B002 OK DELETE completed
+
+   Example:  <IMAP4 connection to home server>
+
+      C: A001 SELECT REMOTE
+      S: A001 NO [REFERRAL IMAP://user;AUTH=*@SERVER2/REMOTE
+          IMAP://user;AUTH=*@SERVER3/REMOTE] Remote mailbox.
+          Try SERVER2 or SERVER3.
+
+      <Client opens second connection to remote server, and
+       issues the commands needed to process the items in the
+       remote mailbox>
+
+      S: * OK IMAP4rev1 server ready
+      C: B001 AUTHENTICATE KERBEROS_V4
+      <authentication exchange>
+      S: B001 OK user is authenticated
+
+      C: B002 SELECT REMOTE
+      S: * 12 EXISTS
+      S: * 1 RECENT
+      S: * OK [UNSEEN 10] Message 10 is first unseen
+      S: * OK [UIDVALIDITY 123456789]
+      S: * FLAGS (Answered Flagged Deleted Seen Draft)
+      S: * OK [PERMANENTFLAGS (Answered Deleted Seen ]
+      S: B002 OK [READ-WRITE] Selected completed
+
+      C: B003 FETCH 10:12 RFC822
+      S: * 10 FETCH . . .
+      S: * 11 FETCH . . .
+      S: * 12 FETCH . . .
+      S: B003 OK FETCH Completed
+
+
+
+
+Gahrns                      Standards Track                     [Page 4]
+
+RFC 2193                IMAP4 Mailbox Referrals           September 1997
+
+
+      <Client is finished processing the REMOTE mailbox and
+       wants to process a mailbox on its home server>
+
+      C: B004 LOGOUT
+      S: * BYE IMAP4rev1 server logging out
+      S: B004 OK LOGOUT Completed
+
+      <Client continues with first connection>
+
+      C: A002 SELECT INBOX
+      S: * 16 EXISTS
+      S: * 2 RECENT
+      S: * OK [UNSEEN 10] Message 10 is first unseen
+      S: * OK [UIDVALIDITY 123456789]
+      S: * FLAGS (Answered Flagged Deleted Seen Draft)
+      S: * OK [PERMANENTFLAGS (Answered Deleted Seen ]
+      S: A002 OK [READ-WRITE] Selected completed
+
+4.2. CREATE Referrals
+
+   An IMAP4 server MAY respond to the CREATE command with one or more
+   IMAP mailbox referrals, if it wishes to direct the client to issue
+   the CREATE against another server.  The server can employ any means,
+   such as examining the hierarchy of the specified mailbox name, in
+   determining which server the mailbox should be created on.
+
+   Example:
+
+      C: A001 CREATE "SHARED/FOO"
+      S: A001 NO [REFERRAL IMAP://user;AUTH=*@SERVER2/SHARED/FOO]
+         Mailbox should be created on remote server
+
+   Alternatively, because a home server is required to maintain a
+   listing of referred remote mailboxes, a server MAY allow the creation
+   of a mailbox that will ultimately reside on a remote server against
+   the home server, and provide referrals on subsequent commands that
+   manipulate the mailbox.
+
+   Example:
+
+      C: A001 CREATE "SHARED/FOO"
+      S: A001 OK CREATE succeeded
+
+      C: A002 SELECT "SHARED/FOO"
+      S: A002 NO [REFERRAL IMAP://user;AUTH=*@SERVER2/SHARED/FOO]
+         Remote mailbox.  Try SERVER2
+
+
+
+
+
+Gahrns                      Standards Track                     [Page 5]
+
+RFC 2193                IMAP4 Mailbox Referrals           September 1997
+
+
+4.3. RENAME Referrals
+
+   An IMAP4 server MAY respond to the RENAME command with one or more
+   pairs of IMAP mailbox referrals.  In each pair of IMAP mailbox
+   referrals, the first one is an URL to the existing mailbox name and
+   the second is an URL to the requested new mailbox name.
+
+   If within an IMAP mailbox referral pair, the existing and new mailbox
+   URLs are on different servers, the remote servers are unable to
+   perform the RENAME operation.   To achieve the same behavior of
+   server RENAME, the client MAY issue the constituent CREATE, FETCH,
+   APPEND, and DELETE commands against both servers.
+
+   If within an IMAP mailbox referral pair, the existing and new mailbox
+   URLs are on the same server it is an indication that the currently
+   connected server is unable to perform the operation.  The client can
+   simply re-issue the RENAME command on the remote server.
+
+   Example:
+
+      C: A001 RENAME FOO BAR
+      S: A001 NO [REFERRAL IMAP://user;AUTH=*@SERVER1/FOO
+              IMAP://user;AUTH=*@SERVER2/BAR] Unable to rename mailbox
+              across servers
+
+   Since the existing and new mailbox names are on different servers,
+   the client would be required to make a connection to both servers and
+   issue the constituent commands require to achieve the RENAME.
+
+   Example:
+
+      C: A001 RENAME FOO BAR
+      S: A001 NO [REFERRAL IMAP://user;AUTH=*@SERVER2/FOO
+              IMAP://user;AUTH=*@SERVER2/BAR] Unable to rename mailbox
+              located on SERVER2
+
+   Since both the existing and new mailbox are on the same remote
+   server, the client can simply make a connection to the remote server
+   and re-issue the RENAME command.
+
+4.4. COPY Referrals
+
+   An IMAP4 server MAY respond to the COPY command with one or more IMAP
+   mailbox referrals.  This indicates that the destination mailbox is on
+   a remote server.  To achieve the same behavior of a server COPY, the
+   client MAY issue the constituent FETCH and APPEND commands against
+   both servers.
+
+
+
+
+Gahrns                      Standards Track                     [Page 6]
+
+RFC 2193                IMAP4 Mailbox Referrals           September 1997
+
+
+   Example:
+
+      C: A001 COPY 1 "SHARED/STUFF"
+      S: A001 NO [REFERRAL IMAP://user;AUTH=*@SERVER2/SHARED/STUFF]
+              Unable to copy message(s) to SERVER2.
+
+5.1 RLIST command
+
+   Arguments:  reference name
+               mailbox name with possible wildcards
+
+   Responses:  untagged responses: LIST
+
+   Result:     OK - RLIST Completed
+               NO - RLIST Failure
+               BAD - command unknown or arguments invalid
+
+   The RLIST command behaves identically to its LIST counterpart, except
+   remote mailboxes are returned in addition to local mailboxes in the
+   LIST responses.
+
+5.2 RLSUB Command
+
+   Arguments:  reference name
+               mailbox name with possible wildcards
+
+   Responses:  untagged responses: LSUB
+
+   Result:     OK - RLSUB Completed
+               NO - RLSUB Failure
+               BAD - command unknown or arguments invalid
+
+   The RLSUB command behaves identically to its LSUB counterpart, except
+   remote mailboxes are returned in addition to local mailboxes in the
+   LSUB responses.
+
+6. Formal Syntax
+
+   The following syntax specification uses the augmented Backus-Naur
+   Form (BNF) as described in [ABNF].
+
+   list_mailbox = <list_mailbox> as defined in [RFC-2060]
+
+   mailbox = <mailbox> as defined in [RFC-2060]
+
+   mailbox_referral = <tag> SPACE "NO" SPACE
+      <referral_response_code> (text / text_mime2)
+      ; See [RFC-2060] for <tag>, text and text_mime2 definition
+
+
+
+Gahrns                      Standards Track                     [Page 7]
+
+RFC 2193                IMAP4 Mailbox Referrals           September 1997
+
+
+   referral_response_code = "[" "REFERRAL" 1*(SPACE <url>) "]"
+      ; See [RFC-1738] for <url> definition
+
+   rlist = "RLIST" SPACE mailbox SPACE list_mailbox
+
+   rlsub = "RLSUB" SPACE mailbox SPACE list_mailbox
+
+6. Security Considerations
+
+   The IMAP4 referral mechanism makes use of IMAP URLs, and as such,
+   have the same security considerations as general internet URLs [RFC-
+   1738], and in particular IMAP URLs [RFC-2192].
+
+   With the MAILBOX-REFERRALS capability, it is potentially easier to
+   write a rogue server that injects a bogus referral response that
+   directs a user to an incorrect mailbox.  Although referrals reduce
+   the effort to write such a server, the referral response makes
+   detection of the intrusion easier.
+
+7. References
+
+   [RFC-2060], Crispin, M., "Internet Message Access Protocol - Version
+   4rev1", RFC 2060, University of Washington, December 1996.
+
+   [RFC-2192], Newman, C., "IMAP URL Scheme", RFC 2192, Innosoft,
+   September 1997.
+
+   [RFC-1738], Berners-Lee, T., Masinter, L., and M. McCahill, "Uniform
+   Resource Locators (URL)", RFC 1738, CERN, Xerox Corporation,
+   University of Minnesota, December 1994.
+
+   [RFC-2119], Bradner, S., "Key words for use in RFCs to Indicate
+   Requirement Levels", RFC 2119, Harvard University, March 1997.
+
+   [ABNF], DRUMS working group, Dave Crocker Editor, "Augmented BNF for
+   Syntax Specifications: ABNF", Work in Progress, Internet Mail
+   Consortium, April 1997.
+
+8.  Acknowledgments
+
+   Many valuable suggestions were received from private discussions and
+   the IMAP4 mailing list.  In particular, Raymond Cheng, Mark Crispin,
+   Mark Keasling, Chris Newman and Larry Osterman made significant
+   contributions to this document.
+
+
+
+
+
+
+
+Gahrns                      Standards Track                     [Page 8]
+
+RFC 2193                IMAP4 Mailbox Referrals           September 1997
+
+
+9. Author's Address
+
+   Mike Gahrns
+   Microsoft
+   One Microsoft Way
+   Redmond, WA, 98072
+
+   Phone: (206) 936-9833
+   EMail: mikega@microsoft.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Gahrns                      Standards Track                     [Page 9]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc2195.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,283 @@
+
+
+
+
+
+
+Network Working Group                                       J. Klensin
+Request for Comments: 2195                                    R. Catoe
+Category: Standards Track                                 P. Krumviede
+Obsoletes: 2095                                                    MCI
+                                                        September 1997
+
+
+       IMAP/POP AUTHorize Extension for Simple Challenge/Response
+
+Status of this Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Abstract
+
+   While IMAP4 supports a number of strong authentication mechanisms as
+   described in RFC 1731, it lacks any mechanism that neither passes
+   cleartext, reusable passwords across the network nor requires either
+   a significant security infrastructure or that the mail server update
+   a mail-system-wide user authentication file on each mail access.
+   This specification provides a simple challenge-response
+   authentication protocol that is suitable for use with IMAP4.  Since
+   it utilizes Keyed-MD5 digests and does not require that the secret be
+   stored in the clear on the server, it may also constitute an
+   improvement on APOP for POP3 use as specified in RFC 1734.
+
+1. Introduction
+
+   Existing Proposed Standards specify an AUTHENTICATE mechanism for the
+   IMAP4 protocol [IMAP, IMAP-AUTH] and a parallel AUTH mechanism for
+   the POP3 protocol [POP3-AUTH].  The AUTHENTICATE mechanism is
+   intended to be extensible; the four methods specified in [IMAP-AUTH]
+   are all fairly powerful and require some security infrastructure to
+   support.  The base POP3 specification [POP3] also contains a
+   lightweight challenge-response mechanism called APOP.  APOP is
+   associated with most of the risks associated with such protocols: in
+   particular, it requires that both the client and server machines have
+   access to the shared secret in cleartext form. CRAM offers a method
+   for avoiding such cleartext storage while retaining the algorithmic
+   simplicity of APOP in using only MD5, though in a "keyed" method.
+
+
+
+
+
+
+
+Klensin, Catoe & Krumviede  Standards Track                     [Page 1]
+
+RFC 2195              IMAP/POP AUTHorize Extension        September 1997
+
+
+   At present, IMAP [IMAP] lacks any facility corresponding to APOP.
+   The only alternative to the strong mechanisms identified in [IMAP-
+   AUTH] is a presumably cleartext username and password, supported
+   through the LOGIN command in [IMAP].  This document describes a
+   simple challenge-response mechanism, similar to APOP and PPP CHAP
+   [PPP], that can be used with IMAP (and, in principle, with POP3).
+
+   This mechanism also has the advantage over some possible alternatives
+   of not requiring that the server maintain information about email
+   "logins" on a per-login basis.  While mechanisms that do require such
+   per-login history records may offer enhanced security, protocols such
+   as IMAP, which may have several connections between a given client
+   and server open more or less simultaneous, may make their
+   implementation particularly challenging.
+
+2. Challenge-Response Authentication Mechanism (CRAM)
+
+   The authentication type associated with CRAM is "CRAM-MD5".
+
+   The data encoded in the first ready response contains an
+   presumptively arbitrary string of random digits, a timestamp, and the
+   fully-qualified primary host name of the server.  The syntax of the
+   unencoded form must correspond to that of an RFC 822 'msg-id'
+   [RFC822] as described in [POP3].
+
+   The client makes note of the data and then responds with a string
+   consisting of the user name, a space, and a 'digest'.  The latter is
+   computed by applying the keyed MD5 algorithm from [KEYED-MD5] where
+   the key is a shared secret and the digested text is the timestamp
+   (including angle-brackets).
+
+   This shared secret is a string known only to the client and server.
+   The `digest' parameter itself is a 16-octet value which is sent in
+   hexadecimal format, using lower-case ASCII characters.
+
+   When the server receives this client response, it verifies the digest
+   provided.  If the digest is correct, the server should consider the
+   client authenticated and respond appropriately.
+
+   Keyed MD5 is chosen for this application because of the greater
+   security imparted to authentication of short messages. In addition,
+   the use of the techniques described in [KEYED-MD5] for precomputation
+   of intermediate results make it possible to avoid explicit cleartext
+   storage of the shared secret on the server system by instead storing
+   the intermediate results which are known as "contexts".
+
+
+
+
+
+
+Klensin, Catoe & Krumviede  Standards Track                     [Page 2]
+
+RFC 2195              IMAP/POP AUTHorize Extension        September 1997
+
+
+   CRAM does not support a protection mechanism.
+
+   Example:
+
+   The examples in this document show the use of the CRAM mechanism with
+   the IMAP4 AUTHENTICATE command [IMAP-AUTH].  The base64 encoding of
+   the challenges and responses is part of the IMAP4 AUTHENTICATE
+   command, not part of the CRAM specification itself.
+
+     S: * OK IMAP4 Server
+     C: A0001 AUTHENTICATE CRAM-MD5
+     S: + PDE4OTYuNjk3MTcwOTUyQHBvc3RvZmZpY2UucmVzdG9uLm1jaS5uZXQ+
+     C: dGltIGI5MTNhNjAyYzdlZGE3YTQ5NWI0ZTZlNzMzNGQzODkw
+     S: A0001 OK CRAM authentication successful
+
+      In this example, the shared secret is the string
+      'tanstaaftanstaaf'.  Hence, the Keyed MD5 digest is produced by
+      calculating
+
+        MD5((tanstaaftanstaaf XOR opad),
+            MD5((tanstaaftanstaaf XOR ipad),
+            <1896.697170952@postoffice.reston.mci.net>))
+
+      where ipad and opad are as defined in the keyed-MD5 Work in
+      Progress [KEYED-MD5] and the string shown in the challenge is the
+      base64 encoding of <1896.697170952@postoffice.reston.mci.net>. The
+      shared secret is null-padded to a length of 64 bytes. If the
+      shared secret is longer than 64 bytes, the MD5 digest of the
+      shared secret is used as a 16 byte input to the keyed MD5
+      calculation.
+
+      This produces a digest value (in hexadecimal) of
+
+           b913a602c7eda7a495b4e6e7334d3890
+
+      The user name is then prepended to it, forming
+
+           tim b913a602c7eda7a495b4e6e7334d3890
+
+      Which is then base64 encoded to meet the requirements of the IMAP4
+      AUTHENTICATE command (or the similar POP3 AUTH command), yielding
+
+           dGltIGI5MTNhNjAyYzdlZGE3YTQ5NWI0ZTZlNzMzNGQzODkw
+
+
+
+
+
+
+
+
+Klensin, Catoe & Krumviede  Standards Track                     [Page 3]
+
+RFC 2195              IMAP/POP AUTHorize Extension        September 1997
+
+
+3. References
+
+   [CHAP]  Lloyd, B., and W. Simpson, "PPP Authentication Protocols",
+       RFC 1334, October 1992.
+
+   [IMAP] Crispin, M., "Internet Message Access Protocol - Version
+       4rev1", RFC 2060, University of Washington, December 1996.
+
+   [IMAP-AUTH] Myers, J., "IMAP4 Authentication Mechanisms",
+       RFC 1731, Carnegie Mellon, December 1994.
+
+   [KEYED-MD5] Krawczyk, Bellare, Canetti, "HMAC: Keyed-Hashing for
+       Message Authentication", RFC 2104, February 1997.
+
+   [MD5]  Rivest, R., "The MD5 Message Digest Algorithm",
+       RFC 1321, MIT Laboratory for Computer Science, April 1992.
+
+   [POP3] Myers, J., and M. Rose, "Post Office Protocol - Version 3",
+       STD 53, RFC 1939, Carnegie Mellon, May 1996.
+
+   [POP3-AUTH] Myers, J., "POP3 AUTHentication command", RFC 1734,
+       Carnegie Mellon, December, 1994.
+
+4. Security Considerations
+
+   It is conjectured that use of the CRAM authentication mechanism
+   provides origin identification and replay protection for a session.
+   Accordingly, a server that implements both a cleartext password
+   command and this authentication type should not allow both methods of
+   access for a given user.
+
+   While the saving, on the server, of "contexts" (see section 2) is
+   marginally better than saving the shared secrets in cleartext as is
+   required by CHAP [CHAP] and APOP [POP3], it is not sufficient to
+   protect the secrets if the server itself is compromised.
+   Consequently, servers that store the secrets or contexts must both be
+   protected to a level appropriate to the potential information value
+   in user mailboxes and identities.
+
+   As the length of the shared secret increases, so does the difficulty
+   of deriving it.
+
+   While there are now suggestions in the literature that the use of MD5
+   and keyed MD5 in authentication procedures probably has a limited
+   effective lifetime, the technique is now widely deployed and widely
+   understood.  It is believed that this general understanding may
+   assist with the rapid replacement, by CRAM-MD5, of the current uses
+   of permanent cleartext passwords in IMAP.   This document has been
+
+
+
+Klensin, Catoe & Krumviede  Standards Track                     [Page 4]
+
+RFC 2195              IMAP/POP AUTHorize Extension        September 1997
+
+
+   deliberately written to permit easy upgrading to use SHA (or whatever
+   alternatives emerge) when they are considered to be widely available
+   and adequately safe.
+
+   Even with the use of CRAM, users are still vulnerable to active
+   attacks.  An example of an increasingly common active attack is 'TCP
+   Session Hijacking' as described in CERT Advisory CA-95:01 [CERT95].
+
+   See section 1 above for additional discussion.
+
+5. Acknowledgements
+
+   This memo borrows ideas and some text liberally from [POP3] and
+   [RFC-1731] and thanks are due the authors of those documents.  Ran
+   Atkinson made a number of valuable technical and editorial
+   contributions to the document.
+
+6. Authors' Addresses
+
+   John C. Klensin
+   MCI Telecommunications
+   800 Boylston St, 7th floor
+   Boston, MA 02199
+   USA
+
+   EMail: klensin@mci.net
+   Phone: +1 617 960 1011
+
+   Randy Catoe
+   MCI Telecommunications
+   2100 Reston Parkway
+   Reston, VA 22091
+   USA
+
+   EMail: randy@mci.net
+   Phone: +1 703 715 7366
+
+   Paul Krumviede
+   MCI Telecommunications
+   2100 Reston Parkway
+   Reston, VA 22091
+   USA
+
+   EMail: paul@mci.net
+   Phone: +1 703 715 7251
+
+
+
+
+
+
+Klensin, Catoe & Krumviede  Standards Track                     [Page 5]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc2221.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,283 @@
+
+
+
+
+
+
+Network Working Group                                           M. Gahrns
+Request for Comments: 2221                                      Microsoft
+Category: Standards Track                                    October 1997
+
+
+                         IMAP4 Login Referrals
+
+Status of this Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (1997).  All Rights Reserved.
+
+1. Abstract
+
+   When dealing with large amounts of users and many IMAP4 [RFC-2060]
+   servers, it is often necessary to move users from one IMAP4 server to
+   another.  For example, hardware failures or organizational changes
+   may dictate such a move.
+
+   Login referrals allow clients to transparently connect to an
+   alternate IMAP4 server, if their home IMAP4 server has changed.
+
+   A referral mechanism can provide efficiencies over the alternative
+   'proxy method', in which the local IMAP4 server contacts the remote
+   server on behalf of the client, and then transfers the data from the
+   remote server to itself, and then on to the client.  The referral
+   mechanism's direct client connection to the remote server is often a
+   more efficient use of bandwidth, and does not require the local
+   server to impersonate the client when authenticating to the remote
+   server.
+
+2. Conventions used in this document
+
+   In examples, "C:" and "S:" indicate lines sent by the client and
+   server respectively.
+
+   A home server, is an IMAP4 server that contains the user's inbox.
+
+   A remote server is a server that contains remote mailboxes.
+
+
+
+
+
+Gahrns                      Standards Track                     [Page 1]
+
+RFC 2221                 IMAP4 Login Referrals              October 1997
+
+
+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+   "SHOULD", "SHOULD NOT", "RECOMMENDED",  "MAY", and "OPTIONAL" in this
+   document are to be interpreted as described in [RFC-2119].
+
+3. Introduction and Overview
+
+   IMAP4 servers that support this extension MUST list the keyword
+   LOGIN-REFERRALS in their CAPABILITY response.  No client action is
+   needed to invoke the LOGIN-REFERRALS capability in a server.
+
+   A LOGIN-REFERRALS capable IMAP4 server SHOULD NOT return a referral
+   to a server that will return a referral. A client MUST NOT follow
+   more than 10 levels of referral without consulting the user.
+
+   A LOGIN-REFERRALS response code MUST contain as an argument a valid
+   IMAP server URL as defined in [IMAP-URL].
+
+   A home server referral consists of either a tagged NO or OK, or an
+   untagged BYE response that contains a LOGIN-REFERRALS response code.
+
+   Example: A001 NO [REFERRAL IMAP://user;AUTH=*@SERVER2/] Remote Server
+
+   NOTE: user;AUTH=* is specified as required by [IMAP-URL] to avoid a
+   client falling back to anonymous login.
+
+4. Home Server Referrals
+
+   A home server referral may be returned in response to an AUTHENTICATE
+   or LOGIN command, or it may appear in the connection startup banner.
+   If a server returns a home server referral in a tagged NO response,
+   that server does not contain any mailboxes that are accessible to the
+   user.  If a server returns a home server referral in a tagged OK
+   response, it indicates that the user's personal mailboxes are
+   elsewhere, but the server contains public mailboxes which are
+   readable by the user.  After receiving a home server referral, the
+   client can not make any assumptions as to whether this was a
+   permanent or temporary move of the user.
+
+4.1.  LOGIN and AUTHENTICATE Referrals
+
+   An IMAP4 server MAY respond to a LOGIN or AUTHENTICATE command with a
+   home server referral if it wishes to direct the user to another IMAP4
+   server.
+
+   Example:  C: A001 LOGIN MIKE PASSWORD
+             S: A001 NO [REFERRAL IMAP://MIKE@SERVER2/] Specified user
+                     is invalid on this server. Try SERVER2.
+
+
+
+
+Gahrns                      Standards Track                     [Page 2]
+
+RFC 2221                 IMAP4 Login Referrals              October 1997
+
+
+   Example:  C: A001 LOGIN MATTHEW PASSWORD
+             S: A001 OK [REFERRAL IMAP://MATTHEW@SERVER2/] Specified
+                     user's personal mailboxes located on Server2, but
+                     public mailboxes are available.
+
+   Example:  C: A001 AUTHENTICATE GSSAPI
+             <authentication exchange>
+             S: A001 NO [REFERRAL IMAP://user;AUTH=GSSAPI@SERVER2/]
+                     Specified user is invalid on this server. Try
+                     SERVER2.
+
+4.2. BYE at connection startup referral
+
+   An IMAP4 server MAY respond with an untagged BYE and a REFERRAL
+   response code that contains an IMAP URL to a home server if it is not
+   willing to accept connections and wishes to direct the client to
+   another IMAP4 server.
+
+   Example:  S: * BYE [REFERRAL IMAP://user;AUTH=*@SERVER2/] Server not
+                  accepting connections.  Try SERVER2
+
+5. Formal Syntax
+
+   The following syntax specification uses the augmented Backus-Naur
+   Form (BNF) as described in [ABNF].
+
+   This amends the "resp_text_code" element of the IMAP4 grammar
+   described in [RFC-2060]
+
+   resp_text_code =/ "REFERRAL" SPACE <imapurl>
+      ; See [IMAP-URL] for definition of <imapurl>
+      ; See [RFC-2060] for base definition of resp_text_code
+
+6. Security Considerations
+
+   The IMAP4 login referral mechanism makes use of IMAP URLs, and as
+   such, have the same security considerations as general internet URLs
+   [RFC-1738], and in particular IMAP URLs [IMAP-URL].
+
+   A server MUST NOT give a login referral if authentication for that
+   user fails. This is to avoid revealing information about the user's
+   account to an unauthorized user.
+
+   With the LOGIN-REFERRALS capability, it is potentially easier to
+   write a rogue 'password catching' server that collects login data and
+   then refers the client to their actual IMAP4 server.  Although
+   referrals reduce the effort to write such a server, the referral
+   response makes detection of the intrusion easier.
+
+
+
+Gahrns                      Standards Track                     [Page 3]
+
+RFC 2221                 IMAP4 Login Referrals              October 1997
+
+
+7. References
+
+   [RFC-2060], Crispin, M., "Internet Message Access Protocol - Version
+   4rev1", RFC 2060, December 1996.
+
+   [IMAP-URL], Newman, C., "IMAP URL Scheme", RFC 2192, Innosoft,
+   September 1997.
+
+   [RFC-1738], Berners-Lee, T., Masinter, L. and M. McCahill, "Uniform
+   Resource Locators  (URL)", RFC 1738, December 1994.
+
+   [RFC-2119], Bradner, S., "Key words for use in RFCs to Indicate
+   Requirement Levels", RFC 2119, March 1997.
+
+   [ABNF], DRUMS working group, Dave Crocker Editor, "Augmented BNF for
+   Syntax Specifications: ABNF", Work in Progress.
+
+8.  Acknowledgments
+
+   Many valuable suggestions were received from private discussions and
+   the IMAP4 mailing list.  In particular, Raymond Cheng, Mark Crispin,
+   Mark Keasling Chris Newman and Larry Osterman made significant
+   contributions to this document.
+
+9. Author's Address
+
+   Mike Gahrns
+   Microsoft
+   One Microsoft Way
+   Redmond, WA, 98072
+
+   Phone: (206) 936-9833
+   EMail: mikega@microsoft.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Gahrns                      Standards Track                     [Page 4]
+
+RFC 2221                 IMAP4 Login Referrals              October 1997
+
+
+10.  Full Copyright Statement
+
+   Copyright (C) The Internet Society (1997).  All Rights Reserved.
+
+   This document and translations of it may be copied and furnished to
+   others, and derivative works that comment on or otherwise explain it
+   or assist in its implmentation may be prepared, copied, published
+   andand distributed, in whole or in part, without restriction of any
+   kind, provided that the above copyright notice and this paragraph are
+   included on all such copies and derivative works.  However, this
+   document itself may not be modified in any way, such as by removing
+   the copyright notice or references to the Internet Society or other
+   Internet organizations, except as needed for the purpose of
+   developing Internet standards in which case the procedures for
+   copyrights defined in the Internet Standards process must be
+   followed, or as required to translate it into languages other than
+   English.
+
+   The limited permissions granted above are perpetual and will not be
+   revoked by the Internet Society or its successors or assigns.
+
+   This document and the information contained herein is provided on an
+   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE."
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Gahrns                      Standards Track                     [Page 5]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc2342.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,563 @@
+
+
+
+
+
+
+Network Working Group                                         M. Gahrns
+Request for Comments: 2342                                    Microsoft
+Category: Standards Track                                     C. Newman
+                                                               Innosoft
+                                                               May 1998
+
+
+                            IMAP4 Namespace
+
+Status of this Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (1998).  All Rights Reserved.
+
+1. Abstract
+
+   IMAP4 [RFC-2060] does not define a default server namespace. As a
+   result, two common namespace models have evolved:
+
+   The "Personal Mailbox" model, in which the default namespace that is
+   presented consists of only the user's personal mailboxes. To access
+   shared mailboxes, the user must use an escape mechanism to reach
+   another namespace.
+
+   The "Complete Hierarchy" model, in which the default namespace that
+   is presented includes the user's personal mailboxes along with any
+   other mailboxes they have access to.
+
+   These two models, create difficulties for certain client operations.
+   This document defines a NAMESPACE command that allows a client to
+   discover the prefixes of namespaces used by a server for personal
+   mailboxes, other users' mailboxes, and shared mailboxes.  This allows
+   a client to avoid much of the manual user configuration that is now
+   necessary when mixing and matching IMAP4 clients and servers.
+
+2. Conventions used in this document
+
+   In examples, "C:" and "S:" indicate lines sent by the client and
+   server respectively.  If such lines are wrapped without a new "C:" or
+   "S:" label, then the wrapping is for editorial clarity and is not
+   part of the command.
+
+
+
+Gahrns & Newman             Standards Track                     [Page 1]
+
+RFC 2342                    IMAP4 Namespace                     May 1998
+
+
+   Personal Namespace: A namespace that the server considers within the
+   personal scope of the authenticated user on a particular connection.
+   Typically, only the authenticated user has access to mailboxes in
+   their Personal Namespace. It is the part of the namespace that
+   belongs to the user that is allocated for mailboxes. If an INBOX
+   exists for a user, it MUST appear within the user's personal
+   namespace.  In the typical case, there SHOULD be only one Personal
+   Namespace on a server.
+
+   Other Users' Namespace: A namespace that consists of mailboxes from
+   the Personal Namespaces of other users.  To access mailboxes in the
+   Other Users' Namespace, the currently authenticated user MUST be
+   explicitly granted access rights.  For example, it is common for a
+   manager to grant to their secretary access rights to their mailbox.
+   In the typical case, there SHOULD be only one Other Users' Namespace
+   on a server.
+
+   Shared Namespace: A namespace that consists of mailboxes that are
+   intended to be shared amongst users and do not exist within a user's
+   Personal Namespace.
+
+   The namespaces a server uses MAY differ on a per-user basis.
+
+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+   "SHOULD", "SHOULD NOT", "RECOMMENDED",  "MAY", and "OPTIONAL" in this
+   document are to be interpreted as described in [RFC-2119].
+
+3. Introduction and Overview
+
+   Clients often attempt to create mailboxes for such purposes as
+   maintaining a record of sent messages (e.g. "Sent Mail") or
+   temporarily saving messages being composed (e.g. "Drafts").  For
+   these clients to inter-operate correctly with the variety of IMAP4
+   servers available, the user must enter the prefix of the Personal
+   Namespace used by the server.  Using the NAMESPACE command, a client
+   is able to automatically discover this prefix without manual user
+   configuration.
+
+   In addition, users are often required to manually enter the prefixes
+   of various namespaces in order to view the mailboxes located there.
+   For example, they might be required to enter the prefix of #shared to
+   view the shared mailboxes namespace. The NAMESPACE command allows a
+   client to automatically discover the namespaces that are available on
+   a server. This allows a client to present the available namespaces to
+   the user in what ever manner it deems appropriate.  For example, a
+
+
+
+
+
+
+Gahrns & Newman             Standards Track                     [Page 2]
+
+RFC 2342                    IMAP4 Namespace                     May 1998
+
+
+   client could choose to initially display only personal mailboxes, or
+   it may choose to display the complete list of mailboxes available,
+   and initially position the user at the root of their Personal
+   Namespace.
+
+   A server MAY choose to make available to the NAMESPACE command only a
+   subset of the complete set of namespaces the server supports. To
+   provide the ability to access these namespaces, a client SHOULD allow
+   the user the ability to manually enter a namespace prefix.
+
+4. Requirements
+
+   IMAP4 servers that support this extension MUST list the keyword
+   NAMESPACE in their CAPABILITY response.
+
+   The NAMESPACE command is valid in the Authenticated and Selected
+   state.
+
+5. NAMESPACE Command
+
+   Arguments: none
+
+   Response:  an untagged NAMESPACE response that contains the prefix
+                 and hierarchy delimiter to the server's Personal
+                 Namespace(s), Other Users' Namespace(s), and Shared
+                 Namespace(s) that the server wishes to expose. The
+                 response will contain a NIL for any namespace class
+                 that is not available. Namespace_Response_Extensions
+                 MAY be included in the response.
+                 Namespace_Response_Extensions which are not on the IETF
+                 standards track, MUST be prefixed with an "X-".
+
+   Result:    OK - Command completed
+                 NO - Error: Can't complete command
+                 BAD - argument invalid
+
+   Example 5.1:
+   ===========
+
+      < A server that supports a single personal namespace.  No leading
+      prefix is used on personal mailboxes and "/" is the hierarchy
+      delimiter.>
+
+      C: A001 NAMESPACE
+      S: * NAMESPACE (("" "/")) NIL NIL
+      S: A001 OK NAMESPACE command completed
+
+
+
+
+
+Gahrns & Newman             Standards Track                     [Page 3]
+
+RFC 2342                    IMAP4 Namespace                     May 1998
+
+
+   Example 5.2:
+   ===========
+
+      < A user logged on anonymously to a server.  No personal mailboxes
+      are associated with the anonymous user and the user does not have
+      access to the Other Users' Namespace.  No prefix is required to
+      access shared mailboxes and the hierarchy delimiter is "." >
+
+      C: A001 NAMESPACE
+      S: * NAMESPACE NIL NIL (("" "."))
+      S: A001 OK NAMESPACE command completed
+
+   Example 5.3:
+   ===========
+
+      < A server that contains a Personal Namespace and a single Shared
+      Namespace. >
+
+      C: A001 NAMESPACE
+      S: * NAMESPACE (("" "/")) NIL (("Public Folders/" "/"))
+      S: A001 OK NAMESPACE command completed
+
+   Example 5.4:
+   ===========
+
+      < A server that contains a Personal Namespace, Other Users'
+      Namespace and multiple Shared Namespaces.  Note that the hierarchy
+      delimiter used within each namespace can be different. >
+
+      C: A001 NAMESPACE
+      S: * NAMESPACE (("" "/")) (("~" "/")) (("#shared/" "/")
+         ("#public/" "/")("#ftp/" "/")("#news." "."))
+      S: A001 OK NAMESPACE command completed
+
+   The prefix string allows a client to do things such as automatically
+   creating personal mailboxes or LISTing all available mailboxes within
+   a namespace.
+
+   Example 5.5:
+   ===========
+
+      < A server that supports only the Personal Namespace, with a
+      leading prefix of INBOX to personal mailboxes and a hierarchy
+      delimiter of ".">
+
+      C: A001 NAMESPACE
+      S: * NAMESPACE (("INBOX." ".")) NIL  NIL
+      S: A001 OK NAMESPACE command completed
+
+
+
+Gahrns & Newman             Standards Track                     [Page 4]
+
+RFC 2342                    IMAP4 Namespace                     May 1998
+
+
+      < Automatically create a mailbox to store sent items.>
+
+      C: A002 CREATE "INBOX.Sent Mail"
+      S: A002 OK CREATE command completed
+
+   Although typically a server will support only a single Personal
+   Namespace, and a single Other User's Namespace, circumstances exist
+   where there MAY be multiples of these, and a client MUST be prepared
+   for them.   If a client is configured such that it is required to
+   create a certain mailbox, there can be circumstances where it is
+   unclear which Personal Namespaces it should create the mailbox in.
+   In these situations a client SHOULD let the user select which
+   namespaces to create the mailbox in.
+
+   Example 5.6:
+   ===========
+
+      < In this example, a server supports 2 Personal Namespaces.  In
+      addition to the regular Personal Namespace, the user has an
+      additional personal namespace to allow access to mailboxes in an
+      MH format mailstore. >
+
+      < The client is configured to save a copy of all mail sent by the
+      user into a mailbox called 'Sent Mail'.  Furthermore, after a
+      message is deleted from a mailbox, the client is configured to
+      move that message to a mailbox called 'Deleted Items'.>
+
+      < Note that this example demonstrates how some extension flags can
+      be passed to further describe the #mh namespace. >
+
+      C: A001 NAMESPACE
+      S: * NAMESPACE (("" "/")("#mh/" "/" "X-PARAM" ("FLAG1" "FLAG2")))
+         NIL NIL
+      S: A001 OK NAMESPACE command completed
+
+      < It is desired to keep only one copy of sent mail. It is unclear
+      which Personal Namespace the client should use to create the 'Sent
+      Mail' mailbox.  The user is prompted to select a namespace and
+      only one 'Sent Mail' mailbox is created. >
+
+      C: A002 CREATE "Sent Mail"
+      S: A002 OK CREATE command completed
+
+      < The client is designed so that it keeps two 'Deleted Items'
+      mailboxes, one for each namespace. >
+
+      C: A003 CREATE "Delete Items"
+      S: A003 OK CREATE command completed
+
+
+
+Gahrns & Newman             Standards Track                     [Page 5]
+
+RFC 2342                    IMAP4 Namespace                     May 1998
+
+
+      C: A004 CREATE "#mh/Deleted Items"
+      S: A004 OK CREATE command completed
+
+   The next level of hierarchy following the Other Users' Namespace
+   prefix SHOULD consist of <username>, where <username> is a user name
+   as per the IMAP4 LOGIN or AUTHENTICATE command.
+
+   A client can construct a LIST command by appending a "%" to the Other
+   Users' Namespace prefix to discover the Personal Namespaces of other
+   users that are available to the currently authenticated user.
+
+   In response to such a LIST command, a server SHOULD NOT return user
+   names that have not granted access to their personal mailboxes to the
+   user in question.
+
+   A server MAY return a LIST response containing only the names of
+   users that have explicitly granted access to the user in question.
+
+   Alternatively, a server MAY return NO to such a LIST command,
+   requiring that a user name be included with the Other Users'
+   Namespace prefix before listing any other user's mailboxes.
+
+   Example 5.7:
+   ===========
+
+      < A server that supports providing a list of other user's
+      mailboxes that are accessible to the currently logged on user. >
+
+      C: A001 NAMESPACE
+      S: * NAMESPACE (("" "/")) (("Other Users/" "/")) NIL
+      S: A001 OK NAMESPACE command completed
+
+      C: A002 LIST "" "Other Users/%"
+      S: * LIST () "/" "Other Users/Mike"
+      S: * LIST () "/" "Other Users/Karen"
+      S: * LIST () "/" "Other Users/Matthew"
+      S: * LIST () "/" "Other Users/Tesa"
+      S: A002 OK LIST command completed
+
+   Example 5.8:
+   ===========
+
+      < A server that does not support providing a list of other user's
+      mailboxes that are accessible to the currently logged on user.
+      The mailboxes are listable if the client includes the name of the
+      other user with the Other Users' Namespace prefix. >
+
+
+
+
+
+Gahrns & Newman             Standards Track                     [Page 6]
+
+RFC 2342                    IMAP4 Namespace                     May 1998
+
+
+      C: A001 NAMESPACE
+      S: * NAMESPACE (("" "/")) (("#Users/" "/")) NIL
+      S: A001 OK NAMESPACE command completed
+
+      < In this example, the currently logged on user has access to the
+      Personal Namespace of user Mike, but the server chose to suppress
+      this information in the LIST response.  However, by appending the
+      user name Mike (received through user input) to the Other Users'
+      Namespace prefix, the client is able to get a listing of the
+      personal mailboxes of user Mike. >
+
+      C: A002 LIST "" "#Users/%"
+      S: A002 NO The requested item could not be found.
+
+      C: A003 LIST "" "#Users/Mike/%"
+      S: * LIST () "/" "#Users/Mike/INBOX"
+      S: * LIST () "/" "#Users/Mike/Foo"
+      S: A003 OK LIST command completed.
+
+      A prefix string might not contain a hierarchy delimiter, because
+      in some cases it is not needed as part of the prefix.
+
+      Example 5.9:
+      ===========
+
+      < A server that allows access to the Other Users' Namespace by
+      prefixing the others' mailboxes with a '~' followed by <username>,
+      where <username> is a user name as per the IMAP4 LOGIN or
+      AUTHENTICATE command.>
+
+      C: A001 NAMESPACE
+      S: * NAMESPACE (("" "/")) (("~" "/")) NIL
+      S: A001 OK NAMESPACE command completed
+
+      < List the mailboxes for user mark >
+
+      C: A002 LIST "" "~mark/%"
+      S: * LIST () "/" "~mark/INBOX"
+      S: * LIST () "/" "~mark/foo"
+      S: A002 OK LIST command completed
+
+   Historical convention has been to start all namespaces with the "#"
+   character.  Namespaces that include the "#" character are not IMAP
+   URL [IMAP-URL] friendly requiring the "#" character to be represented
+   as %23 when within URLs.  As such, server implementers MAY instead
+   consider using namespace prefixes that do not contain the "#"
+   character.
+
+
+
+
+Gahrns & Newman             Standards Track                     [Page 7]
+
+RFC 2342                    IMAP4 Namespace                     May 1998
+
+
+6. Formal Syntax
+
+   The following syntax specification uses the augmented Backus-Naur
+   Form (BNF) as described in [ABNF].
+
+   atom = <atom>
+      ; <atom> as defined in [RFC-2060]
+
+   Namespace = nil / "(" 1*( "(" string SP  (<"> QUOTED_CHAR <"> /
+      nil) *(Namespace_Response_Extension) ")" ) ")"
+
+   Namespace_Command = "NAMESPACE"
+
+   Namespace_Response_Extension = SP string SP "(" string *(SP string)
+      ")"
+
+   Namespace_Response = "*" SP "NAMESPACE" SP Namespace SP Namespace SP
+      Namespace
+
+      ; The first Namespace is the Personal Namespace(s)
+      ; The second Namespace is the Other Users' Namespace(s)
+      ; The third Namespace is the Shared Namespace(s)
+
+      nil = <nil>
+         ; <nil> as defined in [RFC-2060]
+
+      QUOTED_CHAR = <QUOTED_CHAR>
+         ; <QUOTED_CHAR> as defined in [RFC-2060]
+
+      string = <string>
+         ; <string> as defined in [RFC-2060]
+         ; Note that  the namespace prefix is to a mailbox and following
+         ; IMAP4 convention, any international string in the NAMESPACE
+         ; response MUST be of modified UTF-7 format as described in
+         ;  [RFC-2060].
+
+7. Security Considerations
+
+   In response to a LIST command containing an argument of the Other
+   Users' Namespace prefix, a server SHOULD NOT list users that have not
+   granted list access to their personal mailboxes to the currently
+   authenticated user.  Providing such a list, could compromise security
+   by potentially disclosing confidential information of who is located
+   on the server, or providing a starting point of a list of user
+   accounts to attack.
+
+
+
+
+
+
+Gahrns & Newman             Standards Track                     [Page 8]
+
+RFC 2342                    IMAP4 Namespace                     May 1998
+
+
+8. References
+
+   [RFC-2060], Crispin, M., "Internet Message Access Protocol Version
+   4rev1", RFC 2060, December 1996.
+
+   [RFC-2119], Bradner, S., "Key words for use in RFCs to Indicate
+   Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+   [ABNF] Crocker, D., Editor, and P. Overell, "Augmented BNF for Syntax
+   Specifications: ABNF", RFC 2234, November 1997.
+
+   [IMAP-URL], Newman, C., "IMAP URL Scheme", RFC 2192, September 1997.
+
+9.  Acknowledgments
+
+   Many people have participated in the discussion of IMAP namespaces on
+   the IMAP mailing list.  In particular, the authors would like to
+   thank Mark Crispin for many of the concepts relating to the Personal
+   Namespace and accessing the Personal Namespace of other users, Steve
+   Hole for summarizing the two namespace models, John Myers and Jack De
+   Winter for their work in a preceding effort trying to define a
+   standardized personal namespace, and Larry Osterman for his review
+   and collaboration on this document.
+
+11. Authors' Addresses
+
+   Mike Gahrns
+   Microsoft
+   One Microsoft Way
+   Redmond, WA, 98072, USA
+
+   Phone: (425) 936-9833
+   EMail: mikega@microsoft.com
+
+
+   Chris Newman
+   Innosoft International, Inc.
+   1050 East Garvey Ave. South
+   West Covina, CA, 91790, USA
+
+   EMail: chris.newman@innosoft.com
+
+
+
+
+
+
+
+
+
+
+Gahrns & Newman             Standards Track                     [Page 9]
+
+RFC 2342                    IMAP4 Namespace                     May 1998
+
+
+12.  Full Copyright Statement
+
+   Copyright (C) The Internet Society (1998).  All Rights Reserved.
+
+   This document and translations of it may be copied and furnished to
+   others, and derivative works that comment on or otherwise explain it
+   or assist in its implementation may be prepared, copied, published
+   and distributed, in whole or in part, without restriction of any
+   kind, provided that the above copyright notice and this paragraph are
+   included on all such copies and derivative works.  However, this
+   document itself may not be modified in any way, such as by removing
+   the copyright notice or references to the Internet Society or other
+   Internet organizations, except as needed for the purpose of
+   developing Internet standards in which case the procedures for
+   copyrights defined in the Internet Standards process must be
+   followed, or as required to translate it into languages other than
+   English.
+
+   The limited permissions granted above are perpetual and will not be
+   revoked by the Internet Society or its successors or assigns.
+
+   This document and the information contained herein is provided on an
+   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Gahrns & Newman             Standards Track                    [Page 10]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc2683.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1291 @@
+
+
+
+
+
+
+Network Working Group                                           B. Leiba
+Request for Comments: 2683               IBM T.J. Watson Research Center
+Category: Informational                                   September 1999
+
+
+                  IMAP4 Implementation Recommendations
+
+Status of this Memo
+
+   This memo provides information for the Internet community.  It does
+   not specify an Internet standard of any kind.  Distribution of this
+   memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (1999).  All Rights Reserved.
+
+1. Abstract
+
+   The IMAP4 specification [RFC-2060] describes a rich protocol for use
+   in building clients and servers for storage, retrieval, and
+   manipulation of electronic mail.  Because the protocol is so rich and
+   has so many implementation choices, there are often trade-offs that
+   must be made and issues that must be considered when designing such
+   clients and servers.  This document attempts to outline these issues
+   and to make recommendations in order to make the end products as
+   interoperable as possible.
+
+2. Conventions used in this document
+
+   In examples, "C:" indicates lines sent by a client that is connected
+   to a server.  "S:" indicates lines sent by the server to the client.
+
+   The words "must", "must not", "should", "should not", and "may" are
+   used with specific meaning in this document; since their meaning is
+   somewhat different from that specified in RFC 2119, we do not put
+   them in all caps here.  Their meaning is as follows:
+
+   must --       This word means that the action described is necessary
+                 to ensure interoperability.  The recommendation should
+                 not be ignored.
+   must not --   This phrase means that the action described will be
+                 almost certain to hurt interoperability.  The
+                 recommendation should not be ignored.
+
+
+
+
+
+
+
+Leiba                        Informational                      [Page 1]
+
+RFC 2683          IMAP4 Implementation Recommendations    September 1999
+
+
+   should --     This word means that the action described is strongly
+                 recommended and will enhance interoperability or
+                 usability.  The recommendation should not be ignored
+                 without careful consideration.
+   should not -- This phrase means that the action described is strongly
+                 recommended against, and might hurt interoperability or
+                 usability.  The recommendation should not be ignored
+                 without careful consideration.
+   may --        This word means that the action described is an
+                 acceptable implementation choice.  No specific
+                 recommendation is implied; this word is used to point
+                 out a choice that might not be obvious, or to let
+                 implementors know what choices have been made by
+                 existing implementations.
+
+3. Interoperability Issues and Recommendations
+
+3.1.   Accessibility
+
+   This section describes the issues related to access to servers and
+   server resources.  Concerns here include data sharing and maintenance
+   of client/server connections.
+
+3.1.1. Multiple Accesses of the Same Mailbox
+
+   One strong point of IMAP4 is that, unlike POP3, it allows for
+   multiple simultaneous access to a single mailbox.  A user can, thus,
+   read mail from a client at home while the client in the office is
+   still connected; or the help desk staff can all work out of the same
+   inbox, all seeing the same pool of questions.  An important point
+   about this capability, though is that NO SERVER IS GUARANTEED TO
+   SUPPORT THIS.  If you are selecting an IMAP server and this facility
+   is important to you, be sure that the server you choose to install,
+   in the configuration you choose to use, supports it.
+
+   If you are designing a client, you must not assume that you can
+   access the same mailbox more than once at a time.  That means
+
+   1. you must handle gracefully the failure of a SELECT command if the
+      server refuses the second SELECT,
+   2. you must handle reasonably the severing of your connection (see
+      "Severed Connections", below) if the server chooses to allow the
+      second SELECT by forcing the first off,
+   3. you must avoid making multiple connections to the same mailbox in
+      your own client (for load balancing or other such reasons), and
+   4. you must avoid using the STATUS command on a mailbox that you have
+      selected (with some server implementations the STATUS command has
+      the same problems with multiple access as do the SELECT and
+
+
+
+Leiba                        Informational                      [Page 2]
+
+RFC 2683          IMAP4 Implementation Recommendations    September 1999
+
+
+      EXAMINE commands).
+
+   A further note about STATUS: The STATUS command is sometimes used to
+   check a non-selected mailbox for new mail.  This mechanism must not
+   be used to check for new mail in the selected mailbox; section 5.2 of
+   [RFC-2060] specifically forbids this in its last paragraph.  Further,
+   since STATUS takes a mailbox name it is an independent operation, not
+   operating on the selected mailbox.  Because of this, the information
+   it returns is not necessarily in synchronization with the selected
+   mailbox state.
+
+3.1.2. Severed Connections
+
+   The client/server connection may be severed for one of three reasons:
+   the client severs the connection, the server severs the connection,
+   or the connection is severed by outside forces beyond the control of
+   the client and the server (a telephone line drops, for example).
+   Clients and servers must both deal with these situations.
+
+   When the client wants to sever a connection, it's usually because it
+   has finished the work it needed to do on that connection.  The client
+   should send a LOGOUT command, wait for the tagged response, and then
+   close the socket.  But note that, while this is what's intended in
+   the protocol design, there isn't universal agreement here.  Some
+   contend that sending the LOGOUT and waiting for the two responses
+   (untagged BYE and tagged OK) is wasteful and unnecessary, and that
+   the client can simply close the socket.  The server should interpret
+   the closed socket as a log out by the client.  The counterargument is
+   that it's useful from the standpoint of cleanup, problem
+   determination, and the like, to have an explicit client log out,
+   because otherwise there is no way for the server to tell the
+   difference between "closed socket because of log out" and "closed
+   socket because communication was disrupted".  If there is a
+   client/server interaction problem, a client which routinely
+   terminates a session by breaking the connection without a LOGOUT will
+   make it much more difficult to determine the problem.
+
+   Because of this disagreement, server designers must be aware that
+   some clients might close the socket without sending a LOGOUT.  In any
+   case, whether or not a LOGOUT was sent, the server should not
+   implicitly expunge any messages from the selected mailbox.  If a
+   client wants the server to do so, it must send a CLOSE or EXPUNGE
+   command explicitly.
+
+   When the server wants to sever a connection it's usually due to an
+   inactivity timeout or is because a situation has arisen that has
+   changed the state of the mail store in a way that the server can not
+   communicate to the client.  The server should send an untagged BYE
+
+
+
+Leiba                        Informational                      [Page 3]
+
+RFC 2683          IMAP4 Implementation Recommendations    September 1999
+
+
+   response to the client and then close the socket.  Sending an
+   untagged BYE response before severing allows the server to send a
+   human-readable explanation of the problem to the client, which the
+   client may then log, display to the user, or both (see section 7.1.5
+   of [RFC-2060]).
+
+   Regarding inactivity timeouts, there is some controversy.  Unlike
+   POP, for which the design is for a client to connect, retrieve mail,
+   and log out, IMAP's design encourages long-lived (and mostly
+   inactive) client/server sessions.  As the number of users grows, this
+   can use up a lot of server resources, especially with clients that
+   are designed to maintain sessions for mailboxes that the user has
+   finished accessing.  To alleviate this, a server may implement an
+   inactivity timeout, unilaterally closing a session (after first
+   sending an untagged BYE, as noted above).  Some server operators have
+   reported dramatic improvements in server performance after doing
+   this.  As specified in [RFC-2060], if such a timeout is done it must
+   not be until at least 30 minutes of inactivity.  The reason for this
+   specification is to prevent clients from sending commands (such as
+   NOOP) to the server at frequent intervals simply to avert a too-early
+   timeout.  If the client knows that the server may not time out the
+   session for at least 30 minutes, then the client need not poll at
+   intervals more frequent than, say, 25 minutes.
+
+3.2.   Scaling
+
+   IMAP4 has many features that allow for scalability, as mail stores
+   become larger and more numerous.  Large numbers of users, mailboxes,
+   and messages, and very large messages require thought to handle
+   efficiently.  This document will not address the administrative
+   issues involved in large numbers of users, but we will look at the
+   other items.
+
+3.2.1. Flood Control
+
+   There are three situations when a client can make a request that will
+   result in a very large response - too large for the client reasonably
+   to deal with: there are a great many mailboxes available, there are a
+   great many messages in the selected mailbox, or there is a very large
+   message part.  The danger here is that the end user will be stuck
+   waiting while the server sends (and the client processes) an enormous
+   response.  In all of these cases there are things a client can do to
+   reduce that danger.
+
+   There is also the case where a client can flood a server, by sending
+   an arbitratily long command.  We'll discuss that issue, too, in this
+   section.
+
+
+
+
+Leiba                        Informational                      [Page 4]
+
+RFC 2683          IMAP4 Implementation Recommendations    September 1999
+
+
+3.2.1.1.  Listing Mailboxes
+
+   Some servers present Usenet newsgroups to IMAP users.  Newsgroups,
+   and other such hierarchical mailbox structures, can be very numerous
+   but may have only a few entries at the top level of hierarchy.  Also,
+   some servers are built against mail stores that can, unbeknownst to
+   the server, have circular hierarchies - that is, it's possible for
+   "a/b/c/d" to resolve to the same file structure as "a", which would
+   then mean that "a/b/c/d/b" is the same as "a/b", and the hierarchy
+   will never end.  The LIST response in this case will be unlimited.
+
+   Clients that will have trouble with this are those that use
+
+       C: 001 LIST "" *
+
+   to determine the mailbox list.  Because of this, clients should not
+   use an unqualified "*" that way in the LIST command.  A safer
+   approach is to list each level of hierarchy individually, allowing
+   the user to traverse the tree one limb at a time, thus:
+
+       C: 001 LIST "" %
+       S: * LIST () "/" Banana
+       S: * LIST ...etc...
+       S: 001 OK done
+
+   and then
+
+       C: 002 LIST "" Banana/%
+       S: * LIST () "/" Banana/Apple
+       S: * LIST ...etc...
+       S: 002 OK done
+
+   Using this technique the client's user interface can give the user
+   full flexibility without choking on the voluminous reply to "LIST *".
+
+   Of course, it is still possible that the reply to
+
+       C: 005 LIST "" alt.fan.celebrity.%
+
+   may be thousands of entries long, and there is, unfortunately,
+   nothing the client can do to protect itself from that.  This has not
+   yet been a notable problem.
+
+   Servers that may export circular hierarchies (any server that
+   directly presents a UNIX file system, for instance) should limit the
+   hierarchy depth to prevent unlimited LIST responses.  A suggested
+   depth limit is 20 hierarchy levels.
+
+
+
+
+Leiba                        Informational                      [Page 5]
+
+RFC 2683          IMAP4 Implementation Recommendations    September 1999
+
+
+3.2.1.2.  Fetching the List of Messages
+
+   When a client selects a mailbox, it is given a count, in the untagged
+   EXISTS response, of the messages in the mailbox.  This number can be
+   very large.  In such a case it might be unwise to use
+
+       C: 004 FETCH 1:* ALL
+
+   to populate the user's view of the mailbox.  One good method to avoid
+   problems with this is to batch the requests, thus:
+
+       C: 004 FETCH 1:50 ALL
+       S: * 1 FETCH ...etc...
+       S: 004 OK done
+       C: 005 FETCH 51:100 ALL
+       S: * 51 FETCH ...etc...
+       S: 005 OK done
+       C: 006 FETCH 101:150 ALL
+       ...etc...
+
+   Using this method, another command, such as "FETCH 6 BODY[1]" can be
+   inserted as necessary, and the client will not have its access to the
+   server blocked by a storm of FETCH replies.  (Such a method could be
+   reversed to fetch the LAST 50 messages first, then the 50 prior to
+   that, and so on.)
+
+   As a smart extension of this, a well designed client, prepared for
+   very large mailboxes, will not automatically fetch data for all
+   messages AT ALL.  Rather, the client will populate the user's view
+   only as the user sees it, possibly pre-fetching selected information,
+   and only fetching other information as the user scrolls to it.  For
+   example, to select only those messages beginning with the first
+   unseen one:
+
+       C: 003 SELECT INBOX
+       S: * 10000 EXISTS
+       S: * 80 RECENT
+       S: * FLAGS (\Answered \Flagged \Deleted \Draft \Seen)
+       S: * OK [UIDVALIDITY 824708485] UID validity status
+       S: * OK [UNSEEN 9921] First unseen message
+       S: 003 OK [READ-WRITE] SELECT completed
+       C: 004 FETCH 9921:* ALL
+       ... etc...
+
+   If the server does not return an OK [UNSEEN] response, the client may
+   use SEARCH UNSEEN to obtain that value.
+
+
+
+
+
+Leiba                        Informational                      [Page 6]
+
+RFC 2683          IMAP4 Implementation Recommendations    September 1999
+
+
+   This mechanism is good as a default presentation method, but only
+   works well if the default message order is acceptable.  A client may
+   want to present various sort orders to the user (by subject, by date
+   sent, by sender, and so on) and in that case (lacking a SORT
+   extension on the server side) the client WILL have to retrieve all
+   message descriptors.  A client that provides this service should not
+   do it by default and should inform the user of the costs of choosing
+   this option for large mailboxes.
+
+3.2.1.3.  Fetching a Large Body Part
+
+   The issue here is similar to the one for a list of messages.  In the
+   BODYSTRUCTURE response the client knows the size, in bytes, of the
+   body part it plans to fetch.  Suppose this is a 70 MB video clip. The
+   client can use partial fetches to retrieve the body part in pieces,
+   avoiding the problem of an uninterruptible 70 MB literal coming back
+   from the server:
+
+       C: 022 FETCH 3 BODY[1]<0.20000>
+       S: * 3 FETCH (FLAGS(\Seen) BODY[1]<0> {20000}
+       S: ...data...)
+       S: 022 OK done
+       C: 023 FETCH 3 BODY[1]<20001.20000>
+       S: * 3 FETCH (BODY[1]<20001> {20000}
+       S: ...data...)
+       S: 023 OK done
+       C: 024 FETCH 3 BODY[1]<40001.20000>
+       ...etc...
+
+3.2.1.4.  BODYSTRUCTURE vs. Entire Messages
+
+   Because FETCH BODYSTRUCTURE is necessary in order to determine the
+   number of body parts, and, thus, whether a message has "attachments",
+   clients often use FETCH FULL as their normal method of populating the
+   user's view of a mailbox.  The benefit is that the client can display
+   a paperclip icon or some such indication along with the normal
+   message summary.  However, this comes at a significant cost with some
+   server configurations.  The parsing needed to generate the FETCH
+   BODYSTRUCTURE response may be time-consuming compared with that
+   needed for FETCH ENVELOPE.  The client developer should consider this
+   issue when deciding whether the ability to add a paperclip icon is
+   worth the tradeoff in performance, especially with large mailboxes.
+
+   Some clients, rather than using FETCH BODYSTRUCTURE, use FETCH BODY[]
+   (or the equivalent FETCH RFC822) to retrieve the entire message.
+   They then do the MIME parsing in the client.  This may give the
+   client slightly more flexibility in some areas (access, for instance,
+   to header fields that aren't returned in the BODYSTRUCTURE and
+
+
+
+Leiba                        Informational                      [Page 7]
+
+RFC 2683          IMAP4 Implementation Recommendations    September 1999
+
+
+   ENVELOPE responses), but it can cause severe performance problems by
+   forcing the transfer of all body parts when the user might only want
+   to see some of them - a user logged on by modem and reading a small
+   text message with a large ZIP file attached may prefer to read the
+   text only and save the ZIP file for later.  Therefore, a client
+   should not normally retrieve entire messages and should retrieve
+   message body parts selectively.
+
+3.2.1.5.  Long Command Lines
+
+   A client can wind up building a very long command line in an effort to
+   try to be efficient about requesting information from a server.  This
+   can typically happen when a client builds a message set from selected
+   messages and doesn't recognise that contiguous blocks of messages may
+   be group in a range.  Suppose a user selects all 10,000 messages in a
+   large mailbox and then unselects message 287.  The client could build
+   that message set as "1:286,288:10000", but a client that doesn't
+   handle that might try to enumerate each message individually and build
+   "1,2,3,4, [and so on] ,9999,10000".  Adding that to the fetch command
+   results in a command line that's almost 49,000 octets long, and,
+   clearly, one can construct a command line that's even longer.
+
+   A client should limit the length of the command lines it generates to
+   approximately 1000 octets (including all quoted strings but not
+   including literals).  If the client is unable to group things into
+   ranges so that the command line is within that length, it should
+   split the request into multiple commands.  The client should use
+   literals instead of long quoted strings, in order to keep the command
+   length down.
+
+   For its part, a server should allow for a command line of at least
+   8000 octets.  This provides plenty of leeway for accepting reasonable
+   length commands from clients.  The server should send a BAD response
+   to a command that does not end within the server's maximum accepted
+   command length.
+
+3.2.2. Subscriptions
+
+   The client isn't the only entity that can get flooded: the end user,
+   too, may need some flood control.  The IMAP4 protocol provides such
+   control in the form of subscriptions.  Most servers support the
+   SUBSCRIBE, UNSUBSCRIBE, and LSUB commands, and many users choose to
+   narrow down a large list of available mailboxes by subscribing to the
+   ones that they usually want to see.  Clients, with this in mind,
+   should give the user a way to see only subscribed mailboxes.  A
+   client that never uses the LSUB command takes a significant usability
+   feature away from the user.  Of course, the client would not want to
+   hide the LIST command completely; the user needs to have a way to
+
+
+
+Leiba                        Informational                      [Page 8]
+
+RFC 2683          IMAP4 Implementation Recommendations    September 1999
+
+
+   choose between LIST and LSUB.  The usual way to do this is to provide
+   a setting like "show which mailboxes?:  [] all  [] subscribed only".
+
+3.2.3. Searching
+
+   IMAP SEARCH commands can become particularly troublesome (that is,
+   slow) on mailboxes containing a large number of messages.  So let's
+   put a few things in perspective in that regard.
+
+   The flag searches should be fast.  The flag searches (ALL, [UN]SEEN,
+   [UN]ANSWERED, [UN]DELETED, [UN]DRAFT, [UN]FLAGGED, NEW, OLD, RECENT)
+   are known to be used by clients for the client's own use (for
+   instance, some clients use "SEARCH UNSEEN" to find unseen mail and
+   "SEARCH DELETED" to warn the user before expunging messages).
+
+   Other searches, particularly the text searches (HEADER, TEXT, BODY)
+   are initiated by the user, rather than by the client itself, and
+   somewhat slower performance can be tolerated, since the user is aware
+   that the search is being done (and is probably aware that it might be
+   time-consuming).  A smart server might use dynamic indexing to speed
+   commonly used text searches.
+
+   The client may allow other commands to be sent to the server while a
+   SEARCH is in progress, but at the time of this writing there is
+   little or no server support for parallel processing of multiple
+   commands in the same session (and see "Multiple Accesses of the Same
+   Mailbox" above for a description of the dangers of trying to work
+   around this by doing your SEARCH in another session).
+
+   Another word about text searches: some servers, built on database
+   back-ends with indexed search capabilities, may return search results
+   that do not match the IMAP spec's "case-insensitive substring"
+   requirements.  While these servers are in violation of the protocol,
+   there is little harm in the violation as long as the search results
+   are used only in response to a user's request.  Still, developers of
+   such servers should be aware that they ARE violating the protocol,
+   should think carefully about that behaviour, and must be certain that
+   their servers respond accurately to the flag searches for the reasons
+   outlined above.
+
+   In addition, servers should support CHARSET UTF-8 [UTF-8] in
+   searches.
+
+
+
+
+
+
+
+
+
+Leiba                        Informational                      [Page 9]
+
+RFC 2683          IMAP4 Implementation Recommendations    September 1999
+
+
+3.3    Avoiding Invalid Requests
+
+   IMAP4 provides ways for a server to tell a client in advance what is
+   and isn't permitted in some circumstances.  Clients should use these
+   features to avoid sending requests that a well designed client would
+   know to be invalid.  This section explains this in more detail.
+
+3.3.1. The CAPABILITY Command
+
+   All IMAP4 clients should use the CAPABILITY command to determine what
+   version of IMAP and what optional features a server supports.  The
+   client should not send IMAP4rev1 commands and arguments to a server
+   that does not advertize IMAP4rev1 in its CAPABILITY response.
+   Similarly, the client should not send IMAP4 commands that no longer
+   exist in IMAP4rev1 to a server that does not advertize IMAP4 in its
+   CAPABILITY response.  An IMAP4rev1 server is NOT required to support
+   obsolete IMAP4 or IMAP2bis commands (though some do; do not let this
+   fact lull you into thinking that it's valid to send such commands to
+   an IMAP4rev1 server).
+
+   A client should not send commands to probe for the existance of
+   certain extensions.  All standard and standards-track extensions
+   include CAPABILITY tokens indicating their presense.  All private and
+   experimental extensions should do the same, and clients that take
+   advantage of them should use the CAPABILITY response to determine
+   whether they may be used or not.
+
+3.3.2. Don't Do What the Server Says You Can't
+
+   In many cases, the server, in response to a command, will tell the
+   client something about what can and can't be done with a particular
+   mailbox.  The client should pay attention to this information and
+   should not try to do things that it's been told it can't do.
+
+   Examples:
+
+   *  Do not try to SELECT a mailbox that has the \Noselect flag set.
+   *  Do not try to CREATE a sub-mailbox in a mailbox that has the
+      \Noinferiors flag set.
+   *  Do not respond to a failing COPY or APPEND command by trying to
+      CREATE the target mailbox if the server does not respond with a
+      [TRYCREATE] response code.
+   *  Do not try to expunge a mailbox that has been selected with the
+      [READ-ONLY] response code.
+
+
+
+
+
+
+
+Leiba                        Informational                     [Page 10]
+
+RFC 2683          IMAP4 Implementation Recommendations    September 1999
+
+
+3.4.   Miscellaneous Protocol Considerations
+
+   We describe here a number of important protocol-related issues, the
+   misunderstanding of which has caused significant interoperability
+   problems in IMAP4 implementations.  One general item is that every
+   implementer should be certain to take note of and to understand
+   section 2.2.2 and the preamble to section 7 of the IMAP4rev1 spec
+   [RFC-2060].
+
+3.4.1. Well Formed Protocol
+
+   We cannot stress enough the importance of adhering strictly to the
+   protocol grammar.  The specification of the protocol is quite rigid;
+   do not assume that you can insert blank space for "readability" if
+   none is called for.  Keep in mind that there are parsers out there
+   that will crash if there are protocol errors.  There are clients that
+   will report every parser burp to the user.  And in any case,
+   information that cannot be parsed is information that is lost.  Be
+   careful in your protocol generation.  And see "A Word About Testing",
+   below.
+
+   In particular, note that the string in the INTERNALDATE response is
+   NOT an RFC-822 date string - that is, it is not in the same format as
+   the first string in the ENVELOPE response.  Since most clients will,
+   in fact, accept an RFC-822 date string in the INTERNALDATE response,
+   it's easy to miss this in your interoperability testing.  But it will
+   cause a problem with some client, so be sure to generate the correct
+   string for this field.
+
+3.4.2. Special Characters
+
+   Certain characters, currently the double-quote and the backslash, may
+   not be sent as-is inside a quoted string.  These characters must be
+   preceded by the escape character if they are in a quoted string, or
+   else the string must be sent as a literal.  Both clients and servers
+   must handle this, both on output (they must send these characters
+   properly) and on input (they must be able to receive escaped
+   characters in quoted strings).  Example:
+
+       C: 001 LIST "" %
+       S: * LIST () "" INBOX
+       S: * LIST () "\\" TEST
+       S: * LIST () "\\" {12}
+       S: "My" mailbox
+       S: 001 OK done
+       C: 002 LIST "" "\"My\" mailbox\\%"
+       S: * LIST () "\\" {17}
+       S: "My" mailbox\Junk
+
+
+
+Leiba                        Informational                     [Page 11]
+
+RFC 2683          IMAP4 Implementation Recommendations    September 1999
+
+
+       S: 002 OK done
+
+   Note that in the example the server sent the hierarchy delimiter as
+   an escaped character in the quoted string and sent the mailbox name
+   containing imbedded double-quotes as a literal.  The client used only
+   quoted strings, escaping both the backslash and the double-quote
+   characters.
+
+   The CR and LF characters may be sent ONLY in literals; they are not
+   allowed, even if escaped, inside quoted strings.
+
+   And while we're talking about special characters: the IMAP spec, in
+   the section titled "Mailbox International Naming Convention",
+   describes how to encode mailbox names in modified UTF-7 [UTF-7 and
+   RFC-2060].  Implementations must adhere to this in order to be
+   interoperable in the international market, and servers should
+   validate mailbox names sent by client and reject names that do not
+   conform.
+
+   As to special characters in userids and passwords: clients must not
+   restrict what a user may type in for a userid or a password.  The
+   formal grammar specifies that these are "astrings", and an astring
+   can be a literal.  A literal, in turn can contain any 8-bit
+   character, and clients must allow users to enter all 8-bit characters
+   here, and must pass them, unchanged, to the server (being careful to
+   send them as literals when necessary).  In particular, some server
+   configurations use "@" in user names, and some clients do not allow
+   that character to be entered; this creates a severe interoperability
+   problem.
+
+3.4.3. UIDs and UIDVALIDITY
+
+   Servers that support existing back-end mail stores often have no good
+   place to save UIDs for messages.  Often the existing mail store will
+   not have the concept of UIDs in the sense that IMAP has: strictly
+   increasing, never re-issued, 32-bit integers.  Some servers solve
+   this by storing the UIDs in a place that's accessible to end users,
+   allowing for the possibility that the users will delete them.  Others
+   solve it by re-assigning UIDs every time a mailbox is selected.
+
+   The server should maintain UIDs permanently for all messages if it
+   can.  If that's not possible, the server must change the UIDVALIDITY
+   value for the mailbox whenever any of the UIDs may have become
+   invalid.  Clients must recognize that the UIDVALIDITY has changed and
+   must respond to that condition by throwing away any information that
+   they have saved about UIDs in that mailbox.  There have been many
+   problems in this area when clients have failed to do this; in the
+   worst case it will result in loss of mail when a client deletes the
+
+
+
+Leiba                        Informational                     [Page 12]
+
+RFC 2683          IMAP4 Implementation Recommendations    September 1999
+
+
+   wrong piece of mail by using a stale UID.
+
+   It seems to be a common misunderstanding that "the UIDVALIDITY and
+   the UID, taken together, form a 64-bit identifier that uniquely
+   identifies a message on a server".  This is absolutely NOT TRUE.
+   There is no assurance that the UIDVALIDITY values of two mailboxes be
+   different, so the UIDVALIDITY in no way identifies a mailbox.  The
+   ONLY purpose of UIDVALIDITY is, as its name indicates, to give the
+   client a way to check the validity of the UIDs it has cached.  While
+   it is a valid implementation choice to put these values together to
+   make a 64-bit identifier for the message, the important concept here
+   is that UIDs are not unique between mailboxes; they are only unique
+   WITHIN a given mailbox.
+
+   Some server implementations have attempted to make UIDs unique across
+   the entire server.  This is inadvisable, in that it limits the life
+   of UIDs unnecessarily.  The UID is a 32-bit number and will run out
+   in reasonably finite time if it's global across the server.  If you
+   assign UIDs sequentially in one mailbox, you will not have to start
+   re-using them until you have had, at one time or another, 2**32
+   different messages in that mailbox.  In the global case, you will
+   have to reuse them once you have had, at one time or another, 2**32
+   different messages in the entire mail store.  Suppose your server has
+   around 8000 users registered (2**13).  That gives an average of 2**19
+   UIDs per user.  Suppose each user gets 32 messages (2**5) per day.
+   That gives you 2**14 days (16000+ days = about 45 years) before you
+   run out.  That may seem like enough, but multiply the usage just a
+   little (a lot of spam, a lot of mailing list subscriptions, more
+   users) and you limit yourself too much.
+
+   What's worse is that if you have to wrap the UIDs, and, thus, you
+   have to change UIDVALIDITY and invalidate the UIDs in the mailbox,
+   you have to do it for EVERY mailbox in the system, since they all
+   share the same UID pool.  If you assign UIDs per mailbox and you have
+   a problem, you only have to kill the UIDs for that one mailbox.
+
+   Under extreme circumstances (and this is extreme, indeed), the server
+   may have to invalidate UIDs while a mailbox is in use by a client -
+   that is, the UIDs that the client knows about in its active mailbox
+   are no longer valid.  In that case, the server must immediately
+   change the UIDVALIDITY and must communicate this to the client.  The
+   server may do this by sending an unsolicited UIDVALIDITY message, in
+   the same form as in response to the SELECT command.  Clients must be
+   prepared to handle such a message and the possibly coincident failure
+   of the command in process.  For example:
+
+
+
+
+
+
+Leiba                        Informational                     [Page 13]
+
+RFC 2683          IMAP4 Implementation Recommendations    September 1999
+
+
+       C: 032 UID STORE 382 +Flags.silent \Deleted
+       S: * OK [UIDVALIDITY 12345] New UIDVALIDITY value!
+       S: 032 NO UID command rejected because UIDVALIDITY changed!
+       C: ...invalidates local information and re-fetches...
+       C: 033 FETCH 1:* UID
+       ...etc...
+
+   At the time of the writing of this document, the only server known to
+   do this does so only under the following condition: the client
+   selects INBOX, but there is not yet a physical INBOX file created.
+   Nonetheless, the SELECT succeeds, exporting an empty INBOX with a
+   temporary UIDVALIDITY of 1.  While the INBOX remains selected, mail
+   is delivered to the user, which creates the real INBOX file and
+   assigns a permanent UIDVALIDITY (that is likely not to be 1).  The
+   server reports the change of UIDVALIDITY, but as there were no
+   messages before, so no UIDs have actually changed, all the client
+   must do is accept the change in UIDVALIDITY.
+
+   Alternatively, a server may force the client to re-select the
+   mailbox, at which time it will obtain a new UIDVALIDITY value.  To do
+   this, the server closes this client session (see "Severed
+   Connections" above) and the client then reconnects and gets back in
+   synch.  Clients must be prepared for either of these behaviours.
+
+   We do not know of, nor do we anticipate the future existance of, a
+   server that changes UIDVALIDITY while there are existing messages,
+   but clients must be prepared to handle this eventuality.
+
+3.4.4. FETCH Responses
+
+   When a client asks for certain information in a FETCH command, the
+   server may return the requested information in any order, not
+   necessarily in the order that it was requested.  Further, the server
+   may return the information in separate FETCH responses and may also
+   return information that was not explicitly requested (to reflect to
+   the client changes in the state of the subject message).  Some
+   examples:
+
+       C: 001 FETCH 1 UID FLAGS INTERNALDATE
+       S: * 5 FETCH (FLAGS (\Deleted))
+       S: * 1 FETCH (FLAGS (\Seen) INTERNALDATE "..." UID 345)
+       S: 001 OK done
+
+   (In this case, the responses are in a different order.  Also, the
+   server returned a flag update for message 5, which wasn't part of the
+   client's request.)
+
+
+
+
+
+Leiba                        Informational                     [Page 14]
+
+RFC 2683          IMAP4 Implementation Recommendations    September 1999
+
+
+       C: 002 FETCH 2 UID FLAGS INTERNALDATE
+       S: * 2 FETCH (INTERNALDATE "...")
+       S: * 2 FETCH (UID 399)
+       S: * 2 FETCH (FLAGS ())
+       S: 002 OK done
+
+   (In this case, the responses are in a different order and were
+   returned in separate responses.)
+
+       C: 003 FETCH 2 BODY[1]
+       S: * 2 FETCH (FLAGS (\Seen) BODY[1] {14}
+       S: Hello world!
+       S: )
+       S: 003 OK done
+
+   (In this case, the FLAGS response was added by the server, since
+   fetching the body part caused the server to set the \Seen flag.)
+
+   Because of this characteristic a client must be ready to receive any
+   FETCH response at any time and should use that information to update
+   its local information about the message to which the FETCH response
+   refers.  A client must not assume that any FETCH responses will come
+   in any particular order, or even that any will come at all.  If after
+   receiving the tagged response for a FETCH command the client finds
+   that it did not get all of the information requested, the client
+   should send a NOOP command to the server to ensure that the server
+   has an opportunity to send any pending EXPUNGE responses to the
+   client (see [RFC-2180]).
+
+3.4.5. RFC822.SIZE
+
+   Some back-end mail stores keep the mail in a canonical form, rather
+   than retaining the original MIME format of the messages.  This means
+   that the server must reassemble the message to produce a MIME stream
+   when a client does a fetch such as RFC822 or BODY[], requesting the
+   entire message.  It also may mean that the server has no convenient
+   way to know the RFC822.SIZE of the message.  Often, such a server
+   will actually have to build the MIME stream to compute the size, only
+   to throw the stream away and report the size to the client.
+
+   When this is the case, some servers have chosen to estimate the size,
+   rather than to compute it precisely.  Such an estimate allows the
+   client to display an approximate size to the user and to use the
+   estimate in flood control considerations (q.v.), but requires that
+   the client not use the size for things such as allocation of buffers,
+   because those buffers might then be too small to hold the actual MIME
+   stream.  Instead, a client should use the size that's returned in the
+   literal when you fetch the data.
+
+
+
+Leiba                        Informational                     [Page 15]
+
+RFC 2683          IMAP4 Implementation Recommendations    September 1999
+
+
+   The protocol requires that the RFC822.SIZE value returned by the
+   server be EXACT.  Estimating the size is a protocol violation, and
+   server designers must be aware that, despite the performance savings
+   they might realize in using an estimate, this practice will cause
+   some clients to fail in various ways.  If possible, the server should
+   compute the RFC822.SIZE for a particular message once, and then save
+   it for later retrieval.  If that's not possible, the server must
+   compute the value exactly every time.  Incorrect estimates do cause
+   severe interoperability problems with some clients.
+
+3.4.6. Expunged Messages
+
+   If the server allows multiple connections to the same mailbox, it is
+   often possible for messages to be expunged in one client unbeknownst
+   to another client.  Since the server is not allowed to tell the
+   client about these expunged messages in response to a FETCH command,
+   the server may have to deal with the issue of how to return
+   information about an expunged message.  There was extensive
+   discussion about this issue, and the results of that discussion are
+   summarized in [RFC-2180].  See that reference for a detailed
+   explanation and for recommendations.
+
+3.4.7. The Namespace Issue
+
+   Namespaces are a very muddy area in IMAP4 implementation right now
+   (see [NAMESPACE] for a proposal to clear the water a bit).  Until the
+   issue is resolved, the important thing for client developers to
+   understand is that some servers provide access through IMAP to more
+   than just the user's personal mailboxes, and, in fact, the user's
+   personal mailboxes may be "hidden" somewhere in the user's default
+   hierarchy.  The client, therefore, should provide a setting wherein
+   the user can specify a prefix to be used when accessing mailboxes. If
+   the user's mailboxes are all in "~/mail/", for instance, then the
+   user can put that string in the prefix.  The client would then put
+   the prefix in front of any name pattern in the LIST and LSUB
+   commands:
+
+       C: 001 LIST "" ~/mail/%
+
+   (See also "Reference Names in the LIST Command" below.)
+
+3.4.8. Creating Special-Use Mailboxes
+
+   It may seem at first that this is part of the namespace issue; it is
+   not, and is only indirectly related to it.  A number of clients like
+   to create special-use mailboxes with particular names.  Most
+   commonly, clients with a "trash folder" model of message deletion
+   want to create a mailbox with the name "Trash" or "Deleted".  Some
+
+
+
+Leiba                        Informational                     [Page 16]
+
+RFC 2683          IMAP4 Implementation Recommendations    September 1999
+
+
+   clients want to create a "Drafts" mailbox, an "Outbox" mailbox, or a
+   "Sent Mail" mailbox.  And so on.  There are two major
+   interoperability problems with this practice:
+
+   1. different clients may use different names for mailboxes with
+      similar functions (such as "Trash" and "Deleted"), or may manage
+      the same mailboxes in different ways, causing problems if a user
+      switches between clients and
+   2. there is no guarantee that the server will allow the creation of
+      the desired mailbox.
+
+   The client developer is, therefore, well advised to consider
+   carefully the creation of any special-use mailboxes on the server,
+   and, further, the client must not require such mailbox creation -
+   that is, if you do decide to do this, you must handle gracefully the
+   failure of the CREATE command and behave reasonably when your
+   special-use mailboxes do not exist and can not be created.
+
+   In addition, the client developer should provide a convenient way for
+   the user to select the names for any special-use mailboxes, allowing
+   the user to make these names the same in all clients used and to put
+   them where the user wants them.
+
+3.4.9. Reference Names in the LIST Command
+
+   Many implementers of both clients and servers are confused by the
+   "reference name" on the LIST command.  The reference name is intended
+   to be used in much the way a "cd" (change directory) command is used
+   on Unix, PC DOS, Windows, and OS/2 systems.  That is, the mailbox
+   name is interpreted in much the same way as a file of that name would
+   be found if one had done a "cd" command into the directory specified
+   by the reference name.  For example, in Unix we have the following:
+
+       > cd /u/jones/junk
+       > vi banana        [file is "/u/jones/junk/banana"]
+       > vi stuff/banana  [file is "/u/jones/junk/stuff/banana"]
+       > vi /etc/hosts    [file is "/etc/hosts"]
+
+   In the past, there have been several interoperability problems with
+   this.  First, while some IMAP servers are built on Unix or PC file
+   systems, many others are not, and the file system semantics do not
+   make sense in those configurations.  Second, while some IMAP servers
+   expose the underlying file system to the clients, others allow access
+   only to the user's personal mailboxes, or to some other limited set
+   of files, making such file-system-like semantics less meaningful.
+   Third, because the IMAP spec leaves the interpretation of the
+   reference name as "implementation-dependent", in the past the various
+   server implementations handled it in vastly differing ways.
+
+
+
+Leiba                        Informational                     [Page 17]
+
+RFC 2683          IMAP4 Implementation Recommendations    September 1999
+
+
+   The following recommendations are the result of significant
+   operational experience, and are intended to maximize
+   interoperability.
+
+   Server implementations must implement the reference argument in a way
+   that matches the intended "change directory" operation as closely as
+   possible.  As a minimum implementation, the reference argument may be
+   prepended to the mailbox name (while suppressing double delimiters;
+   see the next paragraph).  Even servers that do not provide a way to
+   break out of the current hierarchy (see "breakout facility" below)
+   must provide a reasonable implementation of the reference argument,
+   as described here, so that they will interoperate with clients that
+   use it.
+
+   Server implementations that prepend the reference argument to the
+   mailbox name should insert a hierarchy delimiter between them, and
+   must not insert a second if one is already present:
+
+       C: A001 LIST ABC DEF
+       S: * LIST () "/" ABC/DEF   <=== should do this
+       S: A001 OK done
+
+       C: A002 LIST ABC/ /DEF
+       S: * LIST () "/" ABC//DEF     <=== must not do this
+       S: A002 OK done
+
+   On clients, the reference argument is chiefly used to implement a
+   "breakout facility", wherein the user may directly access a mailbox
+   outside the "current directory" hierarchy.  Client implementations
+   should have an operational mode that does not use the reference
+   argument.  This is to interoperate with older servers that did not
+   implement the reference argument properly.  While it's a good idea to
+   give the user access to a breakout facility, clients that do not
+   intend to do so should not use the reference argument at all.
+
+   Client implementations should always place a trailing hierarchy
+   delimiter on the reference argument.  This is because some servers
+   prepend the reference argument to the mailbox name without inserting
+   a hierarchy delimiter, while others do insert a hierarchy delimiter
+   if one is not already present.  A client that puts the delimiter in
+   will work with both varieties of server.
+
+   Client implementations that implement a breakout facility should
+   allow the user to choose whether or not to use a leading hierarchy
+   delimiter on the mailbox argument.  This is because the handling of a
+   leading mailbox hierarchy delimiter also varies from server to
+   server, and even between different mailstores on the same server.  In
+   some cases, a leading hierarchy delimiter means "discard the
+
+
+
+Leiba                        Informational                     [Page 18]
+
+RFC 2683          IMAP4 Implementation Recommendations    September 1999
+
+
+   reference argument" (implementing the intended breakout facility),
+   thus:
+
+       C: A001 LIST ABC/ /DEF
+       S: * LIST () "/" /DEF
+       S: A001 OK done
+
+   In other cases, however, the two are catenated and the extra
+   hierarchy delimiter is discarded, thus:
+
+       C: A001 LIST ABC/ /DEF
+       S: * LIST () "/" ABC/DEF
+       S: A001 OK done
+
+   Client implementations must not assume that the server supports a
+   breakout facility, but may provide a way for the user to use one if
+   it is available.  Any breakout facility should be exported to the
+   user interface.  Note that there may be other "breakout" characters
+   besides the hierarchy delimiter (for instance, UNIX filesystem
+   servers are likely to use a leading "~" as well), and that their
+   interpretation is server-dependent.
+
+3.4.10.   Mailbox Hierarchy Delimiters
+
+   The server's selection of what to use as a mailbox hierarchy
+   delimiter is a difficult one, involving several issues: What
+   characters do users expect to see?  What characters can they enter
+   for a hierarchy delimiter if it is desired (or required) that the
+   user enter it?  What character can be used for the hierarchy
+   delimiter, noting that the chosen character can not otherwise be used
+   in the mailbox name?
+
+   Because some interfaces show users the hierarchy delimiters or allow
+   users to enter qualified mailbox names containing them, server
+   implementations should use delimiter characters that users generally
+   expect to see as name separators.  The most common characters used
+   for this are "/" (as in Unix file names), "\" (as in OS/2 and Windows
+   file names), and "." (as in news groups).  There is little to choose
+   among these apart from what users may expect or what is dictated by
+   the underlying file system, if any.  One consideration about using
+   "\" is that it's also a special character in the IMAP protocol. While
+   the use of other hierarchy delimiter characters is permissible, A
+   DESIGNER IS WELL ADVISED TO STAY WITH ONE FROM THIS SET unless the
+   server is intended for special purposes only.  Implementers might be
+   thinking about using characters such as "-", "_", ";", "&", "#", "@",
+   and "!", but they should be aware of the surprise to the user as well
+   as of the effect on URLs and other external specifications (since
+   some of these characters have special meanings there).  Also, a
+
+
+
+Leiba                        Informational                     [Page 19]
+
+RFC 2683          IMAP4 Implementation Recommendations    September 1999
+
+
+   server that uses "\" (and clients of such a server) must remember to
+   escape that character in quoted strings or to send literals instead.
+   Literals are recommended over escaped characters in quoted strings in
+   order to maintain compatibility with older IMAP versions that did not
+   allow escaped characters in quoted strings (but check the grammar to
+   see where literals are allowed):
+
+       C: 001 LIST "" {13}
+       S: + send literal
+       C: this\%\%\%\h*
+       S: * LIST () "\\" {27}
+       S: this\is\a\mailbox\hierarchy
+       S: 001 OK LIST complete
+
+   In any case, a server should not use normal alpha-numeric characters
+   (such as "X" or "0") as delimiters; a user would be very surprised to
+   find that "EXPENDITURES" actually represented a two-level hierarchy.
+   And a server should not use characters that are non-printable or
+   difficult or impossible to enter on a standard US keyboard.  Control
+   characters, box-drawing characters, and characters from non-US
+   alphabets fit into this category.  Their use presents
+   interoperability problems that are best avoided.
+
+   The UTF-7 encoding of mailbox names also raises questions about what
+   to do with the hierarchy delimiters in encoded names: do we encode
+   each hierarchy level and separate them with delimiters, or do we
+   encode the fully qualified name, delimiters and all?  The answer for
+   IMAP is the former: encode each hierarchy level separately, and
+   insert delimiters between.  This makes it particularly important not
+   to use as a hierarchy delimiter a character that might cause
+   confusion with IMAP's modified UTF-7 [UTF-7 and RFC-2060] encoding.
+
+   To repeat: a server should use "/", "\", or "." as its hierarchy
+   delimiter.  The use of any other character is likely to cause
+   problems and is STRONGLY DISCOURAGED.
+
+3.4.11.   ALERT Response Codes
+
+   The protocol spec is very clear on the matter of what to do with
+   ALERT response codes, and yet there are many clients that violate it
+   so it needs to be said anyway: "The human-readable text contains a
+   special alert that must be presented to the user in a fashion that
+   calls the user's attention to the message."  That should be clear
+   enough, but I'll repeat it here: Clients must present ALERT text
+   clearly to the user.
+
+
+
+
+
+
+Leiba                        Informational                     [Page 20]
+
+RFC 2683          IMAP4 Implementation Recommendations    September 1999
+
+
+3.4.12.   Deleting Mailboxes
+
+   The protocol does not guarantee that a client may delete a mailbox
+   that is not empty, though on some servers it is permissible and is,
+   in fact, much faster than the alternative or deleting all the
+   messages from the client.  If the client chooses to try to take
+   advantage of this possibility it must be prepared to use the other
+   method in the even that the more convenient one fails.  Further, a
+   client should not try to delete the mailbox that it has selected, but
+   should first close that mailbox; some servers do not permit the
+   deletion of the selected mailbox.
+
+   That said, a server should permit the deletion of a non-empty
+   mailbox; there's little reason to pass this work on to the client.
+   Moreover, forbidding this prevents the deletion of a mailbox that for
+   some reason can not be opened or expunged, leading to possible
+   denial-of-service problems.
+
+   Example:
+
+       [User tells the client to delete mailbox BANANA, which is
+       currently selected...]
+       C: 008 CLOSE
+       S: 008 OK done
+       C: 009 DELETE BANANA
+       S: 009 NO Delete failed; mailbox is not empty.
+       C: 010 SELECT BANANA
+       S: * ... untagged SELECT responses
+       S: 010 OK done
+       C: 011 STORE 1:* +FLAGS.SILENT \DELETED
+       S: 011 OK done
+       C: 012 CLOSE
+       S: 012 OK done
+       C: 013 DELETE BANANA
+       S: 013 OK done
+
+3.5.   A Word About Testing
+
+   Since the whole point of IMAP is interoperability, and since
+   interoperability can not be tested in a vacuum, the final
+   recommendation of this treatise is, "Test against EVERYTHING."  Test
+   your client against every server you can get an account on.  Test
+   your server with every client you can get your hands on.  Many
+   clients make limited test versions available on the Web for the
+   downloading.  Many server owners will give serious client developers
+   guest accounts for testing.  Contact them and ask.  NEVER assume that
+   because your client works with one or two servers, or because your
+   server does fine with one or two clients, you will interoperate well
+
+
+
+Leiba                        Informational                     [Page 21]
+
+RFC 2683          IMAP4 Implementation Recommendations    September 1999
+
+
+   in general.
+
+   In particular, in addition to everything else, be sure to test
+   against the reference implementations: the PINE client, the
+   University of Washington server, and the Cyrus server.
+
+   See the following URLs on the web for more information here:
+
+       IMAP Products and Sources: http://www.imap.org/products.html
+       IMC MailConnect: http://www.imc.org/imc-mailconnect
+
+4. Security Considerations
+
+   This document describes behaviour of clients and servers that use the
+   IMAP4 protocol, and as such, has the same security considerations as
+   described in [RFC-2060].
+
+5. References
+
+   [RFC-2060]  Crispin, M., "Internet Message Access Protocol - Version
+               4rev1", RFC 2060, December 1996.
+
+   [RFC-2119]  Bradner, S., "Key words for use in RFCs to Indicate
+               Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+   [RFC-2180]  Gahrns, M., "IMAP4 Multi-Accessed Mailbox Practice", RFC
+               2180, July 1997.
+
+   [UTF-8]     Yergeau, F., " UTF-8, a transformation format of Unicode
+               and ISO 10646", RFC 2044, October 1996.
+
+   [UTF-7]     Goldsmith, D. and M. Davis, "UTF-7, a Mail-Safe
+               Transformation Format of Unicode", RFC 2152, May 1997.
+
+   [NAMESPACE] Gahrns, M. and C. Newman, "IMAP4 Namespace", Work in
+               Progress.
+
+6. Author's Address
+
+   Barry Leiba
+   IBM T.J. Watson Research Center
+   30 Saw Mill River Road
+   Hawthorne, NY  10532
+
+   Phone: 1-914-784-7941
+   EMail: leiba@watson.ibm.com
+
+
+
+
+
+Leiba                        Informational                     [Page 22]
+
+RFC 2683          IMAP4 Implementation Recommendations    September 1999
+
+
+7. Full Copyright Statement
+
+   Copyright (C) The Internet Society (1999).  All Rights Reserved.
+
+   This document and translations of it may be copied and furnished to
+   others, and derivative works that comment on or otherwise explain it
+   or assist in its implementation may be prepared, copied, published
+   and distributed, in whole or in part, without restriction of any
+   kind, provided that the above copyright notice and this paragraph are
+   included on all such copies and derivative works.  However, this
+   document itself may not be modified in any way, such as by removing
+   the copyright notice or references to the Internet Society or other
+   Internet organizations, except as needed for the purpose of
+   developing Internet standards in which case the procedures for
+   copyrights defined in the Internet Standards process must be
+   followed, or as required to translate it into languages other than
+   English.
+
+   The limited permissions granted above are perpetual and will not be
+   revoked by the Internet Society or its successors or assigns.
+
+   This document and the information contained herein is provided on an
+   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is currently provided by the
+   Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Leiba                        Informational                     [Page 23]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc2971.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,451 @@
+
+
+
+
+
+
+Network Working Group                                        T. Showalter
+Request for Comments: 2971                                Mirapoint, Inc.
+Category: Standards Track                                    October 2000
+
+
+                           IMAP4 ID extension
+
+Status of this Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (2000).  All Rights Reserved.
+
+Abstract
+
+   The ID extension to the Internet Message Access Protocol - Version
+   4rev1 (IMAP4rev1) protocol allows the server and client to exchange
+   identification information on their implementation in order to make
+   bug reports and usage statistics more complete.
+
+1. Introduction
+
+   The IMAP4rev1 protocol described in [IMAP4rev1] provides a method for
+   accessing remote mail stores, but it provides no facility to
+   advertise what program a client or server uses to provide service.
+   This makes it difficult for implementors to get complete bug reports
+   from users, as it is frequently difficult to know what client or
+   server is in use.
+
+   Additionally, some sites may wish to assemble usage statistics based
+   on what clients are used, but in an an environment where users are
+   permitted to obtain and maintain their own clients this is difficult
+   to accomplish.
+
+   The ID command provides a facility to advertise information on what
+   programs are being used along with contact information (should bugs
+   ever occur).
+
+
+
+
+
+
+
+
+Showalter                   Standards Track                     [Page 1]
+
+RFC 2971                   IMAP4 ID extension               October 2000
+
+
+2. Conventions Used in this Document
+
+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+   document are to be interpreted as described in [KEYWORDS].
+
+   The conventions used in this document are the same as specified in
+   [IMAP4rev1].  In examples, "C:" and "S:" indicate lines sent by the
+   client and server respectively.  Line breaks have been inserted for
+   readability.
+
+3. Specification
+
+   The sole purpose of the ID extension is to enable clients and servers
+   to exchange information on their implementations for the purposes of
+   statistical analysis and problem determination.
+
+   This information is be submitted to a server by any client wishing to
+   provide information for statistical purposes, provided the server
+   advertises its willingness to take the information with the atom "ID"
+   included in the list of capabilities returned by the CAPABILITY
+   command.
+
+   Implementations MUST NOT make operational changes based on the data
+   sent as part of the ID command or response.  The ID command is for
+   human consumption only, and is not to be used in improving the
+   performance of clients or servers.
+
+   This includes, but is not limited to, the following:
+
+      Servers MUST NOT attempt to work around client bugs by using
+      information from the ID command.  Clients MUST NOT attempt to work
+      around server bugs based on the ID response.
+
+      Servers MUST NOT provide features to a client or otherwise
+      optimize for a particular client by using information from the ID
+      command.  Clients MUST NOT provide features to a server or
+      otherwise optimize for a particular server based on the ID
+      response.
+
+      Servers MUST NOT deny access to or refuse service for a client
+      based on information from the ID command.  Clients MUST NOT refuse
+      to operate or limit their operation with a server based on the ID
+      response.
+
+
+
+
+
+
+
+Showalter                   Standards Track                     [Page 2]
+
+RFC 2971                   IMAP4 ID extension               October 2000
+
+
+   Rationale: It is imperative that this extension not supplant IMAP's
+   CAPABILITY mechanism with a ad-hoc approach where implementations
+   guess each other's features based on who they claim to be.
+
+   Implementations MUST NOT send false information in an ID command.
+
+   Implementations MAY send less information than they have available or
+   no information at all.  Such behavior may be useful to preserve user
+   privacy.  See Security Considerations, section 7.
+
+3.1. ID Command
+
+   Arguments:  client parameter list or NIL
+
+   Responses:  OPTIONAL untagged response: ID
+
+   Result:     OK    identification information accepted
+               BAD   command unknown or arguments invalid
+
+   Implementation identification information is sent by the client with
+   the ID command.
+
+   This command is valid in any state.
+
+   The information sent is in the form of a list of field/value pairs.
+   Fields are permitted to be any IMAP4 string, and values are permitted
+   to be any IMAP4 string or NIL.  A value of NIL indicates that the
+   client can not or will not specify this information.  The client may
+   also send NIL instead of the list, indicating that it wants to send
+   no information, but would still accept a server response.
+
+   The available fields are defined in section 3.3.
+
+   Example:  C: a023 ID ("name" "sodr" "version" "19.34" "vendor"
+                 "Pink Floyd Music Limited")
+             S: * ID NIL
+             S: a023 OK ID completed
+
+3.2. ID Response
+
+   Contents:   server parameter list
+
+   In response to an ID command issued by the client, the server replies
+   with a tagged response containing information on its implementation.
+   The format is the same as the client list.
+
+
+
+
+
+
+Showalter                   Standards Track                     [Page 3]
+
+RFC 2971                   IMAP4 ID extension               October 2000
+
+
+   Example:  C: a042 ID NIL
+             S: * ID ("name" "Cyrus" "version" "1.5" "os" "sunos"
+                  "os-version" "5.5" "support-url"
+                  "mailto:cyrus-bugs+@andrew.cmu.edu")
+             S: a042 OK ID command completed
+
+   A server MUST send a tagged ID response to an ID command.  However, a
+   server MAY send NIL in place of the list.
+
+3.3. Defined Field Values
+
+   Any string may be sent as a field, but the following are defined to
+   describe certain values that might be sent.  Implementations are free
+   to send none, any, or all of these.  Strings are not case-sensitive.
+   Field strings MUST NOT be longer than 30 octets.  Value strings MUST
+   NOT be longer than 1024 octets.  Implementations MUST NOT send more
+   than 30 field-value pairs.
+
+     name            Name of the program
+     version         Version number of the program
+     os              Name of the operating system
+     os-version      Version of the operating system
+     vendor          Vendor of the client/server
+     support-url     URL to contact for support
+     address         Postal address of contact/vendor
+     date            Date program was released, specified as a date-time
+                       in IMAP4rev1
+     command         Command used to start the program
+     arguments       Arguments supplied on the command line, if any
+                       if any
+     environment     Description of environment, i.e., UNIX environment
+                       variables or Windows registry settings
+
+   Implementations MUST NOT use contact information to submit automatic
+   bug reports.  Implementations may include information from an ID
+   response in a report automatically prepared, but are prohibited from
+   sending the report without user authorization.
+
+   It is preferable to find the name and version of the underlying
+   operating system at runtime in cases where this is possible.
+
+   Information sent via an ID response may violate user privacy.  See
+   Security Considerations, section 7.
+
+   Implementations MUST NOT send the same field name more than once.
+
+
+
+
+
+
+Showalter                   Standards Track                     [Page 4]
+
+RFC 2971                   IMAP4 ID extension               October 2000
+
+
+4. Formal Syntax
+
+   This  syntax is intended to augment the grammar specified in
+   [IMAP4rev1] in order to provide for the ID command.  This
+   specification uses the augmented Backus-Naur Form (BNF) notation as
+   used in [IMAP4rev1].
+
+     command_any ::= "CAPABILITY" / "LOGOUT" / "NOOP" / x_command / id
+         ;; adds id command to command_any in [IMAP4rev1]
+
+     id ::= "ID" SPACE id_params_list
+
+     id_response ::= "ID" SPACE id_params_list
+
+     id_params_list ::= "(" #(string SPACE nstring) ")" / nil
+         ;; list of field value pairs
+
+     response_data ::= "*" SPACE (resp_cond_state / resp_cond_bye /
+         mailbox_data / message_data / capability_data / id_response)
+
+5. Use of the ID extension with Firewalls and Other Intermediaries
+
+   There exist proxies, firewalls, and other intermediary systems that
+   can intercept an IMAP session and make changes to the data exchanged
+   in the session.  Such intermediaries are not anticipated by the IMAP4
+   protocol design and are not within the scope of the IMAP4 standard.
+   However, in order for the ID command to be useful in the presence of
+   such intermediaries, those intermediaries need to take special note
+   of the ID command and response.  In particular, if an intermediary
+   changes any part of the IMAP session it must also change the ID
+   command to advertise its presence.
+
+   A firewall MAY act to block transmission of specific information
+   fields in the ID command and response that it believes reveal
+   information that could expose a security vulnerability.  However, a
+   firewall SHOULD NOT disable the extension, when present, entirely,
+   and SHOULD NOT unconditionally remove either the client or server
+   list.
+
+   Finally, it should be noted that a firewall, when handling a
+   CAPABILITY response, MUST NOT allow the names of extensions to be
+   returned to the client that the firewall has no knowledge of.
+
+
+
+
+
+
+
+
+
+Showalter                   Standards Track                     [Page 5]
+
+RFC 2971                   IMAP4 ID extension               October 2000
+
+
+6. References
+
+   [KEYWORDS]  Bradner, S., "Key words for use in RFCs to Indicate
+               Requirement Levels", RFC 2119, March 1997.
+
+   [IMAP4rev1] Crispin, M., "Internet Message Access Protocol - Version
+               4rev1", RFC 2060, October 1996.
+
+   [RFC-822]   Crocker, D., "Standard for the Format of ARPA Internet
+               Text Messages", STD 11, RFC 822, August 1982.
+
+7. Security Considerations
+
+   This extension has the danger of violating the privacy of users if
+   misused.  Clients and servers should notify users that they implement
+   and enable the ID command.
+
+   It is highly desirable that implementations provide a method of
+   disabling ID support, perhaps by not sending ID at all, or by sending
+   NIL as the argument to the ID command or response.
+
+   Implementors must exercise extreme care in adding fields sent as part
+   of an ID command or response.  Some fields, including a processor ID
+   number, Ethernet address, or other unique (or mostly unique)
+   identifier allow tracking of users in ways that violate user privacy
+   expectations.
+
+   Having implementation information of a given client or server may
+   make it easier for an attacker to gain unauthorized access due to
+   security holes.
+
+   Since this command includes arbitrary data and does not require the
+   user to authenticate, server implementations are cautioned to guard
+   against an attacker sending arbitrary garbage data in order to fill
+   up the ID log.  In particular, if a server naively logs each ID
+   command to disk without inspecting it, an attacker can simply fire up
+   thousands of connections and send a few kilobytes of random data.
+   Servers have to guard against this.  Methods include truncating
+   abnormally large responses; collating responses by storing only a
+   single copy, then keeping a counter of the number of times that
+   response has been seen; keeping only particularly interesting parts
+   of responses; and only logging responses of users who actually log
+   in.
+
+   Security is affected by firewalls which modify the IMAP protocol
+   stream; see section 5, Use of the ID Extension with Firewalls and
+   Other Intermediaries, for more information.
+
+
+
+
+Showalter                   Standards Track                     [Page 6]
+
+RFC 2971                   IMAP4 ID extension               October 2000
+
+
+8. Author's Address
+
+   Tim Showalter
+   Mirapoint, Inc.
+   909 Hermosa Ct.
+   Sunnyvale, CA 94095
+
+   EMail: tjs@mirapoint.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Showalter                   Standards Track                     [Page 7]
+
+RFC 2971                   IMAP4 ID extension               October 2000
+
+
+9.  Full Copyright Statement
+
+   Copyright (C) The Internet Society (2000).  All Rights Reserved.
+
+   This document and translations of it may be copied and furnished to
+   others, and derivative works that comment on or otherwise explain it
+   or assist in its implementation may be prepared, copied, published
+   and distributed, in whole or in part, without restriction of any
+   kind, provided that the above copyright notice and this paragraph are
+   included on all such copies and derivative works.  However, this
+   document itself may not be modified in any way, such as by removing
+   the copyright notice or references to the Internet Society or other
+   Internet organizations, except as needed for the purpose of
+   developing Internet standards in which case the procedures for
+   copyrights defined in the Internet Standards process must be
+   followed, or as required to translate it into languages other than
+   English.
+
+   The limited permissions granted above are perpetual and will not be
+   revoked by the Internet Society or its successors or assigns.
+
+   This document and the information contained herein is provided on an
+   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is currently provided by the
+   Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Showalter                   Standards Track                     [Page 8]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc3348.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,339 @@
+
+
+
+
+
+
+Network Working Group                                          M. Gahrns
+Request for Comments: 3348                                      R. Cheng
+Category: Informational                                        Microsoft
+                                                               July 2002
+
+
+             The Internet Message Action Protocol (IMAP4)
+                        Child Mailbox Extension
+
+Status of this Memo
+
+   This memo provides information for the Internet community.  It does
+   not specify an Internet standard of any kind.  Distribution of this
+   memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (2002).  All Rights Reserved.
+
+Abstract
+
+   The Internet Message Action Protocol (IMAP4) CHILDREN extension
+   provides a mechanism for a client to efficiently determine if a
+   particular mailbox has children, without issuing a LIST "" * or a
+   LIST "" % for each mailbox.
+
+1. Conventions used in this document
+
+   In examples, "C:" and "S:" indicate lines sent by the client and
+   server respectively.  If such lines are wrapped without a new "C:" or
+   "S:" label, then the wrapping is for editorial clarity and is not
+   part of the command.
+
+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+   "SHOULD", "SHOULD NOT", "RECOMMENDED",  "MAY", and "OPTIONAL" in this
+   document are to be interpreted as described in [RFC-2119].
+
+2. Introduction and Overview
+
+   Many IMAP4 [RFC-2060] clients present to the user a hierarchical view
+   of the mailboxes that a user has access to.  Rather than initially
+   presenting to the user the entire mailbox hierarchy, it is often
+   preferable to show to the user a collapsed outline list of the
+   mailbox hierarchy (particularly if there is a large number of
+   mailboxes).  The user can then expand the collapsed outline hierarchy
+   as needed.  It is common to include within the collapsed hierarchy a
+
+
+
+
+
+Gahrns, et al.               Informational                      [Page 1]
+
+RFC 3348             IMAP4 Child Mailbox Extension             July 2002
+
+
+   visual clue (such as a "+") to indicate that there are child
+   mailboxes under a particular mailbox.  When the visual clue is
+   clicked the hierarchy list is expanded to show the child mailboxes.
+
+   Several IMAP vendors implemented this proposal, and it is proposed to
+   document this behavior and functionality as an Informational RFC.
+
+   There is interest in addressing the general extensibility of the IMAP
+   LIST command through an IMAP LIST Extension draft.  Similar
+   functionality to the \HasChildren and \HasNoChildren flags could be
+   incorporated into this new LIST Extension.  It is proposed that the
+   more general LIST Extension draft proceed on the standards track with
+   this proposal being relegated to informational status only.
+
+   If the functionality of the \HasChildren and \HasNoChildren flags
+   were incorporated into a more general LIST extension, this would have
+   the advantage that a client could then have the opportunity to
+   request whether or not the server should return this information.
+   This would be an advantage over the current draft for servers where
+   this information is expensive to compute, since the server would only
+   need to compute the information when it knew that the client
+   requesting the information was able to consume it.
+
+3. Requirements
+
+   IMAP4 servers that support this extension MUST list the keyword
+   CHILDREN in their CAPABILITY response.
+
+   The CHILDREN extension defines two new attributes that MAY be
+   returned within a LIST response.
+
+   \HasChildren - The presence of this attribute indicates that the
+   mailbox has child mailboxes.
+
+   Servers SHOULD NOT return \HasChildren if child mailboxes exist, but
+   none will be displayed to the current user in a LIST response (as
+   should be the case where child mailboxes exist, but a client does not
+   have permissions to access them.)  In this case, \HasNoChildren
+   SHOULD be used.
+
+   In many cases, however, a server may not be able to efficiently
+   compute whether a user has access to all child mailboxes, or multiple
+   users may be accessing the same account and simultaneously changing
+   the mailbox hierarchy.  As such a client MUST be prepared to accept
+   the \HasChildren attribute as a hint.  That is, a mailbox MAY be
+   flagged with the \HasChildren attribute, but no child mailboxes will
+   appear in a subsequent LIST response.
+
+
+
+
+Gahrns, et al.               Informational                      [Page 2]
+
+RFC 3348             IMAP4 Child Mailbox Extension             July 2002
+
+
+   Example 3.1:
+   ============
+
+   /*** Consider a server that has the following mailbox hierarchy:
+
+   INBOX
+   ITEM_1
+      ITEM_1A
+   ITEM_2
+      TOP_SECRET
+
+   Where INBOX, ITEM_1 and ITEM_2 are top level mailboxes.  ITEM_1A is a
+   child mailbox of ITEM_1 and TOP_SECRET is a child mailbox of ITEM_2
+   that the currently logged on user does NOT have access to.
+
+   Note that in this case, the server is not able to efficiently compute
+   access rights to child mailboxes and responds with a \HasChildren
+   attribute for mailbox ITEM_2, even though ITEM_2/TOP_SECRET does not
+   appear in the list response.  ***/
+
+   C: A001 LIST "" *
+   S: * LIST (\HasNoChildren) "/" INBOX
+   S: * LIST (\HasChildren) "/" ITEM_1
+   S: * LIST (\HasNoChildren) "/" ITEM_1/ITEM_1A
+   S: * LIST (\HasChildren) "/" ITEM_2
+   S: A001 OK LIST Completed
+
+   \HasNoChildren - The presence of this attribute indicates that the
+   mailbox has NO child mailboxes that are accessible to the currently
+   authenticated user.  If a mailbox has the \Noinferiors attribute, the
+   \HasNoChildren attribute is redundant and SHOULD be omitted in the
+   LIST response.
+
+   In some instances a server that supports the CHILDREN extension MAY
+   NOT be able to determine whether a mailbox has children.  For example
+   it may have difficulty determining whether there are child mailboxes
+   when LISTing mailboxes while operating in a particular namespace.
+
+   In these cases, a server MAY exclude both the \HasChildren and
+   \HasNoChildren attributes in the LIST response.  As such, a client
+   can not make any assumptions about whether a mailbox has children
+   based upon the absence of a single attribute.
+
+   It is an error for the server to return both a \HasChildren and a
+   \HasNoChildren attribute in a LIST response.
+
+
+
+
+
+
+Gahrns, et al.               Informational                      [Page 3]
+
+RFC 3348             IMAP4 Child Mailbox Extension             July 2002
+
+
+   It is an error for the server to return both a \HasChildren and a
+   \NoInferiors attribute in a LIST response.
+
+   Note: the \HasNoChildren attribute should not be confused with the
+   IMAP4 [RFC-2060] defined attribute \Noinferiors which indicates that
+   no child mailboxes exist now and none can be created in the future.
+
+   The \HasChildren and \HasNoChildren attributes might not be returned
+   in response to a LSUB response.  Many servers maintain a simple
+   mailbox subscription list that is not updated when the underlying
+   mailbox structure is changed.  A client MUST NOT assume that
+   hierarchy information will be maintained in the subscription list.
+
+   RLIST is a command defined in [RFC-2193] that includes in a LIST
+   response mailboxes that are accessible only via referral.  That is, a
+   client must explicitly issue an RLIST command to see a list of these
+   mailboxes.  Thus in the case where a mailbox has child mailboxes that
+   are available only via referral, the mailboxes would appear as
+   \HasNoChildren in response to the LIST command, and \HasChildren in
+   response to the RLIST command.
+
+5. Formal Syntax
+
+   The following syntax specification uses the augmented Backus-Naur
+   Form (BNF) as described in [ABNF].
+
+   Two new mailbox attributes are defined as flag_extensions to the
+   IMAP4 mailbox_list response:
+
+   HasChildren = "\HasChildren"
+
+   HasNoChildren = "\HasNoChildren"
+
+6. Security Considerations
+
+   This extension provides a client a more efficient means of
+   determining whether a particular mailbox has children.  If a mailbox
+   has children, but the currently authenticated user does not have
+   access to any of them, the server SHOULD respond with a
+   \HasNoChildren attribute.  In many cases, however, a server may not
+   be able to efficiently compute whether a user has access to all child
+   mailboxes.  If such a server responds with a \HasChildren attribute,
+   when in fact the currently authenticated user does not have access to
+   any child mailboxes, potentially more information is conveyed about
+   the mailbox than intended.  A server designed with such levels of
+   security in mind SHOULD NOT attach the \HasChildren attribute to a
+   mailbox unless the server is certain that the user has access to at
+   least one of the child mailboxes.
+
+
+
+Gahrns, et al.               Informational                      [Page 4]
+
+RFC 3348             IMAP4 Child Mailbox Extension             July 2002
+
+
+7. References
+
+   [RFC-2060] Crispin, M., "Internet Message Access Protocol - Version
+              4rev1", RFC 2060, December 1996.
+
+   [RFC-2119] Bradner, S., "Key words for use in RFCs to Indicate
+              Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+   [RFC-2234] Crocker, D. and P. Overell, Editors, "Augmented BNF for
+              Syntax Specifications: ABNF", RFC 2234, November 1997.
+
+   [RFC-2193] Gahrns, M., "IMAP4 Mailbox Referrals", RFC 2193, September
+              1997.
+
+8.  Acknowledgments
+
+   The authors would like to thank the participants of several IMC Mail
+   Connect events for their input when this idea was originally
+   presented and refined.
+
+9. Author's Address
+
+   Mike Gahrns
+   Microsoft
+   One Microsoft Way
+   Redmond, WA, 98052
+   Phone: (425) 936-9833
+   EMail: mikega@microsoft.com
+
+   Raymond Cheng
+   Microsoft
+   One Microsoft Way
+   Redmond, WA, 98052
+   Phone: (425) 703-4913
+   EMail: raych@microsoft.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Gahrns, et al.               Informational                      [Page 5]
+
+RFC 3348             IMAP4 Child Mailbox Extension             July 2002
+
+
+10. Full Copyright Statement
+
+   Copyright (C) The Internet Society (2002).  All Rights Reserved.
+
+   This document and translations of it may be copied and furnished to
+   others, and derivative works that comment on or otherwise explain it
+   or assist in its implementation may be prepared, copied, published
+   and distributed, in whole or in part, without restriction of any
+   kind, provided that the above copyright notice and this paragraph are
+   included on all such copies and derivative works.  However, this
+   document itself may not be modified in any way, such as by removing
+   the copyright notice or references to the Internet Society or other
+   Internet organizations, except as needed for the purpose of
+   developing Internet standards in which case the procedures for
+   copyrights defined in the Internet Standards process must be
+   followed, or as required to translate it into languages other than
+   English.
+
+   The limited permissions granted above are perpetual and will not be
+   revoked by the Internet Society or its successors or assigns.
+
+   This document and the information contained herein is provided on an
+   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is currently provided by the
+   Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Gahrns, et al.               Informational                      [Page 6]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc3501.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,6052 @@
+
+
+
+
+
+
+Network Working Group                                         M. Crispin
+Request for Comments: 3501                      University of Washington
+Obsoletes: 2060                                               March 2003
+Category: Standards Track
+
+
+            INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1
+
+Status of this Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (2003).  All Rights Reserved.
+
+Abstract
+
+   The Internet Message Access Protocol, Version 4rev1 (IMAP4rev1)
+   allows a client to access and manipulate electronic mail messages on
+   a server.  IMAP4rev1 permits manipulation of mailboxes (remote
+   message folders) in a way that is functionally equivalent to local
+   folders.  IMAP4rev1 also provides the capability for an offline
+   client to resynchronize with the server.
+
+   IMAP4rev1 includes operations for creating, deleting, and renaming
+   mailboxes, checking for new messages, permanently removing messages,
+   setting and clearing flags, RFC 2822 and RFC 2045 parsing, searching,
+   and selective fetching of message attributes, texts, and portions
+   thereof.  Messages in IMAP4rev1 are accessed by the use of numbers.
+   These numbers are either message sequence numbers or unique
+   identifiers.
+
+   IMAP4rev1 supports a single server.  A mechanism for accessing
+   configuration information to support multiple IMAP4rev1 servers is
+   discussed in RFC 2244.
+
+   IMAP4rev1 does not specify a means of posting mail; this function is
+   handled by a mail transfer protocol such as RFC 2821.
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                     [Page 1]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+Table of Contents
+
+   IMAP4rev1 Protocol Specification ................................  4
+   1.      How to Read This Document ...............................  4
+   1.1.    Organization of This Document ...........................  4
+   1.2.    Conventions Used in This Document .......................  4
+   1.3.    Special Notes to Implementors ...........................  5
+   2.      Protocol Overview .......................................  6
+   2.1.    Link Level ..............................................  6
+   2.2.    Commands and Responses ..................................  6
+   2.2.1.  Client Protocol Sender and Server Protocol Receiver .....  6
+   2.2.2.  Server Protocol Sender and Client Protocol Receiver .....  7
+   2.3.    Message Attributes ......................................  8
+   2.3.1.  Message Numbers .........................................  8
+   2.3.1.1.        Unique Identifier (UID) Message Attribute .......  8
+   2.3.1.2.        Message Sequence Number Message Attribute ....... 10
+   2.3.2.  Flags Message Attribute ................................. 11
+   2.3.3.  Internal Date Message Attribute ......................... 12
+   2.3.4.  [RFC-2822] Size Message Attribute ....................... 12
+   2.3.5.  Envelope Structure Message Attribute .................... 12
+   2.3.6.  Body Structure Message Attribute ........................ 12
+   2.4.    Message Texts ........................................... 13
+   3.      State and Flow Diagram .................................. 13
+   3.1.    Not Authenticated State ................................. 13
+   3.2.    Authenticated State ..................................... 13
+   3.3.    Selected State .......................................... 13
+   3.4.    Logout State ............................................ 14
+   4.      Data Formats ............................................ 16
+   4.1.    Atom .................................................... 16
+   4.2.    Number .................................................. 16
+   4.3.    String .................................................. 16
+   4.3.1.  8-bit and Binary Strings ................................ 17
+   4.4.    Parenthesized List ...................................... 17
+   4.5.    NIL ..................................................... 17
+   5.      Operational Considerations .............................. 18
+   5.1.    Mailbox Naming .......................................... 18
+   5.1.1.  Mailbox Hierarchy Naming ................................ 19
+   5.1.2.  Mailbox Namespace Naming Convention ..................... 19
+   5.1.3.  Mailbox International Naming Convention ................. 19
+   5.2.    Mailbox Size and Message Status Updates ................. 21
+   5.3.    Response when no Command in Progress .................... 21
+   5.4.    Autologout Timer ........................................ 22
+   5.5.    Multiple Commands in Progress ........................... 22
+   6.      Client Commands ........................................  23
+   6.1.    Client Commands - Any State ............................  24
+   6.1.1.  CAPABILITY Command .....................................  24
+   6.1.2.  NOOP Command ...........................................  25
+   6.1.3.  LOGOUT Command .........................................  26
+
+
+
+Crispin                     Standards Track                     [Page 2]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   6.2.    Client Commands - Not Authenticated State ..............  26
+   6.2.1.  STARTTLS Command .......................................  27
+   6.2.2.  AUTHENTICATE Command ...................................  28
+   6.2.3.  LOGIN Command ..........................................  30
+   6.3.    Client Commands - Authenticated State ..................  31
+   6.3.1.  SELECT Command .........................................  32
+   6.3.2.  EXAMINE Command ........................................  34
+   6.3.3.  CREATE Command .........................................  34
+   6.3.4.  DELETE Command .........................................  35
+   6.3.5.  RENAME Command .........................................  37
+   6.3.6.  SUBSCRIBE Command ......................................  39
+   6.3.7.  UNSUBSCRIBE Command ....................................  39
+   6.3.8.  LIST Command ...........................................  40
+   6.3.9.  LSUB Command ...........................................  43
+   6.3.10. STATUS Command .........................................  44
+   6.3.11. APPEND Command .........................................  46
+   6.4.    Client Commands - Selected State .......................  47
+   6.4.1.  CHECK Command ..........................................  47
+   6.4.2.  CLOSE Command ..........................................  48
+   6.4.3.  EXPUNGE Command ........................................  49
+   6.4.4.  SEARCH Command .........................................  49
+   6.4.5.  FETCH Command ..........................................  54
+   6.4.6.  STORE Command ..........................................  58
+   6.4.7.  COPY Command ...........................................  59
+   6.4.8.  UID Command ............................................  60
+   6.5.    Client Commands - Experimental/Expansion ...............  62
+   6.5.1.  X<atom> Command ........................................  62
+   7.      Server Responses .......................................  62
+   7.1.    Server Responses - Status Responses ....................  63
+   7.1.1.  OK Response ............................................  65
+   7.1.2.  NO Response ............................................  66
+   7.1.3.  BAD Response ...........................................  66
+   7.1.4.  PREAUTH Response .......................................  67
+   7.1.5.  BYE Response ...........................................  67
+   7.2.    Server Responses - Server and Mailbox Status ...........  68
+   7.2.1.  CAPABILITY Response ....................................  68
+   7.2.2.  LIST Response ..........................................  69
+   7.2.3.  LSUB Response ..........................................  70
+   7.2.4   STATUS Response ........................................  70
+   7.2.5.  SEARCH Response ........................................  71
+   7.2.6.  FLAGS Response .........................................  71
+   7.3.    Server Responses - Mailbox Size ........................  71
+   7.3.1.  EXISTS Response ........................................  71
+   7.3.2.  RECENT Response ........................................  72
+   7.4.    Server Responses - Message Status ......................  72
+   7.4.1.  EXPUNGE Response .......................................  72
+   7.4.2.  FETCH Response .........................................  73
+   7.5.    Server Responses - Command Continuation Request ........  79
+
+
+
+Crispin                     Standards Track                     [Page 3]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   8.      Sample IMAP4rev1 connection ............................  80
+   9.      Formal Syntax ..........................................  81
+   10.     Author's Note ..........................................  92
+   11.     Security Considerations ................................  92
+   11.1.   STARTTLS Security Considerations .......................  92
+   11.2.   Other Security Considerations ..........................  93
+   12.     IANA Considerations ....................................  94
+   Appendices .....................................................  95
+   A.      References .............................................  95
+   B.      Changes from RFC 2060 ..................................  97
+   C.      Key Word Index ......................................... 103
+   Author's Address ............................................... 107
+   Full Copyright Statement ....................................... 108
+
+IMAP4rev1 Protocol Specification
+
+1.      How to Read This Document
+
+1.1.    Organization of This Document
+
+   This document is written from the point of view of the implementor of
+   an IMAP4rev1 client or server.  Beyond the protocol overview in
+   section 2, it is not optimized for someone trying to understand the
+   operation of the protocol.  The material in sections 3 through 5
+   provides the general context and definitions with which IMAP4rev1
+   operates.
+
+   Sections 6, 7, and 9 describe the IMAP commands, responses, and
+   syntax, respectively.  The relationships among these are such that it
+   is almost impossible to understand any of them separately.  In
+   particular, do not attempt to deduce command syntax from the command
+   section alone; instead refer to the Formal Syntax section.
+
+1.2.    Conventions Used in This Document
+
+   "Conventions" are basic principles or procedures.  Document
+   conventions are noted in this section.
+
+   In examples, "C:" and "S:" indicate lines sent by the client and
+   server respectively.
+
+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+   "SHOULD", "SHOULD NOT", "MAY", and "OPTIONAL" in this document are to
+   be interpreted as described in [KEYWORDS].
+
+   The word "can" (not "may") is used to refer to a possible
+   circumstance or situation, as opposed to an optional facility of the
+   protocol.
+
+
+
+Crispin                     Standards Track                     [Page 4]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   "User" is used to refer to a human user, whereas "client" refers to
+   the software being run by the user.
+
+   "Connection" refers to the entire sequence of client/server
+   interaction from the initial establishment of the network connection
+   until its termination.
+
+   "Session" refers to the sequence of client/server interaction from
+   the time that a mailbox is selected (SELECT or EXAMINE command) until
+   the time that selection ends (SELECT or EXAMINE of another mailbox,
+   CLOSE command, or connection termination).
+
+   Characters are 7-bit US-ASCII unless otherwise specified.  Other
+   character sets are indicated using a "CHARSET", as described in
+   [MIME-IMT] and defined in [CHARSET].  CHARSETs have important
+   additional semantics in addition to defining character set; refer to
+   these documents for more detail.
+
+   There are several protocol conventions in IMAP.  These refer to
+   aspects of the specification which are not strictly part of the IMAP
+   protocol, but reflect generally-accepted practice.  Implementations
+   need to be aware of these conventions, and avoid conflicts whether or
+   not they implement the convention.  For example, "&" may not be used
+   as a hierarchy delimiter since it conflicts with the Mailbox
+   International Naming Convention, and other uses of "&" in mailbox
+   names are impacted as well.
+
+1.3.    Special Notes to Implementors
+
+   Implementors of the IMAP protocol are strongly encouraged to read the
+   IMAP implementation recommendations document [IMAP-IMPLEMENTATION] in
+   conjunction with this document, to help understand the intricacies of
+   this protocol and how best to build an interoperable product.
+
+   IMAP4rev1 is designed to be upwards compatible from the [IMAP2] and
+   unpublished IMAP2bis protocols.  IMAP4rev1 is largely compatible with
+   the IMAP4 protocol described in RFC 1730; the exception being in
+   certain facilities added in RFC 1730 that proved problematic and were
+   subsequently removed.  In the course of the evolution of IMAP4rev1,
+   some aspects in the earlier protocols have become obsolete.  Obsolete
+   commands, responses, and data formats which an IMAP4rev1
+   implementation can encounter when used with an earlier implementation
+   are described in [IMAP-OBSOLETE].
+
+   Other compatibility issues with IMAP2bis, the most common variant of
+   the earlier protocol, are discussed in [IMAP-COMPAT].  A full
+   discussion of compatibility issues with rare (and presumed extinct)
+
+
+
+
+Crispin                     Standards Track                     [Page 5]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   variants of [IMAP2] is in [IMAP-HISTORICAL]; this document is
+   primarily of historical interest.
+
+   IMAP was originally developed for the older [RFC-822] standard, and
+   as a consequence several fetch items in IMAP incorporate "RFC822" in
+   their name.  With the exception of RFC822.SIZE, there are more modern
+   replacements; for example, the modern version of RFC822.HEADER is
+   BODY.PEEK[HEADER].  In all cases, "RFC822" should be interpreted as a
+   reference to the updated [RFC-2822] standard.
+
+2.      Protocol Overview
+
+2.1.    Link Level
+
+   The IMAP4rev1 protocol assumes a reliable data stream such as that
+   provided by TCP.  When TCP is used, an IMAP4rev1 server listens on
+   port 143.
+
+2.2.    Commands and Responses
+
+   An IMAP4rev1 connection consists of the establishment of a
+   client/server network connection, an initial greeting from the
+   server, and client/server interactions.  These client/server
+   interactions consist of a client command, server data, and a server
+   completion result response.
+
+   All interactions transmitted by client and server are in the form of
+   lines, that is, strings that end with a CRLF.  The protocol receiver
+   of an IMAP4rev1 client or server is either reading a line, or is
+   reading a sequence of octets with a known count followed by a line.
+
+2.2.1.  Client Protocol Sender and Server Protocol Receiver
+
+   The client command begins an operation.  Each client command is
+   prefixed with an identifier (typically a short alphanumeric string,
+   e.g., A0001, A0002, etc.) called a "tag".  A different tag is
+   generated by the client for each command.
+
+   Clients MUST follow the syntax outlined in this specification
+   strictly.  It is a syntax error to send a command with missing or
+   extraneous spaces or arguments.
+
+   There are two cases in which a line from the client does not
+   represent a complete command.  In one case, a command argument is
+   quoted with an octet count (see the description of literal in String
+   under Data Formats); in the other case, the command arguments require
+   server feedback (see the AUTHENTICATE command).  In either case, the
+
+
+
+
+Crispin                     Standards Track                     [Page 6]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   server sends a command continuation request response if it is ready
+   for the octets (if appropriate) and the remainder of the command.
+   This response is prefixed with the token "+".
+
+        Note: If instead, the server detected an error in the
+        command, it sends a BAD completion response with a tag
+        matching the command (as described below) to reject the
+        command and prevent the client from sending any more of the
+        command.
+
+        It is also possible for the server to send a completion
+        response for some other command (if multiple commands are
+        in progress), or untagged data.  In either case, the
+        command continuation request is still pending; the client
+        takes the appropriate action for the response, and reads
+        another response from the server.  In all cases, the client
+        MUST send a complete command (including receiving all
+        command continuation request responses and command
+        continuations for the command) before initiating a new
+        command.
+
+   The protocol receiver of an IMAP4rev1 server reads a command line
+   from the client, parses the command and its arguments, and transmits
+   server data and a server command completion result response.
+
+2.2.2.  Server Protocol Sender and Client Protocol Receiver
+
+   Data transmitted by the server to the client and status responses
+   that do not indicate command completion are prefixed with the token
+   "*", and are called untagged responses.
+
+   Server data MAY be sent as a result of a client command, or MAY be
+   sent unilaterally by the server.  There is no syntactic difference
+   between server data that resulted from a specific command and server
+   data that were sent unilaterally.
+
+   The server completion result response indicates the success or
+   failure of the operation.  It is tagged with the same tag as the
+   client command which began the operation.  Thus, if more than one
+   command is in progress, the tag in a server completion response
+   identifies the command to which the response applies.  There are
+   three possible server completion responses: OK (indicating success),
+   NO (indicating failure), or BAD (indicating a protocol error such as
+   unrecognized command or command syntax error).
+
+   Servers SHOULD enforce the syntax outlined in this specification
+   strictly.  Any client command with a protocol syntax error, including
+   (but not limited to) missing or extraneous spaces or arguments,
+
+
+
+Crispin                     Standards Track                     [Page 7]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   SHOULD be rejected, and the client given a BAD server completion
+   response.
+
+   The protocol receiver of an IMAP4rev1 client reads a response line
+   from the server.  It then takes action on the response based upon the
+   first token of the response, which can be a tag, a "*", or a "+".
+
+   A client MUST be prepared to accept any server response at all times.
+   This includes server data that was not requested.  Server data SHOULD
+   be recorded, so that the client can reference its recorded copy
+   rather than sending a command to the server to request the data.  In
+   the case of certain server data, the data MUST be recorded.
+
+   This topic is discussed in greater detail in the Server Responses
+   section.
+
+2.3.    Message Attributes
+
+   In addition to message text, each message has several attributes
+   associated with it.  These attributes can be retrieved individually
+   or in conjunction with other attributes or message texts.
+
+2.3.1.  Message Numbers
+
+   Messages in IMAP4rev1 are accessed by one of two numbers; the unique
+   identifier or the message sequence number.
+
+
+2.3.1.1.        Unique Identifier (UID) Message Attribute
+
+   A 32-bit value assigned to each message, which when used with the
+   unique identifier validity value (see below) forms a 64-bit value
+   that MUST NOT refer to any other message in the mailbox or any
+   subsequent mailbox with the same name forever.  Unique identifiers
+   are assigned in a strictly ascending fashion in the mailbox; as each
+   message is added to the mailbox it is assigned a higher UID than the
+   message(s) which were added previously.  Unlike message sequence
+   numbers, unique identifiers are not necessarily contiguous.
+
+   The unique identifier of a message MUST NOT change during the
+   session, and SHOULD NOT change between sessions.  Any change of
+   unique identifiers between sessions MUST be detectable using the
+   UIDVALIDITY mechanism discussed below.  Persistent unique identifiers
+   are required for a client to resynchronize its state from a previous
+   session with the server (e.g., disconnected or offline access
+   clients); this is discussed further in [IMAP-DISC].
+
+
+
+
+
+Crispin                     Standards Track                     [Page 8]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   Associated with every mailbox are two values which aid in unique
+   identifier handling: the next unique identifier value and the unique
+   identifier validity value.
+
+   The next unique identifier value is the predicted value that will be
+   assigned to a new message in the mailbox.  Unless the unique
+   identifier validity also changes (see below), the next unique
+   identifier value MUST have the following two characteristics.  First,
+   the next unique identifier value MUST NOT change unless new messages
+   are added to the mailbox; and second, the next unique identifier
+   value MUST change whenever new messages are added to the mailbox,
+   even if those new messages are subsequently expunged.
+
+        Note: The next unique identifier value is intended to
+        provide a means for a client to determine whether any
+        messages have been delivered to the mailbox since the
+        previous time it checked this value.  It is not intended to
+        provide any guarantee that any message will have this
+        unique identifier.  A client can only assume, at the time
+        that it obtains the next unique identifier value, that
+        messages arriving after that time will have a UID greater
+        than or equal to that value.
+
+   The unique identifier validity value is sent in a UIDVALIDITY
+   response code in an OK untagged response at mailbox selection time.
+   If unique identifiers from an earlier session fail to persist in this
+   session, the unique identifier validity value MUST be greater than
+   the one used in the earlier session.
+
+        Note: Ideally, unique identifiers SHOULD persist at all
+        times.  Although this specification recognizes that failure
+        to persist can be unavoidable in certain server
+        environments, it STRONGLY ENCOURAGES message store
+        implementation techniques that avoid this problem.  For
+        example:
+
+         1) Unique identifiers MUST be strictly ascending in the
+            mailbox at all times.  If the physical message store is
+            re-ordered by a non-IMAP agent, this requires that the
+            unique identifiers in the mailbox be regenerated, since
+            the former unique identifiers are no longer strictly
+            ascending as a result of the re-ordering.
+
+         2) If the message store has no mechanism to store unique
+            identifiers, it must regenerate unique identifiers at
+            each session, and each session must have a unique
+            UIDVALIDITY value.
+
+
+
+
+Crispin                     Standards Track                     [Page 9]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+         3) If the mailbox is deleted and a new mailbox with the
+            same name is created at a later date, the server must
+            either keep track of unique identifiers from the
+            previous instance of the mailbox, or it must assign a
+            new UIDVALIDITY value to the new instance of the
+            mailbox.  A good UIDVALIDITY value to use in this case
+            is a 32-bit representation of the creation date/time of
+            the mailbox.  It is alright to use a constant such as
+            1, but only if it guaranteed that unique identifiers
+            will never be reused, even in the case of a mailbox
+            being deleted (or renamed) and a new mailbox by the
+            same name created at some future time.
+
+         4) The combination of mailbox name, UIDVALIDITY, and UID
+            must refer to a single immutable message on that server
+            forever.  In particular, the internal date, [RFC-2822]
+            size, envelope, body structure, and message texts
+            (RFC822, RFC822.HEADER, RFC822.TEXT, and all BODY[...]
+            fetch data items) must never change.  This does not
+            include message numbers, nor does it include attributes
+            that can be set by a STORE command (e.g., FLAGS).
+
+
+2.3.1.2.        Message Sequence Number Message Attribute
+
+   A relative position from 1 to the number of messages in the mailbox.
+   This position MUST be ordered by ascending unique identifier.  As
+   each new message is added, it is assigned a message sequence number
+   that is 1 higher than the number of messages in the mailbox before
+   that new message was added.
+
+   Message sequence numbers can be reassigned during the session.  For
+   example, when a message is permanently removed (expunged) from the
+   mailbox, the message sequence number for all subsequent messages is
+   decremented.  The number of messages in the mailbox is also
+   decremented.  Similarly, a new message can be assigned a message
+   sequence number that was once held by some other message prior to an
+   expunge.
+
+   In addition to accessing messages by relative position in the
+   mailbox, message sequence numbers can be used in mathematical
+   calculations.  For example, if an untagged "11 EXISTS" is received,
+   and previously an untagged "8 EXISTS" was received, three new
+   messages have arrived with message sequence numbers of 9, 10, and 11.
+   Another example, if message 287 in a 523 message mailbox has UID
+   12345, there are exactly 286 messages which have lesser UIDs and 236
+   messages which have greater UIDs.
+
+
+
+
+Crispin                     Standards Track                    [Page 10]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+2.3.2.  Flags Message Attribute
+
+   A list of zero or more named tokens associated with the message.  A
+   flag is set by its addition to this list, and is cleared by its
+   removal.  There are two types of flags in IMAP4rev1.  A flag of
+   either type can be permanent or session-only.
+
+   A system flag is a flag name that is pre-defined in this
+   specification.  All system flags begin with "\".  Certain system
+   flags (\Deleted and \Seen) have special semantics described
+   elsewhere.  The currently-defined system flags are:
+
+        \Seen
+           Message has been read
+
+        \Answered
+           Message has been answered
+
+        \Flagged
+           Message is "flagged" for urgent/special attention
+
+        \Deleted
+           Message is "deleted" for removal by later EXPUNGE
+
+        \Draft
+           Message has not completed composition (marked as a draft).
+
+        \Recent
+           Message is "recently" arrived in this mailbox.  This session
+           is the first session to have been notified about this
+           message; if the session is read-write, subsequent sessions
+           will not see \Recent set for this message.  This flag can not
+           be altered by the client.
+
+           If it is not possible to determine whether or not this
+           session is the first session to be notified about a message,
+           then that message SHOULD be considered recent.
+
+           If multiple connections have the same mailbox selected
+           simultaneously, it is undefined which of these connections
+           will see newly-arrived messages with \Recent set and which
+           will see it without \Recent set.
+
+   A keyword is defined by the server implementation.  Keywords do not
+   begin with "\".  Servers MAY permit the client to define new keywords
+   in the mailbox (see the description of the PERMANENTFLAGS response
+   code for more information).
+
+
+
+
+Crispin                     Standards Track                    [Page 11]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   A flag can be permanent or session-only on a per-flag basis.
+   Permanent flags are those which the client can add or remove from the
+   message flags permanently; that is, concurrent and subsequent
+   sessions will see any change in permanent flags.  Changes to session
+   flags are valid only in that session.
+
+        Note: The \Recent system flag is a special case of a
+        session flag.  \Recent can not be used as an argument in a
+        STORE or APPEND command, and thus can not be changed at
+        all.
+
+2.3.3.  Internal Date Message Attribute
+
+   The internal date and time of the message on the server.  This
+   is not the date and time in the [RFC-2822] header, but rather a
+   date and time which reflects when the message was received.  In
+   the case of messages delivered via [SMTP], this SHOULD be the
+   date and time of final delivery of the message as defined by
+   [SMTP].  In the case of messages delivered by the IMAP4rev1 COPY
+   command, this SHOULD be the internal date and time of the source
+   message.  In the case of messages delivered by the IMAP4rev1
+   APPEND command, this SHOULD be the date and time as specified in
+   the APPEND command description.  All other cases are
+   implementation defined.
+
+2.3.4.  [RFC-2822] Size Message Attribute
+
+   The number of octets in the message, as expressed in [RFC-2822]
+   format.
+
+2.3.5.  Envelope Structure Message Attribute
+
+   A parsed representation of the [RFC-2822] header of the message.
+   Note that the IMAP Envelope structure is not the same as an
+   [SMTP] envelope.
+
+2.3.6.  Body Structure Message Attribute
+
+   A parsed representation of the [MIME-IMB] body structure
+   information of the message.
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 12]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+2.4.    Message Texts
+
+   In addition to being able to fetch the full [RFC-2822] text of a
+   message, IMAP4rev1 permits the fetching of portions of the full
+   message text.  Specifically, it is possible to fetch the
+   [RFC-2822] message header, [RFC-2822] message body, a [MIME-IMB]
+   body part, or a [MIME-IMB] header.
+
+3.      State and Flow Diagram
+
+   Once the connection between client and server is established, an
+   IMAP4rev1 connection is in one of four states.  The initial
+   state is identified in the server greeting.  Most commands are
+   only valid in certain states.  It is a protocol error for the
+   client to attempt a command while the connection is in an
+   inappropriate state, and the server will respond with a BAD or
+   NO (depending upon server implementation) command completion
+   result.
+
+3.1.    Not Authenticated State
+
+   In the not authenticated state, the client MUST supply
+   authentication credentials before most commands will be
+   permitted.  This state is entered when a connection starts
+   unless the connection has been pre-authenticated.
+
+3.2.    Authenticated State
+
+   In the authenticated state, the client is authenticated and MUST
+   select a mailbox to access before commands that affect messages
+   will be permitted.  This state is entered when a
+   pre-authenticated connection starts, when acceptable
+   authentication credentials have been provided, after an error in
+   selecting a mailbox, or after a successful CLOSE command.
+
+3.3.    Selected State
+
+   In a selected state, a mailbox has been selected to access.
+   This state is entered when a mailbox has been successfully
+   selected.
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 13]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+3.4.    Logout State
+
+   In the logout state, the connection is being terminated.  This
+   state can be entered as a result of a client request (via the
+   LOGOUT command) or by unilateral action on the part of either
+   the client or server.
+
+   If the client requests the logout state, the server MUST send an
+   untagged BYE response and a tagged OK response to the LOGOUT
+   command before the server closes the connection; and the client
+   MUST read the tagged OK response to the LOGOUT command before
+   the client closes the connection.
+
+   A server MUST NOT unilaterally close the connection without
+   sending an untagged BYE response that contains the reason for
+   having done so.  A client SHOULD NOT unilaterally close the
+   connection, and instead SHOULD issue a LOGOUT command.  If the
+   server detects that the client has unilaterally closed the
+   connection, the server MAY omit the untagged BYE response and
+   simply close its connection.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 14]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+                   +----------------------+
+                   |connection established|
+                   +----------------------+
+                              ||
+                              \/
+            +--------------------------------------+
+            |          server greeting             |
+            +--------------------------------------+
+                      || (1)       || (2)        || (3)
+                      \/           ||            ||
+            +-----------------+    ||            ||
+            |Not Authenticated|    ||            ||
+            +-----------------+    ||            ||
+             || (7)   || (4)       ||            ||
+             ||       \/           \/            ||
+             ||     +----------------+           ||
+             ||     | Authenticated  |<=++       ||
+             ||     +----------------+  ||       ||
+             ||       || (7)   || (5)   || (6)   ||
+             ||       ||       \/       ||       ||
+             ||       ||    +--------+  ||       ||
+             ||       ||    |Selected|==++       ||
+             ||       ||    +--------+           ||
+             ||       ||       || (7)            ||
+             \/       \/       \/                \/
+            +--------------------------------------+
+            |               Logout                 |
+            +--------------------------------------+
+                              ||
+                              \/
+                +-------------------------------+
+                |both sides close the connection|
+                +-------------------------------+
+
+         (1) connection without pre-authentication (OK greeting)
+         (2) pre-authenticated connection (PREAUTH greeting)
+         (3) rejected connection (BYE greeting)
+         (4) successful LOGIN or AUTHENTICATE command
+         (5) successful SELECT or EXAMINE command
+         (6) CLOSE command, or failed SELECT or EXAMINE command
+         (7) LOGOUT command, server shutdown, or connection closed
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 15]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+4.      Data Formats
+
+   IMAP4rev1 uses textual commands and responses.  Data in
+   IMAP4rev1 can be in one of several forms: atom, number, string,
+   parenthesized list, or NIL.  Note that a particular data item
+   may take more than one form; for example, a data item defined as
+   using "astring" syntax may be either an atom or a string.
+
+4.1.    Atom
+
+   An atom consists of one or more non-special characters.
+
+4.2.    Number
+
+   A number consists of one or more digit characters, and
+   represents a numeric value.
+
+4.3.    String
+
+   A string is in one of two forms: either literal or quoted
+   string.  The literal form is the general form of string.  The
+   quoted string form is an alternative that avoids the overhead of
+   processing a literal at the cost of limitations of characters
+   which may be used.
+
+   A literal is a sequence of zero or more octets (including CR and
+   LF), prefix-quoted with an octet count in the form of an open
+   brace ("{"), the number of octets, close brace ("}"), and CRLF.
+   In the case of literals transmitted from server to client, the
+   CRLF is immediately followed by the octet data.  In the case of
+   literals transmitted from client to server, the client MUST wait
+   to receive a command continuation request (described later in
+   this document) before sending the octet data (and the remainder
+   of the command).
+
+   A quoted string is a sequence of zero or more 7-bit characters,
+   excluding CR and LF, with double quote (<">) characters at each
+   end.
+
+   The empty string is represented as either "" (a quoted string
+   with zero characters between double quotes) or as {0} followed
+   by CRLF (a literal with an octet count of 0).
+
+     Note: Even if the octet count is 0, a client transmitting a
+     literal MUST wait to receive a command continuation request.
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 16]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+4.3.1.  8-bit and Binary Strings
+
+   8-bit textual and binary mail is supported through the use of a
+   [MIME-IMB] content transfer encoding.  IMAP4rev1 implementations MAY
+   transmit 8-bit or multi-octet characters in literals, but SHOULD do
+   so only when the [CHARSET] is identified.
+
+   Although a BINARY body encoding is defined, unencoded binary strings
+   are not permitted.  A "binary string" is any string with NUL
+   characters.  Implementations MUST encode binary data into a textual
+   form, such as BASE64, before transmitting the data.  A string with an
+   excessive amount of CTL characters MAY also be considered to be
+   binary.
+
+4.4.    Parenthesized List
+
+   Data structures are represented as a "parenthesized list"; a sequence
+   of data items, delimited by space, and bounded at each end by
+   parentheses.  A parenthesized list can contain other parenthesized
+   lists, using multiple levels of parentheses to indicate nesting.
+
+   The empty list is represented as () -- a parenthesized list with no
+   members.
+
+4.5.    NIL
+
+   The special form "NIL" represents the non-existence of a particular
+   data item that is represented as a string or parenthesized list, as
+   distinct from the empty string "" or the empty parenthesized list ().
+
+        Note: NIL is never used for any data item which takes the
+        form of an atom.  For example, a mailbox name of "NIL" is a
+        mailbox named NIL as opposed to a non-existent mailbox
+        name.  This is because mailbox uses "astring" syntax which
+        is an atom or a string.  Conversely, an addr-name of NIL is
+        a non-existent personal name, because addr-name uses
+        "nstring" syntax which is NIL or a string, but never an
+        atom.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 17]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+5.      Operational Considerations
+
+   The following rules are listed here to ensure that all IMAP4rev1
+   implementations interoperate properly.
+
+5.1.    Mailbox Naming
+
+   Mailbox names are 7-bit.  Client implementations MUST NOT attempt to
+   create 8-bit mailbox names, and SHOULD interpret any 8-bit mailbox
+   names returned by LIST or LSUB as UTF-8.  Server implementations
+   SHOULD prohibit the creation of 8-bit mailbox names, and SHOULD NOT
+   return 8-bit mailbox names in LIST or LSUB.  See section 5.1.3 for
+   more information on how to represent non-ASCII mailbox names.
+
+        Note: 8-bit mailbox names were undefined in earlier
+        versions of this protocol.  Some sites used a local 8-bit
+        character set to represent non-ASCII mailbox names.  Such
+        usage is not interoperable, and is now formally deprecated.
+
+   The case-insensitive mailbox name INBOX is a special name reserved to
+   mean "the primary mailbox for this user on this server".  The
+   interpretation of all other names is implementation-dependent.
+
+   In particular, this specification takes no position on case
+   sensitivity in non-INBOX mailbox names.  Some server implementations
+   are fully case-sensitive; others preserve case of a newly-created
+   name but otherwise are case-insensitive; and yet others coerce names
+   to a particular case.  Client implementations MUST interact with any
+   of these.  If a server implementation interprets non-INBOX mailbox
+   names as case-insensitive, it MUST treat names using the
+   international naming convention specially as described in section
+   5.1.3.
+
+   There are certain client considerations when creating a new mailbox
+   name:
+
+   1)    Any character which is one of the atom-specials (see the Formal
+         Syntax) will require that the mailbox name be represented as a
+         quoted string or literal.
+
+   2)    CTL and other non-graphic characters are difficult to represent
+         in a user interface and are best avoided.
+
+   3)    Although the list-wildcard characters ("%" and "*") are valid
+         in a mailbox name, it is difficult to use such mailbox names
+         with the LIST and LSUB commands due to the conflict with
+         wildcard interpretation.
+
+
+
+
+Crispin                     Standards Track                    [Page 18]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   4)    Usually, a character (determined by the server implementation)
+         is reserved to delimit levels of hierarchy.
+
+   5)    Two characters, "#" and "&", have meanings by convention, and
+         should be avoided except when used in that convention.
+
+5.1.1.  Mailbox Hierarchy Naming
+
+   If it is desired to export hierarchical mailbox names, mailbox names
+   MUST be left-to-right hierarchical using a single character to
+   separate levels of hierarchy.  The same hierarchy separator character
+   is used for all levels of hierarchy within a single name.
+
+5.1.2.  Mailbox Namespace Naming Convention
+
+   By convention, the first hierarchical element of any mailbox name
+   which begins with "#" identifies the "namespace" of the remainder of
+   the name.  This makes it possible to disambiguate between different
+   types of mailbox stores, each of which have their own namespaces.
+
+        For example, implementations which offer access to USENET
+        newsgroups MAY use the "#news" namespace to partition the
+        USENET newsgroup namespace from that of other mailboxes.
+        Thus, the comp.mail.misc newsgroup would have a mailbox
+        name of "#news.comp.mail.misc", and the name
+        "comp.mail.misc" can refer to a different object (e.g., a
+        user's private mailbox).
+
+5.1.3.  Mailbox International Naming Convention
+
+   By convention, international mailbox names in IMAP4rev1 are specified
+   using a modified version of the UTF-7 encoding described in [UTF-7].
+   Modified UTF-7 may also be usable in servers that implement an
+   earlier version of this protocol.
+
+   In modified UTF-7, printable US-ASCII characters, except for "&",
+   represent themselves; that is, characters with octet values 0x20-0x25
+   and 0x27-0x7e.  The character "&" (0x26) is represented by the
+   two-octet sequence "&-".
+
+   All other characters (octet values 0x00-0x1f and 0x7f-0xff) are
+   represented in modified BASE64, with a further modification from
+   [UTF-7] that "," is used instead of "/".  Modified BASE64 MUST NOT be
+   used to represent any printing US-ASCII character which can represent
+   itself.
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 19]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   "&" is used to shift to modified BASE64 and "-" to shift back to
+   US-ASCII.  There is no implicit shift from BASE64 to US-ASCII, and
+   null shifts ("-&" while in BASE64; note that "&-" while in US-ASCII
+   means "&") are not permitted.  However, all names start in US-ASCII,
+   and MUST end in US-ASCII; that is, a name that ends with a non-ASCII
+   ISO-10646 character MUST end with a "-").
+
+   The purpose of these modifications is to correct the following
+   problems with UTF-7:
+
+      1) UTF-7 uses the "+" character for shifting; this conflicts with
+         the common use of "+" in mailbox names, in particular USENET
+         newsgroup names.
+
+      2) UTF-7's encoding is BASE64 which uses the "/" character; this
+         conflicts with the use of "/" as a popular hierarchy delimiter.
+
+      3) UTF-7 prohibits the unencoded usage of "\"; this conflicts with
+         the use of "\" as a popular hierarchy delimiter.
+
+      4) UTF-7 prohibits the unencoded usage of "~"; this conflicts with
+         the use of "~" in some servers as a home directory indicator.
+
+      5) UTF-7 permits multiple alternate forms to represent the same
+         string; in particular, printable US-ASCII characters can be
+         represented in encoded form.
+
+      Although modified UTF-7 is a convention, it establishes certain
+      requirements on server handling of any mailbox name with an
+      embedded "&" character.  In particular, server implementations
+      MUST preserve the exact form of the modified BASE64 portion of a
+      modified UTF-7 name and treat that text as case-sensitive, even if
+      names are otherwise case-insensitive or case-folded.
+
+      Server implementations SHOULD verify that any mailbox name with an
+      embedded "&" character, used as an argument to CREATE, is: in the
+      correctly modified UTF-7 syntax, has no superfluous shifts, and
+      has no encoding in modified BASE64 of any printing US-ASCII
+      character which can represent itself.  However, client
+      implementations MUST NOT depend upon the server doing this, and
+      SHOULD NOT attempt to create a mailbox name with an embedded "&"
+      character unless it complies with the modified UTF-7 syntax.
+
+      Server implementations which export a mail store that does not
+      follow the modified UTF-7 convention MUST convert to modified
+      UTF-7 any mailbox name that contains either non-ASCII characters
+      or the "&" character.
+
+
+
+
+Crispin                     Standards Track                    [Page 20]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+           For example, here is a mailbox name which mixes English,
+           Chinese, and Japanese text:
+           ~peter/mail/&U,BTFw-/&ZeVnLIqe-
+
+           For example, the string "&Jjo!" is not a valid mailbox
+           name because it does not contain a shift to US-ASCII
+           before the "!".  The correct form is "&Jjo-!".  The
+           string "&U,BTFw-&ZeVnLIqe-" is not permitted because it
+           contains a superfluous shift.  The correct form is
+           "&U,BTF2XlZyyKng-".
+
+5.2.    Mailbox Size and Message Status Updates
+
+   At any time, a server can send data that the client did not request.
+   Sometimes, such behavior is REQUIRED.  For example, agents other than
+   the server MAY add messages to the mailbox (e.g., new message
+   delivery), change the flags of the messages in the mailbox (e.g.,
+   simultaneous access to the same mailbox by multiple agents), or even
+   remove messages from the mailbox.  A server MUST send mailbox size
+   updates automatically if a mailbox size change is observed during the
+   processing of a command.  A server SHOULD send message flag updates
+   automatically, without requiring the client to request such updates
+   explicitly.
+
+   Special rules exist for server notification of a client about the
+   removal of messages to prevent synchronization errors; see the
+   description of the EXPUNGE response for more detail.  In particular,
+   it is NOT permitted to send an EXISTS response that would reduce the
+   number of messages in the mailbox; only the EXPUNGE response can do
+   this.
+
+   Regardless of what implementation decisions a client makes on
+   remembering data from the server, a client implementation MUST record
+   mailbox size updates.  It MUST NOT assume that any command after the
+   initial mailbox selection will return the size of the mailbox.
+
+5.3.    Response when no Command in Progress
+
+   Server implementations are permitted to send an untagged response
+   (except for EXPUNGE) while there is no command in progress.  Server
+   implementations that send such responses MUST deal with flow control
+   considerations.  Specifically, they MUST either (1) verify that the
+   size of the data does not exceed the underlying transport's available
+   window size, or (2) use non-blocking writes.
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 21]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+5.4.    Autologout Timer
+
+   If a server has an inactivity autologout timer, the duration of that
+   timer MUST be at least 30 minutes.  The receipt of ANY command from
+   the client during that interval SHOULD suffice to reset the
+   autologout timer.
+
+5.5.    Multiple Commands in Progress
+
+   The client MAY send another command without waiting for the
+   completion result response of a command, subject to ambiguity rules
+   (see below) and flow control constraints on the underlying data
+   stream.  Similarly, a server MAY begin processing another command
+   before processing the current command to completion, subject to
+   ambiguity rules.  However, any command continuation request responses
+   and command continuations MUST be negotiated before any subsequent
+   command is initiated.
+
+   The exception is if an ambiguity would result because of a command
+   that would affect the results of other commands.  Clients MUST NOT
+   send multiple commands without waiting if an ambiguity would result.
+   If the server detects a possible ambiguity, it MUST execute commands
+   to completion in the order given by the client.
+
+   The most obvious example of ambiguity is when a command would affect
+   the results of another command, e.g., a FETCH of a message's flags
+   and a STORE of that same message's flags.
+
+   A non-obvious ambiguity occurs with commands that permit an untagged
+   EXPUNGE response (commands other than FETCH, STORE, and SEARCH),
+   since an untagged EXPUNGE response can invalidate sequence numbers in
+   a subsequent command.  This is not a problem for FETCH, STORE, or
+   SEARCH commands because servers are prohibited from sending EXPUNGE
+   responses while any of those commands are in progress.  Therefore, if
+   the client sends any command other than FETCH, STORE, or SEARCH, it
+   MUST wait for the completion result response before sending a command
+   with message sequence numbers.
+
+        Note: UID FETCH, UID STORE, and UID SEARCH are different
+        commands from FETCH, STORE, and SEARCH.  If the client
+        sends a UID command, it must wait for a completion result
+        response before sending a command with message sequence
+        numbers.
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 22]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   For example, the following non-waiting command sequences are invalid:
+
+      FETCH + NOOP + STORE
+      STORE + COPY + FETCH
+      COPY + COPY
+      CHECK + FETCH
+
+   The following are examples of valid non-waiting command sequences:
+
+      FETCH + STORE + SEARCH + CHECK
+      STORE + COPY + EXPUNGE
+
+      UID SEARCH + UID SEARCH may be valid or invalid as a non-waiting
+      command sequence, depending upon whether or not the second UID
+      SEARCH contains message sequence numbers.
+
+6.      Client Commands
+
+   IMAP4rev1 commands are described in this section.  Commands are
+   organized by the state in which the command is permitted.  Commands
+   which are permitted in multiple states are listed in the minimum
+   permitted state (for example, commands valid in authenticated and
+   selected state are listed in the authenticated state commands).
+
+   Command arguments, identified by "Arguments:" in the command
+   descriptions below, are described by function, not by syntax.  The
+   precise syntax of command arguments is described in the Formal Syntax
+   section.
+
+   Some commands cause specific server responses to be returned; these
+   are identified by "Responses:" in the command descriptions below.
+   See the response descriptions in the Responses section for
+   information on these responses, and the Formal Syntax section for the
+   precise syntax of these responses.  It is possible for server data to
+   be transmitted as a result of any command.  Thus, commands that do
+   not specifically require server data specify "no specific responses
+   for this command" instead of "none".
+
+   The "Result:" in the command description refers to the possible
+   tagged status responses to a command, and any special interpretation
+   of these status responses.
+
+   The state of a connection is only changed by successful commands
+   which are documented as changing state.  A rejected command (BAD
+   response) never changes the state of the connection or of the
+   selected mailbox.  A failed command (NO response) generally does not
+   change the state of the connection or of the selected mailbox; the
+   exception being the SELECT and EXAMINE commands.
+
+
+
+Crispin                     Standards Track                    [Page 23]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+6.1.    Client Commands - Any State
+
+   The following commands are valid in any state: CAPABILITY, NOOP, and
+   LOGOUT.
+
+6.1.1.  CAPABILITY Command
+
+   Arguments:  none
+
+   Responses:  REQUIRED untagged response: CAPABILITY
+
+   Result:     OK - capability completed
+               BAD - command unknown or arguments invalid
+
+      The CAPABILITY command requests a listing of capabilities that the
+      server supports.  The server MUST send a single untagged
+      CAPABILITY response with "IMAP4rev1" as one of the listed
+      capabilities before the (tagged) OK response.
+
+      A capability name which begins with "AUTH=" indicates that the
+      server supports that particular authentication mechanism.  All
+      such names are, by definition, part of this specification.  For
+      example, the authorization capability for an experimental
+      "blurdybloop" authenticator would be "AUTH=XBLURDYBLOOP" and not
+      "XAUTH=BLURDYBLOOP" or "XAUTH=XBLURDYBLOOP".
+
+      Other capability names refer to extensions, revisions, or
+      amendments to this specification.  See the documentation of the
+      CAPABILITY response for additional information.  No capabilities,
+      beyond the base IMAP4rev1 set defined in this specification, are
+      enabled without explicit client action to invoke the capability.
+
+      Client and server implementations MUST implement the STARTTLS,
+      LOGINDISABLED, and AUTH=PLAIN (described in [IMAP-TLS])
+      capabilities.  See the Security Considerations section for
+      important information.
+
+      See the section entitled "Client Commands -
+      Experimental/Expansion" for information about the form of site or
+      implementation-specific capabilities.
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 24]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   Example:    C: abcd CAPABILITY
+               S: * CAPABILITY IMAP4rev1 STARTTLS AUTH=GSSAPI
+               LOGINDISABLED
+               S: abcd OK CAPABILITY completed
+               C: efgh STARTTLS
+               S: efgh OK STARTLS completed
+               <TLS negotiation, further commands are under [TLS] layer>
+               C: ijkl CAPABILITY
+               S: * CAPABILITY IMAP4rev1 AUTH=GSSAPI AUTH=PLAIN
+               S: ijkl OK CAPABILITY completed
+
+
+6.1.2.  NOOP Command
+
+   Arguments:  none
+
+   Responses:  no specific responses for this command (but see below)
+
+   Result:     OK - noop completed
+               BAD - command unknown or arguments invalid
+
+      The NOOP command always succeeds.  It does nothing.
+
+      Since any command can return a status update as untagged data, the
+      NOOP command can be used as a periodic poll for new messages or
+      message status updates during a period of inactivity (this is the
+      preferred method to do this).  The NOOP command can also be used
+      to reset any inactivity autologout timer on the server.
+
+   Example:    C: a002 NOOP
+               S: a002 OK NOOP completed
+                  . . .
+               C: a047 NOOP
+               S: * 22 EXPUNGE
+               S: * 23 EXISTS
+               S: * 3 RECENT
+               S: * 14 FETCH (FLAGS (\Seen \Deleted))
+               S: a047 OK NOOP completed
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 25]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+6.1.3.  LOGOUT Command
+
+   Arguments:  none
+
+   Responses:  REQUIRED untagged response: BYE
+
+   Result:     OK - logout completed
+               BAD - command unknown or arguments invalid
+
+      The LOGOUT command informs the server that the client is done with
+      the connection.  The server MUST send a BYE untagged response
+      before the (tagged) OK response, and then close the network
+      connection.
+
+   Example:    C: A023 LOGOUT
+               S: * BYE IMAP4rev1 Server logging out
+               S: A023 OK LOGOUT completed
+               (Server and client then close the connection)
+
+6.2.    Client Commands - Not Authenticated State
+
+   In the not authenticated state, the AUTHENTICATE or LOGIN command
+   establishes authentication and enters the authenticated state.  The
+   AUTHENTICATE command provides a general mechanism for a variety of
+   authentication techniques, privacy protection, and integrity
+   checking; whereas the LOGIN command uses a traditional user name and
+   plaintext password pair and has no means of establishing privacy
+   protection or integrity checking.
+
+   The STARTTLS command is an alternate form of establishing session
+   privacy protection and integrity checking, but does not establish
+   authentication or enter the authenticated state.
+
+   Server implementations MAY allow access to certain mailboxes without
+   establishing authentication.  This can be done by means of the
+   ANONYMOUS [SASL] authenticator described in [ANONYMOUS].  An older
+   convention is a LOGIN command using the userid "anonymous"; in this
+   case, a password is required although the server may choose to accept
+   any password.  The restrictions placed on anonymous users are
+   implementation-dependent.
+
+   Once authenticated (including as anonymous), it is not possible to
+   re-enter not authenticated state.
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 26]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   In addition to the universal commands (CAPABILITY, NOOP, and LOGOUT),
+   the following commands are valid in the not authenticated state:
+   STARTTLS, AUTHENTICATE and LOGIN.  See the Security Considerations
+   section for important information about these commands.
+
+6.2.1.  STARTTLS Command
+
+   Arguments:  none
+
+   Responses:  no specific response for this command
+
+   Result:     OK - starttls completed, begin TLS negotiation
+               BAD - command unknown or arguments invalid
+
+      A [TLS] negotiation begins immediately after the CRLF at the end
+      of the tagged OK response from the server.  Once a client issues a
+      STARTTLS command, it MUST NOT issue further commands until a
+      server response is seen and the [TLS] negotiation is complete.
+
+      The server remains in the non-authenticated state, even if client
+      credentials are supplied during the [TLS] negotiation.  This does
+      not preclude an authentication mechanism such as EXTERNAL (defined
+      in [SASL]) from using client identity determined by the [TLS]
+      negotiation.
+
+      Once [TLS] has been started, the client MUST discard cached
+      information about server capabilities and SHOULD re-issue the
+      CAPABILITY command.  This is necessary to protect against man-in-
+      the-middle attacks which alter the capabilities list prior to
+      STARTTLS.  The server MAY advertise different capabilities after
+      STARTTLS.
+
+   Example:    C: a001 CAPABILITY
+               S: * CAPABILITY IMAP4rev1 STARTTLS LOGINDISABLED
+               S: a001 OK CAPABILITY completed
+               C: a002 STARTTLS
+               S: a002 OK Begin TLS negotiation now
+               <TLS negotiation, further commands are under [TLS] layer>
+               C: a003 CAPABILITY
+               S: * CAPABILITY IMAP4rev1 AUTH=PLAIN
+               S: a003 OK CAPABILITY completed
+               C: a004 LOGIN joe password
+               S: a004 OK LOGIN completed
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 27]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+6.2.2.  AUTHENTICATE Command
+
+   Arguments:  authentication mechanism name
+
+   Responses:  continuation data can be requested
+
+   Result:     OK - authenticate completed, now in authenticated state
+               NO - authenticate failure: unsupported authentication
+                    mechanism, credentials rejected
+               BAD - command unknown or arguments invalid,
+                    authentication exchange cancelled
+
+      The AUTHENTICATE command indicates a [SASL] authentication
+      mechanism to the server.  If the server supports the requested
+      authentication mechanism, it performs an authentication protocol
+      exchange to authenticate and identify the client.  It MAY also
+      negotiate an OPTIONAL security layer for subsequent protocol
+      interactions.  If the requested authentication mechanism is not
+      supported, the server SHOULD reject the AUTHENTICATE command by
+      sending a tagged NO response.
+
+      The AUTHENTICATE command does not support the optional "initial
+      response" feature of [SASL].  Section 5.1 of [SASL] specifies how
+      to handle an authentication mechanism which uses an initial
+      response.
+
+      The service name specified by this protocol's profile of [SASL] is
+      "imap".
+
+      The authentication protocol exchange consists of a series of
+      server challenges and client responses that are specific to the
+      authentication mechanism.  A server challenge consists of a
+      command continuation request response with the "+" token followed
+      by a BASE64 encoded string.  The client response consists of a
+      single line consisting of a BASE64 encoded string.  If the client
+      wishes to cancel an authentication exchange, it issues a line
+      consisting of a single "*".  If the server receives such a
+      response, it MUST reject the AUTHENTICATE command by sending a
+      tagged BAD response.
+
+      If a security layer is negotiated through the [SASL]
+      authentication exchange, it takes effect immediately following the
+      CRLF that concludes the authentication exchange for the client,
+      and the CRLF of the tagged OK response for the server.
+
+      While client and server implementations MUST implement the
+      AUTHENTICATE command itself, it is not required to implement any
+      authentication mechanisms other than the PLAIN mechanism described
+
+
+
+Crispin                     Standards Track                    [Page 28]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+      in [IMAP-TLS].  Also, an authentication mechanism is not required
+      to support any security layers.
+
+           Note: a server implementation MUST implement a
+           configuration in which it does NOT permit any plaintext
+           password mechanisms, unless either the STARTTLS command
+           has been negotiated or some other mechanism that
+           protects the session from password snooping has been
+           provided.  Server sites SHOULD NOT use any configuration
+           which permits a plaintext password mechanism without
+           such a protection mechanism against password snooping.
+           Client and server implementations SHOULD implement
+           additional [SASL] mechanisms that do not use plaintext
+           passwords, such the GSSAPI mechanism described in [SASL]
+           and/or the [DIGEST-MD5] mechanism.
+
+      Servers and clients can support multiple authentication
+      mechanisms.  The server SHOULD list its supported authentication
+      mechanisms in the response to the CAPABILITY command so that the
+      client knows which authentication mechanisms to use.
+
+      A server MAY include a CAPABILITY response code in the tagged OK
+      response of a successful AUTHENTICATE command in order to send
+      capabilities automatically.  It is unnecessary for a client to
+      send a separate CAPABILITY command if it recognizes these
+      automatic capabilities.  This should only be done if a security
+      layer was not negotiated by the AUTHENTICATE command, because the
+      tagged OK response as part of an AUTHENTICATE command is not
+      protected by encryption/integrity checking.  [SASL] requires the
+      client to re-issue a CAPABILITY command in this case.
+
+      If an AUTHENTICATE command fails with a NO response, the client
+      MAY try another authentication mechanism by issuing another
+      AUTHENTICATE command.  It MAY also attempt to authenticate by
+      using the LOGIN command (see section 6.2.3 for more detail).  In
+      other words, the client MAY request authentication types in
+      decreasing order of preference, with the LOGIN command as a last
+      resort.
+
+      The authorization identity passed from the client to the server
+      during the authentication exchange is interpreted by the server as
+      the user name whose privileges the client is requesting.
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 29]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   Example:    S: * OK IMAP4rev1 Server
+               C: A001 AUTHENTICATE GSSAPI
+               S: +
+               C: YIIB+wYJKoZIhvcSAQICAQBuggHqMIIB5qADAgEFoQMCAQ6iBw
+                  MFACAAAACjggEmYYIBIjCCAR6gAwIBBaESGxB1Lndhc2hpbmd0
+                  b24uZWR1oi0wK6ADAgEDoSQwIhsEaW1hcBsac2hpdmFtcy5jYW
+                  Mud2FzaGluZ3Rvbi5lZHWjgdMwgdCgAwIBAaEDAgEDooHDBIHA
+                  cS1GSa5b+fXnPZNmXB9SjL8Ollj2SKyb+3S0iXMljen/jNkpJX
+                  AleKTz6BQPzj8duz8EtoOuNfKgweViyn/9B9bccy1uuAE2HI0y
+                  C/PHXNNU9ZrBziJ8Lm0tTNc98kUpjXnHZhsMcz5Mx2GR6dGknb
+                  I0iaGcRerMUsWOuBmKKKRmVMMdR9T3EZdpqsBd7jZCNMWotjhi
+                  vd5zovQlFqQ2Wjc2+y46vKP/iXxWIuQJuDiisyXF0Y8+5GTpAL
+                  pHDc1/pIGmMIGjoAMCAQGigZsEgZg2on5mSuxoDHEA1w9bcW9n
+                  FdFxDKpdrQhVGVRDIzcCMCTzvUboqb5KjY1NJKJsfjRQiBYBdE
+                  NKfzK+g5DlV8nrw81uOcP8NOQCLR5XkoMHC0Dr/80ziQzbNqhx
+                  O6652Npft0LQwJvenwDI13YxpwOdMXzkWZN/XrEqOWp6GCgXTB
+                  vCyLWLlWnbaUkZdEYbKHBPjd8t/1x5Yg==
+               S: + YGgGCSqGSIb3EgECAgIAb1kwV6ADAgEFoQMCAQ+iSzBJoAMC
+                  AQGiQgRAtHTEuOP2BXb9sBYFR4SJlDZxmg39IxmRBOhXRKdDA0
+                  uHTCOT9Bq3OsUTXUlk0CsFLoa8j+gvGDlgHuqzWHPSQg==
+               C:
+               S: + YDMGCSqGSIb3EgECAgIBAAD/////6jcyG4GE3KkTzBeBiVHe
+                  ceP2CWY0SR0fAQAgAAQEBAQ=
+               C: YDMGCSqGSIb3EgECAgIBAAD/////3LQBHXTpFfZgrejpLlLImP
+                  wkhbfa2QteAQAgAG1yYwE=
+               S: A001 OK GSSAPI authentication successful
+
+        Note: The line breaks within server challenges and client
+        responses are for editorial clarity and are not in real
+        authenticators.
+
+
+6.2.3.  LOGIN Command
+
+   Arguments:  user name
+               password
+
+   Responses:  no specific responses for this command
+
+   Result:     OK - login completed, now in authenticated state
+               NO - login failure: user name or password rejected
+               BAD - command unknown or arguments invalid
+
+      The LOGIN command identifies the client to the server and carries
+      the plaintext password authenticating this user.
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 30]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+      A server MAY include a CAPABILITY response code in the tagged OK
+      response to a successful LOGIN command in order to send
+      capabilities automatically.  It is unnecessary for a client to
+      send a separate CAPABILITY command if it recognizes these
+      automatic capabilities.
+
+   Example:    C: a001 LOGIN SMITH SESAME
+               S: a001 OK LOGIN completed
+
+        Note: Use of the LOGIN command over an insecure network
+        (such as the Internet) is a security risk, because anyone
+        monitoring network traffic can obtain plaintext passwords.
+        The LOGIN command SHOULD NOT be used except as a last
+        resort, and it is recommended that client implementations
+        have a means to disable any automatic use of the LOGIN
+        command.
+
+        Unless either the STARTTLS command has been negotiated or
+        some other mechanism that protects the session from
+        password snooping has been provided, a server
+        implementation MUST implement a configuration in which it
+        advertises the LOGINDISABLED capability and does NOT permit
+        the LOGIN command.  Server sites SHOULD NOT use any
+        configuration which permits the LOGIN command without such
+        a protection mechanism against password snooping.  A client
+        implementation MUST NOT send a LOGIN command if the
+        LOGINDISABLED capability is advertised.
+
+6.3.    Client Commands - Authenticated State
+
+   In the authenticated state, commands that manipulate mailboxes as
+   atomic entities are permitted.  Of these commands, the SELECT and
+   EXAMINE commands will select a mailbox for access and enter the
+   selected state.
+
+   In addition to the universal commands (CAPABILITY, NOOP, and LOGOUT),
+   the following commands are valid in the authenticated state: SELECT,
+   EXAMINE, CREATE, DELETE, RENAME, SUBSCRIBE, UNSUBSCRIBE, LIST, LSUB,
+   STATUS, and APPEND.
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 31]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+6.3.1.  SELECT Command
+
+   Arguments:  mailbox name
+
+   Responses:  REQUIRED untagged responses: FLAGS, EXISTS, RECENT
+               REQUIRED OK untagged responses:  UNSEEN,  PERMANENTFLAGS,
+               UIDNEXT, UIDVALIDITY
+
+   Result:     OK - select completed, now in selected state
+               NO - select failure, now in authenticated state: no
+                    such mailbox, can't access mailbox
+               BAD - command unknown or arguments invalid
+
+      The SELECT command selects a mailbox so that messages in the
+      mailbox can be accessed.  Before returning an OK to the client,
+      the server MUST send the following untagged data to the client.
+      Note that earlier versions of this protocol only required the
+      FLAGS, EXISTS, and RECENT untagged data; consequently, client
+      implementations SHOULD implement default behavior for missing data
+      as discussed with the individual item.
+
+         FLAGS       Defined flags in the mailbox.  See the description
+                     of the FLAGS response for more detail.
+
+         <n> EXISTS  The number of messages in the mailbox.  See the
+                     description of the EXISTS response for more detail.
+
+         <n> RECENT  The number of messages with the \Recent flag set.
+                     See the description of the RECENT response for more
+                     detail.
+
+         OK [UNSEEN <n>]
+                     The message sequence number of the first unseen
+                     message in the mailbox.  If this is missing, the
+                     client can not make any assumptions about the first
+                     unseen message in the mailbox, and needs to issue a
+                     SEARCH command if it wants to find it.
+
+         OK [PERMANENTFLAGS (<list of flags>)]
+                     A list of message flags that the client can change
+                     permanently.  If this is missing, the client should
+                     assume that all flags can be changed permanently.
+
+         OK [UIDNEXT <n>]
+                     The next unique identifier value.  Refer to section
+                     2.3.1.1 for more information.  If this is missing,
+                     the client can not make any assumptions about the
+                     next unique identifier value.
+
+
+
+Crispin                     Standards Track                    [Page 32]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+         OK [UIDVALIDITY <n>]
+                     The unique identifier validity value.  Refer to
+                     section 2.3.1.1 for more information.  If this is
+                     missing, the server does not support unique
+                     identifiers.
+
+      Only one mailbox can be selected at a time in a connection;
+      simultaneous access to multiple mailboxes requires multiple
+      connections.  The SELECT command automatically deselects any
+      currently selected mailbox before attempting the new selection.
+      Consequently, if a mailbox is selected and a SELECT command that
+      fails is attempted, no mailbox is selected.
+
+      If the client is permitted to modify the mailbox, the server
+      SHOULD prefix the text of the tagged OK response with the
+      "[READ-WRITE]" response code.
+
+      If the client is not permitted to modify the mailbox but is
+      permitted read access, the mailbox is selected as read-only, and
+      the server MUST prefix the text of the tagged OK response to
+      SELECT with the "[READ-ONLY]" response code.  Read-only access
+      through SELECT differs from the EXAMINE command in that certain
+      read-only mailboxes MAY permit the change of permanent state on a
+      per-user (as opposed to global) basis.  Netnews messages marked in
+      a server-based .newsrc file are an example of such per-user
+      permanent state that can be modified with read-only mailboxes.
+
+   Example:    C: A142 SELECT INBOX
+               S: * 172 EXISTS
+               S: * 1 RECENT
+               S: * OK [UNSEEN 12] Message 12 is first unseen
+               S: * OK [UIDVALIDITY 3857529045] UIDs valid
+               S: * OK [UIDNEXT 4392] Predicted next UID
+               S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
+               S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
+               S: A142 OK [READ-WRITE] SELECT completed
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 33]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+6.3.2.  EXAMINE Command
+
+   Arguments:  mailbox name
+
+   Responses:  REQUIRED untagged responses: FLAGS, EXISTS, RECENT
+               REQUIRED OK untagged responses:  UNSEEN,  PERMANENTFLAGS,
+               UIDNEXT, UIDVALIDITY
+
+   Result:     OK - examine completed, now in selected state
+               NO - examine failure, now in authenticated state: no
+                    such mailbox, can't access mailbox
+               BAD - command unknown or arguments invalid
+
+      The EXAMINE command is identical to SELECT and returns the same
+      output; however, the selected mailbox is identified as read-only.
+      No changes to the permanent state of the mailbox, including
+      per-user state, are permitted; in particular, EXAMINE MUST NOT
+      cause messages to lose the \Recent flag.
+
+      The text of the tagged OK response to the EXAMINE command MUST
+      begin with the "[READ-ONLY]" response code.
+
+   Example:    C: A932 EXAMINE blurdybloop
+               S: * 17 EXISTS
+               S: * 2 RECENT
+               S: * OK [UNSEEN 8] Message 8 is first unseen
+               S: * OK [UIDVALIDITY 3857529045] UIDs valid
+               S: * OK [UIDNEXT 4392] Predicted next UID
+               S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
+               S: * OK [PERMANENTFLAGS ()] No permanent flags permitted
+               S: A932 OK [READ-ONLY] EXAMINE completed
+
+
+6.3.3.  CREATE Command
+
+   Arguments:  mailbox name
+
+   Responses:  no specific responses for this command
+
+   Result:     OK - create completed
+               NO - create failure: can't create mailbox with that name
+               BAD - command unknown or arguments invalid
+
+      The CREATE command creates a mailbox with the given name.  An OK
+      response is returned only if a new mailbox with that name has been
+      created.  It is an error to attempt to create INBOX or a mailbox
+      with a name that refers to an extant mailbox.  Any error in
+      creation will return a tagged NO response.
+
+
+
+Crispin                     Standards Track                    [Page 34]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+      If the mailbox name is suffixed with the server's hierarchy
+      separator character (as returned from the server by a LIST
+      command), this is a declaration that the client intends to create
+      mailbox names under this name in the hierarchy.  Server
+      implementations that do not require this declaration MUST ignore
+      the declaration.  In any case, the name created is without the
+      trailing hierarchy delimiter.
+
+      If the server's hierarchy separator character appears elsewhere in
+      the name, the server SHOULD create any superior hierarchical names
+      that are needed for the CREATE command to be successfully
+      completed.  In other words, an attempt to create "foo/bar/zap" on
+      a server in which "/" is the hierarchy separator character SHOULD
+      create foo/ and foo/bar/ if they do not already exist.
+
+      If a new mailbox is created with the same name as a mailbox which
+      was deleted, its unique identifiers MUST be greater than any
+      unique identifiers used in the previous incarnation of the mailbox
+      UNLESS the new incarnation has a different unique identifier
+      validity value.  See the description of the UID command for more
+      detail.
+
+   Example:    C: A003 CREATE owatagusiam/
+               S: A003 OK CREATE completed
+               C: A004 CREATE owatagusiam/blurdybloop
+               S: A004 OK CREATE completed
+
+        Note: The interpretation of this example depends on whether
+        "/" was returned as the hierarchy separator from LIST.  If
+        "/" is the hierarchy separator, a new level of hierarchy
+        named "owatagusiam" with a member called "blurdybloop" is
+        created.  Otherwise, two mailboxes at the same hierarchy
+        level are created.
+
+
+6.3.4.  DELETE Command
+
+   Arguments:  mailbox name
+
+   Responses:  no specific responses for this command
+
+   Result:     OK - delete completed
+               NO - delete failure: can't delete mailbox with that name
+               BAD - command unknown or arguments invalid
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 35]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+      The DELETE command permanently removes the mailbox with the given
+      name.  A tagged OK response is returned only if the mailbox has
+      been deleted.  It is an error to attempt to delete INBOX or a
+      mailbox name that does not exist.
+
+      The DELETE command MUST NOT remove inferior hierarchical names.
+      For example, if a mailbox "foo" has an inferior "foo.bar"
+      (assuming "." is the hierarchy delimiter character), removing
+      "foo" MUST NOT remove "foo.bar".  It is an error to attempt to
+      delete a name that has inferior hierarchical names and also has
+      the \Noselect mailbox name attribute (see the description of the
+      LIST response for more details).
+
+      It is permitted to delete a name that has inferior hierarchical
+      names and does not have the \Noselect mailbox name attribute.  In
+      this case, all messages in that mailbox are removed, and the name
+      will acquire the \Noselect mailbox name attribute.
+
+      The value of the highest-used unique identifier of the deleted
+      mailbox MUST be preserved so that a new mailbox created with the
+      same name will not reuse the identifiers of the former
+      incarnation, UNLESS the new incarnation has a different unique
+      identifier validity value.  See the description of the UID command
+      for more detail.
+
+   Examples:   C: A682 LIST "" *
+               S: * LIST () "/" blurdybloop
+               S: * LIST (\Noselect) "/" foo
+               S: * LIST () "/" foo/bar
+               S: A682 OK LIST completed
+               C: A683 DELETE blurdybloop
+               S: A683 OK DELETE completed
+               C: A684 DELETE foo
+               S: A684 NO Name "foo" has inferior hierarchical names
+               C: A685 DELETE foo/bar
+               S: A685 OK DELETE Completed
+               C: A686 LIST "" *
+               S: * LIST (\Noselect) "/" foo
+               S: A686 OK LIST completed
+               C: A687 DELETE foo
+               S: A687 OK DELETE Completed
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 36]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+               C: A82 LIST "" *
+               S: * LIST () "." blurdybloop
+               S: * LIST () "." foo
+               S: * LIST () "." foo.bar
+               S: A82 OK LIST completed
+               C: A83 DELETE blurdybloop
+               S: A83 OK DELETE completed
+               C: A84 DELETE foo
+               S: A84 OK DELETE Completed
+               C: A85 LIST "" *
+               S: * LIST () "." foo.bar
+               S: A85 OK LIST completed
+               C: A86 LIST "" %
+               S: * LIST (\Noselect) "." foo
+               S: A86 OK LIST completed
+
+
+6.3.5.  RENAME Command
+
+   Arguments:  existing mailbox name
+               new mailbox name
+
+   Responses:  no specific responses for this command
+
+   Result:     OK - rename completed
+               NO - rename failure: can't rename mailbox with that name,
+                    can't rename to mailbox with that name
+               BAD - command unknown or arguments invalid
+
+      The RENAME command changes the name of a mailbox.  A tagged OK
+      response is returned only if the mailbox has been renamed.  It is
+      an error to attempt to rename from a mailbox name that does not
+      exist or to a mailbox name that already exists.  Any error in
+      renaming will return a tagged NO response.
+
+      If the name has inferior hierarchical names, then the inferior
+      hierarchical names MUST also be renamed.  For example, a rename of
+      "foo" to "zap" will rename "foo/bar" (assuming "/" is the
+      hierarchy delimiter character) to "zap/bar".
+
+      If the server's hierarchy separator character appears in the name,
+      the server SHOULD create any superior hierarchical names that are
+      needed for the RENAME command to complete successfully.  In other
+      words, an attempt to rename "foo/bar/zap" to baz/rag/zowie on a
+      server in which "/" is the hierarchy separator character SHOULD
+      create baz/ and baz/rag/ if they do not already exist.
+
+
+
+
+
+Crispin                     Standards Track                    [Page 37]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+      The value of the highest-used unique identifier of the old mailbox
+      name MUST be preserved so that a new mailbox created with the same
+      name will not reuse the identifiers of the former incarnation,
+      UNLESS the new incarnation has a different unique identifier
+      validity value.  See the description of the UID command for more
+      detail.
+
+      Renaming INBOX is permitted, and has special behavior.  It moves
+      all messages in INBOX to a new mailbox with the given name,
+      leaving INBOX empty.  If the server implementation supports
+      inferior hierarchical names of INBOX, these are unaffected by a
+      rename of INBOX.
+
+   Examples:   C: A682 LIST "" *
+               S: * LIST () "/" blurdybloop
+               S: * LIST (\Noselect) "/" foo
+               S: * LIST () "/" foo/bar
+               S: A682 OK LIST completed
+               C: A683 RENAME blurdybloop sarasoop
+               S: A683 OK RENAME completed
+               C: A684 RENAME foo zowie
+               S: A684 OK RENAME Completed
+               C: A685 LIST "" *
+               S: * LIST () "/" sarasoop
+               S: * LIST (\Noselect) "/" zowie
+               S: * LIST () "/" zowie/bar
+               S: A685 OK LIST completed
+
+               C: Z432 LIST "" *
+               S: * LIST () "." INBOX
+               S: * LIST () "." INBOX.bar
+               S: Z432 OK LIST completed
+               C: Z433 RENAME INBOX old-mail
+               S: Z433 OK RENAME completed
+               C: Z434 LIST "" *
+               S: * LIST () "." INBOX
+               S: * LIST () "." INBOX.bar
+               S: * LIST () "." old-mail
+               S: Z434 OK LIST completed
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 38]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+6.3.6.  SUBSCRIBE Command
+
+   Arguments:  mailbox
+
+   Responses:  no specific responses for this command
+
+   Result:     OK - subscribe completed
+               NO - subscribe failure: can't subscribe to that name
+               BAD - command unknown or arguments invalid
+
+      The SUBSCRIBE command adds the specified mailbox name to the
+      server's set of "active" or "subscribed" mailboxes as returned by
+      the LSUB command.  This command returns a tagged OK response only
+      if the subscription is successful.
+
+      A server MAY validate the mailbox argument to SUBSCRIBE to verify
+      that it exists.  However, it MUST NOT unilaterally remove an
+      existing mailbox name from the subscription list even if a mailbox
+      by that name no longer exists.
+
+           Note: This requirement is because a server site can
+           choose to routinely remove a mailbox with a well-known
+           name (e.g., "system-alerts") after its contents expire,
+           with the intention of recreating it when new contents
+           are appropriate.
+
+
+   Example:    C: A002 SUBSCRIBE #news.comp.mail.mime
+               S: A002 OK SUBSCRIBE completed
+
+
+6.3.7.  UNSUBSCRIBE Command
+
+   Arguments:  mailbox name
+
+   Responses:  no specific responses for this command
+
+   Result:     OK - unsubscribe completed
+               NO - unsubscribe failure: can't unsubscribe that name
+               BAD - command unknown or arguments invalid
+
+      The UNSUBSCRIBE command removes the specified mailbox name from
+      the server's set of "active" or "subscribed" mailboxes as returned
+      by the LSUB command.  This command returns a tagged OK response
+      only if the unsubscription is successful.
+
+   Example:    C: A002 UNSUBSCRIBE #news.comp.mail.mime
+               S: A002 OK UNSUBSCRIBE completed
+
+
+
+Crispin                     Standards Track                    [Page 39]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+6.3.8.  LIST Command
+
+   Arguments:  reference name
+               mailbox name with possible wildcards
+
+   Responses:  untagged responses: LIST
+
+   Result:     OK - list completed
+               NO - list failure: can't list that reference or name
+               BAD - command unknown or arguments invalid
+
+      The LIST command returns a subset of names from the complete set
+      of all names available to the client.  Zero or more untagged LIST
+      replies are returned, containing the name attributes, hierarchy
+      delimiter, and name; see the description of the LIST reply for
+      more detail.
+
+      The LIST command SHOULD return its data quickly, without undue
+      delay.  For example, it SHOULD NOT go to excess trouble to
+      calculate the \Marked or \Unmarked status or perform other
+      processing; if each name requires 1 second of processing, then a
+      list of 1200 names would take 20 minutes!
+
+      An empty ("" string) reference name argument indicates that the
+      mailbox name is interpreted as by SELECT.  The returned mailbox
+      names MUST match the supplied mailbox name pattern.  A non-empty
+      reference name argument is the name of a mailbox or a level of
+      mailbox hierarchy, and indicates the context in which the mailbox
+      name is interpreted.
+
+      An empty ("" string) mailbox name argument is a special request to
+      return the hierarchy delimiter and the root name of the name given
+      in the reference.  The value returned as the root MAY be the empty
+      string if the reference is non-rooted or is an empty string.  In
+      all cases, a hierarchy delimiter (or NIL if there is no hierarchy)
+      is returned.  This permits a client to get the hierarchy delimiter
+      (or find out that the mailbox names are flat) even when no
+      mailboxes by that name currently exist.
+
+      The reference and mailbox name arguments are interpreted into a
+      canonical form that represents an unambiguous left-to-right
+      hierarchy.  The returned mailbox names will be in the interpreted
+      form.
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 40]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+           Note: The interpretation of the reference argument is
+           implementation-defined.  It depends upon whether the
+           server implementation has a concept of the "current
+           working directory" and leading "break out characters",
+           which override the current working directory.
+
+           For example, on a server which exports a UNIX or NT
+           filesystem, the reference argument contains the current
+           working directory, and the mailbox name argument would
+           contain the name as interpreted in the current working
+           directory.
+
+           If a server implementation has no concept of break out
+           characters, the canonical form is normally the reference
+           name appended with the mailbox name.  Note that if the
+           server implements the namespace convention (section
+           5.1.2), "#" is a break out character and must be treated
+           as such.
+
+           If the reference argument is not a level of mailbox
+           hierarchy (that is, it is a \NoInferiors name), and/or
+           the reference argument does not end with the hierarchy
+           delimiter, it is implementation-dependent how this is
+           interpreted.  For example, a reference of "foo/bar" and
+           mailbox name of "rag/baz" could be interpreted as
+           "foo/bar/rag/baz", "foo/barrag/baz", or "foo/rag/baz".
+           A client SHOULD NOT use such a reference argument except
+           at the explicit request of the user.  A hierarchical
+           browser MUST NOT make any assumptions about server
+           interpretation of the reference unless the reference is
+           a level of mailbox hierarchy AND ends with the hierarchy
+           delimiter.
+
+      Any part of the reference argument that is included in the
+      interpreted form SHOULD prefix the interpreted form.  It SHOULD
+      also be in the same form as the reference name argument.  This
+      rule permits the client to determine if the returned mailbox name
+      is in the context of the reference argument, or if something about
+      the mailbox argument overrode the reference argument.  Without
+      this rule, the client would have to have knowledge of the server's
+      naming semantics including what characters are "breakouts" that
+      override a naming context.
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 41]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+           For example, here are some examples of how references
+           and mailbox names might be interpreted on a UNIX-based
+           server:
+
+               Reference     Mailbox Name  Interpretation
+               ------------  ------------  --------------
+               ~smith/Mail/  foo.*         ~smith/Mail/foo.*
+               archive/      %             archive/%
+               #news.        comp.mail.*   #news.comp.mail.*
+               ~smith/Mail/  /usr/doc/foo  /usr/doc/foo
+               archive/      ~fred/Mail/*  ~fred/Mail/*
+
+           The first three examples demonstrate interpretations in
+           the context of the reference argument.  Note that
+           "~smith/Mail" SHOULD NOT be transformed into something
+           like "/u2/users/smith/Mail", or it would be impossible
+           for the client to determine that the interpretation was
+           in the context of the reference.
+
+      The character "*" is a wildcard, and matches zero or more
+      characters at this position.  The character "%" is similar to "*",
+      but it does not match a hierarchy delimiter.  If the "%" wildcard
+      is the last character of a mailbox name argument, matching levels
+      of hierarchy are also returned.  If these levels of hierarchy are
+      not also selectable mailboxes, they are returned with the
+      \Noselect mailbox name attribute (see the description of the LIST
+      response for more details).
+
+      Server implementations are permitted to "hide" otherwise
+      accessible mailboxes from the wildcard characters, by preventing
+      certain characters or names from matching a wildcard in certain
+      situations.  For example, a UNIX-based server might restrict the
+      interpretation of "*" so that an initial "/" character does not
+      match.
+
+      The special name INBOX is included in the output from LIST, if
+      INBOX is supported by this server for this user and if the
+      uppercase string "INBOX" matches the interpreted reference and
+      mailbox name arguments with wildcards as described above.  The
+      criteria for omitting INBOX is whether SELECT INBOX will return
+      failure; it is not relevant whether the user's real INBOX resides
+      on this or some other server.
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 42]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   Example:    C: A101 LIST "" ""
+               S: * LIST (\Noselect) "/" ""
+               S: A101 OK LIST Completed
+               C: A102 LIST #news.comp.mail.misc ""
+               S: * LIST (\Noselect) "." #news.
+               S: A102 OK LIST Completed
+               C: A103 LIST /usr/staff/jones ""
+               S: * LIST (\Noselect) "/" /
+               S: A103 OK LIST Completed
+               C: A202 LIST ~/Mail/ %
+               S: * LIST (\Noselect) "/" ~/Mail/foo
+               S: * LIST () "/" ~/Mail/meetings
+               S: A202 OK LIST completed
+
+
+6.3.9.  LSUB Command
+
+   Arguments:  reference name
+               mailbox name with possible wildcards
+
+   Responses:  untagged responses: LSUB
+
+   Result:     OK - lsub completed
+               NO - lsub failure: can't list that reference or name
+               BAD - command unknown or arguments invalid
+
+      The LSUB command returns a subset of names from the set of names
+      that the user has declared as being "active" or "subscribed".
+      Zero or more untagged LSUB replies are returned.  The arguments to
+      LSUB are in the same form as those for LIST.
+
+      The returned untagged LSUB response MAY contain different mailbox
+      flags from a LIST untagged response.  If this should happen, the
+      flags in the untagged LIST are considered more authoritative.
+
+      A special situation occurs when using LSUB with the % wildcard.
+      Consider what happens if "foo/bar" (with a hierarchy delimiter of
+      "/") is subscribed but "foo" is not.  A "%" wildcard to LSUB must
+      return foo, not foo/bar, in the LSUB response, and it MUST be
+      flagged with the \Noselect attribute.
+
+      The server MUST NOT unilaterally remove an existing mailbox name
+      from the subscription list even if a mailbox by that name no
+      longer exists.
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 43]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   Example:    C: A002 LSUB "#news." "comp.mail.*"
+               S: * LSUB () "." #news.comp.mail.mime
+               S: * LSUB () "." #news.comp.mail.misc
+               S: A002 OK LSUB completed
+               C: A003 LSUB "#news." "comp.%"
+               S: * LSUB (\NoSelect) "." #news.comp.mail
+               S: A003 OK LSUB completed
+
+
+6.3.10. STATUS Command
+
+   Arguments:  mailbox name
+               status data item names
+
+   Responses:  untagged responses: STATUS
+
+   Result:     OK - status completed
+               NO - status failure: no status for that name
+               BAD - command unknown or arguments invalid
+
+      The STATUS command requests the status of the indicated mailbox.
+      It does not change the currently selected mailbox, nor does it
+      affect the state of any messages in the queried mailbox (in
+      particular, STATUS MUST NOT cause messages to lose the \Recent
+      flag).
+
+      The STATUS command provides an alternative to opening a second
+      IMAP4rev1 connection and doing an EXAMINE command on a mailbox to
+      query that mailbox's status without deselecting the current
+      mailbox in the first IMAP4rev1 connection.
+
+      Unlike the LIST command, the STATUS command is not guaranteed to
+      be fast in its response.  Under certain circumstances, it can be
+      quite slow.  In some implementations, the server is obliged to
+      open the mailbox read-only internally to obtain certain status
+      information.  Also unlike the LIST command, the STATUS command
+      does not accept wildcards.
+
+           Note: The STATUS command is intended to access the
+           status of mailboxes other than the currently selected
+           mailbox.  Because the STATUS command can cause the
+           mailbox to be opened internally, and because this
+           information is available by other means on the selected
+           mailbox, the STATUS command SHOULD NOT be used on the
+           currently selected mailbox.
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 44]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+           The STATUS command MUST NOT be used as a "check for new
+           messages in the selected mailbox" operation (refer to
+           sections 7, 7.3.1, and 7.3.2 for more information about
+           the proper method for new message checking).
+
+           Because the STATUS command is not guaranteed to be fast
+           in its results, clients SHOULD NOT expect to be able to
+           issue many consecutive STATUS commands and obtain
+           reasonable performance.
+
+      The currently defined status data items that can be requested are:
+
+      MESSAGES
+         The number of messages in the mailbox.
+
+      RECENT
+         The number of messages with the \Recent flag set.
+
+      UIDNEXT
+         The next unique identifier value of the mailbox.  Refer to
+         section 2.3.1.1 for more information.
+
+      UIDVALIDITY
+         The unique identifier validity value of the mailbox.  Refer to
+         section 2.3.1.1 for more information.
+
+      UNSEEN
+         The number of messages which do not have the \Seen flag set.
+
+
+   Example:    C: A042 STATUS blurdybloop (UIDNEXT MESSAGES)
+               S: * STATUS blurdybloop (MESSAGES 231 UIDNEXT 44292)
+               S: A042 OK STATUS completed
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 45]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+6.3.11. APPEND Command
+
+   Arguments:  mailbox name
+               OPTIONAL flag parenthesized list
+               OPTIONAL date/time string
+               message literal
+
+   Responses:  no specific responses for this command
+
+   Result:     OK - append completed
+               NO - append error: can't append to that mailbox, error
+                    in flags or date/time or message text
+               BAD - command unknown or arguments invalid
+
+      The APPEND command appends the literal argument as a new message
+      to the end of the specified destination mailbox.  This argument
+      SHOULD be in the format of an [RFC-2822] message.  8-bit
+      characters are permitted in the message.  A server implementation
+      that is unable to preserve 8-bit data properly MUST be able to
+      reversibly convert 8-bit APPEND data to 7-bit using a [MIME-IMB]
+      content transfer encoding.
+
+           Note: There MAY be exceptions, e.g., draft messages, in
+           which required [RFC-2822] header lines are omitted in
+           the message literal argument to APPEND.  The full
+           implications of doing so MUST be understood and
+           carefully weighed.
+
+      If a flag parenthesized list is specified, the flags SHOULD be set
+      in the resulting message; otherwise, the flag list of the
+      resulting message is set to empty by default.  In either case, the
+      Recent flag is also set.
+
+      If a date-time is specified, the internal date SHOULD be set in
+      the resulting message; otherwise, the internal date of the
+      resulting message is set to the current date and time by default.
+
+      If the append is unsuccessful for any reason, the mailbox MUST be
+      restored to its state before the APPEND attempt; no partial
+      appending is permitted.
+
+      If the destination mailbox does not exist, a server MUST return an
+      error, and MUST NOT automatically create the mailbox.  Unless it
+      is certain that the destination mailbox can not be created, the
+      server MUST send the response code "[TRYCREATE]" as the prefix of
+      the text of the tagged NO response.  This gives a hint to the
+      client that it can attempt a CREATE command and retry the APPEND
+      if the CREATE is successful.
+
+
+
+Crispin                     Standards Track                    [Page 46]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+      If the mailbox is currently selected, the normal new message
+      actions SHOULD occur.  Specifically, the server SHOULD notify the
+      client immediately via an untagged EXISTS response.  If the server
+      does not do so, the client MAY issue a NOOP command (or failing
+      that, a CHECK command) after one or more APPEND commands.
+
+   Example:    C: A003 APPEND saved-messages (\Seen) {310}
+               S: + Ready for literal data
+               C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
+               C: From: Fred Foobar <foobar@Blurdybloop.COM>
+               C: Subject: afternoon meeting
+               C: To: mooch@owatagu.siam.edu
+               C: Message-Id: <B27397-0100000@Blurdybloop.COM>
+               C: MIME-Version: 1.0
+               C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
+               C:
+               C: Hello Joe, do you think we can meet at 3:30 tomorrow?
+               C:
+               S: A003 OK APPEND completed
+
+        Note: The APPEND command is not used for message delivery,
+        because it does not provide a mechanism to transfer [SMTP]
+        envelope information.
+
+6.4.    Client Commands - Selected State
+
+   In the selected state, commands that manipulate messages in a mailbox
+   are permitted.
+
+   In addition to the universal commands (CAPABILITY, NOOP, and LOGOUT),
+   and the authenticated state commands (SELECT, EXAMINE, CREATE,
+   DELETE, RENAME, SUBSCRIBE, UNSUBSCRIBE, LIST, LSUB, STATUS, and
+   APPEND), the following commands are valid in the selected state:
+   CHECK, CLOSE, EXPUNGE, SEARCH, FETCH, STORE, COPY, and UID.
+
+6.4.1.  CHECK Command
+
+   Arguments:  none
+
+   Responses:  no specific responses for this command
+
+   Result:     OK - check completed
+               BAD - command unknown or arguments invalid
+
+      The CHECK command requests a checkpoint of the currently selected
+      mailbox.  A checkpoint refers to any implementation-dependent
+      housekeeping associated with the mailbox (e.g., resolving the
+      server's in-memory state of the mailbox with the state on its
+
+
+
+Crispin                     Standards Track                    [Page 47]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+      disk) that is not normally executed as part of each command.  A
+      checkpoint MAY take a non-instantaneous amount of real time to
+      complete.  If a server implementation has no such housekeeping
+      considerations, CHECK is equivalent to NOOP.
+
+      There is no guarantee that an EXISTS untagged response will happen
+      as a result of CHECK.  NOOP, not CHECK, SHOULD be used for new
+      message polling.
+
+   Example:    C: FXXZ CHECK
+               S: FXXZ OK CHECK Completed
+
+
+6.4.2.  CLOSE Command
+
+   Arguments:  none
+
+   Responses:  no specific responses for this command
+
+   Result:     OK - close completed, now in authenticated state
+               BAD - command unknown or arguments invalid
+
+      The CLOSE command permanently removes all messages that have the
+      \Deleted flag set from the currently selected mailbox, and returns
+      to the authenticated state from the selected state.  No untagged
+      EXPUNGE responses are sent.
+
+      No messages are removed, and no error is given, if the mailbox is
+      selected by an EXAMINE command or is otherwise selected read-only.
+
+      Even if a mailbox is selected, a SELECT, EXAMINE, or LOGOUT
+      command MAY be issued without previously issuing a CLOSE command.
+      The SELECT, EXAMINE, and LOGOUT commands implicitly close the
+      currently selected mailbox without doing an expunge.  However,
+      when many messages are deleted, a CLOSE-LOGOUT or CLOSE-SELECT
+      sequence is considerably faster than an EXPUNGE-LOGOUT or
+      EXPUNGE-SELECT because no untagged EXPUNGE responses (which the
+      client would probably ignore) are sent.
+
+   Example:    C: A341 CLOSE
+               S: A341 OK CLOSE completed
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 48]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+6.4.3.  EXPUNGE Command
+
+   Arguments:  none
+
+   Responses:  untagged responses: EXPUNGE
+
+   Result:     OK - expunge completed
+               NO - expunge failure: can't expunge (e.g., permission
+                    denied)
+               BAD - command unknown or arguments invalid
+
+      The EXPUNGE command permanently removes all messages that have the
+      \Deleted flag set from the currently selected mailbox.  Before
+      returning an OK to the client, an untagged EXPUNGE response is
+      sent for each message that is removed.
+
+   Example:    C: A202 EXPUNGE
+               S: * 3 EXPUNGE
+               S: * 3 EXPUNGE
+               S: * 5 EXPUNGE
+               S: * 8 EXPUNGE
+               S: A202 OK EXPUNGE completed
+
+        Note: In this example, messages 3, 4, 7, and 11 had the
+        \Deleted flag set.  See the description of the EXPUNGE
+        response for further explanation.
+
+
+6.4.4.  SEARCH Command
+
+   Arguments:  OPTIONAL [CHARSET] specification
+               searching criteria (one or more)
+
+   Responses:  REQUIRED untagged response: SEARCH
+
+   Result:     OK - search completed
+               NO - search error: can't search that [CHARSET] or
+                    criteria
+               BAD - command unknown or arguments invalid
+
+      The SEARCH command searches the mailbox for messages that match
+      the given searching criteria.  Searching criteria consist of one
+      or more search keys.  The untagged SEARCH response from the server
+      contains a listing of message sequence numbers corresponding to
+      those messages that match the searching criteria.
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 49]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+      When multiple keys are specified, the result is the intersection
+      (AND function) of all the messages that match those keys.  For
+      example, the criteria DELETED FROM "SMITH" SINCE 1-Feb-1994 refers
+      to all deleted messages from Smith that were placed in the mailbox
+      since February 1, 1994.  A search key can also be a parenthesized
+      list of one or more search keys (e.g., for use with the OR and NOT
+      keys).
+
+      Server implementations MAY exclude [MIME-IMB] body parts with
+      terminal content media types other than TEXT and MESSAGE from
+      consideration in SEARCH matching.
+
+      The OPTIONAL [CHARSET] specification consists of the word
+      "CHARSET" followed by a registered [CHARSET].  It indicates the
+      [CHARSET] of the strings that appear in the search criteria.
+      [MIME-IMB] content transfer encodings, and [MIME-HDRS] strings in
+      [RFC-2822]/[MIME-IMB] headers, MUST be decoded before comparing
+      text in a [CHARSET] other than US-ASCII.  US-ASCII MUST be
+      supported; other [CHARSET]s MAY be supported.
+
+      If the server does not support the specified [CHARSET], it MUST
+      return a tagged NO response (not a BAD).  This response SHOULD
+      contain the BADCHARSET response code, which MAY list the
+      [CHARSET]s supported by the server.
+
+      In all search keys that use strings, a message matches the key if
+      the string is a substring of the field.  The matching is
+      case-insensitive.
+
+      The defined search keys are as follows.  Refer to the Formal
+      Syntax section for the precise syntactic definitions of the
+      arguments.
+
+      <sequence set>
+         Messages with message sequence numbers corresponding to the
+         specified message sequence number set.
+
+      ALL
+         All messages in the mailbox; the default initial key for
+         ANDing.
+
+      ANSWERED
+         Messages with the \Answered flag set.
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 50]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+      BCC <string>
+         Messages that contain the specified string in the envelope
+         structure's BCC field.
+
+      BEFORE <date>
+         Messages whose internal date (disregarding time and timezone)
+         is earlier than the specified date.
+
+      BODY <string>
+         Messages that contain the specified string in the body of the
+         message.
+
+      CC <string>
+         Messages that contain the specified string in the envelope
+         structure's CC field.
+
+      DELETED
+         Messages with the \Deleted flag set.
+
+      DRAFT
+         Messages with the \Draft flag set.
+
+      FLAGGED
+         Messages with the \Flagged flag set.
+
+      FROM <string>
+         Messages that contain the specified string in the envelope
+         structure's FROM field.
+
+      HEADER <field-name> <string>
+         Messages that have a header with the specified field-name (as
+         defined in [RFC-2822]) and that contains the specified string
+         in the text of the header (what comes after the colon).  If the
+         string to search is zero-length, this matches all messages that
+         have a header line with the specified field-name regardless of
+         the contents.
+
+      KEYWORD <flag>
+         Messages with the specified keyword flag set.
+
+      LARGER <n>
+         Messages with an [RFC-2822] size larger than the specified
+         number of octets.
+
+      NEW
+         Messages that have the \Recent flag set but not the \Seen flag.
+         This is functionally equivalent to "(RECENT UNSEEN)".
+
+
+
+
+Crispin                     Standards Track                    [Page 51]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+      NOT <search-key>
+         Messages that do not match the specified search key.
+
+      OLD
+         Messages that do not have the \Recent flag set.  This is
+         functionally equivalent to "NOT RECENT" (as opposed to "NOT
+         NEW").
+
+      ON <date>
+         Messages whose internal date (disregarding time and timezone)
+         is within the specified date.
+
+      OR <search-key1> <search-key2>
+         Messages that match either search key.
+
+      RECENT
+         Messages that have the \Recent flag set.
+
+      SEEN
+         Messages that have the \Seen flag set.
+
+      SENTBEFORE <date>
+         Messages whose [RFC-2822] Date: header (disregarding time and
+         timezone) is earlier than the specified date.
+
+      SENTON <date>
+         Messages whose [RFC-2822] Date: header (disregarding time and
+         timezone) is within the specified date.
+
+      SENTSINCE <date>
+         Messages whose [RFC-2822] Date: header (disregarding time and
+         timezone) is within or later than the specified date.
+
+      SINCE <date>
+         Messages whose internal date (disregarding time and timezone)
+         is within or later than the specified date.
+
+      SMALLER <n>
+         Messages with an [RFC-2822] size smaller than the specified
+         number of octets.
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 52]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+      SUBJECT <string>
+         Messages that contain the specified string in the envelope
+         structure's SUBJECT field.
+
+      TEXT <string>
+         Messages that contain the specified string in the header or
+         body of the message.
+
+      TO <string>
+         Messages that contain the specified string in the envelope
+         structure's TO field.
+
+      UID <sequence set>
+         Messages with unique identifiers corresponding to the specified
+         unique identifier set.  Sequence set ranges are permitted.
+
+      UNANSWERED
+         Messages that do not have the \Answered flag set.
+
+      UNDELETED
+         Messages that do not have the \Deleted flag set.
+
+      UNDRAFT
+         Messages that do not have the \Draft flag set.
+
+      UNFLAGGED
+         Messages that do not have the \Flagged flag set.
+
+      UNKEYWORD <flag>
+         Messages that do not have the specified keyword flag set.
+
+      UNSEEN
+         Messages that do not have the \Seen flag set.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 53]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   Example:    C: A282 SEARCH FLAGGED SINCE 1-Feb-1994 NOT FROM "Smith"
+               S: * SEARCH 2 84 882
+               S: A282 OK SEARCH completed
+               C: A283 SEARCH TEXT "string not in mailbox"
+               S: * SEARCH
+               S: A283 OK SEARCH completed
+               C: A284 SEARCH CHARSET UTF-8 TEXT {6}
+               C: XXXXXX
+               S: * SEARCH 43
+               S: A284 OK SEARCH completed
+
+        Note: Since this document is restricted to 7-bit ASCII
+        text, it is not possible to show actual UTF-8 data.  The
+        "XXXXXX" is a placeholder for what would be 6 octets of
+        8-bit data in an actual transaction.
+
+
+6.4.5.  FETCH Command
+
+   Arguments:  sequence set
+               message data item names or macro
+
+   Responses:  untagged responses: FETCH
+
+   Result:     OK - fetch completed
+               NO - fetch error: can't fetch that data
+               BAD - command unknown or arguments invalid
+
+      The FETCH command retrieves data associated with a message in the
+      mailbox.  The data items to be fetched can be either a single atom
+      or a parenthesized list.
+
+      Most data items, identified in the formal syntax under the
+      msg-att-static rule, are static and MUST NOT change for any
+      particular message.  Other data items, identified in the formal
+      syntax under the msg-att-dynamic rule, MAY change, either as a
+      result of a STORE command or due to external events.
+
+           For example, if a client receives an ENVELOPE for a
+           message when it already knows the envelope, it can
+           safely ignore the newly transmitted envelope.
+
+      There are three macros which specify commonly-used sets of data
+      items, and can be used instead of data items.  A macro must be
+      used by itself, and not in conjunction with other macros or data
+      items.
+
+
+
+
+
+Crispin                     Standards Track                    [Page 54]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+      ALL
+         Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE)
+
+      FAST
+         Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE)
+
+      FULL
+         Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE
+         BODY)
+
+      The currently defined data items that can be fetched are:
+
+      BODY
+         Non-extensible form of BODYSTRUCTURE.
+
+      BODY[<section>]<<partial>>
+         The text of a particular body section.  The section
+         specification is a set of zero or more part specifiers
+         delimited by periods.  A part specifier is either a part number
+         or one of the following: HEADER, HEADER.FIELDS,
+         HEADER.FIELDS.NOT, MIME, and TEXT.  An empty section
+         specification refers to the entire message, including the
+         header.
+
+         Every message has at least one part number.  Non-[MIME-IMB]
+         messages, and non-multipart [MIME-IMB] messages with no
+         encapsulated message, only have a part 1.
+
+         Multipart messages are assigned consecutive part numbers, as
+         they occur in the message.  If a particular part is of type
+         message or multipart, its parts MUST be indicated by a period
+         followed by the part number within that nested multipart part.
+
+         A part of type MESSAGE/RFC822 also has nested part numbers,
+         referring to parts of the MESSAGE part's body.
+
+         The HEADER, HEADER.FIELDS, HEADER.FIELDS.NOT, and TEXT part
+         specifiers can be the sole part specifier or can be prefixed by
+         one or more numeric part specifiers, provided that the numeric
+         part specifier refers to a part of type MESSAGE/RFC822.  The
+         MIME part specifier MUST be prefixed by one or more numeric
+         part specifiers.
+
+         The HEADER, HEADER.FIELDS, and HEADER.FIELDS.NOT part
+         specifiers refer to the [RFC-2822] header of the message or of
+         an encapsulated [MIME-IMT] MESSAGE/RFC822 message.
+         HEADER.FIELDS and HEADER.FIELDS.NOT are followed by a list of
+         field-name (as defined in [RFC-2822]) names, and return a
+
+
+
+Crispin                     Standards Track                    [Page 55]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+         subset of the header.  The subset returned by HEADER.FIELDS
+         contains only those header fields with a field-name that
+         matches one of the names in the list; similarly, the subset
+         returned by HEADER.FIELDS.NOT contains only the header fields
+         with a non-matching field-name.  The field-matching is
+         case-insensitive but otherwise exact.  Subsetting does not
+         exclude the [RFC-2822] delimiting blank line between the header
+         and the body; the blank line is included in all header fetches,
+         except in the case of a message which has no body and no blank
+         line.
+
+         The MIME part specifier refers to the [MIME-IMB] header for
+         this part.
+
+         The TEXT part specifier refers to the text body of the message,
+         omitting the [RFC-2822] header.
+
+            Here is an example of a complex message with some of its
+            part specifiers:
+
+       HEADER     ([RFC-2822] header of the message)
+       TEXT       ([RFC-2822] text body of the message) MULTIPART/MIXED
+       1          TEXT/PLAIN
+       2          APPLICATION/OCTET-STREAM
+       3          MESSAGE/RFC822
+       3.HEADER   ([RFC-2822] header of the message)
+       3.TEXT     ([RFC-2822] text body of the message) MULTIPART/MIXED
+       3.1        TEXT/PLAIN
+       3.2        APPLICATION/OCTET-STREAM
+       4          MULTIPART/MIXED
+       4.1        IMAGE/GIF
+       4.1.MIME   ([MIME-IMB] header for the IMAGE/GIF)
+       4.2        MESSAGE/RFC822
+       4.2.HEADER ([RFC-2822] header of the message)
+       4.2.TEXT   ([RFC-2822] text body of the message) MULTIPART/MIXED
+       4.2.1      TEXT/PLAIN
+       4.2.2      MULTIPART/ALTERNATIVE
+       4.2.2.1    TEXT/PLAIN
+       4.2.2.2    TEXT/RICHTEXT
+
+
+         It is possible to fetch a substring of the designated text.
+         This is done by appending an open angle bracket ("<"), the
+         octet position of the first desired octet, a period, the
+         maximum number of octets desired, and a close angle bracket
+         (">") to the part specifier.  If the starting octet is beyond
+         the end of the text, an empty string is returned.
+
+
+
+
+Crispin                     Standards Track                    [Page 56]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+         Any partial fetch that attempts to read beyond the end of the
+         text is truncated as appropriate.  A partial fetch that starts
+         at octet 0 is returned as a partial fetch, even if this
+         truncation happened.
+
+            Note: This means that BODY[]<0.2048> of a 1500-octet message
+            will return BODY[]<0> with a literal of size 1500, not
+            BODY[].
+
+            Note: A substring fetch of a HEADER.FIELDS or
+            HEADER.FIELDS.NOT part specifier is calculated after
+            subsetting the header.
+
+         The \Seen flag is implicitly set; if this causes the flags to
+         change, they SHOULD be included as part of the FETCH responses.
+
+      BODY.PEEK[<section>]<<partial>>
+         An alternate form of BODY[<section>] that does not implicitly
+         set the \Seen flag.
+
+      BODYSTRUCTURE
+         The [MIME-IMB] body structure of the message.  This is computed
+         by the server by parsing the [MIME-IMB] header fields in the
+         [RFC-2822] header and [MIME-IMB] headers.
+
+      ENVELOPE
+         The envelope structure of the message.  This is computed by the
+         server by parsing the [RFC-2822] header into the component
+         parts, defaulting various fields as necessary.
+
+      FLAGS
+         The flags that are set for this message.
+
+      INTERNALDATE
+         The internal date of the message.
+
+      RFC822
+         Functionally equivalent to BODY[], differing in the syntax of
+         the resulting untagged FETCH data (RFC822 is returned).
+
+      RFC822.HEADER
+         Functionally equivalent to BODY.PEEK[HEADER], differing in the
+         syntax of the resulting untagged FETCH data (RFC822.HEADER is
+         returned).
+
+      RFC822.SIZE
+         The [RFC-2822] size of the message.
+
+
+
+
+Crispin                     Standards Track                    [Page 57]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+      RFC822.TEXT
+         Functionally equivalent to BODY[TEXT], differing in the syntax
+         of the resulting untagged FETCH data (RFC822.TEXT is returned).
+
+      UID
+         The unique identifier for the message.
+
+
+   Example:    C: A654 FETCH 2:4 (FLAGS BODY[HEADER.FIELDS (DATE FROM)])
+               S: * 2 FETCH ....
+               S: * 3 FETCH ....
+               S: * 4 FETCH ....
+               S: A654 OK FETCH completed
+
+
+6.4.6.  STORE Command
+
+   Arguments:  sequence set
+               message data item name
+               value for message data item
+
+   Responses:  untagged responses: FETCH
+
+   Result:     OK - store completed
+               NO - store error: can't store that data
+               BAD - command unknown or arguments invalid
+
+      The STORE command alters data associated with a message in the
+      mailbox.  Normally, STORE will return the updated value of the
+      data with an untagged FETCH response.  A suffix of ".SILENT" in
+      the data item name prevents the untagged FETCH, and the server
+      SHOULD assume that the client has determined the updated value
+      itself or does not care about the updated value.
+
+           Note: Regardless of whether or not the ".SILENT" suffix
+           was used, the server SHOULD send an untagged FETCH
+           response if a change to a message's flags from an
+           external source is observed.  The intent is that the
+           status of the flags is determinate without a race
+           condition.
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 58]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+      The currently defined data items that can be stored are:
+
+      FLAGS <flag list>
+         Replace the flags for the message (other than \Recent) with the
+         argument.  The new value of the flags is returned as if a FETCH
+         of those flags was done.
+
+      FLAGS.SILENT <flag list>
+         Equivalent to FLAGS, but without returning a new value.
+
+      +FLAGS <flag list>
+         Add the argument to the flags for the message.  The new value
+         of the flags is returned as if a FETCH of those flags was done.
+
+      +FLAGS.SILENT <flag list>
+         Equivalent to +FLAGS, but without returning a new value.
+
+      -FLAGS <flag list>
+         Remove the argument from the flags for the message.  The new
+         value of the flags is returned as if a FETCH of those flags was
+         done.
+
+      -FLAGS.SILENT <flag list>
+         Equivalent to -FLAGS, but without returning a new value.
+
+
+   Example:    C: A003 STORE 2:4 +FLAGS (\Deleted)
+               S: * 2 FETCH (FLAGS (\Deleted \Seen))
+               S: * 3 FETCH (FLAGS (\Deleted))
+               S: * 4 FETCH (FLAGS (\Deleted \Flagged \Seen))
+               S: A003 OK STORE completed
+
+
+6.4.7.  COPY Command
+
+   Arguments:  sequence set
+               mailbox name
+
+   Responses:  no specific responses for this command
+
+   Result:     OK - copy completed
+               NO - copy error: can't copy those messages or to that
+                    name
+               BAD - command unknown or arguments invalid
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 59]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+      The COPY command copies the specified message(s) to the end of the
+      specified destination mailbox.  The flags and internal date of the
+      message(s) SHOULD be preserved, and the Recent flag SHOULD be set,
+      in the copy.
+
+      If the destination mailbox does not exist, a server SHOULD return
+      an error.  It SHOULD NOT automatically create the mailbox.  Unless
+      it is certain that the destination mailbox can not be created, the
+      server MUST send the response code "[TRYCREATE]" as the prefix of
+      the text of the tagged NO response.  This gives a hint to the
+      client that it can attempt a CREATE command and retry the COPY if
+      the CREATE is successful.
+
+      If the COPY command is unsuccessful for any reason, server
+      implementations MUST restore the destination mailbox to its state
+      before the COPY attempt.
+
+   Example:    C: A003 COPY 2:4 MEETING
+               S: A003 OK COPY completed
+
+
+6.4.8.  UID Command
+
+   Arguments:  command name
+               command arguments
+
+   Responses:  untagged responses: FETCH, SEARCH
+
+   Result:     OK - UID command completed
+               NO - UID command error
+               BAD - command unknown or arguments invalid
+
+      The UID command has two forms.  In the first form, it takes as its
+      arguments a COPY, FETCH, or STORE command with arguments
+      appropriate for the associated command.  However, the numbers in
+      the sequence set argument are unique identifiers instead of
+      message sequence numbers.  Sequence set ranges are permitted, but
+      there is no guarantee that unique identifiers will be contiguous.
+
+      A non-existent unique identifier is ignored without any error
+      message generated.  Thus, it is possible for a UID FETCH command
+      to return an OK without any data or a UID COPY or UID STORE to
+      return an OK without performing any operations.
+
+      In the second form, the UID command takes a SEARCH command with
+      SEARCH command arguments.  The interpretation of the arguments is
+      the same as with SEARCH; however, the numbers returned in a SEARCH
+      response for a UID SEARCH command are unique identifiers instead
+
+
+
+Crispin                     Standards Track                    [Page 60]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+      of message sequence numbers.  For example, the command UID SEARCH
+      1:100 UID 443:557 returns the unique identifiers corresponding to
+      the intersection of two sequence sets, the message sequence number
+      range 1:100 and the UID range 443:557.
+
+           Note: in the above example, the UID range 443:557
+           appears.  The same comment about a non-existent unique
+           identifier being ignored without any error message also
+           applies here.  Hence, even if neither UID 443 or 557
+           exist, this range is valid and would include an existing
+           UID 495.
+
+           Also note that a UID range of 559:* always includes the
+           UID of the last message in the mailbox, even if 559 is
+           higher than any assigned UID value.  This is because the
+           contents of a range are independent of the order of the
+           range endpoints.  Thus, any UID range with * as one of
+           the endpoints indicates at least one message (the
+           message with the highest numbered UID), unless the
+           mailbox is empty.
+
+      The number after the "*" in an untagged FETCH response is always a
+      message sequence number, not a unique identifier, even for a UID
+      command response.  However, server implementations MUST implicitly
+      include the UID message data item as part of any FETCH response
+      caused by a UID command, regardless of whether a UID was specified
+      as a message data item to the FETCH.
+
+
+      Note: The rule about including the UID message data item as part
+      of a FETCH response primarily applies to the UID FETCH and UID
+      STORE commands, including a UID FETCH command that does not
+      include UID as a message data item.  Although it is unlikely that
+      the other UID commands will cause an untagged FETCH, this rule
+      applies to these commands as well.
+
+   Example:    C: A999 UID FETCH 4827313:4828442 FLAGS
+               S: * 23 FETCH (FLAGS (\Seen) UID 4827313)
+               S: * 24 FETCH (FLAGS (\Seen) UID 4827943)
+               S: * 25 FETCH (FLAGS (\Seen) UID 4828442)
+               S: A999 OK UID FETCH completed
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 61]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+6.5.    Client Commands - Experimental/Expansion
+
+
+6.5.1.  X<atom> Command
+
+   Arguments:  implementation defined
+
+   Responses:  implementation defined
+
+   Result:     OK - command completed
+               NO - failure
+               BAD - command unknown or arguments invalid
+
+      Any command prefixed with an X is an experimental command.
+      Commands which are not part of this specification, a standard or
+      standards-track revision of this specification, or an
+      IESG-approved experimental protocol, MUST use the X prefix.
+
+      Any added untagged responses issued by an experimental command
+      MUST also be prefixed with an X.  Server implementations MUST NOT
+      send any such untagged responses, unless the client requested it
+      by issuing the associated experimental command.
+
+   Example:    C: a441 CAPABILITY
+               S: * CAPABILITY IMAP4rev1 XPIG-LATIN
+               S: a441 OK CAPABILITY completed
+               C: A442 XPIG-LATIN
+               S: * XPIG-LATIN ow-nay eaking-spay ig-pay atin-lay
+               S: A442 OK XPIG-LATIN ompleted-cay
+
+7.      Server Responses
+
+   Server responses are in three forms: status responses, server data,
+   and command continuation request.  The information contained in a
+   server response, identified by "Contents:" in the response
+   descriptions below, is described by function, not by syntax.  The
+   precise syntax of server responses is described in the Formal Syntax
+   section.
+
+   The client MUST be prepared to accept any response at all times.
+
+   Status responses can be tagged or untagged.  Tagged status responses
+   indicate the completion result (OK, NO, or BAD status) of a client
+   command, and have a tag matching the command.
+
+   Some status responses, and all server data, are untagged.  An
+   untagged response is indicated by the token "*" instead of a tag.
+   Untagged status responses indicate server greeting, or server status
+
+
+
+Crispin                     Standards Track                    [Page 62]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   that does not indicate the completion of a command (for example, an
+   impending system shutdown alert).  For historical reasons, untagged
+   server data responses are also called "unsolicited data", although
+   strictly speaking, only unilateral server data is truly
+   "unsolicited".
+
+   Certain server data MUST be recorded by the client when it is
+   received; this is noted in the description of that data.  Such data
+   conveys critical information which affects the interpretation of all
+   subsequent commands and responses (e.g., updates reflecting the
+   creation or destruction of messages).
+
+   Other server data SHOULD be recorded for later reference; if the
+   client does not need to record the data, or if recording the data has
+   no obvious purpose (e.g., a SEARCH response when no SEARCH command is
+   in progress), the data SHOULD be ignored.
+
+   An example of unilateral untagged server data occurs when the IMAP
+   connection is in the selected state.  In the selected state, the
+   server checks the mailbox for new messages as part of command
+   execution.  Normally, this is part of the execution of every command;
+   hence, a NOOP command suffices to check for new messages.  If new
+   messages are found, the server sends untagged EXISTS and RECENT
+   responses reflecting the new size of the mailbox.  Server
+   implementations that offer multiple simultaneous access to the same
+   mailbox SHOULD also send appropriate unilateral untagged FETCH and
+   EXPUNGE responses if another agent changes the state of any message
+   flags or expunges any messages.
+
+   Command continuation request responses use the token "+" instead of a
+   tag.  These responses are sent by the server to indicate acceptance
+   of an incomplete client command and readiness for the remainder of
+   the command.
+
+7.1.    Server Responses - Status Responses
+
+   Status responses are OK, NO, BAD, PREAUTH and BYE.  OK, NO, and BAD
+   can be tagged or untagged.  PREAUTH and BYE are always untagged.
+
+   Status responses MAY include an OPTIONAL "response code".  A response
+   code consists of data inside square brackets in the form of an atom,
+   possibly followed by a space and arguments.  The response code
+   contains additional information or status codes for client software
+   beyond the OK/NO/BAD condition, and are defined when there is a
+   specific action that a client can take based upon the additional
+   information.
+
+
+
+
+
+Crispin                     Standards Track                    [Page 63]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   The currently defined response codes are:
+
+      ALERT
+
+         The human-readable text contains a special alert that MUST be
+         presented to the user in a fashion that calls the user's
+         attention to the message.
+
+      BADCHARSET
+
+         Optionally followed by a parenthesized list of charsets.  A
+         SEARCH failed because the given charset is not supported by
+         this implementation.  If the optional list of charsets is
+         given, this lists the charsets that are supported by this
+         implementation.
+
+      CAPABILITY
+
+         Followed by a list of capabilities.  This can appear in the
+         initial OK or PREAUTH response to transmit an initial
+         capabilities list.  This makes it unnecessary for a client to
+         send a separate CAPABILITY command if it recognizes this
+         response.
+
+      PARSE
+
+         The human-readable text represents an error in parsing the
+         [RFC-2822] header or [MIME-IMB] headers of a message in the
+         mailbox.
+
+      PERMANENTFLAGS
+
+         Followed by a parenthesized list of flags, indicates which of
+         the known flags the client can change permanently.  Any flags
+         that are in the FLAGS untagged response, but not the
+         PERMANENTFLAGS list, can not be set permanently.  If the client
+         attempts to STORE a flag that is not in the PERMANENTFLAGS
+         list, the server will either ignore the change or store the
+         state change for the remainder of the current session only.
+         The PERMANENTFLAGS list can also include the special flag \*,
+         which indicates that it is possible to create new keywords by
+         attempting to store those flags in the mailbox.
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 64]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+      READ-ONLY
+
+         The mailbox is selected read-only, or its access while selected
+         has changed from read-write to read-only.
+
+      READ-WRITE
+
+         The mailbox is selected read-write, or its access while
+         selected has changed from read-only to read-write.
+
+      TRYCREATE
+
+         An APPEND or COPY attempt is failing because the target mailbox
+         does not exist (as opposed to some other reason).  This is a
+         hint to the client that the operation can succeed if the
+         mailbox is first created by the CREATE command.
+
+      UIDNEXT
+
+         Followed by a decimal number, indicates the next unique
+         identifier value.  Refer to section 2.3.1.1 for more
+         information.
+
+      UIDVALIDITY
+
+         Followed by a decimal number, indicates the unique identifier
+         validity value.  Refer to section 2.3.1.1 for more information.
+
+      UNSEEN
+
+         Followed by a decimal number, indicates the number of the first
+         message without the \Seen flag set.
+
+      Additional response codes defined by particular client or server
+      implementations SHOULD be prefixed with an "X" until they are
+      added to a revision of this protocol.  Client implementations
+      SHOULD ignore response codes that they do not recognize.
+
+7.1.1.  OK Response
+
+   Contents:   OPTIONAL response code
+               human-readable text
+
+      The OK response indicates an information message from the server.
+      When tagged, it indicates successful completion of the associated
+      command.  The human-readable text MAY be presented to the user as
+      an information message.  The untagged form indicates an
+
+
+
+
+Crispin                     Standards Track                    [Page 65]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+      information-only message; the nature of the information MAY be
+      indicated by a response code.
+
+      The untagged form is also used as one of three possible greetings
+      at connection startup.  It indicates that the connection is not
+      yet authenticated and that a LOGIN command is needed.
+
+   Example:    S: * OK IMAP4rev1 server ready
+               C: A001 LOGIN fred blurdybloop
+               S: * OK [ALERT] System shutdown in 10 minutes
+               S: A001 OK LOGIN Completed
+
+
+7.1.2.  NO Response
+
+   Contents:   OPTIONAL response code
+               human-readable text
+
+      The NO response indicates an operational error message from the
+      server.  When tagged, it indicates unsuccessful completion of the
+      associated command.  The untagged form indicates a warning; the
+      command can still complete successfully.  The human-readable text
+      describes the condition.
+
+   Example:    C: A222 COPY 1:2 owatagusiam
+               S: * NO Disk is 98% full, please delete unnecessary data
+               S: A222 OK COPY completed
+               C: A223 COPY 3:200 blurdybloop
+               S: * NO Disk is 98% full, please delete unnecessary data
+               S: * NO Disk is 99% full, please delete unnecessary data
+               S: A223 NO COPY failed: disk is full
+
+
+7.1.3.  BAD Response
+
+   Contents:   OPTIONAL response code
+               human-readable text
+
+      The BAD response indicates an error message from the server.  When
+      tagged, it reports a protocol-level error in the client's command;
+      the tag indicates the command that caused the error.  The untagged
+      form indicates a protocol-level error for which the associated
+      command can not be determined; it can also indicate an internal
+      server failure.  The human-readable text describes the condition.
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 66]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   Example:    C: ...very long command line...
+               S: * BAD Command line too long
+               C: ...empty line...
+               S: * BAD Empty command line
+               C: A443 EXPUNGE
+               S: * BAD Disk crash, attempting salvage to a new disk!
+               S: * OK Salvage successful, no data lost
+               S: A443 OK Expunge completed
+
+
+7.1.4.  PREAUTH Response
+
+   Contents:   OPTIONAL response code
+               human-readable text
+
+      The PREAUTH response is always untagged, and is one of three
+      possible greetings at connection startup.  It indicates that the
+      connection has already been authenticated by external means; thus
+      no LOGIN command is needed.
+
+   Example:    S: * PREAUTH IMAP4rev1 server logged in as Smith
+
+
+7.1.5.  BYE Response
+
+   Contents:   OPTIONAL response code
+               human-readable text
+
+      The BYE response is always untagged, and indicates that the server
+      is about to close the connection.  The human-readable text MAY be
+      displayed to the user in a status report by the client.  The BYE
+      response is sent under one of four conditions:
+
+         1) as part of a normal logout sequence.  The server will close
+            the connection after sending the tagged OK response to the
+            LOGOUT command.
+
+         2) as a panic shutdown announcement.  The server closes the
+            connection immediately.
+
+         3) as an announcement of an inactivity autologout.  The server
+            closes the connection immediately.
+
+         4) as one of three possible greetings at connection startup,
+            indicating that the server is not willing to accept a
+            connection from this client.  The server closes the
+            connection immediately.
+
+
+
+
+Crispin                     Standards Track                    [Page 67]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+      The difference between a BYE that occurs as part of a normal
+      LOGOUT sequence (the first case) and a BYE that occurs because of
+      a failure (the other three cases) is that the connection closes
+      immediately in the failure case.  In all cases the client SHOULD
+      continue to read response data from the server until the
+      connection is closed; this will ensure that any pending untagged
+      or completion responses are read and processed.
+
+   Example:    S: * BYE Autologout; idle for too long
+
+7.2.    Server Responses - Server and Mailbox Status
+
+   These responses are always untagged.  This is how server and mailbox
+   status data are transmitted from the server to the client.  Many of
+   these responses typically result from a command with the same name.
+
+7.2.1.  CAPABILITY Response
+
+   Contents:   capability listing
+
+      The CAPABILITY response occurs as a result of a CAPABILITY
+      command.  The capability listing contains a space-separated
+      listing of capability names that the server supports.  The
+      capability listing MUST include the atom "IMAP4rev1".
+
+      In addition, client and server implementations MUST implement the
+      STARTTLS, LOGINDISABLED, and AUTH=PLAIN (described in [IMAP-TLS])
+      capabilities.  See the Security Considerations section for
+      important information.
+
+      A capability name which begins with "AUTH=" indicates that the
+      server supports that particular authentication mechanism.
+
+      The LOGINDISABLED capability indicates that the LOGIN command is
+      disabled, and that the server will respond with a tagged NO
+      response to any attempt to use the LOGIN command even if the user
+      name and password are valid.  An IMAP client MUST NOT issue the
+      LOGIN command if the server advertises the LOGINDISABLED
+      capability.
+
+      Other capability names indicate that the server supports an
+      extension, revision, or amendment to the IMAP4rev1 protocol.
+      Server responses MUST conform to this document until the client
+      issues a command that uses the associated capability.
+
+      Capability names MUST either begin with "X" or be standard or
+      standards-track IMAP4rev1 extensions, revisions, or amendments
+      registered with IANA.  A server MUST NOT offer unregistered or
+
+
+
+Crispin                     Standards Track                    [Page 68]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+      non-standard capability names, unless such names are prefixed with
+      an "X".
+
+      Client implementations SHOULD NOT require any capability name
+      other than "IMAP4rev1", and MUST ignore any unknown capability
+      names.
+
+      A server MAY send capabilities automatically, by using the
+      CAPABILITY response code in the initial PREAUTH or OK responses,
+      and by sending an updated CAPABILITY response code in the tagged
+      OK response as part of a successful authentication.  It is
+      unnecessary for a client to send a separate CAPABILITY command if
+      it recognizes these automatic capabilities.
+
+   Example:    S: * CAPABILITY IMAP4rev1 STARTTLS AUTH=GSSAPI XPIG-LATIN
+
+
+7.2.2.  LIST Response
+
+   Contents:   name attributes
+               hierarchy delimiter
+               name
+
+      The LIST response occurs as a result of a LIST command.  It
+      returns a single name that matches the LIST specification.  There
+      can be multiple LIST responses for a single LIST command.
+
+      Four name attributes are defined:
+
+      \Noinferiors
+         It is not possible for any child levels of hierarchy to exist
+         under this name; no child levels exist now and none can be
+         created in the future.
+
+      \Noselect
+         It is not possible to use this name as a selectable mailbox.
+
+      \Marked
+         The mailbox has been marked "interesting" by the server; the
+         mailbox probably contains messages that have been added since
+         the last time the mailbox was selected.
+
+      \Unmarked
+         The mailbox does not contain any additional messages since the
+         last time the mailbox was selected.
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 69]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+      If it is not feasible for the server to determine whether or not
+      the mailbox is "interesting", or if the name is a \Noselect name,
+      the server SHOULD NOT send either \Marked or \Unmarked.
+
+      The hierarchy delimiter is a character used to delimit levels of
+      hierarchy in a mailbox name.  A client can use it to create child
+      mailboxes, and to search higher or lower levels of naming
+      hierarchy.  All children of a top-level hierarchy node MUST use
+      the same separator character.  A NIL hierarchy delimiter means
+      that no hierarchy exists; the name is a "flat" name.
+
+      The name represents an unambiguous left-to-right hierarchy, and
+      MUST be valid for use as a reference in LIST and LSUB commands.
+      Unless \Noselect is indicated, the name MUST also be valid as an
+      argument for commands, such as SELECT, that accept mailbox names.
+
+   Example:    S: * LIST (\Noselect) "/" ~/Mail/foo
+
+
+7.2.3.  LSUB Response
+
+   Contents:   name attributes
+               hierarchy delimiter
+               name
+
+      The LSUB response occurs as a result of an LSUB command.  It
+      returns a single name that matches the LSUB specification.  There
+      can be multiple LSUB responses for a single LSUB command.  The
+      data is identical in format to the LIST response.
+
+   Example:    S: * LSUB () "." #news.comp.mail.misc
+
+
+7.2.4   STATUS Response
+
+   Contents:   name
+               status parenthesized list
+
+      The STATUS response occurs as a result of an STATUS command.  It
+      returns the mailbox name that matches the STATUS specification and
+      the requested mailbox status information.
+
+   Example:    S: * STATUS blurdybloop (MESSAGES 231 UIDNEXT 44292)
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 70]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+7.2.5.  SEARCH Response
+
+   Contents:   zero or more numbers
+
+      The SEARCH response occurs as a result of a SEARCH or UID SEARCH
+      command.  The number(s) refer to those messages that match the
+      search criteria.  For SEARCH, these are message sequence numbers;
+      for UID SEARCH, these are unique identifiers.  Each number is
+      delimited by a space.
+
+   Example:    S: * SEARCH 2 3 6
+
+
+7.2.6.  FLAGS Response
+
+   Contents:   flag parenthesized list
+
+      The FLAGS response occurs as a result of a SELECT or EXAMINE
+      command.  The flag parenthesized list identifies the flags (at a
+      minimum, the system-defined flags) that are applicable for this
+      mailbox.  Flags other than the system flags can also exist,
+      depending on server implementation.
+
+      The update from the FLAGS response MUST be recorded by the client.
+
+   Example:    S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
+
+
+7.3.    Server Responses - Mailbox Size
+
+   These responses are always untagged.  This is how changes in the size
+   of the mailbox are transmitted from the server to the client.
+   Immediately following the "*" token is a number that represents a
+   message count.
+
+7.3.1.  EXISTS Response
+
+   Contents:   none
+
+      The EXISTS response reports the number of messages in the mailbox.
+      This response occurs as a result of a SELECT or EXAMINE command,
+      and if the size of the mailbox changes (e.g., new messages).
+
+      The update from the EXISTS response MUST be recorded by the
+      client.
+
+   Example:    S: * 23 EXISTS
+
+
+
+
+Crispin                     Standards Track                    [Page 71]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+7.3.2.  RECENT Response
+
+   Contents:   none
+
+      The RECENT response reports the number of messages with the
+      \Recent flag set.  This response occurs as a result of a SELECT or
+      EXAMINE command, and if the size of the mailbox changes (e.g., new
+      messages).
+
+           Note: It is not guaranteed that the message sequence
+           numbers of recent messages will be a contiguous range of
+           the highest n messages in the mailbox (where n is the
+           value reported by the RECENT response).  Examples of
+           situations in which this is not the case are: multiple
+           clients having the same mailbox open (the first session
+           to be notified will see it as recent, others will
+           probably see it as non-recent), and when the mailbox is
+           re-ordered by a non-IMAP agent.
+
+           The only reliable way to identify recent messages is to
+           look at message flags to see which have the \Recent flag
+           set, or to do a SEARCH RECENT.
+
+      The update from the RECENT response MUST be recorded by the
+      client.
+
+   Example:    S: * 5 RECENT
+
+
+7.4.    Server Responses - Message Status
+
+   These responses are always untagged.  This is how message data are
+   transmitted from the server to the client, often as a result of a
+   command with the same name.  Immediately following the "*" token is a
+   number that represents a message sequence number.
+
+7.4.1.  EXPUNGE Response
+
+   Contents:   none
+
+      The EXPUNGE response reports that the specified message sequence
+      number has been permanently removed from the mailbox.  The message
+      sequence number for each successive message in the mailbox is
+      immediately decremented by 1, and this decrement is reflected in
+      message sequence numbers in subsequent responses (including other
+      untagged EXPUNGE responses).
+
+
+
+
+
+Crispin                     Standards Track                    [Page 72]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+      The EXPUNGE response also decrements the number of messages in the
+      mailbox; it is not necessary to send an EXISTS response with the
+      new value.
+
+      As a result of the immediate decrement rule, message sequence
+      numbers that appear in a set of successive EXPUNGE responses
+      depend upon whether the messages are removed starting from lower
+      numbers to higher numbers, or from higher numbers to lower
+      numbers.  For example, if the last 5 messages in a 9-message
+      mailbox are expunged, a "lower to higher" server will send five
+      untagged EXPUNGE responses for message sequence number 5, whereas
+      a "higher to lower server" will send successive untagged EXPUNGE
+      responses for message sequence numbers 9, 8, 7, 6, and 5.
+
+      An EXPUNGE response MUST NOT be sent when no command is in
+      progress, nor while responding to a FETCH, STORE, or SEARCH
+      command.  This rule is necessary to prevent a loss of
+      synchronization of message sequence numbers between client and
+      server.  A command is not "in progress" until the complete command
+      has been received; in particular, a command is not "in progress"
+      during the negotiation of command continuation.
+
+           Note: UID FETCH, UID STORE, and UID SEARCH are different
+           commands from FETCH, STORE, and SEARCH.  An EXPUNGE
+           response MAY be sent during a UID command.
+
+      The update from the EXPUNGE response MUST be recorded by the
+      client.
+
+   Example:    S: * 44 EXPUNGE
+
+
+7.4.2.  FETCH Response
+
+   Contents:   message data
+
+      The FETCH response returns data about a message to the client.
+      The data are pairs of data item names and their values in
+      parentheses.  This response occurs as the result of a FETCH or
+      STORE command, as well as by unilateral server decision (e.g.,
+      flag updates).
+
+      The current data items are:
+
+      BODY
+         A form of BODYSTRUCTURE without extension data.
+
+
+
+
+
+Crispin                     Standards Track                    [Page 73]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+      BODY[<section>]<<origin octet>>
+         A string expressing the body contents of the specified section.
+         The string SHOULD be interpreted by the client according to the
+         content transfer encoding, body type, and subtype.
+
+         If the origin octet is specified, this string is a substring of
+         the entire body contents, starting at that origin octet.  This
+         means that BODY[]<0> MAY be truncated, but BODY[] is NEVER
+         truncated.
+
+            Note: The origin octet facility MUST NOT be used by a server
+            in a FETCH response unless the client specifically requested
+            it by means of a FETCH of a BODY[<section>]<<partial>> data
+            item.
+
+         8-bit textual data is permitted if a [CHARSET] identifier is
+         part of the body parameter parenthesized list for this section.
+         Note that headers (part specifiers HEADER or MIME, or the
+         header portion of a MESSAGE/RFC822 part), MUST be 7-bit; 8-bit
+         characters are not permitted in headers.  Note also that the
+         [RFC-2822] delimiting blank line between the header and the
+         body is not affected by header line subsetting; the blank line
+         is always included as part of header data, except in the case
+         of a message which has no body and no blank line.
+
+         Non-textual data such as binary data MUST be transfer encoded
+         into a textual form, such as BASE64, prior to being sent to the
+         client.  To derive the original binary data, the client MUST
+         decode the transfer encoded string.
+
+      BODYSTRUCTURE
+         A parenthesized list that describes the [MIME-IMB] body
+         structure of a message.  This is computed by the server by
+         parsing the [MIME-IMB] header fields, defaulting various fields
+         as necessary.
+
+         For example, a simple text message of 48 lines and 2279 octets
+         can have a body structure of: ("TEXT" "PLAIN" ("CHARSET"
+         "US-ASCII") NIL NIL "7BIT" 2279 48)
+
+         Multiple parts are indicated by parenthesis nesting.  Instead
+         of a body type as the first element of the parenthesized list,
+         there is a sequence of one or more nested body structures.  The
+         second element of the parenthesized list is the multipart
+         subtype (mixed, digest, parallel, alternative, etc.).
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 74]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+         For example, a two part message consisting of a text and a
+         BASE64-encoded text attachment can have a body structure of:
+         (("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 1152
+         23)("TEXT" "PLAIN" ("CHARSET" "US-ASCII" "NAME" "cc.diff")
+         "<960723163407.20117h@cac.washington.edu>" "Compiler diff"
+         "BASE64" 4554 73) "MIXED")
+
+         Extension data follows the multipart subtype.  Extension data
+         is never returned with the BODY fetch, but can be returned with
+         a BODYSTRUCTURE fetch.  Extension data, if present, MUST be in
+         the defined order.  The extension data of a multipart body part
+         are in the following order:
+
+         body parameter parenthesized list
+            A parenthesized list of attribute/value pairs [e.g., ("foo"
+            "bar" "baz" "rag") where "bar" is the value of "foo", and
+            "rag" is the value of "baz"] as defined in [MIME-IMB].
+
+         body disposition
+            A parenthesized list, consisting of a disposition type
+            string, followed by a parenthesized list of disposition
+            attribute/value pairs as defined in [DISPOSITION].
+
+         body language
+            A string or parenthesized list giving the body language
+            value as defined in [LANGUAGE-TAGS].
+
+         body location
+            A string list giving the body content URI as defined in
+            [LOCATION].
+
+         Any following extension data are not yet defined in this
+         version of the protocol.  Such extension data can consist of
+         zero or more NILs, strings, numbers, or potentially nested
+         parenthesized lists of such data.  Client implementations that
+         do a BODYSTRUCTURE fetch MUST be prepared to accept such
+         extension data.  Server implementations MUST NOT send such
+         extension data until it has been defined by a revision of this
+         protocol.
+
+         The basic fields of a non-multipart body part are in the
+         following order:
+
+         body type
+            A string giving the content media type name as defined in
+            [MIME-IMB].
+
+
+
+
+
+Crispin                     Standards Track                    [Page 75]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+         body subtype
+            A string giving the content subtype name as defined in
+            [MIME-IMB].
+
+         body parameter parenthesized list
+            A parenthesized list of attribute/value pairs [e.g., ("foo"
+            "bar" "baz" "rag") where "bar" is the value of "foo" and
+            "rag" is the value of "baz"] as defined in [MIME-IMB].
+
+         body id
+            A string giving the content id as defined in [MIME-IMB].
+
+         body description
+            A string giving the content description as defined in
+            [MIME-IMB].
+
+         body encoding
+            A string giving the content transfer encoding as defined in
+            [MIME-IMB].
+
+         body size
+            A number giving the size of the body in octets.  Note that
+            this size is the size in its transfer encoding and not the
+            resulting size after any decoding.
+
+         A body type of type MESSAGE and subtype RFC822 contains,
+         immediately after the basic fields, the envelope structure,
+         body structure, and size in text lines of the encapsulated
+         message.
+
+         A body type of type TEXT contains, immediately after the basic
+         fields, the size of the body in text lines.  Note that this
+         size is the size in its content transfer encoding and not the
+         resulting size after any decoding.
+
+         Extension data follows the basic fields and the type-specific
+         fields listed above.  Extension data is never returned with the
+         BODY fetch, but can be returned with a BODYSTRUCTURE fetch.
+         Extension data, if present, MUST be in the defined order.
+
+         The extension data of a non-multipart body part are in the
+         following order:
+
+         body MD5
+            A string giving the body MD5 value as defined in [MD5].
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 76]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+         body disposition
+            A parenthesized list with the same content and function as
+            the body disposition for a multipart body part.
+
+         body language
+            A string or parenthesized list giving the body language
+            value as defined in [LANGUAGE-TAGS].
+
+         body location
+            A string list giving the body content URI as defined in
+            [LOCATION].
+
+         Any following extension data are not yet defined in this
+         version of the protocol, and would be as described above under
+         multipart extension data.
+
+      ENVELOPE
+         A parenthesized list that describes the envelope structure of a
+         message.  This is computed by the server by parsing the
+         [RFC-2822] header into the component parts, defaulting various
+         fields as necessary.
+
+         The fields of the envelope structure are in the following
+         order: date, subject, from, sender, reply-to, to, cc, bcc,
+         in-reply-to, and message-id.  The date, subject, in-reply-to,
+         and message-id fields are strings.  The from, sender, reply-to,
+         to, cc, and bcc fields are parenthesized lists of address
+         structures.
+
+         An address structure is a parenthesized list that describes an
+         electronic mail address.  The fields of an address structure
+         are in the following order: personal name, [SMTP]
+         at-domain-list (source route), mailbox name, and host name.
+
+         [RFC-2822] group syntax is indicated by a special form of
+         address structure in which the host name field is NIL.  If the
+         mailbox name field is also NIL, this is an end of group marker
+         (semi-colon in RFC 822 syntax).  If the mailbox name field is
+         non-NIL, this is a start of group marker, and the mailbox name
+         field holds the group name phrase.
+
+         If the Date, Subject, In-Reply-To, and Message-ID header lines
+         are absent in the [RFC-2822] header, the corresponding member
+         of the envelope is NIL; if these header lines are present but
+         empty the corresponding member of the envelope is the empty
+         string.
+
+
+
+
+
+Crispin                     Standards Track                    [Page 77]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+            Note: some servers may return a NIL envelope member in the
+            "present but empty" case.  Clients SHOULD treat NIL and
+            empty string as identical.
+
+            Note: [RFC-2822] requires that all messages have a valid
+            Date header.  Therefore, the date member in the envelope can
+            not be NIL or the empty string.
+
+            Note: [RFC-2822] requires that the In-Reply-To and
+            Message-ID headers, if present, have non-empty content.
+            Therefore, the in-reply-to and message-id members in the
+            envelope can not be the empty string.
+
+         If the From, To, cc, and bcc header lines are absent in the
+         [RFC-2822] header, or are present but empty, the corresponding
+         member of the envelope is NIL.
+
+         If the Sender or Reply-To lines are absent in the [RFC-2822]
+         header, or are present but empty, the server sets the
+         corresponding member of the envelope to be the same value as
+         the from member (the client is not expected to know to do
+         this).
+
+            Note: [RFC-2822] requires that all messages have a valid
+            From header.  Therefore, the from, sender, and reply-to
+            members in the envelope can not be NIL.
+
+      FLAGS
+         A parenthesized list of flags that are set for this message.
+
+      INTERNALDATE
+         A string representing the internal date of the message.
+
+      RFC822
+         Equivalent to BODY[].
+
+      RFC822.HEADER
+         Equivalent to BODY[HEADER].  Note that this did not result in
+         \Seen being set, because RFC822.HEADER response data occurs as
+         a result of a FETCH of RFC822.HEADER.  BODY[HEADER] response
+         data occurs as a result of a FETCH of BODY[HEADER] (which sets
+         \Seen) or BODY.PEEK[HEADER] (which does not set \Seen).
+
+      RFC822.SIZE
+         A number expressing the [RFC-2822] size of the message.
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 78]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+      RFC822.TEXT
+         Equivalent to BODY[TEXT].
+
+      UID
+         A number expressing the unique identifier of the message.
+
+
+   Example:    S: * 23 FETCH (FLAGS (\Seen) RFC822.SIZE 44827)
+
+
+7.5.    Server Responses - Command Continuation Request
+
+   The command continuation request response is indicated by a "+" token
+   instead of a tag.  This form of response indicates that the server is
+   ready to accept the continuation of a command from the client.  The
+   remainder of this response is a line of text.
+
+   This response is used in the AUTHENTICATE command to transmit server
+   data to the client, and request additional client data.  This
+   response is also used if an argument to any command is a literal.
+
+   The client is not permitted to send the octets of the literal unless
+   the server indicates that it is expected.  This permits the server to
+   process commands and reject errors on a line-by-line basis.  The
+   remainder of the command, including the CRLF that terminates a
+   command, follows the octets of the literal.  If there are any
+   additional command arguments, the literal octets are followed by a
+   space and those arguments.
+
+   Example:    C: A001 LOGIN {11}
+               S: + Ready for additional command text
+               C: FRED FOOBAR {7}
+               S: + Ready for additional command text
+               C: fat man
+               S: A001 OK LOGIN completed
+               C: A044 BLURDYBLOOP {102856}
+               S: A044 BAD No such command as "BLURDYBLOOP"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 79]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+8.      Sample IMAP4rev1 connection
+
+   The following is a transcript of an IMAP4rev1 connection.  A long
+   line in this sample is broken for editorial clarity.
+
+S:   * OK IMAP4rev1 Service Ready
+C:   a001 login mrc secret
+S:   a001 OK LOGIN completed
+C:   a002 select inbox
+S:   * 18 EXISTS
+S:   * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
+S:   * 2 RECENT
+S:   * OK [UNSEEN 17] Message 17 is the first unseen message
+S:   * OK [UIDVALIDITY 3857529045] UIDs valid
+S:   a002 OK [READ-WRITE] SELECT completed
+C:   a003 fetch 12 full
+S:   * 12 FETCH (FLAGS (\Seen) INTERNALDATE "17-Jul-1996 02:44:25 -0700"
+      RFC822.SIZE 4286 ENVELOPE ("Wed, 17 Jul 1996 02:23:25 -0700 (PDT)"
+      "IMAP4rev1 WG mtg summary and minutes"
+      (("Terry Gray" NIL "gray" "cac.washington.edu"))
+      (("Terry Gray" NIL "gray" "cac.washington.edu"))
+      (("Terry Gray" NIL "gray" "cac.washington.edu"))
+      ((NIL NIL "imap" "cac.washington.edu"))
+      ((NIL NIL "minutes" "CNRI.Reston.VA.US")
+      ("John Klensin" NIL "KLENSIN" "MIT.EDU")) NIL NIL
+      "<B27397-0100000@cac.washington.edu>")
+       BODY ("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 3028
+       92))
+S:    a003 OK FETCH completed
+C:    a004 fetch 12 body[header]
+S:    * 12 FETCH (BODY[HEADER] {342}
+S:    Date: Wed, 17 Jul 1996 02:23:25 -0700 (PDT)
+S:    From: Terry Gray <gray@cac.washington.edu>
+S:    Subject: IMAP4rev1 WG mtg summary and minutes
+S:    To: imap@cac.washington.edu
+S:    cc: minutes@CNRI.Reston.VA.US, John Klensin <KLENSIN@MIT.EDU>
+S:    Message-Id: <B27397-0100000@cac.washington.edu>
+S:    MIME-Version: 1.0
+S:    Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
+S:
+S:    )
+S:    a004 OK FETCH completed
+C:    a005 store 12 +flags \deleted
+S:    * 12 FETCH (FLAGS (\Seen \Deleted))
+S:    a005 OK +FLAGS completed
+C:    a006 logout
+S:    * BYE IMAP4rev1 server terminating connection
+S:    a006 OK LOGOUT completed
+
+
+
+Crispin                     Standards Track                    [Page 80]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+9.      Formal Syntax
+
+   The following syntax specification uses the Augmented Backus-Naur
+   Form (ABNF) notation as specified in [ABNF].
+
+   In the case of alternative or optional rules in which a later rule
+   overlaps an earlier rule, the rule which is listed earlier MUST take
+   priority.  For example, "\Seen" when parsed as a flag is the \Seen
+   flag name and not a flag-extension, even though "\Seen" can be parsed
+   as a flag-extension.  Some, but not all, instances of this rule are
+   noted below.
+
+        Note: [ABNF] rules MUST be followed strictly; in
+        particular:
+
+        (1) Except as noted otherwise, all alphabetic characters
+        are case-insensitive.  The use of upper or lower case
+        characters to define token strings is for editorial clarity
+        only.  Implementations MUST accept these strings in a
+        case-insensitive fashion.
+
+        (2) In all cases, SP refers to exactly one space.  It is
+        NOT permitted to substitute TAB, insert additional spaces,
+        or otherwise treat SP as being equivalent to LWSP.
+
+        (3) The ASCII NUL character, %x00, MUST NOT be used at any
+        time.
+
+address         = "(" addr-name SP addr-adl SP addr-mailbox SP
+                  addr-host ")"
+
+addr-adl        = nstring
+                    ; Holds route from [RFC-2822] route-addr if
+                    ; non-NIL
+
+addr-host       = nstring
+                    ; NIL indicates [RFC-2822] group syntax.
+                    ; Otherwise, holds [RFC-2822] domain name
+
+addr-mailbox    = nstring
+                    ; NIL indicates end of [RFC-2822] group; if
+                    ; non-NIL and addr-host is NIL, holds
+                    ; [RFC-2822] group name.
+                    ; Otherwise, holds [RFC-2822] local-part
+                    ; after removing [RFC-2822] quoting
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 81]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+addr-name       = nstring
+                    ; If non-NIL, holds phrase from [RFC-2822]
+                    ; mailbox after removing [RFC-2822] quoting
+
+append          = "APPEND" SP mailbox [SP flag-list] [SP date-time] SP
+                  literal
+
+astring         = 1*ASTRING-CHAR / string
+
+ASTRING-CHAR   = ATOM-CHAR / resp-specials
+
+atom            = 1*ATOM-CHAR
+
+ATOM-CHAR       = <any CHAR except atom-specials>
+
+atom-specials   = "(" / ")" / "{" / SP / CTL / list-wildcards /
+                  quoted-specials / resp-specials
+
+authenticate    = "AUTHENTICATE" SP auth-type *(CRLF base64)
+
+auth-type       = atom
+                    ; Defined by [SASL]
+
+base64          = *(4base64-char) [base64-terminal]
+
+base64-char     = ALPHA / DIGIT / "+" / "/"
+                    ; Case-sensitive
+
+base64-terminal = (2base64-char "==") / (3base64-char "=")
+
+body            = "(" (body-type-1part / body-type-mpart) ")"
+
+body-extension  = nstring / number /
+                   "(" body-extension *(SP body-extension) ")"
+                    ; Future expansion.  Client implementations
+                    ; MUST accept body-extension fields.  Server
+                    ; implementations MUST NOT generate
+                    ; body-extension fields except as defined by
+                    ; future standard or standards-track
+                    ; revisions of this specification.
+
+body-ext-1part  = body-fld-md5 [SP body-fld-dsp [SP body-fld-lang
+                  [SP body-fld-loc *(SP body-extension)]]]
+                    ; MUST NOT be returned on non-extensible
+                    ; "BODY" fetch
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 82]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+body-ext-mpart  = body-fld-param [SP body-fld-dsp [SP body-fld-lang
+                  [SP body-fld-loc *(SP body-extension)]]]
+                    ; MUST NOT be returned on non-extensible
+                    ; "BODY" fetch
+
+body-fields     = body-fld-param SP body-fld-id SP body-fld-desc SP
+                  body-fld-enc SP body-fld-octets
+
+body-fld-desc   = nstring
+
+body-fld-dsp    = "(" string SP body-fld-param ")" / nil
+
+body-fld-enc    = (DQUOTE ("7BIT" / "8BIT" / "BINARY" / "BASE64"/
+                  "QUOTED-PRINTABLE") DQUOTE) / string
+
+body-fld-id     = nstring
+
+body-fld-lang   = nstring / "(" string *(SP string) ")"
+
+body-fld-loc    = nstring
+
+body-fld-lines  = number
+
+body-fld-md5    = nstring
+
+body-fld-octets = number
+
+body-fld-param  = "(" string SP string *(SP string SP string) ")" / nil
+
+body-type-1part = (body-type-basic / body-type-msg / body-type-text)
+                  [SP body-ext-1part]
+
+body-type-basic = media-basic SP body-fields
+                    ; MESSAGE subtype MUST NOT be "RFC822"
+
+body-type-mpart = 1*body SP media-subtype
+                  [SP body-ext-mpart]
+
+body-type-msg   = media-message SP body-fields SP envelope
+                  SP body SP body-fld-lines
+
+body-type-text  = media-text SP body-fields SP body-fld-lines
+
+capability      = ("AUTH=" auth-type) / atom
+                    ; New capabilities MUST begin with "X" or be
+                    ; registered with IANA as standard or
+                    ; standards-track
+
+
+
+
+Crispin                     Standards Track                    [Page 83]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+capability-data = "CAPABILITY" *(SP capability) SP "IMAP4rev1"
+                  *(SP capability)
+                    ; Servers MUST implement the STARTTLS, AUTH=PLAIN,
+                    ; and LOGINDISABLED capabilities
+                    ; Servers which offer RFC 1730 compatibility MUST
+                    ; list "IMAP4" as the first capability.
+
+CHAR8           = %x01-ff
+                    ; any OCTET except NUL, %x00
+
+command         = tag SP (command-any / command-auth / command-nonauth /
+                  command-select) CRLF
+                    ; Modal based on state
+
+command-any     = "CAPABILITY" / "LOGOUT" / "NOOP" / x-command
+                    ; Valid in all states
+
+command-auth    = append / create / delete / examine / list / lsub /
+                  rename / select / status / subscribe / unsubscribe
+                    ; Valid only in Authenticated or Selected state
+
+command-nonauth = login / authenticate / "STARTTLS"
+                    ; Valid only when in Not Authenticated state
+
+command-select  = "CHECK" / "CLOSE" / "EXPUNGE" / copy / fetch / store /
+                  uid / search
+                    ; Valid only when in Selected state
+
+continue-req    = "+" SP (resp-text / base64) CRLF
+
+copy            = "COPY" SP sequence-set SP mailbox
+
+create          = "CREATE" SP mailbox
+                    ; Use of INBOX gives a NO error
+
+date            = date-text / DQUOTE date-text DQUOTE
+
+date-day        = 1*2DIGIT
+                    ; Day of month
+
+date-day-fixed  = (SP DIGIT) / 2DIGIT
+                    ; Fixed-format version of date-day
+
+date-month      = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" /
+                  "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
+
+date-text       = date-day "-" date-month "-" date-year
+
+
+
+
+Crispin                     Standards Track                    [Page 84]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+date-year       = 4DIGIT
+
+date-time       = DQUOTE date-day-fixed "-" date-month "-" date-year
+                  SP time SP zone DQUOTE
+
+delete          = "DELETE" SP mailbox
+                    ; Use of INBOX gives a NO error
+
+digit-nz        = %x31-39
+                    ; 1-9
+
+envelope        = "(" env-date SP env-subject SP env-from SP
+                  env-sender SP env-reply-to SP env-to SP env-cc SP
+                  env-bcc SP env-in-reply-to SP env-message-id ")"
+
+env-bcc         = "(" 1*address ")" / nil
+
+env-cc          = "(" 1*address ")" / nil
+
+env-date        = nstring
+
+env-from        = "(" 1*address ")" / nil
+
+env-in-reply-to = nstring
+
+env-message-id  = nstring
+
+env-reply-to    = "(" 1*address ")" / nil
+
+env-sender      = "(" 1*address ")" / nil
+
+env-subject     = nstring
+
+env-to          = "(" 1*address ")" / nil
+
+examine         = "EXAMINE" SP mailbox
+
+fetch           = "FETCH" SP sequence-set SP ("ALL" / "FULL" / "FAST" /
+                  fetch-att / "(" fetch-att *(SP fetch-att) ")")
+
+fetch-att       = "ENVELOPE" / "FLAGS" / "INTERNALDATE" /
+                  "RFC822" [".HEADER" / ".SIZE" / ".TEXT"] /
+                  "BODY" ["STRUCTURE"] / "UID" /
+                  "BODY" section ["<" number "." nz-number ">"] /
+                  "BODY.PEEK" section ["<" number "." nz-number ">"]
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 85]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+flag            = "\Answered" / "\Flagged" / "\Deleted" /
+                  "\Seen" / "\Draft" / flag-keyword / flag-extension
+                    ; Does not include "\Recent"
+
+flag-extension  = "\" atom
+                    ; Future expansion.  Client implementations
+                    ; MUST accept flag-extension flags.  Server
+                    ; implementations MUST NOT generate
+                    ; flag-extension flags except as defined by
+                    ; future standard or standards-track
+                    ; revisions of this specification.
+
+flag-fetch      = flag / "\Recent"
+
+flag-keyword    = atom
+
+flag-list       = "(" [flag *(SP flag)] ")"
+
+flag-perm       = flag / "\*"
+
+greeting        = "*" SP (resp-cond-auth / resp-cond-bye) CRLF
+
+header-fld-name = astring
+
+header-list     = "(" header-fld-name *(SP header-fld-name) ")"
+
+list            = "LIST" SP mailbox SP list-mailbox
+
+list-mailbox    = 1*list-char / string
+
+list-char       = ATOM-CHAR / list-wildcards / resp-specials
+
+list-wildcards  = "%" / "*"
+
+literal         = "{" number "}" CRLF *CHAR8
+                    ; Number represents the number of CHAR8s
+
+login           = "LOGIN" SP userid SP password
+
+lsub            = "LSUB" SP mailbox SP list-mailbox
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 86]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+mailbox         = "INBOX" / astring
+                    ; INBOX is case-insensitive.  All case variants of
+                    ; INBOX (e.g., "iNbOx") MUST be interpreted as INBOX
+                    ; not as an astring.  An astring which consists of
+                    ; the case-insensitive sequence "I" "N" "B" "O" "X"
+                    ; is considered to be INBOX and not an astring.
+                    ;  Refer to section 5.1 for further
+                    ; semantic details of mailbox names.
+
+mailbox-data    =  "FLAGS" SP flag-list / "LIST" SP mailbox-list /
+                   "LSUB" SP mailbox-list / "SEARCH" *(SP nz-number) /
+                   "STATUS" SP mailbox SP "(" [status-att-list] ")" /
+                   number SP "EXISTS" / number SP "RECENT"
+
+mailbox-list    = "(" [mbx-list-flags] ")" SP
+                   (DQUOTE QUOTED-CHAR DQUOTE / nil) SP mailbox
+
+mbx-list-flags  = *(mbx-list-oflag SP) mbx-list-sflag
+                  *(SP mbx-list-oflag) /
+                  mbx-list-oflag *(SP mbx-list-oflag)
+
+mbx-list-oflag  = "\Noinferiors" / flag-extension
+                    ; Other flags; multiple possible per LIST response
+
+mbx-list-sflag  = "\Noselect" / "\Marked" / "\Unmarked"
+                    ; Selectability flags; only one per LIST response
+
+media-basic     = ((DQUOTE ("APPLICATION" / "AUDIO" / "IMAGE" /
+                  "MESSAGE" / "VIDEO") DQUOTE) / string) SP
+                  media-subtype
+                    ; Defined in [MIME-IMT]
+
+media-message   = DQUOTE "MESSAGE" DQUOTE SP DQUOTE "RFC822" DQUOTE
+                    ; Defined in [MIME-IMT]
+
+media-subtype   = string
+                    ; Defined in [MIME-IMT]
+
+media-text      = DQUOTE "TEXT" DQUOTE SP media-subtype
+                    ; Defined in [MIME-IMT]
+
+message-data    = nz-number SP ("EXPUNGE" / ("FETCH" SP msg-att))
+
+msg-att         = "(" (msg-att-dynamic / msg-att-static)
+                   *(SP (msg-att-dynamic / msg-att-static)) ")"
+
+msg-att-dynamic = "FLAGS" SP "(" [flag-fetch *(SP flag-fetch)] ")"
+                    ; MAY change for a message
+
+
+
+Crispin                     Standards Track                    [Page 87]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+msg-att-static  = "ENVELOPE" SP envelope / "INTERNALDATE" SP date-time /
+                  "RFC822" [".HEADER" / ".TEXT"] SP nstring /
+                  "RFC822.SIZE" SP number /
+                  "BODY" ["STRUCTURE"] SP body /
+                  "BODY" section ["<" number ">"] SP nstring /
+                  "UID" SP uniqueid
+                    ; MUST NOT change for a message
+
+nil             = "NIL"
+
+nstring         = string / nil
+
+number          = 1*DIGIT
+                    ; Unsigned 32-bit integer
+                    ; (0 <= n < 4,294,967,296)
+
+nz-number       = digit-nz *DIGIT
+                    ; Non-zero unsigned 32-bit integer
+                    ; (0 < n < 4,294,967,296)
+
+password        = astring
+
+quoted          = DQUOTE *QUOTED-CHAR DQUOTE
+
+QUOTED-CHAR     = <any TEXT-CHAR except quoted-specials> /
+                  "\" quoted-specials
+
+quoted-specials = DQUOTE / "\"
+
+rename          = "RENAME" SP mailbox SP mailbox
+                    ; Use of INBOX as a destination gives a NO error
+
+response        = *(continue-req / response-data) response-done
+
+response-data   = "*" SP (resp-cond-state / resp-cond-bye /
+                  mailbox-data / message-data / capability-data) CRLF
+
+response-done   = response-tagged / response-fatal
+
+response-fatal  = "*" SP resp-cond-bye CRLF
+                    ; Server closes connection immediately
+
+response-tagged = tag SP resp-cond-state CRLF
+
+resp-cond-auth  = ("OK" / "PREAUTH") SP resp-text
+                    ; Authentication condition
+
+
+
+
+
+Crispin                     Standards Track                    [Page 88]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+resp-cond-bye   = "BYE" SP resp-text
+
+resp-cond-state = ("OK" / "NO" / "BAD") SP resp-text
+                    ; Status condition
+
+resp-specials   = "]"
+
+resp-text       = ["[" resp-text-code "]" SP] text
+
+resp-text-code  = "ALERT" /
+                  "BADCHARSET" [SP "(" astring *(SP astring) ")" ] /
+                  capability-data / "PARSE" /
+                  "PERMANENTFLAGS" SP "("
+                  [flag-perm *(SP flag-perm)] ")" /
+                  "READ-ONLY" / "READ-WRITE" / "TRYCREATE" /
+                  "UIDNEXT" SP nz-number / "UIDVALIDITY" SP nz-number /
+                  "UNSEEN" SP nz-number /
+                  atom [SP 1*<any TEXT-CHAR except "]">]
+
+search          = "SEARCH" [SP "CHARSET" SP astring] 1*(SP search-key)
+                    ; CHARSET argument to MUST be registered with IANA
+
+search-key      = "ALL" / "ANSWERED" / "BCC" SP astring /
+                  "BEFORE" SP date / "BODY" SP astring /
+                  "CC" SP astring / "DELETED" / "FLAGGED" /
+                  "FROM" SP astring / "KEYWORD" SP flag-keyword /
+                  "NEW" / "OLD" / "ON" SP date / "RECENT" / "SEEN" /
+                  "SINCE" SP date / "SUBJECT" SP astring /
+                  "TEXT" SP astring / "TO" SP astring /
+                  "UNANSWERED" / "UNDELETED" / "UNFLAGGED" /
+                  "UNKEYWORD" SP flag-keyword / "UNSEEN" /
+                    ; Above this line were in [IMAP2]
+                  "DRAFT" / "HEADER" SP header-fld-name SP astring /
+                  "LARGER" SP number / "NOT" SP search-key /
+                  "OR" SP search-key SP search-key /
+                  "SENTBEFORE" SP date / "SENTON" SP date /
+                  "SENTSINCE" SP date / "SMALLER" SP number /
+                  "UID" SP sequence-set / "UNDRAFT" / sequence-set /
+                  "(" search-key *(SP search-key) ")"
+
+section         = "[" [section-spec] "]"
+
+section-msgtext = "HEADER" / "HEADER.FIELDS" [".NOT"] SP header-list /
+                  "TEXT"
+                    ; top-level or MESSAGE/RFC822 part
+
+section-part    = nz-number *("." nz-number)
+                    ; body part nesting
+
+
+
+Crispin                     Standards Track                    [Page 89]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+section-spec    = section-msgtext / (section-part ["." section-text])
+
+section-text    = section-msgtext / "MIME"
+                    ; text other than actual body part (headers, etc.)
+
+select          = "SELECT" SP mailbox
+
+seq-number      = nz-number / "*"
+                    ; message sequence number (COPY, FETCH, STORE
+                    ; commands) or unique identifier (UID COPY,
+                    ; UID FETCH, UID STORE commands).
+                    ; * represents the largest number in use.  In
+                    ; the case of message sequence numbers, it is
+                    ; the number of messages in a non-empty mailbox.
+                    ; In the case of unique identifiers, it is the
+                    ; unique identifier of the last message in the
+                    ; mailbox or, if the mailbox is empty, the
+                    ; mailbox's current UIDNEXT value.
+                    ; The server should respond with a tagged BAD
+                    ; response to a command that uses a message
+                    ; sequence number greater than the number of
+                    ; messages in the selected mailbox.  This
+                    ; includes "*" if the selected mailbox is empty.
+
+seq-range       = seq-number ":" seq-number
+                    ; two seq-number values and all values between
+                    ; these two regardless of order.
+                    ; Example: 2:4 and 4:2 are equivalent and indicate
+                    ; values 2, 3, and 4.
+                    ; Example: a unique identifer sequence range of
+                    ; 3291:* includes the UID of the last message in
+                    ; the mailbox, even if that value is less than 3291.
+
+sequence-set    = (seq-number / seq-range) *("," sequence-set)
+                    ; set of seq-number values, regardless of order.
+                    ; Servers MAY coalesce overlaps and/or execute the
+                    ; sequence in any order.
+                    ; Example: a message sequence number set of
+                    ; 2,4:7,9,12:* for a mailbox with 15 messages is
+                    ; equivalent to 2,4,5,6,7,9,12,13,14,15
+                    ; Example: a message sequence number set of *:4,5:7
+                    ; for a mailbox with 10 messages is equivalent to
+                    ; 10,9,8,7,6,5,4,5,6,7 and MAY be reordered and
+                    ; overlap coalesced to be 4,5,6,7,8,9,10.
+
+status          = "STATUS" SP mailbox SP
+                  "(" status-att *(SP status-att) ")"
+
+
+
+
+Crispin                     Standards Track                    [Page 90]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+status-att      = "MESSAGES" / "RECENT" / "UIDNEXT" / "UIDVALIDITY" /
+                  "UNSEEN"
+
+status-att-list =  status-att SP number *(SP status-att SP number)
+
+store           = "STORE" SP sequence-set SP store-att-flags
+
+store-att-flags = (["+" / "-"] "FLAGS" [".SILENT"]) SP
+                  (flag-list / (flag *(SP flag)))
+
+string          = quoted / literal
+
+subscribe       = "SUBSCRIBE" SP mailbox
+
+tag             = 1*<any ASTRING-CHAR except "+">
+
+text            = 1*TEXT-CHAR
+
+TEXT-CHAR       = <any CHAR except CR and LF>
+
+time            = 2DIGIT ":" 2DIGIT ":" 2DIGIT
+                    ; Hours minutes seconds
+
+uid             = "UID" SP (copy / fetch / search / store)
+                    ; Unique identifiers used instead of message
+                    ; sequence numbers
+
+uniqueid        = nz-number
+                    ; Strictly ascending
+
+unsubscribe     = "UNSUBSCRIBE" SP mailbox
+
+userid          = astring
+
+x-command       = "X" atom <experimental command arguments>
+
+zone            = ("+" / "-") 4DIGIT
+                    ; Signed four-digit value of hhmm representing
+                    ; hours and minutes east of Greenwich (that is,
+                    ; the amount that the given time differs from
+                    ; Universal Time).  Subtracting the timezone
+                    ; from the given time will give the UT form.
+                    ; The Universal Time zone is "+0000".
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 91]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+10.     Author's Note
+
+   This document is a revision or rewrite of earlier documents, and
+   supercedes the protocol specification in those documents: RFC 2060,
+   RFC 1730, unpublished IMAP2bis.TXT document, RFC 1176, and RFC 1064.
+
+11.     Security Considerations
+
+   IMAP4rev1 protocol transactions, including electronic mail data, are
+   sent in the clear over the network unless protection from snooping is
+   negotiated.  This can be accomplished either by the use of STARTTLS,
+   negotiated privacy protection in the AUTHENTICATE command, or some
+   other protection mechanism.
+
+11.1.   STARTTLS Security Considerations
+
+   The specification of the STARTTLS command and LOGINDISABLED
+   capability in this document replaces that in [IMAP-TLS].  [IMAP-TLS]
+   remains normative for the PLAIN [SASL] authenticator.
+
+   IMAP client and server implementations MUST implement the
+   TLS_RSA_WITH_RC4_128_MD5 [TLS] cipher suite, and SHOULD implement the
+   TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA [TLS] cipher suite.  This is
+   important as it assures that any two compliant implementations can be
+   configured to interoperate.  All other cipher suites are OPTIONAL.
+   Note that this is a change from section 2.1 of [IMAP-TLS].
+
+   During the [TLS] negotiation, the client MUST check its understanding
+   of the server hostname against the server's identity as presented in
+   the server Certificate message, in order to prevent man-in-the-middle
+   attacks.  If the match fails, the client SHOULD either ask for
+   explicit user confirmation, or terminate the connection and indicate
+   that the server's identity is suspect.  Matching is performed
+   according to these rules:
+
+        The client MUST use the server hostname it used to open the
+        connection as the value to compare against the server name
+        as expressed in the server certificate.  The client MUST
+        NOT use any form of the server hostname derived from an
+        insecure remote source (e.g., insecure DNS lookup).  CNAME
+        canonicalization is not done.
+
+        If a subjectAltName extension of type dNSName is present in
+        the certificate, it SHOULD be used as the source of the
+        server's identity.
+
+        Matching is case-insensitive.
+
+
+
+
+Crispin                     Standards Track                    [Page 92]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+        A "*" wildcard character MAY be used as the left-most name
+        component in the certificate.  For example, *.example.com
+        would match a.example.com, foo.example.com, etc. but would
+        not match example.com.
+
+        If the certificate contains multiple names (e.g., more than
+        one dNSName field), then a match with any one of the fields
+        is considered acceptable.
+
+   Both the client and server MUST check the result of the STARTTLS
+   command and subsequent [TLS] negotiation to see whether acceptable
+   authentication or privacy was achieved.
+
+11.2.   Other Security Considerations
+
+   A server error message for an AUTHENTICATE command which fails due to
+   invalid credentials SHOULD NOT detail why the credentials are
+   invalid.
+
+   Use of the LOGIN command sends passwords in the clear.  This can be
+   avoided by using the AUTHENTICATE command with a [SASL] mechanism
+   that does not use plaintext passwords, by first negotiating
+   encryption via STARTTLS or some other protection mechanism.
+
+   A server implementation MUST implement a configuration that, at the
+   time of authentication, requires:
+      (1) The STARTTLS command has been negotiated.
+   OR
+      (2) Some other mechanism that protects the session from password
+      snooping has been provided.
+   OR
+      (3) The following measures are in place:
+         (a) The LOGINDISABLED capability is advertised, and [SASL]
+         mechanisms (such as PLAIN) using plaintext passwords are NOT
+         advertised in the CAPABILITY list.
+      AND
+         (b) The LOGIN command returns an error even if the password is
+         correct.
+      AND
+         (c) The AUTHENTICATE command returns an error with all [SASL]
+         mechanisms that use plaintext passwords, even if the password
+         is correct.
+
+   A server error message for a failing LOGIN command SHOULD NOT specify
+   that the user name, as opposed to the password, is invalid.
+
+   A server SHOULD have mechanisms in place to limit or delay failed
+   AUTHENTICATE/LOGIN attempts.
+
+
+
+Crispin                     Standards Track                    [Page 93]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   Additional security considerations are discussed in the section
+   discussing the AUTHENTICATE and LOGIN commands.
+
+12.     IANA Considerations
+
+   IMAP4 capabilities are registered by publishing a standards track or
+   IESG approved experimental RFC.  The registry is currently located
+   at:
+
+        http://www.iana.org/assignments/imap4-capabilities
+
+   As this specification revises the STARTTLS and LOGINDISABLED
+   extensions previously defined in [IMAP-TLS], the registry will be
+   updated accordingly.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 94]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+Appendices
+
+A.      Normative References
+
+   The following documents contain definitions or specifications that
+   are necessary to understand this document properly:
+   [ABNF]                Crocker, D. and P. Overell, "Augmented BNF for
+                         Syntax Specifications: ABNF", RFC 2234,
+                         November 1997.
+
+   [ANONYMOUS]           Newman, C., "Anonymous SASL Mechanism", RFC
+                         2245, November 1997.
+
+   [CHARSET]             Freed, N. and J. Postel, "IANA Character Set
+                         Registration Procedures", RFC 2978, October
+                         2000.
+
+   [DIGEST-MD5]          Leach, P. and C. Newman, "Using Digest
+                         Authentication as a SASL Mechanism", RFC 2831,
+                         May 2000.
+
+   [DISPOSITION]         Troost, R., Dorner, S. and K. Moore,
+                         "Communicating Presentation Information in
+                         Internet Messages: The Content-Disposition
+                         Header", RFC 2183, August 1997.
+
+   [IMAP-TLS]            Newman, C., "Using TLS with IMAP, POP3 and
+                         ACAP", RFC 2595, June 1999.
+
+   [KEYWORDS]            Bradner, S., "Key words for use in RFCs to
+                         Indicate Requirement Levels", BCP 14, RFC 2119,
+                         March 1997.
+
+   [LANGUAGE-TAGS]       Alvestrand, H., "Tags for the Identification of
+                         Languages", BCP 47, RFC 3066, January 2001.
+
+   [LOCATION]            Palme, J., Hopmann, A. and N. Shelness, "MIME
+                         Encapsulation of Aggregate Documents, such as
+                         HTML (MHTML)", RFC 2557, March 1999.
+
+   [MD5]                 Myers, J. and M. Rose, "The Content-MD5 Header
+                         Field", RFC 1864, October 1995.
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 95]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   [MIME-HDRS]           Moore, K., "MIME (Multipurpose Internet Mail
+                         Extensions) Part Three: Message Header
+                         Extensions for Non-ASCII Text", RFC 2047,
+                         November 1996.
+
+   [MIME-IMB]            Freed, N. and N. Borenstein, "MIME
+                         (Multipurpose Internet Mail Extensions) Part
+                         One: Format of Internet Message Bodies", RFC
+                         2045, November 1996.
+
+   [MIME-IMT]            Freed, N. and N. Borenstein, "MIME
+                         (Multipurpose Internet Mail Extensions) Part
+                         Two: Media Types", RFC 2046, November 1996.
+
+   [RFC-2822]            Resnick, P., "Internet Message Format", RFC
+                         2822, April 2001.
+
+   [SASL]                Myers, J., "Simple Authentication and Security
+                         Layer (SASL)", RFC 2222, October 1997.
+
+   [TLS]                 Dierks, T. and C. Allen, "The TLS Protocol
+                         Version 1.0", RFC 2246, January 1999.
+
+   [UTF-7]               Goldsmith, D. and M. Davis, "UTF-7: A Mail-Safe
+                         Transformation Format of Unicode", RFC 2152,
+                         May 1997.
+
+   The following documents describe quality-of-implementation issues
+   that should be carefully considered when implementing this protocol:
+
+   [IMAP-IMPLEMENTATION] Leiba, B., "IMAP Implementation
+                         Recommendations", RFC 2683, September 1999.
+
+   [IMAP-MULTIACCESS]    Gahrns, M., "IMAP4 Multi-Accessed Mailbox
+                         Practice", RFC 2180, July 1997.
+
+A.1     Informative References
+
+   The following documents describe related protocols:
+
+   [IMAP-DISC]           Austein, R., "Synchronization Operations for
+                         Disconnected IMAP4 Clients", Work in Progress.
+
+   [IMAP-MODEL]          Crispin, M., "Distributed Electronic Mail
+                         Models in IMAP4", RFC 1733, December 1994.
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 96]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   [ACAP]                Newman, C. and J. Myers, "ACAP -- Application
+                         Configuration Access Protocol", RFC 2244,
+                         November 1997.
+
+   [SMTP]                Klensin, J., "Simple Mail Transfer Protocol",
+                         STD 10, RFC 2821, April 2001.
+
+   The following documents are historical or describe historical aspects
+   of this protocol:
+
+   [IMAP-COMPAT]         Crispin, M., "IMAP4 Compatibility with
+                         IMAP2bis", RFC 2061, December 1996.
+
+   [IMAP-HISTORICAL]     Crispin, M., "IMAP4 Compatibility with IMAP2
+                         and IMAP2bis", RFC 1732, December 1994.
+
+   [IMAP-OBSOLETE]       Crispin, M., "Internet Message Access Protocol
+                         - Obsolete Syntax", RFC 2062, December 1996.
+
+   [IMAP2]               Crispin, M., "Interactive Mail Access Protocol
+                         - Version 2", RFC 1176, August 1990.
+
+   [RFC-822]             Crocker, D., "Standard for the Format of ARPA
+                         Internet Text Messages", STD 11, RFC 822,
+                         August 1982.
+
+   [RFC-821]             Postel, J., "Simple Mail Transfer Protocol",
+                         STD 10, RFC 821, August 1982.
+
+B.      Changes from RFC 2060
+
+   1) Clarify description of unique identifiers and their semantics.
+
+   2) Fix the SELECT description to clarify that UIDVALIDITY is required
+   in the SELECT and EXAMINE responses.
+
+   3) Added an example of a failing search.
+
+   4) Correct store-att-flags: "#flag" should be "1#flag".
+
+   5) Made search and section rules clearer.
+
+   6) Correct the STORE example.
+
+   7) Correct "BASE645" misspelling.
+
+   8) Remove extraneous close parenthesis in example of two-part message
+   with text and BASE64 attachment.
+
+
+
+Crispin                     Standards Track                    [Page 97]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   9) Remove obsolete "MAILBOX" response from mailbox-data.
+
+   10) A spurious "<" in the rule for mailbox-data was removed.
+
+   11) Add CRLF to continue-req.
+
+   12) Specifically exclude "]" from the atom in resp-text-code.
+
+   13) Clarify that clients and servers should adhere strictly to the
+   protocol syntax.
+
+   14) Emphasize in 5.2 that EXISTS can not be used to shrink a mailbox.
+
+   15) Add NEWNAME to resp-text-code.
+
+   16) Clarify that the empty string, not NIL, is used as arguments to
+   LIST.
+
+   17) Clarify that NIL can be returned as a hierarchy delimiter for the
+   empty string mailbox name argument if the mailbox namespace is flat.
+
+   18) Clarify that addr-mailbox and addr-name have RFC-2822 quoting
+   removed.
+
+   19) Update UTF-7 reference.
+
+   20) Fix example in 6.3.11.
+
+   21) Clarify that non-existent UIDs are ignored.
+
+   22) Update DISPOSITION reference.
+
+   23) Expand state diagram.
+
+   24) Clarify that partial fetch responses are only returned in
+   response to a partial fetch command.
+
+   25) Add UIDNEXT response code.  Correct UIDVALIDITY definition
+   reference.
+
+   26) Further clarification of "can" vs. "MAY".
+
+   27) Reference RFC-2119.
+
+   28) Clarify that superfluous shifts are not permitted in modified
+   UTF-7.
+
+   29) Clarify that there are no implicit shifts in modified UTF-7.
+
+
+
+Crispin                     Standards Track                    [Page 98]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   30) Clarify that "INBOX" in a mailbox name is always INBOX, even if
+   it is given as a string.
+
+   31) Add missing open parenthesis in media-basic grammar rule.
+
+   32) Correct attribute syntax in mailbox-data.
+
+   33) Add UIDNEXT to EXAMINE responses.
+
+   34) Clarify UNSEEN, PERMANENTFLAGS, UIDVALIDITY, and UIDNEXT
+   responses in SELECT and EXAMINE.  They are required now, but weren't
+   in older versions.
+
+   35) Update references with RFC numbers.
+
+   36) Flush text-mime2.
+
+   37) Clarify that modified UTF-7 names must be case-sensitive and that
+   violating the convention should be avoided.
+
+   38) Correct UID FETCH example.
+
+   39) Clarify UID FETCH, UID STORE, and UID SEARCH vs. untagged EXPUNGE
+   responses.
+
+   40) Clarify the use of the word "convention".
+
+   41) Clarify that a command is not "in progress" until it has been
+   fully received (specifically, that a command is not "in progress"
+   during command continuation negotiation).
+
+   42) Clarify envelope defaulting.
+
+   43) Clarify that SP means one and only one space character.
+
+   44) Forbid silly states in LIST response.
+
+   45) Clarify that the ENVELOPE, INTERNALDATE, RFC822*, BODY*, and UID
+   for a message is static.
+
+   46) Add BADCHARSET response code.
+
+   47) Update formal syntax to [ABNF] conventions.
+
+   48) Clarify trailing hierarchy delimiter in CREATE semantics.
+
+   49) Clarify that the "blank line" is the [RFC-2822] delimiting blank
+   line.
+
+
+
+Crispin                     Standards Track                    [Page 99]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   50) Clarify that RENAME should also create hierarchy as needed for
+   the command to complete.
+
+   51) Fix body-ext-mpart to not require language if disposition
+   present.
+
+   52) Clarify the RFC822.HEADER response.
+
+   53) Correct missing space after charset astring in search.
+
+   54) Correct missing quote for BADCHARSET in resp-text-code.
+
+   55) Clarify that ALL, FAST, and FULL preclude any other data items
+   appearing.
+
+   56) Clarify semantics of reference argument in LIST.
+
+   57) Clarify that a null string for SEARCH HEADER X-FOO means any
+   message with a header line with a field-name of X-FOO regardless of
+   the text of the header.
+
+   58) Specifically reserve 8-bit mailbox names for future use as UTF-8.
+
+   59) It is not an error for the client to store a flag that is not in
+   the PERMANENTFLAGS list; however, the server will either ignore the
+   change or make the change in the session only.
+
+   60) Correct/clarify the text regarding superfluous shifts.
+
+   61) Correct typographic errors in the "Changes" section.
+
+   62) Clarify that STATUS must not be used to check for new messages in
+   the selected mailbox
+
+   63) Clarify LSUB behavior with "%" wildcard.
+
+   64) Change AUTHORIZATION to AUTHENTICATE in section 7.5.
+
+   65) Clarify description of multipart body type.
+
+   66) Clarify that STORE FLAGS does not affect \Recent.
+
+   67) Change "west" to "east" in description of timezone.
+
+   68) Clarify that commands which break command pipelining must wait
+   for a completion result response.
+
+   69) Clarify that EXAMINE does not affect \Recent.
+
+
+
+Crispin                     Standards Track                   [Page 100]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   70) Make description of MIME structure consistent.
+
+   71) Clarify that date searches disregard the time and timezone of the
+   INTERNALDATE or Date: header.  In other words, "ON 13-APR-2000" means
+   messages with an INTERNALDATE text which starts with "13-APR-2000",
+   even if timezone differential from the local timezone is sufficient
+   to move that INTERNALDATE into the previous or next day.
+
+   72) Clarify that the header fetches don't add a blank line if one
+   isn't in the [RFC-2822] message.
+
+   73) Clarify (in discussion of UIDs) that messages are immutable.
+
+   74) Add an example of CHARSET searching.
+
+   75) Clarify in SEARCH that keywords are a type of flag.
+
+   76) Clarify the mandatory nature of the SELECT data responses.
+
+   77) Add optional CAPABILITY response code in the initial OK or
+   PREAUTH.
+
+   78) Add note that server can send an untagged CAPABILITY command as
+   part of the responses to AUTHENTICATE and LOGIN.
+
+   79) Remove statement about it being unnecessary to issue a CAPABILITY
+   command more than once in a connection.  That statement is no longer
+   true.
+
+   80) Clarify that untagged EXPUNGE decrements the number of messages
+   in the mailbox.
+
+   81) Fix definition of "body" (concatenation has tighter binding than
+   alternation).
+
+   82) Add a new "Special Notes to Implementors" section with reference
+   to [IMAP-IMPLEMENTATION].
+
+   83) Clarify that an untagged CAPABILITY response to an AUTHENTICATE
+   command should only be done if a security layer was not negotiated.
+
+   84) Change the definition of atom to exclude "]".  Update astring to
+   include "]" for compatiblity with the past.  Remove resp-text-atom.
+
+   85) Remove NEWNAME.  It can't work because mailbox names can be
+   literals and can include "]".  Functionality can be addressed via
+   referrals.
+
+
+
+
+Crispin                     Standards Track                   [Page 101]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   86) Move modified UTF-7 rationale in order to have more logical
+   paragraph flow.
+
+   87) Clarify UID uniqueness guarantees with the use of MUST.
+
+   88) Note that clients should read response data until the connection
+   is closed instead of immediately closing on a BYE.
+
+   89) Change RFC-822 references to RFC-2822.
+
+   90) Clarify that RFC-2822 should be followed instead of RFC-822.
+
+   91) Change recommendation of optional automatic capabilities in LOGIN
+   and AUTHENTICATE to use the CAPABILITY response code in the tagged
+   OK.  This is more interoperable than an unsolicited untagged
+   CAPABILITY response.
+
+   92) STARTTLS and AUTH=PLAIN are mandatory to implement; add
+   recommendations for other [SASL] mechanisms.
+
+   93) Clarify that a "connection" (as opposed to "server" or "command")
+   is in one of the four states.
+
+   94) Clarify that a failed or rejected command does not change state.
+
+   95) Split references between normative and informative.
+
+   96) Discuss authentication failure issues in security section.
+
+   97) Clarify that a data item is not necessarily of only one data
+   type.
+
+   98) Clarify that sequence ranges are independent of order.
+
+   99) Change an example to clarify that superfluous shifts in
+   Modified-UTF7 can not be fixed just by omitting the shift.  The
+   entire string must be recalculated.
+
+   100) Change Envelope Structure definition since [RFC-2822] uses
+   "envelope" to refer to the [SMTP] envelope and not the envelope data
+   that appears in the [RFC-2822] header.
+
+   101) Expand on RFC822.HEADER response data vs. BODY[HEADER].
+
+   102) Clarify Logout state semantics, change ASCII art.
+
+   103) Security changes to comply with IESG requirements.
+
+
+
+
+Crispin                     Standards Track                   [Page 102]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+   104) Add definition for body URI.
+
+   105) Break sequence range definition into three rules, with rewritten
+   descriptions for each.
+
+   106) Move STARTTLS and LOGINDISABLED here from [IMAP-TLS].
+
+   107) Add IANA Considerations section.
+
+   108) Clarify valid client assumptions for new message UIDs vs.
+   UIDNEXT.
+
+   109) Clarify that changes to permanentflags affect concurrent
+   sessions as well as subsequent sessions.
+
+   110) Clarify that authenticated state can be entered by the CLOSE
+   command.
+
+   111) Emphasize that SELECT and EXAMINE are the exceptions to the rule
+   that a failing command does not change state.
+
+   112) Clarify that newly-appended messages have the Recent flag set.
+
+   113) Clarify that newly-copied messages SHOULD have the Recent flag
+   set.
+
+   114) Clarify that UID commands always return the UID in FETCH
+   responses.
+
+C.      Key Word Index
+
+       +FLAGS <flag list> (store command data item) ...............   59
+       +FLAGS.SILENT <flag list> (store command data item) ........   59
+       -FLAGS <flag list> (store command data item) ...............   59
+       -FLAGS.SILENT <flag list> (store command data item) ........   59
+       ALERT (response code) ......................................   64
+       ALL (fetch item) ...........................................   55
+       ALL (search key) ...........................................   50
+       ANSWERED (search key) ......................................   50
+       APPEND (command) ...........................................   45
+       AUTHENTICATE (command) .....................................   27
+       BAD (response) .............................................   66
+       BADCHARSET (response code) .................................   64
+       BCC <string> (search key) ..................................   51
+       BEFORE <date> (search key) .................................   51
+       BODY (fetch item) ..........................................   55
+       BODY (fetch result) ........................................   73
+       BODY <string> (search key) .................................   51
+
+
+
+Crispin                     Standards Track                   [Page 103]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+       BODY.PEEK[<section>]<<partial>> (fetch item) ...............   57
+       BODYSTRUCTURE (fetch item) .................................   57
+       BODYSTRUCTURE (fetch result) ...............................   74
+       BODY[<section>]<<origin octet>> (fetch result) .............   74
+       BODY[<section>]<<partial>> (fetch item) ....................   55
+       BYE (response) .............................................   67
+       Body Structure (message attribute) .........................   12
+       CAPABILITY (command) .......................................   24
+       CAPABILITY (response code) .................................   64
+       CAPABILITY (response) ......................................   68
+       CC <string> (search key) ...................................   51
+       CHECK (command) ............................................   47
+       CLOSE (command) ............................................   48
+       COPY (command) .............................................   59
+       CREATE (command) ...........................................   34
+       DELETE (command) ...........................................   35
+       DELETED (search key) .......................................   51
+       DRAFT (search key) .........................................   51
+       ENVELOPE (fetch item) ......................................   57
+       ENVELOPE (fetch result) ....................................   77
+       EXAMINE (command) ..........................................   33
+       EXISTS (response) ..........................................   71
+       EXPUNGE (command) ..........................................   48
+       EXPUNGE (response) .........................................   72
+       Envelope Structure (message attribute) .....................   12
+       FAST (fetch item) ..........................................   55
+       FETCH (command) ............................................   54
+       FETCH (response) ...........................................   73
+       FLAGGED (search key) .......................................   51
+       FLAGS (fetch item) .........................................   57
+       FLAGS (fetch result) .......................................   78
+       FLAGS (response) ...........................................   71
+       FLAGS <flag list> (store command data item) ................   59
+       FLAGS.SILENT <flag list> (store command data item) .........   59
+       FROM <string> (search key) .................................   51
+       FULL (fetch item) ..........................................   55
+       Flags (message attribute) ..................................   11
+       HEADER (part specifier) ....................................   55
+       HEADER <field-name> <string> (search key) ..................   51
+       HEADER.FIELDS <header-list> (part specifier) ...............   55
+       HEADER.FIELDS.NOT <header-list> (part specifier) ...........   55
+       INTERNALDATE (fetch item) ..................................   57
+       INTERNALDATE (fetch result) ................................   78
+       Internal Date (message attribute) ..........................   12
+       KEYWORD <flag> (search key) ................................   51
+       Keyword (type of flag) .....................................   11
+       LARGER <n> (search key) ....................................   51
+       LIST (command) .............................................   40
+
+
+
+Crispin                     Standards Track                   [Page 104]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+       LIST (response) ............................................   69
+       LOGIN (command) ............................................   30
+       LOGOUT (command) ...........................................   25
+       LSUB (command) .............................................   43
+       LSUB (response) ............................................   70
+       MAY (specification requirement term) .......................    4
+       MESSAGES (status item) .....................................   45
+       MIME (part specifier) ......................................   56
+       MUST (specification requirement term) ......................    4
+       MUST NOT (specification requirement term) ..................    4
+       Message Sequence Number (message attribute) ................   10
+       NEW (search key) ...........................................   51
+       NO (response) ..............................................   66
+       NOOP (command) .............................................   25
+       NOT <search-key> (search key) ..............................   52
+       OK (response) ..............................................   65
+       OLD (search key) ...........................................   52
+       ON <date> (search key) .....................................   52
+       OPTIONAL (specification requirement term) ..................    4
+       OR <search-key1> <search-key2> (search key) ................   52
+       PARSE (response code) ......................................   64
+       PERMANENTFLAGS (response code) .............................   64
+       PREAUTH (response) .........................................   67
+       Permanent Flag (class of flag) .............................   12
+       READ-ONLY (response code) ..................................   65
+       READ-WRITE (response code) .................................   65
+       RECENT (response) ..........................................   72
+       RECENT (search key) ........................................   52
+       RECENT (status item) .......................................   45
+       RENAME (command) ...........................................   37
+       REQUIRED (specification requirement term) ..................    4
+       RFC822 (fetch item) ........................................   57
+       RFC822 (fetch result) ......................................   78
+       RFC822.HEADER (fetch item) .................................   57
+       RFC822.HEADER (fetch result) ...............................   78
+       RFC822.SIZE (fetch item) ...................................   57
+       RFC822.SIZE (fetch result) .................................   78
+       RFC822.TEXT (fetch item) ...................................   58
+       RFC822.TEXT (fetch result) .................................   79
+       SEARCH (command) ...........................................   49
+       SEARCH (response) ..........................................   71
+       SEEN (search key) ..........................................   52
+       SELECT (command) ...........................................   31
+       SENTBEFORE <date> (search key) .............................   52
+       SENTON <date> (search key) .................................   52
+       SENTSINCE <date> (search key) ..............................   52
+       SHOULD (specification requirement term) ....................    4
+       SHOULD NOT (specification requirement term) ................    4
+
+
+
+Crispin                     Standards Track                   [Page 105]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+       SINCE <date> (search key) ..................................   52
+       SMALLER <n> (search key) ...................................   52
+       STARTTLS (command) .........................................   27
+       STATUS (command) ...........................................   44
+       STATUS (response) ..........................................   70
+       STORE (command) ............................................   58
+       SUBJECT <string> (search key) ..............................   53
+       SUBSCRIBE (command) ........................................   38
+       Session Flag (class of flag) ...............................   12
+       System Flag (type of flag) .................................   11
+       TEXT (part specifier) ......................................   56
+       TEXT <string> (search key) .................................   53
+       TO <string> (search key) ...................................   53
+       TRYCREATE (response code) ..................................   65
+       UID (command) ..............................................   60
+       UID (fetch item) ...........................................   58
+       UID (fetch result) .........................................   79
+       UID <sequence set> (search key) ............................   53
+       UIDNEXT (response code) ....................................   65
+       UIDNEXT (status item) ......................................   45
+       UIDVALIDITY (response code) ................................   65
+       UIDVALIDITY (status item) ..................................   45
+       UNANSWERED (search key) ....................................   53
+       UNDELETED (search key) .....................................   53
+       UNDRAFT (search key) .......................................   53
+       UNFLAGGED (search key) .....................................   53
+       UNKEYWORD <flag> (search key) ..............................   53
+       UNSEEN (response code) .....................................   65
+       UNSEEN (search key) ........................................   53
+       UNSEEN (status item) .......................................   45
+       UNSUBSCRIBE (command) ......................................   39
+       Unique Identifier (UID) (message attribute) ................    8
+       X<atom> (command) ..........................................   62
+       [RFC-2822] Size (message attribute) ........................   12
+       \Answered (system flag) ....................................   11
+       \Deleted (system flag) .....................................   11
+       \Draft (system flag) .......................................   11
+       \Flagged (system flag) .....................................   11
+       \Marked (mailbox name attribute) ...........................   69
+       \Noinferiors (mailbox name attribute) ......................   69
+       \Noselect (mailbox name attribute) .........................   69
+       \Recent (system flag) ......................................   11
+       \Seen (system flag) ........................................   11
+       \Unmarked (mailbox name attribute) .........................   69
+
+
+
+
+
+
+
+Crispin                     Standards Track                   [Page 106]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+Author's Address
+
+   Mark R. Crispin
+   Networks and Distributed Computing
+   University of Washington
+   4545 15th Avenue NE
+   Seattle, WA  98105-4527
+
+   Phone: (206) 543-5762
+
+   EMail: MRC@CAC.Washington.EDU
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                   [Page 107]
+
+RFC 3501                         IMAPv4                       March 2003
+
+
+Full Copyright Statement
+
+   Copyright (C) The Internet Society (2003).  All Rights Reserved.
+
+   This document and translations of it may be copied and furnished to
+   others, and derivative works that comment on or otherwise explain it
+   or assist in its implementation may be prepared, copied, published
+   and distributed, in whole or in part, without restriction of any
+   kind, provided that the above copyright notice and this paragraph are
+   included on all such copies and derivative works.  However, this
+   document itself may not be modified in any way, such as by removing
+   the copyright notice or references to the Internet Society or other
+   Internet organizations, except as needed for the purpose of
+   developing Internet standards in which case the procedures for
+   copyrights defined in the Internet Standards process must be
+   followed, or as required to translate it into languages other than
+   English.
+
+   The limited permissions granted above are perpetual and will not be
+   revoked by the Internet Society or its successors or assigns.  v This
+   document and the information contained herein is provided on an "AS
+   IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK
+   FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+   LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL
+   NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY
+   OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is currently provided by the
+   Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                   [Page 108]
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc3502.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,395 @@
+
+
+
+
+
+
+Network Working Group                                         M. Crispin
+Request for Comments: 3502                      University of Washington
+Category: Standards Track                                     March 2003
+
+
+    Internet Message Access Protocol (IMAP) - MULTIAPPEND Extension
+
+Status of this Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (2003).  All Rights Reserved.
+
+Abstract
+
+   This document describes the multiappending extension to the Internet
+   Message Access Protocol (IMAP) (RFC 3501).  This extension provides
+   substantial performance improvements for IMAP clients which upload
+   multiple messages at a time to a mailbox on the server.
+
+   A server which supports this extension indicates this with a
+   capability name of "MULTIAPPEND".
+
+Terminology
+
+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+   "SHOULD", "SHOULD NOT", "MAY", and "OPTIONAL" in this document are to
+   be interpreted as described in [KEYWORDS].
+
+Introduction
+
+   The MULTIAPPEND extension permits uploading of multiple messages with
+   a single command.  When used in conjunction with the [LITERAL+]
+   extension, the entire upload is accomplished in a single
+   command/response round trip.
+
+   A MULTIAPPEND APPEND operation is atomic; either all messages are
+   successfully appended, or no messages are appended.
+
+   In the base IMAP specification, each message must be appended in a
+   separate command, and there is no mechanism to "unappend" messages if
+   an error occurs while appending.  Also, some mail stores may require
+
+
+
+Crispin                     Standards Track                     [Page 1]
+
+RFC 3502                    IMAP MULTIAPPEND                  March 2003
+
+
+   an expensive "open/lock + sync/unlock/close" operation as part of
+   appending; this can be quite expensive if it must be done on a
+   per-message basis.
+
+   If the server supports both LITERAL+ and pipelining but not
+   MULTIAPPEND, it may be possible to get some of the performance
+   advantages of MULTIAPPEND by doing a pipelined "batch" append.
+   However, it will not work as well as MULTIAPPEND for the following
+   reasons:
+
+        1) Multiple APPEND commands, even as part of a pipelined batch,
+        are non-atomic by definition.  There is no way to revert the
+        mailbox to the state before the batch append in the event of an
+        error.
+
+        2) It may not be feasible for the server to coalesce pipelined
+        APPEND operations so as to avoid the "open/lock +
+        sync/unlock/close" overhead described above.  In any case, such
+        coalescing would be timing dependent and thus potentially
+        unreliable.  In particular, with traditional UNIX mailbox files,
+        it is assumed that a lock is held only for a single atomic
+        operation, and many applications disregard any lock that is
+        older than 5 minutes.
+
+        3) If an error occurs, depending upon the nature of the error,
+        it is possible for additional messages to be appended after the
+        error.  For example, the user wants to append 5 messages, but a
+        disk quota error occurs with the third message because of its
+        size.  However, the fourth and fifth messages have already been
+        sent in the pipeline, so the mailbox ends up with the first,
+        second, fourth, and fifth messages of the batch appended.
+
+6.3.11.  APPEND Command
+
+   Arguments:  mailbox name
+               one or more messages to upload, specified as:
+                  OPTIONAL flag parenthesized list
+                  OPTIONAL date/time string
+                  message literal
+
+   Data:       no specific responses for this command
+
+   Result:     OK - append completed
+               NO - append error: can't append to that mailbox, error
+                    in flags or date/time or message text,
+                    append cancelled
+               BAD - command unknown or arguments invalid
+
+
+
+
+Crispin                     Standards Track                     [Page 2]
+
+RFC 3502                    IMAP MULTIAPPEND                  March 2003
+
+
+      The APPEND command appends the literal arguments as new messages
+      to the end of the specified destination mailbox.  This argument
+      SHOULD be in the format of an [RFC-2822] message.  8-bit
+      characters are permitted in the message.  A server implementation
+      that is unable to preserve 8-bit data properly MUST be able to
+      reversibly convert 8-bit APPEND data to 7-bit using a [MIME-IMB]
+      content transfer encoding.
+
+            Note: There MAY be exceptions, e.g., draft messages, in
+            which required [RFC-2822] header lines are omitted in the
+            message literal argument to APPEND.  The full implications
+            of doing so MUST be understood and carefully weighed.
+
+      If a flag parenthesized list is specified, the flags SHOULD be set
+      in the resulting message; otherwise, the flag list of the
+      resulting message is set empty by default.
+
+      If a date-time is specified, the internal date SHOULD be set in
+      the resulting message; otherwise, the internal date of the
+      resulting message is set to the current date and time by default.
+
+      A zero-length message literal argument is an error, and MUST
+      return a NO.  This can be used to cancel the append.
+
+      If the append is unsuccessful for any reason (including being
+      cancelled), the mailbox MUST be restored to its state before the
+      APPEND attempt; no partial appending is permitted.  The server MAY
+      return an error before processing all the message arguments.
+
+      If the destination mailbox does not exist, a server MUST return an
+      error, and MUST NOT automatically create the mailbox.  Unless it
+      is certain that the destination mailbox can not be created, the
+      server MUST send the response code "[TRYCREATE]" as the prefix of
+      the text of the tagged NO response.  This gives a hint to the
+      client that it can attempt a CREATE command and retry the APPEND
+      if the CREATE is successful.
+
+      If the mailbox is currently selected, the normal new message
+      actions SHOULD occur.  Specifically, the server SHOULD notify the
+      client immediately via an untagged EXISTS response.  If the server
+      does not do so, the client MAY issue a NOOP command (or failing
+      that, a CHECK command) after one or more APPEND commands.
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                     [Page 3]
+
+RFC 3502                    IMAP MULTIAPPEND                  March 2003
+
+
+   Example: C: A003 APPEND saved-messages (\Seen) {329}
+            S: + Ready for literal data
+            C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
+            C: From: Fred Foobar <foobar@Blurdybloop.example.COM>
+            C: Subject: afternoon meeting
+            C: To: mooch@owatagu.example.net
+            C: Message-Id: <B27397-0100000@Blurdybloop.example.COM>
+            C: MIME-Version: 1.0
+            C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
+            C:
+            C: Hello Joe, do you think we can meet at 3:30 tomorrow?
+            C:  (\Seen) " 7-Feb-1994 22:43:04 -0800" {295}
+            S: + Ready for literal data
+            C: Date: Mon, 7 Feb 1994 22:43:04 -0800 (PST)
+            C: From: Joe Mooch <mooch@OWaTaGu.example.net>
+            C: Subject: Re: afternoon meeting
+            C: To: foobar@blurdybloop.example.com
+            C: Message-Id: <a0434793874930@OWaTaGu.example.net>
+            C: MIME-Version: 1.0
+            C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
+            C:
+            C: 3:30 is fine with me.
+            C:
+            S: A003 OK APPEND completed
+            C: A004 APPEND bogusname (\Flagged) {1023}
+            S: A004 NO [TRYCREATE] No such mailbox as bogusname
+            C: A005 APPEND test (\Flagged) {99}
+            S: + Ready for literal data
+            C: Date: Mon, 7 Feb 2000 22:43:04 -0800 (PST)
+            C: From: Fred Foobar <fred@example.com>
+            C: Subject: hmm...
+            C:  {35403}
+            S: A005 NO APPEND failed: Disk quota exceeded
+
+        Note: The APPEND command is not used for message delivery,
+        because it does not provide a mechanism to transfer [SMTP]
+        envelope information.
+
+Modification to IMAP4rev1 Base Protocol Formal Syntax
+
+   The following syntax specification uses the Augmented Backus-Naur
+   Form (ABNF) notation as specified in [ABNF].
+
+   append          = "APPEND" SP mailbox 1*append-message
+
+   append-message  = [SP flag-list] [SP date-time] SP literal
+
+
+
+
+
+Crispin                     Standards Track                     [Page 4]
+
+RFC 3502                    IMAP MULTIAPPEND                  March 2003
+
+
+MULTIAPPEND Interaction with UIDPLUS Extension
+
+   Servers which support both MULTIAPPEND and [UIDPLUS] will have the
+   "resp-code-apnd" rule modified as follows:
+
+   resp-code-apnd  = "APPENDUID" SP nz-number SP set
+
+   That is, the APPENDUID response code returns as many UIDs as there
+   were messages appended in the multiple append.  The UIDs returned
+   should be in the order the articles where appended.  The message set
+   may not contain extraneous UIDs or the symbol "*".
+
+Security Considerations
+
+   The MULTIAPPEND extension does not raise any security considerations
+   that are not present in the base [IMAP] protocol, and these issues
+   are discussed in [IMAP].  Nevertheless, it is important to remember
+   that IMAP4rev1 protocol transactions, including electronic mail data,
+   are sent in the clear over the network unless protection from
+   snooping is negotiated, either by the use of STARTTLS, privacy
+   protection is negotiated in the AUTHENTICATE command, or some other
+   protection mechanism is in effect.
+
+Normative References
+
+   [ABNF]     Crocker, D. and P. Overell, "Augmented BNF for Syntax
+              Specifications: ABNF", RFC 2234, November 1997.
+
+   [IMAP]     Crispin, M., "Internet Message Access Protocol - Version
+              4rev1", RFC 3501, March 2003.
+
+   [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate
+              Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+   [MIME-IMB] Freed, N. and N. Borenstein, "MIME (Multipurpose Internet
+              Mail Extensions) Part One: Format of Internet Message
+              Bodies", RFC 2045, November 1996.
+
+   [RFC-2822] Resnick, P., "Internet Message Format", RFC 2822, April
+              2001.
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                     [Page 5]
+
+RFC 3502                    IMAP MULTIAPPEND                  March 2003
+
+
+Informative References
+
+   [LITERAL+] Myers, J., "IMAP4 non-synchronizing literals", RFC 2088,
+              January 1997.
+
+   [UIDPLUS]  Myers, J., "IMAP4 UIDPLUS extension", RFC 2359, June 1988.
+
+   [SMTP]     Klensin, J., Editor, "Simple Mail Transfer Protocol", RFC
+              2821, April 2001.
+
+Author's Address
+
+   Mark R. Crispin
+   Networks and Distributed Computing
+   University of Washington
+   4545 15th Avenue NE
+   Seattle, WA  98105-4527
+
+   Phone: (206) 543-5762
+   EMail: MRC@CAC.Washington.EDU
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                     [Page 6]
+
+RFC 3502                    IMAP MULTIAPPEND                  March 2003
+
+
+Full Copyright Statement
+
+   Copyright (C) The Internet Society (2003).  All Rights Reserved.
+
+   This document and translations of it may be copied and furnished to
+   others, and derivative works that comment on or otherwise explain it
+   or assist in its implementation may be prepared, copied, published
+   and distributed, in whole or in part, without restriction of any
+   kind, provided that the above copyright notice and this paragraph are
+   included on all such copies and derivative works.  However, this
+   document itself may not be modified in any way, such as by removing
+   the copyright notice or references to the Internet Society or other
+   Internet organizations, except as needed for the purpose of
+   developing Internet standards in which case the procedures for
+   copyrights defined in the Internet Standards process must be
+   followed, or as required to translate it into languages other than
+   English.
+
+   The limited permissions granted above are perpetual and will not be
+   revoked by the Internet Society or its successors or assigns.
+
+   This document and the information contained herein is provided on an
+   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is currently provided by the
+   Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                     [Page 7]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc3503.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,507 @@
+
+
+
+
+
+
+Network Working Group                                        A. Melnikov
+Request for Comments: 3503                 ACI Worldwide/MessagingDirect
+Category: Standards Track                                     March 2003
+
+
+          Message Disposition Notification (MDN) profile for
+                Internet Message Access Protocol (IMAP)
+
+Status of this Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (2003).  All Rights Reserved.
+
+Abstract
+
+   The Message Disposition Notification (MDN) facility defined in RFC
+   2298 provides a means by which a message can request that message
+   processing by the recipient be acknowledged as well as a format to be
+   used for such acknowledgements.  However, it doesn't describe how
+   multiple Mail User Agents (MUAs) should handle the generation of MDNs
+   in an Internet Message Access Protocol (IMAP4) environment.
+
+   This document describes how to handle MDNs in such an environment and
+   provides guidelines for implementers of IMAP4 that want to add MDN
+   support to their products.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov                    Standards Track                     [Page 1]
+
+RFC 3503                  MDN profile for IMAP                March 2003
+
+
+Table of Contents
+
+   1.  Conventions Used in this Document.............................  2
+   2.  Introduction and Overview.....................................  2
+   3.  Client behavior...............................................  3
+       3.1. Client behavior when receiving a message.................  5
+       3.2. Client behavior when copying a message...................  5
+       3.3. Client behavior when sending a message...................  5
+       3.4. Client behavior when saving a temporary message..........  5
+   4.  Server behavior...............................................  5
+       4.1. Server that supports arbitrary keywords..................  5
+       4.2. Server that supports only $MDNSent keyword...............  5
+       4.3. Interaction with IMAP ACL extension......................  6
+   5.  Examples......................................................  6
+   6.  Security Considerations.......................................  7
+   7.  Formal Syntax.................................................  7
+   8.  Acknowledgments...............................................  7
+   9.  Normative References..........................................  8
+   10. Author's Address..............................................  8
+   11. Full Copyright Statement......................................  9
+
+1.  Conventions Used in this Document
+
+   "C:" and "S:" in examples show lines sent by the client and server
+   respectively.
+
+   The keywords "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY" in
+   this document when typed in uppercase are to be interpreted as
+   defined in "Key words for use in RFCs to Indicate Requirement Levels"
+   [KEYWORDS].
+
+2.  Introduction and Overview
+
+   This memo defines an additional [IMAP4] mailbox keyword that allows
+   multiple Mail User Agents (MUAs) to know if a requested receipt
+   notification was sent.
+
+   Message Disposition Notification [MDN] does not require any special
+   support of IMAP in the case where a user has access to the mailstore
+   from only one computer and is using a single MUA.  In this case, the
+   MUA behaves as described in [MDN], i.e., the MUA performs automatic
+   processing and generates corresponding MDNs, it performs requested
+   action and, with the user's permission, sends appropriate MDNs.  The
+   MUA will not send MDN twice because the MUA keeps track of sent
+   notifications in a local configuration.  However, that does not work
+   when IMAP is used to access the same mailstore from different
+   locations or is using different MUAs.
+
+
+
+
+Melnikov                    Standards Track                     [Page 2]
+
+RFC 3503                  MDN profile for IMAP                March 2003
+
+
+   This document defines a new special purpose mailbox keyword $MDNSent
+   that must be used by MUAs.  It does not define any new command or
+   response for IMAP, but describes a technique that MUAs should use to
+   achieve interoperability.
+
+   When a client opens a mailbox for the first time, it verifies that
+   the server is capable of storing the $MDNSent keyword by examining
+   the PERMANENTFLAGS response code.  In order to support MDN in IMAP, a
+   server MUST support either the $MDNSent keyword, or arbitrary message
+   keywords.
+
+3.  Client behavior
+
+   The use of IMAP requires few additional steps in mail processing on
+   the client side.  The following timeline modifies the timeline found
+   in Section 4 of [MDN].
+
+   -- User composes message.
+
+   -- User tells MUA to send message.
+
+   -- MUA passes message to MSA (original recipient information passed
+      along).  MUA [optionally] saves message to a folder for sent mail
+      with $MDNSent flag set.
+
+   -- MSA sends message to MTA.
+
+   -- Final MTA receives message.
+
+   -- Final MTA delivers message to MUA (possibly generating DSN).
+
+   -- MUA logs into IMAP server, opens mailbox, verifies if mailbox can
+      store $MDNSent keyword by examining PERMANENTFLAGS response.
+
+   -- MUA performs automatic processing and generates corresponding MDNs
+      ("dispatched", "processed", "deleted", "denied" or "failed"
+      disposition type with "automatic-action" and "MDN-sent-
+      automatically" disposition modes) for messages that do not have
+      $MDNSent keyword, or \Draft flag set. (*)
+
+   -- MUA sets the $MDNSent keyword for every message that required an
+      automatic MDN to be sent, whether or not the MDN was sent.
+
+   -- MUA displays a list of messages to user.
+
+   -- User selects a message and requests that some action be performed
+      on it.
+
+
+
+
+Melnikov                    Standards Track                     [Page 3]
+
+RFC 3503                  MDN profile for IMAP                March 2003
+
+
+   -- MUA performs requested action and, with user's permission, sends
+      appropriate MDN ("displayed", "dispatched", "processed",
+      "deleted", "denied" or "failed" disposition type with "manual-
+      action" and "MDN-sent-manually" or "MDN-sent-automatically"
+      disposition mode).  If the generated MDN is saved to a mailbox
+      with the APPEND command, the client MUST specify the $MDNSent
+      keyword in the APPEND.
+
+   -- MUA sets the $MDNSent keyword for all messages for which the user
+      confirmed the dispatching of disposition (or was explicitly
+      prohibited to do so).
+
+   -- User possibly performs other actions on message, but no further
+      MDNs are generated.
+
+   (*) Note: MUA MUST NOT use \Recent flag as an indicator that it
+       should send MDN, because according to [IMAP4], "If multiple
+       connections have the same mailbox selected simultaneously, it is
+       undefined which of these connections will see newly-arrived
+       messages with \Recent set and which will see it without \Recent
+       set".  Thus, using \Recent as an indicator will cause
+       unpredictable client behavior with different IMAP4 servers.
+       However, the client MAY use \Seen flag as one of the indicators
+       that MDN must not be sent.  The client MUST NOT use any other
+       standard flags, like \Draft or \Answered, to indicate that MDN
+       was previously sent, because they have different well known
+       meaning.  In any case, in the presence of the $MDNSent keyword,
+       the client MUST ignore all other flags or keywords for the
+       purpose of generating an MDN and MUST NOT send the MDN.
+
+   When the client opens a mailbox for the first time, it must verify
+   that the server supports the $MDNSent keyword, or arbitrary message
+   keywords by examining PERMANENTFLAGS response code.
+
+   The client MUST NOT try to set the $MDNSent keyword if the server is
+   incapable of storing it permanently.
+
+   The client MUST be prepared to receive NO from the server as the
+   result of STORE $MDNSent when the server advertises the support of
+   storing arbitrary keywords, because the server may limit the number
+   of message keywords it can store in a particular mailbox.  A client
+   SHOULD NOT send MDN if it fails to store the $MDNSent keyword.
+
+   Once the $MDNSent keyword is set, it MUST NOT be unset by a client.
+   The client MAY set the $MDNSent keyword when a user denies sending
+   the notification.  This prohibits all other MUAs from sending MDN for
+   this message.
+
+
+
+
+Melnikov                    Standards Track                     [Page 4]
+
+RFC 3503                  MDN profile for IMAP                March 2003
+
+
+3.1.  Client behavior when receiving a message
+
+   The client MUST NOT send MDN if a message has the $MDNSent keyword
+   set.  It also MUST NOT send MDN if a message has \Draft flag, because
+   some clients use this flag to mark a message as incomplete.
+
+   See the timeline in section 3 for details on client behavior when
+   receiving a message.
+
+3.2.  Client behavior when copying a message
+
+   The client SHOULD verify that $MDNSent is preserved on a COPY
+   operation.  Furthermore, when a message is copied between servers
+   with the APPEND command, the client MUST set the $MDNSent keyword
+   correctly.
+
+3.3.  Client behavior when sending a message
+
+   When saving a sent message to any folder, the client MUST set the
+   $MDNSent keyword to prevent another client from sending MDN for the
+   message.
+
+3.4.  Client behavior when saving a temporary message
+
+   When saving an unfinished message to any folder client MUST set
+   $MDNSent keyword to prevent another client from sending MDN for the
+   message.
+
+4.  Server behavior
+
+   Server implementors that want to follow this specification must
+   insure that their server complies with either section 4.1 or section
+   4.2.  If the server also supports the IMAP [ACL] extension, it MUST
+   also comply with the section 4.3.
+
+4.1.  Server that supports arbitrary keywords
+
+   No changes are required from the server to make it compatible with
+   the extension described in this document if it supports arbitrary
+   keywords.
+
+4.2.  Server that supports only $MDNSent keyword
+
+   Servers that support only the $MDNSent keyword MUST preserve it on
+   the COPY operation.  It is also expected that a server that supports
+   SEARCH <flag> will also support the SEARCH KEYWORD $MDNSent.
+
+
+
+
+
+Melnikov                    Standards Track                     [Page 5]
+
+RFC 3503                  MDN profile for IMAP                March 2003
+
+
+4.3.  Interaction with IMAP ACL extension
+
+   Any server that conforms to either 4.1 or 4.2 and also supports the
+   IMAP [ACL] extension, SHOULD preserve the $MDNSent keyword on COPY
+   even if the client does not have 'w' right.  This will prevent the
+   generation of a duplicated MDN for the same message.  Note that the
+   server MUST still check if the client has rights to perform the COPY
+   operation on a message according to [ACL].
+
+5.  Examples
+
+   1) MUA opens mailbox for the first time.
+
+   a) The server supports storing of arbitrary keywords
+
+   C: a100 select INBOX
+   S: * FLAGS (\Flagged \Draft \Deleted \Seen)
+   S: * OK [PERMANENTFLAGS (\Flagged \Draft \Deleted \Seen \*)]
+   S: * 5 EXISTS
+   S: * 3 RECENT
+   S: * OK [UIDVALIDITY 894294713]
+   S: a100 OK [READ-WRITE] Completed
+
+   b) The server supports storing of the $MDNSent keyword
+
+   C: a100 select INBOX
+   S: * FLAGS (\Flagged \Draft \Deleted \Seen $MDNSent)
+   S: * OK [PERMANENTFLAGS (\Flagged \Draft \Deleted \Seen $MDNSent)]
+   S: * 5 EXISTS
+   S: * 3 RECENT
+   S: * OK [UIDVALIDITY 894294713]
+   S: a100 OK [READ-WRITE] Completed
+
+   2) The MUA successfully sets the $MDNSent keyword
+
+   C: a200 STORE 4 +FLAGS ($MDNSent)
+   S: * 4 FETCH (FLAGS (\Flagged \Seen $MDNSent))
+   S: * FLAGS ($MDNSent \Flagged \Deleted \Draft \Seen)
+   S: * OK [PERMANENTFLAGS ($MDNSent \Flagged \Deleted \Draft \Seen \*)]
+   S: a200 OK STORE completed
+
+   3) The server refuses to store the $MDNSent keyword
+
+   C: a200 STORE 4 +FLAGS ($MDNSent)
+   S: a200 NO STORE failed : no space left to store $MDNSent keyword
+
+
+
+
+
+
+Melnikov                    Standards Track                     [Page 6]
+
+RFC 3503                  MDN profile for IMAP                March 2003
+
+
+   4) All clients and servers MUST treat the $MDNSent keyword as case
+   insensitive in all operations, as stated in [IMAP].
+
+   C: a300 FETCH 1:* FLAGS
+   S: * 1 FETCH (FLAGS (\Seen))
+   S: * 2 FETCH (FLAGS (\Answered \Seen $MdnSENt))
+   S: * 3 FETCH (FLAGS ())
+   S: * 4 FETCH (FLAGS (\Flagged \Seen $MdnSENT))
+   S: * 5 FETCH (FLAGS ($MDNSent))
+   S: * 6 FETCH (FLAGS (\Recent))
+   S: a300 OK FETCH completed
+   C: a400 SEARCH KEYWORDS $mdnsent
+   S: * SEARCH 2 4 5
+   S: a400 OK SEARCH completed
+
+6.  Security Considerations
+
+   There are no known security issues with this extension, not found in
+   [MDN] and/or [IMAP4].
+
+   Section 4.3 changes ACL checking requirements on an IMAP server that
+   implements IMAP [ACL] extension.
+
+7.  Formal Syntax
+
+   The following syntax specification uses the augmented Backus-Naur
+   Form (BNF) notation as specified in [RFC-822], as modified by
+   [IMAP4].  Non-terminals referenced, but not defined below, are as
+   defined by [IMAP4].
+
+   Except as noted otherwise, all alphabetic characters are case-
+   insensitive.  The use of upper or lower case characters to define
+   token strings is for editorial clarity only.  Implementations MUST
+   accept these strings in a case-insensitive fashion.
+
+   flag_keyword    ::= "$MDNSent" / other_keywords
+
+   other_keywords  ::= atom
+
+8.  Acknowledgments
+
+   This document is the product of discussions that took place on the
+   IMAP mailing list.  Special gratitude to Cyrus Daboo and Randall
+   Gellens for reviewing the document.
+
+   Thank you to my father who as he has helped to make me what I am.  I
+   miss you terribly.
+
+
+
+
+Melnikov                    Standards Track                     [Page 7]
+
+RFC 3503                  MDN profile for IMAP                March 2003
+
+
+9.  Normative References
+
+   [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate
+              Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+   [MDN]      Fajman, R., "An Extensible Message Format for Message
+              Disposition Notifications", RFC 2298, March 1998.
+
+   [IMAP4]    Crispin, M., "Internet Message Access Protocol - Version
+              4rev1", RFC 3501, March 2003.
+
+   [ACL]      Myers, J., "IMAP4 ACL extension", RFC 2086, January 1997.
+
+10.  Author's Address
+
+   Alexey Melnikov
+   ACI Worldwide/MessagingDirect
+   59 Clarendon Road
+   Watford, Hertfordshire
+   United Kingdom, WD17 1FQ
+
+   Phone: +44 1923 81 2877
+   EMail: mel@messagingdirect.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov                    Standards Track                     [Page 8]
+
+RFC 3503                  MDN profile for IMAP                March 2003
+
+
+11.  Full Copyright Statement
+
+   Copyright (C) The Internet Society (2003).  All Rights Reserved.
+
+   This document and translations of it may be copied and furnished to
+   others, and derivative works that comment on or otherwise explain it
+   or assist in its implementation may be prepared, copied, published
+   and distributed, in whole or in part, without restriction of any
+   kind, provided that the above copyright notice and this paragraph are
+   included on all such copies and derivative works.  However, this
+   document itself may not be modified in any way, such as by removing
+   the copyright notice or references to the Internet Society or other
+   Internet organizations, except as needed for the purpose of
+   developing Internet standards in which case the procedures for
+   copyrights defined in the Internet Standards process must be
+   followed, or as required to translate it into languages other than
+   English.
+
+   The limited permissions granted above are perpetual and will not be
+   revoked by the Internet Society or its successors or assigns.
+
+   This document and the information contained herein is provided on an
+   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is currently provided by the
+   Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov                    Standards Track                     [Page 9]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc3516.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,451 @@
+
+
+
+
+
+
+Network Working Group                                       L. Nerenberg
+Request for Comments: 3516                               Orthanc Systems
+Category: Standards Track                                     April 2003
+
+
+                     IMAP4 Binary Content Extension
+
+Status of this Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (2003).  All Rights Reserved.
+
+Abstract
+
+   This memo defines the Binary extension to the Internet Message Access
+   Protocol (IMAP4).  It provides a mechanism for IMAP4 clients and
+   servers to exchange message body data without using a MIME content-
+   transfer-encoding.
+
+1.   Conventions Used in this Document
+
+   The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY"
+   in this document are to be interpreted as described in [KEYWORD].
+
+   The abbreviation "CTE" means content-transfer-encoding.
+
+2.   Introduction
+
+   The MIME extensions to Internet messaging allow for the transmission
+   of non-textual (binary) message content [MIME-IMB].  Since the
+   traditional transports for messaging are not always capable of
+   passing binary data transparently, MIME provides encoding schemes
+   that allow binary content to be transmitted over transports that are
+   not otherwise able to do so.
+
+   The overhead of MIME-encoding this content can be considerable in
+   some contexts (e.g., slow radio links, streaming multimedia).
+   Reducing the overhead associated with CTE schemes such as base64
+
+
+
+
+
+
+Nerenberg                   Standards Track                     [Page 1]
+
+RFC 3516             IMAP4 Binary Content Extension           April 2003
+
+
+   can give a noticeable reduction in resource consumption.  The Binary
+   extension lets the server perform CTE decoding prior to transmitting
+   message data to the client.
+
+3.  Content-Transfer-Encoding Considerations
+
+   Every IMAP4 body section has a MIME content-transfer-encoding.
+   (Those without an explicit Content-Transfer-Encoding header are
+   implicitly labeled as "7bit" content.)  In the terminology of [MIME-
+   IMB], the CTE specifies both a decoding algorithm and the domain of
+   the decoded data.  In this memo, "decoding" refers to the CTE
+   decoding step described in [MIME-IMB].
+
+   Certain CTEs use an identity encoding transformation.  For these CTEs
+   there is no decoding required, however the domain of the underlying
+   data may not be expressible in the IMAP4 protocol (e.g., MIME
+   "binary" content containing NUL octets).  To accommodate these cases
+   the Binary extension introduces a new type of literal protocol
+   element that is fully eight bit transparent.
+
+   Thus, server  processing of the FETCH BINARY command involves two
+   logical steps:
+
+   1)  perform any CTE-related decoding
+
+   2)  determine the domain of the decoded data
+
+   Step 2 is necessary to determine which protocol element should be
+   used to transmit the decoded data.  (See FETCH Response Extensions
+   for further details.)
+
+4.  Framework for the IMAP4 Binary Extension
+
+   This memo defines the following extensions to [IMAP4rev1].
+
+4.1.  CAPABILITY Identification
+
+   IMAP4 servers that support this extension MUST include "BINARY" in
+   the response list to the CAPABILITY command.
+
+4.2.  FETCH Command Extensions
+
+   This extension defines three new FETCH command data items.
+
+      BINARY<section-binary>[<partial>]
+
+         Requests that the specified section be transmitted after
+         performing CTE-related decoding.
+
+
+
+Nerenberg                   Standards Track                     [Page 2]
+
+RFC 3516             IMAP4 Binary Content Extension           April 2003
+
+
+         The <partial> argument, if present, requests that a subset of
+         the data be returned.  The semantics of a partial FETCH BINARY
+         command are the same as for a partial FETCH BODY command, with
+         the exception that the <partial> arguments refer to the DECODED
+         section data.
+
+      BINARY.PEEK<section-binary>[<partial>]
+
+         An alternate form of FETCH BINARY that does not implicitly set
+         the \Seen flag.
+
+      BINARY.SIZE<section-binary>
+
+         Requests the decoded size of the section (i.e., the size to
+         expect in response to the corresponding FETCH BINARY request).
+
+         Note: client authors are cautioned that this might be an
+         expensive operation for some server implementations.
+         Needlessly issuing this request could result in degraded
+         performance due to servers having to calculate the value every
+         time the request is issued.
+
+4.3.  FETCH Response Extensions
+
+   This extension defines two new FETCH response data items.
+
+      BINARY<section-binary>[<<number>>]
+
+         An <nstring> or <literal8> expressing the content of the
+         specified section after removing any CTE-related encoding.  If
+         <number> is present it refers to the offset within the DECODED
+         section data.
+
+         If the domain of the decoded data is "8bit" and the data does
+         not contain the NUL octet, the server SHOULD return the data in
+         a <string> instead of a <literal8>; this allows the client to
+         determine if the "8bit" data contains the NUL octet without
+         having to explicitly scan the data stream for for NULs.
+
+         If the server does not know how to decode the section's CTE, it
+         MUST fail the request and issue a "NO" response that contains
+         the "UNKNOWN-CTE" extended response code.
+
+
+
+
+
+
+
+
+
+Nerenberg                   Standards Track                     [Page 3]
+
+RFC 3516             IMAP4 Binary Content Extension           April 2003
+
+
+      BINARY.SIZE<section-binary>
+
+         The size of the section after removing any CTE-related
+         encoding.  The value returned MUST match the size of the
+         <nstring> or <literal8> that will be returned by the
+         corresponding FETCH BINARY request.
+
+         If the server does not know how to decode the section's CTE, it
+         MUST fail the request and issue a "NO" response that contains
+         the "UNKNOWN-CTE" extended response code.
+
+4.4.  APPEND Command Extensions
+
+   The APPEND command is extended to allow the client to append data
+   containing NULs by using the <literal8> syntax.  The server MAY
+   modify the CTE of the appended data, however any such transformation
+   MUST NOT result in a loss of data.
+
+   If the destination mailbox does not support the storage of binary
+   content, the server MUST fail the request and issue a "NO" response
+   that contains the "UNKNOWN-CTE" extended response code.
+
+5.  MIME Encoded Headers
+
+   [MIME-MHE] defines an encoding that allows for non-US-ASCII text in
+   message headers.  This encoding is not the same as the content-
+   transfer-encoding applied to message bodies, and the decoding
+   transformations described in this memo do not apply to [MIME-MHE]
+   encoded header text.  A server MUST NOT perform any conversion of
+   [MIME-MHE] encoded header text in response to any binary FETCH or
+   APPEND request.
+
+6.  Implementation Considerations
+
+   Messaging clients and servers have been notoriously lax in their
+   adherence to the Internet CRLF convention for terminating lines of
+   textual data in Internet protocols.  When sending data using the
+   Binary extension, servers MUST ensure that textual line-oriented
+   sections are always transmitted using the IMAP4 CRLF line termination
+   syntax, regardless of the underlying storage representation of the
+   data on the server.
+
+   A server may choose to store message body binary content in a non-
+   encoded format.  Regardless of the internal storage representation
+   used, the server MUST issue BODYSTRUCTURE responses that describe the
+   message as though the binary-encoded sections are encoded in a CTE
+
+
+
+
+
+Nerenberg                   Standards Track                     [Page 4]
+
+RFC 3516             IMAP4 Binary Content Extension           April 2003
+
+
+   acceptable to the IMAP4 base specification.  Furthermore, the results
+   of a FETCH BODY MUST return the message body content in the format
+   described by the corresponding FETCH BODYSTRUCTURE response.
+
+   While the server is allowed to modify the CTE of APPENDed <literal8>
+   data, this should only be done when it is absolutely necessary.
+   Gratuitous encoding changes will render useless most cryptographic
+   operations that have been performed on the message.
+
+   This extension provides an optimization that is useful in certain
+   specific situations.  It does not absolve clients from providing
+   basic functionality (content transfer decoding) that should be
+   available in all messaging clients.  Clients supporting this
+   extension SHOULD be prepared to perform their own CTE decoding
+   operations.
+
+7.  Formal Protocol Syntax
+
+   The following syntax specification uses the augmented Backus-Naur
+   Form (ABNF) notation as used in [ABNF], and incorporates by reference
+   the Core Rules defined in that document.
+
+   This syntax augments the grammar specified in [IMAP4rev1].
+
+   append         =/  "APPEND" SP mailbox [SP flag-list]
+                      [SP date-time] SP literal8
+
+   fetch-att      =/  "BINARY" [".PEEK"] section-binary [partial]
+                      / "BINARY.SIZE" section-binary
+
+   literal8       =   "~{" number "}" CRLF *OCTET
+                      ; <number> represents the number of OCTETs
+                      ; in the response string.
+
+   msg-att-static =/  "BINARY" section-binary SP (nstring / literal8)
+                      / "BINARY.SIZE" section-binary SP number
+
+   partial        =   "<" number "." nz-number ">"
+
+   resp-text-code =/  "UNKNOWN-CTE"
+
+   section-binary =   "[" [section-part] "]"
+
+
+
+
+
+
+
+
+
+Nerenberg                   Standards Track                     [Page 5]
+
+RFC 3516             IMAP4 Binary Content Extension           April 2003
+
+
+8.  Normative References
+
+   [ABNF]      Crocker, D., Editor, and P. Overell, "Augmented BNF for
+               Syntax Specifications: ABNF", RFC 2234, November 1997.
+
+   [IMAP4rev1] Crispin, M., "Internet Message Access Protocol Version
+               4rev1", RFC 3501, March 2003.
+
+   [KEYWORD]   Bradner, S., "Key words for use in RFCs to Indicate
+               Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+   [MIME-IMB]  Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+               Extensions (MIME) Part One: Format of Internet Message
+               Bodies", RFC 2045, November 1996.
+
+   [MIME-MHE]  Moore, K., "MIME (Multipurpose Internet Mail Extensions)
+               Part Three: Message Header Extensions for Non-ASCII
+               Text", RFC 2047, November 1996.
+
+9.  Security Considerations
+
+   There are no known additional security issues with this extension
+   beyond those described in the base protocol described in [IMAP4rev1].
+
+10.  Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   intellectual property or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; neither does it represent that it
+   has made any effort to identify any such rights.  Information on the
+   IETF's procedures with respect to rights in standards-track and
+   standards-related documentation can be found in BCP-11.  Copies of
+   claims of rights made available for publication and any assurances of
+   licenses to be made available, or the result of an attempt made to
+   obtain a general license or permission for the use of such
+   proprietary rights by implementors or users of this specification can
+   be obtained from the IETF Secretariat.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights which may cover technology that may be required to practice
+   this standard.  Please address the information to the IETF Executive
+   Director.
+
+
+
+
+
+
+Nerenberg                   Standards Track                     [Page 6]
+
+RFC 3516             IMAP4 Binary Content Extension           April 2003
+
+
+11.  Author's Address
+
+   Lyndon Nerenberg
+   Orthanc Systems
+   1606 - 10770 Winterburn Road
+   Edmonton, Alberta
+   Canada  T5S 1T6
+
+   EMail: lyndon@orthanc.ab.ca
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Nerenberg                   Standards Track                     [Page 7]
+
+RFC 3516             IMAP4 Binary Content Extension           April 2003
+
+
+12.  Full Copyright Statement
+
+   Copyright (C) The Internet Society (2003).  All Rights Reserved.
+
+   This document and translations of it may be copied and furnished to
+   others, and derivative works that comment on or otherwise explain it
+   or assist in its implementation may be prepared, copied, published
+   and distributed, in whole or in part, without restriction of any
+   kind, provided that the above copyright notice and this paragraph are
+   included on all such copies and derivative works.  However, this
+   document itself may not be modified in any way, such as by removing
+   the copyright notice or references to the Internet Society or other
+   Internet organizations, except as needed for the purpose of
+   developing Internet standards in which case the procedures for
+   copyrights defined in the Internet Standards process must be
+   followed, or as required to translate it into languages other than
+   English.
+
+   The limited permissions granted above are perpetual and will not be
+   revoked by the Internet Society or its successors or assigns.
+
+   This document and the information contained herein is provided on an
+   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is currently provided by the
+   Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Nerenberg                   Standards Track                     [Page 8]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc3656.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1067 @@
+
+
+
+
+
+
+Network Working Group                                      R. Siemborski
+Request for Comments: 3656                    Carnegie Mellon University
+Category: Experimental                                     December 2003
+
+
+                     The Mailbox Update (MUPDATE)
+                 Distributed Mailbox Database Protocol
+
+Status of this Memo
+
+   This memo defines an Experimental Protocol for the Internet
+   community.  It does not specify an Internet standard of any kind.
+   Discussion and suggestions for improvement are requested.
+   Distribution of this memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (2003).  All Rights Reserved.
+
+Abstract
+
+   As the demand for high-performance mail delivery agents increases, it
+   becomes apparent that single-machine solutions are inadequate to the
+   task, both because of capacity limits and that the failure of the
+   single machine means a loss of mail delivery for all users.  It is
+   preferable to allow many machines to share the responsibility of mail
+   delivery.
+
+   The Mailbox Update (MUPDATE) protocol allows a group of Internet
+   Message Access Protocol (IMAP) or Post Office Protocol - Version 3
+   (POP3) servers to function with a unified mailbox namespace.  This
+   document is intended to serve as a reference guide to that protocol.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Siemborski                    Experimental                      [Page 1]
+
+RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
+
+
+Table of Contents
+
+   1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   3
+   2.  Protocol Overview . . . . . . . . . . . . . . . . . . . . . .   3
+       2.1.  Atoms . . . . . . . . . . . . . . . . . . . . . . . . .   4
+       2.2.  Strings . . . . . . . . . . . . . . . . . . . . . . . .   4
+   3.  Server Responses  . . . . . . . . . . . . . . . . . . . . . .   4
+       3.1.  Response: OK  . . . . . . . . . . . . . . . . . . . . .   5
+       3.2.  Response: NO  . . . . . . . . . . . . . . . . . . . . .   5
+       3.3.  Response: BAD . . . . . . . . . . . . . . . . . . . . .   5
+       3.4.  Response: BYE . . . . . . . . . . . . . . . . . . . . .   6
+       3.5.  Response: RESERVE . . . . . . . . . . . . . . . . . . .   6
+       3.6.  Response: MAILBOX . . . . . . . . . . . . . . . . . . .   6
+       3.7.  Response: DELETE  . . . . . . . . . . . . . . . . . . .   7
+       3.8.  Server Capability Response. . . . . . . . . . . . . . .   7
+   4.  Client Commands . . . . . . . . . . . . . . . . . . . . . . .   8
+       4.1.  Command: ACTIVATE . . . . . . . . . . . . . . . . . . .   8
+       4.2.  Command: AUTHENTICATE . . . . . . . . . . . . . . . . .   8
+       4.3.  Command: DEACTIVATE . . . . . . . . . . . . . . . . . .   9
+       4.4.  Command: DELETE . . . . . . . . . . . . . . . . . . . .   9
+       4.5.  Command: FIND . . . . . . . . . . . . . . . . . . . . .   9
+       4.6.  Command: LIST . . . . . . . . . . . . . . . . . . . . .  10
+       4.7.  Command: LOGOUT . . . . . . . . . . . . . . . . . . . .  10
+       4.8.  Command: NOOP . . . . . . . . . . . . . . . . . . . . .  10
+       4.9.  Command: RESERVE. . . . . . . . . . . . . . . . . . . .  10
+       4.10. Command: STARTTLS . . . . . . . . . . . . . . . . . . .  11
+       4.11. Command: UPDATE . . . . . . . . . . . . . . . . . . . .  12
+   5.  MUPDATE Formal Syntax . . . . . . . . . . . . . . . . . . . .  12
+   6.  MUPDATE URL Scheme. . . . . . . . . . . . . . . . . . . . . .  14
+       6.1.  MUPDATE URL Scheme Registration Form. . . . . . . . . .  14
+   7.  Security Considerations . . . . . . . . . . . . . . . . . . .  15
+   8.  IANA Considerations . . . . . . . . . . . . . . . . . . . . .  16
+   9.  Intellectual Property Rights. . . . . . . . . . . . . . . . .  16
+   10. References. . . . . . . . . . . . . . . . . . . . . . . . . .  17
+       10.1. Normative References. . . . . . . . . . . . . . . . . .  17
+       10.2. Informative References. . . . . . . . . . . . . . . . .  17
+   11. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . .  18
+   12. Author's Address. . . . . . . . . . . . . . . . . . . . . . .  18
+   13. Full Copyright Statement. . . . . . . . . . . . . . . . . . .  19
+
+
+
+
+
+
+
+
+
+
+
+
+Siemborski                    Experimental                      [Page 2]
+
+RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
+
+
+1.  Introduction
+
+   In order to support an architecture where there are multiple [IMAP,
+   POP3] servers sharing a common mailbox database, it is necessary to
+   be able to provide atomic mailbox operations, as well as offer
+   sufficient guarantees about database consistency.
+
+   The primary goal of the MUPDATE protocol is to be simple to implement
+   yet allow for database consistency between participants.
+
+   The key words "MUST, "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT",
+   "RECOMMENDED", and "MAY" in this document are to be interpreted as
+   defined in BCP 14, RFC 2119 [KEYWORDS].
+
+   In examples, "C:" and "S:" indicate lines sent by the client and
+   server respectively.
+
+2.  Protocol Overview
+
+   The MUPDATE protocol assumes a reliable data stream such as a TCP
+   network connection.  IANA has registered port 3905 with a short name
+   of "mupdate" for this purpose.
+
+   In the current implementation of the MUPDATE protocol there are three
+   types of participants: a single master server, slave (or replica)
+   servers, and clients.  The master server maintains an authoritative
+   copy of the mailbox database.  Slave servers connect to the MUPDATE
+   master server as clients, and function as replicas from the point of
+   view of end clients.  End clients may connect to either the master or
+   any slave and perform searches against the database, however
+   operations that change the database can only be performed against the
+   master.  For the purposes of protocol discussion we will consider a
+   slave's connection to the master identical to that of any other
+   client.
+
+   After connection, all commands from a client to server must have an
+   associated unique tag which is an alphanumeric string.  Commands MAY
+   be pipelined from the client to the server (that is, the client need
+   not wait for the response before sending the next command).  The
+   server MUST execute the commands in the order they were received,
+   however.
+
+   If the server supports an inactivity login timeout, it MUST be at
+   least 15 minutes.
+
+
+
+
+
+
+
+Siemborski                    Experimental                      [Page 3]
+
+RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
+
+
+   MUPDATE uses data formats similar to those used in [ACAP].  That is,
+   atoms and strings.  All commands and tags in the protocol are
+   transmitted as atoms.  All other data is considered to a string, and
+   must be quoted or transmitted as a literal.
+
+   Outside of a literal, both clients and servers MUST support line
+   lengths of at least 1024 octets (including the trailing CR and LF
+   characters).  If a line of a longer length must be transmitted,
+   implementations MUST make use of literals to do so.
+
+2.1.  Atoms
+
+   An atom consists of one or more alphanumeric characters.  Atoms MUST
+   be less than 15 octets in length.
+
+2.2.  Strings
+
+   As in [ACAP], a string may be either literal or a quoted string.  A
+   literal is a sequence of zero or more octets (including CR and LF),
+   prefix-quoted with an octet count in the form of an open brace ("{"),
+   the number of octets, an optional plus sign to indicate that the data
+   follows immediately (a non-synchronized literal), a close brace
+   ("}"), and a CRLF sequence.  If the plus sign is omitted (a
+   synchronized literal), then the receiving side MUST send a "+ go
+   ahead" response, and the sending side MUST wait for this response.
+   Servers MUST support literals of atleast 4096 octets.
+
+   Strings that are sent from server to client SHOULD NOT be in the
+   synchronized literal format.
+
+   A quoted string is a sequence of zero or more 7-bit characters,
+   excluding CR, LF, and the double quote (<">), with double quote
+   characters at each end.
+
+   The empty string is represented as either "" (a quoted string with
+   zero characters between double quotes) or as {0} followed by CRLF (a
+   literal with an octet count of 0).
+
+3.  Server Responses
+
+   Every client command in the MUPDATE protocol may receive one or more
+   tagged responses from the server.  Each response is preceded by the
+   same tag as the command that elicited the response from the server.
+
+
+
+
+
+
+
+
+Siemborski                    Experimental                      [Page 4]
+
+RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
+
+
+3.1.  Response: OK
+
+   A tagged OK response indicates that the operation completed
+   successfully.  There is a mandatory implementation-defined string
+   after the OK response.  This response also indicates the beginning of
+   the streaming update mode when given in response to an UPDATE
+   command.
+
+   Example:
+
+C: N01 NOOP
+S: N01 OK "NOOP Complete"
+
+3.2.  Response: NO
+
+   A tagged NO response indicates that the operation was explicitly
+   denied by the server or otherwise failed.  There is a mandatory
+   implementation-defined string after the NO response that SHOULD
+   explain the reason for denial.
+
+   Example:
+
+C: A01 AUTHENTICATE "PLAIN"
+S: A01 NO "PLAIN is not a supported SASL mechanism"
+
+3.3.  Response: BAD
+
+   A tagged BAD response indicates that the command from the client
+   could not be parsed or understood.  There is a mandatory
+   implementation-defined string after the BAD response to provide
+   additional information about the error.  Note that untagged BAD
+   responses are allowed if it is unclear what the tag for a given
+   command is (for example, if a blank line is received by the mupdate
+   server, it can generate an untagged BAD response).  In the case of an
+   untagged response, the tag should be replaced with a "*".
+
+   Example:
+
+C: C01 SELECT "INBOX"
+S: C01 BAD "This is not an IMAP server"
+C:
+S: * BAD "Need Command"
+
+
+
+
+
+
+
+
+
+Siemborski                    Experimental                      [Page 5]
+
+RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
+
+
+3.4.  Response: BYE
+
+   A tagged BYE response indicates that the server has decided to close
+   the connection.  There is a mandatory implementation-defined string
+   after the BYE response that SHOULD explain the reason for closing the
+   connection.  The server MUST close the connection immediately after
+   transmitting the BYE response.
+
+   Example:
+
+C: L01 LOGOUT
+S: L01 BYE "User Logged Out"
+
+3.5.  Response: RESERVE
+
+   A tagged RESERVE response may only be given in response to a FIND,
+   LIST, or UPDATE command.  It includes two parameters: the name of the
+   mailbox that is being reserved (in mUTF-7 encoding, as specified in
+   [IMAP]) and a location string whose contents is defined by the
+   clients that are using the database, though it is RECOMMENDED that
+   the format of this string be the hostname of the server which is
+   storing the mailbox.
+
+   This response indicates that the given name is no longer available in
+   the namespace, though it does not indicate that the given mailbox is
+   available to clients at the current time.
+
+   Example:
+
+S: U01 RESERVE "internet.bugtraq" "mail2.example.org"
+
+3.6.  Response: MAILBOX
+
+   A tagged MAILBOX response may only be given in response to a FIND,
+   LIST, or UPDATE command.  It includes three parameters: the name of
+   the mailbox, a location string (as with RESERVE), and a client-
+   defined string that specifies the IMAP ACL [IMAP-ACL] of the mailbox.
+   This message indicates that the given mailbox is ready to be accessed
+   by clients.
+
+   Example:
+
+S: U01 MAILBOX "internet.bugtraq" "mail2.example.org" "anyone rls"
+
+
+
+
+
+
+
+
+Siemborski                    Experimental                      [Page 6]
+
+RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
+
+
+3.7.  Response: DELETE
+
+   A tagged DELETE response may only be given in response to an UPDATE
+   command, and MUST NOT be given before the OK response to the UPDATE
+   command is given.  It contains a single parameter, that of the
+   mailbox that should be deleted from the slave's database.  This
+   response indicates that the given mailbox no longer exists in the
+   namespace of the database, and may be given for any mailbox name,
+   active, reserved, or nonexistent.  (Though implementations SHOULD NOT
+   issue DELETE responses for nonexistent mailboxes).
+
+   Example:
+
+S: U01 DELETE "user.rjs3.sent-mail-jan-2002"
+
+3.8.  Server Capability Response
+
+   Upon connection of the client to the server, and directly following a
+   successful STARTTLS command, the server MUST issue a capabilities
+   banner, of the following format:
+
+   The banner MUST contain a line that begins with "* AUTH" and contain
+   a space-separated list of SASL mechanisms that the server will accept
+   for authentication.  The mechanism names are transmitted as atoms.
+   Servers MAY advertise no available mechanisms (to indicate that
+   STARTTLS must be completed before authentication may occur).  If
+   STARTTLS is not supported by the server, then the line MUST contain
+   at least one mechanism.
+
+   If the banner is being issued without a TLS layer, and the server
+   supports the STARTTLS command, the banner MUST contain the line "*
+   STARTTLS".  If the banner is being issued under a TLS layer (or the
+   server does not support STARTTLS), the banner MUST NOT contain this
+   line.
+
+   The last line of the banner MUST start with "* OK MUPDATE" and be
+   followed by four strings: the server's hostname, an implementation-
+   defined string giving the name of the implementation, an
+   implementation-defined string giving the version of the
+   implementation, and a string that indicates if the server is a master
+   or a slave.  The master/slave indication MUST be either "(master)" or
+   an MUPDATE URL that defines where the master can be contacted.
+
+   Any unrecognized responses before the "* OK MUPDATE" response MUST be
+   ignored by the client.
+
+
+
+
+
+
+Siemborski                    Experimental                      [Page 7]
+
+RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
+
+
+   Example:
+
+S: * AUTH KERBEROS_V4 GSSAPI
+S: * STARTTLS
+S: * OK MUPDATE "mupdate.example.org" "Cyrus" "v2.1.2" "(master)"
+
+4.  Client Commands
+
+   The following are valid commands that a client may send to the
+   MUPDATE server: AUTHENTICATE, ACTIVATE, DEACTIVATE, DELETE, FIND,
+   LIST, LOGOUT, NOOP, RESERVE, STARTTLS, and UPDATE.
+
+   Before a successful AUTHENTICATE command has occurred, the server
+   MUST NOT accept any commands except for AUTHENTICATE, STARTTLS, and
+   LOGOUT (and SHOULD reply with a NO response for all other commands).
+
+4.1.  Command: ACTIVATE
+
+   The ACTIVATE command has 3 parameters: the mailbox name, its
+   location, and its ACL.  This command MUST NOT not be issued to a
+   slave server.
+
+   This command can also be used to update the ACL or location
+   information of a mailbox.  Note that it is not a requirement for a
+   mailbox to be reserved (or even exist in the database) for an
+   ACTIVATE command to succeed, implementations MUST allow this behavior
+   as it facilitates synchronization of the database with the current
+   state of the mailboxes.
+
+4.2.  Command: AUTHENTICATE
+
+   The AUTHENTICATE command initiates a [SASL] negotiation session
+   between the client and the server.  It has two parameters.  The first
+   parameter is mandatory, and is a string indicating the desired [SASL]
+   mechanism.  The second is a string containing an optional BASE64
+   encoded (as defined in section 6.8 of [MIME]) client first send.
+
+   All of the remaining SASL blobs that are sent MUST be sent across the
+   wire must be in BASE64 encoded format, and followed by a CR and LF
+   combination.  They MUST NOT be encoded as strings.
+
+   Clients may cancel authentication by sending a * followed by a CR and
+   LF.
+
+   The [SASL] service name for the MUPDATE protocol is "mupdate".
+   Implementations are REQUIRED to implement the GSSAPI [SASL]
+   mechanism, though they SHOULD implement as many mechanisms as
+   possible.
+
+
+
+Siemborski                    Experimental                      [Page 8]
+
+RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
+
+
+   If a security layer is negotiated, it should be used directly
+   following the CR and LF combination at the end of the server's OK
+   response (i.e., beginning with the client's next command) Only one
+   successful AUTHENTICATE command may be issued per session.
+
+4.3.  Command: DEACTIVATE
+
+   The DEACTIVATE command takes two parameters, the mailbox name and
+   location data.  The mailbox MUST already exist and be activated on
+   the MUPDATE server.  If the server responds OK, then the mailbox name
+   has been moved to the RESERVE state.  If the server responds NO, then
+   the mailbox name has not been moved (for example, the mailbox was not
+   already active).  Any ACL information that is known about the mailbox
+   MAY be lost when a DEACTIVATE succeeds.  This command MUST NOT be
+   issued to a slave.
+
+   Example:
+
+C: A01 DEACTIVATE "user.rjs3.new" "mail3.example.org!u4"
+S: A01 OK "Mailbox Reserved."
+
+4.4.  Command: DELETE
+
+   The DELETE command takes only a single parameter, the mailbox name to
+   be removed from the database's namespace.  The server SHOULD give a
+   NO response if the mailbox does not exist.  This command MUST NOT be
+   issued to a slave server.
+
+4.5.  Command: FIND
+
+   The FIND command takes a single parameter, a mailbox name.  The
+   server then responds with the current record for the given mailbox,
+   if any, and an OK response.
+
+   Example (mailbox does not exist):
+
+C: F01 FIND "user.rjs3.xyzzy"
+S: F01 OK "Search Complete"
+
+   Example (mailbox is reserved):
+
+C: F01 FIND "user.rjs3"
+S: F01 RESERVE "user.rjs3" "mail4.example.org"
+S: F01 OK "Search Complete"
+
+
+
+
+
+
+
+Siemborski                    Experimental                      [Page 9]
+
+RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
+
+
+4.6.  Command: LIST
+
+   The LIST command is similar to running FIND across the entire
+   database.  The LIST command takes a single optional parameter, which
+   is a prefix to try to match against the location field of the
+   records.  Without the parameter, LIST returns every record in the
+   database.
+
+   For each mailbox that matches, either a MAILBOX or a RESERVE response
+   (as applicable) is sent to the client.  When all responses are
+   complete, an OK response is issued.
+
+   Example:
+
+C: L01 LIST
+S: L01 RESERVE "user.rjs3" "mail4.example.org!u2"
+S: L01 MAILBOX "user.leg" "mail2.example.org!u1" "leg lrswipcda"
+S: L01 OK "List Complete"
+C: L02 LIST "mail4.example.org!"
+S: L02 RESERVE "user.rjs3" "mail4.example.org!u2"
+S: L02 OK "List Complete"
+
+4.7.  Command: LOGOUT
+
+   The LOGOUT command tells the server to close the connection.  Its
+   only valid response is the BYE response.  The LOGOUT command takes no
+   parameters.
+
+4.8.  Command: NOOP
+
+   The NOOP command takes no parameters.  Provided the client is
+   authenticated, its only acceptable response is an OK.  Any idle
+   timeouts that the server may have on the connection SHOULD be reset
+   upon receipt of this command.
+
+   If this command is issued after an UPDATE command has been issued,
+   then the OK response also indicates that all pending database updates
+   have been sent to the client.  That is, the slave can guarantee that
+   its local database is up to date as of a certain time by issuing a
+   NOOP and waiting for the OK.  The OK MUST NOT return until all
+   updates that were pending at the time of the NOOP have been sent.
+
+4.9.  Command: RESERVE
+
+   The RESERVE command takes two parameters (just like the RESERVE
+   response), the mailbox name to reserve and location data.  If the
+   server responds OK, then the mailbox name has been reserved.  If the
+   server responds NO, then the mailbox name has not been reserved (for
+
+
+
+Siemborski                    Experimental                     [Page 10]
+
+RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
+
+
+   example, another server has reserved it already).  This command MUST
+   NOT be issued to a slave.
+
+   The typical sequence for mailbox creation is:
+
+C: R01 RESERVE "user.rjs3.new" "mail3.example.org!u4"
+S: R01 OK "Mailbox Reserved."
+<client does local mailbox create operations>
+C: A01 ACTIVATE "user.rjs3.new" "mail3.example.org!u4" "rjs3 lrswipcda"
+S: A01 OK "Mailbox Activated."
+
+4.10.  Command: STARTTLS
+
+   The STARTTLS command requests the commencement of a [TLS]
+   negotiation.  The negotiation begins immediately after the CRLF in
+   the OK response.  After a client issues a STARTTLS command, it MUST
+   NOT issue further commands until a server response is seen and the
+   [TLS] negotiation is complete.
+
+   The STARTTLS command is only valid in non-authenticated state.  The
+   server remains in non-authenticated state, even if client credentials
+   are supplied during the [TLS] negotiation.  The [SASL] EXTERNAL
+   mechanism MAY be used to authenticate once [TLS] client credentials
+   are successfully exchanged.  Note that servers are not required to
+   support the EXTERNAL mechanism.
+
+   After the [TLS] layer is established, the server MUST re-issue the
+   initial response banner (see Section 3.8).  This is necessary to
+   protect against man-in-the-middle attacks which alter the
+   capabilities list prior to STARTTLS, as well as to advertise any new
+   SASL mechanisms (or other capabilities) that may be available under
+   the layer.  The client MUST discard cached capability information and
+   replace it with the new information.
+
+   After the a successful STARTTLS command, the server SHOULD return a
+   NO response to additional STARTTLS commands.
+
+   Servers MAY choose to not implement STARTTLS.  In this case, they
+   MUST NOT advertise STARTTLS in their capabilities banner, and SHOULD
+   return a BAD response to the STARTTLS command, if it is issued.
+
+   Example:
+
+C: S01 STARTTLS
+S: S01 OK "Begin TLS negotiation now"
+<TLS negotiation, further commands are under TLS layer>
+S: * AUTH KERBEROS_V4 GSSAPI PLAIN
+S: * OK MUPDATE "mupdate.example.org" "Cyrus" "v2.1.2" "(master)"
+
+
+
+Siemborski                    Experimental                     [Page 11]
+
+RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
+
+
+4.11.  Command: UPDATE
+
+   The UPDATE command is how a slave initializes an update stream from
+   the master (though it is also valid to issue this command to a
+   slave).  In response to the command, the server returns a list of all
+   mailboxes in its database (the same results as a parameterless LIST
+   command) followed by an OK response.  From this point forward,
+   whenever an update occurs to the master database, it MUST stream the
+   update to the slave within 30 seconds.  That is, it will send
+   RESERVE, MAILBOX, or DELETE responses as they are applicable.
+
+   After a client has issued an UPDATE command, it may only issue NOOP
+   and LOGOUT commands for the remainder of the session.
+
+   Example:
+
+C: U01 UPDATE
+S: U01 MAILBOX "user.leg" "mail2.example.org!u1" "leg lrswipcda"
+S: U01 MAILBOX "user.rjs3" "mail3.example.org!u4" "rjs3 lrswipcda"
+S: U01 RESERVE "internet.bugtraq" "mail1.example.org!u5" "anyone lrs"
+S: U01 OK "Streaming Begins"
+<some time goes by, and another client creates a new mailbox>
+S: U01 RESERVE "user.leg.new" "mail2.example.org!u1"
+<some more time passes, and the create succeeds>
+S: U01 MAILBOX "user.leg.new" "mail2.example.org!u1" "leg lrswipcda"
+<much more time passes, and the slave decides to send a NOOP to reset
+its inactivity timer>
+C: N01 NOOP
+S: U01 DELETE "user.leg.new"
+S: N01 OK "NOOP Complete"
+
+5.  MUPDATE Formal Syntax
+
+   The following syntax specification uses the Augmented Backus-Naur
+   Form (ABNF) notation as specified in [ABNF].  This uses the ABNF core
+   rules as specified in Appendix A of [ABNF].
+
+   Except as noted otherwise, all alphabetic characters are case-
+   insensitive.  The use of upper or lower case characters to define
+   token strings is for editorial clarity only.  Implementations MUST
+   accept these strings in a case-insensitive fashion.
+
+   Note that this specification also uses some terminals from section 8
+   of [ACAP].
+
+   cmd-activate = "ACTIVATE" SP string SP string SP string
+
+   cmd-authenticate = "AUTHENTICATE" SP sasl-mech [ SP string ]
+
+
+
+Siemborski                    Experimental                     [Page 12]
+
+RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
+
+
+   cmd-delete = "DELETE" SP string
+
+   cmd-find = "FIND" SP string
+
+   cmd-list = "LIST" [ SP string ]
+
+   cmd-logout = "LOGOUT"
+
+   cmd-noop = "NOOP"
+
+   cmd-reserve = "RESERVE" SP string SP string
+
+   cmd-starttls = "STARTTLS"
+
+   cmd-update = "UPDATE"
+
+   command = tag SP command-type CRLF
+
+   command-type = cmd-activate / cmd-authenticate / cmd-delete /
+                  cmd-find / cmd-list / cmd-logout / cmd-noop /
+                  cmd-reserve / cmd-starttls / cmd-update
+
+   response = tag SP response-type CRLF
+
+   response-type = rsp-ok / rsp-no / rsp-bad / rsp-bye / rsp-mailbox /
+                   rsp-reserve / rsp-delete
+
+   rsp-bad = "BAD" SP string
+
+   rsp-bye = "BYE" SP string
+
+   rsp-mailbox = "MAILBOX" SP string SP string SP string
+
+   rsp-no = "NO" SP string
+
+   rsp-ok = "OK" SP string
+
+   rsp-reserve = "RESERVE" SP string SP string
+
+   rsp-delete = "DELETE" SP string
+
+   sasl-mech = 1*ATOM-CHAR
+      ; ATOM-CHAR is defined in [ACAP]
+
+   string = quoted / literal
+      ; quoted and literal are defined in [ACAP]
+
+
+
+
+
+Siemborski                    Experimental                     [Page 13]
+
+RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
+
+
+   tag = 1*ATOM-CHAR
+      ; ATOM-CHAR is defined in [ACAP]
+
+6.  MUPDATE URL Scheme
+
+   This document defines the a URL scheme for the purposes of
+   referencing MUPDATE resources, according to the requirements in
+   [RFC2717].  This includes both MUPDATE servers as a whole, along with
+   individual mailbox entries on a given MUPDATE server.
+
+   There is no MIME type associated with these resources.  It is
+   intended that a URL consumer would either retrieve the MUPDATE record
+   in question, or simply connect to the MUPDATE server running on the
+   specified host.  Note that the consumer will need to have
+   authentication credentials for the specified host.
+
+   The MUPDATE URL scheme is similar to the IMAP URL scheme [IMAP-URL].
+   However, it only takes one of two possible forms:
+
+      mupdate://<iserver>/
+      mupdate://<iserver>/<mailbox>
+
+   The first form refers to a MUPDATE server as a whole, the second form
+   indicates both the server and a mailbox to run a FIND against once
+   authenticated to the server.  Note that part of <iserver> may include
+   username and authentication information along with a hostname and
+   port.
+
+6.1.  MUPDATE URL Scheme Registration Form
+
+   URL scheme name: "mupdate"
+
+   URL scheme syntax:
+
+      This defines the MUPDATE URL Scheme in [ABNF].  Terminals from the
+      BNF of IMAP URLs [IMAP-URL] are also used.
+
+         mupdateurl = "mupdate://" iserver "/" [ enc_mailbox ]
+            ; iserver and enc_mailbox are as defined in [IMAP-URL]
+
+   Character encoding considerations:
+
+      Identical to those described in [IMAP-URL] for the appropriate
+      terminals.
+
+
+
+
+
+
+
+Siemborski                    Experimental                     [Page 14]
+
+RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
+
+
+   Intended Usage:
+
+      The form of the URL without an associated mailbox is intended to
+      designate a MUPDATE server only.  If a mailbox name is included in
+      the URL, then the consumer is expected to execute a FIND command
+      for that mailbox on the specified server.
+
+   Applications and/or protocols which use this URL scheme name:
+
+      The protocol described in this document.
+
+   Interoperability Considerations:
+
+      None.
+
+   Security Considerations:
+
+      Users of the MUPDATE URL Scheme should review the security
+      considerations that are discussed in [IMAP-URL].  In particular,
+      the consequences of including authentication mechanism information
+      in a URL should be reviewed.
+
+   Relevant Publications:
+
+      This document and [IMAP-URL].
+
+   Author, Change Controller, and Contact for Further Information:
+
+      Author of this document.
+
+7.  Security Considerations
+
+   While no unauthenticated users may make modifications or even perform
+   searches on the database, it is important to note that this
+   specification assumes no protections of any type for authenticated
+   users.
+
+   All authenticated users have complete access to the database.  For
+   this reason it is important to ensure that accounts that are making
+   use of the database are well secured.
+
+   A more secure deployment might have all read only access go through a
+   slave, and only have accounts which need write access use the master.
+   This has the disadvantage of a marginally longer time for updates to
+   reach the clients.
+
+
+
+
+
+
+Siemborski                    Experimental                     [Page 15]
+
+RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
+
+
+   The protocol assumes that all authenticated users are cooperating to
+   maintain atomic operations.  Therefore, all new mailboxes SHOULD be
+   RESERVEd before they are ACTIVATEd, despite the fact that the
+   protocol does not require this, and it is therefore possible for a
+   set of participants which do not obey the provided locking to create
+   an inconsistent database.  RESERVEing the mailbox first is not
+   required to perform an activate because this behavior simplifies
+   synchronization with the actual location of the mailboxes.
+
+8.  IANA Considerations
+
+   The IANA has assigned TCP port number 3905 to "mupdate".
+
+   The IANA has registered a URL scheme for the MUPDATE protocol, as
+   defined in section 6.1 of this document.
+
+   IANA has registered a GSSAPI service name of "mupdate" for the
+   MUPDATE protocol in the registry maintained at:
+
+   http://www.iana.org/assignments/gssapi-service-names
+
+9.  Intellectual Property Rights
+
+   The IETF takes no position regarding the validity or scope of any
+   intellectual property or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; neither does it represent that it
+   has made any effort to identify any such rights.  Information on the
+   IETF's procedures with respect to rights in standards-track and
+   standards-related documentation can be found in BCP-11.  Copies of
+   claims of rights made available for publication and any assurances of
+   licenses to be made available, or the result of an attempt made to
+   obtain a general license or permission for the use of such
+   proprietary rights by implementors or users of this specification can
+   be obtained from the IETF Secretariat.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights which may cover technology that may be required to practice
+   this standard.  Please address the information to the IETF Executive
+   Director.
+
+
+
+
+
+
+
+
+
+Siemborski                    Experimental                     [Page 16]
+
+RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
+
+
+10.  References
+
+10.1.  Normative References
+
+   [KEYWORDS]  Bradner, S., "Key words for use in RFCs to Indicate
+               Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+   [IMAP]      Crispin, M., "Internet Message Access Protocol - Version
+               4", RFC 3501, March 2003.
+
+   [ABNF]      Crocker, D., Ed. and P. Overell, "Augmented BNF for
+               Syntax Specifications: ABNF", RFC 2234, November 1997.
+
+   [MIME]      Freed, N. and N. Bornstein, "Multipurpose Internet Mail
+               Extensions (MIME) Part One: Format of Internet Message
+               Bodies", RFC 2045, November 1996.
+
+   [IMAP-ACL]  Myers, J., "IMAP4 ACL extension", RFC 2086, January 1997.
+
+   [SASL]      Myers, J., "Simple Authentication and Security Layer
+               (SASL)", RFC 2222, October 1997.
+
+   [IMAP-URL]  Newman, C., "IMAP URL Scheme", RFC 2192, September 1997.
+
+   [ACAP]      Newman, C. and J. Myers, "ACAP -- Application
+               Configuration Access Protocol", RFC 2244, November 1997.
+
+   [TLS]       Dierks, T. and C. Allen, "The TLS Protocol Version 1.0",
+               RFC 2246, January 1999.
+
+10.2.  Informative References
+
+   [POP3]      Myers, J. and M. Rose, "Post Office Protocol - Version
+               3", STD 53, RFC 1939, May 1996.
+
+   [RFC2717]   Petke, R. and I. King, "Registration Procedures for URL
+               Scheme Names", BCP 35, RFC 2717, November 1999.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Siemborski                    Experimental                     [Page 17]
+
+RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
+
+
+11.  Acknowledgments
+
+   Lawrence Greenfield and Ken Murchison, for a great deal of input on
+   both the protocol and the text of the documents.
+
+12.  Author's  Address
+
+   Robert Siemborski
+   Carnegie Mellon, Andrew Systems Group
+   Cyert Hall 207
+   5000 Forbes Avenue
+   Pittsburgh, PA  15213
+
+   Phone: (412) 268-7456
+   EMail: rjs3+@andrew.cmu.edu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Siemborski                    Experimental                     [Page 18]
+
+RFC 3656     MUPDATE Distributed Mailbox Database Protocol December 2003
+
+
+13.  Full Copyright Statement
+
+   Copyright (C) The Internet Society (2003).  All Rights Reserved.
+
+   This document and translations of it may be copied and furnished to
+   others, and derivative works that comment on or otherwise explain it
+   or assist in its implementation may be prepared, copied, published
+   and distributed, in whole or in part, without restriction of any
+   kind, provided that the above copyright notice and this paragraph are
+   included on all such copies and derivative works.  However, this
+   document itself may not be modified in any way, such as by removing
+   the copyright notice or references to the Internet Society or other
+   Internet organizations, except as needed for the purpose of
+   developing Internet standards in which case the procedures for
+   copyrights defined in the Internet Standards process must be
+   followed, or as required to translate it into languages other than
+   English.
+
+   The limited permissions granted above are perpetual and will not be
+   revoked by the Internet Society or its successors or assignees.
+
+   This document and the information contained herein is provided on an
+   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is currently provided by the
+   Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Siemborski                    Experimental                     [Page 19]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc3691.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,283 @@
+
+
+
+
+
+
+Network Working Group                                        A. Melnikov
+Request for Comments: 3691                                    Isode Ltd.
+Category: Standards Track                                  February 2004
+
+
+        Internet Message Access Protocol (IMAP) UNSELECT command
+
+Status of this Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (2004).  All Rights Reserved.
+
+Abstract
+
+   This document defines an UNSELECT command that can be used to close
+   the current mailbox in an Internet Message Access Protocol - version
+   4 (IMAP4) session without expunging it.  Certain types of IMAP
+   clients need to release resources associated with the selected
+   mailbox without selecting a different mailbox.  While IMAP4 provides
+   this functionality (via a SELECT command with a nonexistent mailbox
+   name or reselecting the same mailbox with EXAMINE command), a more
+   clean solution is desirable.
+
+Table of Contents
+
+   1.  Introduction . . . . . . . . . . . . . . . . . . . . . . . . .  2
+   2.  UNSELECT command . . . . . . . . . . . . . . . . . . . . . . .  2
+   3.  Security Considerations. . . . . . . . . . . . . . . . . . . .  3
+   4.  Formal Syntax. . . . . . . . . . . . . . . . . . . . . . . . .  3
+   5.  IANA Considerations. . . . . . . . . . . . . . . . . . . . . .  3
+   6.  Acknowledgments. . . . . . . . . . . . . . . . . . . . . . . .  3
+   7.  Normative References . . . . . . . . . . . . . . . . . . . . .  4
+   8.  Author's Address . . . . . . . . . . . . . . . . . . . . . . .  4
+   9.  Full Copyright Statement . . . . . . . . . . . . . . . . . . .  5
+
+
+
+
+
+
+
+
+
+
+Melnikov                    Standards Track                     [Page 1]
+
+RFC 3691                 IMAP UNSELECT command             February 2004
+
+
+1.  Introduction
+
+   Certain types of IMAP clients need to release resources associated
+   with the selected mailbox without selecting a different mailbox.
+   While [IMAP4] provides this functionality (via a SELECT command with
+   a nonexistent mailbox name or reselecting the same mailbox with
+   EXAMINE command), a more clean solution is desirable.
+
+   [IMAP4] defines the CLOSE command that closes the selected mailbox as
+   well as permanently removes all messages with the \Deleted flag set.
+
+   However [IMAP4] lacks a command that simply closes the mailbox
+   without expunging it.  This document defines the UNSELECT command for
+   this purpose.
+
+   A server which supports this extension indicates this with a
+   capability name of "UNSELECT".
+
+   "C:" and "S:" in examples show lines sent by the client and server
+   respectively.
+
+   The keywords "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY" in
+   this document when typed in uppercase are to be interpreted as
+   defined in "Key words for use in RFCs to Indicate Requirement Levels"
+   [KEYWORDS].
+
+2.  UNSELECT Command
+
+   Arguments:  none
+
+   Responses:  no specific responses for this command
+
+   Result:     OK - unselect completed, now in authenticated state
+               BAD - no mailbox selected, or argument supplied but
+                     none permitted
+
+      The UNSELECT command frees server's resources associated with the
+      selected mailbox and returns the server to the authenticated
+      state.  This command performs the same actions as CLOSE, except
+      that no messages are permanently removed from the currently
+      selected mailbox.
+
+   Example:    C: A341 UNSELECT
+               S: A341 OK Unselect completed
+
+
+
+
+
+
+
+Melnikov                    Standards Track                     [Page 2]
+
+RFC 3691                 IMAP UNSELECT command             February 2004
+
+
+3.  Security Considerations
+
+   It is believed that this extension doesn't raise any additional
+   security concerns not already discussed in [IMAP4].
+
+4.  Formal Syntax
+
+   The following syntax specification uses the Augmented Backus-Naur
+   Form (ABNF) notation as specified in [ABNF].  Non-terminals
+   referenced but not defined below are as defined by [IMAP4].
+
+   Except as noted otherwise, all alphabetic characters are case-
+   insensitive.  The use of upper or lower case characters to define
+   token strings is for editorial clarity only.  Implementations MUST
+   accept these strings in a case-insensitive fashion.
+
+   command-select  /= "UNSELECT"
+
+5.  IANA Considerations
+
+   IMAP4 capabilities are registered by publishing a standards track or
+   IESG approved experimental RFC.  The registry is currently located
+   at:
+
+      http://www.iana.org/assignments/imap4-capabilities
+
+   This document defines the UNSELECT IMAP capabilities.  IANA has added
+   this capability to the registry.
+
+6.  Acknowledgments
+
+   UNSELECT command was originally implemented by Tim Showalter in Cyrus
+   IMAP server.
+
+   Also, the author of the document would like to thank Vladimir Butenko
+   and Mark Crispin for reminding that UNSELECT has to be documented.
+   Also thanks to Simon Josefsson for pointing out that there are
+   multiple ways to implement UNSELECT.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov                    Standards Track                     [Page 3]
+
+RFC 3691                 IMAP UNSELECT command             February 2004
+
+
+7.  Normative References
+
+   [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate
+              Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+   [IMAP4]    Crispin, M., "Internet Message Access Protocol - Version
+              4rev1", RFC 3501, March 2003.
+
+   [ABNF]     Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax
+              Specifications: ABNF", RFC 2234, November 1997.
+
+8.  Author's Address
+
+   Alexey Melnikov
+   Isode Limited
+   5 Castle Business Village
+   Hampton, Middlesex TW12 2BX
+
+   EMail: Alexey.Melnikov@isode.com
+   URI: http://www.melnikov.ca/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov                    Standards Track                     [Page 4]
+
+RFC 3691                 IMAP UNSELECT command             February 2004
+
+
+9.  Full Copyright Statement
+
+   Copyright (C) The Internet Society (2004).  This document is subject
+   to the rights, licenses and restrictions contained in BCP 78 and
+   except as set forth therein, the authors retain all their rights.
+
+   This document and the information contained herein are provided on an
+   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE
+   REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE
+   INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR
+   IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
+   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   Intellectual Property Rights or other rights that might be claimed
+   to pertain to the implementation or use of the technology
+   described in this document or the extent to which any license
+   under such rights might or might not be available; nor does it
+   represent that it has made any independent effort to identify any
+   such rights.  Information on the procedures with respect to
+   rights in RFC documents can be found in BCP 78 and BCP 79.
+
+   Copies of IPR disclosures made to the IETF Secretariat and any
+   assurances of licenses to be made available, or the result of an
+   attempt made to obtain a general license or permission for the use
+   of such proprietary rights by implementers or users of this
+   specification can be obtained from the IETF on-line IPR repository
+   at http://www.ietf.org/ipr.
+
+   The IETF invites any interested party to bring to its attention
+   any copyrights, patents or patent applications, or other
+   proprietary rights that may cover technology that may be required
+   to implement this standard.  Please address the information to the
+   IETF at ietf-ipr@ietf.org.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is currently provided by the
+   Internet Society.
+
+
+
+
+
+
+
+
+
+Melnikov                    Standards Track                     [Page 5]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc4314.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1515 @@
+
+
+
+
+
+
+Network Working Group                                        A. Melnikov
+Request for Comments: 4314                                    Isode Ltd.
+Obsoletes: 2086                                            December 2005
+Category: Standards Track
+
+
+               IMAP4 Access Control List (ACL) Extension
+
+Status of this Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (2005).
+
+Abstract
+
+   The Access Control List (ACL) extension (RFC 2086) of the Internet
+   Message Access Protocol (IMAP) permits mailbox access control lists
+   to be retrieved and manipulated through the IMAP protocol.
+
+   This document is a revision of RFC 2086.  It defines several new
+   access control rights and clarifies which rights are required for
+   different IMAP commands.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov                    Standards Track                     [Page 1]
+
+RFC 4314                        IMAP ACL                   December 2005
+
+
+Table of Contents
+
+   1. Introduction and Overview .......................................3
+      1.1. Conventions Used in This Document ..........................3
+   2. Access Control ..................................................3
+      2.1. Standard Rights ............................................5
+           2.1.1. Obsolete Rights .....................................5
+      2.2. Rights Defined in RFC 2086 .................................8
+   3. Access control management commands and responses ................8
+      3.1. SETACL Command .............................................8
+      3.2. DELETEACL Command ..........................................9
+      3.3. GETACL Command ............................................10
+      3.4. LISTRIGHTS Command ........................................10
+      3.5. MYRIGHTS Command ..........................................11
+      3.6. ACL Response ..............................................11
+      3.7. LISTRIGHTS Response .......................................12
+      3.8. MYRIGHTS Response .........................................12
+   4. Rights Required to Perform Different IMAP4rev1 Commands ........12
+   5. Other Considerations ...........................................17
+      5.1. Additional Requirements and Implementation Notes ..........17
+           5.1.1. Servers ............................................17
+           5.1.2. Clients ............................................18
+      5.2. Mapping of ACL Rights to READ-WRITE and READ-ONLY
+           Response Codes ............................................19
+   6. Security Considerations ........................................20
+   7. Formal Syntax ..................................................21
+   8. IANA Considerations ............................................22
+   9. Internationalization Considerations ............................22
+   Appendix A. Changes since RFC 2086 ................................23
+   Appendix B. Compatibility with RFC 2086 ...........................24
+   Appendix C. Known Deficiencies ....................................24
+   Appendix D. Acknowledgements ......................................25
+   Normative References ..............................................25
+   Informative References ............................................25
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov                    Standards Track                     [Page 2]
+
+RFC 4314                        IMAP ACL                   December 2005
+
+
+1.  Introduction and Overview
+
+   The ACL (Access Control List) extension of the Internet Message
+   Access Protocol [IMAP4] permits mailbox access control lists to be
+   retrieved and manipulated through the IMAP protocol.
+
+   This document is a revision of RFC 2086 [RFC2086].  It tries to
+   clarify different ambiguities in RFC 2086, in particular, the use of
+   UTF-8 [UTF-8] in access identifiers, which rights are required for
+   different IMAP4 commands, and how READ-WRITE/READ-ONLY response codes
+   are related to ACL.
+
+1.1.  Conventions Used in This Document
+
+   In examples, "C:" and "S:" indicate lines sent by the client and
+   server respectively.
+
+   In all examples "/" character is used as hierarchy separator.
+
+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+   document are to be interpreted as described in RFC 2119 [KEYWORDS].
+
+   The phrase "ACL server" is just a shortcut for saying "IMAP server
+   that supports ACL extension as defined in this document".
+
+2.  Access Control
+
+   The ACL extension is present in any IMAP4 implementation that returns
+   "ACL" as one of the supported capabilities to the CAPABILITY command.
+
+   A server implementation conformant to this document MUST also return
+   rights (see below) not defined in Section 2.2 in the "RIGHTS="
+   capability.
+
+   An access control list is a set of <access identifier,rights> pairs.
+   An ACL applies to a mailbox name.
+
+   Access identifier (or just "identifier") is a UTF-8 [UTF-8] string.
+   The identifier "anyone" is reserved to refer to the universal
+   identity (all authentications, including anonymous).  All user name
+   strings accepted by the LOGIN or AUTHENTICATE commands to
+   authenticate to the IMAP server are reserved as identifiers for the
+   corresponding users.  Identifiers starting with a dash ("-") are
+   reserved for "negative rights", described below.  All other
+   identifier strings are interpreted in an implementation-defined
+   manner.
+
+
+
+
+Melnikov                    Standards Track                     [Page 3]
+
+RFC 4314                        IMAP ACL                   December 2005
+
+
+   Rights is a string listing a (possibly empty) set of alphanumeric
+   characters, each character listing a set of operations that is being
+   controlled.  Lowercase letters are reserved for "standard" rights,
+   listed in Section 2.1.  (Note that for compatibility with deployed
+   clients and servers uppercase rights are not allowed.)  The set of
+   standard rights can only be extended by a standards-track document.
+   Digits are reserved for implementation- or site-defined rights.
+
+   An implementation MAY tie rights together or MAY force rights to
+   always or never be granted to particular identifiers.  For example,
+   in an implementation that uses UNIX mode bits, the rights "swite" are
+   tied, the "a" right is always granted to the owner of a mailbox and
+   is never granted to another user.  If rights are tied in an
+   implementation, the implementation must be conservative in granting
+   rights in response to SETACL commands--unless all rights in a tied
+   set are specified, none of that set should be included in the ACL
+   entry for that identifier.  A client can discover the set of rights
+   that may be granted to a given identifier in the ACL for a given
+   mailbox name by using the LISTRIGHTS command.
+
+   It is possible for multiple identifiers in an access control list to
+   apply to a given user.  For example, an ACL may include rights to be
+   granted to the identifier matching the user, one or more
+   implementation-defined identifiers matching groups that include the
+   user, and/or the identifier "anyone".  How these rights are combined
+   to determine the user's access is implementation defined.  An
+   implementation may choose, for example, to use the union of the
+   rights granted to the applicable identifiers.  An implementation may
+   instead choose, for example, to use only those rights granted to the
+   most specific identifier present in the ACL.  A client can determine
+   the set of rights granted to the logged-in user for a given mailbox
+   name by using the MYRIGHTS command.
+
+   When an identifier in an ACL starts with a dash ("-"), that indicates
+   that associated rights are to be removed from the identifier prefixed
+   by the dash.  This is referred to as a "negative right".  This
+   differs from DELETEACL in that a negative right is added to the ACL
+   and is a part of the calculation of the rights.
+
+   Let's assume that an identifier "fred" refers to a user with login
+   "fred".  If the identifier "-fred" is granted the "w" right, that
+   indicates that the "w" right is to be removed from users matching the
+   identifier "fred", even though the user "fred" might have the "w"
+   right as a consequence of some other identifier in the ACL.  A
+   DELETEACL of "fred" simply deletes the identifier "fred" from the
+   ACL; it does not affect any rights that the user "fred" may get from
+   another entry in the ACL, in particular it doesn't affect rights
+   granted to the identifier "-fred".
+
+
+
+Melnikov                    Standards Track                     [Page 4]
+
+RFC 4314                        IMAP ACL                   December 2005
+
+
+   Server implementations are not required to support "negative right"
+   identifiers.
+
+2.1.  Standard Rights
+
+   The currently defined standard rights are (note that the list below
+   doesn't list all commands that use a particular right):
+
+   l - lookup (mailbox is visible to LIST/LSUB commands, SUBSCRIBE
+       mailbox)
+   r - read (SELECT the mailbox, perform STATUS)
+   s - keep seen/unseen information across sessions (set or clear
+       \SEEN flag via STORE, also set \SEEN during APPEND/COPY/
+       FETCH BODY[...])
+   w - write (set or clear flags other than \SEEN and \DELETED via
+       STORE, also set them during APPEND/COPY)
+   i - insert (perform APPEND, COPY into mailbox)
+   p - post (send mail to submission address for mailbox,
+       not enforced by IMAP4 itself)
+   k - create mailboxes (CREATE new sub-mailboxes in any
+       implementation-defined hierarchy, parent mailbox for the new
+       mailbox name in RENAME)
+   x - delete mailbox (DELETE mailbox, old mailbox name in RENAME)
+   t - delete messages (set or clear \DELETED flag via STORE, set
+       \DELETED flag during APPEND/COPY)
+   e - perform EXPUNGE and expunge as a part of CLOSE
+   a - administer (perform SETACL/DELETEACL/GETACL/LISTRIGHTS)
+
+2.1.1.  Obsolete Rights
+
+   Due to ambiguity in RFC 2086, some existing RFC 2086 server
+   implementations use the "c" right to control the DELETE command.
+   Others chose to use the "d" right to control the DELETE command.  For
+   the former group, let's define the "create" right as union of the "k"
+   and "x" rights, and the "delete" right as union of the "e" and "t"
+   rights.  For the latter group, let's define the "create" rights as a
+   synonym to the "k" right, and the "delete" right as union of the "e",
+   "t", and "x" rights.
+
+   For compatibility with RFC 2086, this section defines two virtual
+   rights "d" and "c".
+
+   If a client includes the "d" right in a rights list, then it MUST be
+   treated as if the client had included every member of the "delete"
+   right.  (It is not an error for a client to specify both the "d"
+   right and one or more members of the "delete" right, but the effect
+   is no different than if just the "d" right or all members of the
+   "delete" right had been specified.)
+
+
+
+Melnikov                    Standards Track                     [Page 5]
+
+RFC 4314                        IMAP ACL                   December 2005
+
+
+   When any of the "delete" member rights is set in a list of rights,
+   the server MUST also include the "d" right when returning the list in
+   a MYRIGHTS or ACL response.  This is to enable older clients
+   conforming to RFC 2086 to work with newer servers. (*)
+
+   Example:    C: A001 SeTacl INBOX/Drafts David lrswida
+               S: A001 OK Setacl complete
+
+   The client has specified the "d" right in the SETACL command above
+   and it expands to "et" on the server:
+
+               C: A002 getacl INBOX/Drafts
+               S: * ACL INBOX Fred rwipslxcetda David lrswideta
+               S: A002 OK Getacl complete
+
+   If the identifier specified in the LISTRIGHTS command can be granted
+   any of the "delete" member rights on a mailbox, then the server MUST
+   include the "d" right in the corresponding LISTRIGHTS response. (*)
+   If the member rights aren't tied to non-member rights, then the "d"
+   right is returned by itself in the LISTRIGHTS response.  If any of
+   the member rights needs to be tied to one (or more) non-member right,
+   then the "d" right and all of the member rights need to be tied to
+   the same non-member right(s) (**).
+
+   If a client includes the "c" right in a rights list, then it MUST be
+   treated as if the client had included every member of the "create"
+   right.  (It is not an error for a client to specify both the "c"
+   right and one or more members of the "create" right, but the effect
+   is no different than if just the "c" right or all members of the
+   "create" right had been specified.)
+
+   When any of the "create" member rights is set in a list of rights,
+   the server MUST also include the "c" right when returning the list in
+   a MYRIGHTS or ACL response.  This is to enable older clients
+   conforming to RFC 2086 to work with newer servers. (*)
+
+   Example:    C: A003 Setacl INBOX/Drafts Byron lrswikda
+               S: A001 OK Setacl complete
+               C: A002 getAcl INBOX/Drafts
+               S: * ACL INBOX Fred rwipslxcetda Byron lrswikcdeta
+               S: A002 OK Getacl complete
+
+   The client has specified the "d" right in the SETACL command above
+   and it expands to "et" on the server: As the client has specified the
+   "k" right (which is a member of the "c" right), the server also
+   returns the "c" right.
+
+
+
+
+
+Melnikov                    Standards Track                     [Page 6]
+
+RFC 4314                        IMAP ACL                   December 2005
+
+
+   If the identifier specified in the LISTRIGHTS command can be granted
+   any of the "create" member rights on a mailbox, then the server MUST
+   include the "c" right in the corresponding LISTRIGHTS response. (*)
+   If the member rights aren't tied to non-member rights, then the "c"
+   right is returned by itself in the LISTRIGHTS response.  If any of
+   the member rights needs to be tied to one (or more) non-member right,
+   then the "c" right and all of the member rights need to be tied to
+   the same non-member right(s) (**).
+
+   Example: The server that ties the rights as follows:
+
+               lr s w i p k x t
+
+            and c=k
+
+            will return:
+
+               S: * LISTRIGHTS archive/imap anyone ""
+                  lr s w i p k x t c d
+
+   Example: The server that ties the rights as follows:
+
+               lr s w i p k xte
+
+            and c=k
+
+            will return:
+
+               S: * LISTRIGHTS archive/imap anyone ""
+                  lr s w i p k xte c d
+
+   Example: The server that ties the rights as follows:
+
+               lr s w i p k x te
+
+            and c=k
+
+            will return:
+
+               S: * LISTRIGHTS archive/imap anyone ""
+                  lr s w i p k c x te d
+
+   Example: The server that ties the rights as follows:
+
+               lr swte i p k x
+
+            and c=kx
+
+
+
+
+Melnikov                    Standards Track                     [Page 7]
+
+RFC 4314                        IMAP ACL                   December 2005
+
+
+            will return:
+
+               S: * LISTRIGHTS archive/imap anyone ""
+                  lr swted i p k x c
+
+   (*)  Clients conforming to this document MUST ignore the virtual "d"
+        and "c" rights in MYRIGHTS, ACL, and LISTRIGHTS responses.
+
+   (**) The IMAPEXT Working Group has debated this issue in great length
+        and after reviewing existing ACL implementations concluded that
+        this is a reasonable restriction.
+
+2.2.  Rights Defined in RFC 2086
+
+   The "RIGHTS=" capability MUST NOT include any of the rights defined
+   in RFC 2086: "l", "r", "s", "w", "i", "p", "a", "c", "d", and the
+   digits ("0" .. "9").
+
+3.  Access control management commands and responses
+
+   Servers, when processing a command that has an identifier as a
+   parameter (i.e., any of SETACL, DELETEACL, and LISTRIGHTS commands),
+   SHOULD first prepare the received identifier using "SASLprep" profile
+   [SASLprep] of the "stringprep" algorithm [Stringprep].  If the
+   preparation of the identifier fails or results in an empty string,
+   the server MUST refuse to perform the command with a BAD response.
+   Note that Section 6 recommends additional identifier's verification
+   steps.
+
+3.1.  SETACL Command
+
+   Arguments:  mailbox name
+               identifier
+               access right modification
+
+   Data:       no specific data for this command
+
+   Result:     OK - setacl completed
+               NO - setacl failure: can't set acl
+               BAD - arguments invalid
+
+   The SETACL command changes the access control list on the specified
+   mailbox so that the specified identifier is granted permissions as
+   specified in the third argument.
+
+   The third argument is a string containing an optional plus ("+") or
+   minus ("-") prefix, followed by zero or more rights characters.  If
+   the string starts with a plus, the following rights are added to any
+
+
+
+Melnikov                    Standards Track                     [Page 8]
+
+RFC 4314                        IMAP ACL                   December 2005
+
+
+   existing rights for the identifier.  If the string starts with a
+   minus, the following rights are removed from any existing rights for
+   the identifier.  If the string does not start with a plus or minus,
+   the rights replace any existing rights for the identifier.
+
+   Note that an unrecognized right MUST cause the command to return the
+   BAD response.  In particular, the server MUST NOT silently ignore
+   unrecognized rights.
+
+   Example:    C: A001 GETACL INBOX/Drafts
+               S: * ACL INBOX/Drafts Fred rwipslxetad Chris lrswi
+               S: A001 OK Getacl complete
+               C: A002 SETACL INBOX/Drafts Chris +cda
+               S: A002 OK Setacl complete
+               C: A003 GETACL INBOX/Drafts
+               S: * ACL INBOX/Drafts Fred rwipslxetad Chris lrswicdakxet
+               S: A003 OK Getacl complete
+
+
+               C: A035 SETACL INBOX/Drafts John lrQswicda
+               S: A035 BAD Uppercase rights are not allowed
+
+
+               C: A036 SETACL INBOX/Drafts John lrqswicda
+               S: A036 BAD The q right is not supported
+
+3.2.  DELETEACL Command
+
+   Arguments:  mailbox name
+               identifier
+
+   Data:       no specific data for this command
+
+   Result:     OK - deleteacl completed
+               NO - deleteacl failure: can't delete acl
+              BAD - arguments invalid
+
+   The DELETEACL command removes any <identifier,rights> pair for the
+   specified identifier from the access control list for the specified
+   mailbox.
+
+   Example:    C: B001 getacl INBOX
+               S: * ACL INBOX Fred rwipslxetad -Fred wetd $team w
+               S: B001 OK Getacl complete
+               C: B002 DeleteAcl INBOX Fred
+               S: B002 OK Deleteacl complete
+
+
+
+
+
+Melnikov                    Standards Track                     [Page 9]
+
+RFC 4314                        IMAP ACL                   December 2005
+
+
+               C: B003 GETACL INBOX
+               S: * ACL INBOX -Fred wetd $team w
+               S: B003 OK Getacl complete
+
+3.3.  GETACL Command
+
+   Arguments:  mailbox name
+
+   Data:       untagged responses: ACL
+
+   Result:     OK - getacl completed
+               NO - getacl failure: can't get acl
+              BAD - arguments invalid
+
+   The GETACL command returns the access control list for mailbox in an
+   untagged ACL response.
+
+   Some implementations MAY permit multiple forms of an identifier to
+   reference the same IMAP account.  Usually, such implementations will
+   have a canonical form that is stored internally.  An ACL response
+   caused by a GETACL command MAY include a canonicalized form of the
+   identifier that might be different from the one used in the
+   corresponding SETACL command.
+
+   Example:    C: A002 GETACL INBOX
+               S: * ACL INBOX Fred rwipsldexta
+               S: A002 OK Getacl complete
+
+3.4.  LISTRIGHTS Command
+
+   Arguments:  mailbox name
+               identifier
+
+   Data:       untagged responses: LISTRIGHTS
+
+   Result:     OK - listrights completed
+               NO - listrights failure: can't get rights list
+               BAD - arguments invalid
+
+   The LISTRIGHTS command takes a mailbox name and an identifier and
+   returns information about what rights can be granted to the
+   identifier in the ACL for the mailbox.
+
+   Some implementations MAY permit multiple forms of an identifier to
+   reference the same IMAP account.  Usually, such implementations will
+   have a canonical form that is stored internally.  A LISTRIGHTS
+
+
+
+
+
+Melnikov                    Standards Track                    [Page 10]
+
+RFC 4314                        IMAP ACL                   December 2005
+
+
+   response caused by a LISTRIGHTS command MUST always return the same
+   form of an identifier as specified by the client.  This is to allow
+   the client to correlate the response with the command.
+
+   Example:    C: a001 LISTRIGHTS ~/Mail/saved smith
+               S: * LISTRIGHTS ~/Mail/saved smith la r swicdkxte
+               S: a001 OK Listrights completed
+
+   Example:    C: a005 listrights archive/imap anyone
+               S: * LISTRIGHTS archive.imap anyone ""
+                  l r s w i p k x t e c d a 0 1 2 3 4 5 6 7 8 9
+               S: a005 Listrights successful
+
+3.5.  MYRIGHTS Command
+
+   Arguments:  mailbox name
+
+   Data:       untagged responses: MYRIGHTS
+
+   Result:     OK - myrights completed
+               NO - myrights failure: can't get rights
+               BAD - arguments invalid
+
+   The MYRIGHTS command returns the set of rights that the user has to
+   mailbox in an untagged MYRIGHTS reply.
+
+   Example:    C: A003 MYRIGHTS INBOX
+               S: * MYRIGHTS INBOX rwiptsldaex
+               S: A003 OK Myrights complete
+
+3.6.  ACL Response
+
+   Data:       mailbox name
+               zero or more identifier rights pairs
+
+   The ACL response occurs as a result of a GETACL command.  The first
+   string is the mailbox name for which this ACL applies.  This is
+   followed by zero or more pairs of strings; each pair contains the
+   identifier for which the entry applies followed by the set of rights
+   that the identifier has.
+
+   Section 2.1.1 details additional server requirements related to
+   handling of the virtual "d" and "c" rights.
+
+
+
+
+
+
+
+
+Melnikov                    Standards Track                    [Page 11]
+
+RFC 4314                        IMAP ACL                   December 2005
+
+
+3.7.  LISTRIGHTS Response
+
+   Data:       mailbox name
+               identifier
+               required rights
+               list of optional rights
+
+   The LISTRIGHTS response occurs as a result of a LISTRIGHTS command.
+   The first two strings are the mailbox name and identifier for which
+   this rights list applies.  Following the identifier is a string
+   containing the (possibly empty) set of rights the identifier will
+   always be granted in the mailbox.
+
+   Following this are zero or more strings each containing a set of
+   rights the identifier can be granted in the mailbox.  Rights
+   mentioned in the same string are tied together.  The server MUST
+   either grant all tied rights to the identifier in the mailbox or
+   grant none.  Section 2.1.1 details additional server requirements
+   related to handling of the virtual "d" and "c" rights.
+
+   The same right MUST NOT be listed more than once in the LISTRIGHTS
+   command.
+
+3.8.  MYRIGHTS Response
+
+   Data:       mailbox name
+               rights
+
+   The MYRIGHTS response occurs as a result of a MYRIGHTS command.  The
+   first string is the mailbox name for which these rights apply.  The
+   second string is the set of rights that the client has.
+
+   Section 2.1.1 details additional server requirements related to
+   handling of the virtual "d" and "c" rights.
+
+4.  Rights Required to Perform Different IMAP4rev1 Commands
+
+   Before executing a command, an ACL-compliant server MUST check which
+   rights are required to perform it.  This section groups command by
+   functions they perform and list the rights required.  It also gives
+   the detailed description of any special processing required.
+
+   For the purpose of this section the UID counterpart of a command is
+   considered to be the same command, e.g., both UID COPY and COPY
+   commands require the same set of rights.
+
+
+
+
+
+
+Melnikov                    Standards Track                    [Page 12]
+
+RFC 4314                        IMAP ACL                   December 2005
+
+
+   The table below summarizes different rights or their combinations
+   that are required in order to perform different IMAP operations.  As
+   it is not always possible to express complex right checking and
+   interactions, the description after the table should be used as the
+   primary reference.
+
+   +-------------------+---+---+---+---+---+---+---+---+---+---+---+---+
+   |Operations\Rights  | l | r | s | w | i | k | x | t | e | a |Any|Non|
+   +-------------------+---+---+---+---+---+---+---+---+---+---+---+---+
+   |                  commands in authenticated state                  |
+   +-------------------------------------------------------------------+
+   |      LIST         | + |   |   |   |   |   |   |   |   |   |   |   |
+   |   SUBSCRIBE       | * |   |   |   |   |   |   |   |   |   |   | * |
+   |  UNSUBSCRIBE      |   |   |   |   |   |   |   |   |   |   |   | + |
+   |      LSUB         | * |   |   |   |   |   |   |   |   |   |   | * |
+   |CREATE (for parent)|   |   |   |   |   | + |   |   |   |   |   |   |
+   |     DELETE        |   | ? |   |   |   |   | + | ? | ? |   |   |   |
+   |     RENAME        |   |   |   |   |   | + | + |   |   |   |   |   |
+   |  SELECT/EXAMINE   |   | + |   |   |   |   |   |   |   |   |   |   |
+   |      STATUS       |   | + |   |   |   |   |   |   |   |   |   |   |
+   |  SETACL/DELETEACL |   |   |   |   |   |   |   |   |   | + |   |   |
+   | GETACL/LISTRIGHTS |   |   |   |   |   |   |   |   |   | + |   |   |
+   |     MYRIGHTS      |   |   |   |   |   |   |   |   |   |   | + |   |
+   |      APPEND       |   |   | ? | ? | + |   |   | ? |   |   |   |   |
+   +-------------------------------------------------------------------+
+   |                     commands in selected state                    |
+   +-------------------------------------------------------------------+
+   |       COPY        |   |   | ? | ? | + |   |   | ? |   |   |   |   |
+   |     EXPUNGE       |   |   |   |   |   |   |   |   | + |   |   |   |
+   |      CLOSE        |   |   |   |   |   |   |   |   | ? |   |   |   |
+   |      FETCH        |   |   | ? |   |   |   |   |   |   |   |   |   |
+   |   STORE flags     |   |   | ? | ? |   |   |   | ? |   |   |   |   |
+   +-------------------+---+---+---+---+---+---+---+---+---+---+---+---+
+
+   Note: for all commands in the selected state, the "r" is implied,
+   because it is required to SELECT/EXAMINE a mailbox.  Servers are not
+   required to check presence of the "r" right once a mailbox is
+   successfully selected.
+
+   Legend:
+    +     - The right is required
+    *     - Only one of the rights marked with * is required
+            (see description below)
+    ?     - The right is OPTIONAL (see description below)
+    "Any" - at least one of the "l", "r", "i", "k", "x", "a" rights is
+            required
+    "Non" - No rights required to perform the command
+
+
+
+
+Melnikov                    Standards Track                    [Page 13]
+
+RFC 4314                        IMAP ACL                   December 2005
+
+
+   Listing and subscribing/unsubscribing mailboxes:
+      LIST - "l" right is required.  However, unlike other commands
+      (e.g., SELECT) the server MUST NOT return a NO response if it
+      can't list a mailbox.
+      Note that if the user has "l" right to a mailbox "A/B", but not to
+      its parent mailbox "A", the LIST command should behave as if the
+      mailbox "A" doesn't exist, for example:
+
+               C: A777 LIST "" *
+               S: * LIST (\NoInferiors) "/" "A/B"
+               S: * LIST () "/" "C"
+               S: * LIST (\NoInferiors) "/" "C/D"
+               S: A777 OK LIST completed
+
+
+      SUBSCRIBE - "l" right is required only if the server checks for
+      mailbox existence when performing SUBSCRIBE.
+
+      UNSUBSCRIBE - no rights required to perform this operation.
+
+      LSUB - "l" right is required only if the server checks for mailbox
+      existence when performing SUBSCRIBE.  However, unlike other
+      commands (e.g., SELECT) the server MUST NOT return a NO response
+      if it can't list a subscribed mailbox.
+
+   Mailbox management:
+      CREATE - "k" right on a nearest existing parent mailbox.  When a
+      new mailbox is created, it SHOULD inherit the ACL from the parent
+      mailbox (if one exists) in the defined hierarchy.
+
+      DELETE - "x" right on the mailbox.  Note that some servers don't
+      allow to delete a non-empty mailbox.  If this is the case, the
+      user would also need "r", "e", and "t" rights, in order to open
+      the mailbox and empty it.
+
+      The DELETE command MUST delete the ACL associated with the deleted
+      mailbox.
+
+      RENAME - Moving a mailbox from one parent to another requires the
+      "x" right on the mailbox itself and the "k" right for the new
+      parent.  For example, if the user wants to rename the mailbox
+      named "A/B/C" to "D/E", the user must have the "x" right for the
+      mailbox "A/B/C" and the "k" right for the mailbox "D".
+      The RENAME command SHOULD NOT change the ACLs on the renamed
+      mailbox and submailboxes.
+
+
+
+
+
+
+Melnikov                    Standards Track                    [Page 14]
+
+RFC 4314                        IMAP ACL                   December 2005
+
+
+   Copying or appending messages:
+      Before performing a COPY/APPEND command, the server MUST check if
+      the user has "i" right for the target mailbox.  If the user
+      doesn't have "i" right, the operation fails.  Otherwise for each
+      copied/appended message the server MUST check if the user has
+         "t" right - when the message has \Deleted flag set
+         "s" right - when the message has \Seen flag set
+         "w" right - for all other message flags.
+      Only when the user has a particular right are the corresponding
+      flags stored for the newly created message.  The server MUST NOT
+      fail a COPY/APPEND if the user has no rights to set a particular
+      flag.
+
+   Example:    C: A003 MYRIGHTS TargetMailbox
+               S: * MYRIGHTS TargetMailbox rwis
+               S: A003 OK Myrights complete
+
+               C: A004 FETCH 1:3 (FLAGS)
+               S: * 1 FETCH (FLAGS (\Draft \Deleted)
+               S: * 2 FETCH (FLAGS (\Answered)
+               S: * 3 FETCH (FLAGS ($Forwarded \Seen)
+               S: A004 OK Fetch Completed
+
+               C: A005 COPY 1:3 TargetMailbox
+               S: A005 OK Copy completed
+
+               C: A006 SELECT TargetMailbox
+                  ...
+               S: A006 Select Completed
+
+      Let's assume that the copied messages received message numbers
+      77:79.
+
+               C: A007 FETCH 77:79 (FLAGS)
+               S: * 77 FETCH (FLAGS (\Draft))
+               S: * 78 FETCH (FLAGS (\Answered))
+               S: * 79 FETCH (FLAGS ($Forwarded \Seen))
+               S: A007 OK Fetch Completed
+
+      \Deleted flag was lost on COPY, as the user has no "t" right in
+      the target mailbox.
+      If the MYRIGHTS command with the tag A003 would have returned:
+
+               S: * MYRIGHTS TargetMailbox rsti
+
+      the response from the FETCH with the tag A007 would have been:
+
+               C: A007 FETCH 77:79 (FLAGS)
+
+
+
+Melnikov                    Standards Track                    [Page 15]
+
+RFC 4314                        IMAP ACL                   December 2005
+
+
+               S: * 77 FETCH (FLAGS (\Deleted))
+               S: * 78 FETCH (FLAGS ())
+               S: * 79 FETCH (FLAGS (\Seen))
+               S: A007 OK Fetch Completed
+
+      In the latter case, \Answered, $Forwarded, and \Draft flags were
+      lost on COPY, as the user has no "w" right in the target mailbox.
+
+   Expunging the selected mailbox:
+      EXPUNGE - "e" right on the selected mailbox.
+
+      CLOSE - "e" right on the selected mailbox.  If the server is
+      unable to expunge the mailbox because the user doesn't have the
+      "e" right, the server MUST ignore the expunge request, close the
+      mailbox, and return the tagged OK response.
+
+   Fetch information about a mailbox and its messages:
+      SELECT/EXAMINE/STATUS - "r" right on the mailbox.
+
+      FETCH - A FETCH request that implies setting \Seen flag MUST NOT
+      set it, if the current user doesn't have "s" right.
+
+   Changing flags:
+      STORE - the server MUST check if the user has
+         "t" right - when the user modifies \Deleted flag
+         "s" right - when the user modifies \Seen flag
+         "w" right - for all other message flags.
+      STORE operation SHOULD NOT fail if the user has rights to modify
+      at least one flag specified in the STORE, as the tagged NO
+      response to a STORE command is not handled very well by deployed
+      clients.
+
+   Changing ACLs:
+      SETACL/DELETEACL - "a" right on the mailbox.
+
+   Reading ACLs:
+      GETACL - "a" right on the mailbox.
+
+      MYRIGHTS - any of the following rights is required to perform the
+      operation: "l", "r", "i", "k", "x", "a".
+
+      LISTRIGHTS - "a" right on the mailbox.
+
+
+
+
+
+
+
+
+
+Melnikov                    Standards Track                    [Page 16]
+
+RFC 4314                        IMAP ACL                   December 2005
+
+
+5.  Other Considerations
+
+5.1.  Additional Requirements and Implementation Notes
+
+5.1.1.  Servers
+
+   This document defines an additional capability that is used to
+   announce the list of extra rights (excluding the ones defined in RFC
+   2086) supported by the server.  The set of rights MUST include "t",
+   "e", "x", and "k".  Note that the extra rights can appear in any
+   order.
+
+   Example:    C: 1 capability
+               S: * CAPABILITY IMAP4REV1 STARTTLS LITERAL+
+                  ACL RIGHTS=texk
+               S: 1 OK completed
+
+   Any server implementing an ACL extension MUST accurately reflect the
+   current user's rights in FLAGS and PERMANENTFLAGS responses.
+
+   Example:    C: A142 SELECT INBOX
+               S: * 172 EXISTS
+               S: * 1 RECENT
+               S: * OK [UNSEEN 12] Message 12 is first unseen
+               S: * OK [UIDVALIDITY 3857529045] UIDs valid
+               S: * OK [UIDNEXT 4392] Predicted next UID
+               S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
+               S: * OK [PERMANENTFLAGS (\Seen \Answered \Flagged \*)] L
+               S: A142 OK [READ-WRITE] SELECT completed
+               C: A143 MYRIGHTS INBOX
+               S: * MYRIGHTS INBOX lrwis
+               S: A143 OK completed
+
+   Note that in order to get better performance the client MAY pipeline
+   SELECT and MYRIGHTS commands:
+
+               C: A142 SELECT INBOX
+               C: A143 MYRIGHTS INBOX
+               S: * 172 EXISTS
+               S: * 1 RECENT
+               S: * OK [UNSEEN 12] Message 12 is first unseen
+               S: * OK [UIDVALIDITY 3857529045] UIDs valid
+               S: * OK [UIDNEXT 4392] Predicted next UID
+               S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
+               S: * OK [PERMANENTFLAGS (\Seen \Answered \Flagged \*)] L
+               S: A142 OK [READ-WRITE] SELECT completed
+               S: * MYRIGHTS INBOX lrwis
+               S: A143 OK completed
+
+
+
+Melnikov                    Standards Track                    [Page 17]
+
+RFC 4314                        IMAP ACL                   December 2005
+
+
+   Servers MAY cache the rights a user has on a mailbox when the mailbox
+   is selected, so that if a client's rights on a mailbox are changed
+   with SETACL or DELETEACL, commands specific to the selected state
+   (e.g., STORE, EXPUNGE) might not reflect the changed rights until the
+   mailbox is re-selected.  If the server checks the rights on each
+   command, then it SHOULD send FLAGS and PERMANENTFLAGS responses if
+   they have changed.  If such server detects that the user no longer
+   has read access to the mailbox, it MAY send an untagged BYE response
+   and close connection.  It MAY also refuse to execute all commands
+   specific to the selected state until the mailbox is closed; however,
+   server implementors should note that most clients don't handle NO
+   responses very well.
+
+   An ACL server MAY modify one or more ACLs for one or more identifiers
+   as a side effect of modifying the ACL specified in a
+   SETACL/DELETEACL.  If the server does that, it MUST send untagged ACL
+   response(s) to notify the client about the changes made.
+
+   An ACL server implementation MUST treat received ACL modification
+   commands as a possible ambiguity with respect to subsequent commands
+   affected by the ACL, as described in Section 5.5 of [IMAP4].  Hence a
+   pipeline SETACL + MYRIGHTS is an ambiguity with respect to the
+   server, meaning that the server must execute the SETACL command to
+   completion before the MYRIGHTS.  However, clients are permitted to
+   send such a pipeline.
+
+5.1.2.  Clients
+
+   The following requirement is put on clients in order to allow for
+   future extensibility.  A client implementation that allows a user to
+   read and update ACLs MUST preserve unrecognized rights that it
+   doesn't allow the user to change.  That is, if the client
+
+   1) can read ACLs
+    and
+   2) can update ACLs
+    but
+   3) doesn't allow the user to change the rights the client doesn't
+   recognize, then it MUST preserve unrecognized rights.
+
+   Otherwise the client could risk unintentionally removing permissions
+   it doesn't understand.
+
+
+
+
+
+
+
+
+
+Melnikov                    Standards Track                    [Page 18]
+
+RFC 4314                        IMAP ACL                   December 2005
+
+
+5.2.  Mapping of ACL Rights to READ-WRITE and READ-ONLY Response Codes
+
+   A particular ACL server implementation MAY allow "shared multiuser
+   access" to some mailboxes.  "Shared multiuser access" to a mailbox
+   means that multiple different users are able to access the same
+   mailbox, if they have proper access rights.  "Shared multiuser
+   access" to the mailbox doesn't mean that the ACL for the mailbox is
+   currently set to allow access by multiple users.  Let's denote a
+   "shared multiuser write access" as a "shared multiuser access" when a
+   user can be granted flag modification rights (any of "w", "s", or
+   "t").
+
+   Section 4 describes which rights are required for modifying different
+   flags.
+
+   If the ACL server implements some flags as shared for a mailbox
+   (i.e., the ACL for the mailbox MAY be set up so that changes to those
+   flags are visible to another user), let's call the set of rights
+   associated with these flags (as described in Section 4) for that
+   mailbox collectively as "shared flag rights".  Note that the "shared
+   flag rights" set MAY be different for different mailboxes.
+
+   If the server doesn't support "shared multiuser write access" to a
+   mailbox or doesn't implement shared flags on the mailbox, "shared
+   flag rights" for the mailbox is defined to be the empty set.
+
+   Example 1: Mailbox "banan" allows "shared multiuser write access" and
+              implements flags \Deleted, \Answered, and $MDNSent as
+              shared flags. "Shared flag rights" for the mailbox "banan"
+              is a set containing flags "t" (because system flag
+              \Deleted requires "t" right) and "w" (because both
+              \Answered and $MDNSent require "w" right).
+
+   Example 2: Mailbox "apple" allows "shared multiuser write access" and
+              implements \Seen system flag as shared flag. "Shared flag
+              rights" for the mailbox "apple" contains "s" right
+              because system flag \Seen requires "s" right.
+
+   Example 3: Mailbox "pear" allows "shared multiuser write access" and
+              implements flags \Seen, \Draft as shared flags. "Shared
+              flag rights" for the mailbox "apple" is a set containing
+              flags "s" (because system flag \Seen requires "s" right)
+              and "w" (because system flag \Draft requires "w" right).
+
+   The server MUST include a READ-ONLY response code in the tagged OK
+   response to a SELECT command if none of the following rights is
+   granted to the current user:
+
+
+
+
+Melnikov                    Standards Track                    [Page 19]
+
+RFC 4314                        IMAP ACL                   December 2005
+
+
+    "i", "e", and "shared flag rights"(***).
+
+   The server SHOULD include a READ-WRITE response code in the tagged OK
+   response if at least one of the "i", "e", or "shared flag
+   rights"(***) is granted to the current user.
+
+   (***) Note that a future extension to this document can extend the
+   list of rights that causes the server to return the READ-WRITE
+   response code.
+
+   Example 1 (continued): The user that has "lrs" rights for the mailbox
+                          "banan".  The server returns READ-ONLY
+                          response code on SELECT, as none of "iewt"
+                          rights is granted to the user.
+
+   Example 2 (continued): The user that has "rit" rights for the mailbox
+                          "apple".  The server returns READ-WRITE
+                          response code on SELECT, as the user has "i"
+                          right.
+
+   Example 3 (continued): The user that has "rset" rights for the
+                          mailbox "pear".  The server returns READ-WRITE
+                          response code on SELECT, as the user has "e"
+                          and "s" rights.
+
+6.  Security Considerations
+
+   An implementation MUST make sure the ACL commands themselves do not
+   give information about mailboxes with appropriately restricted ACLs.
+   For example, when a user agent executes a GETACL command on a mailbox
+   that the user has no permission to LIST, the server would respond to
+   that request with the same error that would be used if the mailbox
+   did not exist, thus revealing no existence information, much less the
+   mailbox's ACL.
+
+   IMAP clients implementing ACL that are able to modify ACLs SHOULD
+   warn a user that wants to give full access (or even just the "a"
+   right) to the special identifier "anyone".
+
+   This document relies on [SASLprep] to describe steps required to
+   perform identifier canonicalization (preparation).  The preparation
+   algorithm in SASLprep was specifically designed such that its output
+   is canonical, and it is well-formed.  However, due to an anomaly
+   [PR29] in the specification of Unicode normalization, canonical
+   equivalence is not guaranteed for a select few character sequences.
+   Identifiers prepared with SASLprep can be stored and returned by an
+   ACL server.  The anomaly affects ACL manipulation and evaluation of
+   identifiers containing the selected character sequences.  These
+
+
+
+Melnikov                    Standards Track                    [Page 20]
+
+RFC 4314                        IMAP ACL                   December 2005
+
+
+   sequences, however, do not appear in well-formed text.  In order to
+   address this problem, an ACL server MAY reject identifiers containing
+   sequences described in [PR29] by sending the tagged BAD response.
+   This is in addition to the requirement to reject identifiers that
+   fail SASLprep preparation as described in Section 3.
+
+   Other security considerations described in [IMAP4] are relevant to
+   this document.  In particular, ACL information is sent in the clear
+   over the network unless confidentiality protection is negotiated.
+
+   This can be accomplished either by the use of STARTTLS, negotiated
+   privacy protection in the AUTHENTICATE command, or some other
+   protection mechanism.
+
+7.  Formal Syntax
+
+   Formal syntax is defined using ABNF [ABNF], extending the ABNF rules
+   in Section 9 of [IMAP4].  Elements not defined here can be found in
+   [ABNF] and [IMAP4].
+
+   Except as noted otherwise, all alphabetic characters are case
+   insensitive.  The use of uppercase or lowercase characters to define
+   token strings is for editorial clarity only.  Implementations MUST
+   accept these strings in a case-insensitive fashion.
+
+   LOWER-ALPHA     =  %x61-7A   ;; a-z
+
+   acl-data        = "ACL" SP mailbox *(SP identifier SP
+                       rights)
+
+   capability      =/ rights-capa
+                       ;;capability is defined in [IMAP4]
+
+   command-auth    =/ setacl / deleteacl / getacl /
+                       listrights / myrights
+                       ;;command-auth is defined in [IMAP4]
+
+   deleteacl       = "DELETEACL" SP mailbox SP identifier
+
+   getacl          = "GETACL" SP mailbox
+
+   identifier      = astring
+
+   listrights      = "LISTRIGHTS" SP mailbox SP identifier
+
+   listrights-data = "LISTRIGHTS" SP mailbox SP identifier
+                           SP rights *(SP rights)
+
+
+
+
+Melnikov                    Standards Track                    [Page 21]
+
+RFC 4314                        IMAP ACL                   December 2005
+
+
+   mailbox-data    =/ acl-data / listrights-data / myrights-data
+                       ;;mailbox-data is defined in [IMAP4]
+
+   mod-rights      = astring
+                       ;; +rights to add, -rights to remove
+                       ;; rights to replace
+
+   myrights        = "MYRIGHTS" SP mailbox
+
+   myrights-data   = "MYRIGHTS" SP mailbox SP rights
+
+   new-rights      = 1*LOWER-ALPHA
+                       ;; MUST include "t", "e", "x", and "k".
+                       ;; MUST NOT include standard rights listed
+                       ;; in section 2.2
+
+   rights          = astring
+                       ;; only lowercase ASCII letters and digits
+                       ;; are allowed.
+
+   rights-capa     = "RIGHTS=" new-rights
+                       ;; RIGHTS=... capability
+
+   setacl          = "SETACL" SP mailbox SP identifier
+                       SP mod-rights
+
+8.  IANA Considerations
+
+   IMAP4 capabilities are registered by publishing a standards-track or
+   IESG-approved experimental RFC.  The registry is currently located
+   at:
+
+      http://www.iana.org/assignments/imap4-capabilities
+
+   This document defines the RIGHTS= IMAP capability.  IANA has added
+   this capability to the registry.
+
+9.  Internationalization Considerations
+
+   Section 3 states requirements on servers regarding
+   internationalization of identifiers.
+
+
+
+
+
+
+
+
+
+
+Melnikov                    Standards Track                    [Page 22]
+
+RFC 4314                        IMAP ACL                   December 2005
+
+
+Appendix A.  Changes since RFC 2086
+
+   1.   Changed the charset of "identifier" from US-ASCII to UTF-8.
+   2.   Specified that mailbox deletion is controlled by the "x" right
+        and EXPUNGE is controlled by the "e" right.
+   3.   Added the "t" right that controls STORE \Deleted.  Redefined the
+        "d" right to be a macro for "e", "t", and possibly "x".
+   4.   Added the "k" right that controls CREATE.  Redefined the "c"
+        right to be a macro for "k" and possibly "x".
+   5.   Specified that the "a" right also controls DELETEACL.
+   6.   Specified that the "r" right also controls STATUS.
+   7.   Removed the requirement to check the "r" right for CHECK, SEARCH
+        and FETCH, as this is required for SELECT/EXAMINE to be
+        successful.
+   8.   LISTRIGHTS requires the "a" right on the mailbox (same as
+        SETACL).
+   9.   Deleted "PARTIAL", this is a deprecated feature of RFC 1730.
+   10.  Specified that the "w" right controls setting flags other than
+        \Seen and \Deleted on APPEND.  Also specified that the "s" right
+        controls the \Seen flag and that the "t" right controls the
+        \Deleted flag.
+   11.  Specified that SUBSCRIBE is NOT allowed with the "r" right.
+   12.  Specified that the "l" right controls SUBSCRIBE.
+   13.  GETACL is NOT allowed with the "r" right, even though there are
+        several implementations that allows that.  If a user only has
+        "r" right, GETACL can disclose information about identifiers
+        existing on the mail system.
+   14.  Clarified that RENAME requires the "k" right for the new parent
+        and the "x" right for the old name.
+   15.  Added new section that describes which rights are required
+        and/or checked when performing various IMAP commands.
+   16.  Added mail client security considerations when dealing with
+        special identifier "anyone".
+   17.  Clarified that negative rights are not the same as DELETEACL.
+   18.  Added "Compatibility with RFC 2086" section.
+   19.  Added section about mapping of ACL rights to READ-WRITE and
+        READ-ONLY response codes.
+   20.  Changed BNF to ABNF.
+   21.  Added "Implementation Notes" section.
+   22.  Updated "References" section.
+   23.  Added more examples.
+   24.  Clarified when the virtual "c" and "d" rights are returned in
+        ACL, MYRIGHTS, and LISTRIGHTS responses.
+
+
+
+
+
+
+
+
+Melnikov                    Standards Track                    [Page 23]
+
+RFC 4314                        IMAP ACL                   December 2005
+
+
+Appendix B.  Compatibility with RFC 2086
+
+   This non-normative section gives guidelines as to how an existing RFC
+   2086 server implementation may be updated to comply with this
+   document.
+
+   This document splits the "d" right into several new different rights:
+   "t", "e", and possibly "x" (see Section 2.1.1 for more details).  The
+   "d" right remains for backward-compatibility, but it is a virtual
+   right.  There are two approaches for RFC 2086 server implementors to
+   handle the "d" right and the new rights that have replaced it:
+
+   a.  Tie "t", "e" (and possibly "x) together - almost no changes.
+   b.  Implement separate "x", "t" and "e".  Return the "d" right in a
+       MYRIGHTS response or an ACL response containing ACL information
+       when any of the "t", "e" (and "x") is granted.
+
+   In a similar manner this document splits the "c" right into several
+   new different rights: "k" and possibly "x" (see Section 2.1.1 for
+   more details).  The "c" right remains for backwards-compatibility but
+   it is a virtual right.  Again, RFC 2086 server implementors can
+   choose to tie rights or to implement separate rights, as described
+   above.
+
+   Also check Sections 5.1.1 and 5.1.2, as well as Appendix A, to see
+   other changes required.  Server implementors should check which
+   rights are required to invoke different IMAP4 commands as described
+   in Section 4.
+
+Appendix C.  Known Deficiencies
+
+   This specification has some known deficiencies including:
+
+   1.  This is inadequate to provide complete read-write access to
+       mailboxes protected by Unix-style rights bits because there is no
+       equivalent to "chown" and "chgrp" commands nor is there a good
+       way to discover such limitations are present.
+   2.  Because this extension leaves the specific semantics of how
+       rights are combined by the server as implementation defined, the
+       ability to build a user-friendly interface is limited.
+   3.  Users, groups, and special identifiers (e.g., anyone) exist in
+       the same namespace.
+
+   The work-in-progress "ACL2" extension is intended to redesign this
+   extension to address these deficiencies without the constraint of
+   backward-compatibility and may eventually supercede this facility.
+
+
+
+
+
+Melnikov                    Standards Track                    [Page 24]
+
+RFC 4314                        IMAP ACL                   December 2005
+
+
+   However, RFC 2086 is deployed in multiple implementations so this
+   intermediate step, which fixes the straightforward deficiencies in a
+   backward-compatible fashion, is considered worthwhile.
+
+Appendix D.  Acknowledgements
+
+   This document is a revision of RFC 2086 written by John G. Myers.
+
+   Editor appreciates comments received from Mark Crispin, Chris Newman,
+   Cyrus Daboo, John G. Myers, Dave Cridland, Ken Murchison, Steve Hole,
+   Vladimir Butenko, Larry Greenfield, Robert Siemborski, Harrie
+   Hazewinkel, Philip Guenther, Brian Candler, Curtis King, Lyndon
+   Nerenberg, Lisa Dusseault, Arnt Gulbrandsen, and other participants
+   of the IMAPEXT working group.
+
+Normative References
+
+   [KEYWORDS]   Bradner, S., "Key words for use in RFCs to Indicate
+                Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+   [ABNF]       Crocker, D. and P. Overell, "Augmented BNF for Syntax
+                Specifications: ABNF", RFC 4234, October 2005.
+
+   [IMAP4]      Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
+                4rev1", RFC 3501, March 2003.
+
+   [UTF-8]      Yergeau, F., "UTF-8, a transformation format of ISO
+                10646", STD 63, RFC 3629, November 2003.
+
+   [Stringprep] Hoffman, P. and M. Blanchet, "Preparation of
+                Internationalized Strings ("stringprep")", RFC 3454,
+                December 2002.
+
+   [SASLprep]   Zeilenga, K., "SASLprep: Stringprep Profile for User
+                Names and Passwords", RFC 4013, February 2005.
+
+Informative References
+
+   [RFC2086]    Myers, J., "IMAP4 ACL extension", RFC 2086,
+                January 1997.
+
+   [PR29]       "Public Review Issue #29: Normalization Issue",
+                February 2004,
+                <http://www.unicode.org/review/pr-29.html>.
+
+
+
+
+
+
+
+Melnikov                    Standards Track                    [Page 25]
+
+RFC 4314                        IMAP ACL                   December 2005
+
+
+Author's Address
+
+   Alexey Melnikov
+   Isode Ltd.
+   5 Castle Business Village
+   36 Station Road
+   Hampton, Middlesex  TW12 2BX
+   GB
+
+   EMail: alexey.melnikov@isode.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov                    Standards Track                    [Page 26]
+
+RFC 4314                        IMAP ACL                   December 2005
+
+
+Full Copyright Statement
+
+   Copyright (C) The Internet Society (2005).
+
+   This document is subject to the rights, licenses and restrictions
+   contained in BCP 78, and except as set forth therein, the authors
+   retain all their rights.
+
+   This document and the information contained herein are provided on an
+   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   Intellectual Property Rights or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; nor does it represent that it has
+   made any independent effort to identify any such rights.  Information
+   on the procedures with respect to rights in RFC documents can be
+   found in BCP 78 and BCP 79.
+
+   Copies of IPR disclosures made to the IETF Secretariat and any
+   assurances of licenses to be made available, or the result of an
+   attempt made to obtain a general license or permission for the use of
+   such proprietary rights by implementers or users of this
+   specification can be obtained from the IETF on-line IPR repository at
+   http://www.ietf.org/ipr.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights that may cover technology that may be required to implement
+   this standard.  Please address the information to the IETF at ietf-
+   ipr@ietf.org.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is currently provided by the
+   Internet Society.
+
+
+
+
+
+
+
+Melnikov                    Standards Track                    [Page 27]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc4315.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,451 @@
+
+
+
+
+
+
+Network Working Group                                         M. Crispin
+Request for Comments: 4315                                 December 2005
+Obsoletes: 2359
+Category: Standards Track
+
+
+      Internet Message Access Protocol (IMAP) - UIDPLUS extension
+
+Status of This Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (2005).
+
+Abstract
+
+   The UIDPLUS extension of the Internet Message Access Protocol (IMAP)
+   provides a set of features intended to reduce the amount of time and
+   resources used by some client operations.  The features in UIDPLUS
+   are primarily intended for disconnected-use clients.
+
+1.  Introduction and Overview
+
+   The UIDPLUS extension is present in any IMAP server implementation
+   that returns "UIDPLUS" as one of the supported capabilities to the
+   CAPABILITY command.
+
+   The UIDPLUS extension defines an additional command.  In addition,
+   this document recommends new status response codes in IMAP that
+   SHOULD be returned by all server implementations, regardless of
+   whether or not the UIDPLUS extension is implemented.
+
+   The added facilities of the features in UIDPLUS are optimizations;
+   clients can provide equivalent functionality, albeit less
+   efficiently, by using facilities in the base protocol.
+
+1.1.  Conventions Used in This Document
+
+   In examples, "C:" and "S:" indicate lines sent by the client and
+   server, respectively.
+
+
+
+
+
+Crispin                     Standards Track                     [Page 1]
+
+RFC 4315                IMAP - UIDPLUS Extension           December 2005
+
+
+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+   "SHOULD", "SHOULD NOT", "MAY", and "OPTIONAL" in this document are to
+   be interpreted as described in [KEYWORDS].
+
+   A "UID set" is similar to the [IMAP] sequence set; however, the "*"
+   value for a sequence number is not permitted.
+
+2.  Additional Commands
+
+   The following command definition is an extension to [IMAP] section
+   6.4.
+
+2.1.  UID EXPUNGE Command
+
+   Arguments:  sequence set
+
+   Data:       untagged responses: EXPUNGE
+
+   Result:     OK - expunge completed
+               NO - expunge failure (e.g., permission denied)
+               BAD - command unknown or arguments invalid
+
+      The UID EXPUNGE command permanently removes all messages that both
+      have the \Deleted flag set and have a UID that is included in the
+      specified sequence set from the currently selected mailbox.  If a
+      message either does not have the \Deleted flag set or has a UID
+      that is not included in the specified sequence set, it is not
+      affected.
+
+      This command is particularly useful for disconnected use clients.
+      By using UID EXPUNGE instead of EXPUNGE when resynchronizing with
+      the server, the client can ensure that it does not inadvertantly
+      remove any messages that have been marked as \Deleted by other
+      clients between the time that the client was last connected and
+      the time the client resynchronizes.
+
+      If the server does not support the UIDPLUS capability, the client
+      should fall back to using the STORE command to temporarily remove
+      the \Deleted flag from messages it does not want to remove, then
+      issuing the EXPUNGE command.  Finally, the client should use the
+      STORE command to restore the \Deleted flag on the messages in
+      which it was temporarily removed.
+
+      Alternatively, the client may fall back to using just the EXPUNGE
+      command, risking the unintended removal of some messages.
+
+
+
+
+
+
+Crispin                     Standards Track                     [Page 2]
+
+RFC 4315                IMAP - UIDPLUS Extension           December 2005
+
+
+   Example:    C: A003 UID EXPUNGE 3000:3002
+               S: * 3 EXPUNGE
+               S: * 3 EXPUNGE
+               S: * 3 EXPUNGE
+               S: A003 OK UID EXPUNGE completed
+
+3.  Additional Response Codes
+
+   The following response codes are extensions to the response codes
+   defined in [IMAP] section 7.1.  With limited exceptions, discussed
+   below, server implementations that advertise the UIDPLUS extension
+   SHOULD return these response codes.
+
+   In the case of a mailbox that has permissions set so that the client
+   can COPY or APPEND to the mailbox, but not SELECT or EXAMINE it, the
+   server SHOULD NOT send an APPENDUID or COPYUID response code as it
+   would disclose information about the mailbox.
+
+   In the case of a mailbox that has UIDNOTSTICKY status (as defined
+   below), the server MAY omit the APPENDUID or COPYUID response code as
+   it is not meaningful.
+
+   If the server does not return the APPENDUID or COPYUID response
+   codes, the client can discover this information by selecting the
+   destination mailbox.  The location of messages placed in the
+   destination mailbox by COPY or APPEND can be determined by using
+   FETCH and/or SEARCH commands (e.g., for Message-ID or some unique
+   marker placed in the message in an APPEND).
+
+   APPENDUID
+
+      Followed by the UIDVALIDITY of the destination mailbox and the UID
+      assigned to the appended message in the destination mailbox,
+      indicates that the message has been appended to the destination
+      mailbox with that UID.
+
+      If the server also supports the [MULTIAPPEND] extension, and if
+      multiple messages were appended in the APPEND command, then the
+      second value is a UID set containing the UIDs assigned to the
+      appended messages, in the order they were transmitted in the
+      APPEND command.  This UID set may not contain extraneous UIDs or
+      the symbol "*".
+
+         Note: the UID set form of the APPENDUID response code MUST NOT
+         be used if only a single message was appended.  In particular,
+         a server MUST NOT send a range such as 123:123.  This is
+         because a client that does not support [MULTIAPPEND] expects
+         only a single UID and not a UID set.
+
+
+
+Crispin                     Standards Track                     [Page 3]
+
+RFC 4315                IMAP - UIDPLUS Extension           December 2005
+
+
+      UIDs are assigned in strictly ascending order in the mailbox
+      (refer to [IMAP], section 2.3.1.1) and UID ranges are as in
+      [IMAP]; in particular, note that a range of 12:10 is exactly
+      equivalent to 10:12 and refers to the sequence 10,11,12.
+
+      This response code is returned in a tagged OK response to the
+      APPEND command.
+
+   COPYUID
+
+      Followed by the UIDVALIDITY of the destination mailbox, a UID set
+      containing the UIDs of the message(s) in the source mailbox that
+      were copied to the destination mailbox and containing the UIDs
+      assigned to the copied message(s) in the destination mailbox,
+      indicates that the message(s) have been copied to the destination
+      mailbox with the stated UID(s).
+
+      The source UID set is in the order the message(s) were copied; the
+      destination UID set corresponds to the source UID set and is in
+      the same order.  Neither of the UID sets may contain extraneous
+      UIDs or the symbol "*".
+
+      UIDs are assigned in strictly ascending order in the mailbox
+      (refer to [IMAP], section 2.3.1.1) and UID ranges are as in
+      [IMAP]; in particular, note that a range of 12:10 is exactly
+      equivalent to 10:12 and refers to the sequence 10,11,12.
+
+      This response code is returned in a tagged OK response to the COPY
+      command.
+
+   UIDNOTSTICKY
+
+      The selected mailbox is supported by a mail store that does not
+      support persistent UIDs; that is, UIDVALIDITY will be different
+      each time the mailbox is selected.  Consequently, APPEND or COPY
+      to this mailbox will not return an APPENDUID or COPYUID response
+      code.
+
+      This response code is returned in an untagged NO response to the
+      SELECT command.
+
+         Note: servers SHOULD NOT have any UIDNOTSTICKY mail stores.
+         This facility exists to support legacy mail stores in which it
+         is technically infeasible to support persistent UIDs.  This
+         should be avoided when designing new mail stores.
+
+
+
+
+
+
+Crispin                     Standards Track                     [Page 4]
+
+RFC 4315                IMAP - UIDPLUS Extension           December 2005
+
+
+   Example:    C: A003 APPEND saved-messages (\Seen) {297}
+               C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
+               C: From: Fred Foobar <foobar@example.com>
+               C: Subject: afternoon meeting
+               C: To: mooch@example.com
+               C: Message-Id: <B27397-0100000@example.com>
+               C: MIME-Version: 1.0
+               C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
+               C:
+               C: Hello Joe, do you think we can meet at 3:30 tomorrow?
+               C:
+               S: A003 OK [APPENDUID 38505 3955] APPEND completed
+               C: A004 COPY 2:4 meeting
+               S: A004 OK [COPYUID 38505 304,319:320 3956:3958] Done
+               C: A005 UID COPY 305:310 meeting
+               S: A005 OK No matching messages, so nothing copied
+               C: A006 COPY 2 funny
+               S: A006 OK Done
+               C: A007 SELECT funny
+               S: * 1 EXISTS
+               S: * 1 RECENT
+               S: * OK [UNSEEN 1] Message 1 is first unseen
+               S: * OK [UIDVALIDITY 3857529045] Validity session-only
+               S: * OK [UIDNEXT 2] Predicted next UID
+               S: * NO [UIDNOTSTICKY] Non-persistent UIDs
+               S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
+               S: * OK [PERMANENTFLAGS (\Deleted \Seen)] Limited
+               S: A007 OK [READ-WRITE] SELECT completed
+
+   In this example, A003 and A004 demonstrate successful appending and
+   copying to a mailbox that returns the UIDs assigned to the messages.
+   A005 is an example in which no messages were copied; this is because
+   in A003, we see that message 2 had UID 304, and message 3 had UID
+   319; therefore, UIDs 305 through 310 do not exist (refer to section
+   2.3.1.1 of [IMAP] for further explanation).  A006 is an example of a
+   message being copied that did not return a COPYUID; and, as expected,
+   A007 shows that the mail store containing that mailbox does not
+   support persistent UIDs.
+
+4.  Formal Syntax
+
+   Formal syntax is defined using ABNF [ABNF], which extends the ABNF
+   rules defined in [IMAP].  The IMAP4 ABNF should be imported before
+   attempting to validate these rules.
+
+   append-uid      = uniqueid
+
+   capability      =/ "UIDPLUS"
+
+
+
+Crispin                     Standards Track                     [Page 5]
+
+RFC 4315                IMAP - UIDPLUS Extension           December 2005
+
+
+   command-select  =/ uid-expunge
+
+   resp-code-apnd  = "APPENDUID" SP nz-number SP append-uid
+
+   resp-code-copy  = "COPYUID" SP nz-number SP uid-set SP uid-set
+
+   resp-text-code  =/ resp-code-apnd / resp-code-copy / "UIDNOTSTICKY"
+                     ; incorporated before the expansion rule of
+                     ;  atom [SP 1*<any TEXT-CHAR except "]">]
+                     ; that appears in [IMAP]
+
+   uid-expunge     = "UID" SP "EXPUNGE" SP sequence-set
+
+   uid-set         = (uniqueid / uid-range) *("," uid-set)
+
+   uid-range       = (uniqueid ":" uniqueid)
+                     ; two uniqueid values and all values
+                     ; between these two regards of order.
+                     ; Example: 2:4 and 4:2 are equivalent.
+
+   Servers that support [MULTIAPPEND] will have the following extension
+   to the above rules:
+
+   append-uid      =/ uid-set
+                     ; only permitted if client uses [MULTIAPPEND]
+                     ; to append multiple messages.
+
+5.  Security Considerations
+
+   The COPYUID and APPENDUID response codes return information about the
+   mailbox, which may be considered sensitive if the mailbox has
+   permissions set that permit the client to COPY or APPEND to the
+   mailbox, but not SELECT or EXAMINE it.
+
+   Consequently, these response codes SHOULD NOT be issued if the client
+   does not have access to SELECT or EXAMINE the mailbox.
+
+6.  IANA Considerations
+
+   This document constitutes registration of the UIDPLUS capability in
+   the imap4-capabilities registry, replacing [RFC2359].
+
+7.  Normative References
+
+   [ABNF]        Crocker, D. and P. Overell, "Augmented BNF for Syntax
+                 Specifications: ABNF", RFC 4234, October 2005.
+
+
+
+
+
+Crispin                     Standards Track                     [Page 6]
+
+RFC 4315                IMAP - UIDPLUS Extension           December 2005
+
+
+   [IMAP]        Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL -
+                 VERSION 4rev1", RFC 3501, March 2003.
+
+   [KEYWORDS]    Bradner, S., "Key words for use in RFCs to Indicate
+                 Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+   [MULTIAPPEND] Crispin, M., "Internet Message Access Protocol (IMAP) -
+                 MULTIAPPEND Extension", RFC 3502, March 2003.
+
+8.  Informative References
+
+   [RFC2359]     Myers, J., "IMAP4 UIDPLUS extension", RFC 2359, June
+                 1998.
+
+9.  Changes from RFC 2359
+
+   This document obsoletes [RFC2359].  However, it is based upon that
+   document, and takes substantial text from it (albeit with numerous
+   clarifications in wording).
+
+   [RFC2359] implied that a server must always return COPYUID/APPENDUID
+   data; thus suggesting that in such cases the server should return
+   arbitrary data if the destination mailbox did not support persistent
+   UIDs.  This document adds the UIDNOTSTICKY response code to indicate
+   that a mailbox does not support persistent UIDs, and stipulates that
+   a UIDPLUS server does not return COPYUID/APPENDUID data when the COPY
+   (or APPEND) destination mailbox has UIDNOTSTICKY status.
+
+Author's Address
+
+   Mark R. Crispin
+   Networks and Distributed Computing
+   University of Washington
+   4545 15th Avenue NE
+   Seattle, WA  98105-4527
+
+   Phone: (206) 543-5762
+   EMail: MRC@CAC.Washington.EDU
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                     [Page 7]
+
+RFC 4315                IMAP - UIDPLUS Extension           December 2005
+
+
+Full Copyright Statement
+
+   Copyright (C) The Internet Society (2005).
+
+   This document is subject to the rights, licenses and restrictions
+   contained in BCP 78, and except as set forth therein, the authors
+   retain all their rights.
+
+   This document and the information contained herein are provided on an
+   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   Intellectual Property Rights or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; nor does it represent that it has
+   made any independent effort to identify any such rights.  Information
+   on the procedures with respect to rights in RFC documents can be
+   found in BCP 78 and BCP 79.
+
+   Copies of IPR disclosures made to the IETF Secretariat and any
+   assurances of licenses to be made available, or the result of an
+   attempt made to obtain a general license or permission for the use of
+   such proprietary rights by implementers or users of this
+   specification can be obtained from the IETF on-line IPR repository at
+   http://www.ietf.org/ipr.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights that may cover technology that may be required to implement
+   this standard.  Please address the information to the IETF at ietf-
+   ipr@ietf.org.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is currently provided by the
+   Internet Society.
+
+
+
+
+
+
+
+Crispin                     Standards Track                     [Page 8]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc4422.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1851 @@
+
+
+
+
+
+
+Network Working Group                                   A. Melnikov, Ed.
+Request for Comments: 4422                                 Isode Limited
+Obsoletes: 2222                                         K. Zeilenga, Ed.
+Category: Standards Track                            OpenLDAP Foundation
+                                                               June 2006
+
+
+            Simple Authentication and Security Layer (SASL)
+
+Status of This Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (2006).
+
+Abstract
+
+   The Simple Authentication and Security Layer (SASL) is a framework
+   for providing authentication and data security services in
+   connection-oriented protocols via replaceable mechanisms.  It
+   provides a structured interface between protocols and mechanisms.
+   The resulting framework allows new protocols to reuse existing
+   mechanisms and allows old protocols to make use of new mechanisms.
+   The framework also provides a protocol for securing subsequent
+   protocol exchanges within a data security layer.
+
+   This document describes how a SASL mechanism is structured, describes
+   how protocols include support for SASL, and defines the protocol for
+   carrying a data security layer over a connection.  In addition, this
+   document defines one SASL mechanism, the EXTERNAL mechanism.
+
+   This document obsoletes RFC 2222.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov & Zeilenga         Standards Track                     [Page 1]
+
+RFC 4422                          SASL                         June 2006
+
+
+Table of Contents
+
+   1. Introduction ....................................................3
+      1.1. Document Audiences .........................................4
+      1.2. Relationship to Other Documents ............................4
+      1.3. Conventions ................................................5
+   2. Identity Concepts ...............................................5
+   3. The Authentication Exchange .....................................6
+      3.1. Mechanism Naming ...........................................8
+      3.2. Mechanism Negotiation ......................................9
+      3.3. Request Authentication Exchange ............................9
+      3.4. Challenges and Responses ...................................9
+           3.4.1. Authorization Identity String ......................10
+      3.5. Aborting Authentication Exchanges .........................10
+      3.6. Authentication Outcome ....................................11
+      3.7. Security Layers ...........................................12
+      3.8. Multiple Authentications ..................................12
+   4. Protocol Requirements ..........................................13
+   5. Mechanism Requirements .........................................16
+   6. Security Considerations ........................................18
+      6.1. Active Attacks ............................................19
+           6.1.1. Hijack Attacks .....................................19
+           6.1.2. Downgrade Attacks ..................................19
+           6.1.3. Replay Attacks .....................................20
+           6.1.4. Truncation Attacks .................................20
+           6.1.5. Other Active Attacks ...............................20
+      6.2. Passive Attacks ...........................................20
+      6.3. Re-keying .................................................21
+      6.4. Other Considerations ......................................21
+   7. IANA Considerations ............................................22
+      7.1. SASL Mechanism Registry ...................................22
+      7.2. Registration Changes ......................................26
+   8. References .....................................................26
+      8.1. Normative References ......................................26
+      8.2. Informative References ....................................27
+   9. Acknowledgements ...............................................28
+   Appendix A.  The SASL EXTERNAL Mechanism ..........................29
+      A.1. EXTERNAL Technical Specification ..........................29
+      A.2. SASL EXTERNAL Examples ....................................30
+      A.3. Security Considerations ...................................31
+   Appendix B.  Changes since RFC 2222 ...............................31
+
+
+
+
+
+
+
+
+
+
+Melnikov & Zeilenga         Standards Track                     [Page 2]
+
+RFC 4422                          SASL                         June 2006
+
+
+1.  Introduction
+
+   The Simple Authentication and Security Layer (SASL) is a framework
+   for providing authentication and data security services in
+   connection-oriented protocols via replaceable mechanisms.  SASL
+   provides a structured interface between protocols and mechanisms.
+   SASL also provides a protocol for securing subsequent protocol
+   exchanges within a data security layer.  The data security layer can
+   provide data integrity, data confidentiality, and other services.
+
+   SASL's design is intended to allow new protocols to reuse existing
+   mechanisms without requiring redesign of the mechanisms and allows
+   existing protocols to make use of new mechanisms without redesign of
+   protocols.
+
+   SASL is conceptually a framework that provides an abstraction layer
+   between protocols and mechanisms as illustrated in the following
+   diagram.
+
+                  SMTP    LDAP    XMPP   Other protocols ...
+                     \       |    |      /
+                      \      |    |     /
+                     SASL abstraction layer
+                      /      |    |     \
+                     /       |    |      \
+              EXTERNAL   GSSAPI  PLAIN   Other mechanisms ...
+
+   It is through the interfaces of this abstraction layer that the
+   framework allows any protocol to utilize any mechanism.  While this
+   layer does generally hide the particulars of protocols from
+   mechanisms and the particulars of mechanisms from protocols, this
+   layer does not generally hide the particulars of mechanisms from
+   protocol implementations.  For example, different mechanisms require
+   different information to operate, some of them use password-based
+   authentication, some of then require realm information, others make
+   use of Kerberos tickets, certificates, etc.  Also, in order to
+   perform authorization, server implementations generally have to
+   implement identity mapping between authentication identities, whose
+   form is mechanism specific, and authorization identities, whose form
+   is application protocol specific.  Section 2 discusses identity
+   concepts.
+
+   It is possible to design and implement this framework in ways that do
+   abstract away particulars of similar mechanisms.  Such a framework
+   implementation, as well as mechanisms implementations, could be
+   designed not only to be shared by multiple implementations of a
+   particular protocol but to be shared by implementations of multiple
+   protocols.
+
+
+
+Melnikov & Zeilenga         Standards Track                     [Page 3]
+
+RFC 4422                          SASL                         June 2006
+
+
+   The framework incorporates interfaces with both protocols and
+   mechanisms in which authentication exchanges are carried out.
+   Section 3 discusses SASL authentication exchanges.
+
+   To use SASL, each protocol (amongst other items) provides a method
+   for identifying which mechanism is to be used, a method for exchange
+   of mechanism-specific server-challenges and client-responses, and a
+   method for communicating the outcome of the authentication exchange.
+   Section 4 discusses SASL protocol requirements.
+
+   Each SASL mechanism defines (amongst other items) a series of
+   server-challenges and client-responses that provide authentication
+   services and negotiate data security services.  Section 5 discusses
+   SASL mechanism requirements.
+
+   Section 6 discusses security considerations.  Section 7 discusses
+   IANA considerations.  Appendix A defines the SASL EXTERNAL mechanism.
+
+1.1.  Document Audiences
+
+   This document is written to serve several different audiences:
+
+      -  protocol designers using this specification to support
+         authentication in their protocol,
+
+      -  mechanism designers that define new SASL mechanisms, and
+
+      -  implementors of clients or servers for those protocols that
+         support SASL.
+
+   While the document organization is intended to allow readers to focus
+   on details relevant to their engineering, readers are encouraged to
+   read and understand all aspects of this document.
+
+1.2.  Relationship to Other Documents
+
+   This document obsoletes RFC 2222.  It replaces all portions of RFC
+   2222 excepting sections 7.1 (the KERBEROS_IV mechanism), 7.2 (the
+   GSSAPI mechanism), 7.3 (the SKEY mechanism).  The KERBEROS_IV and
+   SKEY mechanisms are now viewed as obsolete and their specifications
+   provided in RFC 2222 are Historic.  The GSSAPI mechanism is now
+   separately specified [SASL-GSSAPI].
+
+   Appendix B provides a summary of changes since RFC 2222.
+
+
+
+
+
+
+
+Melnikov & Zeilenga         Standards Track                     [Page 4]
+
+RFC 4422                          SASL                         June 2006
+
+
+1.3.  Conventions
+
+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+   document are to be interpreted as described in BCP 14 [RFC2119].
+
+   Character names in this document use the notation for code points and
+   names from the Unicode Standard [Unicode].  For example, the letter
+   "a" may be represented as either <U+0061> or <LATIN SMALL LETTER A>.
+
+   Note: a glossary of terms used in Unicode can be found in [Glossary].
+   Information on the Unicode character encoding model can be found in
+   [CharModel].
+
+   In examples, "C:" and "S:" indicate lines of data to be sent by the
+   client and server, respectively.  Lines have been wrapped for
+   improved readability.
+
+2.  Identity Concepts
+
+   In practice, authentication and authorization may involve multiple
+   identities, possibly in different forms (simple username, Kerberos
+   principal, X.500 Distinguished Name, etc.), possibly with different
+   representations (e.g., ABNF-described UTF-8 encoded Unicode character
+   string, BER-encoded Distinguished Name).  While technical
+   specifications often prescribe both the identity form and
+   representation used on the network, different identity forms and/or
+   representations may be (and often are) used within implementations.
+   How identities of different forms relate to each other is, generally,
+   a local matter.  In addition, the forms and representations used
+   within an implementation are a local matter.
+
+   However, conceptually, the SASL framework involves two identities:
+
+      1) an identity associated with the authentication credentials
+         (termed the authentication identity), and
+
+      2) an identity to act as (termed the authorization identity).
+
+   SASL mechanism specifications describe the credential form(s) (e.g.,
+   X.509 certificates, Kerberos tickets, simple username/password) used
+   to authenticate the client, including (where appropriate) the syntax
+   and semantics of authentication identities carried in the
+   credentials.  SASL protocol specifications describe the identity
+   form(s) used in authorization and, in particular, prescribe the
+   syntax and semantics of the authorization identity character string
+   to be transferred by mechanisms.
+
+
+
+
+Melnikov & Zeilenga         Standards Track                     [Page 5]
+
+RFC 4422                          SASL                         June 2006
+
+
+   The client provides its credentials (which include or imply an
+   authentication identity) and, optionally, a character string
+   representing the requested authorization identity as part of the SASL
+   exchange.  When this character string is omitted or empty, the client
+   is requesting to act as the identity associated with the credentials
+   (e.g., the user is requesting to act as the authentication identity).
+
+   The server is responsible for verifying the client's credentials and
+   verifying that the identity it associates with the client's
+   credentials (e.g., the authentication identity) is allowed to act as
+   the authorization identity.  A SASL exchange fails if either (or
+   both) of these verifications fails.  (The SASL exchange may fail for
+   other reasons, such as service authorization failure.)
+
+   However, the precise form(s) of the authentication identities (used
+   within the server in its verifications, or otherwise) and the precise
+   form(s) of the authorization identities (used in making authorization
+   decisions, or otherwise) are beyond the scope of SASL and this
+   specification.  In some circumstances, the precise identity forms
+   used in some context outside of the SASL exchange may be dictated by
+   other specifications.  For instance, an identity assumption
+   authorization (proxy authorization) policy specification may dictate
+   how authentication and authorization identities are represented in
+   policy statements.
+
+3.  The Authentication Exchange
+
+   Each authentication exchange consists of a message from the client to
+   the server requesting authentication via a particular mechanism,
+   followed by one or more pairs of challenges from the server and
+   responses from the client, followed by a message from the server
+   indicating the outcome of the authentication exchange.  (Note:
+   exchanges may also be aborted as discussed in Section 3.5.)
+
+   The following illustration provides a high-level overview of an
+   authentication exchange.
+
+      C: Request authentication exchange
+      S: Initial challenge
+      C: Initial response
+      <additional challenge/response messages>
+      S: Outcome of authentication exchange
+
+   If the outcome is successful and a security layer was negotiated,
+   this layer is then installed (see Section 3.7).  This also applies to
+   the following illustrations.
+
+
+
+
+
+Melnikov & Zeilenga         Standards Track                     [Page 6]
+
+RFC 4422                          SASL                         June 2006
+
+
+   Some mechanisms specify that the first data sent in the
+   authentication exchange is from the client to the server.  Protocols
+   may provide an optional initial response field in the request message
+   to carry this data.  Where the mechanism specifies that the first
+   data sent in the exchange is from the client to the server, the
+   protocol provides an optional initial response field, and the client
+   uses this field, the exchange is shortened by one round-trip:
+
+      C: Request authentication exchange + Initial response
+      <additional challenge/response messages>
+      S: Outcome of authentication exchange
+
+   Where the mechanism specifies that the first data sent in the
+   exchange is from the client to the server and this field is
+   unavailable or unused, the client request is followed by an empty
+   challenge.
+
+      C: Request authentication exchange
+      S: Empty Challenge
+      C: Initial Response
+      <additional challenge/response messages>
+      S: Outcome of authentication exchange
+
+   Should a client include an initial response in its request where the
+   mechanism does not allow the client to send data first, the
+   authentication exchange fails.
+
+   Some mechanisms specify that the server is to send additional data to
+   the client when indicating a successful outcome.  Protocols may
+   provide an optional additional data field in the outcome message to
+   carry this data.  Where the mechanism specifies that the server is to
+   return additional data with the successful outcome, the protocol
+   provides an optional additional data field in the outcome message,
+   and the server uses this field, the exchange is shortened by one
+   round-trip:
+
+      C: Request authentication exchange
+      S: Initial challenge
+      C: Initial response
+      <additional challenge/response messages>
+      S: Outcome of authentication exchange with
+         additional data with success
+
+   Where the mechanism specifies that the server is to return additional
+   data to the client with a successful outcome and this field is
+   unavailable or unused, the additional data is sent as a challenge
+   whose response is empty.  After receiving this response, the server
+   then indicates the successful outcome.
+
+
+
+Melnikov & Zeilenga         Standards Track                     [Page 7]
+
+RFC 4422                          SASL                         June 2006
+
+
+      C: Request authentication exchange
+      S: Initial challenge
+      C: Initial response
+      <additional challenge/response messages>
+      S: Additional data challenge
+      C: Empty Response
+      S: Outcome of authentication exchange
+
+   Where mechanisms specify that the first data sent in the exchange is
+   from the client to the server and additional data is sent to the
+   client along with indicating a successful outcome, and the protocol
+   provides fields supporting both, then the exchange takes two fewer
+   round-trips:
+
+      C: Request authentication exchange + Initial response
+      <additional challenge/response messages>
+      S: Outcome of authentication exchange
+         with additional data with success
+
+   instead of:
+
+      C: Request authentication exchange
+      S: Empty Challenge
+      C: Initial Response
+      <additional challenge/response messages>
+      S: Additional data challenge
+      C: Empty Response
+      S: Outcome of authentication exchange
+
+3.1.  Mechanism Naming
+
+   SASL mechanisms are named by character strings, from 1 to 20
+   characters in length, consisting of ASCII [ASCII] uppercase letters,
+   digits, hyphens, and/or underscores.  In the following Augmented
+   Backus-Naur Form (ABNF) [RFC4234] grammar, the <sasl-mech> production
+   defines the syntax of a SASL mechanism name.
+
+      sasl-mech    = 1*20mech-char
+      mech-char    = UPPER-ALPHA / DIGIT / HYPHEN / UNDERSCORE
+      ; mech-char is restricted to A-Z (uppercase only), 0-9, -, and _
+      ; from ASCII character set.
+
+      UPPER-ALPHA  = %x41-5A  ; A-Z (uppercase only)
+      DIGIT        = %x30-39  ; 0-9
+      HYPHEN       = %x2D ; hyphen (-)
+      UNDERSCORE   = %x5F ; underscore (_)
+
+   SASL mechanism names are registered as discussed in Section 7.1.
+
+
+
+Melnikov & Zeilenga         Standards Track                     [Page 8]
+
+RFC 4422                          SASL                         June 2006
+
+
+3.2.  Mechanism Negotiation
+
+   Mechanism negotiation is protocol specific.
+
+   Commonly, a protocol will specify that the server advertises
+   supported and available mechanisms to the client via some facility
+   provided by the protocol, and the client will then select the "best"
+   mechanism from this list that it supports and finds suitable.
+
+   Note that the mechanism negotiation is not protected by the
+   subsequent authentication exchange and hence is subject to downgrade
+   attacks if not protected by other means.
+
+   To detect downgrade attacks, a protocol can allow the client to
+   discover available mechanisms subsequent to the authentication
+   exchange and installation of data security layers with at least data
+   integrity protection.  This allows the client to detect changes to
+   the list of mechanisms supported by the server.
+
+3.3.  Request Authentication Exchange
+
+   The authentication exchange is initiated by the client by requesting
+   authentication via a mechanism it specifies.  The client sends a
+   message that contains the name of the mechanism to the server.  The
+   particulars of the message are protocol specific.
+
+   Note that the name of the mechanism is not protected by the
+   mechanism, and hence is subject to alteration by an attacker if not
+   integrity protected by other means.
+
+   Where the mechanism is defined to allow the client to send data
+   first, and the protocol's request message includes an optional
+   initial response field, the client may include the response to the
+   initial challenge in the authentication request message.
+
+3.4.  Challenges and Responses
+
+   The authentication exchange involves one or more pairs of server-
+   challenges and client-responses, the particulars of which are
+   mechanism specific.  These challenges and responses are enclosed in
+   protocol messages, the particulars of which are protocol specific.
+
+   Through these challenges and responses, the mechanism may:
+
+      -  authenticate the client to the server,
+
+      -  authenticate the server to the client,
+
+
+
+
+Melnikov & Zeilenga         Standards Track                     [Page 9]
+
+RFC 4422                          SASL                         June 2006
+
+
+      -  transfer an authorization identity string,
+
+      -  negotiate a security layer, and
+
+      -  provide other services.
+
+   The negotiation of the security layer may involve negotiation of the
+   security services to be provided in the layer, how these services
+   will be provided, and negotiation of a maximum cipher-text buffer
+   size each side is able to receive in the layer (see Section 3.6).
+
+   After receiving an authentication request or any client response, the
+   server may issue a challenge, abort the exchange, or indicate the
+   outcome of an exchange.  After receiving a challenge, a client
+   mechanism may issue a response or abort the exchange.
+
+3.4.1.  Authorization Identity String
+
+   The authorization identity string is a sequence of zero or more
+   Unicode [Unicode] characters, excluding the NUL (U+0000) character,
+   representing the identity to act as.
+
+   If the authorization identity string is absent, the client is
+   requesting to act as the identity the server associates with the
+   client's credentials.  An empty string is equivalent to an absent
+   authorization identity.
+
+   A non-empty authorization identity string indicates that the client
+   wishes to act as the identity represented by the string.  In this
+   case, the form of identity represented by the string, as well as the
+   precise syntax and semantics of the string, is protocol specific.
+
+   While the character encoding schema used to transfer the
+   authorization identity string in the authentication exchange is
+   mechanism specific, mechanisms are expected to be capable of carrying
+   the entire Unicode repertoire (with the exception of the NUL
+   character).
+
+3.5.  Aborting Authentication Exchanges
+
+   A client or server may desire to abort an authentication exchange if
+   it is unwilling or unable to continue (or enter into).
+
+   A client may abort the authentication exchange by sending a message,
+   the particulars of which are protocol specific, to the server,
+   indicating that the exchange is aborted.  The server may be required
+   by the protocol to return a message in response to the client's abort
+   message.
+
+
+
+Melnikov & Zeilenga         Standards Track                    [Page 10]
+
+RFC 4422                          SASL                         June 2006
+
+
+   Likewise, a server may abort the authentication exchange by sending a
+   message, the particulars of which are protocol specific, to the
+   client, indicating that the exchange is aborted.
+
+3.6.  Authentication Outcome
+
+   At the conclusion of the authentication exchange, the server sends a
+   message, the particulars of which are protocol specific, to the
+   client indicating the outcome of the exchange.
+
+   The outcome is not successful if
+
+      -  the authentication exchange failed for any reason,
+
+      -  the client's credentials could not be verified,
+
+      -  the server cannot associate an identity with the client's
+         credentials,
+
+      -  the client-provided authorization identity string is malformed,
+
+      -  the identity associated with the client's credentials is not
+         authorized to act as the requested authorization identity,
+
+      -  the negotiated security layer (or lack thereof) is not
+         suitable, or
+
+      -  the server is not willing to provide service to the client for
+         any reason.
+
+   The protocol may include an optional additional data field in this
+   outcome message.  This field can only include additional data when
+   the outcome is successful.
+
+   If the outcome is successful and a security layer was negotiated,
+   this layer is then installed.  If the outcome is unsuccessful, or a
+   security layer was not negotiated, any existing security is left in
+   place.
+
+   The outcome message provided by the server can provide a way for the
+   client to distinguish between errors that are best dealt with by re-
+   prompting the user for her credentials, errors that are best dealt
+   with by telling the user to try again later, and errors where the
+   user must contact a system administrator for resolution (see the SYS
+   and AUTH POP Response Codes [RFC3206] specification for an example).
+   This distinction is particularly useful during scheduled server
+   maintenance periods as it reduces support costs.  It is also
+   important that the server can be configured such that the outcome
+
+
+
+Melnikov & Zeilenga         Standards Track                    [Page 11]
+
+RFC 4422                          SASL                         June 2006
+
+
+   message will not distinguish between a valid user with invalid
+   credentials and an invalid user.
+
+3.7.  Security Layers
+
+   SASL mechanisms may offer a wide range of services in security
+   layers.  Typical services include data integrity and data
+   confidentiality.  SASL mechanisms that do not provide a security
+   layer are treated as negotiating no security layer.
+
+   If use of a security layer is negotiated in the authentication
+   protocol exchange, the layer is installed by the server after
+   indicating the outcome of the authentication exchange and installed
+   by the client upon receipt of the outcome indication.  In both cases,
+   the layer is installed before transfer of further protocol data.  The
+   precise position upon which the layer takes effect in the protocol
+   data stream is protocol specific.
+
+   Once the security layer is in effect in the protocol data stream, it
+   remains in effect until either a subsequently negotiated security
+   layer is installed or the underlying transport connection is closed.
+
+   When in effect, the security layer processes protocol data into
+   buffers of protected data.  If at any time the security layer is
+   unable or unwilling to continue producing buffers protecting protocol
+   data, the underlying transport connection MUST be closed.  If the
+   security layer is not able to decode a received buffer, the
+   underlying connection MUST be closed.  In both cases, the underlying
+   transport connection SHOULD be closed gracefully.
+
+   Each buffer of protected data is transferred over the underlying
+   transport connection as a sequence of octets prepended with a four-
+   octet field in network byte order that represents the length of the
+   buffer.  The length of the protected data buffer MUST be no larger
+   than the maximum size that the other side expects.  Upon the receipt
+   of a length field whose value is greater than the maximum size, the
+   receiver SHOULD close the connection, as this might be a sign of an
+   attack.
+
+   The maximum size that each side expects is fixed by the mechanism,
+   either through negotiation or by its specification.
+
+3.8.  Multiple Authentications
+
+   Unless explicitly permitted in the protocol (as stated in the
+   protocol's technical specification), only one successful SASL
+   authentication exchange may occur in a protocol session.  In this
+
+
+
+
+Melnikov & Zeilenga         Standards Track                    [Page 12]
+
+RFC 4422                          SASL                         June 2006
+
+
+   case, once an authentication exchange has successfully completed,
+   further attempts to initiate an authentication exchange fail.
+
+   Where multiple successful SASL authentication exchanges are permitted
+   in the protocol, then in no case may multiple SASL security layers be
+   simultaneously in effect.  If a security layer is in effect and a
+   subsequent SASL negotiation selects a second security layer, then the
+   second security layer replaces the first.  If a security layer is in
+   effect and a subsequent SASL negotiation selects no security layer,
+   the original security layer remains in effect.
+
+   Where multiple successful SASL negotiations are permitted in the
+   protocol, the effect of a failed SASL authentication exchange upon
+   the previously established authentication and authorization state is
+   protocol specific.  The protocol's technical specification should be
+   consulted to determine whether the previous authentication and
+   authorization state remains in force, or changed to an anonymous
+   state, or otherwise was affected.  Regardless of the protocol-
+   specific effect upon previously established authentication and
+   authorization state, the previously negotiated security layer remains
+   in effect.
+
+4.  Protocol Requirements
+
+   In order for a protocol to offer SASL services, its specification
+   MUST supply the following information:
+
+   1) A service name, to be selected from registry of "service" elements
+      for the Generic Security Service Application Program Interface
+      (GSSAPI) host-based service name form, as described in Section 4.1
+      of [RFC2743].  Note that this registry is shared by all GSSAPI and
+      SASL mechanisms.
+
+   2) Detail any mechanism negotiation facility that the protocol
+      provides (see Section 3.2).
+
+      A protocol SHOULD specify a facility through which the client may
+      discover, both before initiation of the SASL exchange and after
+      installing security layers negotiated by the exchange, the names
+      of the SASL mechanisms that the server makes available to the
+      client.  The latter is important to allow the client to detect
+      downgrade attacks.  This facility is typically provided through
+      the protocol's extensions or capabilities discovery facility.
+
+   3) Definition of the messages necessary for authentication exchange,
+      including the following:
+
+
+
+
+
+Melnikov & Zeilenga         Standards Track                    [Page 13]
+
+RFC 4422                          SASL                         June 2006
+
+
+      a) A message to initiate the authentication exchange (see Section
+         3.3).
+
+         This message MUST contain a field for carrying the name of the
+         mechanism selected by the client.
+
+         This message SHOULD contain an optional field for carrying an
+         initial response.  If the message is defined with this field,
+         the specification MUST describe how messages with an empty
+         initial response are distinguished from messages with no
+         initial response.  This field MUST be capable of carrying
+         arbitrary sequences of octets (including zero-length sequences
+         and sequences containing zero-valued octets).
+
+      b) Messages to transfer server challenges and client responses
+         (see Section 3.4).
+
+         Each of these messages MUST be capable of carrying arbitrary
+         sequences of octets (including zero-length sequences and
+         sequences containing zero-valued octets).
+
+      c) A message to indicate the outcome of the authentication
+         exchange (see Section 3.6).
+
+         This message SHOULD contain an optional field for carrying
+         additional data with a successful outcome.  If the message is
+         defined with this field, the specification MUST describe how
+         messages with an empty additional data are distinguished from
+         messages with no additional data.  This field MUST be capable
+         of carrying arbitrary sequences of octets (including zero-
+         length sequences and sequences containing zero-valued octets).
+
+   4) Prescribe the syntax and semantics of non-empty authorization
+      identity strings (see Section 3.4.1).
+
+      In order to avoid interoperability problems due to differing
+      normalizations, the protocol specification MUST detail precisely
+      how and where (client or server) non-empty authorization identity
+      strings are prepared, including all normalizations, for comparison
+      and other applicable functions to ensure proper function.
+
+      Specifications are encouraged to prescribe use of existing
+      authorization identity forms as well as existing string
+      representations, such as simple user names [RFC4013].
+
+      Where the specification does not precisely prescribe how
+      identities in SASL relate to identities used elsewhere in the
+      protocol, for instance, in access control policy statements, it
+
+
+
+Melnikov & Zeilenga         Standards Track                    [Page 14]
+
+RFC 4422                          SASL                         June 2006
+
+
+      may be appropriate for the protocol to provide a facility by which
+      the client can discover information (such as the representation of
+      the identity used in making access control decisions) about
+      established identities for these uses.
+
+   5) Detail any facility the protocol provides that allows the client
+      and/or server to abort authentication exchange (see Section 3.5).
+
+      Protocols that support multiple authentications typically allow a
+      client to abort an ongoing authentication exchange by initiating a
+      new authentication exchange.  Protocols that do not support
+      multiple authentications may require the client to close the
+      connection and start over to abort an ongoing authentication
+      exchange.
+
+      Protocols typically allow the server to abort ongoing
+      authentication exchanges by returning a non-successful outcome
+      message.
+
+   6) Identify precisely where newly negotiated security layers start to
+      take effect, in both directions (see Section 3.7).
+
+      Typically, specifications require security layers to start taking
+      effect on the first octet following the outcome message in data
+      being sent by the server and on the first octet sent after receipt
+      of the outcome message in data being sent by the client.
+
+   7) If the protocol supports other layered security services, such as
+      Transport Layer Security (TLS) [RFC4346], the specification MUST
+      prescribe the order in which security layers are applied to
+      protocol data.
+
+      For instance, where a protocol supports both TLS and SASL security
+      layers, the specification could prescribe any of the following:
+
+      a) SASL security layer is always applied first to data being sent
+         and, hence, applied last to received data,
+
+      b) SASL security layer is always applied last to data being sent
+         and, hence, applied first to received data,
+
+      c) Layers are applied in the order in which they were installed,
+
+      d) Layers are applied in the reverse order in which they were
+         installed, or
+
+      e) Both TLS and SASL security layers cannot be installed.
+
+
+
+
+Melnikov & Zeilenga         Standards Track                    [Page 15]
+
+RFC 4422                          SASL                         June 2006
+
+
+   8) Indicate whether the protocol supports multiple authentications
+      (see Section 3.8).  If so, the protocol MUST detail the effect a
+      failed SASL authentication exchange will have upon a previously
+      established authentication and authorization state.
+
+   Protocol specifications SHOULD avoid stating implementation
+   requirements that would hinder replacement of applicable mechanisms.
+   In general, protocol specifications SHOULD be mechanism neutral.
+   There are a number of reasonable exceptions to this recommendation,
+   including
+
+      -  detailing how credentials (which are mechanism specific) are
+         managed in the protocol,
+
+      -  detailing how authentication identities (which are mechanism
+         specific) and authorization identities (which are protocol
+         specific) relate to each other, and
+
+      -  detailing which mechanisms are applicable to the protocol.
+
+5.  Mechanism Requirements
+
+   SASL mechanism specifications MUST supply the following information:
+
+   1) The name of the mechanism (see Section 3.1).  This name MUST be
+      registered as discussed in Section 7.1.
+
+   2) A definition of the server-challenges and client-responses of the
+      authentication exchange, as well as the following:
+
+      a) An indication of whether the mechanism is client-first,
+         variable, or server-first.  If a SASL mechanism is defined as
+         client-first and the client does not send an initial response
+         in the authentication request, then the first server challenge
+         MUST be empty (the EXTERNAL mechanism is an example of this
+         case).  If a SASL mechanism is defined as variable, then the
+         specification needs to state how the server behaves when the
+         initial client response in the authentication request is
+         omitted (the DIGEST-MD5 mechanism [DIGEST-MD5] is an example of
+         this case).  If a SASL mechanism is defined as server-first,
+         then the client MUST NOT send an initial client response in the
+         authentication request (the CRAM-MD5 mechanism [CRAM-MD5] is an
+         example of this case).
+
+      b) An indication of whether the server is expected to provide
+         additional data when indicating a successful outcome.  If so,
+         if the server sends the additional data as a challenge, the
+
+
+
+
+Melnikov & Zeilenga         Standards Track                    [Page 16]
+
+RFC 4422                          SASL                         June 2006
+
+
+         specification MUST indicate that the response to this challenge
+         is an empty response.
+
+      SASL mechanisms SHOULD be designed to minimize the number of
+      challenges and responses necessary to complete the exchange.
+
+   3) An indication of whether the mechanism is capable of transferring
+      authorization identity strings (see Section 3.4.1).  While some
+      legacy mechanisms are incapable of transmitting an authorization
+      identity (which means that for these mechanisms, the authorization
+      identity is always the empty string), newly defined mechanisms
+      SHOULD be capable of transferring authorization identity strings.
+      The mechanism SHOULD NOT be capable of transferring both no
+      authorization identity string and an empty authorization identity.
+
+      Mechanisms that are capable of transferring an authorization
+      identity string MUST be capable of transferring arbitrary non-
+      empty sequences of Unicode characters, excluding those that
+      contain the NUL (U+0000) character.  Mechanisms SHOULD use the
+      UTF-8 [RFC3629] transformation format.  The specification MUST
+      detail how any Unicode code points special to the mechanism that
+      might appear in the authorization identity string are escaped to
+      avoid ambiguity during decoding of the authorization identity
+      string.  Typically, mechanisms that have special characters
+      require these special characters to be escaped or encoded in the
+      character string (after encoding it in a particular Unicode
+      transformation format) using a data encoding scheme such as Base64
+      [RFC3548].
+
+   4) The specification MUST detail whether the mechanism offers a
+      security layer.  If the mechanism does, the specification MUST
+      detail the security and other services offered in the layer as
+      well as how these services are to be implemented.
+
+   5) If the underlying cryptographic technology used by a mechanism
+      supports data integrity, then the mechanism specification MUST
+      integrity protect the transmission of an authorization identity
+      and the negotiation of the security layer.
+
+   SASL mechanisms SHOULD be protocol neutral.
+
+   SASL mechanisms SHOULD reuse existing credential and identity forms,
+   as well as associated syntaxes and semantics.
+
+   SASL mechanisms SHOULD use the UTF-8 transformation format [RFC3629]
+   for encoding Unicode [Unicode] code points for transfer.
+
+
+
+
+
+Melnikov & Zeilenga         Standards Track                    [Page 17]
+
+RFC 4422                          SASL                         June 2006
+
+
+   In order to avoid interoperability problems due to differing
+   normalizations, when a mechanism calls for character data (other than
+   the authorization identity string) to be used as input to a
+   cryptographic and/or comparison function, the specification MUST
+   detail precisely how and where (client or server) the character data
+   is to be prepared, including all normalizations, for input into the
+   function to ensure proper operation.
+
+   For simple user names and/or passwords in authentication credentials,
+   SASLprep [RFC4013] (a profile of the StringPrep [RFC3454] preparation
+   algorithm), SHOULD be specified as the preparation algorithm.
+
+   The mechanism SHOULD NOT use the authorization identity string in
+   generation of any long-term cryptographic keys or hashes as there is
+   no requirement that the authorization identity string be canonical.
+   Long-term, here, means a term longer than the duration of the
+   authentication exchange in which they were generated.  That is, as
+   different clients (of the same or different protocol) may provide
+   different authorization identity strings that are semantically
+   equivalent, use of authorization identity strings in generation of
+   cryptographic keys and hashes will likely lead to interoperability
+   and other problems.
+
+6.  Security Considerations
+
+   Security issues are discussed throughout this memo.
+
+   Many existing SASL mechanisms do not provide adequate protection
+   against passive attacks, let alone active attacks, in the
+   authentication exchange.  Many existing SASL mechanisms do not offer
+   security layers.  It is hoped that future SASL mechanisms will
+   provide strong protection against passive and active attacks in the
+   authentication exchange, as well as security layers with strong basic
+   data security features (e.g., data integrity and data
+   confidentiality) services.  It is also hoped that future mechanisms
+   will provide more advanced data security services like re-keying (see
+   Section 6.3).
+
+   Regardless, the SASL framework is susceptible to downgrade attacks.
+   Section 6.1.2 offers a variety of approaches for preventing or
+   detecting these attacks.  In some cases, it is appropriate to use
+   data integrity protective services external to SASL (e.g., TLS) to
+   protect against downgrade attacks in SASL.  Use of external
+   protective security services is also important when the mechanisms
+   available do not themselves offer adequate integrity and/or
+   confidentiality protection of the authentication exchange and/or
+   protocol data.
+
+
+
+
+Melnikov & Zeilenga         Standards Track                    [Page 18]
+
+RFC 4422                          SASL                         June 2006
+
+
+6.1.  Active Attacks
+
+6.1.1.  Hijack Attacks
+
+   When the client selects a SASL security layer with at least integrity
+   protection, this protection serves as a counter-measure against an
+   active attacker hijacking the connection and modifying protocol data
+   sent after establishment of the security layer.  Implementations
+   SHOULD close the connection when the security services in a SASL
+   security layer report protocol data report lack of data integrity.
+
+6.1.2.  Downgrade Attacks
+
+   It is important that any security-sensitive protocol negotiations be
+   performed after installation of a security layer with data integrity
+   protection.  Protocols should be designed such that negotiations
+   performed prior to this installation should be revalidated after
+   installation is complete.  Negotiation of the SASL mechanism is
+   security sensitive.
+
+   When a client negotiates the authentication mechanism with the server
+   and/or other security features, it is possible for an active attacker
+   to cause a party to use the least secure security services available.
+   For instance, an attacker can modify the server-advertised mechanism
+   list or can modify the client-advertised security feature list within
+   a mechanism response.  To protect against this sort of attack,
+   implementations SHOULD NOT advertise mechanisms and/or features that
+   cannot meet their minimum security requirements, SHOULD NOT enter
+   into or continue authentication exchanges that cannot meet their
+   minimum security requirements, and SHOULD verify that completed
+   authentication exchanges result in security services that meet their
+   minimum security requirements.  Note that each endpoint needs to
+   independently verify that its security requirements are met.
+
+   In order to detect downgrade attacks to the least (or less) secure
+   mechanism supported, the client can discover the SASL mechanisms that
+   the server makes available both before the SASL authentication
+   exchange and after the negotiated SASL security layer (with at least
+   data integrity protection) has been installed through the protocol's
+   mechanism discovery facility.  If the client finds that the
+   integrity-protected list (the list obtained after the security layer
+   was installed) contains a stronger mechanism than those in the
+   previously obtained list, the client should assume that the
+   previously obtained list was modified by an attacker and SHOULD close
+   the underlying transport connection.
+
+   The client's initiation of the SASL exchange, including the selection
+   of a SASL mechanism, is done in the clear and may be modified by an
+
+
+
+Melnikov & Zeilenga         Standards Track                    [Page 19]
+
+RFC 4422                          SASL                         June 2006
+
+
+   active attacker.  It is important for any new SASL mechanisms to be
+   designed such that an active attacker cannot obtain an authentication
+   with weaker security properties by modifying the SASL mechanism name
+   and/or the challenges and responses.
+
+   Multi-level negotiation of security features is prone to downgrade
+   attack.  Protocol designers should avoid offering higher-level
+   negotiation of security features in protocols (e.g., above SASL
+   mechanism negotiation) and mechanism designers should avoid lower-
+   level negotiation of security features in mechanisms (e.g., below
+   SASL mechanism negotiation).
+
+6.1.3.  Replay Attacks
+
+   Some mechanisms may be subject to replay attacks unless protected by
+   external data security services (e.g., TLS).
+
+6.1.4.  Truncation Attacks
+
+   Most existing SASL security layers do not themselves offer protection
+   against truncation attack.  In a truncation attack, the active
+   attacker causes the protocol session to be closed, causing a
+   truncation of the possibly integrity-protected data stream that leads
+   to behavior of one or both the protocol peers that inappropriately
+   benefits the attacker.  Truncation attacks are fairly easy to defend
+   against in connection-oriented application-level protocols.  A
+   protocol can defend against these attacks by ensuring that each
+   information exchange has a clear final result and that each protocol
+   session has a graceful closure mechanism, and that these are
+   integrity protected.
+
+6.1.5.  Other Active Attacks
+
+   When use of a security layer is negotiated by the authentication
+   protocol exchange, the receiver SHOULD handle gracefully any
+   protected data buffer larger than the defined/negotiated maximal
+   size.  In particular, it MUST NOT blindly allocate the amount of
+   memory specified in the buffer size field, as this might cause the
+   "out of memory" condition.  If the receiver detects a large block, it
+   SHOULD close the connection.
+
+6.2.  Passive Attacks
+
+   Many mechanisms are subject to various passive attacks, including
+   simple eavesdropping of unprotected credential information as well as
+   online and offline dictionary attacks of protected credential
+   information.
+
+
+
+
+Melnikov & Zeilenga         Standards Track                    [Page 20]
+
+RFC 4422                          SASL                         June 2006
+
+
+6.3.  Re-keying
+
+   The secure or administratively permitted lifetimes of SASL
+   mechanisms' security layers are finite.  Cryptographic keys weaken as
+   they are used and as time passes; the more time and/or cipher-text
+   that a cryptanalyst has after the first use of the a key, the easier
+   it is for the cryptanalyst to mount attacks on the key.
+
+   Administrative limits on a security layer's lifetime may take the
+   form of time limits expressed in X.509 certificates, in Kerberos V
+   tickets, or in directories, and are often desired.  In practice, one
+   likely effect of administrative lifetime limits is that applications
+   may find that security layers stop working in the middle of
+   application protocol operation, such as, perhaps, during large data
+   transfers.  As the result of this, the connection will be closed (see
+   Section 3.7), which will result in an unpleasant user experience.
+
+   Re-keying (key renegotiation process) is a way of addressing the
+   weakening of cryptographic keys.  The SASL framework does not itself
+   provide for re-keying; SASL mechanisms may.  Designers of future SASL
+   mechanisms should consider providing re-keying services.
+
+   Implementations that wish to re-key SASL security layers where the
+   mechanism does not provide for re-keying SHOULD reauthenticate the
+   same IDs and replace the expired or soon-to-expire security layers.
+   This approach requires support for reauthentication in the
+   application protocols (see Section 3.8).
+
+6.4.  Other Considerations
+
+   Protocol designers and implementors should understand the security
+   considerations of mechanisms so they may select mechanisms that are
+   applicable to their needs.
+
+   Distributed server implementations need to be careful in how they
+   trust other parties.  In particular, authentication secrets should
+   only be disclosed to other parties that are trusted to manage and use
+   those secrets in a manner acceptable to the disclosing party.
+   Applications using SASL assume that SASL security layers providing
+   data confidentiality are secure even when an attacker chooses the
+   text to be protected by the security layer.  Similarly, applications
+   assume that the SASL security layer is secure even if the attacker
+   can manipulate the cipher-text output of the security layer.  New
+   SASL mechanisms are expected to meet these assumptions.
+
+
+
+
+
+
+
+Melnikov & Zeilenga         Standards Track                    [Page 21]
+
+RFC 4422                          SASL                         June 2006
+
+
+   Unicode security considerations [UTR36] apply to authorization
+   identity strings, as well as UTF-8 [RFC3629] security considerations
+   where UTF-8 is used.  SASLprep [RFC4013] and StringPrep [RFC3454]
+   security considerations also apply where used.
+
+7.  IANA Considerations
+
+7.1.  SASL Mechanism Registry
+
+   The SASL mechanism registry is maintained by IANA.  The registry is
+   currently available at <http://www.iana.org/assignments/sasl-
+   mechanisms>.
+
+   The purpose of this registry is not only to ensure uniqueness of
+   values used to name SASL mechanisms, but also to provide a definitive
+   reference to technical specifications detailing each SASL mechanism
+   available for use on the Internet.
+
+   There is no naming convention for SASL mechanisms; any name that
+   conforms to the syntax of a SASL mechanism name can be registered.
+
+   The procedure detailed in Section 7.1.1 is to be used for
+   registration of a value naming a specific individual mechanism.
+
+   The procedure detailed in Section 7.1.2 is to be used for
+   registration of a value naming a family of related mechanisms.
+
+   Comments may be included in the registry as discussed in Section
+   7.1.3 and may be changed as discussed in Section 7.1.4.
+
+   The SASL mechanism registry has been updated to reflect that this
+   document provides the definitive technical specification for SASL and
+   that this section provides the registration procedures for this
+   registry.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov & Zeilenga         Standards Track                    [Page 22]
+
+RFC 4422                          SASL                         June 2006
+
+
+7.1.1.  Mechanism Name Registration Procedure
+
+   IANA will register new SASL mechanism names on a First Come First
+   Served basis, as defined in BCP 26 [RFC2434].  IANA has the right to
+   reject obviously bogus registration requests, but will perform no
+   review of claims made in the registration form.
+
+   Registration of a SASL mechanism is requested by filling in the
+   following template:
+
+      Subject: Registration of SASL mechanism X
+
+      SASL mechanism name (or prefix for the family):
+
+      Security considerations:
+
+      Published specification (recommended):
+
+      Person & email address to contact for further information:
+
+      Intended usage: (One of COMMON, LIMITED USE, or OBSOLETE)
+
+      Owner/Change controller:
+
+      Note: (Any other information that the author deems relevant may be
+      added here.)
+
+   and sending it via electronic mail to IANA at <iana@iana.org>.
+
+   While this registration procedure does not require expert review,
+   authors of SASL mechanisms are encouraged to seek community review
+   and comment whenever that is feasible.  Authors may seek community
+   review by posting a specification of their proposed mechanism as an
+   Internet-Draft.  SASL mechanisms intended for widespread use should
+   be standardized through the normal IETF process, when appropriate.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov & Zeilenga         Standards Track                    [Page 23]
+
+RFC 4422                          SASL                         June 2006
+
+
+7.1.2.  Family Name Registration Procedure
+
+   As noted above, there is no general naming convention for SASL
+   mechanisms.  However, specifications may reserve a portion of the
+   SASL mechanism namespace for a set of related SASL mechanisms, a
+   "family" of SASL mechanisms.  Each family of SASL mechanisms is
+   identified by a unique prefix, such as X-.  Registration of new SASL
+   mechanism family names requires expert review as defined in BCP 26
+   [RFC2434].
+
+   Registration of a SASL family name is requested by filling in the
+   following template:
+
+      Subject: Registration of SASL mechanism family X
+
+      SASL family name (or prefix for the family):
+
+      Security considerations:
+
+      Published specification (recommended):
+
+      Person & email address to contact for further information:
+
+      Intended usage: (One of COMMON, LIMITED USE, or OBSOLETE)
+
+      Owner/Change controller:
+
+      Note: (Any other information that the author deems relevant may be
+      added here.)
+
+   and sending it via electronic mail to the IETF SASL mailing list at
+   <ietf-sasl@imc.org> and carbon copying IANA at <iana@iana.org>.
+   After allowing two weeks for community input on the IETF SASL mailing
+   list, the expert will determine the appropriateness of the
+   registration request and either approve or disapprove the request
+   with notice to the requestor, the mailing list, and IANA.
+
+   The review should focus on the appropriateness of the requested
+   family name for the proposed use and the appropriateness of the
+   proposed naming and registration plan for existing and future
+   mechanism names in the family.  The scope of this request review may
+   entail consideration of relevant aspects of any provided technical
+   specification, such as their IANA Considerations section.  However,
+   this review is narrowly focused on the appropriateness of the
+   requested registration and not on the overall soundness of any
+   provided technical specification.
+
+
+
+
+
+Melnikov & Zeilenga         Standards Track                    [Page 24]
+
+RFC 4422                          SASL                         June 2006
+
+
+   Authors are encouraged to pursue community review by posting the
+   technical specification as an Internet-Draft and soliciting comment
+   by posting to appropriate IETF mailing lists.
+
+7.1.3.  Comments on SASL Mechanism Registrations
+
+   Comments on a registered SASL mechanism/family should first be sent
+   to the "owner" of the mechanism/family and/or to the <ietf-
+   sasl@imc.org> mailing list.
+
+   Submitters of comments may, after a reasonable attempt to contact the
+   owner, request IANA to attach their comment to the SASL mechanism
+   registration itself by sending mail to <iana@iana.org>.  At IANA's
+   sole discretion, IANA may attach the comment to the SASL mechanism's
+   registration.
+
+7.1.4.  Change Control
+
+   Once a SASL mechanism registration has been published by IANA, the
+   author may request a change to its definition.  The change request
+   follows the same procedure as the registration request.
+
+   The owner of a SASL mechanism may pass responsibility for the SASL
+   mechanism to another person or agency by informing IANA; this can be
+   done without discussion or review.
+
+   The IESG may reassign responsibility for a SASL mechanism.  The most
+   common case of this will be to enable changes to be made to
+   mechanisms where the author of the registration has died, has moved
+   out of contact, or is otherwise unable to make changes that are
+   important to the community.
+
+   SASL mechanism registrations may not be deleted; mechanisms that are
+   no longer believed appropriate for use can be declared OBSOLETE by a
+   change to their "intended usage" field; such SASL mechanisms will be
+   clearly marked in the lists published by IANA.
+
+   The IESG is considered to be the owner of all SASL mechanisms that
+   are on the IETF standards track.
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov & Zeilenga         Standards Track                    [Page 25]
+
+RFC 4422                          SASL                         June 2006
+
+
+7.2.  Registration Changes
+
+   The IANA has updated the SASL mechanisms registry as follows:
+
+   1) Changed the "Intended usage" of the KERBEROS_V4 and SKEY mechanism
+      registrations to OBSOLETE.
+
+   2) Changed the "Published specification" of the EXTERNAL mechanism to
+      this document as indicated below:
+
+      Subject: Updated Registration of SASL mechanism EXTERNAL
+      Family of SASL mechanisms: NO
+      SASL mechanism name: EXTERNAL
+      Security considerations: See A.3 of RFC 4422
+      Published specification (optional, recommended): RFC 4422
+      Person & email address to contact for further information:
+          Alexey Melnikov <Alexey.Melnikov@isode.com>
+      Intended usage: COMMON
+      Owner/Change controller: IESG <iesg@ietf.org>
+      Note: Updates existing entry for EXTERNAL
+
+8.  References
+
+8.1.  Normative References
+
+   [RFC2119]     Bradner, S., "Key words for use in RFCs to Indicate
+                 Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+   [RFC2244]     Newman, C. and J. G. Myers, "ACAP -- Application
+                 Configuration Access Protocol", RFC 2244, November
+                 1997.
+
+   [RFC2434]     Narten, T. and H. Alvestrand, "Guidelines for Writing
+                 an IANA Considerations Section in RFCs", BCP 26, RFC
+                 2434, October 1998.
+
+   [RFC2743]     Linn, J., "Generic Security Service Application Program
+                 Interface Version 2, Update 1", RFC 2743, January 2000.
+
+   [RFC3454]     Hoffman, P. and M. Blanchet, "Preparation of
+                 Internationalized Strings ("stringprep")", RFC 3454,
+                 December 2002.
+
+   [RFC3629]     Yergeau, F., "UTF-8, a transformation format of ISO
+                 10646", STD 63, RFC 3629, November 2003.
+
+   [RFC4013]     Zeilenga, K., "SASLprep: Stringprep Profile for User
+                 Names and Passwords", RFC 4013, February 2005.
+
+
+
+Melnikov & Zeilenga         Standards Track                    [Page 26]
+
+RFC 4422                          SASL                         June 2006
+
+
+   [RFC4234]     Crocker, D. and P. Overell, "Augmented BNF for Syntax
+                 Specifications: ABNF", RFC 4234, October 2005.
+
+   [ASCII]       Coded Character Set--7-bit American Standard Code for
+                 Information Interchange, ANSI X3.4-1986.
+
+   [Unicode]     The Unicode Consortium, "The Unicode Standard, Version
+                 3.2.0" is defined by "The Unicode Standard, Version
+                 3.0" (Reading, MA, Addison-Wesley, 2000. ISBN 0-201-
+                 61633-5), as amended by the "Unicode Standard Annex
+                 #27: Unicode 3.1"
+                 (http://www.unicode.org/reports/tr27/) and by the
+                 "Unicode Standard Annex #28: Unicode 3.2"
+                 (http://www.unicode.org/reports/tr28/).
+
+   [CharModel]   Whistler, K. and M. Davis, "Unicode Technical Report
+                 #17, Character Encoding Model", UTR17,
+                 <http://www.unicode.org/unicode/reports/tr17/>, August
+                 2000.
+
+   [Glossary]    The Unicode Consortium, "Unicode Glossary",
+                 <http://www.unicode.org/glossary/>.
+
+8.2.  Informative References
+
+   [RFC3206]     Gellens, R., "The SYS and AUTH POP Response Codes", RFC
+                 3206, February 2002.
+
+   [RFC3548]     Josefsson, S., "The Base16, Base32, and Base64 Data
+                 Encodings", RFC 3548, July 2003.
+
+   [RFC4301]     Kent, S. and K. Seo, "Security Architecture for the
+                 Internet Protocol", RFC 4301, December 2005.
+
+   [RFC4346]     Dierks, T. and E. Rescorla, "The Transport Layer
+                 Security (TLS) Protocol Version 1.1", RFC 4346, April
+                 2006.
+
+   [SASL-GSSAPI] Melnikov, A. (Editor), "The Kerberos V5 ("GSSAPI") SASL
+                 Mechanism", Work in Progress, May 2006.
+
+   [UTR36]       Davis, M., "(Draft) Unicode Technical Report #36,
+                 Character Encoding Model", UTR17,
+                 <http://www.unicode.org/unicode/reports/tr36/>,
+                 February 2005.
+
+   [CRAM-MD5]    Nerenberg, L., "The CRAM-MD5 SASL Mechanism", Work in
+                 Progress.
+
+
+
+Melnikov & Zeilenga         Standards Track                    [Page 27]
+
+RFC 4422                          SASL                         June 2006
+
+
+   [DIGEST-MD5]  Leach, P., C. Newman, and A. Melnikov, "Using Digest
+                 Authentication as a SASL Mechanism", Work in Progress,
+                 March 2006.
+
+9.  Acknowledgements
+
+   This document is a revision of RFC 2222 written by John Myers.
+
+   This revision is a product of the IETF Simple Authentication and
+   Security Layer (SASL) Working Group.
+
+   The following individuals contributed significantly to this revision:
+   Abhijit Menon-Sen, Hallvard Furuseth, Jeffrey Hutzelman, John Myers,
+   Luke Howard, Magnus Nystrom, Nicolas Williams, Peter Saint-Andre, RL
+   'Bob' Morgan, Rob Siemborski, Sam Hartman, Simon Josefsson, Tim
+   Alsop, and Tony Hansen.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov & Zeilenga         Standards Track                    [Page 28]
+
+RFC 4422                          SASL                         June 2006
+
+
+Appendix A.  The SASL EXTERNAL Mechanism
+
+   This appendix is normative.
+
+   The EXTERNAL mechanism allows a client to request the server to use
+   credentials established by means external to the mechanism to
+   authenticate the client.  The external means may be, for instance, IP
+   Security [RFC4301] or TLS [RFC4346] services.  In absence of some a
+   priori agreement between the client and the server, the client cannot
+   make any assumption as to what external means the server has used to
+   obtain the client's credentials, nor make an assumption as to the
+   form of credentials.  For example, the client cannot assume that the
+   server will use the credentials the client has established via TLS.
+
+A.1.  EXTERNAL Technical Specification
+
+   The name of this mechanism is "EXTERNAL".
+
+   The mechanism does not provide a security layer.
+
+   The mechanism is capable of transferring an authorization identity
+   string.  If empty, the client is requesting to act as the identity
+   the server has associated with the client's credentials.  If non-
+   empty, the client is requesting to act as the identity represented by
+   the string.
+
+   The client is expected to send data first in the authentication
+   exchange.  Where the client does not provide an initial response data
+   in its request to initiate the authentication exchange, the server is
+   to respond to the request with an empty initial challenge and then
+   the client is to provide its initial response.
+
+   The client sends the initial response containing the UTF-8 [RFC3629]
+   encoding of the requested authorization identity string.  This
+   response is non-empty when the client is requesting to act as the
+   identity represented by the (non-empty) string.  This response is
+   empty when the client is requesting to act as the identity the server
+   associated with its authentication credentials.
+
+   The syntax of the initial response is specified as a value of the
+   <extern-initial-resp> production detailed below using the Augmented
+   Backus-Naur Form (ABNF) [RFC4234] notation.
+
+      external-initial-resp = authz-id-string
+      authz-id-string       = *( UTF8-char-no-nul )
+      UTF8-char-no-nul      = UTF8-1-no-nul / UTF8-2 / UTF8-3 / UTF8-4
+      UTF8-1-no-nul         = %x01-7F
+
+
+
+
+Melnikov & Zeilenga         Standards Track                    [Page 29]
+
+RFC 4422                          SASL                         June 2006
+
+
+   where the <UTF8-2>, <UTF8-3>, and <UTF8-4> productions are as defined
+   in [RFC3629].
+
+   There are no additional challenges and responses.
+
+   Hence, the server is to return the outcome of the authentication
+   exchange.
+
+   The exchange fails if
+
+   -  the client has not established its credentials via external means,
+
+   -  the client's credentials are inadequate,
+
+   -  the client provided an empty authorization identity string and the
+      server is unwilling or unable to associate an authorization
+      identity with the client's credentials,
+
+   -  the client provided a non-empty authorization identity string that
+      is invalid per the syntax requirements of the applicable
+      application protocol specification,
+
+   -  the client provided a non-empty authorization identity string
+      representing an identity that the client is not allowed to act as,
+      or
+
+   -  the server is unwilling or unable to provide service to the client
+      for any other reason.
+
+   Otherwise the exchange is successful.  When indicating a successful
+   outcome, additional data is not provided.
+
+A.2.  SASL EXTERNAL Examples
+
+   This section provides examples of EXTERNAL authentication exchanges.
+   The examples are intended to help the readers understand the above
+   text.  The examples are not definitive.  The Application
+   Configuration Access Protocol (ACAP) [RFC2244] is used in the
+   examples.
+
+   The first example shows use of EXTERNAL with an empty authorization
+   identity.  In this example, the initial response is not sent in the
+   client's request to initiate the authentication exchange.
+
+      S: * ACAP (SASL "DIGEST-MD5")
+      C: a001 STARTTLS
+      S: a001 OK "Begin TLS negotiation now"
+      <TLS negotiation, further commands are under TLS layer>
+
+
+
+Melnikov & Zeilenga         Standards Track                    [Page 30]
+
+RFC 4422                          SASL                         June 2006
+
+
+      S: * ACAP (SASL "DIGEST-MD5" "EXTERNAL")
+      C: a002 AUTHENTICATE "EXTERNAL"
+      S: + ""
+      C: + ""
+      S: a002 OK "Authenticated"
+
+   The second example shows use of EXTERNAL with an authorization
+   identity of "fred@example.com".  In this example, the initial
+   response is sent with the client's request to initiate the
+   authentication exchange.  This saves a round-trip.
+
+      S: * ACAP (SASL "DIGEST-MD5")
+      C: a001 STARTTLS
+      S: a001 OK "Begin TLS negotiation now"
+      <TLS negotiation, further commands are under TLS layer>
+      S: * ACAP (SASL "DIGEST-MD5" "EXTERNAL")
+      C: a002 AUTHENTICATE "EXTERNAL" {16+}
+      C: fred@example.com
+      S: a002 NO "Cannot assume requested authorization identity"
+
+A.3.  Security Considerations
+
+   The EXTERNAL mechanism provides no security protection; it is
+   vulnerable to spoofing by either client or server, active attack, and
+   eavesdropping.  It should only be used when adequate security
+   services have been established.
+
+Appendix B.  Changes since RFC 2222
+
+   This appendix is non-normative.
+
+   The material in RFC 2222 was significantly rewritten in the
+   production of this document.
+
+   RFC 2222, by not stating that the authorization identity string was a
+   string of Unicode characters, let alone character data, implied that
+   the authorization identity string was a string of octets.
+
+   -  The authorization identity string is now defined as a string of
+      Unicode characters.  The NUL (U+0000) character is prohibited.
+      While protocol specifications are responsible for defining the
+      authorization identity form, as well as the Unicode string syntax
+      and related semantics, mechanism specifications are responsible
+      for defining how the Unicode string is carried in the
+      authentication exchange.
+
+   -  Deleted "If so, when the client does not send data first, the
+      initial challenge MUST be specified as being an empty challenge."
+
+
+
+Melnikov & Zeilenga         Standards Track                    [Page 31]
+
+RFC 4422                          SASL                         June 2006
+
+
+   The following technical change was made to the EXTERNAL mechanism:
+
+      - The authorization identity string is to be UTF-8 encoded.
+
+      Note that protocol and mechanism specification requirements have
+      been significantly tightened.  Existing protocol and mechanism
+      specifications will need to be updated to meet these requirements.
+
+Editors' Addresses
+
+   Alexey Melnikov
+   Isode Limited
+   5 Castle Business Village
+   36 Station Road
+   Hampton, Middlesex,
+   TW12 2BX, United Kingdom
+
+   EMail: Alexey.Melnikov@isode.com
+   URI:   http://www.melnikov.ca/
+
+
+   Kurt D. Zeilenga
+   OpenLDAP Foundation
+
+   EMail: Kurt@OpenLDAP.org
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov & Zeilenga         Standards Track                    [Page 32]
+
+RFC 4422                          SASL                         June 2006
+
+
+Full Copyright Statement
+
+   Copyright (C) The Internet Society (2006).
+
+   This document is subject to the rights, licenses and restrictions
+   contained in BCP 78, and except as set forth therein, the authors
+   retain all their rights.
+
+   This document and the information contained herein are provided on an
+   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   Intellectual Property Rights or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; nor does it represent that it has
+   made any independent effort to identify any such rights.  Information
+   on the procedures with respect to rights in RFC documents can be
+   found in BCP 78 and BCP 79.
+
+   Copies of IPR disclosures made to the IETF Secretariat and any
+   assurances of licenses to be made available, or the result of an
+   attempt made to obtain a general license or permission for the use of
+   such proprietary rights by implementers or users of this
+   specification can be obtained from the IETF on-line IPR repository at
+   http://www.ietf.org/ipr.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights that may cover technology that may be required to implement
+   this standard.  Please address the information to the IETF at
+   ietf-ipr@ietf.org.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is provided by the IETF
+   Administrative Support Activity (IASA).
+
+
+
+
+
+
+
+Melnikov & Zeilenga         Standards Track                    [Page 33]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc4466.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,955 @@
+
+
+
+
+
+
+Network Working Group                                        A. Melnikov
+Request for Comments: 4466                                    Isode Ltd.
+Updates: 2088, 2342, 3501, 3502, 3516                           C. Daboo
+Category: Standards Track                                     April 2006
+
+
+                   Collected Extensions to IMAP4 ABNF
+
+Status of This Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (2006).
+
+Abstract
+
+   Over the years, many documents from IMAPEXT and LEMONADE working
+   groups, as well as many individual documents, have added syntactic
+   extensions to many base IMAP commands described in RFC 3501.  For
+   ease of reference, this document collects most of such ABNF changes
+   in one place.
+
+   This document also suggests a set of standard patterns for adding
+   options and extensions to several existing IMAP commands defined in
+   RFC 3501.  The patterns provide for compatibility between existing
+   and future extensions.
+
+   This document updates ABNF in RFCs 2088, 2342, 3501, 3502, and 3516.
+   It also includes part of the errata to RFC 3501.  This document
+   doesn't specify any semantic changes to the listed RFCs.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov & Daboo            Standards Track                     [Page 1]
+
+RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
+
+
+Table of Contents
+
+   1. Introduction ....................................................2
+      1.1. Purpose of This Document ...................................2
+      1.2. Conventions Used in This Document ..........................3
+   2. IMAP ABNF Extensions ............................................3
+      2.1. Optional Parameters with the SELECT/EXAMINE Commands .......3
+      2.2. Extended CREATE Command ....................................4
+      2.3. Extended RENAME Command ....................................5
+      2.4. Extensions to FETCH and UID FETCH Commands .................6
+      2.5. Extensions to STORE and UID STORE Commands .................6
+      2.6. Extensions to SEARCH Command ...............................7
+           2.6.1. Extended SEARCH Command .............................7
+           2.6.2. ESEARCH untagged response ...........................8
+      2.7. Extensions to APPEND Command ...............................8
+   3. Formal Syntax ...................................................9
+   4. Security Considerations ........................................14
+   5. Normative References ...........................................15
+   6. Acknowledgements ...............................................15
+
+1.  Introduction
+
+1.1.  Purpose of This Document
+
+   This document serves several purposes:
+
+      1.  rationalize and generalize ABNF for some existing IMAP
+          extensions;
+      2.  collect the ABNF in one place in order to minimize cross
+          references between documents;
+      3.  define building blocks for future extensions so that they can
+          be used together in a compatible way.
+
+   It is expected that a future revision of this document will be
+   incorporated into a revision of RFC 3501.
+
+   This document updates ABNF in RFCs 2088, 2342, 3501, 3502, and 3516.
+   It also includes part of the errata to RFC 3501.  This document
+   doesn't specify any semantic changes to the listed RFCs.
+
+   The ABNF in section 6 of RFC 2342 got rewritten to conform to the
+   ABNF syntax as defined in RFC 4234 and to reference new non-terminals
+   from RFC 3501.  It was also restructured to allow for better
+   readability.  There were no changes "on the wire".
+
+   Section 2 extends ABNF for SELECT, EXAMINE, CREATE, RENAME, FETCH/UID
+   FETCH, STORE/UID STORE, SEARCH, and APPEND commands in a consistent
+   manner.  Extensions to all the commands but APPEND have the same
+
+
+
+Melnikov & Daboo            Standards Track                     [Page 2]
+
+RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
+
+
+   structure.  Extensibility for the APPEND command was done slightly
+   differently in order to preserve backward compatibility with existing
+   extensions.
+
+   Section 2 also defines a new ESEARCH response, whose purpose is to
+   define a better version of the SEARCH response defined in RFC 3501.
+
+   Section 3 defines the collected ABNF that replaces pieces of ABNF in
+   the aforementioned RFCs.  The collected ABNF got generalized to allow
+   for easier future extensibility.
+
+1.2.  Conventions Used in This Document
+
+   In examples, "C:" and "S:" indicate lines sent by the client and
+   server, respectively.
+
+   The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY"
+   in this document are to be interpreted as defined in "Key words for
+   use in RFCs to Indicate Requirement Levels" [KEYWORDS].
+
+2.  IMAP ABNF Extensions
+
+   This section is not normative.  It provides some background on the
+   intended use of different extensions and it gives some guidance about
+   how future extensions should extend the described commands.
+
+2.1.  Optional Parameters with the SELECT/EXAMINE Commands
+
+   This document adds the ability to include one or more parameters with
+   the IMAP SELECT (section 6.3.1 of [IMAP4]) or EXAMINE (section 6.3.2
+   of [IMAP4]) commands, to turn on or off certain standard behaviors,
+   or to add new optional behaviors required for a particular extension.
+
+   There are two possible modes of operation:
+
+   o  A global state change where a single use of the optional parameter
+      will affect the session state from that time on, irrespective of
+      subsequent SELECT/EXAMINE commands.
+
+   o  A per-mailbox state change that will affect the session only for
+      the duration of the new selected state.  A subsequent
+      SELECT/EXAMINE without the optional parameter will cancel its
+      effect for the newly selected mailbox.
+
+   Optional parameters to the SELECT or EXAMINE commands are added as a
+   parenthesized list of attribute/value pairs, and appear after the
+   mailbox name in the standard SELECT or EXAMINE command.  The order of
+   individual parameters is arbitrary.  A parameter value is optional
+
+
+
+Melnikov & Daboo            Standards Track                     [Page 3]
+
+RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
+
+
+   and may consist of atoms, strings, or lists in a specific order.  If
+   the parameter value is present, it always appears in parentheses (*).
+   Any parameter not defined by extensions that the server supports must
+   be rejected with a BAD response.
+
+      Example:
+
+              C: a SELECT INBOX (ANNOTATE)
+              S: ...
+              S: a OK SELECT complete
+
+      In the above example, a single parameter is used with the SELECT
+      command.
+
+      Example:
+
+              C: a EXAMINE INBOX (ANNOTATE RESPONSES ("UID Responses")
+                 CONDSTORE)
+              S: ...
+              S: a OK EXAMINE complete
+
+      In the above example, three parameters are used with the EXAMINE
+      command.  The second parameter consists of two items: an atom
+      "RESPONSES" followed by a quoted string.
+
+      Example:
+
+              C: a SELECT INBOX (BLURDYBLOOP)
+              S: a BAD Unknown parameter in SELECT command
+
+      In the above example, a parameter not supported by the server is
+      used.  This results in the BAD response from the server.
+
+   (*) - if a parameter has a mandatory value, which can always be
+   represented as a number or a sequence-set, the parameter value does
+   not need the enclosing ().  See ABNF for more details.
+
+2.2.  Extended CREATE Command
+
+   Arguments:  mailbox name
+               OPTIONAL list of CREATE parameters
+
+   Responses:  no specific responses for this command
+
+   Result:     OK - create completed
+               NO - create failure: cannot create mailbox with
+                    that name
+               BAD - argument(s) invalid
+
+
+
+Melnikov & Daboo            Standards Track                     [Page 4]
+
+RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
+
+
+   This document adds the ability to include one or more parameters with
+   the IMAP CREATE command (see section 6.3.3 of [IMAP4]), to turn on or
+   off certain standard behaviors, or to add new optional behaviors
+   required for a particular extension.  No CREATE parameters are
+   defined in this document.
+
+   Optional parameters to the CREATE command are added as a
+   parenthesized list of attribute/value pairs after the mailbox name.
+   The order of individual parameters is arbitrary.  A parameter value
+   is optional and may consist of atoms, strings, or lists in a specific
+   order.  If the parameter value is present, it always appears in
+   parentheses (*).  Any parameter not defined by extensions that the
+   server supports must be rejected with a BAD response.
+
+   (*) - if a parameter has a mandatory value, which can always be
+   represented as a number or a sequence-set, the parameter value does
+   not need the enclosing ().  See ABNF for more details.
+
+2.3.  Extended RENAME Command
+
+   Arguments:  existing mailbox name
+               new mailbox name
+               OPTIONAL list of RENAME parameters
+
+   Responses:  no specific responses for this command
+
+   Result:     OK - rename completed
+               NO - rename failure: cannot rename mailbox with
+                    that name, cannot rename to mailbox with
+                    that name, etc.
+               BAD - argument(s) invalid
+
+   This document adds the ability to include one or more parameters with
+   the IMAP RENAME command (see section 6.3.5 of [IMAP4]), to turn on or
+   off certain standard behaviors, or to add new optional behaviors
+   required for a particular extension.  No RENAME parameters are
+   defined in this document.
+
+   Optional parameters to the RENAME command are added as a
+   parenthesized list of attribute/value pairs after the new mailbox
+   name.  The order of individual parameters is arbitrary.  A parameter
+   value is optional and may consist of atoms, strings, or lists in a
+   specific order.  If the parameter value is present, it always appears
+   in parentheses (*).  Any parameter not defined by extensions that the
+   server supports must be rejected with a BAD response.
+
+
+
+
+
+
+Melnikov & Daboo            Standards Track                     [Page 5]
+
+RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
+
+
+   (*) - if a parameter has a mandatory value, which can always be
+   represented as a number or a sequence-set, the parameter value does
+   not need the enclosing ().  See ABNF for more details.
+
+2.4.  Extensions to FETCH and UID FETCH Commands
+
+   Arguments:  sequence set
+               message data item names or macro
+               OPTIONAL fetch modifiers
+
+   Responses:  untagged responses: FETCH
+
+   Result:     OK - fetch completed
+               NO - fetch error: cannot fetch that data
+               BAD - command unknown or arguments invalid
+
+   This document extends the syntax of the FETCH and UID FETCH commands
+   (see section 6.4.5 of [IMAP4]) to include optional FETCH modifiers.
+   No fetch modifiers are defined in this document.
+
+   The order of individual modifiers is arbitrary.  Each modifier is an
+   attribute/value pair.  A modifier value is optional and may consist
+   of atoms and/or strings and/or lists in a specific order.  If the
+   modifier value is present, it always appears in parentheses (*).  Any
+   modifiers not defined by extensions that the server supports must be
+   rejected with a BAD response.
+
+   (*) - if a modifier has a mandatory value, which can always be
+   represented as a number or a sequence-set, the modifier value does
+   not need the enclosing ().  See ABNF for more details.
+
+2.5.  Extensions to STORE and UID STORE Commands
+
+   Arguments:  message set
+               OPTIONAL store modifiers
+               message data item name
+               value for message data item
+
+   Responses:  untagged responses: FETCH
+
+   Result:     OK - store completed
+               NO - store error: cannot store that data
+               BAD - command unknown or arguments invalid
+
+   This document extends the syntax of the STORE and UID STORE commands
+   (see section 6.4.6 of [IMAP4]) to include optional STORE modifiers.
+   No store modifiers are defined in this document.
+
+
+
+
+Melnikov & Daboo            Standards Track                     [Page 6]
+
+RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
+
+
+   The order of individual modifiers is arbitrary.  Each modifier is an
+   attribute/value pair.  A modifier value is optional and may consist
+   of atoms and/or strings and/or lists in a specific order.  If the
+   modifier value is present, it always appears in parentheses (*).  Any
+   modifiers not defined by extensions that the server supports must be
+   rejected with a BAD response.
+
+   (*) - if a modifier has a mandatory value, which can always be
+   represented as a number or a sequence-set, the modifier value does
+   not need the enclosing ().  See ABNF for more details.
+
+2.6.  Extensions to SEARCH Command
+
+2.6.1.  Extended SEARCH Command
+
+   Arguments:  OPTIONAL result specifier
+               OPTIONAL [CHARSET] specification
+               searching criteria (one or more)
+
+   Responses:  REQUIRED untagged response: SEARCH (*)
+
+   Result:     OK - search completed
+               NO - search error: cannot search that [CHARSET] or
+                    criteria
+               BAD - command unknown or arguments invalid
+
+   This section updates definition of the SEARCH command described in
+   section 6.4.4 of [IMAP4].
+
+   The SEARCH command is extended to allow for result options.  This
+   document does not define any result options.
+
+   The order of individual options is arbitrary.  Individual options may
+   contain parameters enclosed in parentheses (**).  If an option has
+   parameters, they consist of atoms and/or strings and/or lists in a
+   specific order.  Any options not defined by extensions that the
+   server supports must be rejected with a BAD response.
+
+   (*) - An extension to the SEARCH command may require another untagged
+   response, or no untagged response to be returned.  Section 2.6.2
+   defines a new ESEARCH untagged response that replaces the SEARCH
+   untagged response.  Note that for a given extended SEARCH command the
+   SEARCH and ESEARCH responses SHOULD be mutually exclusive, i.e., only
+   one of them should be returned.
+
+   (**) - if an option has a mandatory parameter, which can always be
+   represented as a number or a sequence-set, the option parameter does
+   not need the enclosing ().  See ABNF for more details.
+
+
+
+Melnikov & Daboo            Standards Track                     [Page 7]
+
+RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
+
+
+2.6.2.  ESEARCH untagged response
+
+   Contents:   one or more search-return-data pairs
+
+   The ESEARCH response SHOULD be sent as a result of an extended SEARCH
+   or UID SEARCH command specified in section 2.6.1.
+
+   The ESEARCH response starts with an optional search correlator.  If
+   it is missing, then the response was not caused by a particular IMAP
+   command, whereas if it is present, it contains the tag of the command
+   that caused the response to be returned.
+
+   The search correlator is followed by an optional UID indicator.  If
+   this indicator is present, all data in the ESEARCH response refers to
+   UIDs, otherwise all returned data refers to message numbers.
+
+   The rest of the ESEARCH response contains one or more search data
+   pairs.  Each pair starts with unique return item name, followed by a
+   space and the corresponding data.  Search data pairs may be returned
+   in any order.  Unless specified otherwise by an extension, any return
+   item name SHOULD appear only once in an ESEARCH response.
+
+   Example:    S: * ESEARCH UID COUNT 5 ALL 4:19,21,28
+
+   Example:    S: * ESEARCH (TAG "a567") UID COUNT 5 ALL 4:19,21,28
+
+   Example:    S: * ESEARCH COUNT 5 ALL 1:17,21
+
+2.7.  Extensions to APPEND Command
+
+   The IMAP BINARY extension [BINARY] extends the APPEND command to
+   allow a client to append data containing NULs by using the <literal8>
+   syntax.  The ABNF was rewritten to allow for easier extensibility by
+   IMAP extensions.  This document hasn't specified any semantical
+   changes to the [BINARY] extension.
+
+   In addition, the non-terminal "literal8" defined in [BINARY] got
+   extended to allow for non-synchronizing literals if both [BINARY] and
+   [LITERAL+] extensions are supported by the server.
+
+   The IMAP MULTIAPPEND extension [MULTIAPPEND] extends the APPEND
+   command to allow a client to append multiple messages atomically.
+   This document defines a common syntax for the APPEND command that
+   takes into consideration syntactic extensions defined by both
+   [BINARY] and [MULTIAPPEND] extensions.
+
+
+
+
+
+
+Melnikov & Daboo            Standards Track                     [Page 8]
+
+RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
+
+
+3.  Formal Syntax
+
+   The following syntax specification uses the Augmented Backus-Naur
+   Form (ABNF) notation as specified in [ABNF].
+
+   Non-terminals referenced but not defined below are as defined by
+   [IMAP4].
+
+   Except as noted otherwise, all alphabetic characters are case-
+   insensitive.  The use of uppercase or lowercase characters to define
+   token strings is for editorial clarity only.  Implementations MUST
+   accept these strings in a case-insensitive fashion.
+
+   append          = "APPEND" SP mailbox 1*append-message
+                     ;; only a single append-message may appear
+                     ;; if MULTIAPPEND [MULTIAPPEND] capability
+                     ;; is not present
+
+   append-message  = append-opts SP append-data
+
+   append-ext      = append-ext-name SP append-ext-value
+                     ;; This non-terminal define extensions to
+                     ;; to message metadata.
+
+   append-ext-name = tagged-ext-label
+
+   append-ext-value= tagged-ext-val
+                     ;; This non-terminal shows recommended syntax
+                     ;; for future extensions.
+
+
+   append-data     = literal / literal8 / append-data-ext
+
+   append-data-ext = tagged-ext
+                     ;; This non-terminal shows recommended syntax
+                     ;; for future extensions,
+                     ;; i.e., a mandatory label followed
+                     ;; by parameters.
+
+   append-opts     = [SP flag-list] [SP date-time] *(SP append-ext)
+                     ;; message metadata
+
+   charset         = atom / quoted
+                     ;; Exact syntax is defined in [CHARSET].
+
+   create          = "CREATE" SP mailbox
+                     [create-params]
+                     ;; Use of INBOX gives a NO error.
+
+
+
+Melnikov & Daboo            Standards Track                     [Page 9]
+
+RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
+
+
+   create-params   = SP "(" create-param *( SP create-param) ")"
+
+   create-param-name = tagged-ext-label
+
+   create-param      = create-param-name [SP create-param-value]
+
+   create-param-value= tagged-ext-val
+                     ;; This non-terminal shows recommended syntax
+                     ;; for future extensions.
+
+
+   esearch-response  = "ESEARCH" [search-correlator] [SP "UID"]
+                        *(SP search-return-data)
+                      ;; Note that SEARCH and ESEARCH responses
+                      ;; SHOULD be mutually exclusive,
+                      ;; i.e., only one of the response types
+                      ;; should be
+                      ;; returned as a result of a command.
+
+
+   examine         = "EXAMINE" SP mailbox [select-params]
+                     ;; modifies the original IMAP EXAMINE command
+                     ;; to accept optional parameters
+
+   fetch           = "FETCH" SP sequence-set SP ("ALL" / "FULL" /
+                     "FAST" / fetch-att /
+                     "(" fetch-att *(SP fetch-att) ")")
+                     [fetch-modifiers]
+                     ;; modifies the original IMAP4 FETCH command to
+                     ;; accept optional modifiers
+
+   fetch-modifiers = SP "(" fetch-modifier *(SP fetch-modifier) ")"
+
+   fetch-modifier  = fetch-modifier-name [ SP fetch-modif-params ]
+
+   fetch-modif-params  = tagged-ext-val
+                     ;; This non-terminal shows recommended syntax
+                     ;; for future extensions.
+
+   fetch-modifier-name = tagged-ext-label
+
+   literal8        = "~{" number ["+"] "}" CRLF *OCTET
+                      ;; A string that might contain NULs.
+                      ;; <number> represents the number of OCTETs
+                      ;; in the response string.
+                      ;; The "+" is only allowed when both LITERAL+ and
+                      ;; BINARY extensions are supported by the server.
+
+
+
+
+Melnikov & Daboo            Standards Track                    [Page 10]
+
+RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
+
+
+   mailbox-data      =/ Namespace-Response /
+                        esearch-response
+
+   Namespace         = nil / "(" 1*Namespace-Descr ")"
+
+   Namespace-Command = "NAMESPACE"
+
+   Namespace-Descr   = "(" string SP
+                          (DQUOTE QUOTED-CHAR DQUOTE / nil)
+                           *(Namespace-Response-Extension) ")"
+
+   Namespace-Response-Extension = SP string SP
+                     "(" string *(SP string) ")"
+
+   Namespace-Response = "NAMESPACE" SP Namespace
+                        SP Namespace SP Namespace
+         ;; This response is currently only allowed
+         ;; if the IMAP server supports [NAMESPACE].
+         ;; The first Namespace is the Personal Namespace(s)
+         ;; The second Namespace is the Other Users' Namespace(s)
+         ;; The third Namespace is the Shared Namespace(s)
+
+   rename          = "RENAME" SP mailbox SP mailbox
+                     [rename-params]
+                     ;; Use of INBOX as a destination gives
+                     ;; a NO error, unless rename-params
+                     ;; is not empty.
+
+   rename-params     = SP "(" rename-param *( SP rename-param) ")"
+
+   rename-param      = rename-param-name [SP rename-param-value]
+
+   rename-param-name = tagged-ext-label
+
+   rename-param-value= tagged-ext-val
+                     ;; This non-terminal shows recommended syntax
+                     ;; for future extensions.
+
+
+   response-data   = "*" SP response-payload CRLF
+
+   response-payload= resp-cond-state / resp-cond-bye /
+                     mailbox-data / message-data / capability-data
+
+   search          = "SEARCH" [search-return-opts]
+                     SP search-program
+
+   search-correlator  = SP "(" "TAG" SP tag-string ")"
+
+
+
+Melnikov & Daboo            Standards Track                    [Page 11]
+
+RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
+
+
+   search-program     = ["CHARSET" SP charset SP]
+                        search-key *(SP search-key)
+                        ;; CHARSET argument to SEARCH MUST be
+                        ;; registered with IANA.
+
+   search-return-data = search-modifier-name SP search-return-value
+                        ;; Note that not every SEARCH return option
+                        ;; is required to have the corresponding
+                        ;; ESEARCH return data.
+
+   search-return-opts = SP "RETURN" SP "(" [search-return-opt
+                        *(SP search-return-opt)] ")"
+
+   search-return-opt = search-modifier-name [SP search-mod-params]
+
+   search-return-value = tagged-ext-val
+                        ;; Data for the returned search option.
+                        ;; A single "nz-number"/"number" value
+                        ;; can be returned as an atom (i.e., without
+                        ;; quoting).  A sequence-set can be returned
+                        ;; as an atom as well.
+
+   search-modifier-name = tagged-ext-label
+
+   search-mod-params = tagged-ext-val
+                     ;; This non-terminal shows recommended syntax
+                     ;; for future extensions.
+
+
+   select          = "SELECT" SP mailbox [select-params]
+                     ;; modifies the original IMAP SELECT command to
+                     ;; accept optional parameters
+
+   select-params   = SP "(" select-param *(SP select-param) ")"
+
+   select-param    = select-param-name [SP select-param-value]
+                     ;; a parameter to SELECT may contain one or
+                     ;; more atoms and/or strings and/or lists.
+
+   select-param-name= tagged-ext-label
+
+   select-param-value= tagged-ext-val
+                     ;; This non-terminal shows recommended syntax
+                     ;; for future extensions.
+
+
+   status-att-list = status-att-val *(SP status-att-val)
+                     ;; Redefines status-att-list from RFC 3501.
+
+
+
+Melnikov & Daboo            Standards Track                    [Page 12]
+
+RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
+
+
+                     ;; status-att-val is defined in RFC 3501 errata
+
+   status-att-val  = ("MESSAGES" SP number) /
+                     ("RECENT" SP number) /
+                     ("UIDNEXT" SP nz-number) /
+                     ("UIDVALIDITY" SP nz-number) /
+                     ("UNSEEN" SP number)
+                     ;; Extensions to the STATUS responses
+                     ;; should extend this production.
+                     ;; Extensions should use the generic
+                     ;; syntax defined by tagged-ext.
+
+   store           = "STORE" SP sequence-set [store-modifiers]
+                     SP store-att-flags
+                     ;; extend [IMAP4] STORE command syntax
+                     ;; to allow for optional store-modifiers
+
+   store-modifiers =  SP "(" store-modifier *(SP store-modifier)
+                       ")"
+
+   store-modifier  = store-modifier-name [SP store-modif-params]
+
+   store-modif-params = tagged-ext-val
+                     ;; This non-terminal shows recommended syntax
+                     ;; for future extensions.
+
+   store-modifier-name = tagged-ext-label
+
+   tag-string         = string
+                        ;; tag of the command that caused
+                        ;; the ESEARCH response, sent as
+                        ;; a string.
+
+   tagged-ext          = tagged-ext-label SP tagged-ext-val
+                          ;; recommended overarching syntax for
+                          ;; extensions
+
+   tagged-ext-label    = tagged-label-fchar *tagged-label-char
+                         ;; Is a valid RFC 3501 "atom".
+
+   tagged-label-fchar  = ALPHA / "-" / "_" / "."
+
+   tagged-label-char   = tagged-label-fchar / DIGIT / ":"
+
+
+
+
+
+
+
+
+Melnikov & Daboo            Standards Track                    [Page 13]
+
+RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
+
+
+   tagged-ext-comp     = astring /
+                         tagged-ext-comp *(SP tagged-ext-comp) /
+                         "(" tagged-ext-comp ")"
+                          ;; Extensions that follow this general
+                          ;; syntax should use nstring instead of
+                          ;; astring when appropriate in the context
+                          ;; of the extension.
+                          ;; Note that a message set or a "number"
+                          ;; can always be represented as an "atom".
+                          ;; An URL should be represented as
+                          ;; a "quoted" string.
+
+   tagged-ext-simple   = sequence-set / number
+
+   tagged-ext-val      = tagged-ext-simple /
+                         "(" [tagged-ext-comp] ")"
+
+4.  Security Considerations
+
+   This document updates ABNF in RFCs 2088, 2342, 3501, 3502, and 3516.
+   The updated documents must be consulted for security considerations
+   for the extensions that they define.
+
+   As a protocol gets more complex, parser bugs become more common
+   including buffer overflow, denial of service, and other common
+   security coding errors.  To the extent that this document makes the
+   parser more complex, it makes this situation worse.  To the extent
+   that this document makes the parser more consistent and thus simpler,
+   the situation is improved.  The impact will depend on how many
+   deployed IMAP extensions are consistent with this document.
+   Implementers are encouraged to take care of these issues when
+   extending existing implementations.  Future IMAP extensions should
+   strive for consistency and simplicity to the greatest extent
+   possible.
+
+   Extensions to IMAP commands that are permitted in NOT AUTHENTICATED
+   state are more sensitive to these security issues due to the larger
+   possible attacker community prior to authentication, and the fact
+   that some IMAP servers run with elevated privileges in that state.
+   This document does not extend any commands permitted in NOT
+   AUTHENTICATED state.  Future IMAP extensions to commands permitted in
+   NOT AUTHENTICATED state should favor simplicity over consistency or
+   extensibility.
+
+
+
+
+
+
+
+
+Melnikov & Daboo            Standards Track                    [Page 14]
+
+RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
+
+
+5.  Normative References
+
+   [KEYWORDS]    Bradner, S., "Key words for use in RFCs to Indicate
+                 Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+   [IMAP4]       Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL -
+                 VERSION 4rev1", RFC 3501, March 2003.
+
+   [ABNF]        Crocker, D., Ed., and P. Overell, "Augmented BNF for
+                 Syntax Specifications: ABNF", RFC 4234, October 2005.
+
+   [CHARSET]     Freed, N. and J. Postel, "IANA Charset Registration
+                 Procedures", BCP 19, RFC 2978, October 2000.
+
+   [MULTIAPPEND] Crispin, M., "Internet Message Access Protocol (IMAP) -
+                 MULTIAPPEND Extension", RFC 3502, March 2003.
+
+   [NAMESPACE]   Gahrns, M. and C. Newman, "IMAP4 Namespace", RFC 2342,
+                 May 1998.
+
+   [LITERAL+]    Myers, J., "IMAP4 non-synchronizing literals", RFC
+                 2088, January 1997.
+
+   [BINARY]      Nerenberg, L., "IMAP4 Binary Content Extension", RFC
+                 3516, April 2003.
+
+6.  Acknowledgements
+
+   This documents is based on ideas proposed by Pete Resnick, Mark
+   Crispin, Ken Murchison, Philip Guenther, Randall Gellens, and Lyndon
+   Nerenberg.
+
+   However, all errors and omissions must be attributed to the authors
+   of the document.
+
+   Thanks to Philip Guenther, Dave Cridland, Mark Crispin, Chris Newman,
+   Elwyn Davies, and Barry Leiba for comments and corrections.
+
+   literal8 syntax was taken from RFC 3516.
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov & Daboo            Standards Track                    [Page 15]
+
+RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
+
+
+Authors' Addresses
+
+   Alexey Melnikov
+   Isode Limited
+   5 Castle Business Village
+   36 Station Road
+   Hampton, Middlesex, TW12 2BX
+   UK
+
+   EMail: Alexey.Melnikov@isode.com
+
+
+   Cyrus Daboo
+
+   EMail: cyrus@daboo.name
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov & Daboo            Standards Track                    [Page 16]
+
+RFC 4466           Collected Extensions to IMAP4 ABNF         April 2006
+
+
+Full Copyright Statement
+
+   Copyright (C) The Internet Society (2006).
+
+   This document is subject to the rights, licenses and restrictions
+   contained in BCP 78, and except as set forth therein, the authors
+   retain all their rights.
+
+   This document and the information contained herein are provided on an
+   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   Intellectual Property Rights or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; nor does it represent that it has
+   made any independent effort to identify any such rights.  Information
+   on the procedures with respect to rights in RFC documents can be
+   found in BCP 78 and BCP 79.
+
+   Copies of IPR disclosures made to the IETF Secretariat and any
+   assurances of licenses to be made available, or the result of an
+   attempt made to obtain a general license or permission for the use of
+   such proprietary rights by implementers or users of this
+   specification can be obtained from the IETF on-line IPR repository at
+   http://www.ietf.org/ipr.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights that may cover technology that may be required to implement
+   this standard.  Please address the information to the IETF at
+   ietf-ipr@ietf.org.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is provided by the IETF
+   Administrative Support Activity (IASA).
+
+
+
+
+
+
+
+Melnikov & Daboo            Standards Track                    [Page 17]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc4467.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1011 @@
+
+
+
+
+
+
+Network Working Group                                         M. Crispin
+Request for Comments: 4467                      University of Washington
+Updates: 3501                                                   May 2006
+Category: Standards Track
+
+
+      Internet Message Access Protocol (IMAP) - URLAUTH Extension
+
+Status of This Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (2006).
+
+Abstract
+
+   This document describes the URLAUTH extension to the Internet Message
+   Access Protocol (IMAP) (RFC 3501) and the IMAP URL Scheme (IMAPURL)
+   (RFC 2192).  This extension provides a means by which an IMAP client
+   can use URLs carrying authorization to access limited message data on
+   the IMAP server.
+
+   An IMAP server that supports this extension indicates this with a
+   capability name of "URLAUTH".
+
+1.  Introduction
+
+   In [IMAPURL], a URL of the form imap://fred@example.com/INBOX/;uid=20
+   requires authorization as userid "fred".  However, [IMAPURL] implies
+   that it only supports authentication and confuses the concepts of
+   authentication and authorization.
+
+   The URLAUTH extension defines an authorization mechanism for IMAP
+   URLs to replace [IMAPURL]'s authentication-only mechanism.  URLAUTH
+   conveys authorization in the URL string itself and reuses a portion
+   of the syntax of the [IMAPURL] authentication mechanism to convey the
+   authorization identity (which also defines the default namespace in
+   [IMAP]).
+
+   The URLAUTH extension provides a means by which an authorized user of
+   an IMAP server can create URLAUTH-authorized IMAP URLs.  A URLAUTH-
+   authorized URL conveys authorization (not authentication) to the data
+
+
+
+Crispin                     Standards Track                     [Page 1]
+
+RFC 4467                IMAP - URLAUTH Extension                May 2006
+
+
+   addressed by that URL.  This URL can be used in another IMAP session
+   to access specific content on the IMAP server, without otherwise
+   providing authorization to any other data (such as other data in the
+   mailbox specified in the URL) owned by the authorizing user.
+
+   Conceptually, a URLAUTH-authorized URL can be thought of as a "pawn
+   ticket" that carries no authentication information and can be
+   redeemed by whomever presents it.  However, unlike a pawn ticket,
+   URLAUTH has optional mechanisms to restrict the usage of a URLAUTH-
+   authorized URL.  Using these mechanisms, URLAUTH-authorized URLs can
+   be usable by:
+
+      . anonymous (the "pawn ticket" model)
+      . authenticated users only
+      . a specific authenticated user only
+      . message submission acting on behalf of a specific user only
+
+   There is also a mechanism for expiration.
+
+   A URLAUTH-authorized URL can be used in the argument to the BURL
+   command in message composition, as described in [BURL], for such
+   purposes as allowing a client (with limited memory or other
+   resources) to submit a message forward or to resend from an IMAP
+   mailbox without requiring the client to fetch that message data.
+
+   The URLAUTH is generated using an authorization mechanism name and an
+   authorization token, which is generated using a secret mailbox access
+   key.  An IMAP client can request that the server generate and assign
+   a new mailbox access key (thus effectively revoking all current URLs
+   using URLAUTH with the old mailbox access key) but cannot set the
+   mailbox access key to a key of its own choosing.
+
+1.1.  Conventions Used in this Document
+
+   The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY"
+   in this document are to be interpreted as defined in [KEYWORDS].
+
+   The formal syntax uses the Augmented Backus-Naur Form (ABNF) notation
+   including the core rules defined in Appendix A of [ABNF].
+
+   In examples, "C:" and "S:" indicate lines sent by the client and
+   server, respectively.  If a single "C:" or "S:" label applies to
+   multiple lines, then the line breaks between those lines are for
+   editorial clarity only and are not part of the actual protocol
+   exchange.
+
+
+
+
+
+
+Crispin                     Standards Track                     [Page 2]
+
+RFC 4467                IMAP - URLAUTH Extension                May 2006
+
+
+2.  Concepts
+
+2.1.  URLAUTH
+
+   The URLAUTH is a component, appended at the end of a URL, that
+   conveys authorization to access the data addressed by that URL.  It
+   contains an authorized access identifier, an authorization mechanism
+   name, and an authorization token.  The authorization token is
+   generated from the URL, the authorized access identifier, the
+   authorization mechanism name, and a mailbox access key.
+
+2.2.  Mailbox Access Key
+
+   The mailbox access key is a random string with at least 128 bits of
+   entropy.  It is generated by software (not by the human user) and
+   MUST be unpredictable.
+
+   Each user has a table of mailboxes and an associated mailbox access
+   key for each mailbox.  Consequently, the mailbox access key is per-
+   user and per-mailbox.  In other words, two users sharing the same
+   mailbox each have a different mailbox access key for that mailbox,
+   and each mailbox accessed by a single user also has a different
+   mailbox access key.
+
+2.3.  Authorized Access Identifier
+
+   The authorized access identifier restricts use of the URLAUTH
+   authorized URL to certain users authorized on the server, as
+   described in section 3.
+
+2.4.  Authorization Mechanism
+
+   The authorization mechanism is the algorithm by which the URLAUTH is
+   generated and subsequently verified, using the mailbox access key.
+
+2.4.1.  INTERNAL Authorization Mechanism
+
+   This specification defines the INTERNAL mechanism, which uses a token
+   generation algorithm of the server's choosing and does not involve
+   disclosure of the mailbox access key to the client.
+
+      Note: The token generation algorithm chosen by the server
+      implementation should be modern and reasonably secure.  At the
+      time of the writing of this document, an [HMAC] such as HMAC-SHA1
+      is recommended.
+
+
+
+
+
+
+Crispin                     Standards Track                     [Page 3]
+
+RFC 4467                IMAP - URLAUTH Extension                May 2006
+
+
+      If it becomes necessary to change the token generation algorithm
+      of the INTERNAL mechanism (e.g., because an attack against the
+      current algorithm has been discovered), all currently existing
+      URLAUTH-authorized URLs are invalidated by the change in
+      algorithm.  Since this would be an unpleasant surprise to
+      applications that depend upon the validity of a URLAUTH-authorized
+      URL, and there is no good way to do a bulk update of existing
+      deployed URLs, it is best to avoid this situation by using a
+      secure algorithm as opposed to one that is "good enough".
+
+      Server implementations SHOULD consider the possibility of changing
+      the algorithm.  In some cases, it may be desirable to implement
+      the change of algorithm in a way that newly-generated tokens use
+      the new algorithm, but that for a limited period of time tokens
+      using either the new or old algorithm can be validated.
+      Consequently, the server SHOULD incorporate some means of
+      identifying the token generation algorithm within the token.
+
+   Although this specification is extensible for other mechanisms, none
+   are defined in this document.  In addition to the mechanism name
+   itself, other mechanisms may have mechanism-specific data, which is
+   to be interpreted according to the definition of that mechanism.
+
+2.5.  Authorization Token
+
+   The authorization token is a deterministic string of at least 128
+   bits that an entity with knowledge of the secret mailbox access key
+   and URL authorization mechanism can use to verify the URL.
+
+3.  IMAP URL Extensions
+
+   [IMAPURL] is extended by allowing the addition of
+   ";EXPIRE=<datetime>" and ";URLAUTH=<access>:<mech>:<token>" to IMAP
+   URLs that refer to a specific message or message parts.
+
+   The URLAUTH is comprised of ";URLAUTH=<access>:<mech>:<token>" and
+   MUST be at the end of the URL.
+
+   URLAUTH does not apply to, and MUST NOT be used with, any IMAP URL
+   that refers to an entire IMAP server, a list of mailboxes, an entire
+   IMAP mailbox, or IMAP search results.
+
+   When ";EXPIRE=<datetime>" is used, this indicates the latest date and
+   time that the URL is valid.  After that date and time, the URL has
+   expired, and server implementations MUST reject the URL.  If
+   ";EXPIRE=<datetime>" is not used, the URL has no expiration, but
+   still can be revoked as discussed below.
+
+
+
+
+Crispin                     Standards Track                     [Page 4]
+
+RFC 4467                IMAP - URLAUTH Extension                May 2006
+
+
+   The URLAUTH takes the form ";URLAUTH=<access>:<mech>:<token>".  It is
+   composed of three parts.  The <access> portion provides the
+   authorized access identifiers, which may constrain the operations and
+   users that are permitted to use this URL.  The <mech> portion
+   provides the authorization mechanism used by the IMAP server to
+   generate the authorization token that follows.  The <token> portion
+   provides the authorization token.
+
+   The "submit+" access identifier prefix, followed by a userid,
+   indicates that only a userid authorized as a message submission
+   entity on behalf of the specified userid is permitted to use this
+   URL.  The IMAP server does not validate the specified userid but does
+   validate that the IMAP session has an authorization identity that is
+   authorized as a message submission entity.  The authorized message
+   submission entity MUST validate the userid prior to contacting the
+   IMAP server.
+
+   The "user+" access identifier prefix, followed by a userid, indicates
+   that use of this URL is limited to IMAP sessions that are logged in
+   as the specified userid (that is, have authorization identity as that
+   userid).
+
+      Note: If a SASL mechanism that provides both authorization and
+      authentication identifiers is used to authenticate to the IMAP
+      server, the "user+" access identifier MUST match the authorization
+      identifier.
+
+   The "authuser" access identifier indicates that use of this URL is
+   limited to IMAP sessions that are logged in as an authorized user
+   (that is, have authorization identity as an authorized user) of that
+   IMAP server.  Use of this URL is prohibited to anonymous IMAP
+   sessions.
+
+   The "anonymous" access identifier indicates that use of this URL is
+   not restricted by session authorization identity; that is, any IMAP
+   session in authenticated or selected state (as defined in [IMAP]),
+   including anonymous sessions, may issue a URLFETCH using this URL.
+
+   The authorization token is represented as an ASCII-encoded
+   hexadecimal string, which is used to authorize the URL.  The length
+   and the calculation of the authorization token depends upon the
+   mechanism used; but, in all cases, the authorization token is at
+   least 128 bits (and therefore at least 32 hexadecimal digits).
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                     [Page 5]
+
+RFC 4467                IMAP - URLAUTH Extension                May 2006
+
+
+4.  Discussion of URLAUTH Authorization Issues
+
+   In [IMAPURL], the userid before the "@" in the URL has two purposes:
+
+      1) It provides context for user-specific mailbox paths such as
+         "INBOX".
+
+      2) It specifies that resolution of the URL requires logging in as
+         that user and limits use of that URL to only that user.
+
+   An obvious limitation of using the same field for both purposes is
+   that the URL can only be resolved by the mailbox owner.
+
+   URLAUTH overrides the second purpose of the userid in the IMAP URL
+   and by default permits the URL to be resolved by any user permitted
+   by the access identifier.
+
+   The "user+<userid>" access identifier limits resolution of that URL
+   to a particular userid, whereas the "submit+<userid>" access
+   identifier is more general and simply requires that the session be
+   authorized by a user that has been granted a "submit" role within the
+   authentication system.  Use of either of these access identifiers
+   makes it impossible for an attacker, spying on the session, to use
+   the same URL, either directly or by submission to a message
+   submission entity.
+
+   The "authuser" and "anonymous" access identifiers do not have this
+   level of protection and should be used with caution.  These access
+   identifiers are primarily useful for public export of data from an
+   IMAP server, without requiring that it be copied to a web or
+   anonymous FTP server.  Refer to the Security Considerations for more
+   details.
+
+5.  Generation of URLAUTH-Authorized URLs
+
+   A URLAUTH-authorized URL is generated from an initial URL as follows:
+
+   An initial URL is built, ending with ";URLAUTH=<access>" but without
+   the ":<mech>:<token>" components.  An authorization mechanism is
+   selected and used to calculate the authorization token, with the
+   initial URL as the data and a secret known to the IMAP server as the
+   key.  The URLAUTH-authorized URL is generated by taking the initial
+   URL and appending ":", the URL authorization mechanism name, ":", and
+   the ASCII-encoded hexadecimal representation of the authorization
+   token.
+
+
+
+
+
+
+Crispin                     Standards Track                     [Page 6]
+
+RFC 4467                IMAP - URLAUTH Extension                May 2006
+
+
+      Note: ASCII-encoded hexadecimal is used instead of BASE64 because
+      a BASE64 representation may have "=" padding characters, which
+      would be problematic in a URL.
+
+   In the INTERNAL mechanism, the mailbox access key for that mailbox is
+   the secret known to the IMAP server, and a server-selected algorithm
+   is used as described in section 2.4.1.
+
+6.  Validation of URLAUTH-authorized URLs
+
+   A URLAUTH-authorized URL is validated as follows:
+
+   The URL is split at the ":" that separates "<access>" from
+   "<mech>:<token>" in the ";URLAUTH=<access>:<mech>:<token>" portion of
+   the URL.  The "<mech>:<token>" portion is first parsed and saved as
+   the authorization mechanism and the authorization token.  The URL is
+   truncated, discarding the ":" described above, to create a "rump URL"
+   (the URL minus the ":" and the "<mech>:<token>" portion).  The rump
+   URL is then analyzed to identify the mailbox.
+
+   If the mailbox cannot be identified, an authorization token is
+   calculated on the rump URL, using random "plausible" keys (selected
+   by the server) as needed, before returning a validation failure.
+   This prevents timing attacks aimed at identifying mailbox names.
+
+   If the mailbox can be identified, the authorization token is
+   calculated on the rump URL and a secret known to the IMAP server
+   using the given URL authorization mechanism.  Validation is
+   successful if, and only if, the calculated authorization token for
+   that mechanism matches the authorization token supplied in
+   ";URLAUTH=<access>:<mech>:<token>".
+
+   Removal of the ":<mech>:<token>" portion of the URL MUST be the only
+   operation applied to the URLAUTH-authorized URL to get the rump URL.
+   In particular, URL percent escape decoding and case-folding
+   (including to the domain part of the URL) MUST NOT occur.
+
+   In the INTERNAL mechanism, the mailbox access key for that mailbox is
+   used as the secret known to the IMAP server, and the same server-
+   selected algorithm used for generating URLs is used to calculate the
+   authorization token for verification.
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                     [Page 7]
+
+RFC 4467                IMAP - URLAUTH Extension                May 2006
+
+
+7.  Additional Commands
+
+   These commands are extensions to the [IMAP] base protocol.
+
+   The section headings of these commands are intended to correspond
+   with where they would be located in the base protocol document if
+   they were part of that document.
+
+BASE.6.3.RESETKEY.  RESETKEY Command
+
+   Arguments:  optional mailbox name
+               optional mechanism name(s)
+
+   Responses:  none other than in result
+
+   Result:     OK - RESETKEY completed, URLMECH containing new data
+               NO - RESETKEY error: can't change key of that mailbox
+               BAD - command unknown or arguments invalid
+
+   The RESETKEY command has two forms.
+
+   The first form accepts a mailbox name as an argument and generates a
+   new mailbox access key for the given mailbox in the user's mailbox
+   access key table, replacing any previous mailbox access key (and
+   revoking any URLs that were authorized with a URLAUTH using that key)
+   in that table.  By default, the mailbox access key is generated for
+   the INTERNAL mechanism; other mechanisms can be specified with the
+   optional mechanism argument.
+
+   The second form, with no arguments, removes all mailbox access keys
+   in the user's mailbox access key table, revoking all URLs currently
+   authorized using URLAUTH by the user.
+
+   Any current IMAP session logged in as the user that has the mailbox
+   selected will receive an untagged OK response with the URLMECH status
+   response code (see section BASE.7.1.URLMECH for more details about
+   the URLMECH status response code).
+
+   Example:
+
+      C: a31 RESETKEY
+      S: a31 OK All keys removed
+      C: a32 RESETKEY INBOX
+      S: a32 OK [URLMECH INTERNAL] mechs
+      C: a33 RESETKEY INBOX XSAMPLE
+      S: a33 OK [URLMECH INTERNAL XSAMPLE=P34OKhO7VEkCbsiYY8rGEg==] done
+
+
+
+
+
+Crispin                     Standards Track                     [Page 8]
+
+RFC 4467                IMAP - URLAUTH Extension                May 2006
+
+
+BASE.6.3.GENURLAUTH.  GENURLAUTH Command
+
+      Argument:   one or more URL/mechanism pairs
+
+      Response:   untagged response: GENURLAUTH
+
+      Result:     OK - GENURLAUTH completed
+                  NO - GENURLAUTH error: can't generate a URLAUTH
+                  BAD - command unknown or arguments invalid
+
+   The GENURLAUTH command requests that the server generate a URLAUTH-
+   authorized URL for each of the given URLs using the given URL
+   authorization mechanism.
+
+   The server MUST validate each supplied URL as follows:
+
+      (1) The mailbox component of the URL MUST refer to an existing
+          mailbox.
+
+      (2) The server component of the URL MUST contain a valid userid
+          that identifies the owner of the mailbox access key table that
+          will be used to generate the URLAUTH-authorized URL.  As a
+          consequence, the iserver rule of [IMAPURL] is modified so that
+          iuserauth is mandatory.
+
+             Note: the server component of the URL is generally the
+             logged in userid and server.  If not, then the logged in
+             userid and server MUST have owner-type access to the
+             mailbox access key table owned by the userid and server
+             indicated by the server component of the URL.
+
+      (3) There is a valid access identifier that, in the case of
+          "submit+" and "user+", will contain a valid userid.  This
+          userid is not necessarily the same as the owner userid
+          described in (2).
+
+      (4) The server MAY also verify that the iuid and/or isection
+          components (if present) are valid.
+
+   If any of the above checks fail, the server MUST return a tagged BAD
+   response with the following exception.  If an invalid userid is
+   supplied as the mailbox access key owner and/or as part of the access
+   identifier, the server MAY issue a tagged OK response with a
+   generated mailbox key that always fails validation when used with a
+   URLFETCH command.  This exception prevents an attacker from
+   validating userids.
+
+
+
+
+
+Crispin                     Standards Track                     [Page 9]
+
+RFC 4467                IMAP - URLAUTH Extension                May 2006
+
+
+   If there is currently no mailbox access key for the given mailbox in
+   the owner's mailbox access key table, one is automatically generated.
+   That is, it is not necessary to use RESETKEY prior to first-time use
+   of GENURLAUTH.
+
+   If the command is successful, a GENURLAUTH response code is returned
+   listing the requested URLs as URLAUTH-authorized URLs.
+
+   Examples:
+
+      C: a775 GENURLAUTH "imap://joe@example.com/INBOX/;uid=20/
+         ;section=1.2" INTERNAL
+      S: a775 BAD missing access identifier in supplied URL
+      C: a776 GENURLAUTH "imap://example.com/Shared/;uid=20/
+         ;section=1.2;urlauth=submit+fred" INTERNAL
+      S: a776 BAD missing owner username in supplied URL
+      C: a777 GENURLAUTH "imap://joe@example.com/INBOX/;uid=20/
+         ;section=1.2;urlauth=submit+fred" INTERNAL
+      S: * GENURLAUTH "imap://joe@example.com/INBOX/;uid=20/;section=1.2
+         ;urlauth=submit+fred:internal:91354a473744909de610943775f92038"
+      S: a777 OK GENURLAUTH completed
+
+BASE.6.3.URLFETCH.  URLFETCH Command
+
+      Argument:   one or more URLs
+
+      Response:   untagged response: URLFETCH
+
+      Result:     OK - urlfetch completed
+                  NO - urlfetch failed due to server internal error
+                  BAD - command unknown or arguments invalid
+
+   The URLFETCH command requests that the server return the text data
+   associated with the specified IMAP URLs, as described in [IMAPURL]
+   and extended by this document.  The data is returned for all
+   validated URLs, regardless of whether or not the session would
+   otherwise be able to access the mailbox containing that data via
+   SELECT or EXAMINE.
+
+      Note: This command does not require that the URL refer to the
+      selected mailbox; nor does it require that any mailbox be
+      selected.  It also does not in any way interfere with any selected
+      mailbox.
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 10]
+
+RFC 4467                IMAP - URLAUTH Extension                May 2006
+
+
+   The URLFETCH command effectively executes with the access of the
+   userid in the server component of the URL (which is generally the
+   userid that issued the GENURLAUTH).  By itself, the URLAUTH does NOT
+   grant access to the data; once validated, it grants whatever access
+   to the data is held by the userid in the server component of the URL.
+   That access may have changed since the GENURLAUTH was done.
+
+   The URLFETCH command MUST return an untagged URLFETCH response and a
+   tagged OK response to any URLFETCH command that is syntactically
+   valid.  A NO response indicates a server internal failure that may be
+   resolved on later retry.
+
+      Note: The possibility of a NO response is to accommodate
+      implementations that would otherwise have to issue an untagged BYE
+      with a fatal error due to an inability to respond to a valid
+      request.  In an ideal world, a server SHOULD NOT issue a NO
+      response.
+
+   The server MUST return NIL for any IMAP URL that references an entire
+   IMAP server, a list of mailboxes, an entire IMAP mailbox, or IMAP
+   search results.
+
+   Example:
+
+      Note: For clarity, this example uses the LOGIN command, which
+      SHOULD NOT be used over a non-encrypted communication path.
+
+      This example is of a submit server, obtaining a message segment
+      for a message that it has already validated was submitted by
+      "fred".
+
+      S: * OK [CAPABILITY IMAP4REV1 URLAUTH] example.com IMAP server
+      C: a001 LOGIN submitserver secret
+      S: a001 OK submitserver logged in
+      C: a002 URLFETCH "imap://joe@example.com/INBOX/;uid=20/
+         ;section=1.2;urlauth=submit+fred:internal
+         :91354a473744909de610943775f92038"
+      S: * URLFETCH "imap://joe@example.com/INBOX/;uid=20/;section=1.2
+         ;urlauth=submit+fred:internal
+         :91354a473744909de610943775f92038" {28}
+      S: Si vis pacem, para bellum.
+      S:
+      S: a002 OK URLFETCH completed
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 11]
+
+RFC 4467                IMAP - URLAUTH Extension                May 2006
+
+
+8.  Additional Responses
+
+   These responses are extensions to the [IMAP] base protocol.
+
+   The section headings of these responses are intended to correspond
+   with where they would be located in the base protocol document if
+   they were part of that document.
+
+BASE.7.1.URLMECH.  URLMECH Status Response Code
+
+   The URLMECH status response code is followed by a list of URL
+   authorization mechanism names.  Mechanism names other than INTERNAL
+   may be appended with an "=" and BASE64-encoded form of mechanism-
+   specific data.
+
+   This status response code is returned in an untagged OK response in
+   response to a RESETKEY, SELECT, or EXAMINE command.  In the case of
+   the RESETKEY command, this status response code can be sent in the
+   tagged OK response instead of requiring a separate untagged OK
+   response.
+
+   Example:
+
+      C: a33 RESETKEY INBOX XSAMPLE
+      S: a33 OK [URLMECH INTERNAL XSAMPLE=P34OKhO7VEkCbsiYY8rGEg==] done
+
+   In this example, the server supports the INTERNAL mechanism and an
+   experimental mechanism called XSAMPLE, which also holds some
+   mechanism-specific data (the name "XSAMPLE" is for illustrative
+   purposes only).
+
+BASE.7.4.GENURLAUTH.   GENURLAUTH Response
+
+   Contents:   One or more URLs
+
+   The GENURLAUTH response returns the URLAUTH-authorized URL(s)
+   requested by a GENURLAUTH command.
+
+   Example:
+
+      C: a777 GENURLAUTH "imap://joe@example.com/INBOX/;uid=20/
+         ;section=1.2;urlauth=submit+fred" INTERNAL
+      S: * GENURLAUTH "imap://joe@example.com/INBOX/;uid=20/;section=1.2
+         ;urlauth=submit+fred:internal:91354a473744909de610943775f92038"
+      S: a777 OK GENURLAUTH completed
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 12]
+
+RFC 4467                IMAP - URLAUTH Extension                May 2006
+
+
+BASE.7.4.URLFETCH.  URLFETCH Response
+
+   Contents:   One or more URL/nstring pairs
+
+   The URLFETCH response returns the message text data associated with
+   one or more IMAP URLs, as described in [IMAPURL] and extended by this
+   document.  This response occurs as the result of a URLFETCH command.
+
+   The returned data string is NIL if the URL is invalid for any reason
+   (including validation failure).  If the URL is valid, but the IMAP
+   fetch of the body part returned NIL (this should not happen), the
+   returned data string should be the empty string ("") and not NIL.
+
+      Note: This command does not require that the URL refer to the
+      selected mailbox; nor does it require that any mailbox be
+      selected.  It also does not in any way interfere with any selected
+      mailbox.
+
+   Example:
+
+      C: a002 URLFETCH "imap://joe@example.com/INBOX/;uid=20/
+         ;section=1.2;urlauth=submit+fred:internal
+         :91354a473744909de610943775f92038"
+      S: * URLFETCH "imap://joe@example.com/INBOX/;uid=20/;section=1.2
+         ;urlauth=submit+fred:internal
+         :91354a473744909de610943775f92038" {28}
+      S: Si vis pacem, para bellum.
+      S:
+      S: a002 OK URLFETCH completed
+
+9.  Formal Syntax
+
+   The following syntax specification uses the Augmented Backus-Naur
+   Form (ABNF) notation as specified in [ABNF].
+
+   The following modifications are made to the Formal Syntax in [IMAP]:
+
+resetkey        = "RESETKEY" [SP mailbox *(SP mechanism)]
+
+capability      =/ "URLAUTH"
+
+command-auth    =/ resetkey / genurlauth / urlfetch
+
+resp-text-code  =/ "URLMECH" SP "INTERNAL" *(SP mechanism ["=" base64])
+
+genurlauth      = "GENURLAUTH" 1*(SP url-rump SP mechanism)
+
+genurlauth-data = "*" SP "GENURLAUTH" 1*(SP url-full)
+
+
+
+Crispin                     Standards Track                    [Page 13]
+
+RFC 4467                IMAP - URLAUTH Extension                May 2006
+
+
+url-full        = astring
+                     ; contains authimapurlfull as defined below
+
+url-rump        = astring
+                     ; contains authimapurlrump as defined below
+
+urlfetch        = "URLFETCH" 1*(SP url-full)
+
+urlfetch-data   = "*" SP "URLFETCH" 1*(SP url-full SP nstring)
+
+   The following extensions are made to the Formal Syntax in [IMAPURL]:
+
+authimapurl     = "imap://" enc-user [iauth] "@" hostport "/"
+                     imessagepart
+                     ; replaces "imapurl" and "iserver" rules for
+                     ; URLAUTH authorized URLs
+
+authimapurlfull = authimapurl iurlauth
+
+authimapurlrump = authimapurl iurlauth-rump
+
+enc-urlauth     = 32*HEXDIG
+
+enc-user        = 1*achar
+                     ; same as "enc_user" in RFC 2192
+
+iurlauth        = iurlauth-rump ":" mechanism ":" enc-urlauth
+
+iurlauth-rump   = [expire] ";URLAUTH=" access
+
+access          = ("submit+" enc-user) / ("user+" enc-user) /
+                    "authuser" / "anonymous"
+
+expire          = ";EXPIRE=" date-time
+                      ; date-time defined in [DATETIME]
+
+mechanism       = "INTERNAL" / 1*(ALPHA / DIGIT / "-" / ".")
+                     ; case-insensitive
+                     ; new mechanisms MUST be registered with IANA
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 14]
+
+RFC 4467                IMAP - URLAUTH Extension                May 2006
+
+
+10.  Security Considerations
+
+   Security considerations are discussed throughout this memo.
+
+   The mailbox access key SHOULD have at least 128 bits of entropy
+   (refer to [RANDOM] for more details) and MUST be unpredictable.
+
+   The server implementation of the INTERNAL mechanism SHOULD consider
+   the possibility of needing to change the token generation algorithm,
+   and SHOULD incorporate some means of identifying the token generation
+   algorithm within the token.
+
+   The URLMECH status response code may expose sensitive data in the
+   mechanism-specific data for mechanisms other than INTERNAL.  A server
+   implementation MUST implement a configuration that will not return a
+   URLMECH status response code unless some mechanism is provided that
+   protects the session from snooping, such as a TLS or SASL security
+   layer that provides confidentiality protection.
+
+   The calculation of an authorization token with a "plausible" key if
+   the mailbox can not be identified is necessary to avoid attacks in
+   which the server is probed to see if a particular mailbox exists on
+   the server by measuring the amount of time taken to reject a known
+   bad name versus some other name.
+
+   To protect against a computational denial-of-service attack, a server
+   MAY impose progressively longer delays on multiple URL requests that
+   fail validation.
+
+   The decision to use the "authuser" access identifier should be made
+   with caution.  An "authuser" access identifier can be used by any
+   authorized user of the IMAP server; therefore, use of this access
+   identifier should be limited to content that may be disclosed to any
+   authorized user of the IMAP server.
+
+   The decision to use the "anonymous" access identifier should be made
+   with extreme caution.  An "anonymous" access identifier can be used
+   by anyone; therefore, use of this access identifier should be limited
+   to content that may be disclosed to anyone.  Many IMAP servers do not
+   permit anonymous access; in this case, the "anonymous" access
+   identifier is equivalent to "authuser", but this MUST NOT be relied
+   upon.
+
+   Although this specification does not prohibit the theoretical
+   capability to generate a URL with a server component other than the
+   logged in userid and server, this capability should only be provided
+
+
+
+
+
+Crispin                     Standards Track                    [Page 15]
+
+RFC 4467                IMAP - URLAUTH Extension                May 2006
+
+
+   when the logged in userid/server has been authorized as equivalent to
+   the server component userid/server, or otherwise has access to that
+   userid/server mailbox access key table.
+
+11.  IANA Considerations
+
+   This document constitutes registration of the URLAUTH capability in
+   the imap4-capabilities registry.
+
+   URLAUTH authorization mechanisms are registered by publishing a
+   standards track or IESG-approved experimental RFC.  The registry is
+   currently located at:
+
+http://www.iana.org/assignments/urlauth-authorization-mechanism-registry
+
+   This registry is case-insensitive.
+
+   This document constitutes registration of the INTERNAL URLAUTH
+   authorization mechanism.
+
+   IMAP URLAUTH Authorization Mechanism Registry
+
+      Mechanism Name           Reference
+      --------------           ---------
+      INTERNAL                 [RFC4467]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 16]
+
+RFC 4467                IMAP - URLAUTH Extension                May 2006
+
+
+12.  Normative References
+
+   [ABNF]     Crocker, D. and P. Overell, "Augmented BNF for Syntax
+              Specifications: ABNF", RFC 4234, October 2005.
+
+   [BURL]     Newman, C., "Message Submission BURL Extension", RFC 4468,
+              May 2006.
+
+   [DATETIME] Klyne, G. and C. Newman, "Date and Time on the Internet:
+              Timestamps", RFC 3339, July 2002.
+
+   [IMAP]     Crispin, M., "Internet Message Access Protocol - Version
+              4rev1", RFC 3501, March 2003.
+
+   [IMAPURL]  Newman, C., "IMAP URL Scheme", RFC 2192, September 1997.
+
+   [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate
+              Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+13.  Informative References
+
+   [HMAC]     Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: Keyed-
+              Hashing for Message Authentication", RFC 2104, February
+              1997.
+
+   [RANDOM]   Eastlake, D., 3rd, Schiller, J., and S. Crocker,
+              "Randomness Requirements for Security", BCP 106, RFC 4086,
+              June 2005.
+
+Author's Address
+
+   Mark R. Crispin
+   Networks and Distributed Computing
+   University of Washington
+   4545 15th Avenue NE
+   Seattle, WA  98105-4527
+
+   Phone: (206) 543-5762
+   EMail: MRC@CAC.Washington.EDU
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 17]
+
+RFC 4467                IMAP - URLAUTH Extension                May 2006
+
+
+Full Copyright Statement
+
+   Copyright (C) The Internet Society (2006).
+
+   This document is subject to the rights, licenses and restrictions
+   contained in BCP 78, and except as set forth therein, the authors
+   retain all their rights.
+
+   This document and the information contained herein are provided on an
+   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   Intellectual Property Rights or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; nor does it represent that it has
+   made any independent effort to identify any such rights.  Information
+   on the procedures with respect to rights in RFC documents can be
+   found in BCP 78 and BCP 79.
+
+   Copies of IPR disclosures made to the IETF Secretariat and any
+   assurances of licenses to be made available, or the result of an
+   attempt made to obtain a general license or permission for the use of
+   such proprietary rights by implementers or users of this
+   specification can be obtained from the IETF on-line IPR repository at
+   http://www.ietf.org/ipr.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights that may cover technology that may be required to implement
+   this standard.  Please address the information to the IETF at
+   ietf-ipr@ietf.org.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is provided by the IETF
+   Administrative Support Activity (IASA).
+
+
+
+
+
+
+
+Crispin                     Standards Track                    [Page 18]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc4468.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,787 @@
+
+
+
+
+
+
+Network Working Group                                          C. Newman
+Request for Comments: 4468                              Sun Microsystems
+Updates: 3463                                                   May 2006
+Category: Standards Track
+
+
+                   Message Submission BURL Extension
+
+Status of This Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (2006).
+
+Abstract
+
+   The submission profile of Simple Mail Transfer Protocol (SMTP)
+   provides a standard way for an email client to submit a complete
+   message for delivery.  This specification extends the submission
+   profile by adding a new BURL command that can be used to fetch
+   submission data from an Internet Message Access Protocol (IMAP)
+   server.  This permits a mail client to inject content from an IMAP
+   server into the SMTP infrastructure without downloading it to the
+   client and uploading it back to the server.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Newman                      Standards Track                     [Page 1]
+
+RFC 4468           Message Submission BURL Extension            May 2006
+
+
+Table of Contents
+
+   1. Introduction ....................................................2
+   2. Conventions Used in This Document ...............................2
+   3. BURL Submission Extension .......................................3
+      3.1. SMTP Submission Extension Registration .....................3
+      3.2. BURL Transaction ...........................................3
+      3.3. The BURL IMAP Options ......................................4
+      3.4. Examples ...................................................5
+      3.5. Formal Syntax ..............................................6
+   4. 8-Bit and Binary ................................................7
+   5. Updates to RFC 3463 .............................................7
+   6. Response Codes ..................................................7
+   7. IANA Considerations .............................................9
+   8. Security Considerations .........................................9
+   9. References .....................................................11
+      9.1. Normative References ......................................11
+      9.2. Informative References ....................................12
+   Appendix A.  Acknowledgements .....................................13
+
+1.  Introduction
+
+   This specification defines an extension to the standard Message
+   Submission [RFC4409] protocol to permit data to be fetched from an
+   IMAP server at message submission time.  This MAY be used in
+   conjunction with the CHUNKING [RFC3030] mechanism so that chunks of
+   the message can come from an external IMAP server.  This provides the
+   ability to forward an email message without first downloading it to
+   the client.
+
+2.  Conventions Used in This Document
+
+   The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY"
+   in this document are to be interpreted as defined in "Key words for
+   use in RFCs to Indicate Requirement Levels" [RFC2119].
+
+   The formal syntax uses the Augmented Backus-Naur Form (ABNF)
+   [RFC4234] notation including the core rules defined in Appendix B of
+   RFC 4234.
+
+
+
+
+
+
+
+
+
+
+
+
+Newman                      Standards Track                     [Page 2]
+
+RFC 4468           Message Submission BURL Extension            May 2006
+
+
+3.  BURL Submission Extension
+
+   This section defines the BURL submission extension.
+
+3.1.  SMTP Submission Extension Registration
+
+   1.  The name of this submission extension is "BURL".  This extends
+       the Message Submission protocol on port 587 and MUST NOT be
+       advertised by a regular SMTP [RFC2821] server on port 25 that
+       acts as a relay for incoming mail from other SMTP relays.
+
+   2.  The EHLO keyword value associated with the extension is "BURL".
+
+   3.  The BURL EHLO keyword will have zero or more arguments.  The only
+       argument defined at this time is the "imap" argument, which MUST
+       be present in order to use IMAP URLs with BURL.  Clients MUST
+       ignore other arguments after the BURL EHLO keyword unless they
+       are defined by a subsequent IETF standards track specification.
+       The arguments that appear after the BURL EHLO keyword may change
+       subsequent to the use of SMTP AUTH [RFC2554], so a server that
+       advertises BURL with no arguments prior to authentication
+       indicates that BURL is supported but authentication is required
+       to use it.
+
+   4.  This extension adds the BURL SMTP verb.  This verb is used as a
+       replacement for the DATA command and is only permitted during a
+       mail transaction after at least one successful RCPT TO.
+
+3.2.  BURL Transaction
+
+   A simple BURL transaction will consist of MAIL FROM, one or more RCPT
+   TO headers, and a BURL command with the "LAST" tag.  The BURL command
+   will include an IMAP URL pointing to a fully formed message ready for
+   injection into the SMTP infrastructure.  If PIPELINING [RFC2920] is
+   advertised, the client MAY send the entire transaction in one round
+   trip.  If no valid RCPT TO address is supplied, the BURL command will
+   simply fail, and no resolution of the BURL URL argument will be
+   performed.  If at least one valid RCPT TO address is supplied, then
+   the BURL URL argument will be resolved before the server responds to
+   the command.
+
+   A more sophisticated BURL transaction MAY occur when the server also
+   advertises CHUNKING [RFC3030].  In this case, the BURL and BDAT
+   commands may be interleaved until one of them terminates the
+   transaction with the "LAST" argument.  If PIPELINING [RFC2920] is
+   also advertised, then the client may pipeline the entire transaction
+   in one round-trip.  However, it MUST wait for the results of the
+   "LAST" BDAT or BURL command prior to initiating a new transaction.
+
+
+
+Newman                      Standards Track                     [Page 3]
+
+RFC 4468           Message Submission BURL Extension            May 2006
+
+
+   The BURL command directs the server to fetch the data object to which
+   the URL refers and include it in the message.  If the URL fetch
+   fails, the server will fail the entire transaction.
+
+3.3.  The BURL IMAP Options
+
+   When "imap" is present in the space-separated list of arguments
+   following the BURL EHLO keyword, it indicates that the BURL command
+   supports the URLAUTH [RFC4467] extended form of IMAP URLs [RFC2192]
+   and that the submit server is configured with the necessary
+   credentials to resolve "urlauth=submit+" IMAP URLs for the submit
+   server's domain.
+
+   Subsequent to a successful SMTP AUTH command, the submission server
+   MAY indicate a prearranged trust relationship with a specific IMAP
+   server by including a BURL EHLO keyword argument of the form
+   "imap://imap.example.com".  In this case, the submission server will
+   permit a regular IMAP URL referring to messages or parts of messages
+   on imap.example.com that the user who authenticated to the submit
+   server can access.  Note that this form does not imply that the
+   submit server supports URLAUTH URLs; the submit server must advertise
+   both "imap" and "imap://imap.example.com" to indicate support for
+   both extended and non-extended URL forms.
+
+   When the submit server connects to the IMAP server, it acts as an
+   IMAP client and thus is subject to both the mandatory-to-implement
+   IMAP capabilities in Section 6.1.1 of RFC 3501, and the security
+   considerations in Section 11 of RFC 3501.  Specifically, this
+   requires that the submit server implement a configuration that uses
+   STARTTLS followed by SASL PLAIN [SASL-PLAIN] to authenticate to the
+   IMAP server.
+
+   When the submit server resolves a URLAUTH IMAP URL, it uses submit
+   server credentials when authenticating to the IMAP server.  The
+   authentication identity and password used for submit credentials MUST
+   be configurable.  The string "submit" is suggested as a default value
+   for the authentication identity, with no default for the password.
+   Typically, the authorization identity is empty in this case; thus the
+   IMAP server will derive the authorization identity from the
+   authentication identity.  If the IMAP URL uses the "submit+" access
+   identifier prefix, the submit server MUST refuse the BURL command
+   unless the userid in the URL's <access> token matches the submit
+   client's authorization identity.
+
+   When the submit server resolves a regular IMAP URL, it uses the
+   submit client's authorization identity when authenticating to the
+   IMAP server.  If both the submit client and the submit server's
+   embedded IMAP client use SASL PLAIN (or the equivalent), the submit
+
+
+
+Newman                      Standards Track                     [Page 4]
+
+RFC 4468           Message Submission BURL Extension            May 2006
+
+
+   server SHOULD forward the client's credentials if and only if the
+   submit server knows that the IMAP server is in the same
+   administrative domain.  If the submit server supports SASL mechanisms
+   other than PLAIN, it MUST implement a configuration in which the
+   submit server's embedded IMAP client uses STARTTLS and SASL PLAIN
+   with the submit server's authentication identity and password (for
+   the respective IMAP server) and the submit client's authorization
+   identity.
+
+3.4.  Examples
+
+   In examples, "C:" and "S:" indicate lines sent by the client and
+   server, respectively.  If a single "C:" or "S:" label applies to
+   multiple lines, then the line breaks between those lines are for
+   editorial clarity only and are not part of the actual protocol
+   exchange.
+
+   Two successful submissions (without and with pipelining) follow:
+
+   <SSL/TLS encryption layer negotiated>
+   C: EHLO potter.example.com
+   S: 250-owlry.example.com
+   S: 250-8BITMIME
+   S: 250-BURL imap
+   S: 250-AUTH PLAIN
+   S: 250-DSN
+   S: 250 ENHANCEDSTATUSCODES
+   C: AUTH PLAIN aGFycnkAaGFycnkAYWNjaW8=
+   S: 235 2.7.0 PLAIN authentication successful.
+   C: MAIL FROM:<harry@gryffindor.example.com>
+   S: 250 2.5.0 Address Ok.
+   C: RCPT TO:<ron@gryffindor.example.com>
+   S: 250 2.1.5 ron@gryffindor.example.com OK.
+   C: BURL imap://harry@gryffindor.example.com/outbox
+           ;uidvalidity=1078863300/;uid=25;urlauth=submit+harry
+           :internal:91354a473744909de610943775f92038 LAST
+   S: 250 2.5.0 Ok.
+
+   <SSL/TLS encryption layer negotiated>
+   C: EHLO potter.example.com
+   S: 250-owlry.example.com
+   S: 250-8BITMIME
+   S: 250-PIPELINING
+   S: 250-BURL imap
+   S: 250-AUTH PLAIN
+   S: 250-DSN
+   S: 250 ENHANCEDSTATUSCODES
+   C: AUTH PLAIN aGFycnkAaGFycnkAYWNjaW8=
+
+
+
+Newman                      Standards Track                     [Page 5]
+
+RFC 4468           Message Submission BURL Extension            May 2006
+
+
+   C: MAIL FROM:<harry@gryffindor.example.com>
+   C: RCPT TO:<ron@gryffindor.example.com>
+   C: BURL imap://harry@gryffindor.example.com/outbox
+           ;uidvalidity=1078863300/;uid=25;urlauth=submit+harry
+           :internal:91354a473744909de610943775f92038 LAST
+   S: 235 2.7.0 PLAIN authentication successful.
+   S: 250 2.5.0 Address Ok.
+   S: 250 2.1.5 ron@gryffindor.example.com OK.
+   S: 250 2.5.0 Ok.
+
+   Note that PIPELINING of the AUTH command is only permitted if the
+   selected mechanism can be completed in one round trip, a client
+   initial response is provided, and no SASL security layer is
+   negotiated.  This is possible for PLAIN and EXTERNAL, but not for
+   most other SASL mechanisms.
+
+   Some examples of failure cases:
+
+   C: MAIL FROM:<harry@gryffindor.example.com>
+   C: RCPT TO:<malfoy@slitherin.example.com>
+   C: BURL imap://harry@gryffindor.example.com/outbox
+           ;uidvalidity=1078863300/;uid=25;urlauth=submit+harry
+           :internal:91354a473744909de610943775f92038 LAST
+   S: 250 2.5.0 Address Ok.
+   S: 550 5.7.1 Relaying not allowed: malfoy@slitherin.example.com
+   S: 554 5.5.0 No recipients have been specified.
+
+   C: MAIL FROM:<harry@gryffindor.example.com>
+   C: RCPT TO:<ron@gryffindor.example.com>
+   C: BURL imap://harry@gryffindor.example.com/outbox
+           ;uidvalidity=1078863300/;uid=25;urlauth=submit+harry
+           :internal:71354a473744909de610943775f92038 LAST
+   S: 250 2.5.0 Address Ok.
+   S: 250 2.1.5 ron@gryffindor.example.com OK.
+   S: 554 5.7.0 IMAP URL authorization failed
+
+3.5.  Formal Syntax
+
+   The following syntax specification inherits ABNF [RFC4234] and
+   Uniform Resource Identifiers [RFC3986].
+
+      burl-param  = "imap" / ("imap://" authority)
+                  ; parameter to BURL EHLO keyword
+
+      burl-cmd    = "BURL" SP absolute-URI [SP end-marker] CRLF
+
+      end-marker  = "LAST"
+
+
+
+
+Newman                      Standards Track                     [Page 6]
+
+RFC 4468           Message Submission BURL Extension            May 2006
+
+
+4.  8-Bit and Binary
+
+   A submit server that advertises BURL MUST also advertise 8BITMIME
+   [RFC1652] and perform the down conversion described in that
+   specification on the resulting complete message if 8-bit data is
+   received with the BURL command and passed to a 7-bit server.  If the
+   URL argument to BURL refers to binary data, then the submit server
+   MAY refuse the command or down convert as described in Binary SMTP
+   [RFC3030].
+
+   The Submit server MAY refuse to accept a BURL command or combination
+   of BURL and BDAT commands that result in un-encoded 8-bit data in
+   mail or MIME [RFC2045] headers.  Alternatively, the server MAY accept
+   such data and down convert to MIME header encoding [RFC2047].
+
+5.  Updates to RFC 3463
+
+   SMTP or Submit servers that advertise ENHANCEDSTATUSCODES [RFC2034]
+   use enhanced status codes defined in RFC 3463 [RFC3463].  The BURL
+   extension introduces new error cases that that RFC did not consider.
+   The following additional enhanced status codes are defined by this
+   specification:
+
+   X.6.6 Message content not available
+
+      The message content could not be fetched from a remote system.
+      This may be useful as a permanent or persistent temporary
+      notification.
+
+   X.7.8 Trust relationship required
+
+      The submission server requires a configured trust relationship
+      with a third-party server in order to access the message content.
+
+6.  Response Codes
+
+   This section includes example response codes to the BURL command.
+   Other text may be used with the same response codes.  This list is
+   not exhaustive, and BURL clients MUST tolerate any valid SMTP
+   response code.  Most of these examples include the appropriate
+   enhanced status code [RFC3463].
+
+   554 5.5.0 No recipients have been specified
+
+      This response code occurs when BURL is used (for example, with
+      PIPELINING) and all RCPT TOs failed.
+
+
+
+
+
+Newman                      Standards Track                     [Page 7]
+
+RFC 4468           Message Submission BURL Extension            May 2006
+
+
+   503 5.5.0 Valid RCPT TO required before BURL
+
+      This response code is an alternative to the previous one when BURL
+      is used (for example, with PIPELINING) and all RCPT TOs failed.
+
+   554 5.6.3 Conversion required but not supported
+
+      This response code occurs when the URL points to binary data and
+      the implementation does not support down conversion to base64.
+      This can also be used if the URL points to message data with 8-bit
+      content in headers and the server does not down convert such
+      content.
+
+   554 5.3.4 Message too big for system
+
+      The message (subsequent to URL resolution) is larger than the
+      per-message size limit for this server.
+
+   554 5.7.8 URL resolution requires trust relationship
+
+      The submit server does not have a trust relationship with the IMAP
+      server specified in the URL argument to BURL.
+
+   552 5.2.2 Mailbox full
+
+      The recipient is local, the submit server supports direct
+      delivery, and the recipient has exceeded his quota and any grace
+      period for delivery attempts.
+
+   554 5.6.6 IMAP URL resolution failed
+
+      The IMAP URLFETCH command returned an error or no data.
+
+   250 2.5.0 Waiting for additional BURL or BDAT commands
+
+      A BURL command without the "LAST" modifier was sent.  The URL for
+      this BURL command was successfully resolved, but the content will
+      not necessarily be committed to persistent storage until the rest
+      of the message content is collected.  For example, a Unix server
+      may have written the content to a queue file buffer, but may not
+      yet have performed an fsync() operation.  If the server loses
+      power, the content can still be lost.
+
+   451 4.4.1 IMAP server unavailable
+
+      The connection to the IMAP server to resolve the URL failed.
+
+
+
+
+
+Newman                      Standards Track                     [Page 8]
+
+RFC 4468           Message Submission BURL Extension            May 2006
+
+
+   250 2.5.0 Ok.
+
+      The URL was successfully resolved, and the complete message data
+      has been committed to persistent storage.
+
+   250 2.6.4 MIME header conversion with loss performed
+
+      The URL pointed to message data that included mail or MIME headers
+      with 8-bit data.  This data was converted to MIME header encoding
+      [RFC2047], but the submit server may not have correctly guessed
+      the unlabeled character set.
+
+7.  IANA Considerations
+
+   The "BURL" SMTP extension as described in Section 3 has been
+   registered.  This registration has been marked for use by message
+   submission [RFC4409] only in the registry.
+
+8.  Security Considerations
+
+   Modern SMTP submission servers often include content-based security
+   and denial-of-service defense mechanisms such as virus filtering,
+   size limits, server-generated signatures, spam filtering, etc.
+   Implementations of BURL should fetch the URL content prior to
+   application of such content-based mechanisms in order to preserve
+   their function.
+
+   Clients that generate unsolicited bulk email or email with viruses
+   could use this mechanism to compensate for a slow link between the
+   client and submit server.  In particular, this mechanism would make
+   it feasible for a programmable cell phone or other device on a slow
+   link to become a significant source of unsolicited bulk email and/or
+   viruses.  This makes it more important for submit server vendors
+   implementing BURL to have auditing and/or defenses against such
+   denial-of-service attacks including mandatory authentication, logging
+   that associates unique client identifiers with mail transactions,
+   limits on reuse of the same IMAP URL, rate limits, recipient count
+   limits, and content filters.
+
+   Transfer of the URLAUTH [RFC4467] form of IMAP URLs in the clear can
+   expose the authorization token to network eavesdroppers.
+   Implementations that support such URLs can address this issue by
+   using a strong confidentiality protection mechanism.  For example,
+   the SMTP STARTTLS [RFC3207] and the IMAP STARTTLS [RFC3501]
+   extensions, in combination with a configuration setting that requires
+   their use with such IMAP URLs, would address this concern.
+
+
+
+
+
+Newman                      Standards Track                     [Page 9]
+
+RFC 4468           Message Submission BURL Extension            May 2006
+
+
+   Use of a prearranged trust relationship between a submit server and a
+   specific IMAP server introduces security considerations.  A
+   compromise of the submit server should not automatically compromise
+   all accounts on the IMAP server, so trust relationships involving
+   super-user proxy credentials are strongly discouraged.  A system that
+   requires the submit server to authenticate to the IMAP server with
+   submit credentials and subsequently requires a URLAUTH URL to fetch
+   any content addresses this concern.  A trusted third party model for
+   proxy credentials (such as that provided by Kerberos 5 [RFC4120])
+   would also suffice.
+
+   When a client uses SMTP STARTTLS to send a BURL command that
+   references non-public information, there is a user expectation that
+   the entire message content will be treated confidentially.  To
+   address this expectation, the message submission server SHOULD use
+   STARTTLS or a mechanism providing equivalent data confidentiality
+   when fetching the content referenced by that URL.
+
+   A legitimate user of a submit server may try to compromise other
+   accounts on the server by providing an IMAP URLAUTH URL that points
+   to a server under that user's control that is designed to undermine
+   the security of the submit server.  For this reason, the IMAP client
+   code that the submit server uses must be robust with respect to
+   arbitrary input sizes (including large IMAP literals) and arbitrary
+   delays from the IMAP server.  Requiring a prearranged trust
+   relationship between a submit server and the IMAP server also
+   addresses this concern.
+
+   An authorized user of the submit server could set up a fraudulent
+   IMAP server and pass a URL for that server to the submit server.  The
+   submit server might then contact the fraudulent IMAP server to
+   authenticate with submit credentials and fetch content.  There are
+   several ways to mitigate this potential attack.  A submit server that
+   only uses submit credentials with a fixed set of trusted IMAP servers
+   will not be vulnerable to exposure of those credentials.  A submit
+   server can treat the IMAP server as untrusted and include defenses
+   for buffer overflows, denial-of-service slowdowns, and other
+   potential attacks.  Finally, because authentication is required to
+   use BURL, it is possible to keep a secure audit trail and use that to
+   detect and punish the offending party.
+
+
+
+
+
+
+
+
+
+
+
+Newman                      Standards Track                    [Page 10]
+
+RFC 4468           Message Submission BURL Extension            May 2006
+
+
+9.  References
+
+9.1.  Normative References
+
+   [RFC1652]     Klensin, J., Freed, N., Rose, M., Stefferud, E., and D.
+                 Crocker, "SMTP Service Extension for
+                 8bit-MIMEtransport", RFC 1652, July 1994.
+
+   [RFC2119]     Bradner, S., "Key words for use in RFCs to Indicate
+                 Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+   [RFC2192]     Newman, C., "IMAP URL Scheme", RFC 2192,
+                 September 1997.
+
+   [RFC2554]     Myers, J., "SMTP Service Extension for Authentication",
+                 RFC 2554, March 1999.
+
+   [RFC2821]     Klensin, J., "Simple Mail Transfer Protocol", RFC 2821,
+                 April 2001.
+
+   [RFC3207]     Hoffman, P., "SMTP Service Extension for Secure SMTP
+                 over Transport Layer Security", RFC 3207,
+                 February 2002.
+
+   [RFC3501]     Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL -
+                 VERSION 4rev1", RFC 3501, March 2003.
+
+   [RFC3986]     Berners-Lee, T., Fielding, R., and L. Masinter,
+                 "Uniform Resource Identifier (URI): Generic Syntax",
+                 STD 66, RFC 3986, January 2005.
+
+   [RFC4234]     Crocker, D. and P. Overell, "Augmented BNF for Syntax
+                 Specifications: ABNF", RFC 4234, October 2005.
+
+   [RFC4409]     Gellens, R. and J. Klensin, "Message Submission for
+                 Mail", RFC 4409, April 2006.
+
+   [RFC4467]     Crispin, M., "Internet Message Access Protocol (IMAP) -
+                 URLAUTH Extension", RFC 4467, May 2006.
+
+
+
+
+
+
+
+
+
+
+
+
+Newman                      Standards Track                    [Page 11]
+
+RFC 4468           Message Submission BURL Extension            May 2006
+
+
+9.2.  Informative References
+
+   [RFC2034]     Freed, N., "SMTP Service Extension for Returning
+                 Enhanced Error Codes", RFC 2034, October 1996.
+
+   [RFC2045]     Freed, N. and N. Borenstein, "Multipurpose Internet
+                 Mail Extensions (MIME) Part One: Format of Internet
+                 Message Bodies", RFC 2045, November 1996.
+
+   [RFC2047]     Moore, K., "MIME (Multipurpose Internet Mail
+                 Extensions) Part Three: Message Header Extensions for
+                 Non-ASCII Text", RFC 2047, November 1996.
+
+   [RFC2920]     Freed, N., "SMTP Service Extension for Command
+                 Pipelining", STD 60, RFC 2920, September 2000.
+
+   [RFC3030]     Vaudreuil, G., "SMTP Service Extensions for
+                 Transmission of Large and Binary MIME Messages",
+                 RFC 3030, December 2000.
+
+   [RFC3463]     Vaudreuil, G., "Enhanced Mail System Status Codes",
+                 RFC 3463, January 2003.
+
+   [RFC4120]     Neuman, C., Yu, T., Hartman, S., and K. Raeburn, "The
+                 Kerberos Network Authentication Service (V5)", RFC
+                 4120, July 2005.
+
+   [SASL-PLAIN]  Zeilenga, K., "The Plain SASL Mechanism", Work in
+                 Progress, March 2005.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Newman                      Standards Track                    [Page 12]
+
+RFC 4468           Message Submission BURL Extension            May 2006
+
+
+Appendix A.  Acknowledgements
+
+   This document is a product of the lemonade WG.  Many thanks are due
+   to all the participants of that working group for their input.  Mark
+   Crispin was instrumental in the conception of this mechanism.  Thanks
+   to Randall Gellens, Alexey Melnikov, Sam Hartman, Ned Freed, Dave
+   Cridland, Peter Coates, and Mark Crispin for review comments on the
+   document.  Thanks to the RFC Editor for correcting the author's
+   grammar mistakes.  Thanks to Ted Hardie, Randall Gellens, Mark
+   Crispin, Pete Resnick, and Greg Vaudreuil for extremely interesting
+   debates comparing this proposal and alternatives.  Thanks to the
+   lemonade WG chairs Eric Burger and Glenn Parsons for concluding the
+   debate at the correct time and making sure this document got
+   completed.
+
+Author's Address
+
+   Chris Newman
+   Sun Microsystems
+   3401 Centrelake Dr., Suite 410
+   Ontario, CA  91761
+   US
+
+   EMail: chris.newman@sun.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Newman                      Standards Track                    [Page 13]
+
+RFC 4468           Message Submission BURL Extension            May 2006
+
+
+Full Copyright Statement
+
+   Copyright (C) The Internet Society (2006).
+
+   This document is subject to the rights, licenses and restrictions
+   contained in BCP 78, and except as set forth therein, the authors
+   retain all their rights.
+
+   This document and the information contained herein are provided on an
+   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   Intellectual Property Rights or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; nor does it represent that it has
+   made any independent effort to identify any such rights.  Information
+   on the procedures with respect to rights in RFC documents can be
+   found in BCP 78 and BCP 79.
+
+   Copies of IPR disclosures made to the IETF Secretariat and any
+   assurances of licenses to be made available, or the result of an
+   attempt made to obtain a general license or permission for the use of
+   such proprietary rights by implementers or users of this
+   specification can be obtained from the IETF on-line IPR repository at
+   http://www.ietf.org/ipr.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights that may cover technology that may be required to implement
+   this standard.  Please address the information to the IETF at
+   ietf-ipr@ietf.org.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is provided by the IETF
+   Administrative Support Activity (IASA).
+
+
+
+
+
+
+
+Newman                      Standards Track                    [Page 14]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc4469.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,731 @@
+
+
+
+
+
+
+Network Working Group                                         P. Resnick
+Request for Comments: 4469                         QUALCOMM Incorporated
+Updates: 3501, 3502                                           April 2006
+Category: Standards Track
+
+
+       Internet Message Access Protocol (IMAP) CATENATE Extension
+
+Status of This Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (2006).
+
+Abstract
+
+   The CATENATE extension to the Internet Message Access Protocol (IMAP)
+   extends the APPEND command to allow clients to create messages on the
+   IMAP server that may contain a combination of new data along with
+   parts of (or entire) messages already on the server.  Using this
+   extension, the client can catenate parts of an already existing
+   message onto a new message without having to first download the data
+   and then upload it back to the server.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Resnick                     Standards Track                     [Page 1]
+
+RFC 4469                IMAP CATENATE Extension               April 2006
+
+
+1.  Introduction
+
+   The CATENATE extension to the Internet Message Access Protocol (IMAP)
+   [1] allows the client to create a message on the server that can
+   include the text of messages (or parts of messages) that already
+   exist on the server without having to FETCH them and APPEND them back
+   to the server.  The CATENATE extension extends the APPEND command so
+   that, instead of a single message literal, the command can take as
+   arguments any combination of message literals (as described in IMAP
+   [1]) and message URLs (as described in the IMAP URL Scheme [2]
+   specification).  The server takes all the pieces and catenates them
+   into the output message.  The CATENATE extension can also coexist
+   with the MULTIAPPEND extension [3] to APPEND multiple messages in a
+   single command.
+
+   There are some obvious uses for the CATENATE extension.  The
+   motivating use case was to provide a way for a resource-constrained
+   client to compose a message for subsequent submission that contains
+   data that already exists in that client's IMAP store.  Because the
+   client does not have to download and re-upload potentially large
+   message parts, bandwidth and processing limitations do not have as
+   much impact.  In addition, since the client can create a message in
+   its own IMAP store, the command also addresses the desire of the
+   client to archive a copy of a sent message without having to upload
+   the message twice.  (Mechanisms for sending the message are outside
+   the scope of this document.)
+
+   The extended APPEND command can also be used to copy parts of a
+   message to another mailbox for archival purposes while getting rid of
+   undesired parts.  In environments where server storage is limited, a
+   client could get rid of large message parts by copying over only the
+   necessary parts and then deleting the original message.  The
+   mechanism could also be used to add data to a message (such as
+   prepending message header fields) or to include other data by making
+   a copy of the original and catenating the new data.
+
+2.  The CATENATE Capability
+
+   A server that supports this extension returns "CATENATE" as one of
+   the responses to the CAPABILITY command.
+
+
+
+
+
+
+
+
+
+
+
+Resnick                     Standards Track                     [Page 2]
+
+RFC 4469                IMAP CATENATE Extension               April 2006
+
+
+3.  The APPEND Command
+
+   Arguments:  mailbox name
+               (The following can be repeated in the presence of the
+               MULTIAPPEND extension [3])
+               OPTIONAL flag parenthesized list
+               OPTIONAL date/time string
+               a single message literal or one or more message parts to
+               catenate, specified as:
+                           message literal
+                           or
+                           message (or message part) URL
+
+   Responses:  OPTIONAL NO responses: BADURL, TOOBIG
+
+   Result:     OK -  append completed
+               NO -  append error: can't append to that mailbox, error
+                     in flags or date/time or message text, or can't
+                     fetch that data
+               BAD - command unknown or arguments invalid
+
+   The APPEND command concatenates all the message parts and appends
+   them as a new message to the end of the specified mailbox.  The
+   parenthesized flag list and date/time string set the flags and the
+   internal date, respectively, as described in IMAP [1].  The
+   subsequent command parameters specify the message parts that are
+   appended sequentially to the output message.
+
+   If the original form of APPEND is used, a message literal follows the
+   optional flag list and date/time string, which is appended as
+   described in IMAP [1].  If the extended form is used, "CATENATE" and
+   a parenthesized list of message literals and message URLs follows,
+   each of which is appended to the new message.  If a message literal
+   is specified (indicated by "TEXT"), the octets following the count
+   are appended.  If a message URL is specified (indicated by "URL"),
+   the octets of the body part pointed to by that URL are appended, as
+   if the literal returned in a FETCH BODY response were put in place of
+   the message part specifier.  The APPEND command does not cause the
+   \Seen flag to be set for any catenated body part.  The APPEND command
+   does not change the selected mailbox.
+
+   In the extended APPEND command, the string following "URL" is an IMAP
+   URL [2] and is interpreted according to the rules of [2].  The
+   present document only describes the behavior of the command using
+   IMAP URLs that refer to specific messages or message parts on the
+   current IMAP server from the current authenticated IMAP session.
+   Because of that, only relative IMAP message or message part URLs
+   (i.e., those having no scheme or <iserver>) are used.  The base URL
+
+
+
+Resnick                     Standards Track                     [Page 3]
+
+RFC 4469                IMAP CATENATE Extension               April 2006
+
+
+   for evaluating the relative URL is considered "imap://user@server/",
+   where "user" is the user name of the currently authenticated user and
+   "server" is the domain name of the current server.  When in the
+   selected state, the base URL is considered
+   "imap://user@server/mailbox", where "mailbox" is the encoded name of
+   the currently selected mailbox.  Additionally, since the APPEND
+   command is valid in the authenticated state of an IMAP session, no
+   further LOGIN or AUTHENTICATE command is performed for URLs specified
+   in the extended APPEND command.
+
+      Note: Use of an absolute IMAP URL or any URL that refers to
+      anything other than a message or message part from the current
+      authenticated IMAP session is outside the scope of this document
+      and would require an extension to this specification, and a server
+      implementing only this specification would return NO to such a
+      request.
+
+   The client is responsible for making sure that the catenated message
+   is in the format of an Internet Message Format (RFC 2822) [4] or
+   Multipurpose Internet Mail Extension (MIME) [5] message.  In
+   particular, when a URL is catenated, the server copies octets,
+   unchanged, from the indicated message or message part to the
+   catenated message.  It does no data conversion (e.g., MIME transfer
+   encodings) nor any verification that the data is appropriate for the
+   MIME part of the message into which it is inserted.  The client is
+   also responsible for inserting appropriate MIME boundaries between
+   body parts, and writing MIME Content-Type and Content-Transfer-
+   Encoding lines as needed in the appropriate places.
+
+   Responses behave just as the original APPEND command described in
+   IMAP [1].  If the server implements the IMAP UIDPLUS extension [6],
+   it will also return an APPENDUID response code in the tagged OK
+   response.  Two response codes are provided in Section 4 that can be
+   used in the tagged NO response if the APPEND command fails.
+
+4.  Response Codes
+
+   When a APPEND command fails, it may return a response code that
+   describes a reason for the failure.
+
+4.1.  BADURL Response
+
+   The BADURL response code is returned if the APPEND fails to process
+   one of the specified URLs.  Possible reasons for this are bad URL
+   syntax, unrecognized URL schema, invalid message UID, or invalid body
+   part.  The BADURL response code contains the first URL specified as a
+   parameter to the APPEND command that has caused the operation to
+   fail.
+
+
+
+Resnick                     Standards Track                     [Page 4]
+
+RFC 4469                IMAP CATENATE Extension               April 2006
+
+
+4.2.  TOOBIG Response
+
+   The TOOBIG response code is returned if the resulting message will
+   exceed the 4-GB IMAP message limit.  This might happen, for example,
+   if the client specifies 3 URLs for 2-GB messages.  Note that even if
+   the server doesn't return TOOBIG, it still has to be defensive
+   against misbehaving or malicious clients that try to construct a
+   message over the 4-GB limit.  The server may also wish to return the
+   TOOBIG response code if the resulting message exceeds a server-
+   specific message size limit.
+
+5.  Formal Syntax
+
+   The following syntax specification uses the Augmented Backus-Naur
+   Form (ABNF) [7] notation.  Elements not defined here can be found in
+   the formal syntax of the ABNF [7], IMAP [1], and IMAP ABNF extensions
+   [8] specifications.  Note that capability and resp-text-code are
+   extended from the IMAP [1] specification and append-data is extended
+   from the IMAP ABNF extensions [8] specification.
+
+   append-data =/ "CATENATE" SP "(" cat-part *(SP cat-part) ")"
+
+   cat-part = text-literal / url
+
+   text-literal = "TEXT" SP literal
+
+   url = "URL" SP astring
+
+   resp-text-code =/ toobig-response-code / badurl-response-code
+
+   toobig-response-code = "TOOBIG"
+
+   badurl-response-code = "BADURL" SP url-resp-text
+
+   url-resp-text = 1*(%x01-09 /
+                      %x0B-0C /
+                      %x0E-5B /
+                      %x5D-FE) ; Any TEXT-CHAR except "]"
+
+   capability =/ "CATENATE"
+
+   The astring in the definition of url and the url-resp-text in the
+   definition of badurl-response-code each contain an imapurl as defined
+   by [2].
+
+
+
+
+
+
+
+Resnick                     Standards Track                     [Page 5]
+
+RFC 4469                IMAP CATENATE Extension               April 2006
+
+
+6.  Acknowledgements
+
+   Thanks to the members of the LEMONADE working group for their input.
+   Special thanks to Alexey Melnikov for the examples.
+
+7.  Security Considerations
+
+   The CATENATE extension does not raise any security considerations
+   that are not present for the base protocol or in the use of IMAP
+   URLs, and these issues are discussed in the IMAP [1] and IMAP URL [2]
+   documents.
+
+8.  IANA Considerations
+
+   IMAP4 capabilities are registered by publishing a standards track or
+   IESG approved experimental RFC.  The registry is currently located at
+   <http://www.iana.org/assignments/imap4-capabilities>.  This document
+   defines the CATENATE IMAP capability.  The IANA has added this
+   capability to the registry.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Resnick                     Standards Track                     [Page 6]
+
+RFC 4469                IMAP CATENATE Extension               April 2006
+
+
+Appendix A.  Examples
+
+   Lines not starting with "C: " or "S: " are continuations of the
+   previous lines.
+
+   The original message in examples 1 and 2 below (UID = 20) has the
+   following structure:
+
+
+      multipart/mixed MIME message with two body parts:
+
+      1.  text/plain
+
+      2.  application/x-zip-compressed
+
+   Example 1: The following example demonstrates how a CATENATE client
+   can replace an attachment in a draft message, without the need to
+   download it to the client and upload it back.
+
+   C: A003 APPEND Drafts (\Seen \Draft $MDNSent) CATENATE
+    (URL "/Drafts;UIDVALIDITY=385759045/;UID=20/;section=HEADER"
+    TEXT {42}
+   S: + Ready for literal data
+   C:
+   C: --------------030308070208000400050907
+   C:  URL "/Drafts;UIDVALIDITY=385759045/;UID=20/;section=1.MIME"
+    URL "/Drafts;UIDVALIDITY=385759045/;UID=20/;section=1" TEXT {42}
+   S: + Ready for literal data
+   C:
+   C: --------------030308070208000400050907
+   C:  URL "/Drafts;UIDVALIDITY=385759045/;UID=30" TEXT {44}
+   S: + Ready for literal data
+   C:
+   C: --------------030308070208000400050907--
+   C: )
+   S: A003 OK catenate append completed
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Resnick                     Standards Track                     [Page 7]
+
+RFC 4469                IMAP CATENATE Extension               April 2006
+
+
+   Example 2: The following example demonstrates how the CATENATE
+   extension can be used to replace edited text in a draft message, as
+   well as header fields for the top level message part (e.g., Subject
+   has changed).  The previous version of the draft is marked as
+   \Deleted.  Note that the server also supports the UIDPLUS extension,
+   so the APPENDUID response code is returned in the successful OK
+   response to the APPEND command.
+
+   C: A003 APPEND Drafts (\Seen \Draft $MDNSent) CATENATE (TEXT {738}
+   S: + Ready for literal data
+   C: Return-Path: <bar@example.org>
+   C: Received: from [127.0.0.2]
+   C:           by rufus.example.org via TCP (internal) with ESMTPA;
+   C:           Thu, 11 Nov 2004 16:57:07 +0000
+   C: Message-ID: <419399E1.6000505@example.org>
+   C: Date: Thu, 12 Nov 2004 16:57:05 +0000
+   C: From: Bob Ar <bar@example.org>
+   C: X-Accept-Language: en-us, en
+   C: MIME-Version: 1.0
+   C: To: foo@example.net
+   C: Subject: About our holiday trip
+   C: Content-Type: multipart/mixed;
+   C:               boundary="------------030308070208000400050907"
+   C:
+   C: --------------030308070208000400050907
+   C: Content-Type: text/plain; charset=us-ascii; format=flowed
+   C: Content-Transfer-Encoding: 7bit
+   C:
+   C: Our travel agent has sent the updated schedule.
+   C:
+   C: Cheers,
+   C: Bob
+   C: --------------030308070208000400050907
+   C:  URL "/Drafts;UIDVALIDITY=385759045/;UID=20/;Section=2.MIME"
+    URL "/Drafts;UIDVALIDITY=385759045/;UID=20/;Section=2" TEXT {44}
+   S: + Ready for literal data
+   C:
+   C: --------------030308070208000400050907--
+   C: )
+   S: A003 OK [APPENDUID 385759045 45] append Completed
+   C: A004 UID STORE 20 +FLAGS.SILENT (\Deleted)
+   S: A004 OK STORE completed
+
+
+
+
+
+
+
+
+
+Resnick                     Standards Track                     [Page 8]
+
+RFC 4469                IMAP CATENATE Extension               April 2006
+
+
+   Example 3: The following example demonstrates how the CATENATE
+   extension can be used to strip attachments.  Below, a PowerPoint
+   attachment was replaced by a small text part explaining that the
+   attachment was stripped.
+
+   C: A003 APPEND Drafts (\Seen \Draft $MDNSent) CATENATE
+    (URL "/Drafts;UIDVALIDITY=385759045/;UID=21/;section=HEADER"
+    TEXT {42}
+   S: + Ready for literal data
+   C:
+   C: --------------030308070208000400050903
+   C:  URL "/Drafts;UIDVALIDITY=385759045/;UID=21/;section=1.MIME"
+    URL "/Drafts;UIDVALIDITY=385759045/;UID=21/;section=1" TEXT {255}
+   S: + Ready for literal data
+   C:
+   C: --------------030308070208000400050903
+   C: Content-type: text/plain; charset="us-ascii"
+   C: Content-transfer-encoding: 7bit
+   C:
+   C: This body part contained a Power Point presentation that was
+   C: deleted upon your request.
+   C: --------------030308070208000400050903--
+   C: )
+   S: A003 OK append Completed
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Resnick                     Standards Track                     [Page 9]
+
+RFC 4469                IMAP CATENATE Extension               April 2006
+
+
+   Example 4: The following example demonstrates a failed APPEND
+   command.  The server returns the BADURL response code to indicate
+   that one of the provided URLs is invalid.  This example also
+   demonstrates how the CATENATE extension can be used to construct a
+   digest of several messages.
+
+   C: A003 APPEND Sent (\Seen $MDNSent) CATENATE (TEXT {541}
+   S: + Ready for literal data
+   C: Return-Path: <foo@example.org>
+   C: Received: from [127.0.0.2]
+   C:           by rufus.example.org via TCP (internal) with ESMTPA;
+   C:           Thu, 11 Nov 2004 16:57:07 +0000
+   C: Message-ID: <419399E1.6000505@example.org>
+   C: Date: Thu, 21 Nov 2004 16:57:05 +0000
+   C: From: Farren Oo <foo@example.org>
+   C: X-Accept-Language: en-us, en
+   C: MIME-Version: 1.0
+   C: To: bar@example.org
+   C: Subject: Digest of the mailing list for today
+   C: Content-Type: multipart/digest;
+   C:               boundary="------------030308070208000400050904"
+   C:
+   C: --------------030308070208000400050904
+   C:  URL "/INBOX;UIDVALIDITY=785799047/;UID=11467" TEXT {42}
+   S: + Ready for literal data
+   C:
+   C: --------------030308070208000400050904
+   C:  URL "/INBOX;UIDVALIDITY=785799047/;UID=113330/;section=1.5.9"
+    TEXT {42}
+   S: + Ready for literal data
+   C:
+   C: --------------030308070208000400050904
+   C:  URL "/INBOX;UIDVALIDITY=785799047/;UID=11916" TEXT {44}
+   S: + Ready for literal data
+   C:
+   C: --------------030308070208000400050904--
+   C: )
+   S: A003 NO [BADURL "/INBOX;UIDVALIDITY=785799047/;UID=113330;
+   section=1.5.9"] CATENATE append has failed, one message expunged
+
+   Note that the server could have validated the URLs as they were
+   received and therefore could have returned the tagged NO response
+   with BADURL response-code in place of any continuation request after
+   the URL was received.
+
+
+
+
+
+
+
+Resnick                     Standards Track                    [Page 10]
+
+RFC 4469                IMAP CATENATE Extension               April 2006
+
+
+9.  Normative References
+
+   [1]  Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1",
+        RFC 3501, March 2003.
+
+   [2]  Newman, C., "IMAP URL Scheme", RFC 2192, September 1997.
+
+   [3]  Crispin, M., "Internet Message Access Protocol (IMAP) -
+        MULTIAPPEND Extension", RFC 3502, March 2003.
+
+   [4]  Resnick, P., "Internet Message Format", RFC 2822, April 2001.
+
+   [5]  Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+        Extensions (MIME) Part One: Format of Internet Message Bodies",
+        RFC 2045, November 1996.
+
+   [6]  Crispin, M., "Internet Message Access Protocol (IMAP) - UIDPLUS
+        extension", RFC 4315, December 2005.
+
+   [7]  Crocker, D. and P. Overell, "Augmented BNF for Syntax
+        Specifications: ABNF", RFC 4234, October 2005.
+
+   [8]  Melnikov, A. and C. Daboo, "Collected Extensions to IMAP4 ABNF",
+        RFC 4466, April 2006.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Resnick                     Standards Track                    [Page 11]
+
+RFC 4469                IMAP CATENATE Extension               April 2006
+
+
+Author's Address
+
+   Peter W. Resnick
+   QUALCOMM Incorporated
+   5775 Morehouse Drive
+   San Diego, CA  92121-1714
+   US
+
+   Phone: +1 858 651 4478
+   EMail: presnick@qualcomm.com
+   URI:   http://www.qualcomm.com/~presnick/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Resnick                     Standards Track                    [Page 12]
+
+RFC 4469                IMAP CATENATE Extension               April 2006
+
+
+Full Copyright Statement
+
+   Copyright (C) The Internet Society (2006).
+
+   This document is subject to the rights, licenses and restrictions
+   contained in BCP 78, and except as set forth therein, the authors
+   retain all their rights.
+
+   This document and the information contained herein are provided on an
+   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   Intellectual Property Rights or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; nor does it represent that it has
+   made any independent effort to identify any such rights.  Information
+   on the procedures with respect to rights in RFC documents can be
+   found in BCP 78 and BCP 79.
+
+   Copies of IPR disclosures made to the IETF Secretariat and any
+   assurances of licenses to be made available, or the result of an
+   attempt made to obtain a general license or permission for the use of
+   such proprietary rights by implementers or users of this
+   specification can be obtained from the IETF on-line IPR repository at
+   http://www.ietf.org/ipr.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights that may cover technology that may be required to implement
+   this standard.  Please address the information to the IETF at
+   ietf-ipr@ietf.org.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is provided by the IETF
+   Administrative Support Activity (IASA).
+
+
+
+
+
+
+
+Resnick                     Standards Track                    [Page 13]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc4505.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,507 @@
+
+
+
+
+
+
+Network Working Group                                   K. Zeilenga, Ed.
+Request for Comments: 4505                           OpenLDAP Foundation
+Obsoletes: 2245                                                June 2006
+Category: Standards Track
+
+
+  Anonymous Simple Authentication and Security Layer (SASL) Mechanism
+
+Status of This Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (2006).
+
+Abstract
+
+   On the Internet, it is common practice to permit anonymous access to
+   various services.  Traditionally, this has been done with a plain-
+   text password mechanism using "anonymous" as the user name and using
+   optional trace information, such as an email address, as the
+   password.  As plain-text login commands are not permitted in new IETF
+   protocols, a new way to provide anonymous login is needed within the
+   context of the Simple Authentication and Security Layer (SASL)
+   framework.
+
+1.  Introduction
+
+   This document defines an anonymous mechanism for the Simple
+   Authentication and Security Layer ([SASL]) framework.  The name
+   associated with this mechanism is "ANONYMOUS".
+
+   Unlike many other SASL mechanisms, whose purpose is to authenticate
+   and identify the user to a server, the purpose of this SASL mechanism
+   is to allow the user to gain access to services or resources without
+   requiring the user to establish or otherwise disclose their identity
+   to the server.  That is, this mechanism provides an anonymous login
+   method.
+
+   This mechanism does not provide a security layer.
+
+   This document replaces RFC 2245.  Changes since RFC 2245 are detailed
+   in Appendix A.
+
+
+
+Zeilenga                    Standards Track                     [Page 1]
+
+RFC 4505                Anonymous SASL Mechanism               June 2006
+
+
+2.  The Anonymous Mechanism
+
+   The mechanism consists of a single message from the client to the
+   server.  The client may include in this message trace information in
+   the form of a string of [UTF-8]-encoded [Unicode] characters prepared
+   in accordance with [StringPrep] and the "trace" stringprep profile
+   defined in Section 3 of this document.  The trace information, which
+   has no semantical value, should take one of two forms: an Internet
+   email address, or an opaque string that does not contain the '@'
+   (U+0040) character and that can be interpreted by the system
+   administrator of the client's domain.  For privacy reasons, an
+   Internet email address or other information identifying the user
+   should only be used with permission from the user.
+
+   A server that permits anonymous access will announce support for the
+   ANONYMOUS mechanism and allow anyone to log in using that mechanism,
+   usually with restricted access.
+
+   A formal grammar for the client message using Augmented BNF [ABNF] is
+   provided below as a tool for understanding this technical
+   specification.
+
+      message     = [ email / token ]
+                    ;; to be prepared in accordance with Section 3
+
+      UTF1        = %x00-3F / %x41-7F ;; less '@' (U+0040)
+      UTF2        = %xC2-DF UTF0
+      UTF3        = %xE0 %xA0-BF UTF0 / %xE1-EC 2(UTF0) /
+                    %xED %x80-9F UTF0 / %xEE-EF 2(UTF0)
+      UTF4        = %xF0 %x90-BF 2(UTF0) / %xF1-F3 3(UTF0) /
+                    %xF4 %x80-8F 2(UTF0)
+      UTF0        = %x80-BF
+
+      TCHAR       = UTF1 / UTF2 / UTF3 / UTF4
+                    ;; any UTF-8 encoded Unicode character
+                    ;; except '@' (U+0040)
+
+      email       = addr-spec
+                    ;; as defined in [IMAIL]
+
+      token       = 1*255TCHAR
+
+   Note to implementors:
+      The <token> production is restricted to 255 UTF-8-encoded Unicode
+      characters.  As the encoding of a characters uses a sequence of 1
+      to 4 octets, a token may be as long as 1020 octets.
+
+
+
+
+
+Zeilenga                    Standards Track                     [Page 2]
+
+RFC 4505                Anonymous SASL Mechanism               June 2006
+
+
+3.  The "trace" Profile of "Stringprep"
+
+   This section defines the "trace" profile of [StringPrep].  This
+   profile is designed for use with the SASL ANONYMOUS Mechanism.
+   Specifically, the client is to prepare the <message> production in
+   accordance with this profile.
+
+   The character repertoire of this profile is Unicode 3.2 [Unicode].
+
+   No mapping is required by this profile.
+
+   No Unicode normalization is required by this profile.
+
+   The list of unassigned code points for this profile is that provided
+   in Appendix A of [StringPrep].  Unassigned code points are not
+   prohibited.
+
+   Characters from the following tables of [StringPrep] are prohibited:
+
+      - C.2.1 (ASCII control characters)
+      - C.2.2 (Non-ASCII control characters)
+      - C.3 (Private use characters)
+      - C.4 (Non-character code points)
+      - C.5 (Surrogate codes)
+      - C.6 (Inappropriate for plain text)
+      - C.8 (Change display properties are deprecated)
+      - C.9 (Tagging characters)
+
+   No additional characters are prohibited.
+
+   This profile requires bidirectional character checking per Section 6
+   of [StringPrep].
+
+4.  Example
+
+   Here is a sample ANONYMOUS login between an IMAP client and server.
+   In this example, "C:" and "S:" indicate lines sent by the client and
+   server, respectively.  If such lines are wrapped without a new "C:"
+   or "S:" label, then the wrapping is for editorial clarity and is not
+   part of the command.
+
+   Note that this example uses the IMAP profile [IMAP4] of SASL.  The
+   base64 encoding of challenges and responses as well as the "+ "
+   preceding the responses are part of the IMAP4 profile, not part of
+   SASL itself.  Additionally, protocols with SASL profiles permitting
+   an initial client response will be able to avoid the extra round trip
+   below (the server response with an empty "+ ").
+
+
+
+
+Zeilenga                    Standards Track                     [Page 3]
+
+RFC 4505                Anonymous SASL Mechanism               June 2006
+
+
+   In this example, the trace information is "sirhc".
+
+      S: * OK IMAP4 server ready
+      C: A001 CAPABILITY
+      S: * CAPABILITY IMAP4 IMAP4rev1 AUTH=DIGEST-MD5 AUTH=ANONYMOUS
+      S: A001 OK done
+      C: A002 AUTHENTICATE ANONYMOUS
+      S: +
+      C: c2lyaGM=
+      S: A003 OK Welcome, trace information has been logged.
+
+5.  Security Considerations
+
+   The ANONYMOUS mechanism grants access to services and/or resources by
+   anyone.  For this reason, it should be disabled by default so that
+   the administrator can make an explicit decision to enable it.
+
+   If the anonymous user has any write privileges, a denial-of-service
+   attack is possible by filling up all available space.  This can be
+   prevented by disabling all write access by anonymous users.
+
+   If anonymous users have read and write access to the same area, the
+   server can be used as a communication mechanism to exchange
+   information anonymously.  Servers that accept anonymous submissions
+   should implement the common "drop box" model, which forbids anonymous
+   read access to the area where anonymous submissions are accepted.
+
+   If the anonymous user can run many expensive operations (e.g., an
+   IMAP SEARCH BODY command), this could enable a denial-of-service
+   attack.  Servers are encouraged to reduce the priority of anonymous
+   users or limit their resource usage.
+
+   While servers may impose a limit on the number of anonymous users,
+   note that such limits enable denial-of-service attacks and should be
+   used with caution.
+
+   The trace information is not authenticated, so it can be falsified.
+   This can be used as an attempt to get someone else in trouble for
+   access to questionable information.  Administrators investigating
+   abuse need to realize that this trace information may be falsified.
+
+   A client that uses the user's correct email address as trace
+   information without explicit permission may violate that user's
+   privacy.  Anyone who accesses an anonymous archive on a sensitive
+   subject (e.g., sexual abuse) likely has strong privacy needs.
+   Clients should not send the email address without the explicit
+   permission of the user and should offer the option of supplying no
+   trace information, thus only exposing the source IP address and time.
+
+
+
+Zeilenga                    Standards Track                     [Page 4]
+
+RFC 4505                Anonymous SASL Mechanism               June 2006
+
+
+   Anonymous proxy servers could enhance this privacy but would have to
+   consider the resulting potential denial-of-service attacks.
+
+   Anonymous connections are susceptible to man-in-the-middle attacks
+   that view or alter the data transferred.  Clients and servers are
+   encouraged to support external data security services.
+
+   Protocols that fail to require an explicit anonymous login are more
+   susceptible to break-ins given certain common implementation
+   techniques.  Specifically, Unix servers that offer user login may
+   initially start up as root and switch to the appropriate user id
+   after an explicit login command.  Normally, such servers refuse all
+   data access commands prior to explicit login and may enter a
+   restricted security environment (e.g., the Unix chroot(2) function)
+   for anonymous users.  If anonymous access is not explicitly
+   requested, the entire data access machinery is exposed to external
+   security attacks without the chance for explicit protective measures.
+   Protocols that offer restricted data access should not allow
+   anonymous data access without an explicit login step.
+
+   General [SASL] security considerations apply to this mechanism.
+
+   [StringPrep] security considerations and [Unicode] security
+   considerations discussed in [StringPrep] apply to this mechanism.
+   [UTF-8] security considerations also apply.
+
+6.  IANA Considerations
+
+   The SASL Mechanism registry [IANA-SASL] entry for the ANONYMOUS
+   mechanism has been updated by the IANA to reflect that this document
+   now provides its technical specification.
+
+      To: iana@iana.org
+      Subject: Updated Registration of SASL mechanism ANONYMOUS
+
+      SASL mechanism name: ANONYMOUS
+      Security considerations: See RFC 4505.
+      Published specification (optional, recommended): RFC 4505
+      Person & email address to contact for further information:
+           Kurt Zeilenga <Kurt@OpenLDAP.org>
+           Chris Newman <Chris.Newman@sun.com>
+      Intended usage: COMMON
+      Author/Change controller: IESG <iesg@ietf.org>
+      Note: Updates existing entry for ANONYMOUS
+
+
+
+
+
+
+
+Zeilenga                    Standards Track                     [Page 5]
+
+RFC 4505                Anonymous SASL Mechanism               June 2006
+
+
+   The [StringPrep] profile "trace", first defined in this RFC, has been
+   registered:
+
+      To: iana@iana.org
+      Subject: Initial Registration of Stringprep "trace" profile
+
+      Stringprep profile: trace
+      Published specification: RFC 4505
+      Person & email address to contact for further information:
+          Kurt Zeilenga <kurt@openldap.org>
+
+7.  Acknowledgement
+
+   This document is a revision of RFC 2245 by Chris Newman.  Portions of
+   the grammar defined in Section 1 were borrowed from RFC 3629 by
+   Francois Yergeau.
+
+   This document is a product of the IETF SASL WG.
+
+8.  Normative References
+
+   [ABNF]       Crocker, D. and P. Overell, "Augmented BNF for Syntax
+                Specifications: ABNF", RFC 4234, October 2005.
+
+   [IMAIL]      Resnick, P., "Internet Message Format", RFC 2822, April
+                2001.
+
+   [SASL]       Melnikov, A., Ed. and K. Zeilenga, Ed., "Simple
+                Authentication and Security Layer (SASL)", RFC 4422,
+                June 2006.
+
+   [StringPrep] Hoffman, P. and M. Blanchet, "Preparation of
+                Internationalized Strings ('stringprep')", RFC 3454,
+                December 2002.
+
+   [Unicode]    The Unicode Consortium, "The Unicode Standard, Version
+                3.2.0" is defined by "The Unicode Standard, Version 3.0"
+                (Reading, MA, Addison-Wesley, 2000. ISBN 0-201-61633-5),
+                as amended by the "Unicode Standard Annex #27: Unicode
+                3.1" (http://www.unicode.org/reports/tr27/) and by the
+                "Unicode Standard Annex #28: Unicode 3.2"
+                (http://www.unicode.org/reports/tr28/).
+
+   [UTF-8]      Yergeau, F., "UTF-8, a transformation format of ISO
+                10646", RFC 3629 (also STD 63), November 2003.
+
+
+
+
+
+
+Zeilenga                    Standards Track                     [Page 6]
+
+RFC 4505                Anonymous SASL Mechanism               June 2006
+
+
+9.  Informative References
+
+   [IMAP4]      Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
+                4rev1", RFC 3501, March 2003.
+
+   [IANA-SASL]  IANA, "SIMPLE AUTHENTICATION AND SECURITY LAYER (SASL)
+                MECHANISMS", <http://www.iana.org/assignments/sasl-
+                mechanisms>.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Zeilenga                    Standards Track                     [Page 7]
+
+RFC 4505                Anonymous SASL Mechanism               June 2006
+
+
+Appendix A.  Changes since RFC 2245
+
+   This appendix is non-normative.
+
+   RFC 2245 allows the client to include optional trace information in
+   the form of a human readable string.  RFC 2245 restricted this string
+   to US-ASCII.  As the Internet is international, this document uses a
+   string restricted to UTF-8 encoded Unicode characters.  A
+   "stringprep" profile is defined to precisely define which Unicode
+   characters are allowed in this string.  While the string remains
+   restricted to 255 characters, the encoded length of each character
+   may now range from 1 to 4 octets.
+
+   Additionally, a number of editorial changes were made.
+
+Editor's Address
+
+   Kurt D. Zeilenga
+   OpenLDAP Foundation
+
+   EMail: Kurt@OpenLDAP.org
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Zeilenga                    Standards Track                     [Page 8]
+
+RFC 4505                Anonymous SASL Mechanism               June 2006
+
+
+Full Copyright Statement
+
+   Copyright (C) The Internet Society (2006).
+
+   This document is subject to the rights, licenses and restrictions
+   contained in BCP 78, and except as set forth therein, the authors
+   retain all their rights.
+
+   This document and the information contained herein are provided on an
+   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   Intellectual Property Rights or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; nor does it represent that it has
+   made any independent effort to identify any such rights.  Information
+   on the procedures with respect to rights in RFC documents can be
+   found in BCP 78 and BCP 79.
+
+   Copies of IPR disclosures made to the IETF Secretariat and any
+   assurances of licenses to be made available, or the result of an
+   attempt made to obtain a general license or permission for the use of
+   such proprietary rights by implementers or users of this
+   specification can be obtained from the IETF on-line IPR repository at
+   http://www.ietf.org/ipr.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights that may cover technology that may be required to implement
+   this standard.  Please address the information to the IETF at
+   ietf-ipr@ietf.org.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is provided by the IETF
+   Administrative Support Activity (IASA).
+
+
+
+
+
+
+
+Zeilenga                    Standards Track                     [Page 9]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc4549.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1963 @@
+
+
+
+
+
+
+Network Working Group                                   A. Melnikov, Ed.
+Request for Comments: 4549                                    Isode Ltd.
+Category: Informational                                        June 2006
+
+
+       Synchronization Operations for Disconnected IMAP4 Clients
+
+Status of This Memo
+
+   This memo provides information for the Internet community.  It does
+   not specify an Internet standard of any kind.  Distribution of this
+   memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (2006).
+
+Abstract
+
+   This document attempts to address some of the issues involved in
+   building a disconnected IMAP4 client.  In particular, it deals with
+   the issues of what might be called the "driver" portion of the
+   synchronization tool: the portion of the code responsible for issuing
+   the correct set of IMAP4 commands to synchronize the disconnected
+   client in the way that is most likely to make the human who uses the
+   disconnected client happy.
+
+   This note describes different strategies that can be used by
+   disconnected clients and shows how to use IMAP protocol in order to
+   minimize the time of the synchronization process.
+
+   This note also lists IMAP extensions that a server should implement
+   in order to provide better synchronization facilities to disconnected
+   clients.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov                     Informational                      [Page 1]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+Table of Contents
+
+   1. Introduction ....................................................3
+      1.1. Conventions Used in This Document ..........................3
+   2. Design Principles ...............................................3
+   3. Overall Picture of Synchronization ..............................4
+   4. Mailbox Synchronization Steps and Strategies ....................7
+      4.1. Checking UID Validity ......................................7
+      4.2. Synchronizing Local Changes with the Server ................8
+           4.2.1. Uploading Messages to the Mailbox ...................8
+           4.2.2. Optimizing "move" and "copy" Operations .............9
+           4.2.3. Replaying Local Flag Changes .......................14
+           4.2.4. Processing Mailbox Compression (EXPUNGE) Requests ..15
+           4.2.5. Closing a Mailbox ..................................17
+      4.3. Details of "Normal" Synchronization of a Single Mailbox ...18
+           4.3.1. Discovering New Messages and Changes to Old
+                  Messages ...........................................18
+           4.3.2. Searching for "Interesting" Messages. ..............20
+           4.3.3. Populating Cache with "Interesting" Messages. ......21
+           4.3.4. User-Initiated Synchronization .....................22
+      4.4. Special Case: Descriptor-Only Synchronization .............22
+      4.5. Special Case: Fast New-Only Synchronization ...............23
+      4.6. Special Case: Blind FETCH .................................23
+   5. Implementation Considerations ..................................24
+      5.1. Error Recovery during Playback ............................26
+      5.2. Quality of Implementation Issues ..........................28
+      5.3. Optimizations .............................................28
+   6. IMAP Extensions That May Help ..................................30
+      6.1. CONDSTORE Extension .......................................30
+   7. Security Considerations ........................................33
+   8. References .....................................................33
+      8.1. Normative References ......................................33
+      8.2. Informative References ....................................34
+   9. Acknowledgements ...............................................34
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov                     Informational                      [Page 2]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+1.  Introduction
+
+   Several recommendations presented in this document are generally
+   applicable to all types of IMAP clients.  However, this document
+   tries to concentrate on disconnected mail clients [IMAP-MODEL].  It
+   also suggests some IMAP extensions* that should be implemented by
+   IMAP servers in order to make the life of disconnected clients
+   easier.  In particular, the [UIDPLUS] extension was specifically
+   designed to streamline certain disconnected operations, like
+   expunging, uploading, and copying messages (see Sections 4.2.1,
+   4.2.2.1, and 4.2.4).
+
+   Readers of this document are also strongly advised to read RFC 2683
+   [RFC2683].
+
+   * Note that the functionality provided by the base IMAP protocol
+     [IMAP4] is sufficient to perform basic synchronization.
+
+1.1.  Conventions Used in This Document
+
+   In examples, "C:" and "S:" indicate lines sent by the client and
+   server, respectively.  Long lines in examples are broken for
+   editorial clarity.
+
+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+   document are to be interpreted as described in RFC 2119 [KEYWORDS].
+
+   Let's call an IMAP command idempotent if the result of executing the
+   command twice sequentially is the same as the result of executing the
+   command just once.
+
+2.  Design Principles
+
+   All mailbox state or content information stored on the disconnected
+   client should be viewed strictly as a cache of the state of the
+   server.  The "master" state remains on the server, just as it would
+   with an interactive IMAP4 client.  The one exception to this rule is
+   that information about the state of the disconnected client's cache
+   (the state includes flag changes while offline and during scheduled
+   message uploads) remains on the disconnected client: that is, the
+   IMAP4 server is not responsible for remembering the state of the
+   disconnected IMAP4 client.
+
+   We assume that a disconnected client is a client that, for whatever
+   reason, wants to minimize the length of time that it is "on the
+   phone" to the IMAP4 server.  Often this will be because the client is
+   using a dialup connection, possibly with very low bandwidth, but
+
+
+
+Melnikov                     Informational                      [Page 3]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+   sometimes it might just be that the human is in a hurry to catch an
+   airplane, or some other event beyond our control.  Whatever the
+   reason, we assume that we must make efficient use of the network
+   connection, both in the usual sense (not generating spurious traffic)
+   and in the sense that we would prefer not to have the connection
+   sitting idle while the client and/or the server is performing
+   strictly local computation or I/O.  Another, perhaps simpler way of
+   stating this is that we assume that network connections are
+   "expensive".
+
+   Practical experience with disconnected mail systems has shown that
+   there is no single synchronization strategy that is appropriate for
+   all cases.  Different humans have different preferences, and the same
+   human's preference will vary depending both on external circumstance
+   (how much of a hurry the human is in today) and on the value that the
+   human places on the messages being transferred.  The point here is
+   that there is no way that the synchronization program can guess
+   exactly what the human wants to do, so the human will have to provide
+   some guidance.
+
+   Taken together, the preceding two principles lead to the conclusion
+   that the synchronization program must make its decisions based on
+   some kind of guidance provided by the human, by selecting the
+   appropriate options in the user interface or through some sort of
+   configuration file.  Almost certainly, it should not pause for I/O
+   with the human in the middle of the synchronization process.  The
+   human will almost certainly have several different configurations for
+   the synchronization program, for different circumstances.
+
+   Since a disconnected client has no way of knowing what changes might
+   have occurred to the mailbox while it was disconnected, message
+   numbers are not useful to a disconnected client.  All disconnected
+   client operations should be performed using UIDs, so that the client
+   can be sure that it and the server are talking about the same
+   messages during the synchronization process.
+
+3.  Overall Picture of Synchronization
+
+   The basic strategy for synchronization is outlined below.  Note that
+   the real strategy may vary from one application to another or may
+   depend on a synchronization mode.
+
+   a) Process any "actions" that were pending on the client that were
+      not associated with any mailbox.  (In particular sending messages
+      composed offline with SMTP.  This is not part of IMAP
+      synchronization, but it is mentioned here for completeness.)
+
+
+
+
+
+Melnikov                     Informational                      [Page 4]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+   b) Fetch the current list of "interesting" mailboxes.  (The
+      disconnected client should allow the user to skip this step
+      completely.)
+
+   c) "Client-to-server synchronization": for each IMAP "action" that
+      was pending on the client, do the following:
+
+      1) If the action implies opening a new mailbox (any operation that
+         operates on messages), open the mailbox.  Check its UID
+         validity value (see Section 4.1 for more details) returned in
+         the UIDVALIDITY response code.  If the UIDVALIDITY value
+         returned by the server differs, the client MUST empty the local
+         cache of the mailbox and remove any pending "actions" that
+         refer to UIDs in that mailbox (and consider them failed).  Note
+         that this doesn't affect actions performed on client-generated
+         fake UIDs (see Section 5).
+
+      2) Perform the action.  If the action is to delete a mailbox
+         (DELETE), make sure that the mailbox is closed first (see also
+         Section 3.4.12 of [RFC2683]).
+
+   d) "Server-to-client synchronization": for each mailbox that requires
+      synchronization, do the following:
+
+      1) Check the mailbox UIDVALIDITY (see Section 4.1 for more
+         details) with SELECT/EXAMINE/STATUS.
+
+         If UIDVALIDITY value returned by the server differs, the client
+         MUST
+
+         * empty the local cache of that mailbox;
+         * remove any pending "actions" that refer to UIDs in that
+           mailbox and consider them failed; and
+         * skip step 2-II.
+
+      2) Fetch the current "descriptors";
+
+         I)  Discover new messages.
+
+         II) Discover changes to old messages.
+
+      3) Fetch the bodies of any "interesting" messages that the client
+         doesn't already have.
+
+   e) Close all open mailboxes not required for further operations (if
+      staying online) or disconnect all open connections (if going
+      offline).
+
+
+
+
+Melnikov                     Informational                      [Page 5]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+   Terms used:
+
+   "Actions" are queued requests that were made by the human to the
+   client's Mail User Agent (MUA) software while the client was
+   disconnected.
+
+   We define "descriptors" as a set of IMAP4 FETCH data items.
+   Conceptually, a message's descriptor is that set of information that
+   allows the synchronization program to decide what protocol actions
+   are necessary to bring the local cache to the desired state for this
+   message; since this decision is really up to the human, this
+   information probably includes at least a few header fields intended
+   for human consumption.  Exactly what will constitute a descriptor
+   depends on the client implementation.  At a minimum, the descriptor
+   contains the message's UID and FLAGS.  Other likely candidates are
+   the RFC822.SIZE, RFC822.HEADER, BODYSTRUCTURE, or ENVELOPE data
+   items.
+
+   Comments:
+
+   1) The list of actions should be ordered.  For example, if the human
+      deletes message A1 in mailbox A, then expunges mailbox A, and then
+      deletes message A2 in mailbox A, the human will expect that
+      message A1 is gone and that message A2 is still present but is now
+      deleted.
+
+      By processing all the actions before proceeding with
+      synchronization, we avoid having to compensate for the local MUA's
+      changes to the server's state.  That is, once we have processed
+      all the pending actions, the steps that the client must take to
+      synchronize itself will be the same no matter where the changes to
+      the server's state originated.
+
+   2) Steps a and b can be performed in parallel.  Alternatively, step a
+      can be performed after d.
+
+   3) On step b, the set of "interesting" mailboxes pretty much has to
+      be determined by the human.  What mailboxes belong to this set may
+      vary between different IMAP4 sessions with the same server,
+      client, and human.  An interesting mailbox can be a mailbox
+      returned by LSUB command (see Section 6.3.9 of [IMAP4]).  The
+      special mailbox "INBOX" SHOULD be in the default set of mailboxes
+      that the client considers interesting.  However, providing the
+      ability to ignore INBOX for a particular session or client may be
+      valuable for some mail filtering strategies.
+
+
+
+
+
+
+Melnikov                     Informational                      [Page 6]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+   4) On step d-2-II, the client also finds out about changes to the
+      flags of messages that the client already has in its local cache,
+      and about messages in the local cache that no longer exist on the
+      server (i.e., messages that have been expunged).
+
+   5) "Interesting" messages are those messages that the synchronization
+      program thinks the human wants to have cached locally, based on
+      the configuration and the data retrieved in step b.
+
+   6) A disconnected IMAP client is a special case of an IMAP client, so
+      it MUST be able to handle any "unexpected" unsolicited responses,
+      like EXISTS and EXPUNGE, at any time.  The disconnected client MAY
+      ignore EXPUNGE response during "client-to-server" synchronization
+      phase (step c).
+
+   The rest of this discussion will focus primarily on the
+   synchronization issues for a single mailbox.
+
+4.  Mailbox Synchronization Steps and Strategies
+
+4.1.  Checking UID Validity
+
+   The "UID validity" of a mailbox is a number returned in an
+   UIDVALIDITY response code in an OK untagged response at mailbox
+   selection time.  The UID validity value changes between sessions when
+   UIDs fail to persist between sessions.
+
+   Whenever the client selects a mailbox, the client must compare the
+   returned UID validity value with the value stored in the local cache.
+   If the UID validity values differ, the UIDs in the client's cache are
+   no longer valid.  The client MUST then empty the local cache of that
+   mailbox and remove any pending "actions" that refer to UIDs in that
+   mailbox.  The client MAY also issue a warning to the human.  The
+   client MUST NOT cancel any scheduled uploads (i.e., APPENDs) for the
+   mailbox.
+
+   Note that UIDVALIDITY is not only returned on a mailbox selection.
+   The COPYUID and APPENDUID response codes defined in the [UIDPLUS]
+   extension (see also 4.2.2) and the UIDVALIDITY STATUS response data
+   item also contain a UIDVALIDITY value for some other mailbox.  The
+   client SHOULD behave as described in the previous paragraph (but it
+   should act on the other mailbox's cache), no matter how it obtained
+   the UIDVALIDITY value.
+
+
+
+
+
+
+
+
+Melnikov                     Informational                      [Page 7]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+4.2.  Synchronizing Local Changes with the Server
+
+4.2.1.  Uploading Messages to the Mailbox
+
+   Two of the most common examples of operations resulting in message
+   uploads are:
+
+   1) Saving a draft message
+
+   2) Copying a message between remote mailboxes on two different IMAP
+      servers or a local mailbox and a remote mailbox.
+
+   Message upload is performed with the APPEND command.  A message
+   scheduled to be uploaded has no UID associated with it, as all UIDs
+   are assigned by the server.  The APPEND command will effectively
+   associate a UID with the uploaded message that can be stored in the
+   local cache for future reference.  However, [IMAP4] doesn't describe
+   a simple mechanism to discover the message UID by just performing the
+   APPEND command.  In order to discover the UID, the client can do one
+   of the following:
+
+   1) Remove the uploaded message from cache.  Then, use the mechanism
+      described in 4.3 to fetch the information about the uploaded
+      message as if it had been uploaded by some other client.
+
+   2) Try to fetch header information as described in 4.2.2 in order to
+      find a message that corresponds to the uploaded message.  One
+      strategy for doing this is described in 4.2.2.
+
+   Case 1 describes a not particularly smart client.
+
+      C: A003 APPEND Drafts (\Seen $MDNSent) {310}
+      S: + Ready for literal data
+      C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
+      C: From: Fred Foobar <foobar@blt.example.COM>
+      C: Subject: afternoon meeting
+      C: To: mooch@owatagu.siam.edu
+      C: Message-Id: <B27397-0100000@blt.example.COM>
+      C: MIME-Version: 1.0
+      C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
+      C:
+      C: Hello Joe, do you think we can meet at 3:30 tomorrow?
+      C:
+      S: A003 OK APPEND Completed
+
+   Fortunately, there is a simpler way to discover the message UID in
+   the presence of the [UIDPLUS] extension:
+
+
+
+
+Melnikov                     Informational                      [Page 8]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+      C: A003 APPEND Drafts (\Seen $MDNSent) {310}
+      S: + Ready for literal data
+      C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
+      C: From: Fred Foobar <foobar@blt.example.COM>
+      C: Subject: afternoon meeting
+      C: To: mooch@owatagu.siam.edu
+      C: Message-Id: <B27397-0100000@blt.example.COM>
+      C: MIME-Version: 1.0
+      C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
+      C:
+      C: Hello Joe, do you think we can meet at 3:30 tomorrow?
+      C:
+      S: A003 OK [APPENDUID 1022843275 77712] APPEND completed
+
+   The UID of the appended message is the second parameter of APPENDUID
+   response code.
+
+4.2.2.  Optimizing "move" and "copy" Operations
+
+   Practical experience with IMAP and other mailbox access protocols
+   that support multiple mailboxes suggests that moving a message from
+   one mailbox to another is an extremely common operation.
+
+4.2.2.1.  Moving a Message between Two Mailboxes on the Same Server
+
+   In IMAP4, a "move" operation between two mailboxes on the same server
+   is really a combination of a COPY operation and a STORE +FLAGS
+   (\Deleted) operation.  This makes good protocol sense for IMAP, but
+   it leaves a simple-minded disconnected client in the silly position
+   of deleting and possibly expunging its cached copy of a message, then
+   fetching an identical copy via the network.
+
+   However, the presence of the UIDPLUS extension in the server can
+   help:
+
+      C: A001 UID COPY 567,414 "Interesting Messages"
+      S: A001 OK [COPYUID 1022843275 414,567 5:6] Completed
+
+   This tells the client that the message with UID 414 in the current
+   mailbox was successfully copied to the mailbox "Interesting Messages"
+   and was given the UID 5, and that the message with UID 567 was given
+   the UID 6.
+
+   In the absence of UIDPLUS extension support in the server, the
+   following trick can be used.  By including the Message-ID: header and
+   the INTERNALDATE data item as part of the descriptor, the client can
+   check the descriptor of a "new" message against messages that are
+   already in its cache and avoid fetching the extra copy.  Of course,
+
+
+
+Melnikov                     Informational                      [Page 9]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+   it's possible that the cost of checking to see if the message is
+   already in the local cache may exceed the cost of just fetching it,
+   so this technique should not be used blindly.  If the MUA implements
+   a "move" command, it makes special provisions to use this technique
+   when it knows that a copy/delete sequence is the result of a "move"
+   command.
+
+   Note that servers are not required (although they are strongly
+   encouraged with "SHOULD language") to preserve INTERNALDATE when
+   copying messages.
+
+   Also note that since it's theoretically possible for this algorithm
+   to find the wrong message (given sufficiently malignant Message-ID
+   headers), implementers should provide a way to disable this
+   optimization, both permanently and on a message-by-message basis.
+
+   Example 1: Copying a message in the absence of UIDPLUS extension.
+
+   At some point in time the client has fetched the source message and
+   some information was cached:
+
+      C: C021 UID FETCH <uids> (BODY.PEEK[] INTERNALDATE FLAGS)
+      ...
+      S: * 27 FETCH (UID 123 INTERNALDATE "31-May-2002 05:26:59 -0600"
+          FLAGS (\Draft $MDNSent) BODY[] {1036}
+      S: ...
+      S: Message-Id: <20040903110856.22a127cd@chardonnay>
+      S: ...
+      S: ...message body...
+      S: )
+      ...
+      S: C021 OK fetch completed
+
+   Later on, the client decides to copy the message:
+
+      C: C035 UID COPY 123 "Interesting Messages"
+      S: C035 OK Completed
+
+   As the server hasn't provided the COPYUID response code, the client
+   tries the optimization described above:
+
+      C: C036 SELECT "Interesting Messages"
+      ...
+      C: C037 UID SEARCH ON 31-May-2002 HEADER
+          "Message-Id" "20040903110856.22a127cd@chardonnay"
+      S: SEARCH 12368
+      S: C037 OK completed
+
+
+
+
+Melnikov                     Informational                     [Page 10]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+   Note that if the server has returned multiple UIDs in the SEARCH
+   response, the client MUST NOT use any of the returned UID.
+
+4.2.2.2.  Moving a Message from a Remote Mailbox to a Local
+
+   Moving a message from a remote mailbox to a local is done with FETCH
+   (that includes FLAGS and INTERNALDATE) followed by UID STORE <uid>
+   +FLAGS.SILENT (\Deleted):
+
+      C: A003 UID FETCH 123 (BODY.PEEK[] INTERNALDATE FLAGS)
+      S: * 27 FETCH (UID 123 INTERNALDATE "31-May-2002 05:26:59 -0600"
+          FLAGS (\Seen $MDNSent) BODY[]
+      S: ...message body...
+      S: )
+      S: A003 OK UID FETCH completed
+      C: A004 UID STORE <uid> +FLAGS.SILENT (\Deleted)
+      S: A004 STORE completed
+
+   Note that there is no reason to fetch the message during
+   synchronization if it's already in the client's cache.  Also, the
+   client SHOULD preserve delivery date in the local cache.
+
+4.2.2.3.  Moving a Message from a Local Mailbox to a Remote
+
+   Moving a message from a local mailbox to a remote is done with
+   APPEND:
+
+   C: A003 APPEND Drafts (\Seen $MDNSent) "31-May-2002 05:26:59 -0600"
+       {310}
+   S: + Ready for literal data
+   C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
+   C: From: Fred Foobar <foobar@blt.example.COM>
+   C: Subject: afternoon meeting
+   C: To: mooch@owatagu.siam.edu
+   C: Message-Id: <B27397-0100000@blt.example.COM>
+   C: MIME-Version: 1.0
+   C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
+   C:
+   C: Hello Joe, do you think we can meet at 3:30 tomorrow?
+   C:
+   S: A003 OK [APPENDUID 1022843275 77712] completed
+
+   The client SHOULD specify the delivery date from the local cache in
+   the APPEND.
+
+   If the [LITERAL+] extension is available, the client can save a
+   round-trip*:
+
+
+
+
+Melnikov                     Informational                     [Page 11]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+   C: A003 APPEND Drafts (\Seen $MDNSent) "31-May-2002 05:26:59 -0600"
+       {310+}
+   C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
+   C: From: Fred Foobar <foobar@blt.example.COM>
+   C: Subject: afternoon meeting
+   C: To: mooch@owatagu.siam.edu
+   C: Message-Id: <B27397-0100000@blt.example.COM>
+   C: MIME-Version: 1.0
+   C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
+   C:
+   C: Hello Joe, do you think we can meet at 3:30 tomorrow?
+   C:
+   S: A003 OK [APPENDUID 1022843275 77712] completed
+
+   * Note that there is a risk that the server will reject the message
+     due to its size.  If this happens, the client will waste bandwidth
+     transferring the whole message.  If the client wouldn't have used
+     the LITERAL+, this could have been avoided:
+
+   C: A003 APPEND Drafts (\Seen $MDNSent) "31-May-2004 05:26:59 -0600"
+       {16777215}
+   S: A003 NO Sorry, message is too big
+
+4.2.2.4.  Moving a Message between Two Mailboxes on Different Servers
+
+   Moving a message between two mailbox on two different servers is a
+   combination of the operations described in 4.2.2.2 followed by the
+   operations described in 4.2.2.3.
+
+4.2.2.5.  Uploading Multiple Messages to a Remote Mailbox with
+          MULTIAPPEND
+
+   When there is a need to upload multiple messages to a remote mailbox
+   (e.g., as per 4.2.2.3), the presence of certain IMAP extensions may
+   significantly improve performance.  One of them is [MULTIAPPEND].
+
+   For some mail stores, opening a mailbox for appending might be
+   expensive.  [MULTIAPPEND] tells the server to open the mailbox once
+   (instead of opening and closing it "n" times per "n" messages to be
+   uploaded) and to keep it open while a group of messages is being
+   uploaded to the server.
+
+   Also, if the server supports both [MULTIAPPEND] and [LITERAL+]
+   extensions, the entire upload is accomplished in a single
+   command/response round-trip.
+
+
+
+
+
+
+Melnikov                     Informational                     [Page 12]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+   Note: Client implementers should be aware that [MULTIAPPEND] performs
+   append of multiple messages atomically.  This means, for example, if
+   there is not enough space to save "n"-th message (or the message has
+   invalid structure and is rejected by the server) after successful
+   upload of "n-1" messages, the whole upload operation fails, and no
+   message will be saved in the mailbox.  Although this behavior might
+   be desirable in certain situations, it might not be what you want.
+   Otherwise, the client should use the regular APPEND command (Section
+   4.2.2.3), possibly utilizing the [LITERAL+] extension.  See also
+   Section 5.1 for discussions about error recovery.
+
+   Note: MULTIAPPEND can be used together with the UIDPLUS extension in
+   a way similar to what was described in Section 4.2.1.  [MULTIAPPEND]
+   extends the syntax of the APPENDUID response code to allow for
+   multiple message UIDs in the second parameter.
+
+   Example 2:
+
+   This example demonstrates the use of MULTIAPPEND together with
+   UIDPLUS (synchronization points where the client waits for
+   confirmations from the server are marked with "<--->"):
+
+   C: A003 APPEND Jan-2002 (\Seen $MDNSent) "31-May-2002 05:26:59 -0600"
+       {310}
+   <--->
+   S: + Ready for literal data
+   C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
+   C: From: Fred Foobar <foobar@blt.example.COM>
+   C: Subject: afternoon meeting
+   C: To: mooch@owatagu.siam.edu
+   C: Message-Id: <B27397-0100000@blt.example.COM>
+   C: MIME-Version: 1.0
+   C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
+   C:
+   C: Hello Joe, do you think we can meet at 3:30 tomorrow?
+   C:  (\Seen) " 1-Jun-2002 22:43:04 -0800" {286}
+   <--->
+   S: + Ready for literal data
+   C: Date: Mon, 7 Feb 1994 22:43:04 -0800 (PST)
+   C: From: Joe Mooch <mooch@OWaTaGu.siam.EDU>
+   C: Subject: Re: afternoon meeting
+   C: To: foobar@blt.example.com
+   C: Message-Id: <a0434793874930@OWaTaGu.siam.EDU>
+   C: MIME-Version: 1.0
+   C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
+   C:
+   C: 3:30 is fine with me.
+   C:
+
+
+
+Melnikov                     Informational                     [Page 13]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+   S: A003 OK [APPENDUID 1022843275 77712,77713] completed
+
+   The upload takes 3 round-trips.
+
+   Example 3:
+
+   In this example, Example 2 was modified for the case when the server
+   supports MULTIAPPEND, LITERAL+, and UIDPLUS.  The upload takes only 1
+   round-trip.
+
+   C: A003 APPEND Jan-2002 (\Seen $MDNSent) "31-May-2002 05:26:59 -0600"
+       {310+}
+   C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
+   C: From: Fred Foobar <foobar@blt.example.COM>
+   C: Subject: afternoon meeting
+   C: To: mooch@owatagu.siam.edu
+   C: Message-Id: <B27397-0100000@blt.example.COM>
+   C: MIME-Version: 1.0
+   C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
+   C:
+   C: Hello Joe, do you think we can meet at 3:30 tomorrow?
+   C:  (\Seen) " 1-Jun-2002 22:43:04 -0800" {286+}
+   C: Date: Mon, 7 Feb 1994 22:43:04 -0800 (PST)
+   C: From: Joe Mooch <mooch@OWaTaGu.siam.EDU>
+   C: Subject: Re: afternoon meeting
+   C: To: foobar@blt.example.com
+   C: Message-Id: <a0434793874930@OWaTaGu.siam.EDU>
+   C: MIME-Version: 1.0
+   C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
+   C:
+   C: 3:30 is fine with me.
+   C:
+   S: A003 OK [APPENDUID 1022843275 77712,77713] completed
+
+4.2.3.  Replaying Local Flag Changes
+
+   The disconnected client uses the STORE command to synchronize local
+   flag state with the server.  The disconnected client SHOULD use
+   +FLAGS.SILENT or -FLAGS.SILENT in order to set or unset flags
+   modified by the user while offline.  The FLAGS form MUST NOT be used,
+   as there is a risk that this will overwrite flags on the server that
+   have been changed by some other client.
+
+   Example 4:
+
+   For the message with UID 15, the disconnected client stores the
+   following flags \Seen and $Highest.  The flags were modified on the
+   server by some other client: \Seen, \Answered, and $Highest.  While
+
+
+
+Melnikov                     Informational                     [Page 14]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+   offline, the user requested that the $Highest flags be removed and
+   that the \Deleted flag be added.  The flag synchronization sequence
+   for the message should look like:
+
+      C: A001 UID STORE 15 +FLAGS.SILENT (\Deleted)
+      S: A001 STORE completed
+      C: A002 UID STORE 15 -FLAGS.SILENT ($Highest)
+      S: A002 STORE completed
+
+   If the disconnected client is able to store an additional binary
+   state information (or a piece of information that can take a value
+   from a predefined set of values) in the local cache of an IMAP
+   mailbox or in a local mailbox (e.g., message priority), and if the
+   server supports storing of arbitrary keywords, the client MUST use
+   keywords to store this state on the server.
+
+   Example 5:
+
+   Imagine a speculative mail client that can mark a message as one of
+   work-related ($Work), personal ($Personal), or spam ($Spam).  In
+   order to mark a message as personal, the client issues:
+
+      C: A001 UID STORE 15 +FLAGS.SILENT ($Personal)
+      S: A001 STORE completed
+      C: A002 UID STORE 15 -FLAGS.SILENT ($Work $Spam)
+      S: A002 STORE completed
+
+   In order to mark the message as not work, not personal and not spam,
+   the client issues:
+
+      C: A003 UID STORE 15 -FLAGS.SILENT ($Personal $Work $Spam)
+      S: A003 STORE completed
+
+4.2.4.  Processing Mailbox Compression (EXPUNGE) Requests
+
+   A naive disconnected client implementation that supports compressing
+   a mailbox while offline may decide to issue an EXPUNGE command to the
+   server in order to expunge messages marked \Deleted.  The problem
+   with this command during synchronization is that it permanently
+   erases all messages with the \Deleted flag set, i.e., even those
+   messages that were marked as \Deleted on the server while the user
+   was offline.  Doing this might result in an unpleasant surprise for
+   the user.
+
+   Fortunately the [UIDPLUS] extension can help in this case as well.
+   The extension introduces UID EXPUNGE command, that, unlike EXPUNGE,
+   takes a UID set parameter, that lists UIDs of all messages that can
+   be expunged.  When processing this command the server erases only
+
+
+
+Melnikov                     Informational                     [Page 15]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+   messages with \Deleted flag listed in the UID list.  Thus, messages
+   not listed in the UID set will not be expunged even if they have the
+   \Deleted flag set.
+
+   Example 6:
+
+   While the user was offline, 3 messages with UIDs 7, 27, and 65 were
+   marked \Deleted when the user requested to compress the open mailbox.
+   Another client marked a message \Deleted on the server (UID 34).
+   During synchronization, the disconnected client issues:
+
+      C: A001 UID EXPUNGE 7,27,65
+      S: * ... EXPUNGE
+      S: * ... EXPUNGE
+      S: * ... EXPUNGE
+      S: A001 UID EXPUNGE completed
+
+   If another client issues UID SEARCH DELETED command (to find all
+   messages with the \Deleted flag) before and after the UID EXPUNGE, it
+   will get:
+
+   Before:
+
+      C: B001 UID SEARCH DELETED
+      S: * SEARCH 65 34 27 7
+      S: B001 UID SEARCH completed
+
+   After:
+
+      C: B002 UID SEARCH DELETED
+      S: * SEARCH 34
+      S: B002 UID SEARCH completed
+
+   In the absence of the [UIDPLUS] extension, the following sequence of
+   commands can be used as an approximation.  Note: It's possible for
+   another client to mark additional messages as deleted while this
+   sequence is being performed.  In this case, these additional messages
+   will be expunged as well.
+
+   1) Find all messages marked \Deleted on the server.
+
+      C: A001 UID SEARCH DELETED
+      S: * SEARCH 65 34 27 7
+      S: A001 UID SEARCH completed
+
+   2) Find all messages that must not be erased (for the previous
+      example the list will consist of the message with UID 34).
+
+
+
+
+Melnikov                     Informational                     [Page 16]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+   3) Temporarily remove \Deleted flag on all messages found in step 2.
+
+      C: A002 UID STORE 34 -FLAGS.SILENT (\Deleted)
+      S: A002 UID STORE completed
+
+   4) Expunge the mailbox.
+
+      C: A003 EXPUNGE
+      S: * 20 EXPUNGE
+      S: * 7 EXPUNGE
+      S: * 1 EXPUNGE
+      S: A003 EXPUNGE completed
+
+      Here, the message with UID 7 has message number 1, with UID 27 has
+      message number 7, and with UID 65 has message number 20.
+
+   5) Restore \Deleted flag on all messages found when performing step
+      2.
+
+      C: A004 UID STORE 34 +FLAGS.SILENT (\Deleted)
+      S: A004 UID STORE completed
+
+4.2.5.  Closing a Mailbox
+
+   When the disconnected client has to close a mailbox, it should not
+   use the CLOSE command, because CLOSE does a silent EXPUNGE.  (Section
+   4.2.4 explains why EXPUNGE should not be used by a disconnected
+   client.)  It is safe to use CLOSE only if the mailbox was opened with
+   EXAMINE.
+
+   If the mailbox was opened with SELECT, the client can use one of the
+   following commands to implicitly close the mailbox and prevent the
+   silent expunge:
+
+   1) UNSELECT - This is a command described in [UNSELECT] that works as
+      CLOSE, but doesn't cause the silent EXPUNGE.  This command is
+      supported by the server if it reports UNSELECT in its CAPABILITY
+      list.
+
+   2) SELECT <another_mailbox> - SELECT causes implicit CLOSE without
+      EXPUNGE.
+
+   3) If the client intends to issue LOGOUT after closing the mailbox,
+      it may just issue LOGOUT, because LOGOUT causes implicit CLOSE
+      without EXPUNGE as well.
+
+   4) SELECT <non_existing_mailbox> - If the client knows a mailbox that
+      doesn't exist or can't be selected, it MAY SELECT it.
+
+
+
+Melnikov                     Informational                     [Page 17]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+   If the client opened the mailbox with SELECT and just wants to avoid
+   implicit EXPUNGE without closing the mailbox, it may also use the
+   following:
+
+   5) EXAMINE <mailbox> - Reselect the same mailbox in read-only mode.
+
+4.3.  Details of "Normal" Synchronization of a Single Mailbox
+
+   The most common form of synchronization is where the human trusts the
+   integrity of the client's copy of the state of a particular mailbox
+   and simply wants to bring the client's cache up to date so that it
+   accurately reflects the mailbox's current state on the server.
+
+4.3.1.  Discovering New Messages and Changes to Old Messages
+
+   Let <lastseenuid> represent the highest UID that the client knows
+   about in this mailbox.  Since UIDs are allocated in strictly
+   ascending order, this is simply the UID of the last message in the
+   mailbox that the client knows about.  Let <lastseenuid+1> represent
+   <lastseenuid>'s UID plus one.  Let <descriptors> represent a list
+   consisting of all the FETCH data item items that the implementation
+   considers part of the descriptor; at a minimum this is just the FLAGS
+   data item, but it usually also includes BODYSTRUCTURE and
+   RFC822.SIZE.  At this step, <descriptors> SHOULD NOT include RFC822.
+
+   With no further information, the client can issue the following two
+   commands:
+
+      tag1 UID FETCH <lastseenuid+1>:* <descriptors>
+      tag2 UID FETCH 1:<lastseenuid> FLAGS
+
+   The first command will request some information about "new" messages
+   (i.e., messages received by the server since the last
+   synchronization).  It will also allow the client to build a message
+   number to UID map (only for new messages).  The second command allows
+   the client to
+
+      1) update cached flags for old messages;
+
+      2) find out which old messages got expunged; and
+
+      3) build a mapping between message numbers and UIDs (for old
+         messages).
+
+   The order here is significant.  We want the server to start returning
+   the list of new message descriptors as fast as it can, so that the
+   client can start issuing more FETCH commands, so we start out by
+   asking for the descriptors of all the messages we know the client
+
+
+
+Melnikov                     Informational                     [Page 18]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+   cannot possibly have cached yet.  The second command fetches the
+   information we need to determine what changes may have occurred to
+   messages that the client already has cached.  Note that the former
+   command should only be issued if the UIDNEXT value cached by the
+   client differs from the one returned by the server.  Once the client
+   has issued these two commands, there's nothing more the client can do
+   with this mailbox until the responses to the first command start
+   arriving.  A clever synchronization program might use this time to
+   fetch its local cache state from disk or to start the process of
+   synchronizing another mailbox.
+
+   The following is an example of the first FETCH:
+
+   C: A011 UID fetch 131:* (FLAGS BODYSTRUCTURE INTERNALDATE
+       RFC822.SIZE)
+
+   Note 1: The first FETCH may result in the server's sending a huge
+   volume of data.  A smart disconnected client should use message
+   ranges (see also Section 3.2.1.2 of [RFC2683]), so that the user is
+   able to execute a different operation between fetching information
+   for a group of new messages.
+
+   Example 7:
+
+   Knowing the new UIDNEXT returned by the server on SELECT or EXAMINE
+   (<uidnext>), the client can split the UID range
+   <lastseenuid+1>:<uidnext> into groups, e.g., 100 messages.  After
+   that, the client can issue:
+
+      C: A011 UID fetch <lastseenuid+1>:<lastseenuid+100>
+          (FLAGS BODYSTRUCTURE INTERNALDATE RFC822.SIZE)
+      ...
+      C: A012 UID fetch <lastseenuid+101>:<lastseenuid+200>
+          (FLAGS BODYSTRUCTURE INTERNALDATE RFC822.SIZE)
+      ...
+      ...
+      C: A0FF UID fetch <lastseenuid+901>:<uidnext>
+          (FLAGS BODYSTRUCTURE INTERNALDATE RFC822.SIZE)
+
+   Note that unless a SEARCH command is issued, it is impossible to
+   determine how many messages will fall into a subrange, as UIDs are
+   not necessarily contiguous.
+
+   Note 2: The client SHOULD ignore any unsolicited EXPUNGE responses
+   received during the first FETCH command.  EXPUNGE responses contain
+   message numbers that are useless to a client that doesn't have the
+   message-number-to-UID translation table.
+
+
+
+
+Melnikov                     Informational                     [Page 19]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+   The second FETCH command will result in zero or more untagged fetch
+   responses.  Each response will have a corresponding UID FETCH data
+   item.  All messages that didn't have a matching untagged FETCH
+   response MUST be removed from the local cache.
+
+   For example, if the <lastseenuid> had a value 15000 and the local
+   cache contained 3 messages with the UIDs 12, 777, and 14999,
+   respectively, then after receiving the following responses from the
+   server, the client must remove the message with UID 14999 from its
+   local cache.
+
+      S: * 1 FETCH (UID 12 FLAGS (\Seen))
+      S: * 2 FETCH (UID 777 FLAGS (\Answered \Deleted))
+
+   Note 3: If the client is not interested in flag changes (i.e., the
+   client only wants to know which old messages are still on the
+   server), the second FETCH command can be substituted with:
+
+      tag2 UID SEARCH UID 1:<lastseenuid>
+
+   This command will generate less traffic.  However, an implementor
+   should be aware that in order to build the mapping table from message
+   numbers to UIDs, the output of the SEARCH command MUST be sorted
+   first, because there is no requirement for a server to return UIDs in
+   SEARCH response in any particular order.
+
+4.3.2.  Searching for "Interesting" Messages.
+
+   This step is performed entirely on the client (from the information
+   received in the step described in 4.3.1), entirely on the server, or
+   on some combination of both.  The decision on what is an
+   "interesting" message is up to the client software and the human.
+   One easy criterion that should probably be implemented in any client
+   is whether the message is "too big" for automatic retrieval, where
+   "too big" is a parameter defined in the client's configuration.
+
+   Another commonly used criterion is the age of a message.  For
+   example, the client may choose to download only messages received in
+   the last week (in this case, <date> would be today's date minus 7
+   days):
+
+      tag3 UID SEARCH UID <uidset> SINCE <date>
+
+   Keep in mind that a date search disregards time and time zone.  The
+   client can avoid doing this search if it specified INTERNALDATE in
+   <descriptors> on the step described in 4.3.1.  If the client did, it
+   can perform the local search on its message cache.
+
+
+
+
+Melnikov                     Informational                     [Page 20]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+   At this step, the client also decides what kind of information about
+   a particular message to fetch from the server.  In particular, even
+   for a message that is considered "too big", the client MAY choose to
+   fetch some part(s) of it.  For example, if the message is a
+   multipart/mixed containing a text part and a MPEG attachment, there
+   is no reason for the client not to fetch the text part.  The decision
+   of which part should or should not be fetched can be based on the
+   information received in the BODYSTRUCTURE FETCH response data item
+   (i.e., if BODYSTRUCTURE was included in <descriptors> on the step
+   described in 4.3.1).
+
+4.3.3.  Populating Cache with "Interesting" Messages.
+
+   Once the client has found out which messages are "interesting", it
+   can start issuing appropriate FETCH commands for "interesting"
+   messages or parts thereof.
+
+   Note that fetching a message into the disconnected client's local
+   cache does NOT imply that the human has (or even will) read the
+   message.  Thus, the synchronization program for a disconnected client
+   should always be careful to use the .PEEK variants of the FETCH data
+   items that implicitly set the \Seen flag.
+
+   Once the last descriptor has arrived and the last FETCH command has
+   been issued, the client simply needs to process the incoming fetch
+   items and use them to update the local message cache.
+
+   In order to avoid deadlock problems, the client must give processing
+   of received messages priority over issuing new FETCH commands during
+   this synchronization process.  This may necessitate temporary local
+   queuing of FETCH requests that cannot be issued without causing a
+   deadlock.  In order to achieve the best use of the "expensive"
+   network connection, the client will almost certainly need to pay
+   careful attention to any flow-control information that it can obtain
+   from the underlying transport connection (usually a TCP connection).
+
+   Note: The requirement stated in the previous paragraph might result
+   in an unpleasant user experience, if followed blindly.  For example,
+   the user might be unwilling to wait for the client to finish
+   synchronization before starting to process the user's requests.  A
+   smart disconnected client should allow the user to perform requested
+   operations in between IMAP commands that are part of the
+   synchronization process.  See also Note 1 in Section 4.3.1.
+
+
+
+
+
+
+
+
+Melnikov                     Informational                     [Page 21]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+   Example 8:
+
+   After fetching a message BODYSTRUCTURE, the client discovers a
+   complex MIME message.  Then, it decides to fetch MIME headers of the
+   nested MIME messages and some body parts.
+
+   C: A011 UID fetch 11 (BODYSTRUCTURE)
+   S: ...
+   C: A012 UID fetch 11 (BODY[HEADER] BODY[1.MIME] BODY[1.1.MIME]
+       BODY[1.2.MIME] BODY[2.MIME] BODY[3.MIME] BODY[4.MIME]
+       BODY[5.MIME] BODY[6.MIME] BODY[7.MIME] BODY[8.MIME] BODY[9.MIME]
+       BODY[10.MIME] BODY[11.MIME] BODY[12.MIME] BODY[13.MIME]
+       BODY[14.MIME] BODY[15.MIME] BODY[16.MIME] BODY[17.MIME]
+       BODY[18.MIME] BODY[19.MIME] BODY[20.MIME] BODY[21.MIME])
+   S: ...
+   C: A013 UID fetch 11 (BODY[1.1] BODY[1.2])
+   S: ...
+   C: A014 UID fetch 11 (BODY[3] BODY[4] BODY[5] BODY[6] BODY[7] BODY[8]
+       BODY[9] BODY[10] BODY[11] BODY[13] BODY[14] BODY[15] BODY[16]
+       BODY[21])
+   S: ...
+
+4.3.4.  User-Initiated Synchronization
+
+   After the client has finished the main synchronization process as
+   described in Sections 4.3.1-4.3.3, the user may optionally request
+   additional synchronization steps while the client is still online.
+   This is not any different from the process described in Sections
+   4.3.2 and 4.3.3.
+
+   Typical examples are:
+
+    1) fetch all messages selected in UI.
+    2) fetch all messages marked as \Flagged on the server.
+
+4.4.  Special Case: Descriptor-Only Synchronization
+
+   For some mailboxes, fetching the descriptors might be the entire
+   synchronization step.  Practical experience with IMAP has shown that
+   a certain class of mailboxes (e.g., "archival" mailboxes) are used
+   primarily for long-term storage of important messages that the human
+   wants to have instantly available on demand but does not want
+   cluttering up the disconnected client's cache at any other time.
+   Messages in this kind of mailbox would be fetched exclusively by
+   explicit actions queued by the local MUA.  Thus, the only
+   synchronization desirable on this kind of mailbox is fetching enough
+   descriptor information for the user to be able to identify messages
+   for subsequent download.
+
+
+
+Melnikov                     Informational                     [Page 22]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+   Special mailboxes that receive messages from a high volume, low
+   priority mailing list might also be in this category, at least when
+   the human is in a hurry.
+
+4.5.  Special Case: Fast New-Only Synchronization
+
+   In some cases, the human might be in such a hurry that he or she
+   doesn't care about changes to old messages, just about new messages.
+   In this case, the client can skip the UID FETCH command that obtains
+   the flags and UIDs for old messages (1:<lastseenuid>).
+
+4.6.  Special Case: Blind FETCH
+
+   In some cases, the human may know (for whatever reason) that he or
+   she always wants to fetch any new messages in a particular mailbox,
+   unconditionally.  In this case, the client can just fetch the
+   messages themselves, rather than just the descriptors, by using a
+   command like:
+
+      tag1 UID FETCH <lastseenuid+1>:* (FLAGS BODY.PEEK[])
+
+   Note that this example ignores the fact that the messages can be
+   arbitrary long.  The disconnected client MUST always check for
+   message size before downloading, unless explicitly told otherwise.  A
+   well-behaved client should instead use something like the following:
+
+   1) Issue "tag1 UID FETCH <lastseenuid+1>:* (FLAGS RFC822.SIZE)".
+
+   2) From the message sizes returned in step 1, construct UID set
+      <required_messages>.
+
+   3) Issue "tag2 UID FETCH <required_messages> (BODY.PEEK[])".
+
+   or
+
+   1) Issue "tag1 UID FETCH <lastseenuid+1>:* (FLAGS)".
+
+   2) Construct UID set <old_uids> from the responses of step 1.
+
+   3) Issue "tag2 SEARCH UID <old_uids> SMALLER <message_limit>".
+      Construct UID set <required_messages> from the result of the
+      SEARCH command.
+
+   4) Issue "tag3 UID FETCH <required_messages> (BODY.PEEK[])".
+
+
+
+
+
+
+
+Melnikov                     Informational                     [Page 23]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+   or
+
+   1) Issue "tag1 UID FETCH <lastseenuid+1>:* (FLAGS
+      BODY.PEEK[]<0.<length>>)", where <length> should be replaced with
+      the maximal message size the client is willing to download.
+
+      Note: In response to such a command, the server will only return
+      partial data if the message is longer than <length>.  It will
+      return the full message data for any message whose size is smaller
+      than or equal to <length>.  In the former case, the client will
+      not be able to extract the full MIME structure of the message from
+      the truncated data, so the client should include BODYSTRUCTURE in
+      the UID FETCH command as well.
+
+5.  Implementation Considerations
+
+   Below are listed some common implementation pitfalls that should be
+   considered when implementing a disconnected client.
+
+   1) Implementing fake UIDs on the client.
+
+      A message scheduled to be uploaded has no UID, as UIDs are
+      selected by the server.  The client may implement fake UIDs
+      internally in order to reference not-yet-uploaded messages in
+      further operations.  (For example, a message could be scheduled to
+      be uploaded, but subsequently marked as deleted or copied to
+      another mailbox).  Here, the client MUST NOT under any
+      circumstances send these fake UIDs to the server.  Also, client
+      implementers should be reminded that according to [IMAP4] a UID is
+      a 32-bit unsigned integer excluding 0.  So, both 4294967295 and
+      2147483648 are valid UIDs, and 0 and -1 are both invalid.  Some
+      disconnected mail clients have been known to send negative numbers
+      (e.g., "-1") as message UIDs to servers during synchronization.
+
+      Situation 1: The user starts composing a new message, edits it,
+      saves it, continues to edit it, and saves it again.
+
+      A disconnected client may record in its replay log (log of
+      operations to be replayed on the server during synchronization)
+      the sequence of operations as shown below.  For the purpose of
+      this situation, we assume that all draft messages are stored in
+      the mailbox called Drafts on an IMAP server.  We will also use the
+      following conventions:  <old_uid> is the UID of the intermediate
+      version of the draft when it was saved for the first time.  This
+      is a fake UID generated on the client.  <new_uid> is the UID of
+      the final version of the draft.  This is another fake UID
+      generated on the client.
+
+
+
+
+Melnikov                     Informational                     [Page 24]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+      1) APPEND Drafts (\Seen $MDNSent \Drafts) {<nnn>}
+         ...first version of the message follows...
+
+      2) APPEND Drafts (\Seen $MDNSent \Drafts) {<mmm>}
+         ...final version of the message follows...
+
+      3) STORE <old_uid> +FLAGS (\Deleted)
+
+      Step 1 corresponds to the first attempt to save the draft message,
+      step 2 corresponds to the second attempt to save the draft
+      message, and step 3 deletes the first version of the draft message
+      saved in step 1.
+
+      A naive disconnected client may send the command in step 3 without
+      replacing the fake client generated <old_uid> with the value
+      returned by the server in step 1.  A server will probably reject
+      this command, which will make the client believe that the
+      synchronization sequence has failed.
+
+   2) Section 5.1 discusses common implementation errors related to
+      error recovery during playback.
+
+   3) Don't assume that the disconnected client is the only client used
+      by the user.
+
+      Situation 2: Some clients may use the \Deleted flag as an
+      indicator that the message should not appear in the user's view.
+      Usage of the \Deleted flag for this purpose is not safe, as other
+      clients (e.g., online clients) might EXPUNGE the mailbox at any
+      time.
+
+   4) Beware of data dependencies between synchronization operations.
+
+      It might be very tempting for a client writer to perform some
+      optimizations on the playback log.  Such optimizations might
+      include removing redundant operations (for example, see
+      optimization 2 in Section 5.3), or their reordering.
+
+      It is not always safe to reorder or remove redundant operations
+      during synchronization because some operations may have
+      dependencies (as Situation 3 demonstrates).  So, if in doubt,
+      don't do this.
+
+      Situation 3: The user copies a message out of a mailbox and then
+      deletes the mailbox.
+
+
+
+
+
+
+Melnikov                     Informational                     [Page 25]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+         C: A001 SELECT Old-Mail
+         S: ...
+         C: A002 UID COPY 111 ToDo
+         S: A002 OK [COPYUID 1022843345 111 94] Copy completed
+         ...
+         C: A015 CLOSE
+         S: A015 OK Completed
+         C: A016 DELETE Old-Mail
+         S: A016 OK Mailbox deletion completed successfully
+
+      If the client performs DELETE (tag A016) first and COPY (tag A002)
+      second, then the COPY fails.  Also, the message that the user so
+      carefully copied into another mailbox has been lost.
+
+5.1.  Error Recovery during Playback
+
+   Error recovery during synchronization is one of the trickiest parts
+   to get right.  Below, we will discuss certain error conditions and
+   suggest possible choices for handling them.
+
+   1) Lost connection to the server.
+
+      The client MUST remember the current position in the playback
+      (replay) log and replay it starting from the interrupted operation
+      (the last command issued by the client, but not acknowledged by
+      the server) the next time it successfully connects to the same
+      server.  If the connection was lost while executing a non-
+      idempotent IMAP command (see the definition in Section 1), then
+      when the client is reconnected, it MUST make sure that the
+      interrupted command was indeed not executed.  If it wasn't
+      executed, the client must restart playback from the interrupted
+      command, otherwise from the following command.
+
+      Upon reconnect, care must be taken in order to properly reapply
+      logical operations that are represented by multiple IMAP commands,
+      e.g., UID EXPUNGE emulation when UID EXPUNGE is not supported by
+      the server (see Section 4.2.4).
+
+      Once the client detects that the connection to the server was
+      lost, it MUST stop replaying its log.  There are existing
+      disconnected clients that, to the great annoyance of users, pop up
+      an error dialog for each and every playback operation that fails.
+
+   2) Copying/appending messages to a mailbox that doesn't exist.  (The
+      server advertises this condition by sending the TRYCREATE response
+      code in the tagged NO response to the APPEND or COPY command.)
+
+
+
+
+
+Melnikov                     Informational                     [Page 26]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+      The user should be advised about the situation and be given one of
+      the following choices:
+
+      a) Try to recreate a mailbox.
+      b) Copy/upload messages to another mailbox.
+      c) Skip copy/upload.
+      d) Abort replay.
+
+   3) Copying messages from a mailbox that doesn't exist, or renaming or
+      getting/changing ACLs [ACL] on a mailbox that doesn't exist:
+
+      a) Skip operation.
+      b) Abort replay.
+
+   4) Deleting mailboxes or deleting/expunging messages that no longer
+      exist.
+
+      This is actually is not an error and should be ignored by the
+      client.
+
+   5) Performing operations on messages that no longer exist.
+
+      a) Skip operation.
+      b) Abort replay.
+
+      In the case of changing flags on an expunged message, the client
+      should silently ignore the error.
+
+   Note 1: Several synchronization operations map to multiple IMAP
+   commands (for example, "move" described in 4.2.2).  The client must
+   guarantee atomicity of each such multistep operation.  For example,
+   when performing a "move" between two mailboxes on the same server, if
+   the server is unable to copy messages, the client MUST NOT attempt to
+   set the \Deleted flag on the messages being copied, let alone expunge
+   them.  However, the client MAY consider that move operation to have
+   succeeded even if the server was unable to set the \Deleted flag on
+   copied messages.
+
+   Note 2: Many synchronization operations have data dependencies.  A
+   failed operation must cause all dependent operations to fail as well.
+   The client should check this and MUST NOT try to perform all
+   dependent operations blindly (unless the user corrected the original
+   problem).  For example, a message may be scheduled to be appended to
+   a mailbox on the server and later on the appended message may be
+   copied to another mailbox.  If the APPEND operation fails, the client
+   must not attempt to COPY the failed message later on.  (See also
+   Section 5, Situation 3).
+
+
+
+
+Melnikov                     Informational                     [Page 27]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+5.2.  Quality of Implementation Issues
+
+   Below, some quality of implementation issues are listed for
+   disconnected clients.  They will help to write a disconnected client
+   that works correctly, performs synchronization as quickly as possible
+   (and thus can make the user happier as well as save her some money),
+   and minimizes the server load:
+
+   1) Don't lose information.
+
+      No matter how smart your client is in other areas, if it loses
+      information, users will get very upset.
+
+   2) Don't do work unless explicitly asked.  Be flexible.  Ask all
+      questions BEFORE starting synchronization, if possible.
+
+   3) Minimize traffic.
+
+      The client MUST NOT issue a command if the client already received
+      the required information from the server.
+
+      The client MUST make use of UIDPLUS extension if it is supported
+      by the server.
+
+      See also optimization 1 in Section 5.3.
+
+   4) Minimize the number of round-trips.
+
+      Round-trips kill performance, especially on links with high
+      latency.  Sections 4.2.2.5 and 5.2 give some advice on how to
+      minimize the number of round-trips.
+
+      See also optimization 1 in Section 5.3.
+
+5.3.  Optimizations
+
+   Some useful optimizations are described in this section.  A
+   disconnected client that supports the recommendations listed below
+   will give the user a more pleasant experience.
+
+   1) The initial OK or PREAUTH responses may contain the CAPABILITY
+      response code as described in Section 7.1 of [IMAP4].  This
+      response code gives the same information as returned by the
+      CAPABILITY command*.  A disconnected client that pays attention to
+      this response code can avoid sending CAPABILITY command and will
+      save a round-trip.
+
+
+
+
+
+Melnikov                     Informational                     [Page 28]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+      * Note: Some servers report in the CAPABILITY response code
+        extensions that are only relevant in unauthenticated state or in
+        all states.  Such servers usually send another CAPABILITY
+        response code upon successful authentication using LOGIN or
+        AUTHENTICATE command (that negotiates no security layer; see
+        Section 6.2.2 of [IMAP4]).  The CAPABILITY response code sent
+        upon successful LOGIN/AUTHENTICATE might be different from the
+        CAPABILITY response code in the initial OK response, as
+        extensions only relevant for unauthenticated state will not be
+        advertised, and some additional extensions available only in
+        authenticated and/or selected state will be.
+
+   Example 9:
+
+   S: * OK [CAPABILITY IMAP4REV1 LOGIN-REFERRALS STARTTLS
+       AUTH=DIGEST-MD5 AUTH=SRP] imap.example.com ready
+   C: 2 authenticate DIGEST-MD5
+   S: 2 OK [CAPABILITY IMAP4REV1 IDLE NAMESPACE MAILBOX-REFERRALS SCAN
+       SORT THREAD=REFERENCES THREAD=ORDEREDSUBJECT MULTIAPPEND]
+       User authenticated (no layer)
+
+   2) An advanced disconnected client may choose to optimize its replay
+      log.  For example, there might be some operations that are
+      redundant (the list is not complete):
+
+      a) an EXPUNGE followed by another EXPUNGE or CLOSE;
+      b) changing flags (other than the \Deleted flag) on a message that
+         gets immediately expunged;
+      c) opening and closing the same mailbox.
+
+   When optimizing, be careful about data dependencies between commands.
+   For example, if the client is wishing to optimize (see case b, above)
+
+      tag1 UID STORE <uid1> +FLAGS (\Deleted)
+      ...
+      tag2 UID STORE <uid1> +FLAGS (\Flagged)
+      ...
+      tag3 UID COPY <uid1> "Backup"
+      ...
+      tag4 UID EXPUNGE <uid1>
+
+   it can't remove the second UID STORE command because the message is
+   being copied before it gets expunged.
+
+   In general, it might be a good idea to keep mailboxes open during
+   synchronization (see case c above), if possible.  This can be more
+   easily achieved in conjunction with optimization 3 described below.
+
+
+
+
+Melnikov                     Informational                     [Page 29]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+   3) Perform some synchronization steps in parallel, if possible.
+
+      Several synchronization steps don't depend on each other and thus
+      can be performed in parallel.  Because the server machine is
+      usually more powerful than the client machine and can perform some
+      operations in parallel, this may speed up the total time of
+      synchronization.
+
+      In order to achieve such parallelization, the client will have to
+      open more than one connection to the same server.  Client writers
+      should not forget about non-trivial cost associated with
+      establishing a TCP connection and performing an authentication.
+      The disconnected client MUST NOT use one connection per mailbox.
+      In most cases, it is sufficient to have two connections.  The
+      disconnected client SHOULD avoid selecting the same mailbox in
+      more than one connection; see Section 3.1.1 of [RFC2683] for more
+      details.
+
+      Any mailbox synchronization MUST start with checking the
+      UIDVALIDITY as described in Section 4.1 of this document.  The
+      client MAY use STATUS command to check UID Validity of a non-
+      selected mailbox.  This is preferable to opening many connections
+      to the same server to perform synchronization of multiple
+      mailboxes simultaneously.  As described in Section 5.3.10 of
+      [IMAP4], this SHOULD NOT be used on the selected mailbox.
+
+6.  IMAP Extensions That May Help
+
+   The following extensions can save traffic and/or the number of
+   round-trips:
+
+   1) The use of [UIDPLUS] is discussed in Sections 4.1, 4.2.1, 4.2.2.1
+      and 4.2.4.
+
+   2) The use of the MULTIAPPEND and LITERAL+ extensions for uploading
+      messages is discussed in Section 4.2.2.5.
+
+   3) Use the CONDSTORE extension (see Section 6.1) for quick flag
+      resynchronization.
+
+6.1.  CONDSTORE Extension
+
+   An advanced disconnected mail client should use the [CONDSTORE]
+   extension when it is supported by the server.  The client must cache
+   the value from HIGHESTMODSEQ OK response code received on mailbox
+   opening and update it whenever the server sends MODSEQ FETCH data
+   items.
+
+
+
+
+Melnikov                     Informational                     [Page 30]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+   If the client receives NOMODSEQ OK untagged response instead of
+   HIGHESTMODSEQ, it MUST remove the last known HIGHESTMODSEQ value from
+   its cache and follow the more general instructions in Section 3.
+
+   When the client opens the mailbox for synchronization, it first
+   compares UIDVALIDITY as described in step d-1 in Section 3.  If the
+   cached UIDVALIDITY value matches the one returned by the server, the
+   client MUST compare the cached value of HIGHESTMODSEQ with the one
+   returned by the server.  If the cached HIGHESTMODSEQ value also
+   matches the one returned by the server, then the client MUST NOT
+   fetch flags for cached messages, as they hasn't changed.  If the
+   value on the server is higher than the cached one, the client MAY use
+   "SEARCH MODSEQ <cached-value>" to find all messages with flags
+   changed since the last time the client was online and had the mailbox
+   opened.  Alternatively, the client MAY use "FETCH 1:* (FLAGS)
+   (CHANGEDSINCE <cached-value>)".  The latter operation combines
+   searching for changed messages and fetching new information.
+
+   In all cases, the client still needs to fetch information about new
+   messages (if requested by the user) as well as discover which
+   messages have been expunged.
+
+   Step d ("Server-to-client synchronization") in Section 4 in the
+   presence of the CONDSTORE extension is amended as follows:
+
+   d) "Server-to-client synchronization" - For each mailbox that
+      requires synchronization, do the following:
+
+      1a) Check the mailbox UIDVALIDITY (see section 4.1 for more
+          details) with SELECT/EXAMINE/STATUS.
+
+          If the UIDVALIDITY value returned by the server differs, the
+          client MUST
+
+          * empty the local cache of that mailbox;
+          * "forget" the cached HIGHESTMODSEQ value for the mailbox;
+          * remove any pending "actions" that refer to UIDs in that
+            mailbox (note that this doesn't affect actions performed on
+            client-generated fake UIDs; see Section 5); and
+          * skip steps 1b and 2-II;
+
+      1b) Check the mailbox HIGHESTMODSEQ.  If the cached value is the
+          same as the one returned by the server, skip fetching message
+          flags on step 2-II, i.e., the client only has to find out
+          which messages got expunged.
+
+
+
+
+
+
+Melnikov                     Informational                     [Page 31]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+      2) Fetch the current "descriptors".
+
+         I)  Discover new messages.
+
+         II) Discover changes to old messages and flags for new messages
+             using
+             "FETCH 1:* (FLAGS) (CHANGEDSINCE <cached-value>)" or
+             "SEARCH MODSEQ <cached-value>".
+
+             Discover expunged messages; for example, using
+             "UID SEARCH 1:<lastseenuid>".  (All messages not returned
+             in this command are expunged.)
+
+      3) Fetch the bodies of any "interesting" messages that the client
+         doesn't already have.
+
+         Example 10:
+
+         The UIDVALIDITY value is the same, but the HIGHESTMODSEQ value
+         has changed on the server while the client was offline.
+
+      C: A142 SELECT INBOX
+      S: * 172 EXISTS
+      S: * 1 RECENT
+      S: * OK [UNSEEN 12] Message 12 is first unseen
+      S: * OK [UIDVALIDITY 3857529045] UIDs valid
+      S: * OK [UIDNEXT 201] Predicted next UID
+      S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
+      S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
+      S: * OK [HIGHESTMODSEQ 20010715194045007]
+      S: A142 OK [READ-WRITE] SELECT completed
+
+   After that, either:
+
+      C: A143 UID FETCH 1:* (FLAGS) (CHANGEDSINCE 20010715194032001)
+      S: * 2 FETCH (UID 6 MODSEQ (20010715205008000) FLAGS (\Deleted))
+      S: * 5 FETCH (UID 9 MODSEQ (20010715195517000) FLAGS ($NoJunk
+          $AutoJunk $MDNSent))
+         ...
+      S: A143 OK FETCH completed
+
+   or:
+
+
+
+
+
+
+
+
+
+Melnikov                     Informational                     [Page 32]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+      C: A143 UID SEARCH MODSEQ 20010715194032001 UID 1:20
+      S: * SEARCH 6 9 11 12 18 19 20 23 (MODSEQ 20010917162500)
+      S: A143 OK Search complete
+      C: A144 UID SEARCH 1:20
+      S: * SEARCH 6 9 ...
+      S: A144 OK FETCH completed
+
+7.  Security Considerations
+
+   It is believed that this document does not raise any new security
+   concerns that are not already present in the base [IMAP4] protocol,
+   and these issues are discussed in [IMAP4].  Additional security
+   considerations may be found in different extensions mentioned in this
+   document; in particular, in [UIDPLUS], [LITERAL+], [CONDSTORE],
+   [MULTIAPPEND], and [UNSELECT].
+
+   Implementers are also reminded about the importance of thorough
+   testing.
+
+8.  References
+
+8.1.  Normative References
+
+   [KEYWORDS]    Bradner, S., "Key words for use in RFCs to Indicate
+                 Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+   [IMAP4]       Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL -
+                 VERSION 4rev1", RFC 3501, March 2003.
+
+   [UIDPLUS]     Crispin, M., "Internet Message Access Protocol (IMAP) -
+                 UIDPLUS extension", RFC 4315, December 2005.
+
+   [LITERAL+]    Myers, J., "IMAP4 non-synchronizing literals", RFC
+                 2088, January 1997.
+
+   [CONDSTORE]   Melnikov, A. and S. Hole, "IMAP Extension for
+                 Conditional STORE Operation or Quick Flag Changes
+                 Resynchronization", RFC 4551, June 2006.
+
+   [MULTIAPPEND] Crispin, M., "Internet Message Access Protocol (IMAP) -
+                 MULTIAPPEND Extension", RFC 3502, March 2003.
+
+   [UNSELECT]    Melnikov, A., "Internet Message Access Protocol (IMAP)
+                 UNSELECT command", RFC 3691, February 2004.
+
+   [RFC2683]     Leiba, B., "IMAP4 Implementation Recommendations", RFC
+                 2683, September 1999.
+
+
+
+
+Melnikov                     Informational                     [Page 33]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+8.2.  Informative References
+
+   [ACL]         Melnikov, A., "IMAP4 Access Control List (ACL)
+                 Extension", RFC 4314, December 2005.
+
+   [IMAP-MODEL]  Crispin, M., "Distributed Electronic Mail Models in
+                 IMAP4", RFC 1733, December 1994.
+
+9.  Acknowledgements
+
+   This document is based on version 01 of the text written by Rob
+   Austein in November 1994.
+
+   The editor appreciates comments posted by Mark Crispin to the IMAP
+   mailing list and the comments/corrections/ideas received from Grant
+   Baillie, Cyrus Daboo, John G. Myers, Chris Newman, and Timo Sirainen.
+
+   The editor would also like to thank the developers of Netscape
+   Messenger and Mozilla mail clients for providing examples of
+   disconnected mail clients that served as a base for many
+   recommendations in this document.
+
+Editor's Address
+
+   Alexey Melnikov
+   Isode Limited
+   5 Castle Business Village
+   36 Station Road
+   Hampton, Middlesex
+   TW12 2BX
+   United Kingdom
+
+   Phone: +44 77 53759732
+   EMail: alexey.melnikov@isode.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov                     Informational                     [Page 34]
+
+RFC 4549        Synch Ops for Disconnected IMAP4 Clients       June 2006
+
+
+Full Copyright Statement
+
+   Copyright (C) The Internet Society (2006).
+
+   This document is subject to the rights, licenses and restrictions
+   contained in BCP 78, and except as set forth therein, the authors
+   retain all their rights.
+
+   This document and the information contained herein are provided on an
+   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   Intellectual Property Rights or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; nor does it represent that it has
+   made any independent effort to identify any such rights.  Information
+   on the procedures with respect to rights in RFC documents can be
+   found in BCP 78 and BCP 79.
+
+   Copies of IPR disclosures made to the IETF Secretariat and any
+   assurances of licenses to be made available, or the result of an
+   attempt made to obtain a general license or permission for the use of
+   such proprietary rights by implementers or users of this
+   specification can be obtained from the IETF on-line IPR repository at
+   http://www.ietf.org/ipr.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights that may cover technology that may be required to implement
+   this standard.  Please address the information to the IETF at
+   ietf-ipr@ietf.org.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is provided by the IETF
+   Administrative Support Activity (IASA).
+
+
+
+
+
+
+
+Melnikov                     Informational                     [Page 35]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc4551.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1403 @@
+
+
+
+
+
+
+Network Working Group                                        A. Melnikov
+Request for Comments: 4551                                    Isode Ltd.
+Updates: 3501                                                    S. Hole
+Category: Standards Track                  ACI WorldWide/MessagingDirect
+                                                               June 2006
+
+
+             IMAP Extension for Conditional STORE Operation
+                or Quick Flag Changes Resynchronization
+
+Status of This Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (2006).
+
+Abstract
+
+   Often, multiple IMAP (RFC 3501) clients need to coordinate changes to
+   a common IMAP mailbox.  Examples include different clients working on
+   behalf of the same user, and multiple users accessing shared
+   mailboxes.  These clients need a mechanism to synchronize state
+   changes for messages within the mailbox.  They must be able to
+   guarantee that only one client can change message state (e.g.,
+   message flags) at any time.  An example of such an application is use
+   of an IMAP mailbox as a message queue with multiple dequeueing
+   clients.
+
+   The Conditional Store facility provides a protected update mechanism
+   for message state information that can detect and resolve conflicts
+   between multiple writing mail clients.
+
+   The Conditional Store facility also allows a client to quickly
+   resynchronize mailbox flag changes.
+
+   This document defines an extension to IMAP (RFC 3501).
+
+
+
+
+
+
+
+
+
+Melnikov & Hole             Standards Track                     [Page 1]
+
+RFC 4551          IMAP Extension for Conditional STORE         June 2006
+
+
+Table of Contents
+
+   1.  Introduction and Overview ................................. 3
+   2.  Conventions Used in This Document ......................... 5
+   3.  IMAP Protocol Changes ..................................... 6
+   3.1. New OK untagged responses for SELECT and EXAMINE ......... 6
+   3.1.1. HIGHESTMODSEQ response code ............................ 6
+   3.1.2. NOMODSEQ response code ................................. 7
+   3.2. STORE and UID STORE Commands ............................. 7
+   3.3 FETCH and UID FETCH Commands ..............................13
+   3.3.1. CHANGEDSINCE FETCH modifier ............................13
+   3.3.2. MODSEQ message data item in FETCH Command ..............14
+   3.4. MODSEQ search criterion in SEARCH ........................16
+   3.5. Modified SEARCH untagged response ........................17
+   3.6. HIGHESTMODSEQ status data items ..........................17
+   3.7. CONDSTORE parameter to SELECT and EXAMINE ................18
+   3.8. Additional quality of implementation issues ..............18
+   4.  Formal Syntax .............................................19
+   5.  Server implementation considerations ......................21
+   6.  Security Considerations ...................................22
+   7.  IANA Considerations .......................................22
+   8.  References ................................................23
+   8.1. Normative References .....................................23
+   8.2. Informative References ...................................23
+   9.  Acknowledgements ..........................................23
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov & Hole             Standards Track                     [Page 2]
+
+RFC 4551          IMAP Extension for Conditional STORE         June 2006
+
+
+1. Introduction and Overview
+
+   The Conditional STORE extension is present in any IMAP4
+   implementation that returns "CONDSTORE" as one of the supported
+   capabilities in the CAPABILITY command response.
+
+   An IMAP server that supports this extension MUST associate a positive
+   unsigned 64-bit value called a modification sequence (mod-sequence)
+   with every IMAP message.  This is an opaque value updated by the
+   server whenever a metadata item is modified.  The server MUST
+   guarantee that each STORE command performed on the same mailbox
+   (including simultaneous stores to different metadata items from
+   different connections) will get a different mod-sequence value.
+   Also, for any two successful STORE operations performed in the same
+   session on the same mailbox, the mod-sequence of the second completed
+   operation MUST be greater than the mod-sequence of the first
+   completed.  Note that the latter rule disallows the use of the system
+   clock as a mod-sequence, because if system time changes (e.g., an NTP
+   [NTP] client adjusting the time), the next generated value might be
+   less than the previous one.
+
+   Mod-sequences allow a client that supports the CONDSTORE extension to
+   determine if a message metadata has changed since some known moment.
+   Whenever the state of a flag changes (i.e., the flag is added where
+   previously it wasn't set, or the flag is removed and before it was
+   set) the value of the modification sequence for the message MUST be
+   updated.  Adding the flag when it is already present or removing when
+   it is not present SHOULD NOT change the mod-sequence.
+
+   When a message is appended to a mailbox (via the IMAP APPEND command,
+   COPY to the mailbox, or using an external mechanism) the server
+   generates a new modification sequence that is higher than the highest
+   modification sequence of all messages in the mailbox and assigns it
+   to the appended message.
+
+   The server MAY store separate (per-message) modification sequence
+   values for different metadata items.  If the server does so, per-
+   message mod-sequence is the highest mod-sequence of all metadata
+   items for the specified message.
+
+   The server that supports this extension is not required to be able to
+   store mod-sequences for every available mailbox.  Section 3.1.2
+   describes how the server may act if a particular mailbox doesn't
+   support the persistent storage of mod-sequences.
+
+
+
+
+
+
+
+Melnikov & Hole             Standards Track                     [Page 3]
+
+RFC 4551          IMAP Extension for Conditional STORE         June 2006
+
+
+   This extension makes the following changes to the IMAP4 protocol:
+
+      a) adds UNCHANGEDSINCE STORE modifier.
+
+      b) adds the MODIFIED response code which should be used with an OK
+         response to the STORE command.  (It can also be used in a NO
+         response.)
+
+      c) adds a new MODSEQ message data item for use with the FETCH
+         command.
+
+      d) adds CHANGEDSINCE FETCH modifier.
+
+      e) adds a new MODSEQ search criterion.
+
+      f) extends the syntax of untagged SEARCH responses to include
+         mod-sequence.
+
+      g) adds new OK untagged responses for the SELECT and EXAMINE
+         commands.
+
+      h) defines an additional parameter to SELECT/EXAMINE commands.
+
+      i) adds the HIGHESTMODSEQ status data item to the STATUS command.
+
+   A client supporting CONDSTORE extension indicates its willingness to
+   receive mod-sequence updates in all untagged FETCH responses by
+   issuing:
+
+      -  a SELECT or EXAMINE command with the CONDSTORE parameter,
+      -  a STATUS (HIGHESTMODSEQ) command,
+      -  a FETCH or SEARCH command that includes the MODSEQ message data
+         item,
+      -  a FETCH command with the CHANGEDSINCE modifier, or
+      -  a STORE command with the UNCHANGEDSINCE modifier.
+
+   The server MUST include mod-sequence data in all subsequent untagged
+   FETCH responses (until the connection is closed), whether they were
+   caused by a regular STORE, a STORE with UNCHANGEDSINCE modifier, or
+   an external agent.
+
+   This document uses the term "CONDSTORE-aware client" to refer to a
+   client that announces its willingness to receive mod-sequence updates
+   as described above.  The term "CONDSTORE enabling command" will refer
+   any of the commands listed above.  A future extension to this
+   document may extend the list of CONDSTORE enabling commands.  A first
+   CONDSTORE enabling command executed in the session MUST cause the
+
+
+
+
+Melnikov & Hole             Standards Track                     [Page 4]
+
+RFC 4551          IMAP Extension for Conditional STORE         June 2006
+
+
+   server to return HIGHESTMODSEQ (Section 3.1.1) unless the server has
+   sent NOMODSEQ (Section 3.1.2) response code when the currently
+   selected mailbox was selected.
+
+   The rest of this document describes the protocol changes more
+   rigorously.
+
+2.  Conventions Used in This Document
+
+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+   document are to be interpreted as described in RFC 2119 [KEYWORDS].
+
+   In examples, lines beginning with "S:" are sent by the IMAP server,
+   and lines beginning with "C:" are sent by the client.  Line breaks
+   may appear in example commands solely for editorial clarity; when
+   present in the actual message, they are represented by "CRLF".
+
+   Formal syntax is defined using ABNF [ABNF].
+
+   The term "metadata" or "metadata item" is used throughout this
+   document.  It refers to any system or user-defined keyword.  Future
+   documents may extend "metadata" to include other dynamic message
+   data.
+
+   Some IMAP mailboxes are private, accessible only to the owning user.
+   Other mailboxes are not, either because the owner has set an Access
+   Control List [ACL] that permits access by other users, or because it
+   is a shared mailbox.  Let's call a metadata item "shared" for the
+   mailbox if any changes to the metadata items are persistent and
+   visible to all other users accessing the mailbox.  Otherwise, the
+   metadata item is called "private".  Note that private metadata items
+   are still visible to all sessions accessing the mailbox as the same
+   user.  Also note that different mailboxes may have different metadata
+   items as shared.
+
+   See Section 1 for the definition of a "CONDSTORE-aware client" and a
+   "CONDSTORE enabling command".
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov & Hole             Standards Track                     [Page 5]
+
+RFC 4551          IMAP Extension for Conditional STORE         June 2006
+
+
+3.  IMAP Protocol Changes
+
+3.1.  New OK Untagged Responses for SELECT and EXAMINE
+
+   This document adds two new response codes, HIGHESTMODSEQ and
+   NOMODSEQ.  One of those response codes MUST be returned in the OK
+   untagged response for a successful SELECT/EXAMINE command.
+
+   When opening a mailbox, the server must check if the mailbox supports
+   the persistent storage of mod-sequences.  If the mailbox supports the
+   persistent storage of mod-sequences and the mailbox open operation
+   succeeds, the server MUST send the OK untagged response including
+   HIGHESTMODSEQ response code.  If the persistent storage for the
+   mailbox is not supported, the server MUST send the OK untagged
+   response including NOMODSEQ response code instead.
+
+3.1.1.  HIGHESTMODSEQ Response Code
+
+   This document adds a new response code that is returned in the OK
+   untagged response for the SELECT and EXAMINE commands.  A server
+   supporting the persistent storage of mod-sequences for the mailbox
+   MUST send the OK untagged response including HIGHESTMODSEQ response
+   code with every successful SELECT or EXAMINE command:
+
+      OK [HIGHESTMODSEQ <mod-sequence-value>]
+
+      where <mod-sequence-value> is the highest mod-sequence value of
+      all messages in the mailbox.  When the server changes UIDVALIDITY
+      for a mailbox, it doesn't have to keep the same HIGHESTMODSEQ for
+      the mailbox.
+
+   A disconnected client can use the value of HIGHESTMODSEQ to check if
+   it has to refetch metadata from the server.  If the UIDVALIDITY value
+   has changed for the selected mailbox, the client MUST delete the
+   cached value of HIGHESTMODSEQ.  If UIDVALIDITY for the mailbox is the
+   same, and if the HIGHESTMODSEQ value stored in the client's cache is
+   less than the value returned by the server, then some metadata items
+   on the server have changed since the last synchronization, and the
+   client needs to update its cache.  The client MAY use SEARCH MODSEQ
+   (Section 3.4) to find out exactly which metadata items have changed.
+   Alternatively, the client MAY issue FETCH with the CHANGEDSINCE
+   modifier (Section 3.3.1) in order to fetch data for all messages that
+   have metadata items changed since some known modification sequence.
+
+   Example 1:
+
+      C: A142 SELECT INBOX
+      S: * 172 EXISTS
+
+
+
+Melnikov & Hole             Standards Track                     [Page 6]
+
+RFC 4551          IMAP Extension for Conditional STORE         June 2006
+
+
+      S: * 1 RECENT
+      S: * OK [UNSEEN 12] Message 12 is first unseen
+      S: * OK [UIDVALIDITY 3857529045] UIDs valid
+      S: * OK [UIDNEXT 4392] Predicted next UID
+      S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
+      S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
+      S: * OK [HIGHESTMODSEQ 715194045007]
+      S: A142 OK [READ-WRITE] SELECT completed
+
+3.1.2.  NOMODSEQ Response Code
+
+   A server that doesn't support the persistent storage of mod-sequences
+   for the mailbox MUST send the OK untagged response including NOMODSEQ
+   response code with every successful SELECT or EXAMINE command.  A
+   server that returned NOMODSEQ response code for a mailbox, which
+   subsequently receives one of the following commands while the mailbox
+   is selected:
+
+      -  a FETCH command with the CHANGEDSINCE modifier,
+      -  a FETCH or SEARCH command that includes the MODSEQ message data
+         item, or
+      -  a STORE command with the UNCHANGEDSINCE modifier
+
+   MUST reject any such command with the tagged BAD response.
+
+   Example 2:
+
+      C: A142 SELECT INBOX
+      S: * 172 EXISTS
+      S: * 1 RECENT
+      S: * OK [UNSEEN 12] Message 12 is first unseen
+      S: * OK [UIDVALIDITY 3857529045] UIDs valid
+      S: * OK [UIDNEXT 4392] Predicted next UID
+      S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
+      S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
+      S: * OK [NOMODSEQ] Sorry, this mailbox format doesn't support
+           modsequences
+      S: A142 OK [READ-WRITE] SELECT completed
+
+3.2.  STORE and UID STORE Commands
+
+   This document defines the following STORE modifier (see Section 2.5
+   of [IMAPABNF]):
+
+   UNCHANGEDSINCE <mod-sequence>
+
+      For each message specified in the message set, the server performs
+      the following.  If the mod-sequence of any metadata item of the
+
+
+
+Melnikov & Hole             Standards Track                     [Page 7]
+
+RFC 4551          IMAP Extension for Conditional STORE         June 2006
+
+
+      message is equal or less than the specified UNCHANGEDSINCE value,
+      then the requested operation (as described by the message data
+      item) is performed.  If the operation is successful, the server
+      MUST update the mod-sequence attribute of the message.  An
+      untagged FETCH response MUST be sent, even if the .SILENT suffix
+      is specified, and the response MUST include the MODSEQ message
+      data item.  This is required to update the client's cache with the
+      correct mod-sequence values.  See Section 3.3.2 for more details.
+
+      However, if the mod-sequence of any metadata item of the message
+      is greater than the specified UNCHANGEDSINCE value, then the
+      requested operation MUST NOT be performed.  In this case, the
+      mod-sequence attribute of the message is not updated, and the
+      message number (or unique identifier in the case of the UID STORE
+      command) is added to the list of messages that failed the
+      UNCHANGESINCE test.
+
+      When the server finished performing the operation on all the
+      messages in the message set, it checks for a non-empty list of
+      messages that failed the UNCHANGESINCE test.  If this list is
+      non-empty, the server MUST return in the tagged response a
+      MODIFIED response code.  The MODIFIED response code includes the
+      message set (for STORE) or set of UIDs (for UID STORE) of all
+      messages that failed the UNCHANGESINCE test.
+
+   Example 3:
+
+      All messages pass the UNCHANGESINCE test.
+
+      C: a103 UID STORE 6,4,8 (UNCHANGEDSINCE 12121230045)
+          +FLAGS.SILENT (\Deleted)
+      S: * 1 FETCH (UID 4 MODSEQ (12121231000))
+      S: * 2 FETCH (UID 6 MODSEQ (12121230852))
+      S: * 4 FETCH (UID 8 MODSEQ (12121130956))
+      S: a103 OK Conditional Store completed
+
+   Example 4:
+
+      C: a104 STORE * (UNCHANGEDSINCE 12121230045) +FLAGS.SILENT
+         (\Deleted $Processed)
+      S: * 50 FETCH (MODSEQ (12111230047))
+      S: a104 OK Store (conditional) completed
+
+   Example 5:
+
+      C: c101 STORE 1 (UNCHANGEDSINCE 12121230045) -FLAGS.SILENT
+         (\Deleted)
+      S: * OK [HIGHESTMODSEQ 12111230047]
+
+
+
+Melnikov & Hole             Standards Track                     [Page 8]
+
+RFC 4551          IMAP Extension for Conditional STORE         June 2006
+
+
+      S: * 50 FETCH (MODSEQ (12111230048))
+      S: c101 OK Store (conditional) completed
+
+      HIGHESTMODSEQ response code was sent by the server presumably
+      because this was the first CONDSTORE enabling command.
+
+   Example 6:
+
+      In spite of the failure of the conditional STORE operation for
+      message 7, the server continues to process the conditional STORE
+      in order to find all messages that fail the test.
+
+      C: d105 STORE 7,5,9 (UNCHANGEDSINCE 320162338)
+          +FLAGS.SILENT (\Deleted)
+      S: * 5 FETCH (MODSEQ (320162350))
+      S: d105 OK [MODIFIED 7,9] Conditional STORE failed
+
+   Example 7:
+
+      Same as above, but the server follows the SHOULD recommendation in
+      Section 6.4.6 of [IMAP4].
+
+      C: d105 STORE 7,5,9 (UNCHANGEDSINCE 320162338)
+          +FLAGS.SILENT (\Deleted)
+      S: * 7 FETCH (MODSEQ (320162342) FLAGS (\Seen \Deleted))
+      S: * 5 FETCH (MODSEQ (320162350))
+      S: * 9 FETCH (MODSEQ (320162349) FLAGS (\Answered))
+      S: d105 OK [MODIFIED 7,9] Conditional STORE failed
+
+      Use of UNCHANGEDSINCE with a modification sequence of 0 always
+      fails if the metadata item exists.  A system flag MUST always be
+      considered existent, whether it was set or not.
+
+   Example 8:
+
+      C: a102 STORE 12 (UNCHANGEDSINCE 0)
+          +FLAGS.SILENT ($MDNSent)
+      S: a102 OK [MODIFIED 12] Conditional STORE failed
+
+      The client has tested the presence of the $MDNSent user-defined
+      keyword.
+
+   Note: A client trying to make an atomic change to the state of a
+   particular metadata item (or a set of metadata items) should be
+   prepared to deal with the case when the server returns the MODIFIED
+   response code if the state of the metadata item being watched hasn't
+   changed (but the state of some other metadata item has).  This is
+   necessary, because some servers don't store separate mod-sequences
+
+
+
+Melnikov & Hole             Standards Track                     [Page 9]
+
+RFC 4551          IMAP Extension for Conditional STORE         June 2006
+
+
+   for different metadata items.  However, a server implementation
+   SHOULD avoid generating spurious MODIFIED responses for +FLAGS/-FLAGS
+   STORE operations, even when the server stores a single mod-sequence
+   per message.  Section 5 describes how this can be achieved.
+
+   Unless the server has included an unsolicited FETCH to update
+   client's knowledge about messages that have failed the UNCHANGEDSINCE
+   test, upon receipt of the MODIFIED response code, the client SHOULD
+   try to figure out if the required metadata items have indeed changed
+   by issuing FETCH or NOOP command.  It is RECOMMENDED that the server
+   avoids the need for the client to do that by sending an unsolicited
+   FETCH response (Examples 9 and 10).
+
+   If the required metadata items haven't changed, the client SHOULD
+   retry the command with the new mod-sequence.  The client SHOULD allow
+   for a configurable but reasonable number of retries (at least 2).
+
+   Example 9:
+
+      In the example below, the server returns the MODIFIED response
+      code without sending information describing why the STORE
+      UNCHANGEDSINCE operation has failed.
+
+      C: a106 STORE 100:150 (UNCHANGEDSINCE 212030000000)
+          +FLAGS.SILENT ($Processed)
+      S: * 100 FETCH (MODSEQ (303181230852))
+      S: * 102 FETCH (MODSEQ (303181230852))
+      ...
+      S: * 150 FETCH (MODSEQ (303181230852))
+      S: a106 OK [MODIFIED 101] Conditional STORE failed
+
+      The flag $Processed was set on the message 101...
+
+      C: a107 NOOP
+      S: * 101 FETCH (MODSEQ (303011130956) FLAGS ($Processed))
+      S: a107 OK
+
+      Or the flag hasn't changed, but another has (note that this server
+      behaviour is discouraged.  Server implementers should also see
+      Section 5)...
+
+      C: b107 NOOP
+      S: * 101 FETCH (MODSEQ (303011130956) FLAGS (\Deleted \Answered))
+      S: b107 OK
+
+      ...and the client retries the operation for the message 101 with
+      the updated UNCHANGEDSINCE value
+
+
+
+
+Melnikov & Hole             Standards Track                    [Page 10]
+
+RFC 4551          IMAP Extension for Conditional STORE         June 2006
+
+
+      C: b108 STORE 101 (UNCHANGEDSINCE 303011130956)
+          +FLAGS.SILENT ($Processed)
+      S: * 101 FETCH (MODSEQ (303181230852))
+      S: b108 OK Conditional Store completed
+
+   Example 10:
+
+      Same as above, but the server avoids the need for the client to
+      poll for changes.
+
+      The flag $Processed was set on the message 101 by another
+      client...
+
+      C: a106 STORE 100:150 (UNCHANGEDSINCE 212030000000)
+          +FLAGS.SILENT ($Processed)
+      S: * 100 FETCH (MODSEQ (303181230852))
+      S: * 101 FETCH (MODSEQ (303011130956) FLAGS ($Processed))
+      S: * 102 FETCH (MODSEQ (303181230852))
+      ...
+      S: * 150 FETCH (MODSEQ (303181230852))
+      S: a106 OK [MODIFIED 101] Conditional STORE failed
+
+      Or the flag hasn't changed, but another has (note that this server
+      behaviour is discouraged.  Server implementers should also see
+      Section 5)...
+
+      C: a106 STORE 100:150 (UNCHANGEDSINCE 212030000000)
+          +FLAGS.SILENT ($Processed)
+      S: * 100 FETCH (MODSEQ (303181230852))
+      S: * 101 FETCH (MODSEQ (303011130956) FLAGS (\Deleted \Answered))
+      S: * 102 FETCH (MODSEQ (303181230852))
+      ...
+      S: * 150 FETCH (MODSEQ (303181230852))
+      S: a106 OK [MODIFIED 101] Conditional STORE failed
+
+      ...and the client retries the operation for the message 101 with
+      the updated UNCHANGEDSINCE value
+
+      C: b108 STORE 101 (UNCHANGEDSINCE 303011130956)
+          +FLAGS.SILENT ($Processed)
+      S: * 101 FETCH (MODSEQ (303181230852))
+      S: b108 OK Conditional Store completed
+
+      Or the flag hasn't changed, but another has (nice server
+      behaviour.  Server implementers should also see Section 5)...
+
+      C: a106 STORE 100:150 (UNCHANGEDSINCE 212030000000)
+          +FLAGS.SILENT ($Processed)
+
+
+
+Melnikov & Hole             Standards Track                    [Page 11]
+
+RFC 4551          IMAP Extension for Conditional STORE         June 2006
+
+
+      S: * 100 FETCH (MODSEQ (303181230852))
+      S: * 101 FETCH (MODSEQ (303011130956) FLAGS ($Processed \Deleted
+           \Answered))
+      S: * 102 FETCH (MODSEQ (303181230852))
+      ...
+      S: * 150 FETCH (MODSEQ (303181230852))
+      S: a106 OK Conditional STORE completed
+
+   Example 11:
+
+      The following example is based on the example from the Section
+      4.2.3 of [RFC-2180] and demonstrates that the MODIFIED response
+      code may be also returned in the tagged NO response.
+
+      Client tries to conditionally STORE flags on a mixture of expunged
+      and non-expunged messages; one message fails the UNCHANGEDSINCE
+      test.
+
+      C: B001 STORE 1:7 (UNCHANGEDSINCE 320172338) +FLAGS (\SEEN)
+      S: * 1 FETCH (MODSEQ (320172342) FLAGS (\SEEN))
+      S: * 3 FETCH (MODSEQ (320172342) FLAGS (\SEEN))
+      S: B001 NO [MODIFIED 2] Some of the messages no longer exist.
+
+      C: B002 NOOP
+      S: * 4 EXPUNGE
+      S: * 4 EXPUNGE
+      S: * 4 EXPUNGE
+      S: * 4 EXPUNGE
+      S: * 2 FETCH (MODSEQ (320172340) FLAGS (\Deleted \Answered))
+      S: B002 OK NOOP Completed.
+
+      By receiving FETCH responses for messages 1 and 3, and EXPUNGE
+      responses that indicate that messages 4 through 7 have been
+      expunged, the client retries the operation only for the message 2.
+      The updated UNCHANGEDSINCE value is used.
+
+      C: b003 STORE 2 (UNCHANGEDSINCE 320172340) +FLAGS (\Seen)
+      S: * 2 FETCH (MODSEQ (320180050))
+      S: b003 OK Conditional Store completed
+
+   Note: If a message is specified multiple times in the message set,
+   and the server doesn't internally eliminate duplicates from the
+   message set, it MUST NOT fail the conditional STORE operation for the
+   second (or subsequent) occurrence of the message if the operation
+   completed successfully for the first occurrence.  For example, if the
+   client specifies:
+
+
+
+
+
+Melnikov & Hole             Standards Track                    [Page 12]
+
+RFC 4551          IMAP Extension for Conditional STORE         June 2006
+
+
+         e105 STORE 7,3:9 (UNCHANGEDSINCE 12121230045)
+          +FLAGS.SILENT (\Deleted)
+
+   the server must not fail the operation for message 7 as part of
+   processing "3:9" if it succeeded when message 7 was processed the
+   first time.
+
+   Once the client specified the UNCHANGEDSINCE modifier in a STORE
+   command, the server MUST include the MODSEQ fetch response data items
+   in all subsequent unsolicited FETCH responses.
+
+   This document also changes the behaviour of the server when it has
+   performed a STORE or UID STORE command and the UNCHANGEDSINCE
+   modifier is not specified.  If the operation is successful for a
+   message, the server MUST update the mod-sequence attribute of the
+   message.  The server is REQUIRED to include the mod-sequence value
+   whenever it decides to send the unsolicited FETCH response to all
+   CONDSTORE-aware clients that have opened the mailbox containing the
+   message.
+
+   Server implementers should also see Section 3.8 for additional
+   quality of implementation issues related to the STORE command.
+
+3.3.  FETCH and UID FETCH Commands
+
+3.3.1.  CHANGEDSINCE FETCH Modifier
+
+   This document defines the following FETCH modifier (see Section 2.4
+   of [IMAPABNF]):
+
+   CHANGEDSINCE <mod-sequence>
+
+      CHANGEDSINCE FETCH modifier allows to create a further subset of
+      the list of messages described by sequence set.  The information
+      described by message data items is only returned for messages that
+      have mod-sequence bigger than <mod-sequence>.
+
+      When CHANGEDSINCE FETCH modifier is specified, it implicitly adds
+      MODSEQ FETCH message data item (Section 3.3.2).
+
+   Example 12:
+
+      C: s100 UID FETCH 1:* (FLAGS) (CHANGEDSINCE 12345)
+      S: * 1 FETCH (UID 4 MODSEQ (65402) FLAGS (\Seen))
+      S: * 2 FETCH (UID 6 MODSEQ (75403) FLAGS (\Deleted))
+      S: * 4 FETCH (UID 8 MODSEQ (29738) FLAGS ($NoJunk $AutoJunk
+           $MDNSent))
+      S: s100 OK FETCH completed
+
+
+
+Melnikov & Hole             Standards Track                    [Page 13]
+
+RFC 4551          IMAP Extension for Conditional STORE         June 2006
+
+
+3.3.2.  MODSEQ Message Data Item in FETCH Command
+
+   This extension adds a MODSEQ message data item to the FETCH command.
+   The MODSEQ message data item allows clients to retrieve mod-sequence
+   values for a range of messages in the currently selected mailbox.
+
+   Once the client specified the MODSEQ message data item in a FETCH
+   request, the server MUST include the MODSEQ fetch response data items
+   in all subsequent unsolicited FETCH responses.
+
+   Syntax:  MODSEQ
+
+      The MODSEQ message data item causes the server to return MODSEQ
+      fetch response data items.
+
+   Syntax:  MODSEQ ( <permsg-modsequence> )
+
+      MODSEQ response data items contain per-message mod-sequences.
+
+      The MODSEQ response data item is returned if the client issued
+      FETCH with MODSEQ message data item.  It also allows the server to
+      notify the client about mod-sequence changes caused by conditional
+      STOREs (Section 3.2) and/or changes caused by external sources.
+
+   Example 13:
+
+      C: a FETCH 1:3 (MODSEQ)
+      S: * 1 FETCH (MODSEQ (624140003))
+      S: * 2 FETCH (MODSEQ (624140007))
+      S: * 3 FETCH (MODSEQ (624140005))
+      S: a OK Fetch complete
+
+      In this example, the client requests per-message mod-sequences for
+      a set of messages.
+
+   When a flag for a message is modified in a different session, the
+   server sends an unsolicited FETCH response containing the mod-
+   sequence for the message.
+
+   Example 14:
+
+      (Session 1, authenticated as a user "alex").  The user adds a
+      shared flag \Deleted:
+
+         C: A142 SELECT INBOX
+         ...
+         S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
+         S: * OK [PERMANENTFLAGS (\Answered \Deleted \Seen \*)] Limited
+
+
+
+Melnikov & Hole             Standards Track                    [Page 14]
+
+RFC 4551          IMAP Extension for Conditional STORE         June 2006
+
+
+         ...
+
+         C: A160 STORE 7 +FLAGS.SILENT (\Deleted)
+         S: * 7 FETCH (MODSEQ (2121231000))
+         S: A160 OK Store completed
+
+      (Session 2, also authenticated as the user "alex").  Any changes
+      to flags are always reported to all sessions authenticated as the
+      same user as in the session 1.
+
+         C: C180 NOOP
+         S: * 7 FETCH (FLAGS (\Deleted \Answered) MODSEQ (12121231000))
+         S: C180 OK Noop completed
+
+      (Session 3, authenticated as a user "andrew").  As \Deleted is a
+      shared flag, changes in session 1 are also reported in session 3:
+
+         C: D210 NOOP
+         S: * 7 FETCH (FLAGS (\Deleted \Answered) MODSEQ (12121231000))
+         S: D210 OK Noop completed
+
+      The user modifies a private flag \Seen in session 1...
+
+         C: A240 STORE 7 +FLAGS.SILENT (\Seen)
+         S: * 7 FETCH (MODSEQ (12121231777))
+         S: A240 OK Store completed
+
+      ...which is only reported in session 2...
+
+         C: C270 NOOP
+         S: * 7 FETCH (FLAGS (\Deleted \Answered \Seen) MODSEQ
+              (12121231777))
+         S: C270 OK Noop completed
+
+      ...but not in session 3.
+
+         C: D300 NOOP
+         S: D300 OK Noop completed
+
+      And finally, the user removes flags \Answered (shared) and \Seen
+      (private) in session 1.
+
+         C: A330 STORE 7 -FLAGS.SILENT (\Answered \Seen)
+         S: * 7 FETCH (MODSEQ (12121245160))
+         S: A330 OK Store completed
+
+
+
+
+
+
+Melnikov & Hole             Standards Track                    [Page 15]
+
+RFC 4551          IMAP Extension for Conditional STORE         June 2006
+
+
+      Both changes are reported in the session 2...
+
+         C: C360 NOOP
+         S: * 7 FETCH (FLAGS (\Deleted) MODSEQ (12121245160))
+         S: C360 OK Noop completed
+
+      ...and only changes to shared flags are reported in session 3.
+
+         C: D390 NOOP
+         S: * 7 FETCH (FLAGS (\Deleted) MODSEQ (12121245160))
+         S: D390 OK Noop completed
+
+   Server implementers should also see Section 3.8 for additional
+   quality of implementation issues related to the FETCH command.
+
+3.4.  MODSEQ Search Criterion in SEARCH
+
+   The MODSEQ criterion for the SEARCH command allows a client to search
+   for the metadata items that were modified since a specified moment.
+
+   Syntax:  MODSEQ [<entry-name> <entry-type-req>] <mod-sequence-valzer>
+
+      Messages that have modification values that are equal to or
+      greater than <mod-sequence-valzer>.  This allows a client, for
+      example, to find out which messages contain metadata items that
+      have changed since the last time it updated its disconnected
+      cache.  The client may also specify <entry-name> (name of metadata
+      item) and <entry-type-req> (type of metadata item) before
+      <mod-sequence-valzer>.  <entry-type-req> can be one of "shared",
+      "priv" (private), or "all".  The latter means that the server
+      should use the biggest value among "priv" and "shared" mod-
+      sequences for the metadata item.  If the server doesn't store
+      internally separate mod-sequences for different metadata items, it
+      MUST ignore <entry-name> and <entry-type-req>.  Otherwise, the
+      server should use them to narrow down the search.
+
+      For a flag <flagname>, the corresponding <entry-name> has a form
+      "/flags/<flagname>" as defined in [IMAPABNF].  Note that the
+      leading "\" character that denotes a system flag has to be escaped
+      as per Section 4.3 of [IMAP4], as the <entry-name> uses syntax for
+      quoted strings.
+
+   If client specifies a MODSEQ criterion in a SEARCH command and the
+   server returns a non-empty SEARCH result, the server MUST also append
+   (to the end of the untagged SEARCH response) the highest mod-sequence
+   for all messages being returned.  See also Section 3.5.
+
+
+
+
+
+Melnikov & Hole             Standards Track                    [Page 16]
+
+RFC 4551          IMAP Extension for Conditional STORE         June 2006
+
+
+   Example 15:
+
+      C: a SEARCH MODSEQ "/flags/\\draft" all 620162338
+      S: * SEARCH 2 5 6 7 11 12 18 19 20 23 (MODSEQ 917162500)
+      S: a OK Search complete
+
+      In the above example, the message numbers of any messages
+      containing the string "IMAP4" in the "value" attribute of the
+      "/comment" entry and having a mod-sequence equal to or greater
+      than 620162338 for the "\Draft" flag are returned in the search
+      results.
+
+   Example 16:
+
+      C: t SEARCH OR NOT MODSEQ 720162338 LARGER 50000
+      S: * SEARCH
+      S: t OK Search complete, nothing found
+
+3.5.  Modified SEARCH Untagged Response
+
+   Data:       zero or more numbers
+               mod-sequence value (omitted if no match)
+
+   This document extends syntax of the untagged SEARCH response to
+   include the highest mod-sequence for all messages being returned.
+
+   If a client specifies a MODSEQ criterion in a SEARCH (or UID SEARCH)
+   command and the server returns a non-empty SEARCH result, the server
+   MUST also append (to the end of the untagged SEARCH response) the
+   highest mod-sequence for all messages being returned.  See Section
+   3.4 for examples.
+
+3.6.  HIGHESTMODSEQ Status Data Items
+
+   This document defines a new status data item:
+
+   HIGHESTMODSEQ
+
+      The highest mod-sequence value of all messages in the mailbox.
+      This is the same value that is returned by the server in the
+      HIGHESTMODSEQ response code in an OK untagged response (see
+      Section 3.1.1).  If the server doesn't support the persistent
+      storage of mod-sequences for the mailbox (see Section 3.1.2), the
+      server MUST return 0 as the value of HIGHESTMODSEQ status data
+      item.
+
+
+
+
+
+
+Melnikov & Hole             Standards Track                    [Page 17]
+
+RFC 4551          IMAP Extension for Conditional STORE         June 2006
+
+
+   Example 17:
+
+      C: A042 STATUS blurdybloop (UIDNEXT MESSAGES HIGHESTMODSEQ)
+      S: * STATUS blurdybloop (MESSAGES 231 UIDNEXT 44292
+           HIGHESTMODSEQ 7011231777)
+      S: A042 OK STATUS completed
+
+3.7.  CONDSTORE Parameter to SELECT and EXAMINE
+
+   The CONDSTORE extension defines a single optional select parameter,
+   "CONDSTORE", which tells the server that it MUST include the MODSEQ
+   fetch response data items in all subsequent unsolicited FETCH
+   responses.
+
+   The CONDSTORE parameter to SELECT/EXAMINE helps avoid a race
+   condition that might arise when one or more metadata items are
+   modified in another session after the server has sent the
+   HIGHESTMODSEQ response code and before the client was able to issue a
+   CONDSTORE enabling command.
+
+   Example 18:
+
+      C: A142 SELECT INBOX (CONDSTORE)
+      S: * 172 EXISTS
+      S: * 1 RECENT
+      S: * OK [UNSEEN 12] Message 12 is first unseen
+      S: * OK [UIDVALIDITY 3857529045] UIDs valid
+      S: * OK [UIDNEXT 4392] Predicted next UID
+      S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
+      S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
+      S: * OK [HIGHESTMODSEQ 715194045007]
+      S: A142 OK [READ-WRITE] SELECT completed, CONDSTORE is now enabled
+
+3.8.  Additional Quality-of-Implementation Issues
+
+   Server implementations should follow the following rule, which
+   applies to any successfully completed STORE/UID STORE (with and
+   without UNCHANGEDSINCE modifier), as well as to a FETCH command that
+   implicitly sets \Seen flag:
+
+      Adding the flag when it is already present or removing when it is
+      not present SHOULD NOT change the mod-sequence.
+
+   This will prevent spurious client synchronization requests.
+
+
+
+
+
+
+
+Melnikov & Hole             Standards Track                    [Page 18]
+
+RFC 4551          IMAP Extension for Conditional STORE         June 2006
+
+
+   However, note that client implementers MUST NOT rely on this server
+   behavior.  A client can't distinguish between the case when a server
+   has violated the SHOULD mentioned above, and that when one or more
+   clients set and unset (or unset and set) the flag in another session.
+
+4.  Formal Syntax
+
+   The following syntax specification uses the Augmented Backus-Naur
+   Form (ABNF) [ABNF] notation.  Elements not defined here can be found
+   in the formal syntax of the ABNF [ABNF], IMAP [IMAP4], and IMAP ABNF
+   extensions [IMAPABNF] specifications.
+
+   Except as noted otherwise, all alphabetic characters are case-
+   insensitive.  The use of upper- or lowercase characters to define
+   token strings is for editorial clarity only.  Implementations MUST
+   accept these strings in a case-insensitive fashion.
+
+   capability          =/ "CONDSTORE"
+
+   status-att          =/ "HIGHESTMODSEQ"
+                          ;; extends non-terminal defined in RFC 3501.
+
+   status-att-val      =/ "HIGHESTMODSEQ" SP mod-sequence-valzer
+                          ;; extends non-terminal defined in [IMAPABNF].
+                          ;; Value 0 denotes that the mailbox doesn't
+                          ;; support persistent mod-sequences
+                          ;; as described in Section 3.1.2
+
+   store-modifier      =/ "UNCHANGEDSINCE" SP mod-sequence-valzer
+                          ;; Only a single "UNCHANGEDSINCE" may be
+                          ;; specified in a STORE operation
+
+   fetch-modifier      =/ chgsince-fetch-mod
+                          ;; conforms to the generic "fetch-modifier"
+                          ;; syntax defined in [IMAPABNF].
+
+   chgsince-fetch-mod  = "CHANGEDSINCE" SP mod-sequence-value
+                          ;; CHANGEDSINCE FETCH modifier conforms to
+                          ;; the fetch-modifier syntax
+
+   fetch-att           =/ fetch-mod-sequence
+                          ;; modifies original IMAP4 fetch-att
+
+   fetch-mod-sequence  = "MODSEQ"
+
+   fetch-mod-resp      = "MODSEQ" SP "(" permsg-modsequence ")"
+
+   msg-att-dynamic     =/ fetch-mod-resp
+
+
+
+Melnikov & Hole             Standards Track                    [Page 19]
+
+RFC 4551          IMAP Extension for Conditional STORE         June 2006
+
+
+   search-key          =/ search-modsequence
+                          ;; modifies original IMAP4 search-key
+                          ;;
+                          ;; This change applies to all commands
+                          ;; referencing this non-terminal, in
+                          ;; particular SEARCH.
+
+   search-modsequence  = "MODSEQ" [search-modseq-ext] SP
+                         mod-sequence-valzer
+
+   search-modseq-ext   = SP entry-name SP entry-type-req
+
+   resp-text-code      =/ "HIGHESTMODSEQ" SP mod-sequence-value /
+                          "NOMODSEQ" /
+                          "MODIFIED" SP set
+
+   entry-name          = entry-flag-name
+
+   entry-flag-name     = DQUOTE "/flags/" attr-flag DQUOTE
+                          ;; each system or user defined flag <flag>
+                          ;; is mapped to "/flags/<flag>".
+                          ;;
+                          ;; <entry-flag-name> follows the escape rules
+                          ;; used by "quoted" string as described in
+                          ;; Section 4.3 of [IMAP4], e.g., for the flag
+                          ;; \Seen the corresponding <entry-name> is
+                          ;; "/flags/\\seen", and for the flag
+                          ;; $MDNSent, the corresponding <entry-name>
+                          ;; is "/flags/$mdnsent".
+
+   entry-type-resp     = "priv" / "shared"
+                          ;; metadata item type
+
+   entry-type-req      = entry-type-resp / "all"
+                          ;; perform SEARCH operation on private
+                          ;; metadata item, shared metadata item or both
+
+   permsg-modsequence  = mod-sequence-value
+                          ;; per message mod-sequence
+
+   mod-sequence-value  = 1*DIGIT
+                          ;; Positive unsigned 64-bit integer
+                          ;; (mod-sequence)
+                          ;; (1 <= n < 18,446,744,073,709,551,615)
+
+   mod-sequence-valzer = "0" / mod-sequence-value
+
+   search-sort-mod-seq = "(" "MODSEQ" SP mod-sequence-value ")"
+
+
+
+Melnikov & Hole             Standards Track                    [Page 20]
+
+RFC 4551          IMAP Extension for Conditional STORE         June 2006
+
+
+   select-param        =/ condstore-param
+                          ;; conforms to the generic "select-param"
+                          ;; non-terminal syntax defined in [IMAPABNF].
+
+   condstore-param     = "CONDSTORE"
+
+   mailbox-data        =/ "SEARCH" [1*(SP nz-number) SP
+                          search-sort-mod-seq]
+
+   attr-flag           = "\\Answered" / "\\Flagged" / "\\Deleted" /
+                         "\\Seen" / "\\Draft" / attr-flag-keyword /
+                         attr-flag-extension
+                          ;; Does not include "\\Recent"
+
+   attr-flag-extension = "\\" atom
+                          ;; Future expansion.  Client implementations
+                          ;; MUST accept flag-extension flags.  Server
+                          ;; implementations MUST NOT generate
+                          ;; flag-extension flags except as defined by
+                          ;; future standard or standards-track
+                          ;; revisions of [IMAP4].
+
+   attr-flag-keyword   = atom
+
+5.  Server Implementation Considerations
+
+   This section describes how a server implementation that doesn't store
+   separate per-metadata mod-sequences for different metadata items can
+   avoid sending the MODIFIED response to any of the following
+   conditional STORE operations:
+
+      +FLAGS
+      -FLAGS
+      +FLAGS.SILENT
+      -FLAGS.SILENT
+
+   Note that the optimization described in this section can't be
+   performed in case of a conditional STORE FLAGS operation.
+
+   Let's use the following example.  The client has issued
+
+      C: a106 STORE 100:150 (UNCHANGEDSINCE 212030000000)
+         +FLAGS.SILENT ($Processed)
+
+   When the server receives the command and parses it successfully, it
+   iterates through the message set and tries to execute the conditional
+   STORE command for each message.
+
+
+
+
+Melnikov & Hole             Standards Track                    [Page 21]
+
+RFC 4551          IMAP Extension for Conditional STORE         June 2006
+
+
+   Each server internally works as a client, i.e., it has to cache the
+   current state of all IMAP flags as it is known to the client.  In
+   order to report flag changes to the client, the server compares the
+   cached values with the values in its database for IMAP flags.
+
+   Imagine that another client has changed the state of a flag \Deleted
+   on the message 101 and that the change updated the mod-sequence for
+   the message.  The server knows that the mod-sequence for the mailbox
+   has changed; however, it also knows that:
+
+   a) the client is not interested in \Deleted flag, as it hasn't
+      included it in +FLAGS.SILENT operation; and
+
+   b) the state of the flag $Processed hasn't changed (the server can
+      determine this by comparing cached flag state with the state of
+      the flag in the database).
+
+   Therefore, the server doesn't have to report MODIFIED to the client.
+   Instead, the server may set $Processed flag, update the mod-sequence
+   for the message 101 once again and send an untagged FETCH response
+   with new mod-sequence and flags:
+
+      S: * 101 FETCH (MODSEQ (303011130956)
+         FLAGS ($Processed \Deleted \Answered))
+
+   See also Section 3.8 for additional quality-of-implementation issues.
+
+6.  Security Considerations
+
+   It is believed that the Conditional STORE extension doesn't raise any
+   new security concerns that are not already discussed in [IMAP4].
+   However, the availability of this extension may make it possible for
+   IMAP4 to be used in critical applications it could not be used for
+   previously, making correct IMAP server implementation and operation
+   even more important.
+
+7.  IANA Considerations
+
+   IMAP4 capabilities are registered by publishing a standards track or
+   IESG approved experimental RFC.  The registry is currently located
+   at:
+
+         http://www.iana.org/assignments/imap4-capabilities
+
+   This document defines the CONDSTORE IMAP capability.  IANA has added
+   it to the registry accordingly.
+
+
+
+
+
+Melnikov & Hole             Standards Track                    [Page 22]
+
+RFC 4551          IMAP Extension for Conditional STORE         June 2006
+
+
+8.  References
+
+8.1.  Normative References
+
+   [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate
+              Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+   [ABNF]     Crocker, D. and P. Overell, "Augmented BNF for Syntax
+              Specifications: ABNF", RFC 4234, October 2005.
+
+   [IMAP4]    Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
+              4rev1", RFC 3501, March 2003.
+
+   [IMAPABNF] Melnikov, A. and C. Daboo, "Collected Extensions to IMAP4
+              ABNF", RFC 4466, April 2006.
+
+8.2.  Informative References
+
+   [ACAP]     Newman, C. and J. Myers, "ACAP -- Application
+              Configuration Access Protocol", RFC 2244, November 1997.
+
+   [ACL]      Melnikov, A., "IMAP4 Access Control List (ACL) Extension",
+              RFC 4314, December 2005.
+
+   [ANN]      Daboo, C. and R. Gellens, "IMAP ANNOTATE Extension", Work
+              in Progress, March 2006.
+
+   [NTP]      Mills, D., "Network Time Protocol (Version 3)
+              Specification, Implementation and Analysis", RFC 1305,
+              March 1992.
+
+   [RFC-2180] Gahrns, M., "IMAP4 Multi-Accessed Mailbox Practice", RFC
+              2180, July 1997.
+
+9.  Acknowledgements
+
+   Some text was borrowed from "IMAP ANNOTATE Extension" [ANN] by
+   Randall Gellens and Cyrus Daboo and from "ACAP -- Application
+   Configuration Access Protocol" [ACAP] by Chris Newman and John Myers.
+
+   Many thanks to Randall Gellens for his thorough review of the
+   document.
+
+   The authors also acknowledge the feedback provided by Cyrus Daboo,
+   Larry Greenfield, Chris Newman, Harrie Hazewinkel, Arnt Gulbrandsen,
+   Timo Sirainen, Mark Crispin, Ned Freed, Ken Murchison, and Dave
+   Cridland.
+
+
+
+
+Melnikov & Hole             Standards Track                    [Page 23]
+
+RFC 4551          IMAP Extension for Conditional STORE         June 2006
+
+
+Authors' Addresses
+
+   Alexey Melnikov
+   Isode Limited
+   5 Castle Business Village
+   36 Station Road
+   Hampton, Middlesex
+   TW12 2BX,
+   United Kingdom
+
+   EMail: Alexey.Melnikov@isode.com
+
+
+   Steve Hole
+   ACI WorldWide/MessagingDirect
+   #1807, 10088 102 Ave
+   Edmonton, AB
+   T5J 2Z1
+   Canada
+
+   EMail: Steve.Hole@messagingdirect.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov & Hole             Standards Track                    [Page 24]
+
+RFC 4551          IMAP Extension for Conditional STORE         June 2006
+
+
+Full Copyright Statement
+
+   Copyright (C) The Internet Society (2006).
+
+   This document is subject to the rights, licenses and restrictions
+   contained in BCP 78, and except as set forth therein, the authors
+   retain all their rights.
+
+   This document and the information contained herein are provided on an
+   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   Intellectual Property Rights or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; nor does it represent that it has
+   made any independent effort to identify any such rights.  Information
+   on the procedures with respect to rights in RFC documents can be
+   found in BCP 78 and BCP 79.
+
+   Copies of IPR disclosures made to the IETF Secretariat and any
+   assurances of licenses to be made available, or the result of an
+   attempt made to obtain a general license or permission for the use of
+   such proprietary rights by implementers or users of this
+   specification can be obtained from the IETF on-line IPR repository at
+   http://www.ietf.org/ipr.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights that may cover technology that may be required to implement
+   this standard.  Please address the information to the IETF at
+   ietf-ipr@ietf.org.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is provided by the IETF
+   Administrative Support Activity (IASA).
+
+
+
+
+
+
+
+Melnikov & Hole             Standards Track                    [Page 25]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc4616.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,619 @@
+
+
+
+
+
+
+Network Working Group                                   K. Zeilenga, Ed.
+Request for Comments: 4616                           OpenLDAP Foundation
+Updates: 2595                                                August 2006
+Category: Standards Track
+
+
+  The PLAIN Simple Authentication and Security Layer (SASL) Mechanism
+
+Status of This Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The Internet Society (2006).
+
+Abstract
+
+   This document defines a simple clear-text user/password Simple
+   Authentication and Security Layer (SASL) mechanism called the PLAIN
+   mechanism.  The PLAIN mechanism is intended to be used, in
+   combination with data confidentiality services provided by a lower
+   layer, in protocols that lack a simple password authentication
+   command.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Zeilenga                    Standards Track                     [Page 1]
+
+RFC 4616                The PLAIN SASL Mechanism             August 2006
+
+
+1.  Introduction
+
+   Clear-text, multiple-use passwords are simple, interoperate with
+   almost all existing operating system authentication databases, and
+   are useful for a smooth transition to a more secure password-based
+   authentication mechanism.  The drawback is that they are unacceptable
+   for use over network connections where data confidentiality is not
+   ensured.
+
+   This document defines the PLAIN Simple Authentication and Security
+   Layer ([SASL]) mechanism for use in protocols with no clear-text
+   login command (e.g., [ACAP] or [SMTP-AUTH]).  This document updates
+   RFC 2595, replacing Section 6.  Changes since RFC 2595 are detailed
+   in Appendix A.
+
+   The name associated with this mechanism is "PLAIN".
+
+   The PLAIN SASL mechanism does not provide a security layer.
+
+   The PLAIN mechanism should not be used without adequate data security
+   protection as this mechanism affords no integrity or confidentiality
+   protections itself.  The mechanism is intended to be used with data
+   security protections provided by application-layer protocol,
+   generally through its use of Transport Layer Security ([TLS])
+   services.
+
+   By default, implementations SHOULD advertise and make use of the
+   PLAIN mechanism only when adequate data security services are in
+   place.  Specifications for IETF protocols that indicate that this
+   mechanism is an applicable authentication mechanism MUST mandate that
+   implementations support an strong data security service, such as TLS.
+
+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+   document are to be interpreted as described in [Keywords].
+
+2.  PLAIN SASL Mechanism
+
+   The mechanism consists of a single message, a string of [UTF-8]
+   encoded [Unicode] characters, from the client to the server.  The
+   client presents the authorization identity (identity to act as),
+   followed by a NUL (U+0000) character, followed by the authentication
+   identity (identity whose password will be used), followed by a NUL
+   (U+0000) character, followed by the clear-text password.  As with
+   other SASL mechanisms, the client does not provide an authorization
+   identity when it wishes the server to derive an identity from the
+   credentials and use that as the authorization identity.
+
+
+
+
+Zeilenga                    Standards Track                     [Page 2]
+
+RFC 4616                The PLAIN SASL Mechanism             August 2006
+
+
+   The formal grammar for the client message using Augmented BNF [ABNF]
+   follows.
+
+   message   = [authzid] UTF8NUL authcid UTF8NUL passwd
+   authcid   = 1*SAFE ; MUST accept up to 255 octets
+   authzid   = 1*SAFE ; MUST accept up to 255 octets
+   passwd    = 1*SAFE ; MUST accept up to 255 octets
+   UTF8NUL   = %x00 ; UTF-8 encoded NUL character
+
+   SAFE      = UTF1 / UTF2 / UTF3 / UTF4
+               ;; any UTF-8 encoded Unicode character except NUL
+
+   UTF1      = %x01-7F ;; except NUL
+   UTF2      = %xC2-DF UTF0
+   UTF3      = %xE0 %xA0-BF UTF0 / %xE1-EC 2(UTF0) /
+               %xED %x80-9F UTF0 / %xEE-EF 2(UTF0)
+   UTF4      = %xF0 %x90-BF 2(UTF0) / %xF1-F3 3(UTF0) /
+               %xF4 %x80-8F 2(UTF0)
+   UTF0      = %x80-BF
+
+   The authorization identity (authzid), authentication identity
+   (authcid), password (passwd), and NUL character deliminators SHALL be
+   transferred as [UTF-8] encoded strings of [Unicode] characters.  As
+   the NUL (U+0000) character is used as a deliminator, the NUL (U+0000)
+   character MUST NOT appear in authzid, authcid, or passwd productions.
+
+   The form of the authzid production is specific to the application-
+   level protocol's SASL profile [SASL].  The authcid and passwd
+   productions are form-free.  Use of non-visible characters or
+   characters that a user may be unable to enter on some keyboards is
+   discouraged.
+
+   Servers MUST be capable of accepting authzid, authcid, and passwd
+   productions up to and including 255 octets.  It is noted that the
+   UTF-8 encoding of a Unicode character may be as long as 4 octets.
+
+   Upon receipt of the message, the server will verify the presented (in
+   the message) authentication identity (authcid) and password (passwd)
+   with the system authentication database, and it will verify that the
+   authentication credentials permit the client to act as the (presented
+   or derived) authorization identity (authzid).  If both steps succeed,
+   the user is authenticated.
+
+   The presented authentication identity and password strings, as well
+   as the database authentication identity and password strings, are to
+   be prepared before being used in the verification process.  The
+   [SASLPrep] profile of the [StringPrep] algorithm is the RECOMMENDED
+   preparation algorithm.  The SASLprep preparation algorithm is
+
+
+
+Zeilenga                    Standards Track                     [Page 3]
+
+RFC 4616                The PLAIN SASL Mechanism             August 2006
+
+
+   recommended to improve the likelihood that comparisons behave in an
+   expected manner.  The SASLprep preparation algorithm is not mandatory
+   so as to allow the server to employ other preparation algorithms
+   (including none) when appropriate.  For instance, use of a different
+   preparation algorithm may be necessary for the server to interoperate
+   with an external system.
+
+   When preparing the presented strings using [SASLPrep], the presented
+   strings are to be treated as "query" strings (Section 7 of
+   [StringPrep]) and hence unassigned code points are allowed to appear
+   in their prepared output.  When preparing the database strings using
+   [SASLPrep], the database strings are to be treated as "stored"
+   strings (Section 7 of [StringPrep]) and hence unassigned code points
+   are prohibited from appearing in their prepared output.
+
+   Regardless of the preparation algorithm used, if the output of a
+   non-invertible function (e.g., hash) of the expected string is
+   stored, the string MUST be prepared before input to that function.
+
+   Regardless of the preparation algorithm used, if preparation fails or
+   results in an empty string, verification SHALL fail.
+
+   When no authorization identity is provided, the server derives an
+   authorization identity from the prepared representation of the
+   provided authentication identity string.  This ensures that the
+   derivation of different representations of the authentication
+   identity produces the same authorization identity.
+
+   The server MAY use the credentials to initialize any new
+   authentication database, such as one suitable for [CRAM-MD5] or
+   [DIGEST-MD5].
+
+3.  Pseudo-Code
+
+   This section provides pseudo-code illustrating the verification
+   process (using hashed passwords and the SASLprep preparation
+   function) discussed above.  This section is not definitive.
+
+   boolean Verify(string authzid, string authcid, string passwd) {
+     string pAuthcid = SASLprep(authcid, true); # prepare authcid
+     string pPasswd = SASLprep(passwd, true);   # prepare passwd
+     if (pAuthcid == NULL || pPasswd == NULL) {
+       return false;     # preparation failed
+     }
+     if (pAuthcid == "" || pPasswd == "") {
+       return false;     # empty prepared string
+     }
+
+
+
+
+Zeilenga                    Standards Track                     [Page 4]
+
+RFC 4616                The PLAIN SASL Mechanism             August 2006
+
+
+     storedHash = FetchPasswordHash(pAuthcid);
+     if (storedHash == NULL || storedHash == "") {
+       return false;     # error or unknown authcid
+     }
+
+     if (!Compare(storedHash, Hash(pPasswd))) {
+       return false;     # incorrect password
+     }
+
+     if (authzid == NULL ) {
+       authzid = DeriveAuthzid(pAuthcid);
+       if (authzid == NULL || authzid == "") {
+           return false; # could not derive authzid
+       }
+     }
+
+     if (!Authorize(pAuthcid, authzid)) {
+       return false;     # not authorized
+     }
+
+     return true;
+   }
+
+   The second parameter of the SASLprep function, when true, indicates
+   that unassigned code points are allowed in the input.  When the
+   SASLprep function is called to prepare the password prior to
+   computing the stored hash, the second parameter would be false.
+
+   The second parameter provided to the Authorize function is not
+   prepared by this code.  The application-level SASL profile should be
+   consulted to determine what, if any, preparation is necessary.
+
+   Note that the DeriveAuthzid and Authorize functions (whether
+   implemented as one function or two, whether designed in a manner in
+   which these functions or whether the mechanism implementation can be
+   reused elsewhere) require knowledge and understanding of mechanism
+   and the application-level protocol specification and/or
+   implementation details to implement.
+
+   Note that the Authorize function outcome is clearly dependent on
+   details of the local authorization model and policy.  Both functions
+   may be dependent on other factors as well.
+
+
+
+
+
+
+
+
+
+Zeilenga                    Standards Track                     [Page 5]
+
+RFC 4616                The PLAIN SASL Mechanism             August 2006
+
+
+4.  Examples
+
+   This section provides examples of PLAIN authentication exchanges.
+   The examples are intended to help the readers understand the above
+   text.  The examples are not definitive.
+
+   "C:" and "S:" indicate lines sent by the client and server,
+   respectively.  "<NUL>" represents a single NUL (U+0000) character.
+   The Application Configuration Access Protocol ([ACAP]) is used in the
+   examples.
+
+   The first example shows how the PLAIN mechanism might be used for
+   user authentication.
+
+   S: * ACAP (SASL "CRAM-MD5") (STARTTLS)
+   C: a001 STARTTLS
+   S: a001 OK "Begin TLS negotiation now"
+   <TLS negotiation, further commands are under TLS layer>
+   S: * ACAP (SASL "CRAM-MD5" "PLAIN")
+   C: a002 AUTHENTICATE "PLAIN"
+   S: + ""
+   C: {21}
+   C: <NUL>tim<NUL>tanstaaftanstaaf
+   S: a002 OK "Authenticated"
+
+   The second example shows how the PLAIN mechanism might be used to
+   attempt to assume the identity of another user.  In this example, the
+   server rejects the request.  Also, this example makes use of the
+   protocol optional initial response capability to eliminate a round-
+   trip.
+
+   S: * ACAP (SASL "CRAM-MD5") (STARTTLS)
+   C: a001 STARTTLS
+   S: a001 OK "Begin TLS negotiation now"
+   <TLS negotiation, further commands are under TLS layer>
+   S: * ACAP (SASL "CRAM-MD5" "PLAIN")
+   C: a002 AUTHENTICATE "PLAIN" {20+}
+   C: Ursel<NUL>Kurt<NUL>xipj3plmq
+   S: a002 NO "Not authorized to requested authorization identity"
+
+5.  Security Considerations
+
+   As the PLAIN mechanism itself provided no integrity or
+   confidentiality protections, it should not be used without adequate
+   external data security protection, such as TLS services provided by
+   many application-layer protocols.  By default, implementations SHOULD
+   NOT advertise and SHOULD NOT make use of the PLAIN mechanism unless
+   adequate data security services are in place.
+
+
+
+Zeilenga                    Standards Track                     [Page 6]
+
+RFC 4616                The PLAIN SASL Mechanism             August 2006
+
+
+   When the PLAIN mechanism is used, the server gains the ability to
+   impersonate the user to all services with the same password
+   regardless of any encryption provided by TLS or other confidentiality
+   protection mechanisms.  Whereas many other authentication mechanisms
+   have similar weaknesses, stronger SASL mechanisms address this issue.
+   Clients are encouraged to have an operational mode where all
+   mechanisms that are likely to reveal the user's password to the
+   server are disabled.
+
+   General [SASL] security considerations apply to this mechanism.
+
+   Unicode, [UTF-8], and [StringPrep] security considerations also
+   apply.
+
+6.  IANA Considerations
+
+   The SASL Mechanism registry [IANA-SASL] entry for the PLAIN mechanism
+   has been updated by the IANA to reflect that this document now
+   provides its technical specification.
+
+   To: iana@iana.org
+   Subject: Updated Registration of SASL mechanism PLAIN
+
+   SASL mechanism name: PLAIN
+   Security considerations: See RFC 4616.
+   Published specification (optional, recommended): RFC 4616
+   Person & email address to contact for further information:
+        Kurt Zeilenga <kurt@openldap.org>
+        IETF SASL WG <ietf-sasl@imc.org>
+   Intended usage: COMMON
+   Author/Change controller: IESG <iesg@ietf.org>
+   Note: Updates existing entry for PLAIN
+
+7.  Acknowledgements
+
+   This document is a revision of RFC 2595 by Chris Newman.  Portions of
+   the grammar defined in Section 2 were borrowed from [UTF-8] by
+   Francois Yergeau.
+
+   This document is a product of the IETF Simple Authentication and
+   Security Layer (SASL) Working Group.
+
+
+
+
+
+
+
+
+
+
+Zeilenga                    Standards Track                     [Page 7]
+
+RFC 4616                The PLAIN SASL Mechanism             August 2006
+
+
+8.  Normative References
+
+   [ABNF]        Crocker, D., Ed. and P. Overell, "Augmented BNF for
+                 Syntax Specifications: ABNF", RFC 4234, October 2005.
+
+   [Keywords]    Bradner, S., "Key words for use in RFCs to Indicate
+                 Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+   [SASL]        Melnikov, A., Ed., and K. Zeilenga, Ed., "Simple
+                 Authentication and Security Layer (SASL)", RFC 4422,
+                 June 2006.
+
+   [SASLPrep]    Zeilenga, K., "SASLprep: Stringprep Profile for User
+                 Names and Passwords", RFC 4013, February 2005.
+
+   [StringPrep]  Hoffman, P. and M. Blanchet, "Preparation of
+                 Internationalized Strings ("stringprep")", RFC 3454,
+                 December 2002.
+
+   [Unicode]     The Unicode Consortium, "The Unicode Standard, Version
+                 3.2.0" is defined by "The Unicode Standard, Version
+                 3.0" (Reading, MA, Addison-Wesley, 2000. ISBN 0-201-
+                 61633-5), as amended by the "Unicode Standard Annex
+                 #27: Unicode 3.1"
+                 (http://www.unicode.org/reports/tr27/) and by the
+                 "Unicode Standard Annex #28: Unicode 3.2"
+                 (http://www.unicode.org/reports/tr28/).
+
+   [UTF-8]       Yergeau, F., "UTF-8, a transformation format of ISO
+                 10646", STD 63, RFC 3629, November 2003.
+
+   [TLS]         Dierks, T. and E. Rescorla, "The Transport Layer
+                 Security (TLS) Protocol Version 1.1", RFC 4346, April
+                 2006.
+
+9.  Informative References
+
+   [ACAP]        Newman, C. and J. Myers, "ACAP -- Application
+                 Configuration Access Protocol", RFC 2244, November
+                 1997.
+
+   [CRAM-MD5]    Nerenberg, L., Ed., "The CRAM-MD5 SASL Mechanism", Work
+                 in Progress, June 2006.
+
+   [DIGEST-MD5]  Melnikov, A., Ed., "Using Digest Authentication as a
+                 SASL Mechanism", Work in Progress, June 2006.
+
+
+
+
+
+Zeilenga                    Standards Track                     [Page 8]
+
+RFC 4616                The PLAIN SASL Mechanism             August 2006
+
+
+   [IANA-SASL]   IANA, "SIMPLE AUTHENTICATION AND SECURITY LAYER (SASL)
+                 MECHANISMS",
+                 <http://www.iana.org/assignments/sasl-mechanisms>.
+
+   [SMTP-AUTH]   Myers, J., "SMTP Service Extension for Authentication",
+                 RFC 2554, March 1999.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Zeilenga                    Standards Track                     [Page 9]
+
+RFC 4616                The PLAIN SASL Mechanism             August 2006
+
+
+Appendix A.  Changes since RFC 2595
+
+   This appendix is non-normative.
+
+   This document replaces Section 6 of RFC 2595.
+
+   The specification details how the server is to compare client-
+   provided character strings with stored character strings.
+
+   The ABNF grammar was updated.  In particular, the grammar now allows
+   LINE FEED (U+000A) and CARRIAGE RETURN (U+000D) characters in the
+   authzid, authcid, passwd productions.  However, whether these control
+   characters may be used depends on the string preparation rules
+   applicable to the production.  For passwd and authcid productions,
+   control characters are prohibited.  For authzid, one must consult the
+   application-level SASL profile.  This change allows PLAIN to carry
+   all possible authorization identity strings allowed in SASL.
+
+   Pseudo-code was added.
+
+   The example section was expanded to illustrate more features of the
+   PLAIN mechanism.
+
+Editor's Address
+
+   Kurt D. Zeilenga
+   OpenLDAP Foundation
+
+   EMail: Kurt@OpenLDAP.org
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Zeilenga                    Standards Track                    [Page 10]
+
+RFC 4616                The PLAIN SASL Mechanism             August 2006
+
+
+Full Copyright Statement
+
+   Copyright (C) The Internet Society (2006).
+
+   This document is subject to the rights, licenses and restrictions
+   contained in BCP 78, and except as set forth therein, the authors
+   retain all their rights.
+
+   This document and the information contained herein are provided on an
+   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+   ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+   INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+   INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   Intellectual Property Rights or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; nor does it represent that it has
+   made any independent effort to identify any such rights.  Information
+   on the procedures with respect to rights in RFC documents can be
+   found in BCP 78 and BCP 79.
+
+   Copies of IPR disclosures made to the IETF Secretariat and any
+   assurances of licenses to be made available, or the result of an
+   attempt made to obtain a general license or permission for the use of
+   such proprietary rights by implementers or users of this
+   specification can be obtained from the IETF on-line IPR repository at
+   http://www.ietf.org/ipr.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights that may cover technology that may be required to implement
+   this standard.  Please address the information to the IETF at
+   ietf-ipr@ietf.org.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is provided by the IETF
+   Administrative Support Activity (IASA).
+
+
+
+
+
+
+
+Zeilenga                    Standards Track                    [Page 11]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc4731.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,451 @@
+
+
+
+
+
+
+Network Working Group                                        A. Melnikov
+Request for Comments: 4731                                     Isode Ltd
+Category: Standards Track                                    D. Cridland
+                                                   Inventure Systems Ltd
+                                                           November 2006
+
+
+           IMAP4 Extension to SEARCH Command for Controlling
+                  What Kind of Information Is Returned
+
+Status of This Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The IETF Trust (2006).
+
+Abstract
+
+   This document extends IMAP (RFC 3501) SEARCH and UID SEARCH commands
+   with several result options, which can control what kind of
+   information is returned. The following result options are defined:
+   minimal value, maximal value, all found messages, and number of found
+   messages.
+
+Table of Contents
+
+   1. Introduction ....................................................2
+   2. Conventions Used in This Document ...............................2
+   3. IMAP Protocol Changes ...........................................2
+      3.1. New SEARCH/UID SEARCH Result Options .......................2
+      3.2. Interaction with CONDSTORE extension .......................4
+   4. Formal Syntax ...................................................5
+   5. Security Considerations .........................................6
+   6. IANA Considerations .............................................6
+   7. Normative References ............................................6
+   8. Acknowledgments .................................................6
+
+
+
+
+
+
+
+
+
+Melnikov & Cridland         Standards Track                     [Page 1]
+
+RFC 4731               IMAP4 Extension to SEARCH           November 2006
+
+
+1.  Introduction
+
+   [IMAPABNF] extended SEARCH and UID SEARCH commands with result
+   specifiers (also known as result options), which can control what
+   kind of information is returned.
+
+   A server advertising the ESEARCH capability supports the following
+   result options:  minimal value, maximal value, all found messages,
+   and number of found messages.  These result options allow clients to
+   get SEARCH results in more convenient forms, while also saving
+   bandwidth required to transport the results, for example, by finding
+   the first unseen message or returning the number of unseen or deleted
+   messages.  Also, when a single MIN or a single MAX result option is
+   specified, servers can optimize execution of SEARCHes.
+
+2.  Conventions Used in This Document
+
+   In examples, "C:" and "S:" indicate lines sent by the client and
+   server, respectively.
+
+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+   document are to be interpreted as described in RFC 2119 [KEYWORDS].
+
+3.   IMAP Protocol Changes
+
+3.1.  New SEARCH/UID SEARCH Result Options
+
+   The SEARCH/UID SEARCH commands are extended to allow for the
+   following result options:
+
+      MIN
+         Return the lowest message number/UID that satisfies the SEARCH
+         criteria.
+
+         If the SEARCH results in no matches, the server MUST NOT
+         include the MIN result option in the ESEARCH response; however,
+         it still MUST send the ESEARCH response.
+
+      MAX
+         Return the highest message number/UID that satisfies the SEARCH
+         criteria.
+
+         If the SEARCH results in no matches, the server MUST NOT
+         include the MAX result option in the ESEARCH response; however,
+         it still MUST send the ESEARCH response.
+
+
+
+
+
+Melnikov & Cridland         Standards Track                     [Page 2]
+
+RFC 4731               IMAP4 Extension to SEARCH           November 2006
+
+
+      ALL
+         Return all message numbers/UIDs that satisfy the SEARCH
+         criteria.  Unlike regular (unextended) SEARCH, the messages are
+         always returned using the sequence-set syntax.  A sequence-set
+         representation may be more compact and can be used as is in a
+         subsequent command that accepts sequence-set.  Note, the client
+         MUST NOT assume that messages/UIDs will be listed in any
+         particular order.
+
+         If the SEARCH results in no matches, the server MUST NOT
+         include the ALL result option in the ESEARCH response; however,
+         it still MUST send the ESEARCH response.
+
+      COUNT
+         Return number of the messages that satisfy the SEARCH criteria.
+         This result option MUST always be included in the ESEARCH
+         response.
+
+   If one or more result options described above are specified, the
+   extended SEARCH command MUST return a single ESEARCH response
+   [IMAPABNF], instead of the SEARCH response.
+
+   An extended UID SEARCH command MUST cause an ESEARCH response with
+   the UID indicator present.
+
+   Note that future extensions to this document can allow servers to
+   return multiple ESEARCH responses for a single extended SEARCH
+   command.  These extensions will have to describe how results from
+   multiple ESEARCH responses are to be amalgamated.
+
+   If the list of result options is empty, that requests the server to
+   return an ESEARCH response instead of the SEARCH response.  This is
+   equivalent to "(ALL)".
+
+      Example:    C: A282 SEARCH RETURN (MIN COUNT) FLAGGED
+                     SINCE 1-Feb-1994 NOT FROM "Smith"
+                  S: * ESEARCH (TAG "A282") MIN 2 COUNT 3
+                  S: A282 OK SEARCH completed
+
+      Example:    C: A283 SEARCH RETURN () FLAGGED
+                     SINCE 1-Feb-1994 NOT FROM "Smith"
+                  S: * ESEARCH (TAG "A283") ALL 2,10:11
+                  S: A283 OK SEARCH completed
+
+   The following example demonstrates finding the first unseen message
+   as returned in the UNSEEN response code on a successful SELECT
+   command:
+
+
+
+
+Melnikov & Cridland         Standards Track                     [Page 3]
+
+RFC 4731               IMAP4 Extension to SEARCH           November 2006
+
+
+      Example:    C: A284 SEARCH RETURN (MIN) UNSEEN
+                  S: * ESEARCH (TAG "A284") MIN 4
+                  S: A284 OK SEARCH completed
+
+   The following example demonstrates that if the ESEARCH UID indicator
+   is present, all data in the ESEARCH response is referring to UIDs;
+   for example, the MIN result specifier will be followed by a UID.
+
+      Example:    C: A285 UID SEARCH RETURN (MIN MAX) 1:5000
+                  S: * ESEARCH (TAG "A285") UID MIN 7 MAX 3800
+                  S: A285 OK SEARCH completed
+
+   The following example demonstrates returning the number of deleted
+   messages:
+
+      Example:    C: A286 SEARCH RETURN (COUNT) DELETED
+                  S: * ESEARCH (TAG "A286") COUNT 15
+                  S: A286 OK SEARCH completed
+
+3.2.  Interaction with CONDSTORE extension
+
+   When the server supports both the ESEARCH and the CONDSTORE
+   [CONDSTORE] extension, and the client requests one or more result
+   option described in section 3.1 together with the MODSEQ search
+   criterion in the same SEARCH/UID SEARCH command, then the server MUST
+   return the ESEARCH response containing the MODSEQ result option
+   (described in the following paragraph) instead of the extended SEARCH
+   response described in section 3.5 of [CONDSTORE].
+
+   If the SEARCH/UID SEARCH command contained a single MIN or MAX result
+   option, the MODSEQ result option contains the mod-sequence for the
+   found message.  If the SEARCH/UID SEARCH command contained both MIN
+   and MAX result options and no ALL/COUNT option, the MODSEQ result
+   option contains the highest mod-sequence for the two returned
+   messages.  Otherwise the MODSEQ result option contains the highest
+   mod-sequence for all messages being returned.
+
+   Example: The following example demonstrates how Example 15 from
+   [CONDSTORE] would look in the presence of one or more result option:
+
+         C: a1 SEARCH RETURN (MIN) MODSEQ "/flags/\\draft"
+             all 620162338
+         S: * ESEARCH (TAG "a1") MIN 2 MODSEQ 917162488
+         S: a1 OK Search complete
+
+         C: a2 SEARCH RETURN (MAX) MODSEQ "/flags/\\draft"
+             all 620162338
+         S: * ESEARCH (TAG "a2") MAX 23 MODSEQ 907162321
+
+
+
+Melnikov & Cridland         Standards Track                     [Page 4]
+
+RFC 4731               IMAP4 Extension to SEARCH           November 2006
+
+
+         S: a2 OK Search complete
+
+         C: a3 SEARCH RETURN (MIN MAX) MODSEQ "/flags/\\draft"
+             all 620162338
+         S: * ESEARCH (TAG "a3") MIN 2 MAX 23 MODSEQ 917162488
+         S: a3 OK Search complete
+
+         C: a4 SEARCH RETURN (MIN COUNT) MODSEQ "/flags/\\draft"
+             all 620162338
+         S: * ESEARCH (TAG "a4") MIN 2 COUNT 10 MODSEQ 917162500
+         S: a4 OK Search complete
+
+4.  Formal Syntax
+
+   The following syntax specification uses the Augmented Backus-Naur
+   Form (ABNF) notation as specified in [ABNF].
+
+   Non-terminals referenced but not defined below are as defined by
+   [IMAP4], [CONDSTORE], or [IMAPABNF].
+
+   Except as noted otherwise, all alphabetic characters are case-
+   insensitive.  The use of upper or lowercase characters to define
+   token strings is for editorial clarity only.  Implementations MUST
+   accept these strings in a case-insensitive fashion.
+
+     capability         =/ "ESEARCH"
+
+     search-return-data = "MIN" SP nz-number /
+                          "MAX" SP nz-number /
+                          "ALL" SP sequence-set /
+                          "COUNT" SP number
+                          ;; conforms to the generic
+                          ;; search-return-data syntax defined
+                          ;; in [IMAPABNF]
+
+     search-return-opt  = "MIN" / "MAX" / "ALL" / "COUNT"
+                          ;; conforms to generic search-return-opt
+                          ;; syntax defined in [IMAPABNF]
+
+     When the CONDSTORE [CONDSTORE] IMAP extension is also supported,
+     the ABNF is updated as follows:
+
+     search-return-data =/ "MODSEQ" SP mod-sequence-value
+                          ;; mod-sequence-value is defined
+                          ;; in [CONDSTORE]
+
+
+
+
+
+
+Melnikov & Cridland         Standards Track                     [Page 5]
+
+RFC 4731               IMAP4 Extension to SEARCH           November 2006
+
+
+5.  Security Considerations
+
+   In the general case, the IMAP SEARCH/UID SEARCH commands can be CPU
+   and/or IO intensive, and are seen by some as a potential attack point
+   for denial of service attacks, so some sites/implementations even
+   disable them entirely.  This is quite unfortunate, as SEARCH command
+   is one of the best examples demonstrating IMAP advantage over POP3.
+
+   The ALL and COUNT return options don't change how SEARCH is working
+   internally; they only change how information about found messages is
+   returned.  MIN and MAX SEARCH result options described in this
+   document can lighten the load on IMAP servers that choose to optimize
+   SEARCHes containing only one or both of them.
+
+   It is believed that this extension doesn't raise any additional
+   security concerns not already discussed in [IMAP4].
+
+6.  IANA Considerations
+
+   IMAP4 capabilities are registered by publishing a standards track RFC
+   or an IESG-approved experimental RFC.  The registry is currently
+   located at <http://www.iana.org/assignments/imap4-capabilities>.
+
+   This document defines the ESEARCH IMAP capability, which IANA added
+   to the registry.
+
+7.  Normative References
+
+   [KEYWORDS]  Bradner, S., "Key words for use in RFCs to Indicate
+               Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+   [IMAP4]     Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
+               4rev1", RFC 3501, March 2003.
+
+   [ABNF]      Crocker, D. (Ed.) and P. Overell , "Augmented BNF for
+               Syntax Specifications: ABNF", RFC 4234, October 2005.
+
+   [IMAPABNF]  Melnikov, A. and C. Daboo, "Collected Extensions to IMAP4
+               ABNF", RFC 4466, April 2006..
+
+   [CONDSTORE] Melnikov, A. and S. Hole, "IMAP Extension for Conditional
+               STORE", RFC 4551, June 2006.
+
+8.  Acknowledgments
+
+   Thanks to Michael Wener, Arnt Gulbrandsen, Cyrus Daboo, Mark Crispin,
+   and Pete Maclean for comments and corrections.
+
+
+
+
+Melnikov & Cridland         Standards Track                     [Page 6]
+
+RFC 4731               IMAP4 Extension to SEARCH           November 2006
+
+
+Authors' Addresses
+
+   Alexey Melnikov
+   Isode Limited
+   5 Castle Business Village
+   36 Station Road
+   Hampton, Middlesex, TW12 2BX
+   UK
+
+   EMail: Alexey.Melnikov@isode.com
+
+
+   Dave A. Cridland
+   Inventure Systems Limited
+
+   EMail: dave.cridland@inventuresystems.co.uk
+   URL: http://invsys.co.uk/dave/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov & Cridland         Standards Track                     [Page 7]
+
+RFC 4731               IMAP4 Extension to SEARCH           November 2006
+
+
+Full Copyright Statement
+
+   Copyright (C) The IETF Trust (2006).
+
+   This document is subject to the rights, licenses and restrictions
+   contained in BCP 78, and except as set forth therein, the authors
+   retain all their rights.
+
+   This document and the information contained herein are provided on an
+   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST,
+   AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT
+   THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY
+   IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
+   PURPOSE.
+
+Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   Intellectual Property Rights or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; nor does it represent that it has
+   made any independent effort to identify any such rights.  Information
+   on the procedures with respect to rights in RFC documents can be
+   found in BCP 78 and BCP 79.
+
+   Copies of IPR disclosures made to the IETF Secretariat and any
+   assurances of licenses to be made available, or the result of an
+   attempt made to obtain a general license or permission for the use of
+   such proprietary rights by implementers or users of this
+   specification can be obtained from the IETF on-line IPR repository at
+   http://www.ietf.org/ipr.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights that may cover technology that may be required to implement
+   this standard.  Please address the information to the IETF at
+   ietf-ipr@ietf.org.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is currently provided by the
+   Internet Society.
+
+
+
+
+
+
+Melnikov & Cridland         Standards Track                     [Page 8]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc4752.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,563 @@
+
+
+
+
+
+
+Network Working Group                                   A. Melnikov, Ed.
+Request for Comments: 4752                                         Isode
+Obsoletes: 2222                                            November 2006
+Category: Standards Track
+
+
+                       The Kerberos V5 ("GSSAPI")
+       Simple Authentication and Security Layer (SASL) Mechanism
+
+Status of This Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The IETF Trust (2006).
+
+Abstract
+
+   The Simple Authentication and Security Layer (SASL) is a framework
+   for adding authentication support to connection-based protocols.
+   This document describes the method for using the Generic Security
+   Service Application Program Interface (GSS-API) Kerberos V5 in the
+   SASL.
+
+   This document replaces Section 7.2 of RFC 2222, the definition of the
+   "GSSAPI" SASL mechanism.  This document, together with RFC 4422,
+   obsoletes RFC 2222.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov                    Standards Track                     [Page 1]
+
+RFC 4752                 SASL GSSAPI Mechanism             November 2006
+
+
+Table of Contents
+
+   1. Introduction ....................................................2
+      1.1. Relationship to Other Documents ............................2
+   2. Conventions Used in This Document ...............................2
+   3. Kerberos V5 GSS-API Mechanism ...................................2
+      3.1. Client Side of Authentication Protocol Exchange ............3
+      3.2. Server Side of Authentication Protocol Exchange ............4
+      3.3. Security Layer .............................................6
+   4. IANA Considerations .............................................7
+   5. Security Considerations .........................................7
+   6. Acknowledgements ................................................8
+   7. Changes since RFC 2222 ..........................................8
+   8. References ......................................................8
+      8.1. Normative References .......................................8
+      8.2. Informative References .....................................9
+
+1.  Introduction
+
+   This specification documents currently deployed Simple Authentication
+   and Security Layer (SASL [SASL]) mechanism supporting the Kerberos V5
+   [KERBEROS] Generic Security Service Application Program Interface
+   ([GSS-API]) mechanism [RFC4121].  The authentication sequence is
+   described in Section 3.  Note that the described authentication
+   sequence has known limitations, in particular, it lacks channel
+   bindings and the number of round-trips required to complete
+   authentication exchange is not minimal.  SASL WG is working on a
+   separate document that should address these limitations.
+
+1.1.  Relationship to Other Documents
+
+   This document, together with RFC 4422, obsoletes RFC 2222 in its
+   entirety.  This document replaces Section 7.2 of RFC 2222.  The
+   remainder is obsoleted as detailed in Section 1.2 of RFC 4422.
+
+2.  Conventions Used in This Document
+
+   The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY"
+   in this document are to be interpreted as defined in "Key words for
+   use in RFCs to Indicate Requirement Levels" [KEYWORDS].
+
+3.  Kerberos V5 GSS-API Mechanism
+
+   The SASL mechanism name for the Kerberos V5 GSS-API mechanism
+   [RFC4121] is "GSSAPI".  Though known as the SASL GSSAPI mechanism,
+   the mechanism is specifically tied to Kerberos V5 and GSS-API's
+   Kerberos V5 mechanism.
+
+
+
+
+Melnikov                    Standards Track                     [Page 2]
+
+RFC 4752                 SASL GSSAPI Mechanism             November 2006
+
+
+   The GSSAPI SASL mechanism is a "client goes first" SASL mechanism;
+   i.e., it starts with the client sending a "response" created as
+   described in the following section.
+
+   The implementation MAY set any GSS-API flags or arguments not
+   mentioned in this specification as is necessary for the
+   implementation to enforce its security policy.
+
+   Note that major status codes returned by GSS_Init_sec_context() or
+   GSS_Accept_sec_context() other than GSS_S_COMPLETE or
+   GSS_S_CONTINUE_NEEDED cause authentication failure.  Major status
+   codes returned by GSS_Unwrap() other than GSS_S_COMPLETE (without any
+   additional supplementary status codes) cause authentication and/or
+   security layer failure.
+
+3.1.  Client Side of Authentication Protocol Exchange
+
+   The client calls GSS_Init_sec_context, passing in
+   input_context_handle of 0 (initially), mech_type of the Kerberos V5
+   GSS-API mechanism [KRB5GSS], chan_binding of NULL, and targ_name
+   equal to output_name from GSS_Import_Name called with input_name_type
+   of GSS_C_NT_HOSTBASED_SERVICE (*) and input_name_string of
+   "service@hostname" where "service" is the service name specified in
+   the protocol's profile, and "hostname" is the fully qualified host
+   name of the server.  When calling the GSS_Init_sec_context, the
+   client MUST pass the integ_req_flag of TRUE (**).  If the client will
+   be requesting a security layer, it MUST also supply to the
+   GSS_Init_sec_context a mutual_req_flag of TRUE, and a
+   sequence_req_flag of TRUE.  If the client will be requesting a
+   security layer providing confidentiality protection, it MUST also
+   supply to the GSS_Init_sec_context a conf_req_flag of TRUE.  The
+   client then responds with the resulting output_token.  If
+   GSS_Init_sec_context returns GSS_S_CONTINUE_NEEDED, then the client
+   should expect the server to issue a token in a subsequent challenge.
+   The client must pass the token to another call to
+   GSS_Init_sec_context, repeating the actions in this paragraph.
+
+   (*) Clients MAY use name types other than GSS_C_NT_HOSTBASED_SERVICE
+   to import servers' acceptor names, but only when they have a priori
+   knowledge that the servers support alternate name types.  Otherwise
+   clients MUST use GSS_C_NT_HOSTBASED_SERVICE for importing acceptor
+   names.
+
+   (**) Note that RFC 2222 [RFC2222] implementations will not work with
+   GSS-API implementations that require integ_req_flag to be true.  No
+   implementations of RFC 1964 [KRB5GSS] or RFC 4121 [RFC4121] that
+   require integ_req_flag to be true are believed to exist and it is
+   expected that any future update to [RFC4121] will require that
+
+
+
+Melnikov                    Standards Track                     [Page 3]
+
+RFC 4752                 SASL GSSAPI Mechanism             November 2006
+
+
+   integrity be available even in not explicitly requested by the
+   application.
+
+   When GSS_Init_sec_context returns GSS_S_COMPLETE, the client examines
+   the context to ensure that it provides a level of protection
+   permitted by the client's security policy.  In particular, if the
+   integ_avail flag is not set in the context, then no security layer
+   can be offered or accepted.
+
+   If the conf_avail flag is not set in the context, then no security
+   layer with confidentiality can be offered or accepted.  If the
+   context is acceptable, the client takes the following actions: If the
+   last call to GSS_Init_sec_context returned an output_token, then the
+   client responds with the output_token, otherwise the client responds
+   with no data.  The client should then expect the server to issue a
+   token in a subsequent challenge.  The client passes this token to
+   GSS_Unwrap and interprets the first octet of resulting cleartext as a
+   bit-mask specifying the security layers supported by the server and
+   the second through fourth octets as the maximum size output_message
+   the server is able to receive (in network byte order).  If the
+   resulting cleartext is not 4 octets long, the client fails the
+   negotiation.  The client verifies that the server maximum buffer is 0
+   if the server does not advertise support for any security layer.
+
+   The client then constructs data, with the first octet containing the
+   bit-mask specifying the selected security layer, the second through
+   fourth octets containing in network byte order the maximum size
+   output_message the client is able to receive (which MUST be 0 if the
+   client does not support any security layer), and the remaining octets
+   containing the UTF-8 [UTF8] encoded authorization identity.
+   (Implementation note: The authorization identity is not terminated
+   with the zero-valued (%x00) octet (e.g., the UTF-8 encoding of the
+   NUL (U+0000) character)).  The client passes the data to GSS_Wrap
+   with conf_flag set to FALSE and responds with the generated
+   output_message.  The client can then consider the server
+   authenticated.
+
+3.2.  Server Side of Authentication Protocol Exchange
+
+   A server MUST NOT advertise support for the "GSSAPI" SASL mechanism
+   described in this document unless it has acceptor credential for the
+   Kerberos V GSS-API mechanism [KRB5GSS].
+
+   The server passes the initial client response to
+   GSS_Accept_sec_context as input_token, setting input_context_handle
+   to 0 (initially), chan_binding of NULL, and a suitable
+   acceptor_cred_handle (see below).  If GSS_Accept_sec_context returns
+   GSS_S_CONTINUE_NEEDED, the server returns the generated output_token
+
+
+
+Melnikov                    Standards Track                     [Page 4]
+
+RFC 4752                 SASL GSSAPI Mechanism             November 2006
+
+
+   to the client in challenge and passes the resulting response to
+   another call to GSS_Accept_sec_context, repeating the actions in this
+   paragraph.
+
+   Servers SHOULD use a credential obtained by calling GSS_Acquire_cred
+   or GSS_Add_cred for the GSS_C_NO_NAME desired_name and the Object
+   Identifier (OID) of the Kerberos V5 GSS-API mechanism [KRB5GSS](*).
+   Servers MAY use GSS_C_NO_CREDENTIAL as an acceptor credential handle.
+   Servers MAY use a credential obtained by calling GSS_Acquire_cred or
+   GSS_Add_cred for the server's principal name(s) (**) and the Kerberos
+   V5 GSS-API mechanism [KRB5GSS].
+
+   (*) Unlike GSS_Add_cred the GSS_Acquire_cred uses an OID set of GSS-
+   API mechanism as an input parameter.  The OID set can be created by
+   using GSS_Create_empty_OID_set and GSS_Add_OID_set_member.  It can be
+   freed by calling the GSS_Release_oid_set.
+
+
+   (**) Use of server's principal names having
+   GSS_C_NT_HOSTBASED_SERVICE name type and "service@hostname" format,
+   where "service" is the service name specified in the protocol's
+   profile, and "hostname" is the fully qualified host name of the
+   server, is RECOMMENDED.  The server name is generated by calling
+   GSS_Import_name with input_name_type of GSS_C_NT_HOSTBASED_SERVICE
+   and input_name_string of "service@hostname".
+
+   Upon successful establishment of the security context (i.e.,
+   GSS_Accept_sec_context returns GSS_S_COMPLETE), the server SHOULD
+   verify that the negotiated GSS-API mechanism is indeed Kerberos V5
+   [KRB5GSS].  This is done by examining the value of the mech_type
+   parameter returned from the GSS_Accept_sec_context call.  If the
+   value differs, SASL authentication MUST be aborted.
+
+   Upon successful establishment of the security context and if the
+   server used GSS_C_NO_NAME/GSS_C_NO_CREDENTIAL to create acceptor
+   credential handle, the server SHOULD also check using the
+   GSS_Inquire_context that the target_name used by the client matches
+   either
+
+   -  the GSS_C_NT_HOSTBASED_SERVICE "service@hostname" name syntax,
+      where "service" is the service name specified in the application
+      protocol's profile,
+
+      or
+
+   -  the GSS_KRB5_NT_PRINCIPAL_NAME [KRB5GSS] name syntax for a two-
+      component principal where the first component matches the service
+      name specified in the application protocol's profile.
+
+
+
+Melnikov                    Standards Track                     [Page 5]
+
+RFC 4752                 SASL GSSAPI Mechanism             November 2006
+
+
+   When GSS_Accept_sec_context returns GSS_S_COMPLETE, the server
+   examines the context to ensure that it provides a level of protection
+   permitted by the server's security policy.  In particular, if the
+   integ_avail flag is not set in the context, then no security layer
+   can be offered or accepted.  If the conf_avail flag is not set in the
+   context, then no security layer with confidentiality can be offered
+   or accepted.
+
+   If the context is acceptable, the server takes the following actions:
+   If the last call to GSS_Accept_sec_context returned an output_token,
+   the server returns it to the client in a challenge and expects a
+   reply from the client with no data.  Whether or not an output_token
+   was returned (and after receipt of any response from the client to
+   such an output_token), the server then constructs 4 octets of data,
+   with the first octet containing a bit-mask specifying the security
+   layers supported by the server and the second through fourth octets
+   containing in network byte order the maximum size output_token the
+   server is able to receive (which MUST be 0 if the server does not
+   support any security layer).  The server must then pass the plaintext
+   to GSS_Wrap with conf_flag set to FALSE and issue the generated
+   output_message to the client in a challenge.
+
+   The server must then pass the resulting response to GSS_Unwrap and
+   interpret the first octet of resulting cleartext as the bit-mask for
+   the selected security layer, the second through fourth octets as the
+   maximum size output_message the client is able to receive (in network
+   byte order), and the remaining octets as the authorization identity.
+   The server verifies that the client has selected a security layer
+   that was offered and that the client maximum buffer is 0 if no
+   security layer was chosen.  The server must verify that the src_name
+   is authorized to act as the authorization identity.  After these
+   verifications, the authentication process is complete.  The server is
+   not expected to return any additional data with the success
+   indicator.
+
+3.3.  Security Layer
+
+   The security layers and their corresponding bit-masks are as follows:
+
+          1 No security layer
+          2 Integrity protection.
+            Sender calls GSS_Wrap with conf_flag set to FALSE
+          4 Confidentiality protection.
+            Sender calls GSS_Wrap with conf_flag set to TRUE
+
+   Other bit-masks may be defined in the future; bits that are not
+   understood must be negotiated off.
+
+
+
+
+Melnikov                    Standards Track                     [Page 6]
+
+RFC 4752                 SASL GSSAPI Mechanism             November 2006
+
+
+   When decoding any received data with GSS_Unwrap, the major_status
+   other than the GSS_S_COMPLETE MUST be treated as a fatal error.
+
+   Note that SASL negotiates the maximum size of the output_message to
+   send.  Implementations can use the GSS_Wrap_size_limit call to
+   determine the corresponding maximum size input_message.
+
+4.  IANA Considerations
+
+   IANA modified the existing registration for "GSSAPI" as follows:
+
+   Family of SASL mechanisms:  NO
+
+   SASL mechanism name:  GSSAPI
+
+   Security considerations:  See Section 5 of RFC 4752
+
+   Published specification:  RFC 4752
+
+   Person & email address to contact for further information:
+      Alexey Melnikov <Alexey.Melnikov@isode.com>
+
+   Intended usage:  COMMON
+
+   Owner/Change controller:  iesg@ietf.org
+
+   Additional information:  This mechanism is for the Kerberos V5
+      mechanism of GSS-API.
+
+5.  Security Considerations
+
+   Security issues are discussed throughout this memo.
+
+   When constructing the input_name_string, the client SHOULD NOT
+   canonicalize the server's fully qualified domain name using an
+   insecure or untrusted directory service.
+
+   For compatibility with deployed software, this document requires that
+   the chan_binding (channel bindings) parameter to GSS_Init_sec_context
+   and GSS_Accept_sec_context be NULL, hence disallowing use of GSS-API
+   support for channel bindings.  GSS-API channel bindings in SASL is
+   expected to be supported via a new GSS-API family of SASL mechanisms
+   (to be introduced in a future document).
+
+   Additional security considerations are in the [SASL] and [GSS-API]
+   specifications.  Additional security considerations for the GSS-API
+   mechanism can be found in [KRB5GSS] and [KERBEROS].
+
+
+
+
+Melnikov                    Standards Track                     [Page 7]
+
+RFC 4752                 SASL GSSAPI Mechanism             November 2006
+
+
+6.  Acknowledgements
+
+   This document replaces Section 7.2 of RFC 2222 [RFC2222] by John G.
+   Myers.  He also contributed significantly to this revision.
+
+   Lawrence Greenfield converted text of this document to the XML
+   format.
+
+   Contributions of many members of the SASL mailing list are gratefully
+   acknowledged, in particular comments from Chris Newman, Nicolas
+   Williams, Jeffrey Hutzelman, Sam Hartman, Mark Crispin, and Martin
+   Rex.
+
+7.  Changes since RFC 2222
+
+   RFC 2078 [RFC2078] specifies the version of GSS-API used by RFC 2222
+   [RFC2222], which provided the original version of this specification.
+   That version of GSS-API did not provide the integ_integ_avail flag as
+   an input to GSS_Init_sec_context.  Instead, integrity was always
+   requested.  RFC 4422 [SASL] requires that when possible, the security
+   layer negotiation be integrity protected.  To meet this requirement
+   and as part of moving from RFC 2078 [RFC2078] to RFC 2743 [GSS-API],
+   this specification requires that clients request integrity from
+   GSS_Init_sec_context so they can use GSS_Wrap to protect the security
+   layer negotiation.  This specification does not require that the
+   mechanism offer the integrity security layer, simply that the
+   security layer negotiation be wrapped.
+
+8.  References
+
+8.1.  Normative References
+
+   [GSS-API]  Linn, J., "Generic Security Service Application Program
+              Interface Version 2, Update 1", RFC 2743, January 2000.
+
+   [KERBEROS] Neuman, C., Yu, T., Hartman, S., and K. Raeburn, "The
+              Kerberos Network Authentication Service (V5)", RFC 4120,
+              July 2005.
+
+   [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate
+              Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+   [KRB5GSS]  Linn, J., "The Kerberos Version 5 GSS-API Mechanism", RFC
+              1964, June 1996.
+
+
+
+
+
+
+
+Melnikov                    Standards Track                     [Page 8]
+
+RFC 4752                 SASL GSSAPI Mechanism             November 2006
+
+
+   [RFC4121]  Zhu, L., Jaganathan, K., and S. Hartman, "The Kerberos
+              Version 5 Generic Security Service Application Program
+              Interface (GSS-API) Mechanism: Version 2", RFC 4121, July
+              2005.
+
+   [SASL]     Melnikov, A. and  K. Zeilenga, "Simple Authentication and
+              Security Layer (SASL)", RFC 4422, June 2006.
+
+   [UTF8]     Yergeau, F., "UTF-8, a transformation format of ISO
+              10646", STD 63, RFC 3629, November 2003.
+
+8.2.  Informative References
+
+   [RFC2078]  Linn, J., "Generic Security Service Application Program
+              Interface, Version 2", RFC 2078, January 1997.
+
+   [RFC2222]  Myers, J., "Simple Authentication and Security Layer
+              (SASL)", RFC 2222, October 1997.
+
+Editor's Address
+
+   Alexey Melnikov
+   Isode Limited
+   5 Castle Business Village
+   36 Station Road
+   Hampton, Middlesex  TW12 2BX
+   UK
+
+   EMail: Alexey.Melnikov@isode.com
+   URI:   http://www.melnikov.ca/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov                    Standards Track                     [Page 9]
+
+RFC 4752                 SASL GSSAPI Mechanism             November 2006
+
+
+Full Copyright Statement
+
+   Copyright (C) The IETF Trust (2006).
+
+   This document is subject to the rights, licenses and restrictions
+   contained in BCP 78, and except as set forth therein, the authors
+   retain all their rights.
+
+   This document and the information contained herein are provided on an
+   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST,
+   AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT
+   THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY
+   IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
+   PURPOSE.
+
+Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   Intellectual Property Rights or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; nor does it represent that it has
+   made any independent effort to identify any such rights.  Information
+   on the procedures with respect to rights in RFC documents can be
+   found in BCP 78 and BCP 79.
+
+   Copies of IPR disclosures made to the IETF Secretariat and any
+   assurances of licenses to be made available, or the result of an
+   attempt made to obtain a general license or permission for the use of
+   such proprietary rights by implementers or users of this
+   specification can be obtained from the IETF on-line IPR repository at
+   http://www.ietf.org/ipr.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights that may cover technology that may be required to implement
+   this standard.  Please address the information to the IETF at
+   ietf-ipr@ietf.org.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is currently provided by the
+   Internet Society.
+
+
+
+
+
+
+Melnikov                    Standards Track                    [Page 10]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc4790.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1459 @@
+
+
+
+
+
+
+Network Working Group                                          C. Newman
+Request for Comments: 4790                              Sun Microsystems
+Category: Standards Track                                      M. Duerst
+                                                Aoyama Gakuin University
+                                                          A. Gulbrandsen
+                                                                    Oryx
+                                                              March 2007
+
+
+            Internet Application Protocol Collation Registry
+
+Status of This Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Copyright Notice
+
+   Copyright (C) The IETF Trust (2007).
+
+Abstract
+
+   Many Internet application protocols include string-based lookup,
+   searching, or sorting operations.  However, the problem space for
+   searching and sorting international strings is large, not fully
+   explored, and is outside the area of expertise for the Internet
+   Engineering Task Force (IETF).  Rather than attempt to solve such a
+   large problem, this specification creates an abstraction framework so
+   that application protocols can precisely identify a comparison
+   function, and the repertoire of comparison functions can be extended
+   in the future.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Newman, et al.              Standards Track                     [Page 1]
+
+RFC 4790                   Collation Registry                 March 2007
+
+
+Table of Contents
+
+   1.  Introduction . . . . . . . . . . . . . . . . . . . . . . . . .  4
+     1.1.  Conventions Used in This Document  . . . . . . . . . . . .  4
+   2.  Collation Definition and Purpose . . . . . . . . . . . . . . .  4
+     2.1.  Definition . . . . . . . . . . . . . . . . . . . . . . . .  4
+     2.2.  Purpose  . . . . . . . . . . . . . . . . . . . . . . . . .  4
+     2.3.  Some Other Terms Used in this Document . . . . . . . . . .  5
+     2.4.  Sort Keys  . . . . . . . . . . . . . . . . . . . . . . . .  5
+   3.  Collation Identifier Syntax  . . . . . . . . . . . . . . . . .  6
+     3.1.  Basic Syntax . . . . . . . . . . . . . . . . . . . . . . .  6
+     3.2.  Wildcards  . . . . . . . . . . . . . . . . . . . . . . . .  6
+     3.3.  Ordering Direction . . . . . . . . . . . . . . . . . . . .  7
+     3.4.  URIs . . . . . . . . . . . . . . . . . . . . . . . . . . .  7
+     3.5.  Naming Guidelines  . . . . . . . . . . . . . . . . . . . .  7
+   4.  Collation Specification Requirements . . . . . . . . . . . . .  8
+     4.1.  Collation/Server Interface . . . . . . . . . . . . . . . .  8
+     4.2.  Operations Supported . . . . . . . . . . . . . . . . . . .  8
+       4.2.1.  Validity . . . . . . . . . . . . . . . . . . . . . . .  9
+       4.2.2.  Equality . . . . . . . . . . . . . . . . . . . . . . .  9
+       4.2.3.  Substring  . . . . . . . . . . . . . . . . . . . . . .  9
+       4.2.4.  Ordering . . . . . . . . . . . . . . . . . . . . . . . 10
+     4.3.  Sort Keys  . . . . . . . . . . . . . . . . . . . . . . . . 10
+     4.4.  Use of Lookup Tables . . . . . . . . . . . . . . . . . . . 11
+   5.  Application Protocol Requirements  . . . . . . . . . . . . . . 11
+     5.1.  Character Encoding . . . . . . . . . . . . . . . . . . . . 11
+     5.2.  Operations . . . . . . . . . . . . . . . . . . . . . . . . 11
+     5.3.  Wildcards  . . . . . . . . . . . . . . . . . . . . . . . . 12
+     5.4.  String Comparison  . . . . . . . . . . . . . . . . . . . . 12
+     5.5.  Disconnected Clients . . . . . . . . . . . . . . . . . . . 12
+     5.6.  Error Codes  . . . . . . . . . . . . . . . . . . . . . . . 13
+     5.7.  Octet Collation  . . . . . . . . . . . . . . . . . . . . . 13
+   6.  Use by Existing Protocols  . . . . . . . . . . . . . . . . . . 13
+   7.  Collation Registration . . . . . . . . . . . . . . . . . . . . 14
+     7.1.  Collation Registration Procedure . . . . . . . . . . . . . 14
+     7.2.  Collation Registration Format  . . . . . . . . . . . . . . 15
+       7.2.1.  Registration Template  . . . . . . . . . . . . . . . . 15
+       7.2.2.  The Collation Element  . . . . . . . . . . . . . . . . 15
+       7.2.3.  The Identifier Element . . . . . . . . . . . . . . . . 16
+       7.2.4.  The Title Element  . . . . . . . . . . . . . . . . . . 16
+       7.2.5.  The Operations Element . . . . . . . . . . . . . . . . 16
+       7.2.6.  The Specification Element  . . . . . . . . . . . . . . 16
+       7.2.7.  The Submitter Element  . . . . . . . . . . . . . . . . 16
+       7.2.8.  The Owner Element  . . . . . . . . . . . . . . . . . . 16
+       7.2.9.  The Version Element  . . . . . . . . . . . . . . . . . 17
+       7.2.10. The Variable Element . . . . . . . . . . . . . . . . . 17
+     7.3.  Structure of Collation Registry  . . . . . . . . . . . . . 17
+     7.4.  Example Initial Registry Summary . . . . . . . . . . . . . 18
+
+
+
+Newman, et al.              Standards Track                     [Page 2]
+
+RFC 4790                   Collation Registry                 March 2007
+
+
+   8.  Guidelines for Expert Reviewer . . . . . . . . . . . . . . . . 18
+   9.  Initial Collations . . . . . . . . . . . . . . . . . . . . . . 19
+     9.1.  ASCII Numeric Collation  . . . . . . . . . . . . . . . . . 20
+       9.1.1.  ASCII Numeric Collation Description  . . . . . . . . . 20
+       9.1.2.  ASCII Numeric Collation Registration . . . . . . . . . 20
+     9.2.  ASCII Casemap Collation  . . . . . . . . . . . . . . . . . 21
+       9.2.1.  ASCII Casemap Collation Description  . . . . . . . . . 21
+       9.2.2.  ASCII Casemap Collation Registration . . . . . . . . . 22
+     9.3.  Octet Collation  . . . . . . . . . . . . . . . . . . . . . 22
+       9.3.1.  Octet Collation Description  . . . . . . . . . . . . . 22
+       9.3.2.  Octet Collation Registration . . . . . . . . . . . . . 23
+   10. IANA Considerations  . . . . . . . . . . . . . . . . . . . . . 23
+   11. Security Considerations  . . . . . . . . . . . . . . . . . . . 23
+   12. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 23
+   13. References . . . . . . . . . . . . . . . . . . . . . . . . . . 24
+     13.1. Normative References . . . . . . . . . . . . . . . . . . . 24
+     13.2. Informative References . . . . . . . . . . . . . . . . . . 24
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Newman, et al.              Standards Track                     [Page 3]
+
+RFC 4790                   Collation Registry                 March 2007
+
+
+1.  Introduction
+
+   The Application Configuration Access Protocol ACAP [11] specification
+   introduced the concept of a comparator (which we call collation in
+   this document), but failed to create an IANA registry.  With the
+   introduction of stringprep [6] and the Unicode Collation Algorithm
+   [7], it is now time to create that registry and populate it with some
+   initial values appropriate for an international community.  This
+   specification replaces and generalizes the definition of a comparator
+   in ACAP, and creates a collation registry.
+
+1.1.  Conventions Used in This Document
+
+   The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY"
+   in this document are to be interpreted as defined in "Key words for
+   use in RFCs to Indicate Requirement Levels" [1].
+
+   The attribute syntax specifications use the Augmented Backus-Naur
+   Form (ABNF) [2] notation, including the core rules defined in
+   Appendix A.  The ABNF production "Language-tag" is imported from
+   Language Tags [5] and "reg-name" from URI: Generic Syntax [4].
+
+2.  Collation Definition and Purpose
+
+2.1.  Definition
+
+   A collation is a named function which takes two arbitrary length
+   strings as input and can be used to perform one or more of three
+   basic comparison operations: equality test, substring match, and
+   ordering test.
+
+2.2.  Purpose
+
+   Collations are an abstraction for comparison functions so that these
+   comparison functions can be used in multiple protocols.  The details
+   of a particular comparison operation can be specified by someone with
+   appropriate expertise, independent of the application protocols that
+   use that collation.  This is similar to the way a charset [13]
+   separates the details of octet to character mapping from a protocol
+   specification, such as MIME [9], or the way SASL [10] separates the
+   details of an authentication mechanism from a protocol specification,
+   such as ACAP [11].
+
+
+
+
+
+
+
+
+
+Newman, et al.              Standards Track                     [Page 4]
+
+RFC 4790                   Collation Registry                 March 2007
+
+
+   Here is a small diagram to help illustrate the value of this
+   abstraction:
+
+   +-------------------+                         +-----------------+
+   | IMAP i18n SEARCH  |--+                      | Basic           |
+   +-------------------+  |                   +--| Collation Spec  |
+                          |                   |  +-----------------+
+   +-------------------+  |  +-------------+  |  +-----------------+
+   | ACAP i18n SEARCH  |--+--| Collation   |--+--| A stringprep    |
+   +-------------------+  |  | Registry    |  |  | Collation Spec  |
+                          |  +-------------+  |  +-----------------+
+   +-------------------+  |                   |  +-----------------+
+   | ...other protocol |--+                   |  | locale-specific |
+   +-------------------+                      +--| Collation Spec  |
+                                                 +-----------------+
+
+   Thus IMAP, ACAP, and future application protocols with international
+   search capability simply specify how to interface to the collation
+   registry instead of each protocol specification having to specify all
+   the collations it supports.
+
+2.3.  Some Other Terms Used in this Document
+
+   The terms client, server, and protocol are used in somewhat unusual
+   senses.
+
+   Client means a user, or a program acting directly on behalf of a
+   user.  This may be a mail reader acting as an IMAP client, or it may
+   be an interactive shell, where the user can type protocol commands/
+   requests directly, or it may be a script or program written by the
+   user.
+
+   Server means a program that performs services requested by the
+   client.  This may be a traditional server such as an HTTP server, or
+   it may be a Sieve [14] interpreter running a Sieve script written by
+   a user.  A server needs to use the operations provided by collations
+   in order to fulfill the client's requests.
+
+   The protocol describes how the client tells the server what it wants
+   done, and (if applicable) how the server tells the client about the
+   results.  IMAP is a protocol by this definition, and so is the Sieve
+   language.
+
+2.4.  Sort Keys
+
+   One component of a collation is a transformation, which turns a
+   string into a sort key, which is then used while sorting.
+
+
+
+
+Newman, et al.              Standards Track                     [Page 5]
+
+RFC 4790                   Collation Registry                 March 2007
+
+
+   The transformation can range from an identity mapping (e.g., the
+   i;octet collation Section 9.3) to a mapping that makes the string
+   unreadable to a human.
+
+   This is an implementation detail of collations or servers.  A
+   protocol SHOULD NOT expose it to clients, since some collations leave
+   the sort key's format up to the implementation, and current
+   conformant implementations are known to use different formats.
+
+3.  Collation Identifier Syntax
+
+3.1.  Basic Syntax
+
+   The collation identifier itself is a single US-ASCII string.  The
+   identifier MUST NOT be longer than 254 characters, and obeys the
+   following grammar:
+
+     collation-char  = ALPHA / DIGIT / "-" / ";" / "=" / "."
+
+     collation-id    = collation-prefix ";" collation-core-name
+                       *collation-arg
+
+     collation-scope = Language-tag / "vnd-" reg-name
+
+     collation-core-name = ALPHA *( ALPHA / DIGIT / "-" )
+
+     collation-arg   = ";" ALPHA *( ALPHA / DIGIT ) "="
+                       1*( ALPHA / DIGIT / "." )
+
+
+   Note: the ABNF production "Language-tag" is imported from Language
+   Tags [5] and "reg-name" from URI: Generic Syntax [4].
+
+   There is a special identifier called "default".  For protocols that
+   have a default collation, "default" refers to that collation.  For
+   other protocols, the identifier "default" MUST match no collations,
+   and servers SHOULD treat it in the same way as they treat nonexistent
+   collations.
+
+3.2.  Wildcards
+
+   The string a client uses to select a collation MAY contain one or
+   more wildcard ("*") characters that match zero or more collation-
+   chars.  Wildcard characters MUST NOT be adjacent.  If the wildcard
+   string matches multiple collations, the server SHOULD attempt to
+   select a widely useful collation in preference to a narrowly useful
+   one.
+
+
+
+
+Newman, et al.              Standards Track                     [Page 6]
+
+RFC 4790                   Collation Registry                 March 2007
+
+
+     collation-wild  =  ("*" / (ALPHA ["*"])) *(collation-char ["*"])
+                         ; MUST NOT exceed 254 characters total
+
+3.3.  Ordering Direction
+
+   When used as a protocol element for ordering, the collation
+   identifier MAY be prefixed by either "+" or "-" to explicitly specify
+   an ordering direction. "+" has no effect on the ordering operation,
+   while "-" inverts the result of the ordering operation.  In general,
+   collation-order is used when a client requests a collation, and
+   collation-selected is used when the server informs the client of the
+   selected collation.
+
+     collation-selected =  ["+" / "-"] collation-id
+
+     collation-order =  ["+" / "-"] collation-wild
+
+3.4.  URIs
+
+   Some protocols are designed to use URIs [4] to refer to collations
+   rather than simple tokens.  A special section of the IANA URL space
+   is reserved for such usage.  The "collation-uri" form is used to
+   refer to a specific named collation (the collation registration may
+   not actually be present).  The "collation-auri" form is an abstract
+   name for an ordering, a collation pattern or a vendor private
+   collator.
+
+     collation-uri   =  "http://www.iana.org/assignments/collation/"
+                        collation-id ".xml"
+
+     collation-auri  =  ( "http://www.iana.org/assignments/collation/"
+                        collation-order ".xml" ) / other-uri
+
+     other-uri       =  <absoluteURI>
+                     ;  excluding the IANA collation namespace.
+
+3.5.  Naming Guidelines
+
+   While this specification makes no absolute requirements on the
+   structure of collation identifiers, naming consistency is important,
+   so the following initial guidelines are provided.
+
+   Collation identifiers with an international audience typically begin
+   with "i;".  Collation identifiers intended for a particular language
+   or locale typically begin with a language tag [5] followed by a ";".
+   After the first ";" is normally the name of the general collation
+   algorithm, followed by a series of algorithm modifications separated
+   by the ";" delimiter.  Parameterized modifications will use "=" to
+
+
+
+Newman, et al.              Standards Track                     [Page 7]
+
+RFC 4790                   Collation Registry                 March 2007
+
+
+   delimit the parameter from the value.  The version numbers of any
+   lookup tables used by the algorithm SHOULD be present as
+   parameterized modifications.
+
+   Collation identifiers of the form *;vnd-hostname;* are reserved for
+   vendor-specific collations created by the owner of the hostname
+   following the "vnd-" prefix (e.g., vnd-example.com for the vendor
+   example.com).  Registration of such collations (or the name space as
+   a whole), with intended use of the "Vendor", is encouraged when a
+   public specification or open-source implementation is available, but
+   is not required.
+
+4.  Collation Specification Requirements
+
+4.1.  Collation/Server Interface
+
+   The collation itself defines what it operates on.  Most collations
+   are expected to operate on character strings.  The i;octet
+   (Section 9.3) collation operates on octet strings.  The i;ascii-
+   numeric (Section 9.1) operation operates on numbers.
+
+   This specification defines the collation interface in terms of octet
+   strings.  However, implementations may choose to use character
+   strings instead.  Such implementations may not be able to implement
+   e.g., i;octet.  Since i;octet is not currently mandatory to implement
+   for any protocol, this should not be a problem.
+
+4.2.  Operations Supported
+
+   A collation specification MUST state which of the three basic
+   operations are supported (equality, substring, ordering) and how to
+   perform each of the supported operations on any two input character
+   strings, including empty strings.  Collations must be deterministic,
+   i.e., given a collation with a specific identifier, and any two fixed
+   input strings, the result MUST be the same for the same operation.
+
+   In general, collation operations should behave as their names
+   suggest.  While a collation may be new, the operations are not, so
+   the new collation's operations should be similar to those of older
+   collations.  For example, a date/time collation should not provide a
+   "substring" operation that would morph IMAP substring SEARCH into
+   e.g., a date-range search.
+
+   A non-obvious consequence of the rules for each collation operation
+   is that, for any single collation, either none or all of the
+   operations can return "undefined".  For example, it is not possible
+   to have an equality operation that never returns "undefined", and a
+   substring operation that occasionally does.
+
+
+
+Newman, et al.              Standards Track                     [Page 8]
+
+RFC 4790                   Collation Registry                 March 2007
+
+
+4.2.1.  Validity
+
+   The validity test takes one string as argument.  It returns valid if
+   its input string is a valid input to the collation's other
+   operations, and invalid if not.  (In other words, a string is valid
+   if it is equal to itself according to the collation's equality
+   operation.)
+
+   The validity test is provided by all collations.  It MUST NOT be
+   listed separately in the collation registration.
+
+4.2.2.  Equality
+
+   The equality test always returns "match" or "no-match" when it is
+   supplied valid input, and MAY return "undefined" if one or both input
+   strings are not valid.
+
+   The equality test MUST be reflexive and symmetric.  For valid input,
+   it MUST be transitive.
+
+   If a collation provides either a substring or an ordering test, it
+   MUST also provide an equality test.  The substring and/or ordering
+   tests MUST be consistent with the equality test.
+
+   The return values of the equality test are called "match", "no-match"
+   and "undefined" in this document.
+
+4.2.3.  Substring
+
+   The substring matching operation determines if the first string is a
+   substring of the second string, i.e., if one or more substrings of
+   the second string is equal to the first, as defined by the
+   collation's equality operation.
+
+   A collation that supports substring matching will automatically
+   support two special cases of substring matching: prefix and suffix
+   matching, if those special cases are supported by the application
+   protocol.  It returns "match" or "no-match" when it is supplied valid
+   input and returns "undefined" when supplied invalid input.
+
+   Application protocols MAY return position information for substring
+   matches.  If this is done, the position information SHOULD include
+   both the starting offset and the ending offset for each match.  This
+   is important because more sophisticated collations can match strings
+   of unequal length (for example, a pre-composed accented character can
+   match a decomposed accented character).  In general, overlapping
+   matches SHOULD be reported (as when "ana" occurs twice within
+   "banana"), although there are cases where a collation may decide not
+
+
+
+Newman, et al.              Standards Track                     [Page 9]
+
+RFC 4790                   Collation Registry                 March 2007
+
+
+   to.  For example, in a collation which treats all whitespace
+   sequences as identical, the substring operation could be defined such
+   that " 1 " (SP "1" SP) is reported just once within "  1  " (SP SP
+   "1" SP SP), not four times (SP SP "1" SP, SP "1" SP, SP "1" SP SP and
+   SP SP "1" SP SP), since the four matches are, in a sense, the same
+   match.
+
+   A string is a substring of itself.  The empty string is a substring
+   of all strings.
+
+   Note that the substring operation of some collations can match
+   strings of unequal length.  For example, a pre-composed accented
+   character can match a decomposed accented character.  The Unicode
+   Collation Algorithm [7] discusses this in more detail.
+
+   The return values of the substring operation are called "match", "no-
+   match", and "undefined" in this document.
+
+4.2.4.  Ordering
+
+   The ordering operation determines how two strings are ordered.  It
+   MUST be reflexive.  For valid input, it MUST be transitive and
+   trichotomous.
+
+   Ordering returns "less" if the first string is listed before the
+   second string, according to the collation; "greater", if the second
+   string is listed before the first string; and "equal", if the two
+   strings are equal, as defined by the collation's equality operation.
+   If one or both strings are invalid, the result of ordering is
+   "undefined".
+
+   When the collation is used with a "+" prefix, the behavior is the
+   same as when used with no prefix.  When the collation is used with a
+   "-" prefix, the result of the ordering operation of the collation
+   MUST be reversed.
+
+   The return values of the ordering operation are called "less",
+   "equal", "greater", and "undefined" in this document.
+
+4.3.  Sort Keys
+
+   A collation specification SHOULD describe the internal transformation
+   algorithm to generate sort keys.  This algorithm can be applied to
+   individual strings, and the result can be stored to potentially
+   optimize future comparison operations.  A collation MAY specify that
+   the sort key is generated by the identity function.  The sort key may
+   have no meaning to a human.  The sort key may not be valid input to
+   the collation.
+
+
+
+Newman, et al.              Standards Track                    [Page 10]
+
+RFC 4790                   Collation Registry                 March 2007
+
+
+4.4.  Use of Lookup Tables
+
+   Some collations use customizable lookup tables, e.g., because the
+   tables depend on locale, and may be modified after shipping the
+   software.  Collations that use more than one customizable lookup
+   table in a documented format MUST assign numbers to the tables they
+   use.  This permits an application protocol command to access the
+   tables used by a server collation, so that clients and servers use
+   the same tables.
+
+5.  Application Protocol Requirements
+
+   This section describes the requirements and issues that an
+   application protocol needs to consider if it offers searching,
+   substring matching and/or sorting, and permits the use of characters
+   outside the US-ASCII charset.
+
+5.1.  Character Encoding
+
+   The protocol specification has to make sure that it is clear on which
+   characters (rather than just octets) the collations are used.  This
+   can be done by specifying the protocol itself in terms of characters
+   (e.g., in the case of a query language), by specifying a single
+   character encoding for the protocol (e.g., UTF-8 [3]), or by
+   carefully describing the relevant issues of character encoding
+   labeling and conversion.  In the later case, details to consider
+   include how to handle unknown charsets, any charsets that are
+   mandatory-to-implement, any issues with byte-order that might apply,
+   and any transfer encodings that need to be supported.
+
+5.2.  Operations
+
+   The protocol must specify which of the operations defined in this
+   specification (equality matching, substring matching, and ordering)
+   can be invoked in the protocol, and how they are invoked.  There may
+   be more than one way to invoke an operation.
+
+   The protocol MUST provide a mechanism for the client to select the
+   collation to use with equality matching, substring matching, and
+   ordering.
+
+   If a protocol needs a total ordering and the collation chosen does
+   not provide it because the ordering operation returns "undefined" at
+   least once, the recommended fallback is to sort all invalid strings
+   after the valid ones, and use i;octet to order the invalid strings.
+
+   Although the collation's substring function provides a list of
+   matches, a protocol need not provide all that to the client.  It may
+
+
+
+Newman, et al.              Standards Track                    [Page 11]
+
+RFC 4790                   Collation Registry                 March 2007
+
+
+   provide only the first matching substring, or even just the
+   information that the substring search matched.  In this way,
+   collations can be used with protocols that are defined such that "x
+   is a substring of y" returns true-false.
+
+   If the protocol provides positional information for the results of a
+   substring match, that positional information SHOULD fully specify the
+   substring(s) in the result that matches, independent of the length of
+   the search string.  For example, returning both the starting and
+   ending offset of the match would suffice, as would the starting
+   offset and a length.  Returning just the starting offset is not
+   acceptable.  This rule is necessary because advanced collations can
+   treat strings of different lengths as equal (for example, pre-
+   composed and decomposed accented characters).
+
+5.3.  Wildcards
+
+   The protocol MUST specify whether it allows the use of wildcards in
+   collation identifiers.  If the protocol allows wildcards, then:
+      The protocol MUST specify how comparisons behave in the absence of
+      explicit collation negotiation, or when a collation of "default"
+      is requested.  The protocol MAY specify that the default collation
+      used in such circumstances is sensitive to server configuration.
+
+      The protocol SHOULD provide a way to list available collations
+      matching a given wildcard pattern, or patterns.
+
+5.4.  String Comparison
+
+   If a protocol compares strings in any nontrivial way, using a
+   collation may be appropriate.  As an example, many protocols use
+   case-independent strings.  In many cases, a simple ASCII mapping to
+   upper/lower case works well.  In other cases, it may be better to use
+   a specifiable collation; for example, so that a server can treat "i"
+   and "I" as equivalent in Italy, and different in Turkey (Turkish also
+   has a dotted upper-case" I" and a dotless lower-case "i").
+
+   Protocol designers should consider, in each case, whether to use a
+   specifiable collation.  Keywords often have other needs than user
+   variables, and search arguments may be different again.
+
+5.5.  Disconnected Clients
+
+   If the protocol supports disconnected clients, and a collation is
+   used that can use configurable tables (e.g., to support
+   locale-specific extensions), then the client may not be able to
+   reproduce the server's collation operations while offline.
+
+
+
+
+Newman, et al.              Standards Track                    [Page 12]
+
+RFC 4790                   Collation Registry                 March 2007
+
+
+   A mechanism to download such tables has been discussed.  Such a
+   mechanism is not included in the present specification, since the
+   problem is not yet well understood.
+
+5.6.  Error Codes
+
+   The protocol specification should consider assigning protocol error
+   codes for the following circumstances:
+
+   o  The client requests the use of a collation by identifier or
+      pattern, but no implemented collation matches that pattern.
+
+   o  The client attempts to use a collation for an operation that is
+      not supported by that collation -- for example, attempting to use
+      the "i;ascii-numeric" collation for substring matching.
+
+   o  The client uses an equality or substring matching collation, and
+      the result is an error.  It may be appropriate to distinguish
+      between the two input strings, particularly when one is supplied
+      by the client and the other is stored by the server.  It might
+      also be appropriate to distinguish the specific case of an invalid
+      UTF-8 string.
+
+5.7.  Octet Collation
+
+   The i;octet (Section 9.3) collation is only usable with protocols
+   based on octet-strings.  Clients and servers MUST NOT use i;octet
+   with other protocols.
+
+   If the protocol permits the use of collations with data structures
+   other than strings, the protocol MUST describe the default behavior
+   for a collation with those data structures.
+
+6.  Use by Existing Protocols
+
+   This section is informative.
+
+   Both ACAP [11] and Sieve [14] are standards track specifications that
+   used collations prior to the creation of this specification and
+   registry.  Those standards do not meet all the application protocol
+   requirements described in Section 5.
+
+   These protocols allow the use of the i;octet (Section 9.3) collation
+   working directly on UTF-8 data, as used in these protocols.
+
+
+
+
+
+
+
+Newman, et al.              Standards Track                    [Page 13]
+
+RFC 4790                   Collation Registry                 March 2007
+
+
+   In Sieve, all matches are either true or false.  Accordingly, Sieve
+   servers must treat "undefined" and "no-match" results of the equality
+   and substring operations as false, and only "match" as true.
+
+   In ACAP and Sieve, there are no invalid strings.  In this document's
+   terms, invalid strings sort after valid strings.
+
+   IMAP [15] also collates, although that is explicit only when the
+   COMPARATOR [17] extension is used.  The built-in IMAP substring
+   operation and the ordering provided by the SORT [16] extension may
+   not meet the requirements made in this document.
+
+   Other protocols may be in a similar position.
+
+   In IMAP, the default collation is i;ascii-casemap, because its
+   operations are understood to match IMAP's built-in operations.
+
+7.  Collation Registration
+
+7.1.  Collation Registration Procedure
+
+   The IETF will create a mailing list, collation@ietf.org, which can be
+   used for public discussion of collation proposals prior to
+   registration.  Use of the mailing list is strongly encouraged.  The
+   IESG will appoint a designated expert who will monitor the
+   collation@ietf.org mailing list and review registrations.
+
+   The registration procedure begins when a completed registration
+   template is sent to iana@iana.org and collation@ietf.org.  The
+   designated expert is expected to tell IANA and the submitter of the
+   registration within two weeks whether the registration is approved,
+   approved with minor changes, or rejected with cause.  When a
+   registration is rejected with cause, it can be re-submitted if the
+   concerns listed in the cause are addressed.  Decisions made by the
+   designated expert can be appealed to the IESG Applications Area
+   Director, then to the IESG.  They follow the normal appeals procedure
+   for IESG decisions.
+
+   Collation registrations in a standards track, BCP, or IESG-approved
+   experimental RFC are owned by the IETF, and changes to the
+   registration follow normal procedures for updating such documents.
+   Collation registrations in other RFCs are owned by the RFC author(s).
+   Other collation registrations are owned by the individual(s) listed
+   in the contact field of the registration, and IANA will preserve this
+   information.
+
+   If the registration is a change of an existing collation, it MUST be
+   approved by the owner.  In the event the owner cannot be contacted
+
+
+
+Newman, et al.              Standards Track                    [Page 14]
+
+RFC 4790                   Collation Registry                 March 2007
+
+
+   for a period of one month, and the designated expert deems the change
+   necessary, the IESG MAY re-assign ownership to an appropriate party.
+
+7.2.  Collation Registration Format
+
+   Registration of a collation is done by sending a well-formed XML
+   document to collation@ietf.org and iana@iana.org.
+
+7.2.1.  Registration Template
+
+   Here is a template for the registration:
+
+   <?xml version='1.0'?>
+   <!DOCTYPE collation SYSTEM 'collationreg.dtd'>
+   <collation rfc="YYYY" scope="global" intendedUse="common">
+     <identifier>collation identifier</identifier>
+     <title>technical title for collation</title>
+     <operations>equality order substring</operations>
+     <specification>specification reference</specification>
+     <owner>email address of owner or IETF</owner>
+     <submitter>email address of submitter</submitter>
+     <version>1</version>
+   </collation>
+
+7.2.2.  The Collation Element
+
+   The root of the registration document MUST be a <collation> element.
+   The collation element contains the other elements in the
+   registration, which are described in the following sub-subsections,
+   in the order given here.
+
+   The <collation> element MAY include an "rfc=" attribute if the
+   specification is in an RFC.  The "rfc=" attribute gives only the
+   number of the RFC, without any prefix, such as "RFC", or suffix, such
+   as ".txt".
+
+   The <collation> element MUST include a "scope=" attribute, which MUST
+   have one of the values "global", "local", or "other".
+
+   The <collation> element MUST include an "intendedUse=" attribute,
+   which must have one of the values "common", "limited", "vendor", or
+   "deprecated".  Collation specifications intended for "common" use are
+   expected to reference standards from standards bodies with
+   significant experience dealing with the details of international
+   character sets.
+
+   Be aware that future revisions of this specification may add
+   additional function types, as well as additional XML attributes,
+
+
+
+Newman, et al.              Standards Track                    [Page 15]
+
+RFC 4790                   Collation Registry                 March 2007
+
+
+   values, and elements.  Any system that automatically parses these XML
+   documents MUST take this into account to preserve future
+   compatibility.
+
+7.2.3.  The Identifier Element
+
+   The <identifier> element gives the precise identifier of the
+   collation, e.g., i;ascii-casemap.  The <identifier> element is
+   mandatory.
+
+7.2.4.  The Title Element
+
+   The <title> element gives the title of the collation.  The <title>
+   element is mandatory.
+
+7.2.5.  The Operations Element
+
+   The <operations> element lists which of the three operations
+   ("equality", "order" or "substring") the collation provides,
+   separated by single spaces.  The <operations> element is mandatory.
+
+7.2.6.  The Specification Element
+
+   The <specification> element describes where to find the
+   specification.  The <specification> element is mandatory.  It MAY
+   have a URI attribute.  There may be more than one <specification>
+   element, in which case, they together form the specification.
+
+   If it is discovered that parts of a collation specification conflict,
+   a new revision of the collation is necessary, and the
+   collation@ietf.org mailing list should be notified.
+
+7.2.7.  The Submitter Element
+
+   The <submitter> element provides an RFC 2822 [12] email address for
+   the person who submitted the registration.  It is optional if the
+   <owner> element contains an email address.
+
+   There may be more than one <submitter> element.
+
+7.2.8.  The Owner Element
+
+   The <owner> element contains either the four letters "IETF" or an
+   email address of the owner of the registration.  The <owner> element
+   is mandatory.  There may be more than one <owner> element.  If so,
+   all owners are equal.  Each owner can speak for all.
+
+
+
+
+
+Newman, et al.              Standards Track                    [Page 16]
+
+RFC 4790                   Collation Registry                 March 2007
+
+
+7.2.9.  The Version Element
+
+   The <version> element MUST be included when the registration is
+   likely to be revised, or has been revised in such a way that the
+   results change for one or more input strings.  The <version> element
+   is optional.
+
+7.2.10.  The Variable Element
+
+   The <variable> element specifies an optional variable to control the
+   collation's behaviour, for example whether it is case sensitive.  The
+   <variable> element is optional.  When <variable> is used, it must
+   contain <name> and <default> elements, and it may contain one or more
+   <value> elements.
+
+7.2.10.1.  The Name Element
+
+   The <name> element specifies the name value of a variable.  The
+   <name> element is mandatory.
+
+7.2.10.2.  The Default Element
+
+   The <default> element specifies the default value of a variable.  The
+   <default> element is mandatory.
+
+7.2.10.3.  The Value Element
+
+   The <value> element specifies a legal value of a variable.  The
+   <value> element is optional.  If one or more <value> elements are
+   present, only those values are legal.  If none are, then the
+   variable's legal values do not form an enumerated set, and the rules
+   MUST be specified in an RFC accompanying the registration.
+
+7.3.  Structure of Collation Registry
+
+   Once the registration is approved, IANA will store each XML
+   registration document in a URL of the form
+   http://www.iana.org/assignments/collation/collation-id.xml, where
+   collation-id is the content of the identifier element in the
+   registration.  Both the submitter and the designated expert are
+   responsible for verifying that the XML is well-formed.  The
+   registration document should avoid using new elements.  If any are
+   necessary, it is important to be consistent with other registrations.
+
+   IANA will also maintain a text summary of the registry under the name
+   http://www.iana.org/assignments/collation/collation-index.html.  This
+   summary is divided into four sections.  The first section is for
+   collations intended for common use.  This section is intended for
+
+
+
+Newman, et al.              Standards Track                    [Page 17]
+
+RFC 4790                   Collation Registry                 March 2007
+
+
+   collation registrations published in IESG-approved RFCs, or for
+   locally scoped collations from the primary standards body for that
+   locale.  The designated expert is encouraged to reject collation
+   registrations with an intended use of "common" if the expert believes
+   it should be "limited", as it is desirable to keep the number of
+   "common" registrations small and of high quality.  The second section
+   is reserved for limited-use collations.  The third section is
+   reserved for registered vendor-specific collations.  The final
+   section is reserved for deprecated collations.
+
+7.4.  Example Initial Registry Summary
+
+   The following is an example of how IANA might structure the initial
+   registry summary.html file:
+
+     Collation                              Functions Scope Reference
+     ---------                              --------- ----- ---------
+   Common Use Collations:
+     i;ascii-casemap                        e, o, s   Local [RFC 4790]
+
+   Limited Use Collations:
+     i;octet                                e, o, s   Other [RFC 4790]
+     i;ascii-numeric                        e, o      Other [RFC 4790]
+
+   Vendor Collations:
+
+   Deprecated Collations:
+
+
+   References
+   ----------
+   [RFC 4790]  Newman, C., Duerst, M., Gulbrandsen, A., "Internet
+               Application Protocol Collation Registry", RFC 4790,
+               Sun Microsystems, March 2007.
+
+8.  Guidelines for Expert Reviewer
+
+   The expert reviewer appointed by the IESG has fairly broad latitude
+   for this registry.  While a number of collations are expected
+   (particularly customizations of the UCA for localized use), an
+   explosion of collations (particularly common-use collations) is not
+   desirable for widespread interoperability.  However, it is important
+   for the expert reviewer to provide cause when rejecting a
+   registration, and, when possible, to describe corrective action to
+
+
+
+
+
+
+
+Newman, et al.              Standards Track                    [Page 18]
+
+RFC 4790                   Collation Registry                 March 2007
+
+
+   permit the registration to proceed.  The following table includes
+   some example reasons to reject a registration with cause:
+
+   o  The registration is not a well-formed XML document.
+
+   o  The registration has an intended use of "common", but there is no
+      evidence the collation will be widely deployed, so it should be
+      listed as "limited".
+
+   o  The registration has an intended use of "common", but it is
+      redundant with the functionality of a previously registered
+      "common" collation.
+
+   o  The registration has an intended use of "common", but the
+      specification is not detailed enough to allow interoperable
+      implementations by others.
+
+   o  The collation identifier fails to precisely identify the version
+      numbers of relevant tables to use.
+
+   o  The registration fails to meet one of the "MUST" requirements in
+      Section 4.
+
+   o  The collation identifier fails to meet the syntax in Section 3.
+
+   o  The collation specification referenced in the registration is
+      vague or has optional features without a clear behavior specified.
+
+   o  The referenced specification does not adequately address security
+      considerations specific to that collation.
+
+   o  The registration's operations are needlessly different from those
+      of traditional operations.
+
+   o  The registration's XML is needlessly different from that of
+      already registered collations.
+
+9.  Initial Collations
+
+   This section registers the three collations that were originally
+   defined in [11], and are implemented in most [14] engines.  Some of
+   the behavior of these collations is perhaps not ideal, such as
+   i;ascii-casemap accepting non-ASCII input.  Compatibility with widely
+   deployed code was judged more important than fixing the collations.
+   Some of the aspects of these collations are necessary to maintain
+   compatibility with widely deployed code.
+
+
+
+
+
+Newman, et al.              Standards Track                    [Page 19]
+
+RFC 4790                   Collation Registry                 March 2007
+
+
+9.1.  ASCII Numeric Collation
+
+9.1.1.  ASCII Numeric Collation Description
+
+   The "i;ascii-numeric" collation is a simple collation intended for
+   use with arbitrarily-sized, unsigned decimal integer numbers stored
+   as octet strings.  US-ASCII digits (0x30 to 0x39) represent digits of
+   the numbers.  Before converting from string to integer, the input
+   string is truncated at the first non-digit character.  All input is
+   valid; strings that do not start with a digit represent positive
+   infinity.
+
+   The collation supports equality and ordering, but does not support
+   the substring operation.
+
+   The equality operation returns "match" if the two strings represent
+   the same number (i.e., leading zeroes and trailing non-digits are
+   disregarded), and "no-match" if the two strings represent different
+   numbers.
+
+   The ordering operation returns "less" if the first string represents
+   a smaller number than the second, "equal" if they represent the same
+   number, and "greater" if the first string represents a larger number
+   than the second.
+
+   Some examples: "0" is less than "1", and "1" is less than
+   "4294967298". "4294967298", "04294967298", and "4294967298b" are all
+   equal. "04294967298" is less than "". "", "x", and "y" are equal.
+
+9.1.2.  ASCII Numeric Collation Registration
+
+   <?xml version='1.0'?>
+   <!DOCTYPE collation SYSTEM 'collationreg.dtd'>
+   <collation rfc="4790" scope="other" intendedUse="limited">
+     <identifier>i;ascii-numeric</identifier>
+     <title>ASCII Numeric</title>
+     <operations>equality order</operations>
+     <specification>RFC 4790</specification>
+     <owner>IETF</owner>
+     <submitter>chris.newman@sun.com</submitter>
+   </collation>
+
+
+
+
+
+
+
+
+
+
+Newman, et al.              Standards Track                    [Page 20]
+
+RFC 4790                   Collation Registry                 March 2007
+
+
+9.2.  ASCII Casemap Collation
+
+9.2.1.  ASCII Casemap Collation Description
+
+   The "i;ascii-casemap" collation is a simple collation that operates
+   on octet strings and treats US-ASCII letters case-insensitively.  It
+   provides equality, substring, and ordering operations.  All input is
+   valid.  Note that letters outside ASCII are not treated case-
+   insensitively.
+
+   Its equality, ordering, and substring operations are as for i;octet,
+   except that at first, the lower-case letters (octet values 97-122) in
+   each input string are changed to upper case (octet values 65-90).
+
+   Care should be taken when using OS-supplied functions to implement
+   this collation, as it is not locale sensitive.  Functions, such as
+   strcasecmp and toupper, are sometimes locale sensitive, and may
+   inappropriately map lower-case letters other than a-z to upper case.
+
+   The i;ascii-casemap collation is well-suited for use with many
+   Internet protocols and computer languages.  Use with natural language
+   is often inappropriate; even though the collation apparently supports
+   languages such as Swahili and English, in real-world use, it tends to
+   mis-sort a number of types of string:
+
+   o  people and place names containing non-ASCII,
+
+   o  words such as "naive" (if spelled with an accent, the accented
+      character could push the word to the wrong spot in a sorted list),
+
+   o  names such as "Lloyd" (which, in Welsh, sorts after "Lyon", unlike
+      in English),
+
+   o  strings containing euro and pound sterling symbols, quotation
+      marks other than '"', dashes/hyphens, etc.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Newman, et al.              Standards Track                    [Page 21]
+
+RFC 4790                   Collation Registry                 March 2007
+
+
+9.2.2.  ASCII Casemap Collation Registration
+
+   <?xml version='1.0'?>
+   <!DOCTYPE collation SYSTEM 'collationreg.dtd'>
+   <collation rfc="4790" scope="local" intendedUse="common">
+     <identifier>i;ascii-casemap</identifier>
+     <title>ASCII Casemap</title>
+     <operations>equality order substring</operations>
+     <specification>RFC 4790</specification>
+     <owner>IETF</owner>
+     <submitter>chris.newman@sun.com</submitter>
+   </collation>
+
+9.3.  Octet Collation
+
+9.3.1.  Octet Collation Description
+
+   The "i;octet" collation is a simple and fast collation intended for
+   use on binary octet strings rather than on character data.  Protocols
+   that want to make this collation available have to do so by
+   explicitly allowing it.  If not explicitly allowed, it MUST NOT be
+   used.  It never returns an "undefined" result.  It provides equality,
+   substring, and ordering operations.
+
+   The ordering algorithm is as follows:
+
+   1.  If both strings are the empty string, return the result "equal".
+
+   2.  If the first string is empty and the second is not, return the
+       result "less".
+
+   3.  If the second string is empty and the first is not, return the
+       result "greater".
+
+   4.  If both strings begin with the same octet value, remove the first
+       octet from both strings and repeat this algorithm from step 1.
+
+   5.  If the unsigned value (0 to 255) of the first octet of the first
+       string is less than the unsigned value of the first octet of the
+       second string, then return "less".
+
+   6.  If this step is reached, return "greater".
+
+   This algorithm is roughly equivalent to the C library function
+   memcmp, with appropriate length checks added.
+
+
+
+
+
+
+Newman, et al.              Standards Track                    [Page 22]
+
+RFC 4790                   Collation Registry                 March 2007
+
+
+   The matching operation returns "match" if the sorting algorithm would
+   return "equal".  Otherwise, the matching operation returns "no-
+   match".
+
+   The substring operation returns "match" if the first string is the
+   empty string, or if there exists a substring of the second string of
+   length equal to the length of the first string, which would result in
+   a "match" result from the equality function.  Otherwise, the
+   substring operation returns "no-match".
+
+9.3.2.  Octet Collation Registration
+
+   This collation is defined with intendedUse="limited" because it can
+   only be used by protocols that explicitly allow it.
+
+   <?xml version='1.0'?>
+   <!DOCTYPE collation SYSTEM 'collationreg.dtd'>
+   <collation rfc="4790" scope="global" intendedUse="limited">
+     <identifier>i;octet</identifier>
+     <title>Octet</title>
+     <operations>equality order substring</operations>
+     <specification>RFC 4790</specification>
+     <owner>IETF</owner>
+     <submitter>chris.newman@sun.com</submitter>
+   </collation>
+
+10.  IANA Considerations
+
+   Section 7 defines how to register collations with IANA.  Section 9
+   defines a list of predefined collations that have been registered
+   with IANA.
+
+11.  Security Considerations
+
+   Collations will normally be used with UTF-8 strings.  Thus, the
+   security considerations for UTF-8 [3], stringprep [6], and Unicode
+   TR-36 [8] also apply, and are normative to this specification.
+
+12.  Acknowledgements
+
+   The authors want to thank all who have contributed to this document,
+   including Brian Carpenter, John Cowan, Dave Cridland, Mark Davis,
+   Spencer Dawkins, Lisa Dusseault, Lars Eggert, Frank Ellermann, Philip
+   Guenther, Tony Hansen, Ted Hardie, Sam Hartman, Kjetil Torgrim Homme,
+   Michael Kay, John Klensin, Alexey Melnikov, Jim Melton, and Abhijit
+   Menon-Sen.
+
+
+
+
+
+Newman, et al.              Standards Track                    [Page 23]
+
+RFC 4790                   Collation Registry                 March 2007
+
+
+13.  References
+
+13.1.  Normative References
+
+   [1]   Bradner, S., "Key words for use in RFCs to Indicate Requirement
+         Levels", BCP 14, RFC 2119, March 1997.
+
+   [2]   Crocker, D. and P. Overell, "Augmented BNF for Syntax
+         Specifications: ABNF", RFC 4234, October 2005.
+
+   [3]   Yergeau, F., "UTF-8, a transformation format of ISO 10646",
+         STD 63, RFC 3629, November 2003.
+
+   [4]   Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
+         Resource Identifier (URI): Generic Syntax", RFC 3986,
+         January 2005.
+
+   [5]   Phillips, A. and M. Davis, "Tags for Identifying Languages",
+         BCP 47, RFC 4646, September 2006.
+
+   [6]   Hoffman, P. and M. Blanchet, "Preparation of Internationalized
+         Strings ("stringprep")", RFC 3454, December 2002.
+
+   [7]   Davis, M. and K. Whistler, "Unicode Collation Algorithm version
+         14", May 2005,
+         <http://www.unicode.org/reports/tr10/tr10-14.html>.
+
+   [8]   Davis, M. and M. Suignard, "Unicode Security Considerations",
+         February 2006, <http://www.unicode.org/reports/tr36/>.
+
+13.2.  Informative References
+
+   [9]   Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+         Extensions (MIME) Part One: Format of Internet Message Bodies",
+         RFC 2045, November 1996.
+
+   [10]  Melnikov, A., "Simple Authentication and Security Layer
+         (SASL)", RFC 4422, June 2006.
+
+   [11]  Newman, C. and J. Myers, "ACAP -- Application Configuration
+         Access Protocol", RFC 2244, November 1997.
+
+   [12]  Resnick, P., "Internet Message Format", RFC 2822, April 2001.
+
+   [13]  Freed, N. and J. Postel, "IANA Charset Registration
+         Procedures", BCP 19, RFC 2978, October 2000.
+
+
+
+
+
+Newman, et al.              Standards Track                    [Page 24]
+
+RFC 4790                   Collation Registry                 March 2007
+
+
+   [14]  Showalter, T., "Sieve: A Mail Filtering Language", RFC 3028,
+         January 2001.
+
+   [15]  Crispin, M., "Internet Message Access Protocol - Version
+         4rev1", RFC 3501, March 2003.
+
+   [16]  Crispin, M. and K. Murchison, "Internet Message Access Protocol
+         - Sort and Thread Extensions", Work in Progress, May 2004.
+
+   [17]  Newman, C. and A. Gulbrandsen, "Internet Message Access
+         Protocol Internationalization", Work in Progress, January 2006.
+
+Authors' Addresses
+
+   Chris Newman
+   Sun Microsystems
+   1050 Lakes Drive
+   West Covina, CA  91790
+   USA
+
+   EMail: chris.newman@sun.com
+
+
+   Martin Duerst
+   Aoyama Gakuin University
+   5-10-1 Fuchinobe
+   Sagamihara, Kanagawa  229-8558
+   Japan
+
+   Phone: +81 42 759 6329
+   Fax:   +81 42 759 6495
+   EMail: duerst@it.aoyama.ac.jp
+   URI:   http://www.sw.it.aoyama.ac.jp/D%C3%BCrst/
+
+   Note: Please write "Duerst" with u-umlaut wherever possible, for
+   example as "D&#252;rst" in XML and HTML.
+
+
+   Arnt Gulbrandsen
+   Oryx Mail Systems GmbH
+   Schweppermannstr. 8
+   81671 Munich
+   Germany
+
+   Fax:   +49 89 4502 9758
+   EMail: arnt@oryx.com
+   URI:   http://www.oryx.com/arnt/
+
+
+
+
+Newman, et al.              Standards Track                    [Page 25]
+
+RFC 4790                   Collation Registry                 March 2007
+
+
+Full Copyright Statement
+
+   Copyright (C) The IETF Trust (2007).
+
+   This document is subject to the rights, licenses and restrictions
+   contained in BCP 78, and except as set forth therein, the authors
+   retain all their rights.
+
+   This document and the information contained herein are provided on an
+   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
+   THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
+   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   Intellectual Property Rights or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; nor does it represent that it has
+   made any independent effort to identify any such rights.  Information
+   on the procedures with respect to rights in RFC documents can be
+   found in BCP 78 and BCP 79.
+
+   Copies of IPR disclosures made to the IETF Secretariat and any
+   assurances of licenses to be made available, or the result of an
+   attempt made to obtain a general license or permission for the use of
+   such proprietary rights by implementers or users of this
+   specification can be obtained from the IETF on-line IPR repository at
+   http://www.ietf.org/ipr.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights that may cover technology that may be required to implement
+   this standard.  Please address the information to the IETF at
+   ietf-ipr@ietf.org.
+
+Acknowledgement
+
+   Funding for the RFC Editor function is currently provided by the
+   Internet Society.
+
+
+
+
+
+
+
+Newman, et al.              Standards Track                    [Page 26]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc4959.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,395 @@
+
+
+
+
+
+
+Network Working Group                                      R. Siemborski
+Request for Comments: 4959                                  Google, Inc.
+Category: Standards Track                                 A. Gulbrandsen
+                                                  Oryx Mail Systems GmbH
+                                                          September 2007
+
+
+   IMAP Extension for Simple Authentication and Security Layer (SASL)
+                        Initial Client Response
+
+Status of This Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Abstract
+
+   To date, the Internet Message Access Protocol (IMAP) has used a
+   Simple Authentication and Security Layer (SASL) profile which always
+   required at least one complete round trip for an authentication, as
+   it did not support an initial client response argument.  This
+   additional round trip at the beginning of the session is undesirable,
+   especially when round-trip costs are high.
+
+   This document defines an extension to IMAP which allows clients and
+   servers to avoid this round trip by allowing an initial client
+   response argument to the IMAP AUTHENTICATE command.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Siemborski & Gulbrandsen  Standards Track                       [Page 1]
+
+RFC 4959       IMAP Ext for SASL Initial Client Response  September 2007
+
+
+1.  Introduction
+
+   The SASL initial client response extension is present in any IMAP
+   [RFC3501] server implementation which returns "SASL-IR" as one of the
+   supported capabilities in its CAPABILITY response.
+
+   Servers which support this extension will accept an optional initial
+   client response with the AUTHENTICATE command for any SASL [RFC4422]
+   mechanisms which support it.
+
+2.  Conventions Used in This Document
+
+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+   document are to be interpreted as described in [RFC2119].
+
+   In examples, "C:" and "S:" indicate lines sent by the client and
+   server, respectively.
+
+   Formal syntax is defined by [RFC4234] as extended by [RFC3501].
+
+3.  IMAP Changes to the IMAP AUTHENTICATE Command
+
+   This extension adds an optional second argument to the AUTHENTICATE
+   command that is defined in Section 6.2.2 of [RFC3501].  If this
+   second argument is present, it represents the contents of the
+   "initial client response" defined in Section 5.1 of [RFC4422].
+
+   As with any other client response, this initial client response MUST
+   be encoded as defined in Section 4 of [RFC4648].  It also MUST be
+   transmitted outside of a quoted string or literal.  To send a zero-
+   length initial response, the client MUST send a single pad character
+   ("=").  This indicates that the response is present, but is a zero-
+   length string.
+
+   When decoding the BASE64 [RFC4648] data in the initial client
+   response, decoding errors MUST be treated as IMAP [RFC3501] would
+   handle them in any normal SASL client response.  In particular, the
+   server should check for any characters not explicitly allowed by the
+   BASE64 alphabet, as well as any sequence of BASE64 characters that
+   contains the pad character ('=') anywhere other than the end of the
+   string (e.g., "=AAA" and "AAA=BBB" are not allowed).
+
+   If the client uses an initial response with a SASL mechanism that
+   does not support an initial response, the server MUST reject the
+   command with a tagged BAD response.
+
+
+
+
+
+Siemborski & Gulbrandsen  Standards Track                       [Page 2]
+
+RFC 4959       IMAP Ext for SASL Initial Client Response  September 2007
+
+
+   Note: support and use of the initial client response is optional for
+   both clients and servers.  Servers that implement this extension MUST
+   support clients that omit the initial client response, and clients
+   that implement this extension MUST NOT send an initial client
+   response to servers that do not advertise the SASL-IR capability.  In
+   such a situation, clients MUST fall back to an IMAP [RFC3501]
+   compatible mode.
+
+   If either the client or the server do not support the SASL-IR
+   capability, a mechanism which uses an initial client response is
+   negotiated using the challenge/response exchange described in
+   [RFC3501], with an initial zero-length server challenge.
+
+4.  Examples
+
+   The following is an example authentication using the PLAIN (see
+   [RFC4616]) SASL mechanism (under a TLS protection layer, see
+   [RFC4346]) and an initial client response:
+
+            ... client connects to server and negotiates a TLS
+           protection layer ...
+        C: C01 CAPABILITY
+        S: * CAPABILITY IMAP4rev1 SASL-IR AUTH=PLAIN
+        S: C01 OK Completed
+        C: A01 AUTHENTICATE PLAIN dGVzdAB0ZXN0AHRlc3Q=
+        S: A01 OK Success (tls protection)
+
+   Note that even when a server supports this extension, the following
+   negotiation (which does not use the initial response) is still valid
+   and MUST be supported by the server:
+
+            ... client connects to server and negotiates a TLS
+           protection layer ...
+        C: C01 CAPABILITY
+        S: * CAPABILITY IMAP4rev1 SASL-IR AUTH=PLAIN
+        S: C01 OK Completed
+        C: A01 AUTHENTICATE PLAIN
+            (note that there is a space following the "+" in the
+           following line)
+        S: +
+        C: dGVzdAB0ZXN0AHRlc3Q=
+        S: A01 OK Success (tls protection)
+
+   The following is an example authentication using the SASL EXTERNAL
+   mechanism (defined in [RFC4422]) under a TLS protection layer (see
+   [RFC4346]) and an empty initial client response:
+
+
+
+
+
+Siemborski & Gulbrandsen  Standards Track                       [Page 3]
+
+RFC 4959       IMAP Ext for SASL Initial Client Response  September 2007
+
+
+            ... client connects to server and negotiates a TLS
+           protection layer ...
+        C: C01 CAPABILITY
+        S: * CAPABILITY IMAP4rev1 SASL-IR AUTH=PLAIN AUTH=EXTERNAL
+        S: C01 OK Completed
+        C: A01 AUTHENTICATE EXTERNAL =
+        S: A01 OK Success (tls protection)
+
+   This is in contrast with the handling of such a situation when an
+   initial response is omitted:
+
+         ... client connects to server and negotiates a TLS protection
+           layer ...
+        C: C01 CAPABILITY
+        S: * CAPABILITY IMAP4rev1 SASL-IR AUTH=PLAIN AUTH=EXTERNAL
+        S: C01 OK Completed
+        C: A01 AUTHENTICATE EXTERNAL
+            (note that there is a space following the "+" in the
+           following line)
+        S: +
+        C:
+        S: A01 OK Success (tls protection)
+
+5.  IANA Considerations
+
+   The IANA has added SASL-IR to the IMAP4 Capabilities Registry.
+
+6.  Security Considerations
+
+   The extension defined in this document is subject to many of the
+   Security Considerations defined in [RFC3501] and [RFC4422].
+
+   Server implementations MUST treat the omission of an initial client
+   response from the AUTHENTICATE command as defined by [RFC3501] (as if
+   this extension did not exist).
+
+   Although [RFC3501] has no express line length limitations, some
+   implementations choose to enforce them anyway.  Such implementations
+   MUST be aware that the addition of the initial response parameter to
+   AUTHENTICATE may increase the maximum line length that IMAP parsers
+   may expect to support.  Server implementations MUST be able to
+   receive the largest possible initial client response that their
+   supported mechanisms might receive.
+
+
+
+
+
+
+
+
+Siemborski & Gulbrandsen  Standards Track                       [Page 4]
+
+RFC 4959       IMAP Ext for SASL Initial Client Response  September 2007
+
+
+7.  Formal Syntax
+
+   The following syntax specification uses the Augmented Backus-Naur
+   Form [RFC4234] notation.  [RFC3501] defines the non-terminals
+   capability, auth-type, and base64.
+
+      capability    =/ "SASL-IR"
+
+      authenticate  = "AUTHENTICATE" SP auth-type [SP (base64 / "=")]
+                      *(CRLF base64)
+                      ;;redefine AUTHENTICATE from [RFC3501]
+
+8.  Acknowledgments
+
+   The authors would like to acknowledge the contributions of Ken
+   Murchison and Mark Crispin, along with the rest of the IMAPEXT
+   Working Group for their assistance in reviewing this document.
+
+   Alexey Melnikov and Cyrus Daboo also had some early discussions about
+   this extension.
+
+9.  References
+
+9.1.  Normative References
+
+   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
+              Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+   [RFC3501]  Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
+              4rev1", RFC 3501, March 2003.
+
+   [RFC4234]  Crocker, D. and P. Overell, "Augmented BNF for Syntax
+              Specifications: ABNF", RFC 4234, October 2005.
+
+   [RFC4422]  Melnikov, A. and  K. Zeilenga, "Simple Authentication and
+              Security Layer (SASL)", RFC 4422, June 2006.
+
+   [RFC4648]  Josefsson, S., "The Base16, Base32, and Base64 Data
+              Encodings", RFC 4648, October 2006.
+
+9.2.  Informative References
+
+   [RFC4616]  Zeilenga, K., "The PLAIN Simple Authentication and
+              Security Layer (SASL) Mechanism", RFC 4616, August 2006.
+
+   [RFC4346]  Dierks, T. and E. Rescorla, "The Transport Layer Security
+              (TLS) Protocol Version 1.1", RFC 4346, April 2006.
+
+
+
+
+Siemborski & Gulbrandsen  Standards Track                       [Page 5]
+
+RFC 4959       IMAP Ext for SASL Initial Client Response  September 2007
+
+
+Authors' Addresses
+
+   Robert Siemborski
+   Google, Inc.
+   1600 Ampitheatre Parkway
+   Mountain View, CA 94043
+
+   Phone: +1 650 623 6925
+   EMail: robsiemb@google.com
+
+
+   Arnt Gulbrandsen
+   Oryx Mail Systems GmbH
+   Schweppermannstr. 8
+   D-81671 Muenchen
+   Germany
+
+   EMail: arnt@oryx.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Siemborski & Gulbrandsen  Standards Track                       [Page 6]
+
+RFC 4959       IMAP Ext for SASL Initial Client Response  September 2007
+
+
+Full Copyright Statement
+
+   Copyright (C) The IETF Trust (2007).
+
+   This document is subject to the rights, licenses and restrictions
+   contained in BCP 78, and except as set forth therein, the authors
+   retain all their rights.
+
+   This document and the information contained herein are provided on an
+   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
+   THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
+   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   Intellectual Property Rights or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; nor does it represent that it has
+   made any independent effort to identify any such rights.  Information
+   on the procedures with respect to rights in RFC documents can be
+   found in BCP 78 and BCP 79.
+
+   Copies of IPR disclosures made to the IETF Secretariat and any
+   assurances of licenses to be made available, or the result of an
+   attempt made to obtain a general license or permission for the use of
+   such proprietary rights by implementers or users of this
+   specification can be obtained from the IETF on-line IPR repository at
+   http://www.ietf.org/ipr.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights that may cover technology that may be required to implement
+   this standard.  Please address the information to the IETF at
+   ietf-ipr@ietf.org.
+
+
+
+
+
+
+
+
+
+
+
+
+Siemborski & Gulbrandsen  Standards Track                       [Page 7]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc4978.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,507 @@
+
+
+
+
+
+
+Network Working Group                                     A. Gulbrandsen
+Request for Comments: 4978                        Oryx Mail Systems GmbH
+Category: Standards Track                                    August 2007
+
+
+                      The IMAP COMPRESS Extension
+
+Status of this Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Abstract
+
+   The COMPRESS extension allows an IMAP connection to be effectively
+   and efficiently compressed.
+
+   Table of Contents
+
+   1. Introduction and Overview .......................................2
+   2. Conventions Used in This Document ...............................2
+   3. The COMPRESS Command ............................................3
+   4. Compression Efficiency ..........................................4
+   5. Formal Syntax ...................................................6
+   6. Security Considerations .........................................6
+   7. IANA Considerations .............................................6
+   8. Acknowledgements ................................................7
+   9. References ......................................................7
+      9.1. Normative References .......................................7
+      9.2. Informative References .....................................7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Gulbrandsen                 Standards Track                     [Page 1]
+
+RFC 4978              The IMAP COMPRESS Extension            August 2007
+
+
+1.  Introduction and Overview
+
+   A server which supports the COMPRESS extension indicates this with
+   one or more capability names consisting of "COMPRESS=" followed by a
+   supported compression algorithm name as described in this document.
+
+   The goal of COMPRESS is to reduce the bandwidth usage of IMAP.
+
+   Compared to PPP compression (see [RFC1962]) and modem-based
+   compression (see [MNP] and [V42BIS]), COMPRESS offers much better
+   compression efficiency.  COMPRESS can be used together with Transport
+   Security Layer (TLS) [RFC4346], Simple Authentication and Security
+   layer (SASL) encryption, Virtual Private Networks (VPNs), etc.
+   Compared to TLS compression [RFC3749], COMPRESS has the following
+   (dis)advantages:
+
+   - COMPRESS can be implemented easily both by IMAP servers and
+     clients.
+
+   - IMAP COMPRESS benefits from an intimate knowledge of the IMAP
+     protocol's state machine, allowing for dynamic and aggressive
+     optimization of the underlying compression algorithm's parameters.
+
+   - When the TLS layer implements compression, any protocol using that
+     layer can transparently benefit from that compression (e.g., SMTP
+     and IMAP).  COMPRESS is specific to IMAP.
+
+   In order to increase interoperation, it is desirable to have as few
+   different compression algorithms as possible, so this document
+   specifies only one.  The DEFLATE algorithm (defined in [RFC1951]) is
+   standard, widely available and fairly efficient, so it is the only
+   algorithm defined by this document.
+
+   In order to increase interoperation, IMAP servers that advertise this
+   extension SHOULD also advertise the TLS DEFLATE compression mechanism
+   as defined in [RFC3749].  IMAP clients MAY use either COMPRESS or TLS
+   compression, however, if the client and server support both, it is
+   RECOMMENDED that the client choose TLS compression.
+
+   The extension adds one new command (COMPRESS) and no new responses.
+
+2.  Conventions Used in This Document
+
+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+   document are to be interpreted as described in [RFC2119].
+
+   Formal syntax is defined by [RFC4234] as modified by [RFC3501].
+
+
+
+Gulbrandsen                 Standards Track                     [Page 2]
+
+RFC 4978              The IMAP COMPRESS Extension            August 2007
+
+
+   In the examples, "C:" and "S:" indicate lines sent by the client and
+   server respectively. "[...]" denotes elision.
+
+3.  The COMPRESS Command
+
+   Arguments: Name of compression mechanism: "DEFLATE".
+
+   Responses: None
+
+   Result: OK The server will compress its responses and expects the
+              client to compress its commands.
+           NO Compression is already active via another layer.
+          BAD Command unknown, invalid or unknown argument, or COMPRESS
+              already active.
+
+   The COMPRESS command instructs the server to use the named
+   compression mechanism ("DEFLATE" is the only one defined) for all
+   commands and/or responses after COMPRESS.
+
+   The client MUST NOT send any further commands until it has seen the
+   result of COMPRESS.  If the response was OK, the client MUST compress
+   starting with the first command after COMPRESS.  If the server
+   response was BAD or NO, the client MUST NOT turn on compression.
+
+   If the server responds NO because it knows that the same mechanism is
+   active already (e.g., because TLS has negotiated the same mechanism),
+   it MUST send COMPRESSIONACTIVE as resp-text-code (see [RFC3501],
+   Section 7.1), and the resp-text SHOULD say which layer compresses.
+
+   If the server issues an OK response, the server MUST compress
+   starting immediately after the CRLF which ends the tagged OK
+   response.  (Responses issued by the server before the OK response
+   will, of course, still be uncompressed.)  If the server issues a BAD
+   or NO response, the server MUST NOT turn on compression.
+
+   For DEFLATE (as for many other compression mechanisms), the
+   compressor can trade speed against quality.  When decompressing there
+   isn't much of a tradeoff.  Consequently, the client and server are
+   both free to pick the best reasonable rate of compression for the
+   data they send.
+
+   When COMPRESS is combined with TLS (see [RFC4346]) or SASL (see
+   [RFC4422]) security layers, the sending order of the three extensions
+   MUST be first COMPRESS, then SASL, and finally TLS.  That is, before
+   data is transmitted it is first compressed.  Second, if a SASL
+   security layer has been negotiated, the compressed data is then
+   signed and/or encrypted accordingly.  Third, if a TLS security layer
+   has been negotiated, the data from the previous step is signed and/or
+
+
+
+Gulbrandsen                 Standards Track                     [Page 3]
+
+RFC 4978              The IMAP COMPRESS Extension            August 2007
+
+
+   encrypted accordingly.  When receiving data, the processing order
+   MUST be reversed.  This ensures that before sending, data is
+   compressed before it is encrypted, independent of the order in which
+   the client issues COMPRESS, AUTHENTICATE, and STARTTLS.
+
+   The following example illustrates how commands and responses are
+   compressed during a simple login sequence:
+
+        S: * OK [CAPABILITY IMAP4REV1 STARTTLS COMPRESS=DEFLATE]
+        C: a starttls
+        S: a OK TLS active
+
+            From this point on, everything is encrypted.
+
+        C: b login arnt tnra
+        S: b OK Logged in as arnt
+        C: c compress deflate
+        S: d OK DEFLATE active
+
+            From this point on, everything is compressed before being
+            encrypted.
+
+   The following example demonstrates how a server may refuse to
+   compress twice:
+
+        S: * OK [CAPABILITY IMAP4REV1 STARTTLS COMPRESS=DEFLATE]
+        [...]
+        C: c compress deflate
+        S: c NO [COMPRESSIONACTIVE] DEFLATE active via TLS
+
+4.  Compression Efficiency
+
+   This section is informative, not normative.
+
+   IMAP poses some unusual problems for a compression layer.
+
+   Upstream is fairly simple.  Most IMAP clients send the same few
+   commands again and again, so any compression algorithm that can
+   exploit repetition works efficiently.  The APPEND command is an
+   exception; clients that send many APPEND commands may want to
+   surround large literals with flushes in the same way as is
+   recommended for servers later in this section.
+
+   Downstream has the unusual property that several kinds of data are
+   sent, confusing all dictionary-based compression algorithms.
+
+
+
+
+
+
+Gulbrandsen                 Standards Track                     [Page 4]
+
+RFC 4978              The IMAP COMPRESS Extension            August 2007
+
+
+   One type is IMAP responses.  These are highly compressible; zlib
+   using its least CPU-intensive setting compresses typical responses to
+   25-40% of their original size.
+
+   Another type is email headers.  These are equally compressible, and
+   benefit from using the same dictionary as the IMAP responses.
+
+   A third type is email body text.  Text is usually fairly short and
+   includes much ASCII, so the same compression dictionary will do a
+   good job here, too.  When multiple messages in the same thread are
+   read at the same time, quoted lines etc. can often be compressed
+   almost to zero.
+
+   Finally, attachments (non-text email bodies) are transmitted, either
+   in binary form or encoded with base-64.
+
+   When attachments are retrieved in binary form, DEFLATE may be able to
+   compress them, but the format of the attachment is usually not IMAP-
+   like, so the dictionary built while compressing IMAP does not help.
+   The compressor has to adapt its dictionary from IMAP to the
+   attachment's format, and then back.  A few file formats aren't
+   compressible at all using deflate, e.g., .gz, .zip, and .jpg files.
+
+   When attachments are retrieved in base-64 form, the same problems
+   apply, but the base-64 encoding adds another problem.  8-bit
+   compression algorithms such as deflate work well on 8-bit file
+   formats, however base-64 turns a file into something resembling 6-bit
+   bytes, hiding most of the 8-bit file format from the compressor.
+
+   When using the zlib library (see [RFC1951]), the functions
+   deflateInit2(), deflate(), inflateInit2(), and inflate() suffice to
+   implement this extension.  The windowBits value must be in the range
+   -8 to -15, or else deflateInit2() uses the wrong format.
+   deflateParams() can be used to improve compression rate and resource
+   use.  The Z_FULL_FLUSH argument to deflate() can be used to clear the
+   dictionary (the receiving peer does not need to do anything).
+
+   A client can improve downstream compression by implementing BINARY
+   (defined in [RFC3516]) and using FETCH BINARY instead of FETCH BODY.
+   In the author's experience, the improvement ranges from 5% to 40%
+   depending on the attachment being downloaded.
+
+   A server can improve downstream compression if it hints to the
+   compressor that the data type is about to change strongly, e.g., by
+   sending a Z_FULL_FLUSH at the start and end of large non-text
+   literals (before and after '*CHAR8' in the definition of literal in
+   RFC 3501, page 86).  Small literals are best left alone.  A possible
+   boundary is 5k.
+
+
+
+Gulbrandsen                 Standards Track                     [Page 5]
+
+RFC 4978              The IMAP COMPRESS Extension            August 2007
+
+
+   A server can improve the CPU efficiency both of the server and the
+   client if it adjusts the compression level (e.g., using the
+   deflateParams() function in zlib) at these points, to avoid trying to
+   compress incompressible attachments.  A very simple strategy is to
+   change the level to 0 at the start of a literal provided the first
+   two bytes are either 0x1F 0x8B (as in deflate-compressed files) or
+   0xFF 0xD8 (JPEG), and to keep it at 1-5 the rest of the time.  More
+   complex strategies are possible.
+
+5.  Formal Syntax
+
+   The following syntax specification uses the Augmented Backus-Naur
+   Form (ABNF) notation as specified in [RFC4234].  This syntax augments
+   the grammar specified in [RFC3501].  [RFC4234] defines SP and
+   [RFC3501] defines command-auth, capability, and resp-text-code.
+
+   Except as noted otherwise, all alphabetic characters are case-
+   insensitive.  The use of upper or lower case characters to define
+   token strings is for editorial clarity only.  Implementations MUST
+   accept these strings in a case-insensitive fashion.
+
+       command-auth =/ compress
+
+       compress    = "COMPRESS" SP algorithm
+
+       capability  =/ "COMPRESS=" algorithm
+                     ;; multiple COMPRESS capabilities allowed
+
+       algorithm   = "DEFLATE"
+
+       resp-text-code =/ "COMPRESSIONACTIVE"
+
+   Note that due the syntax of capability names, future algorithm names
+   must be atoms.
+
+6.  Security Considerations
+
+   As for TLS compression [RFC3749].
+
+7.  IANA Considerations
+
+   The IANA has added COMPRESS=DEFLATE to the list of IMAP capabilities.
+
+
+
+
+
+
+
+
+
+Gulbrandsen                 Standards Track                     [Page 6]
+
+RFC 4978              The IMAP COMPRESS Extension            August 2007
+
+
+8.  Acknowledgements
+
+   Eric Burger, Dave Cridland, Tony Finch, Ned Freed, Philip Guenther,
+   Randall Gellens, Tony Hansen, Cullen Jennings, Stephane Maes, Alexey
+   Melnikov, Lyndon Nerenberg, and Zoltan Ordogh have all helped with
+   this document.
+
+   The author would also like to thank various people in the rooms at
+   meetings, whose help is real, but not reflected in the author's
+   mailbox.
+
+9.  References
+
+9.1.  Normative References
+
+   [RFC1951]  Deutsch, P., "DEFLATE Compressed Data Format Specification
+              version 1.3", RFC 1951, May 1996.
+
+   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
+              Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+   [RFC3501]  Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
+              4rev1", RFC 3501, March 2003.
+
+   [RFC4234]  Crocker, D. and P. Overell, "Augmented BNF for Syntax
+              Specifications: ABNF", RFC 4234, October 2005.
+
+9.2.  Informative References
+
+   [RFC1962]  Rand, D., "The PPP Compression Control Protocol (CCP)",
+              RFC 1962, June 1996.
+
+   [RFC3516]  Nerenberg, L., "IMAP4 Binary Content Extension", RFC 3516,
+              April 2003.
+
+   [RFC3749]  Hollenbeck, S., "Transport Layer Security Protocol
+              Compression Methods", RFC 3749, May 2004.
+
+   [RFC4346]  Dierks, T. and E. Rescorla, "The Transport Layer Security
+              (TLS) Protocol Version 1.1", RFC 4346, April 2006.
+
+   [RFC4422]  Melnikov, A. and  K. Zeilenga, "Simple Authentication and
+              Security Layer (SASL)", RFC 4422, June 2006.
+
+   [V42BIS]   ITU, "V.42bis: Data compression procedures for data
+              circuit-terminating equipment (DCE) using error correction
+              procedures", http://www.itu.int/rec/T-REC-V.42bis, January
+              1990.
+
+
+
+Gulbrandsen                 Standards Track                     [Page 7]
+
+RFC 4978              The IMAP COMPRESS Extension            August 2007
+
+
+   [MNP]      Gilbert Held, "The Complete Modem Reference", Second
+              Edition, Wiley Professional Computing, ISBN 0-471-00852-4,
+              May 1994.
+
+Author's Address
+
+    Arnt Gulbrandsen
+    Oryx Mail Systems GmbH
+    Schweppermannstr. 8
+    D-81671 Muenchen
+    Germany
+
+    Fax: +49 89 4502 9758
+    EMail: arnt@oryx.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Gulbrandsen                 Standards Track                     [Page 8]
+
+RFC 4978              The IMAP COMPRESS Extension            August 2007
+
+
+Full Copyright Statement
+
+   Copyright (C) The IETF Trust (2007).
+
+   This document is subject to the rights, licenses and restrictions
+   contained in BCP 78, and except as set forth therein, the authors
+   retain all their rights.
+
+   This document and the information contained herein are provided on an
+   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
+   THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
+   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   Intellectual Property Rights or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; nor does it represent that it has
+   made any independent effort to identify any such rights.  Information
+   on the procedures with respect to rights in RFC documents can be
+   found in BCP 78 and BCP 79.
+
+   Copies of IPR disclosures made to the IETF Secretariat and any
+   assurances of licenses to be made available, or the result of an
+   attempt made to obtain a general license or permission for the use of
+   such proprietary rights by implementers or users of this
+   specification can be obtained from the IETF on-line IPR repository at
+   http://www.ietf.org/ipr.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights that may cover technology that may be required to implement
+   this standard.  Please address the information to the IETF at
+   ietf-ipr@ietf.org.
+
+
+
+
+
+
+
+
+
+
+
+
+Gulbrandsen                 Standards Track                     [Page 9]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc5032.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,283 @@
+
+
+
+
+
+
+Network Working Group                                     E. Burger, Ed.
+Request for Comments: 5032                             BEA Systems, Inc.
+Updates: 3501                                             September 2007
+Category: Standards Track
+
+
+              WITHIN Search Extension to the IMAP Protocol
+
+Status of This Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Abstract
+
+   This document describes the WITHIN extension to IMAP SEARCH.  IMAP
+   SEARCH returns messages whose internal date is within or outside a
+   specified interval.  The mechanism described here, OLDER and YOUNGER,
+   differs from BEFORE and SINCE in that the client specifies an
+   interval, rather than a date.  WITHIN is useful for persistent
+   searches where either the device does not have the capacity to
+   perform the search at regular intervals or the network is of limited
+   bandwidth and thus there is a desire to reduce network traffic from
+   sending repeated requests and redundant responses.
+
+1.  Introduction
+
+   This extension exposes two new search keys, OLDER and YOUNGER, each
+   of which takes a non-zero integer argument corresponding to a time
+   interval in seconds.  The server calculates the time of interest by
+   subtracting the time interval the client presents from the current
+   date and time of the server.  The server then either returns messages
+   older or younger than the resultant time and date, depending on the
+   search key used.
+
+1.1.  Conventions Used in This Document
+
+   In examples, "C:" and "S:" indicate lines sent by the client and
+   server, respectively.
+
+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+   document are to be interpreted as described in RFC 2119 [RFC2119].
+
+
+
+
+
+Burger                      Standards Track                     [Page 1]
+
+RFC 5032                     Search Within                September 2007
+
+
+   When describing the general syntax, we omit some definitions, as RFC
+   3501 [RFC3501] defines them.
+
+2.  Protocol Operation
+
+   An IMAP4 server that supports the capability described here MUST
+   return "WITHIN" as one of the server supported capabilities in the
+   CAPABILITY command.
+
+   For both the OLDER and YOUNGER search keys, the server calculates a
+   target date and time by subtracting the interval, specified in
+   seconds, from the current date and time of the server.  The server
+   then compares the target time with the INTERNALDATE of the message,
+   as specified in IMAP [RFC3501].  For OLDER, messages match if the
+   INTERNALDATE is less recent than or equal to the target time.  For
+   YOUNGER, messages match if the INTERNALDATE is more recent than or
+   equal to the target time.
+
+   Both OLDER and YOUNGER searches always result in exact matching, to
+   the resolution of a second.  However, if one is doing a dynamic
+   evaluation, for example, in a context [CONTEXT], one needs to be
+   aware that the server might perform the evaluation periodically.
+   Thus, the server may delay the updates.  Clients MUST be aware that
+   dynamic search results may not reflect the current state of the
+   mailbox.  If the client needs a search result that reflects the
+   current state of the mailbox, we RECOMMEND that the client issue a
+   new search.
+
+3.  Formal Syntax
+
+   The following syntax specification uses the Augmented Backus-Naur
+   Form (ABNF) notation.  Elements not defined here can be found in the
+   formal syntax of ABNF [RFC4234] and IMAP [RFC3501].
+
+   This document extends RFC 3501 [RFC3501] with two new search keys:
+   OLDER <interval> and YOUNGER <interval>.
+
+   search-key =/ ( "OLDER" / "YOUNGER" ) SP nz-number
+                  ; search-key defined in RFC 3501
+
+4.  Example
+
+   C: a1 SEARCH UNSEEN YOUNGER 259200
+   S: a1 * SEARCH 4 8 15 16 23 42
+
+   Search for all unseen messages within the past 3 days, or 259200
+   seconds, according to the server's current time.
+
+
+
+
+Burger                      Standards Track                     [Page 2]
+
+RFC 5032                     Search Within                September 2007
+
+
+5.  Security Considerations
+
+   The WITHIN extension does not raise any security considerations that
+   are not present in the base protocol.  Considerations are the same as
+   for IMAP [RFC3501].
+
+6.  IANA Considerations
+
+   Per the IMAP RFC [RFC3501], registration of a new IMAP capability in
+   the IMAP Capability registry requires the publication of a standards-
+   track RFC or an IESG approved experimental RFC.  The registry is
+   currently located at
+   <http://www.iana.org/assignments/imap4-capabilities>.  This
+   standards-track document defines the WITHIN IMAP capability.  IANA
+   has added this extension to the IANA IMAP Capability registry.
+
+7.  References
+
+7.1.  Normative References
+
+   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
+              Requirement Levels", RFC 2119, BCP 14, March 1997.
+
+   [RFC3501]  Crispin, M., "Internet Message Access Protocol - Version
+              4rev1", RFC 3501, March 2003.
+
+   [RFC4234]  Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax
+              Specifications: ABNF", RFC 4234, October 2005.
+
+7.2.  Informative References
+
+   [CONTEXT]  Melnikov, D. and C. King, "Contexts for IMAP4", Work
+              in Progress, May 2006.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Burger                      Standards Track                     [Page 3]
+
+RFC 5032                     Search Within                September 2007
+
+
+Appendix A.  Contributors
+
+   Stephane Maes and Ray Cromwell wrote the original version of this
+   document as part of P-IMAP, as well as the first versions for the
+   IETF.  From an attribution perspective, they are clearly authors.
+
+Appendix B.  Acknowledgements
+
+   The authors want to thank all who have contributed key insight and
+   who have extensively reviewed and discussed the concepts of LPSEARCH.
+   They also thank the authors of its early introduction in P-IMAP.
+
+   We also want to give a special thanks to Arnt Gilbrandsen, Ken
+   Murchison, Zoltan Ordogh, and most especially Dave Cridland for their
+   review and suggestions.  A special thank you goes to Alexey Melnikov
+   for his choice submission of text.
+
+Author's Address
+
+   Eric W. Burger (editor)
+   BEA Systems, Inc.
+   USA
+
+   EMail: eric.burger@bea.com
+   URI:   http://www.standardstrack.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Burger                      Standards Track                     [Page 4]
+
+RFC 5032                     Search Within                September 2007
+
+
+Full Copyright Statement
+
+   Copyright (C) The IETF Trust (2007).
+
+   This document is subject to the rights, licenses and restrictions
+   contained in BCP 78, and except as set forth therein, the authors
+   retain all their rights.
+
+   This document and the information contained herein are provided on an
+   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
+   THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
+   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   Intellectual Property Rights or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; nor does it represent that it has
+   made any independent effort to identify any such rights.  Information
+   on the procedures with respect to rights in RFC documents can be
+   found in BCP 78 and BCP 79.
+
+   Copies of IPR disclosures made to the IETF Secretariat and any
+   assurances of licenses to be made available, or the result of an
+   attempt made to obtain a general license or permission for the use of
+   such proprietary rights by implementers or users of this
+   specification can be obtained from the IETF on-line IPR repository at
+   http://www.ietf.org/ipr.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights that may cover technology that may be required to implement
+   this standard.  Please address the information to the IETF at
+   ietf-ipr@ietf.org.
+
+
+
+
+
+
+
+
+
+
+
+
+Burger                      Standards Track                     [Page 5]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc5051.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,395 @@
+
+
+
+
+
+
+Network Working Group                                         M. Crispin
+Request for Comments: 5051                      University of Washington
+Category: Standards Track                                   October 2007
+
+
+         i;unicode-casemap - Simple Unicode Collation Algorithm
+
+Status of This Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Abstract
+
+   This document describes "i;unicode-casemap", a simple case-
+   insensitive collation for Unicode strings.  It provides equality,
+   substring, and ordering operations.
+
+1.  Introduction
+
+   The "i;ascii-casemap" collation described in [COMPARATOR] is quite
+   simple to implement and provides case-independent comparisons for the
+   26 Latin alphabetics.  It is specified as the default and/or baseline
+   comparator in some application protocols, e.g., [IMAP-SORT].
+
+   However, the "i;ascii-casemap" collation does not produce
+   satisfactory results with non-ASCII characters.  It is possible, with
+   a modest extension, to provide a more sophisticated collation with
+   greater multilingual applicability than "i;ascii-casemap".  This
+   extension provides case-independent comparisons for a much greater
+   number of characters.  It also collates characters with diacriticals
+   with the non-diacritical character forms.
+
+   This collation, "i;unicode-casemap", is intended to be an alternative
+   to, and preferred over, "i;ascii-casemap".  It does not replace the
+   "i;basic" collation described in [BASIC].
+
+2.  Unicode Casemap Collation Description
+
+   The "i;unicode-casemap" collation is a simple collation which is
+   case-insensitive in its treatment of characters.  It provides
+   equality, substring, and ordering operations.  The validity test
+   operation returns "valid" for any input.
+
+
+
+
+
+Crispin                     Standards Track                     [Page 1]
+
+RFC 5051                   i;unicode-casemap                October 2007
+
+
+   This collation allows strings in arbitrary (and mixed) character
+   sets, as long as the character set for each string is identified and
+   it is possible to convert the string to Unicode.  Strings which have
+   an unidentified character set and/or cannot be converted to Unicode
+   are not rejected, but are treated as binary.
+
+   Each input string is prepared by converting it to a "titlecased
+   canonicalized UTF-8" string according to the following steps, using
+   UnicodeData.txt ([UNICODE-DATA]):
+
+      (1) A Unicode codepoint is obtained from the input string.
+
+          (a) If the input string is in a known charset that can be
+              converted to Unicode, a sequence in the string's charset
+              is read and checked for validity according to the rules of
+              that charset.  If the sequence is valid, it is converted
+              to a Unicode codepoint.  Note that for input strings in
+              UTF-8, the UTF-8 sequence must be valid according to the
+              rules of [UTF-8]; e.g., overlong UTF-8 sequences are
+              invalid.
+
+          (b) If the input string is in an unknown charset, or an
+              invalid sequence occurs in step (1)(a), conversion ceases.
+              No further preparation is performed, and any partial
+              preparation results are discarded.  The original string is
+              used unchanged with the i;octet comparator.
+
+      (2) The following steps, using UnicodeData.txt ([UNICODE-DATA]),
+          are performed on the resulting codepoint from step (1)(a).
+
+          (a) If the codepoint has a titlecase property in
+              UnicodeData.txt (this is normally the same as the
+              uppercase property), the codepoint is converted to the
+              codepoints in the titlecase property.
+
+          (b) If the resulting codepoint from (2)(a) has a decomposition
+              property of any type in UnicodeData.txt, the codepoint is
+              converted to the codepoints in the decomposition property.
+              This step is recursively applied to each of the resulting
+              codepoints until no more decomposition is possible
+              (effectively Normalization Form KD).
+
+          Example: codepoint U+01C4 (LATIN CAPITAL LETTER DZ WITH CARON)
+          has a titlecase property of U+01C5 (LATIN CAPITAL LETTER D
+          WITH SMALL LETTER Z WITH CARON).  Codepoint U+01C5 has a
+          decomposition property of U+0044 (LATIN CAPITAL LETTER D)
+          U+017E (LATIN SMALL LETTER Z WITH CARON).  U+017E has a
+          decomposition property of U+007A (LATIN SMALL LETTER Z) U+030c
+
+
+
+Crispin                     Standards Track                     [Page 2]
+
+RFC 5051                   i;unicode-casemap                October 2007
+
+
+          (COMBINING CARON).  Neither U+0044, U+007A, nor U+030C have
+          any decomposition properties.  Therefore, U+01C4 is converted
+          to U+0044 U+007A U+030C by this step.
+
+      (3) The resulting codepoint(s) from step (2) is/are appended, in
+          UTF-8 format, to the "titlecased canonicalized UTF-8" string.
+
+      (4) Repeat from step (1) until there is no more data in the input
+          string.
+
+   Following the above preparation process on each string, the equality,
+   ordering, and substring operations are as for i;octet.
+
+   It is permitted to use an alternative implementation of the above
+   preparation process if it produces the same results.  For example, it
+   may be more convenient for an implementation to convert all input
+   strings to a sequence of UTF-16 or UTF-32 values prior to performing
+   any of the step (2) actions.  Similarly, if all input strings are (or
+   are convertible to) Unicode, it may be possible to use UTF-32 as an
+   alternative to UTF-8 in step (3).
+
+      Note: UTF-16 is unsuitable as an alternative to UTF-8 in step (3),
+      because UTF-16 surrogates will cause i;octet to collate codepoints
+      U+E0000 through U+FFFF after non-BMP codepoints.
+
+   This collation is not locale sensitive.  Consequently, care should be
+   taken when using OS-supplied functions to implement this collation.
+   Functions such as strcasecmp and toupper are sometimes locale
+   sensitive and may inconsistently casemap letters.
+
+   The i;unicode-casemap collation is well suited to use with many
+   Internet protocols and computer languages.  Use with natural language
+   is often inappropriate; even though the collation apparently supports
+   languages such as Swahili and English, in real-world use it tends to
+   mis-sort a number of types of string:
+
+   o  people and place names containing scripts that are not collated
+      according to "alphabetical order".
+   o  words with characters that have diacriticals.  However,
+      i;unicode-casemap generally does a better job than i;ascii-casemap
+      for most (but not all) languages.  For example, German umlaut
+      letters will sort correctly, but some Scandinavian letters will
+      not.
+   o  names such as "Lloyd" (which in Welsh sorts after "Lyon", unlike
+      in English),
+   o  strings containing other non-letter symbols; e.g., euro and pound
+      sterling symbols, quotation marks other than '"', dashes/hyphens,
+      etc.
+
+
+
+Crispin                     Standards Track                     [Page 3]
+
+RFC 5051                   i;unicode-casemap                October 2007
+
+
+3.  Unicode Casemap Collation Registration
+
+   <?xml version='1.0'?>
+   <!DOCTYPE collation SYSTEM 'collationreg.dtd'>
+   <collation rfc="5051" scope="global" intendedUse="common">
+   <identifier>i;unicode-casemap</identifier>
+   <title>Unicode Casemap</title>
+   <operations>equality order substring</operations>
+   <specification>RFC 5051</specification>
+   <owner>IETF</owner>
+   <submitter>mrc@cac.washington.edu</submitter>
+   </collation>
+
+4.  Security Considerations
+
+   The security considerations for [UTF-8], [STRINGPREP], and [UNICODE-
+   SECURITY] apply and are normative to this specification.
+
+   The results from this comparator will vary depending upon the
+   implementation for several reasons.  Implementations MUST consider
+   whether these possibilities are a problem for their use case:
+
+   1) New characters added in Unicode may have decomposition or
+      titlecase properties that will not be known to an implementation
+      based upon an older revision of Unicode.  This impacts step (2).
+
+   2) Step (2)(b) defines a subset of Normalization Form KD (NFKD) that
+      does not require normalization of out-of-order diacriticals.
+      However, an implementation MAY use an NFKD library routine that
+      does such normalization.  This impacts step (2)(b) and possibly
+      also step (1)(a), and is an issue only with ill-formed UTF-8
+      input.
+
+   3) The set of charsets handled in step (1)(a) is open-ended.  UTF-8
+      (and, by extension, US-ASCII) are the only mandatory-to-implement
+      charsets.  This impacts step (1)(a).
+
+      Implementations SHOULD, as far as feasible, support all the
+      charsets they are likely to encounter in the input data, in order
+      to avoid poor collation caused by the fall through to the (1)(b)
+      rule.
+
+   4) Other charsets may have revisions which add new characters that
+      are not known to an implementation based upon an older revision.
+      This impacts step (1)(a) and possibly also step (1)(b).
+
+
+
+
+
+
+Crispin                     Standards Track                     [Page 4]
+
+RFC 5051                   i;unicode-casemap                October 2007
+
+
+   An attacker may create input that is ill-formed or in an unknown
+   charset, with the intention of impacting the results of this
+   comparator or exploiting other parts of the system which process this
+   input in different ways.  Note, however, that even well-formed data
+   in a known charset can impact the result of this comparator in
+   unexpected ways.  For example, an attacker can substitute U+0041
+   (LATIN CAPITAL LETTER A) with U+0391 (GREEK CAPITAL LETTER ALPHA) or
+   U+0410 (CYRILLIC CAPITAL LETTER A) in the intention of causing a
+   non-match of strings which visually appear the same and/or causing
+   the string to appear elsewhere in a sort.
+
+5.  IANA Considerations
+
+   The i;unicode-casemap collation defined in section 2 has been added
+   to the registry of collations defined in [COMPARATOR].
+
+6.  Normative References
+
+   [COMPARATOR]          Newman, C., Duerst, M., and A. Gulbrandsen,
+                         "Internet Application Protocol Collation
+                         Registry", RFC 4790, February 2007.
+
+   [STRINGPREP]          Hoffman, P. and M. Blanchet, "Preparation of
+                         Internationalized Strings ("stringprep")", RFC
+                         3454, December 2002.
+
+   [UTF-8]               Yergeau, F., "UTF-8, a transformation format of
+                         ISO 10646", STD 63, RFC 3629, November 2003.
+
+   [UNICODE-DATA]        <http://www.unicode.org/Public/UNIDATA/
+                         UnicodeData.txt>
+
+                         Although the UnicodeData.txt file referenced
+                         here is part of the Unicode standard, it is
+                         subject to change as new characters are added
+                         to Unicode and errors are corrected in Unicode
+                         revisions.  As a result, it may be less stable
+                         than might otherwise be implied by the
+                         standards status of this specification.
+
+   [UNICODE-SECURITY]    Davis, M. and M. Suignard, "Unicode Security
+                         Considerations", February 2006,
+                         <http://www.unicode.org/reports/tr36/>.
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                     [Page 5]
+
+RFC 5051                   i;unicode-casemap                October 2007
+
+
+7.  Informative References
+
+   [BASIC]               Newman, C., Duerst, M., and A. Gulbrandsen,
+                         "i;basic - the Unicode Collation Algorithm",
+                         Work in Progress, March 2007.
+
+   [IMAP-SORT]           Crispin, M. and K. Murchison, "Internet Message
+                         Access Protocol - SORT and THREAD Extensions",
+                         Work in Progress, September 2007.
+
+Author's Address
+
+   Mark R. Crispin
+   Networks and Distributed Computing
+   University of Washington
+   4545 15th Avenue NE
+   Seattle, WA  98105-4527
+
+   Phone: +1 (206) 543-5762
+   EMail: MRC@CAC.Washington.EDU
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                     [Page 6]
+
+RFC 5051                   i;unicode-casemap                October 2007
+
+
+Full Copyright Statement
+
+   Copyright (C) The IETF Trust (2007).
+
+   This document is subject to the rights, licenses and restrictions
+   contained in BCP 78, and except as set forth therein, the authors
+   retain all their rights.
+
+   This document and the information contained herein are provided on an
+   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
+   THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
+   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   Intellectual Property Rights or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; nor does it represent that it has
+   made any independent effort to identify any such rights.  Information
+   on the procedures with respect to rights in RFC documents can be
+   found in BCP 78 and BCP 79.
+
+   Copies of IPR disclosures made to the IETF Secretariat and any
+   assurances of licenses to be made available, or the result of an
+   attempt made to obtain a general license or permission for the use of
+   such proprietary rights by implementers or users of this
+   specification can be obtained from the IETF on-line IPR repository at
+   http://www.ietf.org/ipr.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights that may cover technology that may be required to implement
+   this standard.  Please address the information to the IETF at
+   ietf-ipr@ietf.org.
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin                     Standards Track                     [Page 7]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc5092.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1795 @@
+
+
+
+
+
+
+Network Working Group                                   A. Melnikov, Ed.
+Request for Comments: 5092                                    Isode Ltd.
+Obsoletes: 2192                                                C. Newman
+Updates: 4467                                           Sun Microsystems
+Category: Standards Track                                  November 2007
+
+
+                            IMAP URL Scheme
+
+Status of This Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Abstract
+
+   IMAP (RFC 3501) is a rich protocol for accessing remote message
+   stores.  It provides an ideal mechanism for accessing public mailing
+   list archives as well as private and shared message stores.  This
+   document defines a URL scheme for referencing objects on an IMAP
+   server.
+
+   This document obsoletes RFC 2192.  It also updates RFC 4467.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov & Newman           Standards Track                     [Page 1]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+Table of Contents
+
+   1. Introduction ....................................................2
+   2. Conventions Used in This Document ...............................3
+   3. IMAP userinfo Component (iuserinfo) .............................4
+      3.1. IMAP Mailbox Naming Scope ..................................4
+      3.2. IMAP User Name and Authentication Mechanism ................4
+      3.3. Limitations of enc-user ....................................6
+   4. IMAP Server .....................................................7
+   5. Lists of Messages ...............................................7
+   6. A Specific Message or Message Part ..............................8
+      6.1. URLAUTH Authorized URL .....................................9
+           6.1.1. Concepts ............................................9
+                  6.1.1.1. URLAUTH ....................................9
+                  6.1.1.2. Mailbox Access Key .........................9
+                  6.1.1.3. Authorized Access Identifier ...............9
+                  6.1.1.4. Authorization Mechanism ...................10
+                  6.1.1.5. Authorization Token .......................10
+           6.1.2. URLAUTH Extensions to IMAP URL .....................10
+   7. Relative IMAP URLs .............................................11
+      7.1. absolute-path References ..................................12
+      7.2. relative-path References ..................................12
+   8. Internationalization Considerations ............................13
+   9. Examples .......................................................13
+      9.1. Examples of Relative URLs .................................16
+   10. Security Considerations .......................................16
+      10.1. Security Considerations Specific to URLAUTH Authorized
+            URL ......................................................17
+   11. ABNF for IMAP URL Scheme ......................................17
+   12. IANA Considerations ...........................................21
+      12.1. IANA Registration of imap: URI Scheme ....................21
+   13. References ....................................................22
+      13.1. Normative References .....................................22
+      13.2. Informative References ...................................23
+   Appendix A. Sample Code............................................24
+   Appendix B. List of Changes since RFC 2192.........................30
+   Appendix C. List of Changes since RFC 4467.........................31
+   Appendix D. Acknowledgments........................................31
+
+1.  Introduction
+
+   The IMAP URL scheme is used to designate IMAP servers, mailboxes,
+   messages, MIME bodies [MIME], and search programs on Internet hosts
+   accessible using the IMAP protocol over TCP.
+
+   The IMAP URL follows the common Internet scheme syntax as defined in
+   [URI-GEN].  If :<port> is omitted, the port defaults to 143 (as
+   defined in Section 2.1 of [IMAP4]).
+
+
+
+Melnikov & Newman           Standards Track                     [Page 2]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+   An absolute IMAP URL takes one of the following forms:
+
+      imap://<iserver>[/]
+
+      imap://<iserver>/<enc-mailbox>[<uidvalidity>][?<enc-search>]
+
+      imap://<iserver>/<enc-mailbox>[<uidvalidity>]<iuid>
+       [<isection>][<ipartial>][<iurlauth>]
+
+   The first form is used to refer to an IMAP server (see Section 4),
+   the second form refers to the contents of a mailbox or a set of
+   messages resulting from a search (see Section 5), and the final form
+   refers to a specific message or message part, and possibly a byte
+   range in that part (see Section 6).  If [URLAUTH] extension is
+   supported, then the final form can have the <iurlauth> component (see
+   Section 6.1 for more details).
+
+   The <iserver> component common to all types of absolute IMAP URLs has
+   the following syntax expressed in ABNF [ABNF]:
+
+      [iuserinfo "@"] host [ ":" port ]
+
+   The <iserver> component is the same as "authority" defined in
+   [URI-GEN].  The syntax and uses of the <iuserinfo> ("IMAP userinfo
+   component") are described in detail in Section 3.  The syntax of
+   <host> and <port> is described in [URI-GEN].
+
+2.  Conventions Used in This Document
+
+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+   document are to be interpreted as described in RFC 2119 [KEYWORDS].
+
+   This document references many productions from [URI-GEN].  When the
+   document needs to emphasize IMAP URI-specific differences from [URI-
+   GEN] (i.e., for parts of IMAP URIs that have more restricted syntax
+   than generic URIs), it uses a non-terminal i<foo> to define an IMAP-
+   specific version of the non-terminal <foo> from [URI-GEN].
+
+   Note that the ABNF syntax shown in Section 11 is normative.  Sections
+   2-6 may use a less formal syntax that does not necessarily match the
+   normative ABNF shown in Section 11.  If there are any differences
+   between the syntax shown in Sections 2-6 and Section 11, then the
+   syntax shown in Section 11 must be treated as authoritative.  Non-
+   syntax requirements included in Sections 2-6 are, of course,
+   normative.
+
+
+
+
+
+Melnikov & Newman           Standards Track                     [Page 3]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+3.  IMAP userinfo Component (iuserinfo)
+
+   The <iuserinfo> component conforms to the generic syntax of
+   <userinfo> defined in [URI-GEN].  It has the following syntax
+   expressed in ABNF [ABNF]:
+
+      enc-user [iauth] / [enc-user] iauth
+
+   The meaning of the different parts is described in subsections of
+   this section.
+
+3.1.  IMAP Mailbox Naming Scope
+
+   The "enc-user" part of the "iuserinfo" component, if present, denotes
+   mailbox naming scope.  If it is absent, the IMAP URL can only
+   reference mailboxes with globally unique names, i.e., mailboxes with
+   names that don't change depending on the user the client
+   authenticated as to the IMAP server.  Note that not all IMAP
+   implementations support globally unique names.
+
+   For example, a personal mailbox described by the following URL
+   <imap://michael@example.org/INBOX> is most likely different from a
+   personal mailbox described by <imap://bester@example.org/INBOX>, even
+   though both URLs use the same mailbox name.
+
+3.2.  IMAP User Name and Authentication Mechanism
+
+   The userinfo component (see [URI-GEN]) of an IMAP URI may contain an
+   IMAP user name (a.k.a. authorization identity [SASL], "enc-user")
+   and/or an authentication mechanism. (Note that the "enc-user" also
+   defines a mailbox naming scope as described in Section 3.1).  The
+   IMAP user name and the authentication mechanism are used in the
+   "LOGIN" or "AUTHENTICATE" commands after making the connection to the
+   IMAP server.
+
+   If no user name and no authentication mechanism are supplied, the
+   client MUST authenticate as anonymous to the server.  If the server
+   advertises AUTH=ANONYMOUS IMAP capability, the client MUST use the
+   AUTHENTICATE command with ANONYMOUS [ANONYMOUS] SASL mechanism.  If
+   SASL ANONYMOUS is not available, the (case-insensitive) user name
+   "anonymous" is used with the "LOGIN" command and the Internet email
+   address of the end user accessing the resource is supplied as the
+   password.  The latter option is given in order to provide for
+   interoperability with deployed servers.
+
+   Note that, as described in RFC 3501, the "LOGIN" command MUST NOT be
+   used when the IMAP server advertises the LOGINDISABLED capability.
+
+
+
+
+Melnikov & Newman           Standards Track                     [Page 4]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+   An authentication mechanism (as used by the IMAP AUTHENTICATE
+   command) can be expressed by adding ";AUTH=<enc-auth-type>" to the
+   end of the user name in an IMAP URL.  When such an <enc-auth-type> is
+   indicated, the client SHOULD request appropriate credentials from
+   that mechanism and use the "AUTHENTICATE" command instead of the
+   "LOGIN" command.  If no user name is specified, one MUST be obtained
+   from the mechanism or requested from the user/configuration as
+   appropriate.
+
+   The string ";AUTH=*" indicates that the client SHOULD select an
+   appropriate authentication mechanism.  (Though the '*' character in
+   this usage is not strictly a delimiter, it is being treated like a
+   sub-delim [URI-GEN] in this instance.  It MUST NOT be percent-encoded
+   in this usage, as ";AUTH=%2A" will not match this production.)  It
+   MAY use any mechanism listed in the response to the CAPABILITY
+   command (or CAPABILITY response code) or use an out-of-band security
+   service resulting in a PREAUTH connection.  If no user name is
+   specified and no appropriate authentication mechanisms are available,
+   the client SHOULD fall back to anonymous login as described above.
+   The behavior prescribed in this section allows a URL that grants
+   read-write access to authorized users and read-only anonymous access
+   to other users.
+
+   If a user name is included with no authentication mechanism, then
+   ";AUTH=*" is assumed.
+
+   Clients must take care when resolving a URL that requires or requests
+   any sort of authentication, since URLs can easily come from untrusted
+   sources.  Supplying authentication credentials to the wrong server
+   may compromise the security of the user's account; therefore, the
+   program resolving the URL should meet at least one of the following
+   criteria in this case:
+
+   1) The URL comes from a trusted source, such as a referral server
+      that the client has validated and trusts according to site policy.
+      Note that user entry of the URL may or may not count as a trusted
+      source, depending on the experience level of the user and site
+      policy.
+
+   2) Explicit local site policy permits the client to connect to the
+      server in the URL.  For example, a company example.com may have a
+      site policy to trust all IMAP server names ending in example.com,
+      whereas such a policy would be unwise for example.edu where random
+      students can set up IMAP servers.
+
+   3) The user confirms that connecting to that domain name with the
+      specified credentials and/or mechanism is permitted.  For example,
+      when using "LOGIN" or SASL PLAIN with Transport Layer Security
+
+
+
+Melnikov & Newman           Standards Track                     [Page 5]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+      (TLS), the IMAP URL client presents a dialog box "Is it OK to send
+      your password to server "example.com"?  Please be aware the owners
+      of example.com will be able to reuse your password to connect to
+      other servers on your behalf".
+
+   4) A mechanism is used that validates the server before passing
+      potentially compromising client credentials.  For example, a site
+      has a designated TLS certificate used to certify site-trusted IMAP
+      server certificates, and this has been configured explicitly into
+      the IMAP URL client.  Another example is use of a Simple
+      Authentication and Security Layer (SASL) mechanism such as
+      DIGEST-MD5 [DIGEST-MD5], which supports mutual authentication.
+
+   5) An authentication mechanism is used that will not reveal any
+      information to the server that could be used to compromise future
+      connections.  Examples are SASL ANONYMOUS [ANONYMOUS] or GSSAPI
+      [GSSAPI].
+
+   URLs that do not include a user name but include an authentication
+   mechanism (";AUTH=<mech>") must be treated with extra care, since for
+   some <mech>s they are more likely to compromise the user's primary
+   account.  A URL containing ";AUTH=*" must also be treated with extra
+   care since it might fall back on a weaker security mechanism.
+   Finally, clients are discouraged from using a plaintext password as a
+   fallback with ";AUTH=*" unless the connection has strong encryption.
+
+   A program interpreting IMAP URLs MAY cache open connections to an
+   IMAP server for later reuse.  If a URL contains a user name, only
+   connections authenticated as that user may be reused.  If a URL does
+   not contain a user name or authentication mechanism, then only an
+   anonymous connection may be reused.
+
+   Note that if unsafe or reserved characters such as " " (space) or ";"
+   are present in the user name or authentication mechanism, they MUST
+   be percent-encoded as described in [URI-GEN].
+
+3.3.  Limitations of enc-user
+
+   As per Sections 3.1 and 3.2 of this document, the IMAP URI enc-user
+   has two purposes:
+
+      1) It provides context for user-specific mailbox paths such as
+         "INBOX" (Section 3.1).
+
+      2) It specifies that resolution of the URL requires logging in as
+         that user and limits use of that URL to only that user (Section
+         3.2).
+
+
+
+
+Melnikov & Newman           Standards Track                     [Page 6]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+   An obvious limitation of using the same field for both purposes is
+   that the URL can be resolved only by the mailbox owner.  In order to
+   avoid this restriction, implementations should use globally unique
+   mailbox names (see Section 3.1) whenever possible.
+
+      Note: There is currently no general way in IMAP of learning a
+      globally unique name for a mailbox.  However, by looking at the
+      NAMESPACE [NAMESPACE] command result, it is possible to determine
+      whether or not a mailbox name is globally unique.
+
+   The URLAUTH component overrides the second purpose of the enc-user in
+   the IMAP URI and by default permits the URI to be resolved by any
+   user permitted by the <access> identifier.  URLAUTH and <access>
+   identifier are described in Section 6.1.
+
+4.  IMAP Server
+
+   An IMAP URL referring to an IMAP server has the following form:
+
+      imap://<iserver>[/]
+
+   This URL type is frequently used to describe a location of an IMAP
+   server, both in referrals and in configuration.  It may optionally
+   contain the <iuserinfo> component (see Sections 3 and 11).  A program
+   interpreting this URL would issue the standard set of commands it
+   uses to present a view of the content of the IMAP server, as visible
+   to the user described by the "enc-user" part of the <iuserinfo>
+   component, if the "enc-user" part is specified.
+
+5.  Lists of Messages
+
+   An IMAP URL referring to a list of messages has the following form:
+
+      imap://<iserver>/<enc-mailbox>[<uidvalidity>][?<enc-search>]
+
+   The <enc-mailbox> field is used as the argument to the IMAP4 "SELECT"
+   or "EXAMINE" command.  Note that if unsafe or reserved characters
+   such as " " (space), ";", or "?" are present in <enc-mailbox>, they
+   MUST be percent-encoded as described in [URI-GEN].
+
+   The <uidvalidity> field is optional.  If it is present, it MUST be
+   the same as the value of IMAP4 UIDVALIDITY response code at the time
+   the URL was created.  This MUST be used by the program interpreting
+   the IMAP URL to determine if the URL is stale.  If the IMAP URL is
+   stale, then the program should behave as if the corresponding mailbox
+   doesn't exist.
+
+
+
+
+
+Melnikov & Newman           Standards Track                     [Page 7]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+   Note that the <uidvalidity> field is a modifier to the <enc-mailbox>,
+   i.e., it is considered a part of the last "component" (as used in
+   [URI-GEN]) of the <enc-mailbox>.  This is significant during relative
+   URI resolution.
+
+   The "?<enc-search>" field is optional.  If it is not present, the
+   program interpreting the URL will present the entire content of the
+   mailbox.
+
+   If the "?<enc-search>" field is present, the program interpreting the
+   URL should use the contents of this field as arguments following an
+   IMAP4 SEARCH command.  These arguments are likely to contain unsafe
+   characters such as " " (space) (which are likely to be present in the
+   <enc-search>).  If unsafe characters are present, they MUST be
+   percent-encoded as described in [URI-GEN].
+
+   Note that quoted strings and non-synchronizing literals [LITERAL+]
+   are allowed in the <enc-search> content; however, synchronizing
+   literals are not allowed, as their presence would effectively mean
+   that the agent interpreting IMAP URLs needs to parse an <enc-search>
+   content, find all synchronizing literals, and perform proper command
+   continuation request handling (see Sections 4.3 and 7 of [IMAP4]).
+
+6.  A Specific Message or Message Part
+
+   An IMAP URL referring to a specific message or message part has the
+   following form:
+
+      imap://<iserver>/<enc-mailbox>[<uidvalidity>]<iuid>
+      [<isection>][<ipartial>][<iurlauth>]
+
+   The <enc-mailbox> and [uidvalidity] are as defined in Section 5
+   above.
+
+   If <uidvalidity> is present in this form, it SHOULD be used by the
+   program interpreting the URL to determine if the URL is stale.
+
+   The <iuid> refers to an IMAP4 message Unique Identifier (UID), and it
+   SHOULD be used as the <set> argument to the IMAP4 "UID FETCH"
+   command.
+
+   The <isection> field is optional.  If not present, the URL refers to
+   the entire Internet message as returned by the IMAP command "UID
+   FETCH <uid> BODY.PEEK[]".  If present, the URL refers to the object
+   returned by a "UID FETCH <uid> BODY.PEEK[<section>]" command.  The
+   type of the object may be determined by using a "UID FETCH <uid>
+   BODYSTRUCTURE" command and locating the appropriate part in the
+
+
+
+
+Melnikov & Newman           Standards Track                     [Page 8]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+   resulting BODYSTRUCTURE.  Note that unsafe characters in [isection]
+   MUST be percent-encoded as described in [URI-GEN].
+
+   The <ipartial> field is optional.  If present, it effectively appends
+   "<<partial-range>>" to the end of the UID FETCH BODY.PEEK[<section>]
+   command constructed as described in the previous paragraph.  In other
+   words, it allows the client to request a byte range of the
+   message/message part.
+
+   The <iurlauth> field is described in detail in Section 6.1.
+
+6.1.  URLAUTH Authorized URL
+
+   URLAUTH authorized URLs are only supported by an IMAP server
+   advertising the URLAUTH IMAP capability [URLAUTH].
+
+6.1.1.  Concepts
+
+6.1.1.1.  URLAUTH
+
+   URLAUTH is a component, appended at the end of a URL, that conveys
+   authorization to access the data addressed by that URL.  It contains
+   an authorized access identifier, an authorization mechanism name, and
+   an authorization token.  The authorization token is generated from
+   the URL, the authorized access identifier, authorization mechanism
+   name, and a mailbox access key.
+
+      Note: This specification only allows for the URLAUTH component in
+      IMAP URLs describing a message or its part.
+
+6.1.1.2.  Mailbox Access Key
+
+   The mailbox access key is an unpredictable, random string.  To ensure
+   unpredictability, the random string with at least 128 bits of entropy
+   is generated by software or hardware (not by the human user).
+
+   Each user has a table of mailboxes and an associated mailbox access
+   key for each mailbox.  Consequently, the mailbox access key is per-
+   user and per-mailbox.  In other words, two users sharing the same
+   mailbox each have a different mailbox access key for that mailbox,
+   and each mailbox accessed by a single user also has a different
+   mailbox access key.
+
+6.1.1.3.  Authorized Access Identifier
+
+   The authorized <access> identifier restricts use of the URLAUTH
+   authorized URL to certain users authorized on the server, as
+   described in Section 6.1.2.
+
+
+
+Melnikov & Newman           Standards Track                     [Page 9]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+6.1.1.4.  Authorization Mechanism
+
+   The authorization mechanism is the algorithm by which the URLAUTH is
+   generated and subsequently verified, using the mailbox access key.
+
+6.1.1.5.  Authorization Token
+
+   The authorization token is a deterministic string of at least 128
+   bits that an entity with knowledge of the secret mailbox access key
+   and URL authorization mechanism can use to verify the URL.
+
+6.1.2.  URLAUTH Extensions to IMAP URL
+
+   A specific message or message part IMAP URL can optionally contain
+   ";EXPIRE=<datetime>" and/or ";URLAUTH=<access>:<mech>:<token>".
+
+   When ";EXPIRE=<datetime>" is used, this indicates the latest date and
+   time that the URL is valid.  After that date and time, the URL has
+   expired and server implementations MUST reject the URL.  If
+   ";EXPIRE=<datetime>" is not used, the URL has no expiration, but can
+   still be revoked using the RESETKEY command [URLAUTH].
+
+   The URLAUTH takes the form ";URLAUTH=<access>:<mech>:<token>", and it
+   MUST be at the end of the URL.  It is composed of three parts.  The
+   <access> portion provides the authorized access identifiers that may
+   constrain the operations and users that are permitted to use this
+   URL.  The <mech> portion provides the authorization mechanism used by
+   the IMAP server to generate the authorization token that follows.
+   The <token> portion provides the authorization token, which can be
+   generated using the GENURLAUTH command [URLAUTH].
+
+   The "submit+" <access> identifier prefix, followed by a userid,
+   indicates that only a userid authorized as a message submission
+   entity on behalf of the specified userid is permitted to use this
+   URL.  The IMAP server does not validate the specified userid but does
+   validate that the IMAP session has an authorization identity that is
+   authorized as a message submission entity.  The authorized message
+   submission entity MUST validate the userid prior to contacting the
+   IMAP server.
+
+   The "user+" <access> identifier prefix, followed by a userid,
+   indicates that use of this URL is limited to IMAP sessions that are
+   logged in as the specified userid (that is, have authorization
+   identity as that userid).
+
+      Note: If a SASL mechanism that provides both authorization and
+      authentication identifiers is used to authenticate to the IMAP
+      server, the "user+" <access> identifier MUST match the
+
+
+
+Melnikov & Newman           Standards Track                    [Page 10]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+      authorization identifier.  If the SASL mechanism can't transport
+      the authorization identifier, the "user+" <access> identifier MUST
+      match the authorization identifier derived from the authentication
+      identifier (see [SASL]).
+
+   The "authuser" <access> identifier indicates that use of this URL is
+   limited to authenticated IMAP sessions that are logged in as any
+   non-anonymous user (that is, have authorization identity as a non-
+   anonymous user) of that IMAP server.  To restate this: use of this
+   type of URL is prohibited to anonymous IMAP sessions, i.e., any
+   URLFETCH command containing this type of URL issued in an anonymous
+   session MUST return NIL in the URLFETCH response.
+
+   The "anonymous" <access> identifier indicates that use of this URL is
+   not restricted by session authorization identity; that is, any IMAP
+   session in authenticated or selected state (as defined in [IMAP4]),
+   including anonymous sessions, may issue a URLFETCH [URLAUTH] using
+   this URL.
+
+   The authorization token is represented as an ASCII-encoded
+   hexadecimal string, which is used to authorize the URL.  The length
+   and the calculation of the authorization token depend upon the
+   mechanism used, but in all cases, the authorization token is at least
+   128 bits (and therefore at least 32 hexadecimal digits).
+
+   Example:
+
+      <imap://joe@example.com/INBOX/;uid=20/;section=1.2;urlauth=
+      submit+fred:internal:91354a473744909de610943775f92038>
+
+7.  Relative IMAP URLs
+
+   Relative IMAP URLs are permitted and are resolved according to the
+   rules defined in [URI-GEN].  In particular, in IMAP URLs parameters
+   (such as ";uid=" or ";section=") are treated as part of the normal
+   path with respect to relative URL resolution.
+
+   [URI-GEN] defines four forms of relative URLs: <inetwork-path>,
+   <iabsolute-path>, <irelative-path>, and <ipath-empty>.  Their syntax
+   is defined in Section 11.
+
+   A relative reference that begins with two slash characters is termed
+   a network-path reference (<inetwork-path>); such references are
+   rarely used, because in most cases they can be replaced with an
+   equivalent absolute URL.  A relative reference that begins with a
+   single slash character is termed an absolute-path reference
+   (<iabsolute-path>; see also Section 7.1).  A relative reference that
+   does not begin with a slash character is termed a relative-path
+
+
+
+Melnikov & Newman           Standards Track                    [Page 11]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+   reference (<irelative-path>; see also Section 7.2).  The final form
+   is <ipath-empty>, which is "same-document reference" (see Section 4.4
+   of [URI-GEN]).
+
+   The following observations about relative URLs are important:
+
+   The <iauth> grammar element (which is a part of <iuserinfo>, which
+   is, in turn, a part of <iserver>; see Section 3) is considered part
+   of the user name for purposes of resolving relative IMAP URLs.  This
+   means that unless a new user name/server specification is included in
+   the relative URL, the authentication mechanism is inherited from the
+   base IMAP URL.
+
+   URLs always use "/" as the hierarchy delimiter for the purpose of
+   resolving paths in relative URLs.  IMAP4 permits the use of any
+   hierarchy delimiter in mailbox names.  For this reason, relative
+   mailbox paths will only work if the mailbox uses "/" as the hierarchy
+   delimiter.  Relative URLs may be used on mailboxes that use other
+   delimiters, but in that case, the entire mailbox name MUST be
+   specified in the relative URL or inherited as a whole from the base
+   URL.
+
+   If an IMAP server allows for mailbox names starting with "./" or
+   "../", ending with "/." or "/..", or containing sequences "/../" or
+   "/./", then such mailbox names MUST be percent-encoded as described
+   in [URI-GEN].  Otherwise, they would be misinterpreted as dot-
+   segments (see Section 3.3 of [URI-GEN]), which are processed
+   specially during the relative path resolution process.
+
+7.1.  absolute-path References
+
+   A relative reference that begins with a single slash character is
+   termed an absolute-path reference (see Section 4.2 of [URI-GEN]).  If
+   an IMAP server permits mailbox names with a leading "/", then the
+   leading "/" MUST be percent-encoded as described in [URI-GEN].
+   Otherwise, the produced absolute-path reference URI will be
+   misinterpreted as a network-path reference [URI-GEN] described by the
+   <inetwork-path> non-terminal.
+
+7.2.  relative-path References
+
+   A relative reference that does not begin with a slash character is
+   termed a relative-path reference [URI-GEN].  Implementations MUST NOT
+   generate or accept relative-path IMAP references.
+
+   See also Section 4.2 of [URI-GEN] for restrictions on relative-path
+   references.
+
+
+
+
+Melnikov & Newman           Standards Track                    [Page 12]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+8.  Internationalization Considerations
+
+   IMAP4, Section 5.1.3 [IMAP4] includes a convention for encoding non-
+   US-ASCII characters in IMAP mailbox names.  Because this convention
+   is private to IMAP, it is necessary to convert IMAP's encoding to one
+   that can be more easily interpreted by a URL display program.  For
+   this reason, IMAP's modified UTF-7 encoding for mailboxes MUST be
+   converted to UTF-8 [UTF-8].  Since 8-bit octets are not permitted in
+   URLs, the UTF-8 octets are percent-encoded as required by the URL
+   specification [URI-GEN], Section 2.1.  Sample code is included in
+   Appendix A to demonstrate this conversion.
+
+   IMAP user names are UTF-8 strings and MUST be percent-encoded as
+   required by the URL specification [URI-GEN], Section 2.1.
+
+   Also note that IMAP SEARCH criteria can contain non-US-ASCII
+   characters.  8-bit octets in those strings MUST be percent-encoded as
+   required by the URL specification [URI-GEN], Section 2.1.
+
+9.  Examples
+
+   The following examples demonstrate how an IMAP4 client program might
+   translate various IMAP4 URLs into a series of IMAP4 commands.
+   Commands sent from the client to the server are prefixed with "C:",
+   and responses sent from the server to the client are prefixed with
+   "S:".
+
+   The URL:
+
+      <imap://minbari.example.org/gray-council;UIDVALIDITY=385759045/;
+      UID=20/;PARTIAL=0.1024>
+
+   may result in the following client commands and server responses:
+
+      <connect to minbari.example.org, port 143>
+      S: * OK [CAPABILITY IMAP4rev1 STARTTLS AUTH=ANONYMOUS] Welcome
+      C: A001 AUTHENTICATE ANONYMOUS
+      S: +
+      C: c2hlcmlkYW5AYmFieWxvbjUuZXhhbXBsZS5vcmc=
+      S: A001 OK Welcome sheridan@babylon5.example.org
+      C: A002 SELECT gray-council
+      <client verifies the UIDVALIDITY matches>
+      C: A003 UID FETCH 20 BODY.PEEK[]<0.1024>
+
+   The URL:
+
+      <imap://psicorp.example.org/~peter/%E6%97%A5%E6%9C%AC%E8%AA%9E/
+      %E5%8F%B0%E5%8C%97>
+
+
+
+Melnikov & Newman           Standards Track                    [Page 13]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+   may result in the following client commands:
+
+      <connect to psicorp.example.org, port 143>
+      S: * OK [CAPABILITY IMAP4rev1 STARTTLS AUTH=CRAM-MD5] Welcome
+      C: A001 LOGIN ANONYMOUS bester@psycop.psicorp.example.org
+      C: A002 SELECT ~peter/&ZeVnLIqe-/&U,BTFw-
+      <commands the client uses for viewing the contents of
+       the mailbox>
+
+   The URL:
+
+      <imap://;AUTH=GSSAPI@minbari.example.org/gray-council/;uid=20/
+      ;section=1.2>
+
+   may result in the following client commands:
+
+      <connect to minbari.example.org, port 143>
+      S: * OK Greetings
+      C: A000 CAPABILITY
+      S: * CAPABILITY IMAP4rev1 STARTTLS AUTH=GSSAPI
+      S: A000 OK
+      C: A001 AUTHENTICATE GSSAPI
+      <authentication exchange>
+      C: A002 SELECT gray-council
+      C: A003 UID FETCH 20 BODY.PEEK[1.2]
+
+   If the following relative URL is located in that body part:
+
+      <;section=1.4>
+
+   this could result in the following client commands:
+
+      C: A004 UID FETCH 20 (BODY.PEEK[1.2.MIME]
+            BODY.PEEK[1.MIME]
+            BODY.PEEK[HEADER.FIELDS (Content-Location)])
+      <Client looks for Content-Location headers in
+       result.  If no such headers, then it does the following>
+      C: A005 UID FETCH 20 BODY.PEEK[1.4]
+
+   The URL:
+
+      <imap://;AUTH=*@minbari.example.org/gray%20council?
+      SUBJECT%20shadows>
+
+
+
+
+
+
+
+
+Melnikov & Newman           Standards Track                    [Page 14]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+   could result in the following:
+
+      <connect to minbari.example.org, port 143>
+      S: * OK Welcome
+      C: A001 CAPABILITY
+      S: * CAPABILITY IMAP4rev1 AUTH=DIGEST-MD5
+      S: A001 OK
+      C: A002 AUTHENTICATE DIGEST-MD5
+      <authentication exchange>
+      S: A002 OK user lennier authenticated
+      C: A003 SELECT "gray council"
+      ...
+      C: A004 SEARCH SUBJECT shadows
+      S: * SEARCH 8 10 13 14 15 16
+      S: A004 OK SEARCH completed
+      C: A005 FETCH 8,10,13:16 ALL
+      ...
+
+   In the example above, the client has implementation-dependent
+   choices.  The authentication mechanism could be anything, including
+   PREAUTH.  The final FETCH command could fetch more or less
+   information about the messages, depending on what it wishes to
+   display to the user.
+
+   The URL:
+
+      <imap://john;AUTH=*@minbari.example.org/babylon5/personel?
+      charset%20UTF-8%20SUBJECT%20%7B14+%7D%0D%0A%D0%98%D0%B2%
+      D0%B0%D0%BD%D0%BE%D0%B2%D0%B0>
+
+   shows that 8-bit data can be sent using non-synchronizing literals
+   [LITERAL+].  This could result in the following:
+
+      <connect to minbari.example.org, port 143>
+      S: * OK Hi there
+      C: A001 CAPABILITY
+      S: * CAPABILITY IMAP4rev1 LITERAL+ AUTH=DIGEST-MD5
+      S: A001 OK
+      C: A002 AUTHENTICATE DIGEST-MD5
+      <authentication exchange>
+      S: A002 OK user john authenticated
+      C: A003 SELECT babylon5/personel
+      ...
+      C: A004 SEARCH CHARSET UTF-8 SUBJECT {14+}
+      C: XXXXXXXXXXXXXX
+      S: * SEARCH 7 10 12
+      S: A004 OK SEARCH completed
+      C: A005 FETCH 7,10,12 ALL
+
+
+
+Melnikov & Newman           Standards Track                    [Page 15]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+      ...
+
+   where XXXXXXXXXXXXXX is 14 bytes of UTF-8 encoded data as specified
+   in the URL above.
+
+9.1.  Examples of Relative URLs
+
+   The following absolute-path reference
+
+      </foo/;UID=20/..>
+
+   is the same as
+
+      </foo>
+
+   That is, both of them reference the mailbox "foo" located on the IMAP
+   server described by the corresponding Base URI.
+
+   The following relative-path reference
+
+      <;UID=20>
+
+   references a message with UID in the mailbox specified by the Base
+   URI.
+
+   The following edge case example demonstrates that the ;UIDVALIDITY=
+   modifier is a part of the mailbox name as far as relative URI
+   resolution is concerned:
+
+      <..;UIDVALIDITY=385759045/;UID=20>
+
+   In this example, ".." is not a dot-segment [URI-GEN].
+
+10.  Security Considerations
+
+   Security considerations discussed in the IMAP specification [IMAP4]
+   and the URI specification [URI-GEN] are relevant.  Security
+   considerations related to authenticated URLs are discussed in Section
+   3.2 of this document.
+
+   Many email clients store the plaintext password for later use after
+   logging into an IMAP server.  Such clients MUST NOT use a stored
+   password in response to an IMAP URL without explicit permission from
+   the user to supply that password to the specified host name.
+
+   Clients resolving IMAP URLs that wish to achieve data confidentiality
+   and/or integrity SHOULD use the STARTTLS command (if supported by the
+
+
+
+
+Melnikov & Newman           Standards Track                    [Page 16]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+   server) before starting authentication, or use a SASL mechanism, such
+   as GSSAPI, that provides a confidentiality security layer.
+
+10.1.  Security Consideration Specific to URLAUTH Authorized URL
+
+   The "user+<userid>" <access> identifier limits resolution of that URL
+   to a particular userid, whereas the "submit+<userid>" <access>
+   identifier is more general and simply requires that the session be
+   authorized by a user that has been granted a "submit" role within the
+   authentication system.  Use of either of these mechanisms limits the
+   scope of the URL.  An attacker who cannot authenticate using the
+   appropriate credentials cannot make use of the URL.
+
+   The "authuser" and "anonymous" <access> identifiers do not have this
+   level of protection.  These access identifiers are primarily useful
+   for public export of data from an IMAP server, without requiring that
+   it be copied to a web or anonymous FTP server.
+
+   The decision to use the "authuser" <access> identifier should be made
+   with caution.  An "authuser" <access> identifier can be used by any
+   authorized user of the IMAP server; therefore, use of this access
+   identifier should be limited to content that may be disclosed to any
+   authorized user of the IMAP server.
+
+   The decision to use the "anonymous" <access> identifier should be
+   made with extreme caution.  An "anonymous" <access> identifier can be
+   used by anyone; therefore, use of this access identifier should be
+   limited to content that may be disclosed to anyone.
+
+11.  ABNF for IMAP URL Scheme
+
+   Formal syntax is defined using ABNF [ABNF], extending the ABNF rules
+   in Section 9 of [IMAP4].  Elements not defined here can be found in
+   [ABNF], [IMAP4], [IMAPABNF], or [URI-GEN].  Strings are not case
+   sensitive, and free insertion of linear white space is not permitted.
+
+   sub-delims-sh = "!" / "$" / "'" / "(" / ")" /
+                   "*" / "+" / ","
+                      ;; Same as [URI-GEN] sub-delims,
+                      ;; but without ";", "&" and "=".
+
+   uchar            = unreserved / sub-delims-sh / pct-encoded
+
+   achar            = uchar / "&" / "="
+                      ;; Same as [URI-GEN] 'unreserved / sub-delims /
+                      ;; pct-encoded', but ";" is disallowed.
+
+   bchar            = achar / ":" / "@" / "/"
+
+
+
+Melnikov & Newman           Standards Track                    [Page 17]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+   enc-auth-type    = 1*achar
+                   ; %-encoded version of [IMAP4] "auth-type"
+
+   enc-mailbox      = 1*bchar
+                  ; %-encoded version of [IMAP4] "mailbox"
+
+   enc-search       = 1*bchar
+                           ; %-encoded version of [IMAPABNF]
+                           ; "search-program".  Note that IMAP4
+                           ; literals may not be used in
+                           ; a "search-program", i.e., only
+                           ; quoted or non-synchronizing
+                           ; literals (if the server supports
+                           ; LITERAL+ [LITERAL+]) are allowed.
+
+   enc-section      = 1*bchar
+                  ; %-encoded version of [IMAP4] "section-spec"
+
+   enc-user         = 1*achar
+                  ; %-encoded version of [IMAP4] authorization
+                  ; identity or "userid".
+
+   imapurl          = "imap://" iserver ipath-query
+               ; Defines an absolute IMAP URL
+
+   ipath-query      = ["/" [ icommand ]]
+                    ; Corresponds to "path-abempty [ "?" query ]"
+                    ; in [URI-GEN]
+
+   Generic syntax for relative URLs is defined in Section 4.2 of
+   [URI-GEN].  For ease of implementation, the relative IMAP URL syntax
+   is defined below:
+
+   imapurl-rel     = inetwork-path
+
+                     / iabsolute-path
+                     / irelative-path
+                     / ipath-empty
+
+   inetwork-path   = "//" iserver ipath-query
+               ; Corresponds to '"//" authority path-abempty
+               ; [ "?" query ]' in [URI-GEN]
+
+   iabsolute-path  = "/" [ icommand ]
+               ; icommand, if present, MUST NOT start with '/'.
+               ;
+               ; Corresponds to 'path-absolute [ "?" query ]'
+               ; in [URI-GEN]
+
+
+
+Melnikov & Newman           Standards Track                    [Page 18]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+   irelative-path  = imessagelist /
+                     imsg-or-part
+               ; Corresponds to 'path-noscheme [ "?" query ]'
+               ; in [URI-GEN]
+
+   imsg-or-part    = ( imailbox-ref "/" iuid-only ["/" isection-only]
+                       ["/" ipartial-only] ) /
+                     ( iuid-only ["/" isection-only]
+                       ["/" ipartial-only] ) /
+                     ( isection-only ["/" ipartial-only] ) /
+                     ipartial-only
+
+   ipath-empty     = 0<pchar>
+                    ; Zero characters.
+                    ; The same-document reference.
+
+   The following three rules are only used in the presence of the IMAP
+   [URLAUTH] extension:
+
+   authimapurl     = "imap://" iserver "/" imessagepart
+                     ; Same as "imapurl" when "[icommand]" is
+                     ; "imessagepart"
+
+   authimapurlfull = authimapurl iurlauth
+                     ; Same as "imapurl" when "[icommand]" is
+                     ; "imessagepart iurlauth"
+
+   authimapurlrump = authimapurl iurlauth-rump
+
+
+   enc-urlauth     = 32*HEXDIG
+
+   iurlauth        = iurlauth-rump iua-verifier
+
+   iua-verifier    = ":" uauth-mechanism ":" enc-urlauth
+
+   iurlauth-rump   = [expire] ";URLAUTH=" access
+
+   access          = ("submit+" enc-user) / ("user+" enc-user) /
+                       "authuser" / "anonymous"
+
+   expire          = ";EXPIRE=" date-time
+                         ; date-time is defined in [DATETIME]
+
+   uauth-mechanism = "INTERNAL" / 1*(ALPHA / DIGIT / "-" / ".")
+                        ; Case-insensitive.
+                        ; New mechanisms MUST be registered with IANA.
+
+
+
+
+Melnikov & Newman           Standards Track                    [Page 19]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+   iauth            = ";AUTH=" ( "*" / enc-auth-type )
+
+   icommand         = imessagelist /
+                      imessagepart [iurlauth]
+
+   imailbox-ref     = enc-mailbox [uidvalidity]
+
+   imessagelist     = imailbox-ref [ "?" enc-search ]
+                  ; "enc-search" is [URI-GEN] "query".
+
+   imessagepart     = imailbox-ref iuid [isection] [ipartial]
+
+   ipartial         = "/" ipartial-only
+
+   ipartial-only    = ";PARTIAL=" partial-range
+
+   isection         = "/" isection-only
+
+   isection-only    = ";SECTION=" enc-section
+
+   iserver          = [iuserinfo "@"] host [ ":" port ]
+                           ; This is the same as "authority" defined
+                           ; in [URI-GEN].  See [URI-GEN] for "host"
+                           ; and "port" definitions.
+
+   iuid             = "/" iuid-only
+
+   iuid-only        = ";UID=" nz-number
+                  ; See [IMAP4] for "nz-number" definition
+
+   iuserinfo        = enc-user [iauth] / [enc-user] iauth
+                                ; conforms to the generic syntax of
+                                ; "userinfo" as defined in [URI-GEN].
+
+   partial-range    = number ["." nz-number]
+                  ; partial FETCH.  The first number is
+                           ; the offset of the first byte,
+                           ; the second number is the length of
+                           ; the fragment.
+
+   uidvalidity      = ";UIDVALIDITY=" nz-number
+                       ; See [IMAP4] for "nz-number" definition
+
+
+
+
+
+
+
+
+
+Melnikov & Newman           Standards Track                    [Page 20]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+12.  IANA Considerations
+
+   IANA has updated the "imap" definition in the "Uniform Resource
+   Identifier scheme registry" to point to this document.
+
+   The registration template (as per [URI-REG]) is specified in Section
+   12.1 of this document.
+
+12.1.  IANA Registration of imap: URI Scheme
+
+   This section provides the information required to register the imap:
+   URI scheme.
+
+   URI scheme name: imap
+
+   Status: permanent
+
+   URI scheme syntax:
+
+      See Section 11 of [RFC5092].
+
+   URI scheme semantics:
+
+      The imap: URI scheme is used to designate IMAP servers, mailboxes,
+      messages, MIME bodies [MIME] and their parts, and search programs
+      on Internet hosts accessible using the IMAP protocol.
+
+      There is no MIME type associated with this URI.
+
+   Encoding considerations:
+
+      See Section 8 of [RFC5092].
+
+   Applications/protocols that use this URI scheme name:
+
+      The imap: URI is intended to be used by applications that might
+      need access to an IMAP mailstore.  Such applications may include
+      (but are not limited to) IMAP-capable web browsers; IMAP clients
+      that wish to access a mailbox, message, or edit a message on the
+      server using [CATENATE]; [SUBMIT] clients and servers that are
+      requested to assemble a complete message on submission using
+      [BURL].
+
+   Interoperability considerations:
+
+      A widely deployed IMAP client Netscape Mail (and possibly
+      Mozilla/Thunderbird/Seamonkey) uses a different imap: scheme
+      internally.
+
+
+
+Melnikov & Newman           Standards Track                    [Page 21]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+   Security considerations:
+
+      See Security Considerations (Section 10) of [RFC5092].
+
+   Contact:
+
+      Alexey Melnikov <alexey.melnikov@isode.com>
+
+   Author/Change controller:
+
+      IESG
+
+   References:
+
+      [RFC5092] and [IMAP4].
+
+13. References
+
+13.1.  Normative References
+
+   [KEYWORDS]   Bradner, S., "Key words for use in RFCs to Indicate
+                Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+   [IMAP4]      Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
+                4rev1", RFC 3501, March 2003.
+
+   [IMAPABNF]   Melnikov, A. and C. Daboo, "Collected Extensions to
+                IMAP4 ABNF", RFC 4466, April 2006.
+
+   [ABNF]       Crocker, D., Ed., and P. Overell, "Augmented BNF for
+                Syntax Specifications: ABNF", RFC 4234, October 2005.
+
+   [MIME]       Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+                Extensions (MIME) Part One: Format of Internet Message
+                Bodies", RFC 2045, November 1996.
+
+   [URI-GEN]    Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
+                Resource Identifier (URI): Generic Syntax", STD 66, RFC
+                3986, January 2005.
+
+   [UTF-8]      Yergeau, F., "UTF-8, a transformation format of ISO
+                10646", STD 63, RFC 3629, November 2003.
+
+   [NAMESPACE]  Gahrns, M. and C. Newman, "IMAP4 Namespace", RFC 2342,
+                May 1998.
+
+   [LITERAL+]   Myers, J., "IMAP4 non-synchronizing literals", RFC 2088,
+                January 1997.
+
+
+
+Melnikov & Newman           Standards Track                    [Page 22]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+   [ANONYMOUS]  Zeilenga, K., "Anonymous Simple Authentication and
+                Security Layer (SASL) Mechanism", RFC 4505, June 2006.
+
+   [DATETIME]   Klyne, G. and C. Newman, "Date and Time on the Internet:
+                Timestamps", RFC 3339, July 2002.
+
+   [URLAUTH]    Crispin, M., "Internet Message Access Protocol (IMAP) -
+                URLAUTH Extension", RFC 4467, May 2006.
+
+13.2.  Informative References
+
+   [SUBMIT]     Gellens, R. and J. Klensin, "Message Submission for
+                Mail", RFC 4409, April 2006.
+
+   [BURL]       Newman, C., "Message Submission BURL Extension", RFC
+                4468, May 2006.
+
+   [CATENATE]   Resnick, P., "Internet Message Access Protocol (IMAP)
+                CATENATE Extension", RFC 4469, April 2006.
+
+   [SASL]       Melnikov, A., Ed., and K. Zeilenga, Ed., "Simple
+                Authentication and Security Layer (SASL)", RFC 4422,
+                June 2006.
+
+   [GSSAPI]     Melnikov, A., Ed., "The Kerberos V5 ("GSSAPI") Simple
+                Authentication and Security Layer (SASL) Mechanism", RFC
+                4752, November 2006.
+
+   [DIGEST-MD5] Leach, P. and C. Newman, "Using Digest Authentication as
+                a SASL Mechanism", RFC 2831, May 2000.
+
+   [URI-REG]    Hansen, T., Hardie, T., and L. Masinter, "Guidelines and
+                Registration Procedures for New URI Schemes", BCP 115,
+                RFC 4395, February 2006.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov & Newman           Standards Track                    [Page 23]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+Appendix A.  Sample Code
+
+   Here is sample C source code to convert between URL paths and IMAP
+   mailbox names, taking into account mapping between IMAP's modified
+   UTF-7 [IMAP4] and hex-encoded UTF-8, which is more appropriate for
+   URLs.  This code has not been rigorously tested nor does it
+   necessarily behave reasonably with invalid input, but it should serve
+   as a useful example.  This code just converts the mailbox portion of
+   the URL and does not deal with parameters, query, or server
+   components of the URL.
+
+/* Copyright (C) The IETF Trust (2007).  This version of
+   sample C code is part of RFC XXXX; see the RFC itself
+   for full legal notices.
+
+   Regarding this sample C code (or any portion of it), the authors
+   make no guarantees and are not responsible for any damage
+   resulting from its use.  The authors grant irrevocable permission
+   to anyone to use, modify, and distribute it in any way that does
+   not diminish the rights of anyone else to use, modify, and
+   distribute it, provided that redistributed derivative works do
+   not contain misleading author or version information.
+
+   Derivative works need not be licensed under similar terms.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+/* hexadecimal lookup table */
+static const char hex[] = "0123456789ABCDEF";
+
+#define XX 127
+/*
+ * Table for decoding hexadecimal in %encoding
+ */
+static const char index_hex[256] = {
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+     0, 1, 2, 3,  4, 5, 6, 7,  8, 9,XX,XX, XX,XX,XX,XX,
+    XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+
+
+
+Melnikov & Newman           Standards Track                    [Page 24]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+    XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+};
+#define HEXCHAR(c)  (index_hex[(unsigned char)(c)])
+
+/* "gen-delims" excluding "/" but including "%" */
+#define GENERAL_DELIMS_NO_SLASH     ":?#[]@" "%"
+
+/* "gen-delims" (excluding "/", but including "%")
+   plus subset of "sub-delims" */
+#define GENERAL_UNSAFE_NO_SLASH     GENERAL_DELIMS_NO_SLASH ";&=+"
+#define OTHER_UNSAFE                " \"<>\\^`{|}"
+
+/* URL unsafe printable characters */
+static const char mailbox_url_unsafe[] = GENERAL_UNSAFE_NO_SLASH
+                                         OTHER_UNSAFE;
+
+/* UTF7 modified base64 alphabet */
+static const char base64chars[] =
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
+
+#define UNDEFINED 64
+
+/* UTF16 definitions */
+#define UTF16MASK   0x03FFUL
+#define UTF16SHIFT  10
+#define UTF16BASE   0x10000UL
+#define UTF16HIGHSTART   0xD800UL
+#define UTF16HIGHEND     0xDBFFUL
+#define UTF16LOSTART     0xDC00UL
+#define UTF16LOEND  0xDFFFUL
+
+/* Convert an IMAP mailbox to a URL path
+ *  dst needs to have roughly 4 times the storage space of src
+ *    Hex encoding can triple the size of the input
+ *    UTF-7 can be slightly denser than UTF-8
+ *     (worst case: 8 octets UTF-7 becomes 9 octets UTF-8)
+ */
+void MailboxToURL(char *dst, char *src)
+{
+    unsigned char c, i, bitcount;
+    unsigned long ucs4, utf16, bitbuf;
+    unsigned char base64[256], utf8[6];
+
+    /* initialize modified base64 decoding table */
+
+
+
+Melnikov & Newman           Standards Track                    [Page 25]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+    memset(base64, UNDEFINED, sizeof (base64));
+    for (i = 0; i < sizeof (base64chars); ++i) {
+     base64[(int) base64chars[i]] = i;
+    }
+
+    /* loop until end of string */
+    while (*src != '\0') {
+     c = *src++;
+     /* deal with literal characters and &- */
+     if (c != '&' || *src == '-') {
+         /* NB: There are no "URL safe" characters after the '~' */
+         if (c < ' ' || c > '~' ||
+             strchr(mailbox_url_unsafe, c) != NULL) {
+          /* hex encode if necessary */
+          dst[0] = '%';
+          dst[1] = hex[c >> 4];
+          dst[2] = hex[c & 0x0f];
+          dst += 3;
+         } else {
+          /* encode literally */
+          *dst++ = c;
+         }
+         /* skip over the '-' if this is an &- sequence */
+         if (c == '&') ++src;
+
+     } else {
+        /* convert modified UTF-7 -> UTF-16 -> UCS-4 -> UTF-8 -> HEX */
+         bitbuf = 0;
+         bitcount = 0;
+         ucs4 = 0;
+         while ((c = base64[(unsigned char) *src]) != UNDEFINED) {
+          ++src;
+          bitbuf = (bitbuf << 6) | c;
+          bitcount += 6;
+          /* enough bits for a UTF-16 character? */
+          if (bitcount >= 16) {
+              bitcount -= 16;
+              utf16 = (bitcount ? bitbuf >> bitcount
+                             : bitbuf) & 0xffff;
+              /* convert UTF16 to UCS4 */
+              if
+                    (utf16 >= UTF16HIGHSTART && utf16 <= UTF16HIGHEND) {
+               ucs4 = (utf16 - UTF16HIGHSTART) << UTF16SHIFT;
+               continue;
+              } else if
+                    (utf16 >= UTF16LOSTART && utf16 <= UTF16LOEND) {
+               ucs4 += utf16 - UTF16LOSTART + UTF16BASE;
+              } else {
+
+
+
+Melnikov & Newman           Standards Track                    [Page 26]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+               ucs4 = utf16;
+              }
+              /* convert UTF-16 range of UCS4 to UTF-8 */
+              if (ucs4 <= 0x7fUL) {
+               utf8[0] = (unsigned char) ucs4;
+               i = 1;
+              } else if (ucs4 <= 0x7ffUL) {
+               utf8[0] = 0xc0 | (unsigned char) (ucs4 >> 6);
+               utf8[1] = 0x80 | (unsigned char) (ucs4 & 0x3f);
+               i = 2;
+              } else if (ucs4 <= 0xffffUL) {
+               utf8[0] = 0xe0 | (unsigned char) (ucs4 >> 12);
+               utf8[1] = 0x80 | (unsigned char) ((ucs4 >> 6) & 0x3f);
+               utf8[2] = 0x80 | (unsigned char) (ucs4 & 0x3f);
+               i = 3;
+              } else {
+               utf8[0] = 0xf0 | (unsigned char) (ucs4 >> 18);
+               utf8[1] = 0x80 | (unsigned char) ((ucs4 >> 12) & 0x3f);
+               utf8[2] = 0x80 | (unsigned char) ((ucs4 >> 6) & 0x3f);
+               utf8[3] = 0x80 | (unsigned char) (ucs4 & 0x3f);
+               i = 4;
+              }
+              /* convert utf8 to hex */
+              for (c = 0; c < i; ++c) {
+               dst[0] = '%';
+               dst[1] = hex[utf8[c] >> 4];
+               dst[2] = hex[utf8[c] & 0x0f];
+               dst += 3;
+              }
+          }
+         }
+         /* skip over trailing '-' in modified UTF-7 encoding */
+         if (*src == '-') ++src;
+     }
+    }
+    /* terminate destination string */
+    *dst = '\0';
+}
+
+/* Convert hex coded UTF-8 URL path to modified UTF-7 IMAP mailbox
+ *  dst should be about twice the length of src to deal with non-hex
+ *  coded URLs
+ */
+int URLtoMailbox(char *dst, char *src)
+{
+    unsigned int utf8pos = 0;
+    unsigned int utf8total, i, c, utf7mode, bitstogo, utf16flag;
+    unsigned long ucs4 = 0, bitbuf = 0;
+
+
+
+Melnikov & Newman           Standards Track                    [Page 27]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+    utf7mode = 0; /* is the output UTF7 currently in base64 mode? */
+    utf8total = 0; /* how many octets is the current input UTF-8 char;
+                      0 == between characters */
+    bitstogo = 0; /* bits that need to be encoded into base64; if
+                     bitstogo != 0 then utf7mode == 1 */
+    while ((c = (unsigned char)*src) != '\0') {
+     ++src;
+     /* undo hex-encoding */
+     if (c == '%' && src[0] != '\0' && src[1] != '\0') {
+         c = HEXCHAR(src[0]);
+         i = HEXCHAR(src[1]);
+         if (c == XX || i == XX) {
+             return 0;
+         } else {
+             c = (char)((c << 4) | i);
+         }
+         src += 2;
+     }
+     /* normal character? */
+     if (c >= ' ' && c <= '~') {
+         /* switch out of UTF-7 mode */
+         if (utf7mode) {
+          if (bitstogo) {
+          *dst++ = base64chars[(bitbuf << (6 - bitstogo)) & 0x3F];
+          }
+          *dst++ = '-';
+          utf7mode = 0;
+          bitstogo = bitbuf = 0;
+         }
+         *dst++ = c;
+         /* encode '&' as '&-' */
+         if (c == '&') {
+          *dst++ = '-';
+         }
+         continue;
+     }
+     /* switch to UTF-7 mode */
+     if (!utf7mode) {
+         *dst++ = '&';
+         utf7mode = 1;
+     }
+     /* Encode US-ASCII characters as themselves */
+     if (c < 0x80) {
+         ucs4 = c;
+         utf8total = 1;
+     } else if (utf8total) {
+         /* this is a subsequent octet of a multi-octet character */
+         /* save UTF8 bits into UCS4 */
+
+
+
+Melnikov & Newman           Standards Track                    [Page 28]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+         ucs4 = (ucs4 << 6) | (c & 0x3FUL);
+         if (++utf8pos < utf8total) {
+          continue;
+         }
+     } else {
+         /* this is the first octet of a multi-octet character */
+         utf8pos = 1;
+         if (c < 0xE0) {
+          utf8total = 2;
+          ucs4 = c & 0x1F;
+         } else if (c < 0xF0) {
+          utf8total = 3;
+          ucs4 = c & 0x0F;
+         } else {
+          /* NOTE: can't convert UTF8 sequences longer than 4 */
+          utf8total = 4;
+          ucs4 = c & 0x03;
+         }
+         continue;
+     }
+     /* Finished with UTF-8 character.  Make sure it isn't an
+        overlong sequence.  If it is, return failure. */
+     if ((ucs4 < 0x80 && utf8total > 1) ||
+         (ucs4 < 0x0800 && utf8total > 2) ||
+         (ucs4 < 0x00010000 && utf8total > 3) ||
+         (ucs4 < 0x00200000 && utf8total > 4) ||
+         (ucs4 < 0x04000000 && utf8total > 5) ||
+         (ucs4 < 0x80000000 && utf8total > 6)) {
+         return 0;
+     }
+     /* loop to split ucs4 into two utf16 chars if necessary */
+     utf8total = 0;
+     do {
+         if (ucs4 >= UTF16BASE) {
+                ucs4 -= UTF16BASE;
+          bitbuf = (bitbuf << 16) | ((ucs4 >> UTF16SHIFT)
+                            + UTF16HIGHSTART);
+          ucs4 = (ucs4 & UTF16MASK) + UTF16LOSTART;
+          utf16flag = 1;
+         } else {
+          bitbuf = (bitbuf << 16) | ucs4;
+          utf16flag = 0;
+         }
+         bitstogo += 16;
+         /* spew out base64 */
+         while (bitstogo >= 6) {
+          bitstogo -= 6;
+          *dst++ = base64chars[(bitstogo ? (bitbuf >> bitstogo)
+
+
+
+Melnikov & Newman           Standards Track                    [Page 29]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+                               : bitbuf)
+                         & 0x3F];
+         }
+     } while (utf16flag);
+    }
+    /* if in UTF-7 mode, finish in ASCII */
+    if (utf7mode) {
+     if (bitstogo) {
+         *dst++ = base64chars[(bitbuf << (6 - bitstogo)) & 0x3F];
+     }
+     *dst++ = '-';
+    }
+    /* tie off string */
+    *dst = '\0';
+    return 1;
+}
+
+Appendix B.  List of Changes since RFC 2192
+
+   Updated boilerplate, list of editor's, etc.
+   Updated references.
+   Updated ABNF not to use _, to use SP instead of SPACE, etc.
+   Updated example domains to use example.org.
+   Fixed ABNF error in "imessagelist" non-terminal.
+   Updated ABNF, due to changes in RFC 3501, RFC 4466, and RFC 3986.
+   Renamed "iuserauth" non-terminal to <iuserinfo>.
+   Clarified that the userinfo component describes both authorization
+   identity and mailbox naming scope.
+   Allow for non-synchronizing literals in "enc-search".
+   Added "ipartial" specifier that denotes a partial FETCH.
+   Moved URLAUTH text from RFC 4467 to this document.
+   Updated ABNF for the whole server to allow missing trailing "/"
+   (e.g., "imap://imap.example.com" is now valid and is the same as
+   "imap://imap.example.com/").
+   Clarified how relative-path references are constructed.
+   Added more examples demonstrating relative-path references.
+   Added rules for relative URLs and restructured ABNF as the result.
+   Removed text on use of relative URLs in MHTML.
+   Added examples demonstrating security considerations when resolving
+   URLs.
+   Recommend usage of STARTTLS/SASL security layer to protect
+   confidential data.
+   Removed some advices about connection reuse that were incorrect.
+   Removed URLs referencing a list of mailboxes, as this feature
+   hasn't seen any deployments.
+   Clarified that user name "anonymous" is case-insensitive.
+
+
+
+
+
+Melnikov & Newman           Standards Track                    [Page 30]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+Appendix C.  List of Changes since RFC 4467
+
+   Renamed <mechanism> to <uauth-mechanism>.  Restructured ABNF.
+
+Appendix D.  Acknowledgments
+
+   Text describing URLAUTH was lifted from [URLAUTH] by Mark Crispin.
+
+   Stephane H. Maes contributed some ideas to this document; he also
+   co-edited early versions of this document.
+
+   The editors would like to thank Mark Crispin, Ken Murchison, Ted
+   Hardie, Zoltan Ordogh, Dave Cridland, Kjetil Torgrim Homme, Lisa
+   Dusseault, Spencer Dawkins, Filip Navara, Shawn M. Emery, Sam
+   Hartman, Russ Housley, and Lars Eggert for the time they devoted to
+   reviewing this document and/or for the comments received.
+
+Authors' Addresses
+
+   Chris Newman (Author/Editor)
+   Sun Microsystems
+   3401 Centrelake Dr., Suite 410
+   Ontario, CA 91761
+   EMail: chris.newman@sun.com
+
+   Alexey Melnikov (Editor)
+   Isode Limited
+   5 Castle Business Village
+   36 Station Road
+   Hampton, Middlesex
+   TW12 2BX, UK
+   EMail: Alexey.Melnikov@isode.com
+   URI:   http://www.melnikov.ca/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov & Newman           Standards Track                    [Page 31]
+
+RFC 5092                    IMAP URL Scheme                November 2007
+
+
+Full Copyright Statement
+
+   Copyright (C) The IETF Trust (2007).
+
+   This document is subject to the rights, licenses and restrictions
+   contained in BCP 78, and except as set forth therein, the authors
+   retain all their rights.
+
+   This document and the information contained herein are provided on an
+   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
+   THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
+   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   Intellectual Property Rights or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; nor does it represent that it has
+   made any independent effort to identify any such rights.  Information
+   on the procedures with respect to rights in RFC documents can be
+   found in BCP 78 and BCP 79.
+
+   Copies of IPR disclosures made to the IETF Secretariat and any
+   assurances of licenses to be made available, or the result of an
+   attempt made to obtain a general license or permission for the use of
+   such proprietary rights by implementers or users of this
+   specification can be obtained from the IETF on-line IPR repository at
+   http://www.ietf.org/ipr.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights that may cover technology that may be required to implement
+   this standard.  Please address the information to the IETF at
+   ietf-ipr@ietf.org.
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov & Newman           Standards Track                    [Page 32]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc5161.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,395 @@
+
+
+
+
+
+
+Network Working Group                                A. Gulbrandsen, Ed.
+Request for Comments: 5161                        Oryx Mail Systems GmbH
+Category: Standards Track                               A. Melnikov, Ed.
+                                                           Isode Limited
+                                                              March 2008
+
+
+                       The IMAP ENABLE Extension
+
+Status of This Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Abstract
+
+   Most IMAP extensions are used by the client when it wants to and the
+   server supports it.  However, a few extensions require the server to
+   know whether a client supports that extension.  The ENABLE extension
+   allows an IMAP client to say which extensions it supports.
+
+1.  Overview
+
+   Several IMAP extensions allow the server to return unsolicited
+   responses specific to these extensions in certain circumstances.
+   However, servers cannot send those unsolicited responses until they
+   know that the clients support such extensions and thus won't choke on
+   the extension response data.
+
+   Up until now, extensions have typically stated that a server cannot
+   send the unsolicited responses until after the client has used a
+   command with the extension data (i.e., at that point the server knows
+   the client is aware of the extension).  CONDSTORE ([RFC4551]),
+   ANNOTATE ([ANNOTATE]), and some extensions under consideration at the
+   moment use various commands to enable server extensions.  For
+   example, CONDSTORE uses a SELECT or FETCH parameter, and ANNOTATE
+   uses a side effect of FETCH.
+
+   The ENABLE extension provides an explicit indication from the client
+   that it supports particular extensions.  This is done using a new
+   ENABLE command.
+
+   An IMAP server that supports ENABLE advertises this by including the
+   word ENABLE in its capability list.
+
+
+
+
+Gulbrandsen & Melnikov      Standards Track                     [Page 1]
+
+RFC 5161               The IMAP ENABLE Extension              March 2008
+
+
+   Most IMAP extensions do not require the client to enable the
+   extension in any way.
+
+2.  Conventions Used in This Document
+
+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+   document are to be interpreted as described in [RFC2119].
+
+   Formal syntax is defined by [RFC5234] and [RFC3501].
+
+   Example lines prefaced by "C:" are sent by the client and ones
+   prefaced by "S:" by the server.  The five characters [...] means that
+   something has been elided.
+
+3.  Protocol Changes
+
+3.1.  The ENABLE Command
+
+   Arguments: capability names
+
+   Result:    OK: Relevant capabilities enabled
+              BAD: No arguments, or syntax error in an argument
+
+   The ENABLE command takes a list of capability names, and requests the
+   server to enable the named extensions.  Once enabled using ENABLE,
+   each extension remains active until the IMAP connection is closed.
+   For each argument, the server does the following:
+
+   - If the argument is not an extension known to the server, the server
+     MUST ignore the argument.
+
+   - If the argument is an extension known to the server, and it is not
+     specifically permitted to be enabled using ENABLE, the server MUST
+     ignore the argument.  (Note that knowing about an extension doesn't
+     necessarily imply supporting that extension.)
+
+   - If the argument is an extension that is supported by the server and
+     that needs to be enabled, the server MUST enable the extension for
+     the duration of the connection.  At present, this applies only to
+     CONDSTORE ([RFC4551]).  Note that once an extension is enabled,
+     there is no way to disable it.
+
+   If the ENABLE command is successful, the server MUST send an untagged
+   ENABLED response (see Section 3.2).
+
+
+
+
+
+
+Gulbrandsen & Melnikov      Standards Track                     [Page 2]
+
+RFC 5161               The IMAP ENABLE Extension              March 2008
+
+
+   Clients SHOULD only include extensions that need to be enabled by the
+   server.  At the time of publication, CONDSTORE is the only such
+   extension (i.e., ENABLE CONDSTORE is an additional "CONDSTORE
+   enabling command" as defined in [RFC4551]).  Future RFCs may add to
+   this list.
+
+   The ENABLE command is only valid in the authenticated state (see
+   [RFC3501]), before any mailbox is selected.  Clients MUST NOT issue
+   ENABLE once they SELECT/EXAMINE a mailbox; however, server
+   implementations don't have to check that no mailbox is selected or
+   was previously selected during the duration of a connection.
+
+   The ENABLE command can be issued multiple times in a session.  It is
+   additive; i.e., "ENABLE a b", followed by "ENABLE c" is the same as a
+   single command "ENABLE a b c".  When multiple ENABLE commands are
+   issued, each corresponding ENABLED response SHOULD only contain
+   extensions enabled by the corresponding ENABLE command.
+
+   There are no limitations on pipelining ENABLE.  For example, it is
+   possible to send ENABLE and then immediately SELECT, or a LOGIN
+   immediately followed by ENABLE.
+
+   The server MUST NOT change the CAPABILITY list as a result of
+   executing ENABLE; i.e., a CAPABILITY command issued right after an
+   ENABLE command MUST list the same capabilities as a CAPABILITY
+   command issued before the ENABLE command.  This is demonstrated in
+   the following example:
+
+      C: t1 CAPABILITY
+      S: * CAPABILITY IMAP4rev1 ID LITERAL+ ENABLE X-GOOD-IDEA
+      S: t1 OK foo
+      C: t2 ENABLE CONDSTORE X-GOOD-IDEA
+      S: * ENABLED X-GOOD-IDEA
+      S: t2 OK foo
+      C: t3 CAPABILITY
+      S: * CAPABILITY IMAP4rev1 ID LITERAL+ ENABLE X-GOOD-IDEA
+      S: t3 OK foo again
+
+   In the following example, the client enables CONDSTORE:
+
+      C: a1 ENABLE CONDSTORE
+      S: * ENABLED CONDSTORE
+      S: a1 OK Conditional Store enabled
+
+
+
+
+
+
+
+
+Gulbrandsen & Melnikov      Standards Track                     [Page 3]
+
+RFC 5161               The IMAP ENABLE Extension              March 2008
+
+
+3.2.  The ENABLED Response
+
+   Contents:   capability listing
+
+   The ENABLED response occurs as a result of an ENABLE command.  The
+   capability listing contains a space-separated listing of capability
+   names that the server supports and that were successfully enabled.
+   The ENABLED response may contain no capabilities, which means that no
+   extensions listed by the client were successfully enabled.
+
+3.3.  Note to Designers of Extensions That May Use the ENABLE Command
+
+   Designers of IMAP extensions are discouraged from creating extensions
+   that require ENABLE unless there is no good alternative design.
+   Specifically, extensions that cause potentially incompatible behavior
+   changes to deployed server responses (and thus benefit from ENABLE)
+   have a higher complexity cost than extensions that do not.
+
+4.  Formal Syntax
+
+   The following syntax specification uses the Augmented Backus-Naur
+   Form (ABNF) notation as specified in [RFC5234] including the core
+   rules in Appendix B.1.  [RFC3501] defines the non-terminals
+   "capability" and "command-any".
+
+   Except as noted otherwise, all alphabetic characters are
+   case-insensitive.  The use of upper or lower case characters to
+   define token strings is for editorial clarity only.  Implementations
+   MUST accept these strings in a case-insensitive fashion.
+
+      capability    =/ "ENABLE"
+
+      command-any   =/ "ENABLE" 1*(SP capability)
+
+      response-data =/ "*" SP enable-data CRLF
+
+      enable-data   = "ENABLED" *(SP capability)
+
+5.  Security Considerations
+
+   It is believed that this extension doesn't add any security
+   considerations that are not already present in the base IMAP protocol
+   [RFC3501].
+
+6.  IANA Considerations
+
+   The IANA has added ENABLE to the IMAP4 Capabilities Registry.
+
+
+
+
+Gulbrandsen & Melnikov      Standards Track                     [Page 4]
+
+RFC 5161               The IMAP ENABLE Extension              March 2008
+
+
+7.  Acknowledgments
+
+   The editors would like to thank Randy Gellens, Chris Newman, Peter
+   Coates, Dave Cridland, Mark Crispin, Ned Freed, Dan Karp, Cyrus
+   Daboo, Ken Murchison, and Eric Burger for comments and corrections.
+   However, this doesn't necessarily mean that they endorse this
+   extension, agree with all details, or are responsible for errors
+   introduced by the editors.
+
+8.  Normative References
+
+   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
+              Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+   [RFC3501]  Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
+              4rev1", RFC 3501, March 2003.
+
+   [RFC5234]  Crocker, D., Ed., and P. Overell, "Augmented BNF for
+              Syntax Specifications: ABNF", STD 68, RFC 5234, January
+              2008.
+
+   [RFC4551]  Melnikov, A. and S. Hole, "IMAP Extension for Conditional
+              STORE Operation or Quick Flag Changes Resynchronization",
+              RFC 4551, June 2006.
+
+9.  Informative References
+
+   [ANNOTATE] Daboo, C. and R. Gellens, "IMAP ANNOTATE Extension", Work
+              in Progress, August 2006.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Gulbrandsen & Melnikov      Standards Track                     [Page 5]
+
+RFC 5161               The IMAP ENABLE Extension              March 2008
+
+
+Editors' Addresses
+
+   Arnt Gulbrandsen
+   Oryx Mail Systems GmbH
+   Schweppermannstr. 8
+   D-81671 Muenchen
+   Germany
+
+   Fax: +49 89 4502 9758
+   EMail: arnt@oryx.com
+
+
+   Alexey Melnikov
+   Isode Ltd
+   5 Castle Business Village
+   36 Station Road
+   Hampton, Middlesex  TW12 2BX
+   UK
+
+   EMail: Alexey.Melnikov@isode.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Gulbrandsen & Melnikov      Standards Track                     [Page 6]
+
+RFC 5161               The IMAP ENABLE Extension              March 2008
+
+
+Full Copyright Statement
+
+   Copyright (C) The IETF Trust (2008).
+
+   This document is subject to the rights, licenses and restrictions
+   contained in BCP 78, and except as set forth therein, the authors
+   retain all their rights.
+
+   This document and the information contained herein are provided on an
+   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
+   THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
+   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   Intellectual Property Rights or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; nor does it represent that it has
+   made any independent effort to identify any such rights.  Information
+   on the procedures with respect to rights in RFC documents can be
+   found in BCP 78 and BCP 79.
+
+   Copies of IPR disclosures made to the IETF Secretariat and any
+   assurances of licenses to be made available, or the result of an
+   attempt made to obtain a general license or permission for the use of
+   such proprietary rights by implementers or users of this
+   specification can be obtained from the IETF on-line IPR repository at
+   http://www.ietf.org/ipr.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights that may cover technology that may be required to implement
+   this standard.  Please address the information to the IETF at
+   ietf-ipr@ietf.org.
+
+
+
+
+
+
+
+
+
+
+
+
+Gulbrandsen & Melnikov      Standards Track                     [Page 7]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc5162.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1291 @@
+
+
+
+
+
+
+Network Working Group                                        A. Melnikov
+Request for Comments: 5162                                   D. Cridland
+Category: Standards Track                                      Isode Ltd
+                                                               C. Wilson
+                                                                   Nokia
+                                                              March 2008
+
+
+          IMAP4 Extensions for Quick Mailbox Resynchronization
+
+Status of This Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Abstract
+
+   This document defines an IMAP4 extension, which gives an IMAP client
+   the ability to quickly resynchronize any previously opened mailbox as
+   part of the SELECT command, without the need for server-side state or
+   additional client round-trips.  This extension also introduces a new
+   response that allows for a more compact representation of a list of
+   expunged messages (and always includes the Unique Identifiers (UIDs)
+   expunged).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov, et al.            Standards Track                     [Page 1]
+
+RFC 5162               IMAP Quick Mailbox Resync              March 2008
+
+
+Table of Contents
+
+   1.  Introduction and Overview  . . . . . . . . . . . . . . . . . .  2
+   2.  Requirements Notation  . . . . . . . . . . . . . . . . . . . .  4
+   3.  IMAP Protocol Changes  . . . . . . . . . . . . . . . . . . . .  4
+     3.1.  QRESYNC Parameter to SELECT/EXAMINE  . . . . . . . . . . .  4
+     3.2.  VANISHED UID FETCH Modifier  . . . . . . . . . . . . . . .  8
+     3.3.  EXPUNGE Command  . . . . . . . . . . . . . . . . . . . . . 10
+     3.4.  CLOSE Command  . . . . . . . . . . . . . . . . . . . . . . 11
+     3.5.  UID EXPUNGE Command  . . . . . . . . . . . . . . . . . . . 11
+     3.6.  VANISHED Response  . . . . . . . . . . . . . . . . . . . . 12
+     3.7.  CLOSED Response Code . . . . . . . . . . . . . . . . . . . 15
+   4.  Server Implementation Considerations . . . . . . . . . . . . . 15
+     4.1.  Server Implementations That Don't Store Extra State  . . . 15
+     4.2.  Server Implementations Storing Minimal State . . . . . . . 16
+     4.3.  Additional State Required on the Server  . . . . . . . . . 16
+   5.  Updated Synchronization Sequence . . . . . . . . . . . . . . . 17
+   6.  Formal Syntax  . . . . . . . . . . . . . . . . . . . . . . . . 19
+   7.  Security Considerations  . . . . . . . . . . . . . . . . . . . 20
+   8.  IANA Considerations  . . . . . . . . . . . . . . . . . . . . . 21
+   9.  Acknowledgments  . . . . . . . . . . . . . . . . . . . . . . . 21
+   10. References . . . . . . . . . . . . . . . . . . . . . . . . . . 21
+     10.1. Normative References . . . . . . . . . . . . . . . . . . . 21
+     10.2. Informative References . . . . . . . . . . . . . . . . . . 22
+
+1.  Introduction and Overview
+
+   The [CONDSTORE] extension gives a disconnected client the ability to
+   quickly resynchronize IMAP flag changes for previously seen messages.
+   This can be done using the CHANGEDSINCE FETCH modifier once a mailbox
+   is opened.  In order for the client to discover which messages have
+   been expunged, the client still has to issue a UID FETCH or a UID
+   SEARCH command.  This document defines an extension to [CONDSTORE]
+   that allows a reconnecting client to perform full resynchronization,
+   including discovery of expunged messages, in a single round-trip.
+   This extension also introduces a new response, VANISHED, that allows
+   for a more compact representation of a list of expunged messages.
+
+   This extension can be useful for mobile clients that can experience
+   frequent disconnects caused by environmental factors (battery life,
+   signal strength, etc.).  Such clients need a way to quickly reconnect
+   to the IMAP server, while minimizing delay experienced by the user as
+   well as the amount of traffic (and hence the expense) generated by
+   resynchronization.
+
+
+
+
+
+
+
+Melnikov, et al.            Standards Track                     [Page 2]
+
+RFC 5162               IMAP Quick Mailbox Resync              March 2008
+
+
+   By extending the SELECT command to perform the additional
+   resynchronization, this also allows clients to reduce concurrent
+   connections to the IMAP server held purely for the sake of avoiding
+   the resynchronization.
+
+   The quick resync IMAP extension is present if an IMAP4 server returns
+   "QRESYNC" as one of the supported capabilities to the CAPABILITY
+   command.
+
+   Servers supporting this extension MUST implement and advertise
+   support for the [ENABLE] IMAP extension.  Also, the presence of the
+   "QRESYNC" capability implies support for the [CONDSTORE] IMAP
+   extension even if the CONDSTORE capability isn't advertised.  A
+   server compliant with this specification is REQUIREd to support
+   "ENABLE QRESYNC" and "ENABLE QRESYNC CONDSTORE" (which are "CONDSTORE
+   enabling commands", as defined in [CONDSTORE], and have identical
+   results), but there is no requirement for a compliant server to
+   support "ENABLE CONDSTORE" by itself.  The "ENABLE QRESYNC"/"ENABLE
+   QRESYNC CONDSTORE" command also tells the server that it SHOULD start
+   sending VANISHED responses (see Section 3.6) instead of EXPUNGE
+   responses.  This change remains in effect until the connection is
+   closed.
+
+   For compatibility with clients that only support the [CONDSTORE] IMAP
+   extension, servers SHOULD advertise CONDSTORE in the CAPABILITY
+   response as well.
+
+   A client making use of this extension MUST issue "ENABLE QRESYNC"
+   once it is authenticated.  A server MUST respond with a tagged BAD
+   response if the QRESYNC parameter to the SELECT/EXAMINE command or
+   the VANISHED UID FETCH modifier is specified and the client hasn't
+   issued "ENABLE QRESYNC" in the current connection.
+
+   This document puts additional requirements on a server implementing
+   the [CONDSTORE] extension.  Each mailbox that supports persistent
+   storage of mod-sequences, i.e., for which the server has sent a
+   HIGHESTMODSEQ untagged OK response code on a successful SELECT/
+   EXAMINE, MUST increment the per-mailbox mod-sequence when one or more
+   messages are expunged due to EXPUNGE, UID EXPUNGE or CLOSE; the
+   server MUST associate the incremented mod-sequence with the UIDs of
+   the expunged messages.
+
+   A client that supports CONDSTORE but not this extension might
+   resynchronize a mailbox and discover that its HIGHESTMODSEQ has
+   increased from the value cached by the client.  If the increase is
+   only due to messages having been expunged since the client last
+   synchronized, the client is likely to send a FETCH ...  CHANGEDSINCE
+   command that returns no data.  Thus, a client that supports CONDSTORE
+
+
+
+Melnikov, et al.            Standards Track                     [Page 3]
+
+RFC 5162               IMAP Quick Mailbox Resync              March 2008
+
+
+   but not this extension might incur a penalty of an unneeded round-
+   trip when resynchronizing some mailboxes (those that have had
+   messages expunged but no flag changes since the last
+   synchronization).
+
+   This extra round-trip is only incurred by clients that support
+   CONDSTORE but not this extension, and only when a mailbox has had
+   messages expunged but no flag changes to non-expunged messages.
+   Since CONDSTORE is a relatively new extension, it is thought likely
+   that clients that support it will also support this extension.
+
+2.  Requirements Notation
+
+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+   document are to be interpreted as described in [RFC2119].
+
+   In examples, "C:" and "S:" indicate lines sent by the client and
+   server respectively.  If a single "C:" or "S:" label applies to
+   multiple lines, then the line breaks between those lines are for
+   editorial clarity only and are not part of the actual protocol
+   exchange.  The five characters [...] means that something has been
+   elided.
+
+   Understanding of the IMAP message sequence numbers and UIDs and the
+   EXPUNGE response [RFC3501] is essential when reading this document.
+
+3.  IMAP Protocol Changes
+
+3.1.  QRESYNC Parameter to SELECT/EXAMINE
+
+   The Quick Resynchronization parameter to SELECT/EXAMINE commands has
+   four arguments:
+
+   o  the last known UIDVALIDITY,
+
+   o  the last known modification sequence,
+
+   o  the optional set of known UIDs, and
+
+   o  an optional parenthesized list of known sequence ranges and their
+      corresponding UIDs.
+
+   A server MUST respond with a tagged BAD response if the Quick
+   Resynchronization parameter to SELECT/EXAMINE command is specified
+   and the client hasn't issued "ENABLE QRESYNC" in the current
+   connection.
+
+
+
+
+Melnikov, et al.            Standards Track                     [Page 4]
+
+RFC 5162               IMAP Quick Mailbox Resync              March 2008
+
+
+   Before opening the specified mailbox, the server verifies all
+   arguments for syntactic validity.  If any parameter is not
+   syntactically valid, the server returns the tagged BAD response, and
+   the mailbox remains unselected.  Once the check is done, the server
+   opens the mailbox as if no SELECT/EXAMINE parameters are specified
+   (this is subject to processing of other parameters as defined in
+   other extensions).  In particular this means that the server MUST
+   send all untagged responses as specified in Sections 6.3.1 and 6.3.2
+   of [RFC3501].
+
+   After that, the server checks the UIDVALIDITY value provided by the
+   client.  If the provided UIDVALIDITY doesn't match the UIDVALIDITY
+   for the mailbox being opened, then the server MUST ignore the
+   remaining parameters and behave as if no dynamic message data
+   changed.  The client can discover this situation by comparing the
+   UIDVALIDITY value returned by the server.  This behavior allows the
+   client not to synchronize the mailbox or decide on the best
+   synchronization strategy.
+
+   Example: Attempting to resynchronize INBOX, but the provided
+            UIDVALIDITY parameter doesn't match the current UIDVALIDITY
+            value.
+
+   C: A02 SELECT INBOX (QRESYNC (67890007 20050715194045000
+            41,43:211,214:541))
+            S: * 464 EXISTS
+            S: * 3 RECENT
+            S: * OK [UIDVALIDITY 3857529045] UIDVALIDITY
+            S: * OK [UIDNEXT 550] Predicted next UID
+            S: * OK [HIGHESTMODSEQ 90060128194045007]
+            S: * OK [UNSEEN 12] Message 12 is first unseen
+            S: * FLAGS (\Answered \Flagged \Draft \Deleted \Seen)
+            S: * OK [PERMANENTFLAGS (\Answered \Flagged \Draft
+            \Deleted \Seen \*)] Permanent flags
+            S: A02 OK [READ-WRITE] Sorry, UIDVALIDITY mismatch
+
+   Modification Sequence and UID Parameters:
+
+   A server that doesn't support the persistent storage of mod-sequences
+   for the mailbox MUST send the OK untagged response including the
+   NOMODSEQ response code with every successful SELECT or EXAMINE
+   command, as described in [CONDSTORE].  Such a server doesn't need to
+   remember mod-sequences for expunged messages in the mailbox.  It MUST
+   ignore the remaining parameters and behave as if no dynamic message
+   data changed.
+
+   If the provided UIDVALIDITY matches that of the selected mailbox, the
+   server then checks the last known modification sequence.
+
+
+
+Melnikov, et al.            Standards Track                     [Page 5]
+
+RFC 5162               IMAP Quick Mailbox Resync              March 2008
+
+
+   The server sends the client any pending flag changes (using FETCH
+   responses that MUST contain UIDs) and expunges those that have
+   occurred in this mailbox since the provided modification sequence.
+
+   If the list of known UIDs was also provided, the server should only
+   report flag changes and expunges for the specified messages.  If the
+   client did not provide the list of UIDs, the server acts as if the
+   client has specified "1:<maxuid>", where <maxuid> is the mailbox's
+   UIDNEXT value minus 1.  If the mailbox is empty and never had any
+   messages in it, then lack of the list of UIDs is interpreted as an
+   empty set of UIDs.
+
+   Thus, the client can process just these pending events and need not
+   perform a full resynchronization.  Without the message sequence
+   number matching information, the result of this step is semantically
+   equivalent to the client issuing:
+   tag1 UID FETCH "known-uids" (FLAGS) (CHANGEDSINCE
+   "mod-sequence-value" VANISHED)
+
+   Example:
+      C: A03 SELECT INBOX (QRESYNC (67890007
+         90060115194045000 41,43:211,214:541))
+      S: * OK [CLOSED]
+      S: * 314 EXISTS
+      S: * 15 RECENT
+      S: * OK [UIDVALIDITY 67890007] UIDVALIDITY
+      S: * OK [UIDNEXT 567] Predicted next UID
+      S: * OK [HIGHESTMODSEQ 90060115205545359]
+      S: * OK [UNSEEN 7] There are some unseen messages in the mailbox
+      S: * FLAGS (\Answered \Flagged \Draft \Deleted \Seen)
+      S: * OK [PERMANENTFLAGS (\Answered \Flagged \Draft
+         \Deleted \Seen \*)] Permanent flags
+      S: * VANISHED (EARLIER) 41,43:116,118,120:211,214:540
+      S: * 49 FETCH (UID 117 FLAGS (\Seen \Answered) MODSEQ
+         (90060115194045001))
+      S: * 50 FETCH (UID 119 FLAGS (\Draft $MDNSent) MODSEQ
+         (90060115194045308))
+      S: ...
+      S: * 100 FETCH (UID 541 FLAGS (\Seen $Forwarded) MODSEQ
+         (90060115194045001))
+      S: A03 OK [READ-WRITE] mailbox selected
+
+   Message sequence match data:
+
+   A client MAY provide a parenthesized list of a message sequence set
+   and the corresponding UID sets.  Both MUST be provided in ascending
+   order.  The server uses this data to restrict the range for which it
+   provides expunged message information.
+
+
+
+Melnikov, et al.            Standards Track                     [Page 6]
+
+RFC 5162               IMAP Quick Mailbox Resync              March 2008
+
+
+   Conceptually, the client provides a small sample of sequence numbers
+   for which it knows the corresponding UIDs.  The server then compares
+   each sequence number and UID pair the client provides with the
+   current state of the mailbox.  If a pair matches, then the client
+   knows of any expunges up to, and including, the message, and thus
+   will not include that range in the VANISHED response, even if the
+   "mod-sequence-value" provided by the client is too old for the server
+   to have data of when those messages were expunged.
+
+   Thus, if the Nth message number in the first set in the list is 4,
+   and the Nth UID in the second set in the list is 8, and the mailbox's
+   fourth message has UID 8, then no UIDs equal to or less than 8 are
+   present in the VANISHED response.  If the (N+1)th message number is
+   12, and the (N+1)th UID is 24, and the (N+1)th message in the mailbox
+   has UID 25, then the lowest UID included in the VANISHED response
+   would be 9.
+
+   In the following two examples, the server is unable to remember
+   expunges at all, and only UIDs with messages divisible by three are
+   present in the mailbox.  In the first example, the client does not
+   use the fourth parameter; in the second, it provides it.  This
+   example is somewhat extreme, but shows that judicious usage of the
+   sequence match data can save a substantial amount of bandwidth.
+
+   Example:
+      C: A04 SELECT INBOX (QRESYNC (67890007
+         90060115194045000 1:29997))
+      S: * 10003 EXISTS
+      S: * 5 RECENT
+      S: * OK [UIDVALIDITY 67890007] UIDVALIDITY
+      S: * OK [UIDNEXT 30013] Predicted next UID
+      S: * OK [HIGHESTMODSEQ 90060115205545359]
+      S: * OK [UNSEEN 7] There are some unseen messages in the mailbox
+      S: * FLAGS (\Answered \Flagged \Draft \Deleted \Seen)
+      S: * OK [PERMANENTFLAGS (\Answered \Flagged \Draft
+         \Deleted \Seen \*)] Permanent flags
+      S: * VANISHED (EARLIER) 1:2,4:5,7:8,10:11,13:14 [...]
+         29998:29999,30001:30002,30004:30005,30007:30008
+      S: * 9889 FETCH (UID 29667 FLAGS (\Seen \Answered) MODSEQ
+         (90060115194045027))
+      S: * 9890 FETCH (UID 29670 FLAGS (\Draft $MDNSent) MODSEQ
+         (90060115194045028))
+      S: ...
+      S: * 9999 FETCH (UID 29997 FLAGS (\Seen $Forwarded) MODSEQ
+         (90060115194045031))
+      S: A04 OK [READ-WRITE] mailbox selected
+
+
+
+
+
+Melnikov, et al.            Standards Track                     [Page 7]
+
+RFC 5162               IMAP Quick Mailbox Resync              March 2008
+
+
+   Example:
+      C: B04 SELECT INBOX (QRESYNC (67890007
+         90060115194045000 1:29997 (5000,7500,9000,9990:9999 15000,
+         22500,27000,29970,29973,29976,29979,29982,29985,29988,29991,
+         29994,29997)))
+      S: * 10003 EXISTS
+      S: * 5 RECENT
+      S: * OK [UIDVALIDITY 67890007] UIDVALIDITY
+      S: * OK [UIDNEXT 30013] Predicted next UID
+      S: * OK [HIGHESTMODSEQ 90060115205545359]
+      S: * OK [UNSEEN 7] There are some unseen messages in the mailbox
+      S: * FLAGS (\Answered \Flagged \Draft \Deleted \Seen)
+      S: * OK [PERMANENTFLAGS (\Answered \Flagged \Draft
+         \Deleted \Seen \*)] Permanent flags
+      S: * VANISHED (EARLIER) 29998:29999,30001:30002,30004:30005,30007:
+         30008
+      S: * 9889 FETCH (UID 29667 FLAGS (\Seen \Answered) MODSEQ
+         (90060115194045027))
+      S: * 9890 FETCH (UID 29670 FLAGS (\Draft $MDNSent) MODSEQ
+         (90060115194045028))
+      S: ...
+      S: * 9999 FETCH (UID 29997 FLAGS (\Seen $Forwarded) MODSEQ
+         (90060115194045031))
+      S: B04 OK [READ-WRITE] mailbox selected
+
+3.2.  VANISHED UID FETCH Modifier
+
+   [IMAPABNF] has extended the syntax of the FETCH and UID FETCH
+   commands to include an optional FETCH modifier.  This document
+   defines a new UID FETCH modifier: VANISHED.
+
+   Note, that the VANISHED UID FETCH modifier is NOT allowed with a
+   FETCH command.  The server MUST return a tagged BAD response if this
+   response is specified as a modifier to the FETCH command.
+
+   A server MUST respond with a tagged BAD response if the VANISHED UID
+   FETCH modifier is specified and the client hasn't issued "ENABLE
+   QRESYNC" in the current connection.
+
+   The VANISHED UID FETCH modifier MUST only be specified together with
+   the CHANGEDSINCE UID FETCH modifier.
+
+   The VANISHED UID FETCH modifier instructs the server to report those
+   messages from the UID set parameter that have been expunged and whose
+   associated mod-sequence is larger than the specified mod-sequence.
+   That is, the client requests to be informed of messages from the
+   specified set that were expunged since the specified mod-sequence.
+   Note that the mod-sequence(s) associated with these messages were
+
+
+
+Melnikov, et al.            Standards Track                     [Page 8]
+
+RFC 5162               IMAP Quick Mailbox Resync              March 2008
+
+
+   updated when the messages were expunged (as described above).  The
+   expunged messages are reported using the VANISHED response as
+   described in Section 3.6, which MUST contain the EARLIER tag.  Any
+   VANISHED (EARLIER) responses MUST be returned before any FETCH
+   responses, as otherwise the client might get confused about how
+   message numbers map to UIDs.
+
+   Note: A server that receives a mod-sequence smaller than <minmodseq>,
+   where <minmodseq> is the value of the smallest expunged mod-sequence
+   it remembers minus one, MUST behave as if it was requested to report
+   all expunged messages from the provided UID set parameter.
+
+   Example 1: Without the VANISHED UID FETCH modifier, a CONDSTORE-aware
+   client [CONDSTORE] needs to issue separate commands to learn of flag
+   changes and expunged messages since the last synchronization:
+
+   C: s100 UID FETCH 300:500 (FLAGS) (CHANGEDSINCE 12345)
+   S: * 1 FETCH (UID 404 MODSEQ (65402) FLAGS (\Seen))
+   S: * 2 FETCH (UID 406 MODSEQ (75403) FLAGS (\Deleted))
+   S: * 4 FETCH (UID 408 MODSEQ (29738) FLAGS ($NoJunk
+       $AutoJunk $MDNSent))
+   S: s100 OK FETCH completed
+   C: s101 UID SEARCH 300:500
+   S: * SEARCH 404 406 407 408 410 412
+   S: s101 OK search completed
+
+   Where 300 and 500 are the lowest and highest UIDs from client's
+   cache.  The second SEARCH response tells the client that the messages
+   with UIDs 407, 410, and 412 are still present, but their flags
+   haven't changed since the specified modification sequence.
+
+   Using the VANISHED UID FETCH modifier, it is sufficient to issue only
+   a single command:
+
+   C: s100 UID FETCH 300:500 (FLAGS) (CHANGEDSINCE 12345
+       VANISHED)
+   S: * VANISHED (EARLIER) 300:310,405,411
+   S: * 1 FETCH (UID 404 MODSEQ (65402) FLAGS (\Seen))
+   S: * 2 FETCH (UID 406 MODSEQ (75403) FLAGS (\Deleted))
+   S: * 4 FETCH (UID 408 MODSEQ (29738) FLAGS ($NoJunk
+       $AutoJunk $MDNSent))
+   S: s100 OK FETCH completed
+
+
+
+
+
+
+
+
+
+Melnikov, et al.            Standards Track                     [Page 9]
+
+RFC 5162               IMAP Quick Mailbox Resync              March 2008
+
+
+3.3.  EXPUNGE Command
+
+   Arguments: none
+
+   Responses: untagged responses: EXPUNGE or VANISHED
+
+   Result: OK - expunge completed
+           NO - expunge failure: can't expunge (e.g., permission denied)
+           BAD - command unknown or arguments invalid
+
+   This section updates the definition of the EXPUNGE command described
+   in Section 6.4.3 of [RFC3501].
+
+   The EXPUNGE command permanently removes all messages that have the
+   \Deleted flag set from the currently selected mailbox.  Before
+   returning an OK to the client, those messages that are removed are
+   reported using a VANISHED response or EXPUNGE responses.
+
+   If the server is capable of storing modification sequences for the
+   selected mailbox, it MUST increment the per-mailbox mod-sequence if
+   at least one message was permanently removed due to the execution of
+   the EXPUNGE command.  For each permanently removed message, the
+   server MUST remember the incremented mod-sequence and corresponding
+   UID.  If at least one message got expunged, the server MUST send the
+   updated per-mailbox modification sequence using the HIGHESTMODSEQ
+   response code (defined in [CONDSTORE]) in the tagged OK response.
+
+      Example:    C: A202 EXPUNGE
+                  S: * 3 EXPUNGE
+                  S: * 3 EXPUNGE
+                  S: * 5 EXPUNGE
+                  S: * 8 EXPUNGE
+                  S: A202 OK [HIGHESTMODSEQ 20010715194045319] expunged
+
+   Note: In this example, messages 3, 4, 7, and 11 had the \Deleted flag
+   set.  The first "* 3 EXPUNGE" reports message # 3 as expunged.  The
+   second "* 3 EXPUNGE" reports message # 4 as expunged (the message
+   number got decremented due to the previous EXPUNGE response).  See
+   the description of the EXPUNGE response in [RFC3501] for further
+   explanation.
+
+   Note that if the server chooses to always send VANISHED responses
+   instead of EXPUNGE responses, the previous example might look like
+   this:
+
+      Example:    C: B202 EXPUNGE
+                  S: * VANISHED 405,407,410,425
+                  S: B202 OK [HIGHESTMODSEQ 20010715194045319] expunged
+
+
+
+Melnikov, et al.            Standards Track                    [Page 10]
+
+RFC 5162               IMAP Quick Mailbox Resync              March 2008
+
+
+   Here messages with message numbers 3, 4, 7, and 11 have respective
+   UIDs 405, 407, 410, and 425.
+
+3.4.  CLOSE Command
+
+   Arguments: none
+
+   Responses: no specific responses for this command
+
+   Result: OK - close completed, now in authenticated state
+           BAD - command unknown or arguments invalid
+
+   This section updates the definition of the CLOSE command described in
+   Section 6.4.2 of [RFC3501].
+
+   The CLOSE command permanently removes all messages that have the
+   \Deleted flag set from the currently selected mailbox, and returns to
+   the authenticated state from the selected state.  No untagged EXPUNGE
+   (or VANISHED) responses are sent.
+
+   If the server is capable of storing modification sequences for the
+   selected mailbox, it MUST increment the per-mailbox mod-sequence if
+   at least one message was permanently removed due to the execution of
+   the CLOSE command.  For each permanently removed message, the server
+   MUST remember the incremented mod-sequence and corresponding UID.  If
+   at least one message got expunged, the server MUST send the updated
+   per-mailbox modification sequence using the HIGHESTMODSEQ response
+   code (defined in [CONDSTORE]) in the tagged OK response.
+
+      Example:    C: A202 CLOSE
+                  S: A202 OK [HIGHESTMODSEQ 20010715194045319] done
+
+3.5.  UID EXPUNGE Command
+
+   Arguments: message set
+
+   Responses: untagged responses: EXPUNGE or VANISHED
+
+   Result: OK - expunge completed
+           NO - expunge failure: can't expunge (e.g., permission denied)
+           BAD - command unknown or arguments invalid
+
+   This section updates the definition of the UID EXPUNGE command
+   described in Section 2.1 of [UIDPLUS].  Servers that implement both
+   [UIDPLUS] and QRESYNC extensions must implement UID EXPUNGE as
+   described in this section.
+
+
+
+
+
+Melnikov, et al.            Standards Track                    [Page 11]
+
+RFC 5162               IMAP Quick Mailbox Resync              March 2008
+
+
+   The UID EXPUNGE command permanently removes from the currently
+   selected mailbox all messages that both have the \Deleted flag set
+   and have a UID that is included in the specified message set.  If a
+   message either does not have the \Deleted flag set or has a UID that
+   is not included in the specified message set, it is not affected.
+
+   This command is particularly useful for disconnected mode clients.
+   By using UID EXPUNGE instead of EXPUNGE when resynchronizing with the
+   server, the client can avoid inadvertently removing any messages that
+   have been marked as \Deleted by other clients between the time that
+   the client was last connected and the time the client resynchronizes.
+
+   Before returning an OK to the client, those messages that are removed
+   are reported using a VANISHED response or EXPUNGE responses.
+
+   If the server is capable of storing modification sequences for the
+   selected mailbox, it MUST increment the per-mailbox mod-sequence if
+   at least one message was permanently removed due to the execution of
+   the UID EXPUNGE command.  For each permanently removed message, the
+   server MUST remember the incremented mod-sequence and corresponding
+   UID.  If at least one message got expunged, the server MUST send the
+   updated per-mailbox modification sequence using the HIGHESTMODSEQ
+   response code (defined in [CONDSTORE]) in the tagged OK response.
+
+   Example:    C: . UID EXPUNGE 3000:3002
+               S: * 3 EXPUNGE
+               S: * 3 EXPUNGE
+               S: * 3 EXPUNGE
+               S: . OK [HIGHESTMODSEQ 20010715194045319] Ok
+
+   Note: In this example, at least messages with message numbers 3, 4,
+   and 5 (UIDs 3000 to 3002) had the \Deleted flag set.  The first "* 3
+   EXPUNGE" reports message # 3 as expunged.  The second "* 3 EXPUNGE"
+   reports message # 4 as expunged (the message number got decremented
+   due to the previous EXPUNGE response).  See the description of the
+   EXPUNGE response in [RFC3501] for further explanation.
+
+3.6.  VANISHED Response
+
+   Contents:  an optional EARLIER tag
+
+   list of UIDs
+
+   The VANISHED response reports that the specified UIDs have been
+   permanently removed from the mailbox.  This response is similar to
+   the EXPUNGE response [RFC3501]; however, it can return information
+   about multiple messages, and it returns UIDs instead of message
+
+
+
+
+Melnikov, et al.            Standards Track                    [Page 12]
+
+RFC 5162               IMAP Quick Mailbox Resync              March 2008
+
+
+   numbers.  The first benefit saves bandwidth, while the second is more
+   convenient for clients that only use UIDs to access the IMAP server.
+
+   The VANISHED response has the same restrictions on when it can be
+   sent as does the EXPUNGE response (see below).
+
+   The VANISHED response has two forms.  The first form contains the
+   EARLIER tag, which signifies that the response was caused by a UID
+   FETCH (VANISHED) or a SELECT/EXAMINE (QRESYNC) command.  This
+   response is sent if the UID set parameter to the UID FETCH (VANISHED)
+   command includes UIDs of messages that are no longer in the mailbox.
+   When the client sees a VANISHED EARLIER response, it MUST NOT
+   decrement message sequence numbers for each successive message in the
+   mailbox.
+
+   The second form doesn't contain the EARLIER tag and is described
+   below.  Once a client has issued "ENABLE QRESYNC", the server SHOULD
+   use the VANISHED response without the EARLIER tag instead of the
+   EXPUNGE response.  The server SHOULD continue using VANISHED in lieu
+   of EXPUNGE for the duration of the connection.  In particular, this
+   affects the EXPUNGE [RFC3501] and UID EXPUNGE [UIDPLUS] commands, as
+   well as messages expunged in other connections.  Such a VANISHED
+   response MUST NOT contain the EARLIER tag.
+
+   A VANISHED response sent because of an EXPUNGE or UID EXPUNGE command
+   or because messages were expunged in other connections (i.e., the
+   VANISHED response without the EARLIER tag) also decrements the number
+   of messages in the mailbox; it is not necessary for the server to
+   send an EXISTS response with the new value.  It also decrements
+   message sequence numbers for each successive message in the mailbox
+   (see the example at the end of this section).  Note that a VANISHED
+   response caused by EXPUNGE, UID EXPUNGE, or messages expunged in
+   other connections SHOULD only contain UIDs for messages expunged
+   since the last VANISHED/EXPUNGE response sent for the currently
+   opened mailbox or since the mailbox was opened.  That is, servers
+   SHOULD NOT send UIDs for previously expunged messages, unless
+   explicitly requested to do so by the UID FETCH (VANISHED) command.
+
+   Note that client implementors must take care to properly decrement
+   the number of messages in the mailbox even if a server violates this
+   last SHOULD or repeats the same UID multiple times in the returned
+   UID set.  In general, this means that a client using this extension
+   should either avoid using message numbers entirely, or have a
+   complete mapping of UIDs to message sequence numbers for the selected
+   mailbox.
+
+
+
+
+
+
+Melnikov, et al.            Standards Track                    [Page 13]
+
+RFC 5162               IMAP Quick Mailbox Resync              March 2008
+
+
+   Because clients handle the two different forms of the VANISHED
+   response differently, servers MUST NOT report UIDs resulting from a
+   UID FETCH (VANISHED) or a SELECT/EXAMINE (QRESYNC) in the same
+   VANISHED response as UIDs of messages expunged now (i.e., messages
+   expunged in other connections).  Instead, the server MUST send
+   separate VANISHED responses: one with the EARLIER tag and one
+   without.
+
+   A VANISHED response MUST NOT be sent when no command is in progress,
+   nor while responding to a FETCH, STORE, or SEARCH command.  This rule
+   is necessary to prevent a loss of synchronization of message sequence
+   numbers between client and server.  A command is not "in progress"
+   until the complete command has been received; in particular, a
+   command is not "in progress" during the negotiation of command
+   continuation.
+
+   Note: UID FETCH, UID STORE, and UID SEARCH are different commands
+   from FETCH, STORE, and SEARCH.  A VANISHED response MAY be sent
+   during a UID command.  However, the VANISHED response MUST NOT be
+   sent during a UID SEARCH command that contains message numbers in the
+   search criteria.
+
+   The update from the VANISHED response MUST be recorded by the client.
+
+   Example: Let's assume that there is the following mapping between
+   message numbers and UIDs in the currently selected mailbox (here "X"
+   marks messages with the \Deleted flag set, and "x" represents UIDs
+   which are not relevant for the example):
+
+   Message numbers:   1    2    3    4    5  6   7  8  9 10  11
+   UIDs:              x  504  505  507  508  x 510  x  x  x 625
+   \Deleted messages:           X    X           X            X
+
+   In the presence of the extension defined in this document:
+
+   C: A202 EXPUNGE
+   S: * VANISHED 505,507,510,625
+   S: A202 OK EXPUNGE completed
+
+   Without the QRESYNC extension, the same example might look like:
+
+   C: A202 EXPUNGE
+   S: * 3 EXPUNGE
+   S: * 3 EXPUNGE
+   S: * 5 EXPUNGE
+   S: * 8 EXPUNGE
+   S: A202 OK EXPUNGE completed
+
+
+
+
+Melnikov, et al.            Standards Track                    [Page 14]
+
+RFC 5162               IMAP Quick Mailbox Resync              March 2008
+
+
+   (Continuing previous example) If subsequently messages with UIDs 504
+   and 508 got marked as \Deleted:
+
+   C: A210 EXPUNGE
+   S: * VANISHED 504,508
+   S: A210 OK EXPUNGE completed
+
+   i.e., the last VANISHED response only contains UIDs of messages
+   expunged since the previous VANISHED response.
+
+3.7.  CLOSED Response Code
+
+   The CLOSED response code has no parameters.  A server implementing
+   the extension defined in this document MUST return the CLOSED
+   response code when the currently selected mailbox is closed
+   implicitly using the SELECT/EXAMINE command on another mailbox.  The
+   CLOSED response code serves as a boundary between responses for the
+   previously opened mailbox (which was closed) and the newly selected
+   mailbox: all responses before the CLOSED response code relate to the
+   mailbox that was closed, and all subsequent responses relate to the
+   newly opened mailbox.
+
+   There is no need to return the CLOSED response code on completion of
+   the CLOSE or the UNSELECT [UNSELECT] command (or similar) whose
+   purpose is to close the currently selected mailbox without opening a
+   new one.
+
+4.  Server Implementation Considerations
+
+   This section describes a minimalist implementation, a moderate
+   implementation, and an example of a full implementation.
+
+4.1.  Server Implementations That Don't Store Extra State
+
+   Strictly speaking, a server implementation that doesn't remember mod-
+   sequences associated with expunged messages can be considered
+   compliant with this specification.  Such implementations return all
+   expunged messages specified in the UID set of the UID FETCH
+   (VANISHED) command every time, without paying attention to the
+   specified CHANGEDSINCE mod-sequence.  Such implementations are
+   discouraged, as they can end up returning VANISHED responses that are
+   bigger than the result of a UID SEARCH command for the same UID set.
+
+   Clients that use the message sequence match data can reduce the scope
+   of this VANISHED response substantially in the typical case where
+   expunges have not happened, or happen only toward the end of the
+   mailbox.
+
+
+
+
+Melnikov, et al.            Standards Track                    [Page 15]
+
+RFC 5162               IMAP Quick Mailbox Resync              March 2008
+
+
+4.2.  Server Implementations Storing Minimal State
+
+   A server that stores the HIGHESTMODSEQ value at the time of the last
+   EXPUNGE can omit the VANISHED response when a client provides a
+   MODSEQ value that is equal to, or higher than, the current value of
+   this datum, that is, when there have been no EXPUNGEs.
+
+   A client providing message sequence match data can reduce the scope
+   as above.  In the case where there have been no expunges, the server
+   can ignore this data.
+
+4.3.  Additional State Required on the Server
+
+   When compared to the [CONDSTORE] extension, this extension requires
+   servers to store additional state associated with expunged messages.
+   Note that implementations are not required to store this state in
+   persistent storage; however, use of persistent storage is advisable.
+
+   One possible way to correctly implement the extension described in
+   this document is to store a queue of <UID set, mod-sequence> pairs.
+   <UID set> can be represented as a sequence of <min UID, max UID>
+   pairs.
+
+   When messages are expunged, one or more entries are added to the
+   queue tail.
+
+   When the server receives a request to return messages expunged since
+   a given mod-sequence, it will search the queue from the tail (i.e.,
+   going from the highest expunged mod-sequence to the lowest) until it
+   sees the first record with a mod-sequence less than or equal to the
+   given mod-sequence or it reaches the head of the queue.
+
+   Note that indefinitely storing information about expunged messages
+   can cause storage and related problems for an implementation.  In the
+   worst case, this could result in almost 64Gb of storage for each IMAP
+   mailbox.  For example, consider an implementation that stores <min
+   UID, max UID, mod-sequence> triples for each range of messages
+   expunged at the same time.  Each triple requires 16 octets: 4 octets
+   for each of the two UIDs, and 8 octets for the mod-sequence.  Assume
+   that there is a mailbox containing a single message with a UID of
+   2**32-1 (the maximum possible UID value), where messages had
+   previously existed with UIDs starting at 1, and have been expunged
+   one at a time.  For this mailbox alone, storage is required for the
+   triples <1, 1, modseq1>, <2, 2, modseq2>, ..., <2**32-2, 2**32-2,
+   modseq4294967294>.
+
+
+
+
+
+
+Melnikov, et al.            Standards Track                    [Page 16]
+
+RFC 5162               IMAP Quick Mailbox Resync              March 2008
+
+
+   Hence, implementations are encouraged to adopt strategies to protect
+   against such storage problems, such as limiting the size of the queue
+   used to store mod-sequences for expunged messages and "expiring"
+   older records when this limit is reached.  When the selected
+   implementation-specific queue limit is reached, the oldest record(s)
+   are deleted from the queue (note that such records are located at the
+   queue head).  For all such "expired" records, the server needs to
+   store a single mod-sequence, which is the highest mod-sequence for
+   all "expired" expunged messages.
+
+   Note that if the client provides the message sequence match data,
+   this can heavily reduce the data cost of sending a complete set of
+   missing UIDs; thus, reducing the problems for clients if a server is
+   unable to persist much of this queue.  If the queue contains data
+   back to the requested mod-sequence, this data can be ignored.
+
+   Also, note that if the UIDVALIDITY of the mailbox changes or if the
+   mailbox is deleted, then any state associated with expunged messages
+   doesn't need to be preserved and SHOULD be deleted.
+
+5.  Updated Synchronization Sequence
+
+   This section updates the description of optimized synchronization in
+   Section 6.1 of the [IMAP-DISC].
+
+   An advanced disconnected mail client should use the QRESYNC and
+   [CONDSTORE] extensions when they are supported by the server.  The
+   client uses the value from the HIGHESTMODSEQ OK response code
+   received on mailbox opening to determine if it needs to
+   resynchronize.  Once the synchronization is complete, it MUST cache
+   the received value (unless the mailbox UIDVALIDITY value has changed;
+   see below).  The client MUST update its copy of the HIGHESTMODSEQ
+   value whenever the server sends a subsequent HIGHESTMODSEQ OK
+   response code.
+
+   After completing a full synchronization, the client MUST also take
+   note of any unsolicited MODSEQ FETCH data items received from the
+   server.  Whenever the client receives a tagged response to a command,
+   it calculates the highest value among all MODSEQ FETCH data items
+   received since the last tagged response.  If this value is bigger
+   than the client's copy of the HIGHESTMODSEQ value, then the client
+   MUST use this value as its new HIGHESTMODSEQ value.
+
+   Note: It is not safe to update the client's copy of the HIGHESTMODSEQ
+   value with a MODSEQ FETCH data item value as soon as it is received
+   because servers are not required to send MODSEQ FETCH data items in
+   increasing modseqence order.  This can lead to the client missing
+   some changes in case of connectivity loss.
+
+
+
+Melnikov, et al.            Standards Track                    [Page 17]
+
+RFC 5162               IMAP Quick Mailbox Resync              March 2008
+
+
+   When opening the mailbox for synchronization, the client uses the
+   QRESYNC parameter to the SELECT/EXAMINE command.  The QRESYNC
+   parameter is followed by the UIDVALIDITY and mailbox HIGHESTMODSEQ
+   values, as known to the client.  It can be optionally followed by the
+   set of UIDs, for example, if the client is only interested in partial
+   synchronization of the mailbox.  The client may also transmit a list
+   containing its knowledge of message numbers.
+
+   If the SELECT/EXAMINE command is successful, the client compares
+   UIDVALIDITY as described in step d)1) in Section 3 of the
+   [IMAP-DISC].  If the cached UIDVALIDITY value matches the one
+   returned by the server and the server also returns the HIGHESTMODSEQ
+   response code, then the server reports expunged messages and returns
+   flag changes for all messages specified by the client in the UID set
+   parameter (or for all messages in the mailbox, if the client omitted
+   the UID set parameter).  At this point, the client is synchronized,
+   except for maybe the new messages.
+
+   If upon a successful SELECT/EXAMINE (QRESYNC) command the client
+   receives a NOMODSEQ OK untagged response (instead of the
+   HIGHESTMODSEQ response code), it MUST remove the last known
+   HIGHESTMODSEQ value from its cache and follow the more general
+   instructions in Section 3 of the [IMAP-DISC].
+
+   At this point, the client is in sync with the server regarding old
+   messages.  This client can now fetch information about new messages
+   (if requested by the user).
+
+   Step d) ("Server-to-client synchronization") in Section 4 of the
+   [IMAP-DISC] in the presence of the QRESYNC & CONDSTORE extensions is
+   amended as follows:
+
+   d) "Server-to-client synchronization" -- for each mailbox that
+      requires synchronization, do the following:
+
+   1a) Check the mailbox UIDVALIDITY (see Section 4.1 of the [IMAP-DISC]
+       for more details) after issuing SELECT/EXAMINE (QRESYNC) command.
+
+       If the UIDVALIDITY value returned by the server differs, the
+       client MUST
+
+       *   empty the local cache of that mailbox;
+
+       *   "forget" the cached HIGHESTMODSEQ value for the mailbox;
+
+
+
+
+
+
+
+Melnikov, et al.            Standards Track                    [Page 18]
+
+RFC 5162               IMAP Quick Mailbox Resync              March 2008
+
+
+       *   remove any pending "actions" which refer to UIDs in that
+           mailbox.  Note, this doesn't affect actions performed on
+           client generated fake UIDs (see Section 5 of the
+           [IMAP-DISC]);
+
+   2)  Fetch the current "descriptors";
+
+       I) Discover new messages.
+
+   3)  Fetch the bodies of any "interesting" messages that the client
+       doesn't already have.
+
+   Example: The UIDVALIDITY value is the same, but the HIGHESTMODSEQ
+            value has changed on the server while the client was
+            offline:
+
+    C: A142 SELECT INBOX (QRESYNC (3857529045 20010715194032001 1:198))
+    S: * 172 EXISTS
+    S: * 1 RECENT
+    S: * OK [UNSEEN 12] Message 12 is first unseen
+    S: * OK [UIDVALIDITY 3857529045] UIDs valid
+    S: * OK [UIDNEXT 201] Predicted next UID
+    S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
+    S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
+    S: * OK [HIGHESTMODSEQ 20010715194045007]
+    S: * VANISHED (EARLIER) 1:5,7:8,10:15
+    S: * 2 FETCH (UID 6 MODSEQ (20010715205008000)
+        FLAGS (\Deleted))
+    S: * 5 FETCH (UID 9 MODSEQ (20010715195517000)
+        FLAGS ($NoJunk $AutoJunk $MDNSent))
+       ...
+    S: A142 OK [READ-WRITE] SELECT completed
+
+6.  Formal Syntax
+
+   The following syntax specification uses the Augmented Backus-Naur
+   Form (ABNF) notation as specified in [ABNF].
+
+   Non-terminals referenced but not defined below are as defined by
+   [RFC3501], [CONDSTORE], or [IMAPABNF].
+
+   Except as noted otherwise, all alphabetic characters are case-
+   insensitive.  The use of upper or lower case characters to define
+   token strings is for editorial clarity only.  Implementations MUST
+   accept these strings in a case-insensitive fashion.
+
+
+
+
+
+
+Melnikov, et al.            Standards Track                    [Page 19]
+
+RFC 5162               IMAP Quick Mailbox Resync              March 2008
+
+
+   capability          =/ "QRESYNC"
+
+   select-param        =  "QRESYNC" SP "(" uidvalidity SP
+                       mod-sequence-value [SP known-uids]
+                       [SP seq-match-data] ")"
+                       ;; conforms to the generic select-param
+                       ;; syntax defined in [IMAPABNF]
+
+   seq-match-data      =  "(" known-sequence-set SP known-uid-set ")"
+
+   uidvalidity         =  nz-number
+
+   known-uids          =  sequence-set
+                       ;; sequence of UIDs, "*" is not allowed
+
+   known-sequence-set  =  sequence-set
+                       ;; set of message numbers corresponding to
+                       ;; the UIDs in known-uid-set, in ascending order.
+                       ;; * is not allowed.
+
+   known-uid-set       =  sequence-set
+                       ;; set of UIDs corresponding to the messages in
+                       ;; known-sequence-set, in ascending order.
+                       ;; * is not allowed.
+
+   message-data        =/ expunged-resp
+
+   expunged-resp       =  "VANISHED" [SP "(EARLIER)"] SP known-uids
+
+   rexpunges-fetch-mod =  "VANISHED"
+                       ;; VANISHED UID FETCH modifier conforms
+                       ;; to the fetch-modifier syntax
+                       ;; defined in [IMAPABNF].  It is only
+                       ;; allowed in the UID FETCH command.
+
+   resp-text-code      =/ "CLOSED"
+
+7.  Security Considerations
+
+   As always, it is important to thoroughly test clients and servers
+   implementing this extension, as it changes how the server reports
+   expunged messages to the client.
+
+   Security considerations relevant to [CONDSTORE] are relevant to this
+   extension.
+
+   This document doesn't raise any new security concerns not already
+   raised by [CONDSTORE] or [RFC3501].
+
+
+
+Melnikov, et al.            Standards Track                    [Page 20]
+
+RFC 5162               IMAP Quick Mailbox Resync              March 2008
+
+
+8.  IANA Considerations
+
+   IMAP4 capabilities are registered by publishing a standards track or
+   IESG approved experimental RFC.  The registry is currently located
+   at:
+
+      http://www.iana.org/assignments/imap4-capabilities
+
+   This document defines the QRESYNC IMAP capability.  IANA has added
+   this capability to the registry.
+
+9.  Acknowledgments
+
+   Thanks to Steve Hole, Cyrus Daboo, and Michael Wener for encouraging
+   creation of this document.
+
+   Valuable comments, both in agreement and in dissent, were received
+   from Timo Sirainen, Michael Wener, Randall Gellens, Arnt Gulbrandsen,
+   Chris Newman, Peter Coates, Mark Crispin, Elwyn Davies, Dan Karp,
+   Eric Rescorla, and Mike Zraly.
+
+   This document takes substantial text from [RFC3501] by Mark Crispin.
+
+10.  References
+
+10.1.  Normative References
+
+   [ABNF]       Crocker, D. and P. Overell, "Augmented BNF for Syntax
+                Specifications: ABNF", STD 68, RFC 5234, January 2008.
+
+   [CONDSTORE]  Melnikov, A. and S. Hole, "IMAP Extension for
+                Conditional STORE Operation or Quick Flag Changes
+                Resynchronization", RFC 4551, June 2006.
+
+   [ENABLE]     Gulbrandsen, A., Ed. and A. Melnikov, Ed., "The IMAP
+                ENABLE Extension", RFC 5161, March 2008.
+
+   [IMAPABNF]   Melnikov, A. and C. Daboo, "Collected Extensions to
+                IMAP4 ABNF", RFC 4466, April 2006.
+
+   [RFC2119]    Bradner, S., "Key words for use in RFCs to Indicate
+                Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+   [RFC3501]    Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
+                4rev1", RFC 3501, March 2003.
+
+   [UIDPLUS]    Crispin, M., "Internet Message Access Protocol (IMAP) -
+                UIDPLUS extension", RFC 4315, December 2005.
+
+
+
+Melnikov, et al.            Standards Track                    [Page 21]
+
+RFC 5162               IMAP Quick Mailbox Resync              March 2008
+
+
+10.2.  Informative References
+
+   [IMAP-DISC]  Melnikov, A., Ed., "Synchronization Operations For
+                Disconnected Imap4 Clients", RFC 4549, June 2006.
+
+   [UNSELECT]   Melnikov, A., "Internet Message Access Protocol (IMAP)
+                UNSELECT command", RFC 3691, February 2004.
+
+Authors' Addresses
+
+   Alexey Melnikov
+   Isode Ltd
+   5 Castle Business Village
+   36 Station Road
+   Hampton, Middlesex  TW12 2BX
+   UK
+
+   EMail: Alexey.Melnikov@isode.com
+
+
+   Dave Cridland
+   Isode Ltd
+   5 Castle Business Village
+   36 Station Road
+   Hampton, Middlesex  TW12 2BX
+   UK
+
+   EMail: dave.cridland@isode.com
+
+
+   Corby Wilson
+   Nokia
+   5 Wayside Rd.
+   Burlington, MA  01803
+   USA
+
+   EMail: corby@computer.org
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov, et al.            Standards Track                    [Page 22]
+
+RFC 5162               IMAP Quick Mailbox Resync              March 2008
+
+
+Full Copyright Statement
+
+   Copyright (C) The IETF Trust (2008).
+
+   This document is subject to the rights, licenses and restrictions
+   contained in BCP 78, and except as set forth therein, the authors
+   retain all their rights.
+
+   This document and the information contained herein are provided on an
+   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
+   THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
+   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   Intellectual Property Rights or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; nor does it represent that it has
+   made any independent effort to identify any such rights.  Information
+   on the procedures with respect to rights in RFC documents can be
+   found in BCP 78 and BCP 79.
+
+   Copies of IPR disclosures made to the IETF Secretariat and any
+   assurances of licenses to be made available, or the result of an
+   attempt made to obtain a general license or permission for the use of
+   such proprietary rights by implementers or users of this
+   specification can be obtained from the IETF on-line IPR repository at
+   http://www.ietf.org/ipr.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights that may cover technology that may be required to implement
+   this standard.  Please address the information to the IETF at
+   ietf-ipr@ietf.org.
+
+
+
+
+
+
+
+
+
+
+
+
+Melnikov, et al.            Standards Track                    [Page 23]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/rfc/rfc5234.txt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,899 @@
+
+
+
+
+
+
+Network Working Group                                    D. Crocker, Ed.
+Request for Comments: 5234                   Brandenburg InternetWorking
+STD: 68                                                       P. Overell
+Obsoletes: 4234                                                THUS plc.
+Category: Standards Track                                   January 2008
+
+
+             Augmented BNF for Syntax Specifications: ABNF
+
+Status of This Memo
+
+   This document specifies an Internet standards track protocol for the
+   Internet community, and requests discussion and suggestions for
+   improvements.  Please refer to the current edition of the "Internet
+   Official Protocol Standards" (STD 1) for the standardization state
+   and status of this protocol.  Distribution of this memo is unlimited.
+
+Abstract
+
+   Internet technical specifications often need to define a formal
+   syntax.  Over the years, a modified version of Backus-Naur Form
+   (BNF), called Augmented BNF (ABNF), has been popular among many
+   Internet specifications.  The current specification documents ABNF.
+   It balances compactness and simplicity with reasonable
+   representational power.  The differences between standard BNF and
+   ABNF involve naming rules, repetition, alternatives, order-
+   independence, and value ranges.  This specification also supplies
+   additional rule definitions and encoding for a core lexical analyzer
+   of the type common to several Internet specifications.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crocker & Overell           Standards Track                     [Page 1]
+
+RFC 5234                          ABNF                      January 2008
+
+
+Table of Contents
+
+   1.  Introduction . . . . . . . . . . . . . . . . . . . . . . . . .  3
+   2.  Rule Definition  . . . . . . . . . . . . . . . . . . . . . . .  3
+     2.1.  Rule Naming  . . . . . . . . . . . . . . . . . . . . . . .  3
+     2.2.  Rule Form  . . . . . . . . . . . . . . . . . . . . . . . .  4
+     2.3.  Terminal Values  . . . . . . . . . . . . . . . . . . . . .  4
+     2.4.  External Encodings . . . . . . . . . . . . . . . . . . . .  6
+   3.  Operators  . . . . . . . . . . . . . . . . . . . . . . . . . .  6
+     3.1.  Concatenation:  Rule1 Rule2  . . . . . . . . . . . . . . .  6
+     3.2.  Alternatives:  Rule1 / Rule2 . . . . . . . . . . . . . . .  7
+     3.3.  Incremental Alternatives: Rule1 =/ Rule2 . . . . . . . . .  7
+     3.4.  Value Range Alternatives:  %c##-## . . . . . . . . . . . .  8
+     3.5.  Sequence Group:  (Rule1 Rule2) . . . . . . . . . . . . . .  8
+     3.6.  Variable Repetition:  *Rule  . . . . . . . . . . . . . . .  9
+     3.7.  Specific Repetition:  nRule  . . . . . . . . . . . . . . .  9
+     3.8.  Optional Sequence:  [RULE] . . . . . . . . . . . . . . . .  9
+     3.9.  Comment:  ; Comment  . . . . . . . . . . . . . . . . . . .  9
+     3.10. Operator Precedence  . . . . . . . . . . . . . . . . . . . 10
+   4.  ABNF Definition of ABNF  . . . . . . . . . . . . . . . . . . . 10
+   5.  Security Considerations  . . . . . . . . . . . . . . . . . . . 12
+   6.  References . . . . . . . . . . . . . . . . . . . . . . . . . . 12
+     6.1.  Normative References . . . . . . . . . . . . . . . . . . . 12
+     6.2.  Informative References . . . . . . . . . . . . . . . . . . 12
+   Appendix A.  Acknowledgements  . . . . . . . . . . . . . . . . . . 13
+   Appendix B.  Core ABNF of ABNF . . . . . . . . . . . . . . . . . . 13
+     B.1.  Core Rules . . . . . . . . . . . . . . . . . . . . . . . . 13
+     B.2.  Common Encoding  . . . . . . . . . . . . . . . . . . . . . 15
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crocker & Overell           Standards Track                     [Page 2]
+
+RFC 5234                          ABNF                      January 2008
+
+
+1.  Introduction
+
+   Internet technical specifications often need to define a formal
+   syntax and are free to employ whatever notation their authors deem
+   useful.  Over the years, a modified version of Backus-Naur Form
+   (BNF), called Augmented BNF (ABNF), has been popular among many
+   Internet specifications.  It balances compactness and simplicity with
+   reasonable representational power.  In the early days of the Arpanet,
+   each specification contained its own definition of ABNF.  This
+   included the email specifications, [RFC733] and then [RFC822], which
+   came to be the common citations for defining ABNF.  The current
+   document separates those definitions to permit selective reference.
+   Predictably, it also provides some modifications and enhancements.
+
+   The differences between standard BNF and ABNF involve naming rules,
+   repetition, alternatives, order-independence, and value ranges.
+   Appendix B supplies rule definitions and encoding for a core lexical
+   analyzer of the type common to several Internet specifications.  It
+   is provided as a convenience and is otherwise separate from the meta
+   language defined in the body of this document, and separate from its
+   formal status.
+
+2.  Rule Definition
+
+2.1.  Rule Naming
+
+   The name of a rule is simply the name itself, that is, a sequence of
+   characters, beginning with an alphabetic character, and followed by a
+   combination of alphabetics, digits, and hyphens (dashes).
+
+   NOTE:
+
+      Rule names are case insensitive.
+
+   The names <rulename>, <Rulename>, <RULENAME>, and <rUlENamE> all
+   refer to the same rule.
+
+   Unlike original BNF, angle brackets ("<", ">") are not required.
+   However, angle brackets may be used around a rule name whenever their
+   presence facilitates in discerning the use of a rule name.  This is
+   typically restricted to rule name references in free-form prose, or
+   to distinguish partial rules that combine into a string not separated
+   by white space, such as shown in the discussion about repetition,
+   below.
+
+
+
+
+
+
+
+Crocker & Overell           Standards Track                     [Page 3]
+
+RFC 5234                          ABNF                      January 2008
+
+
+2.2.  Rule Form
+
+   A rule is defined by the following sequence:
+
+         name =  elements crlf
+
+   where <name> is the name of the rule, <elements> is one or more rule
+   names or terminal specifications, and <crlf> is the end-of-line
+   indicator (carriage return followed by line feed).  The equal sign
+   separates the name from the definition of the rule.  The elements
+   form a sequence of one or more rule names and/or value definitions,
+   combined according to the various operators defined in this document,
+   such as alternative and repetition.
+
+   For visual ease, rule definitions are left aligned.  When a rule
+   requires multiple lines, the continuation lines are indented.  The
+   left alignment and indentation are relative to the first lines of the
+   ABNF rules and need not match the left margin of the document.
+
+2.3.  Terminal Values
+
+   Rules resolve into a string of terminal values, sometimes called
+   characters.  In ABNF, a character is merely a non-negative integer.
+   In certain contexts, a specific mapping (encoding) of values into a
+   character set (such as ASCII) will be specified.
+
+   Terminals are specified by one or more numeric characters, with the
+   base interpretation of those characters indicated explicitly.  The
+   following bases are currently defined:
+
+         b           =  binary
+
+         d           =  decimal
+
+         x           =  hexadecimal
+
+   Hence:
+
+         CR          =  %d13
+
+         CR          =  %x0D
+
+   respectively specify the decimal and hexadecimal representation of
+   [US-ASCII] for carriage return.
+
+
+
+
+
+
+
+Crocker & Overell           Standards Track                     [Page 4]
+
+RFC 5234                          ABNF                      January 2008
+
+
+   A concatenated string of such values is specified compactly, using a
+   period (".") to indicate a separation of characters within that
+   value.  Hence:
+
+         CRLF        =  %d13.10
+
+   ABNF permits the specification of literal text strings directly,
+   enclosed in quotation marks.  Hence:
+
+         command     =  "command string"
+
+   Literal text strings are interpreted as a concatenated set of
+   printable characters.
+
+   NOTE:
+
+      ABNF strings are case insensitive and the character set for these
+      strings is US-ASCII.
+
+   Hence:
+
+         rulename = "abc"
+
+   and:
+
+         rulename = "aBc"
+
+   will match "abc", "Abc", "aBc", "abC", "ABc", "aBC", "AbC", and
+   "ABC".
+
+      To specify a rule that is case sensitive, specify the characters
+      individually.
+
+   For example:
+
+         rulename    =  %d97 %d98 %d99
+
+   or
+
+         rulename    =  %d97.98.99
+
+   will match only the string that comprises only the lowercase
+   characters, abc.
+
+
+
+
+
+
+
+
+Crocker & Overell           Standards Track                     [Page 5]
+
+RFC 5234                          ABNF                      January 2008
+
+
+2.4.  External Encodings
+
+   External representations of terminal value characters will vary
+   according to constraints in the storage or transmission environment.
+   Hence, the same ABNF-based grammar may have multiple external
+   encodings, such as one for a 7-bit US-ASCII environment, another for
+   a binary octet environment, and still a different one when 16-bit
+   Unicode is used.  Encoding details are beyond the scope of ABNF,
+   although Appendix B provides definitions for a 7-bit US-ASCII
+   environment as has been common to much of the Internet.
+
+   By separating external encoding from the syntax, it is intended that
+   alternate encoding environments can be used for the same syntax.
+
+3.  Operators
+
+3.1.  Concatenation:  Rule1 Rule2
+
+   A rule can define a simple, ordered string of values (i.e., a
+   concatenation of contiguous characters) by listing a sequence of rule
+   names.  For example:
+
+         foo         =  %x61           ; a
+
+         bar         =  %x62           ; b
+
+         mumble      =  foo bar foo
+
+   So that the rule <mumble> matches the lowercase string "aba".
+
+   Linear white space: Concatenation is at the core of the ABNF parsing
+   model.  A string of contiguous characters (values) is parsed
+   according to the rules defined in ABNF.  For Internet specifications,
+   there is some history of permitting linear white space (space and
+   horizontal tab) to be freely and implicitly interspersed around major
+   constructs, such as delimiting special characters or atomic strings.
+
+   NOTE:
+
+      This specification for ABNF does not provide for implicit
+      specification of linear white space.
+
+   Any grammar that wishes to permit linear white space around
+   delimiters or string segments must specify it explicitly.  It is
+   often useful to provide for such white space in "core" rules that are
+   then used variously among higher-level rules.  The "core" rules might
+   be formed into a lexical analyzer or simply be part of the main
+   ruleset.
+
+
+
+Crocker & Overell           Standards Track                     [Page 6]
+
+RFC 5234                          ABNF                      January 2008
+
+
+3.2.  Alternatives:  Rule1 / Rule2
+
+   Elements separated by a forward slash ("/") are alternatives.
+   Therefore,
+
+         foo / bar
+
+   will accept <foo> or <bar>.
+
+   NOTE:
+
+      A quoted string containing alphabetic characters is a special form
+      for specifying alternative characters and is interpreted as a non-
+      terminal representing the set of combinatorial strings with the
+      contained characters, in the specified order but with any mixture
+      of upper- and lowercase.
+
+3.3.  Incremental Alternatives: Rule1 =/ Rule2
+
+   It is sometimes convenient to specify a list of alternatives in
+   fragments.  That is, an initial rule may match one or more
+   alternatives, with later rule definitions adding to the set of
+   alternatives.  This is particularly useful for otherwise independent
+   specifications that derive from the same parent ruleset, such as
+   often occurs with parameter lists.  ABNF permits this incremental
+   definition through the construct:
+
+         oldrule     =/ additional-alternatives
+
+   So that the ruleset
+
+         ruleset     =  alt1 / alt2
+
+         ruleset     =/ alt3
+
+         ruleset     =/ alt4 / alt5
+
+   is the same as specifying
+
+         ruleset     =  alt1 / alt2 / alt3 / alt4 / alt5
+
+
+
+
+
+
+
+
+
+
+
+Crocker & Overell           Standards Track                     [Page 7]
+
+RFC 5234                          ABNF                      January 2008
+
+
+3.4.  Value Range Alternatives:  %c##-##
+
+   A range of alternative numeric values can be specified compactly,
+   using a dash ("-") to indicate the range of alternative values.
+   Hence:
+
+         DIGIT       =  %x30-39
+
+   is equivalent to:
+
+         DIGIT       =  "0" / "1" / "2" / "3" / "4" / "5" / "6" /
+
+                        "7" / "8" / "9"
+
+   Concatenated numeric values and numeric value ranges cannot be
+   specified in the same string.  A numeric value may use the dotted
+   notation for concatenation or it may use the dash notation to specify
+   one value range.  Hence, to specify one printable character between
+   end-of-line sequences, the specification could be:
+
+         char-line = %x0D.0A %x20-7E %x0D.0A
+
+3.5.  Sequence Group:  (Rule1 Rule2)
+
+   Elements enclosed in parentheses are treated as a single element,
+   whose contents are strictly ordered.  Thus,
+
+         elem (foo / bar) blat
+
+   matches (elem foo blat) or (elem bar blat), and
+
+         elem foo / bar blat
+
+   matches (elem foo) or (bar blat).
+
+   NOTE:
+
+      It is strongly advised that grouping notation be used, rather than
+      relying on the proper reading of "bare" alternations, when
+      alternatives consist of multiple rule names or literals.
+
+   Hence, it is recommended that the following form be used:
+
+        (elem foo) / (bar blat)
+
+   It will avoid misinterpretation by casual readers.
+
+
+
+
+
+Crocker & Overell           Standards Track                     [Page 8]
+
+RFC 5234                          ABNF                      January 2008
+
+
+   The sequence group notation is also used within free text to set off
+   an element sequence from the prose.
+
+3.6.  Variable Repetition:  *Rule
+
+   The operator "*" preceding an element indicates repetition.  The full
+   form is:
+
+         <a>*<b>element
+
+   where <a> and <b> are optional decimal values, indicating at least
+   <a> and at most <b> occurrences of the element.
+
+   Default values are 0 and infinity so that *<element> allows any
+   number, including zero; 1*<element> requires at least one;
+   3*3<element> allows exactly 3; and 1*2<element> allows one or two.
+
+3.7.  Specific Repetition:  nRule
+
+   A rule of the form:
+
+         <n>element
+
+   is equivalent to
+
+         <n>*<n>element
+
+   That is, exactly <n> occurrences of <element>.  Thus, 2DIGIT is a
+   2-digit number, and 3ALPHA is a string of three alphabetic
+   characters.
+
+3.8.  Optional Sequence:  [RULE]
+
+   Square brackets enclose an optional element sequence:
+
+         [foo bar]
+
+   is equivalent to
+
+         *1(foo bar).
+
+3.9.  Comment:  ; Comment
+
+   A semicolon starts a comment that continues to the end of line.  This
+   is a simple way of including useful notes in parallel with the
+   specifications.
+
+
+
+
+
+Crocker & Overell           Standards Track                     [Page 9]
+
+RFC 5234                          ABNF                      January 2008
+
+
+3.10.  Operator Precedence
+
+   The various mechanisms described above have the following precedence,
+   from highest (binding tightest) at the top, to lowest (loosest) at
+   the bottom:
+
+      Rule name, prose-val, Terminal value
+
+      Comment
+
+      Value range
+
+      Repetition
+
+      Grouping, Optional
+
+      Concatenation
+
+      Alternative
+
+   Use of the alternative operator, freely mixed with concatenations,
+   can be confusing.
+
+      Again, it is recommended that the grouping operator be used to
+      make explicit concatenation groups.
+
+4.  ABNF Definition of ABNF
+
+   NOTES:
+
+      1.  This syntax requires a formatting of rules that is relatively
+          strict.  Hence, the version of a ruleset included in a
+          specification might need preprocessing to ensure that it can
+          be interpreted by an ABNF parser.
+
+      2.  This syntax uses the rules provided in Appendix B.
+
+
+         rulelist       =  1*( rule / (*c-wsp c-nl) )
+
+         rule           =  rulename defined-as elements c-nl
+                                ; continues if next line starts
+                                ;  with white space
+
+         rulename       =  ALPHA *(ALPHA / DIGIT / "-")
+
+
+
+
+
+
+Crocker & Overell           Standards Track                    [Page 10]
+
+RFC 5234                          ABNF                      January 2008
+
+
+         defined-as     =  *c-wsp ("=" / "=/") *c-wsp
+                                ; basic rules definition and
+                                ;  incremental alternatives
+
+         elements       =  alternation *c-wsp
+
+         c-wsp          =  WSP / (c-nl WSP)
+
+         c-nl           =  comment / CRLF
+                                ; comment or newline
+
+         comment        =  ";" *(WSP / VCHAR) CRLF
+
+         alternation    =  concatenation
+                           *(*c-wsp "/" *c-wsp concatenation)
+
+         concatenation  =  repetition *(1*c-wsp repetition)
+
+         repetition     =  [repeat] element
+
+         repeat         =  1*DIGIT / (*DIGIT "*" *DIGIT)
+
+         element        =  rulename / group / option /
+                           char-val / num-val / prose-val
+
+         group          =  "(" *c-wsp alternation *c-wsp ")"
+
+         option         =  "[" *c-wsp alternation *c-wsp "]"
+
+         char-val       =  DQUOTE *(%x20-21 / %x23-7E) DQUOTE
+                                ; quoted string of SP and VCHAR
+                                ;  without DQUOTE
+
+         num-val        =  "%" (bin-val / dec-val / hex-val)
+
+         bin-val        =  "b" 1*BIT
+                           [ 1*("." 1*BIT) / ("-" 1*BIT) ]
+                                ; series of concatenated bit values
+                                ;  or single ONEOF range
+
+         dec-val        =  "d" 1*DIGIT
+                           [ 1*("." 1*DIGIT) / ("-" 1*DIGIT) ]
+
+         hex-val        =  "x" 1*HEXDIG
+                           [ 1*("." 1*HEXDIG) / ("-" 1*HEXDIG) ]
+
+
+
+
+
+
+Crocker & Overell           Standards Track                    [Page 11]
+
+RFC 5234                          ABNF                      January 2008
+
+
+         prose-val      =  "<" *(%x20-3D / %x3F-7E) ">"
+                                ; bracketed string of SP and VCHAR
+                                ;  without angles
+                                ; prose description, to be used as
+                                ;  last resort
+
+5.  Security Considerations
+
+   Security is truly believed to be irrelevant to this document.
+
+6.  References
+
+6.1.  Normative References
+
+   [US-ASCII]  American National Standards Institute, "Coded Character
+               Set -- 7-bit American Standard Code for Information
+               Interchange", ANSI X3.4, 1986.
+
+6.2.  Informative References
+
+   [RFC733]    Crocker, D., Vittal, J., Pogran, K., and D. Henderson,
+               "Standard for the format of ARPA network text messages",
+               RFC 733, November 1977.
+
+   [RFC822]    Crocker, D., "Standard for the format of ARPA Internet
+               text messages", STD 11, RFC 822, August 1982.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crocker & Overell           Standards Track                    [Page 12]
+
+RFC 5234                          ABNF                      January 2008
+
+
+Appendix A.  Acknowledgements
+
+   The syntax for ABNF was originally specified in RFC 733.  Ken L.
+   Harrenstien, of SRI International, was responsible for re-coding the
+   BNF into an Augmented BNF that makes the representation smaller and
+   easier to understand.
+
+   This recent project began as a simple effort to cull out the portion
+   of RFC 822 that has been repeatedly cited by non-email specification
+   writers, namely the description of Augmented BNF.  Rather than simply
+   and blindly converting the existing text into a separate document,
+   the working group chose to give careful consideration to the
+   deficiencies, as well as benefits, of the existing specification and
+   related specifications made available over the last 15 years, and
+   therefore to pursue enhancement.  This turned the project into
+   something rather more ambitious than was first intended.
+   Interestingly, the result is not massively different from that
+   original, although decisions, such as removing the list notation,
+   came as a surprise.
+
+   This "separated" version of the specification was part of the DRUMS
+   working group, with significant contributions from Jerome Abela,
+   Harald Alvestrand, Robert Elz, Roger Fajman, Aviva Garrett, Tom
+   Harsch, Dan Kohn, Bill McQuillan, Keith Moore, Chris Newman, Pete
+   Resnick, and Henning Schulzrinne.
+
+   Julian Reschke warrants a special thanks for converting the Draft
+   Standard version to XML source form.
+
+Appendix B.  Core ABNF of ABNF
+
+   This appendix contains some basic rules that are in common use.
+   Basic rules are in uppercase.  Note that these rules are only valid
+   for ABNF encoded in 7-bit ASCII or in characters sets that are a
+   superset of 7-bit ASCII.
+
+B.1.  Core Rules
+
+   Certain basic rules are in uppercase, such as SP, HTAB, CRLF, DIGIT,
+   ALPHA, etc.
+
+         ALPHA          =  %x41-5A / %x61-7A   ; A-Z / a-z
+
+         BIT            =  "0" / "1"
+
+         CHAR           =  %x01-7F
+                                ; any 7-bit US-ASCII character,
+                                ;  excluding NUL
+
+
+
+Crocker & Overell           Standards Track                    [Page 13]
+
+RFC 5234                          ABNF                      January 2008
+
+
+         CR             =  %x0D
+                                ; carriage return
+
+         CRLF           =  CR LF
+                                ; Internet standard newline
+
+         CTL            =  %x00-1F / %x7F
+                                ; controls
+
+         DIGIT          =  %x30-39
+                                ; 0-9
+
+         DQUOTE         =  %x22
+                                ; " (Double Quote)
+
+         HEXDIG         =  DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
+
+         HTAB           =  %x09
+                                ; horizontal tab
+
+         LF             =  %x0A
+                                ; linefeed
+
+         LWSP           =  *(WSP / CRLF WSP)
+                                ; Use of this linear-white-space rule
+                                ;  permits lines containing only white
+                                ;  space that are no longer legal in
+                                ;  mail headers and have caused
+                                ;  interoperability problems in other
+                                ;  contexts.
+                                ; Do not use when defining mail
+                                ;  headers and use with caution in
+                                ;  other contexts.
+
+         OCTET          =  %x00-FF
+                                ; 8 bits of data
+
+         SP             =  %x20
+
+         VCHAR          =  %x21-7E
+                                ; visible (printing) characters
+
+         WSP            =  SP / HTAB
+                                ; white space
+
+
+
+
+
+
+
+Crocker & Overell           Standards Track                    [Page 14]
+
+RFC 5234                          ABNF                      January 2008
+
+
+B.2.  Common Encoding
+
+   Externally, data are represented as "network virtual ASCII" (namely,
+   7-bit US-ASCII in an 8-bit field), with the high (8th) bit set to
+   zero.  A string of values is in "network byte order", in which the
+   higher-valued bytes are represented on the left-hand side and are
+   sent over the network first.
+
+Authors' Addresses
+
+   Dave Crocker (editor)
+   Brandenburg InternetWorking
+   675 Spruce Dr.
+   Sunnyvale, CA  94086
+   US
+
+   Phone: +1.408.246.8253
+   EMail: dcrocker@bbiw.net
+
+
+   Paul Overell
+   THUS plc.
+   1/2 Berkeley Square,
+   99 Berkeley Street
+   Glasgow  G3 7HR
+   UK
+
+   EMail: paul.overell@thus.net
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crocker & Overell           Standards Track                    [Page 15]
+
+RFC 5234                          ABNF                      January 2008
+
+
+Full Copyright Statement
+
+   Copyright (C) The IETF Trust (2008).
+
+   This document is subject to the rights, licenses and restrictions
+   contained in BCP 78, and except as set forth therein, the authors
+   retain all their rights.
+
+   This document and the information contained herein are provided on an
+   "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+   OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND
+   THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS
+   OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
+   THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+   WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+   The IETF takes no position regarding the validity or scope of any
+   Intellectual Property Rights or other rights that might be claimed to
+   pertain to the implementation or use of the technology described in
+   this document or the extent to which any license under such rights
+   might or might not be available; nor does it represent that it has
+   made any independent effort to identify any such rights.  Information
+   on the procedures with respect to rights in RFC documents can be
+   found in BCP 78 and BCP 79.
+
+   Copies of IPR disclosures made to the IETF Secretariat and any
+   assurances of licenses to be made available, or the result of an
+   attempt made to obtain a general license or permission for the use of
+   such proprietary rights by implementers or users of this
+   specification can be obtained from the IETF on-line IPR repository at
+   http://www.ietf.org/ipr.
+
+   The IETF invites any interested party to bring to its attention any
+   copyrights, patents or patent applications, or other proprietary
+   rights that may cover technology that may be required to implement
+   this standard.  Please address the information to the IETF at
+   ietf-ipr@ietf.org.
+
+
+
+
+
+
+
+
+
+
+
+
+Crocker & Overell           Standards Track                    [Page 16]
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/makefile.nt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,76 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+# Program:	IMAP Toolkit Makefile for Windows 9x and Windows NT
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		7 December 1989
+# Last Edited:	30 August 2006
+
+
+COPY=copy
+CD=cd
+MAKE=nmake /nologo /f makefile.nt
+MKDIR=mkdir
+RD=rmdir /s /q
+
+
+# Make the IMAP Toolkit
+
+build:	c-client mtest mailutil imapd ipopd
+	$(CD) c-client
+	$(MAKE)
+	$(CD) ..\mtest
+	$(MAKE)
+	$(CD) ..\mailutil
+	$(MAKE)
+	$(CD) ..\ipopd
+	$(MAKE)
+	$(CD) ..\imapd
+	$(MAKE)
+	$(CD) ..
+
+c-client:
+	$(MKDIR) c-client
+	$(COPY) src\c-client\*.* c-client
+	$(COPY) src\charset\*.* c-client
+	$(COPY) src\osdep\nt\*.* c-client
+
+mtest:
+	$(MKDIR) mtest
+	$(COPY) src\mtest\*.* mtest
+
+mailutil:
+	$(MKDIR) mailutil
+	$(COPY) src\mailutil\*.* mailutil
+
+ipopd:
+	$(MKDIR) ipopd
+	$(COPY) src\ipopd\*.* ipopd
+
+imapd:
+	$(MKDIR) imapd
+	$(COPY) src\imapd\*.* imapd
+
+clean:
+	$(RD) c-client mtest mailutil ipopd imapd
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo 'not war?'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/makefile.ntk	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,76 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+# Program:	IMAP Toolkit Makefile for Windows 9x and Windows NT + Kerberos
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		7 December 1989
+# Last Edited:	30 August 2006
+
+
+COPY=copy
+CD=cd
+MAKE=nmake /nologo /f makefile.ntk
+MKDIR=mkdir
+RD=rmdir /s /q
+
+
+# Make the IMAP Toolkit
+
+build:	c-client mtest mailutil imapd ipopd
+	$(CD) c-client
+	$(MAKE)
+	$(CD) ..\mtest
+	$(MAKE)
+	$(CD) ..\mailutil
+	$(MAKE)
+	$(CD) ..\ipopd
+	$(MAKE)
+	$(CD) ..\imapd
+	$(MAKE)
+	$(CD) ..
+
+c-client:
+	$(MKDIR) c-client
+	$(COPY) src\c-client\*.* c-client
+	$(COPY) src\charset\*.* c-client
+	$(COPY) src\osdep\nt\*.* c-client
+
+mtest:
+	$(MKDIR) mtest
+	$(COPY) src\mtest\*.* mtest
+
+mailutil:
+	$(MKDIR) mailutil
+	$(COPY) src\mailutil\*.* mailutil
+
+ipopd:
+	$(MKDIR) ipopd
+	$(COPY) src\ipopd\*.* ipopd
+
+imapd:
+	$(MKDIR) imapd
+	$(COPY) src\imapd\*.* imapd
+
+clean:
+	$(RD) c-client mtest mailutil ipopd imapd
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo 'not war?'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/makefile.os2	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,59 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+# Program:	IMAP Toolkit Makefile
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		7 December 1989
+# Last Edited:	30 August 2006
+
+
+COPY=copy
+MAKE=make -f makefile.os2
+MKDIR=md
+RD=rm -rf
+
+
+# Make the IMAP Toolkit
+
+build:	c-client mtest mailutil
+	(cd c-client & $(MAKE))
+	(cd mtest & $(MAKE))
+	(cd mailutil & $(MAKE))
+
+c-client:
+	$(MKDIR) c-client
+	$(COPY) src\c-client\\* c-client
+	$(COPY) src\charset\\* c-client
+	$(COPY) src\osdep\os2\\* c-client
+
+mtest:
+	$(MKDIR) mtest
+	$(COPY) src\mtest\\* mtest
+
+mailutil:
+	$(MKDIR) mailutil
+	$(COPY) src\mailutil\\* mailutil
+
+clean:
+	$(RD) c-client mtest mailutil
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo 'not war?'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/makefile.w2k	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,77 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+# Program:	IMAP Toolkit Makefile for Windows 2000/XP
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		7 December 1989
+# Last Edited:	20 August 2006
+
+
+IP=6
+COPY=copy
+CD=cd
+MAKE=nmake /nologo /f makefile.w2k IP=$(IP)
+MKDIR=mkdir
+RD=rmdir /s /q
+
+
+# Make the IMAP Toolkit
+
+build:	c-client mtest mailutil imapd ipopd
+	$(CD) c-client
+	$(MAKE)
+	$(CD) ..\mtest
+	$(MAKE)
+	$(CD) ..\mailutil
+	$(MAKE)
+	$(CD) ..\ipopd
+	$(MAKE)
+	$(CD) ..\imapd
+	$(MAKE)
+	$(CD) ..
+
+c-client:
+	$(MKDIR) c-client
+	$(COPY) src\c-client\*.* c-client
+	$(COPY) src\charset\*.* c-client
+	$(COPY) src\osdep\nt\*.* c-client
+
+mtest:
+	$(MKDIR) mtest
+	$(COPY) src\mtest\*.* mtest
+
+mailutil:
+	$(MKDIR) mailutil
+	$(COPY) src\mailutil\*.* mailutil
+
+ipopd:
+	$(MKDIR) ipopd
+	$(COPY) src\ipopd\*.* ipopd
+
+imapd:
+	$(MKDIR) imapd
+	$(COPY) src\imapd\*.* imapd
+
+clean:
+	$(RD) c-client mtest mailutil ipopd imapd
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo 'not war?'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/makefile.wce	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,64 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+# Program:	IMAP Toolkit Makefile
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		7 December 1989
+# Last Edited:	30 August 2006
+
+
+COPY=copy
+CD=cd
+MAKE=nmake /nologo /f makefile.wce
+MKDIR=mkdir
+RD=rmdir /s /q
+
+
+# Make the IMAP Toolkit
+
+build:	c-client mtest mailutil
+	$(CD) c-client
+	$(MAKE)
+#	$(CD) ..\mtest
+#	$(MAKE)
+#	$(CD) ..\mailutil
+#	$(MAKE)
+	$(CD) ..
+
+c-client:
+	$(MKDIR) c-client
+	$(COPY) src\c-client\*.* c-client
+	$(COPY) src\charset\*.* c-client
+	$(COPY) src\osdep\wce\*.* c-client
+
+mtest:
+	$(MKDIR) mtest
+	$(COPY) src\mtest\*.* mtest
+
+mailutil:
+	$(MKDIR) mailutil
+	$(COPY) src\mailutil\*.* mailutil
+
+clean:
+	$(RD) c-client mtest
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo 'not war?'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ansilib/memmove.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,40 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Memory move
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+ 
+/* Copy memory block
+ * Accepts: destination pointer
+ *	    source pointer
+ *	    length
+ * Returns: destination pointer
+ */
+
+void *memmove (void *s,void *ct,size_t n)
+{
+  bcopy (ct,s,n);		/* they should have this one */
+  return s;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ansilib/memmove2.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,49 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Memory move when no bcopy()
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	30 August 2006
+ */
+
+/* Copy memory block
+ * Accepts: destination pointer
+ *	    source pointer
+ *	    length
+ * Returns: destination pointer
+ */
+
+void *memmove (void *s,void *ct,size_t n)
+{
+  char *dp,*sp;
+  int i;
+  unsigned long dest = (unsigned long) s;
+  unsigned long src = (unsigned long) ct;
+  if (((dest < src) && ((dest + n) < src)) ||
+      ((dest > src) && ((src + n) < dest))) return (void *) memcpy (s,ct,n);
+  dp = (char *) s;
+  sp = (char *) ct;
+  if (dest < src) for (i = 0; i < n; ++i) dp[i] = sp[i];
+  else if (dest > src) for (i = n - 1; i >= 0; --i) dp[i] = sp[i];
+  return s;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ansilib/memset.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,40 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Set memory
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *
+ * Date:	11 May 1989
+ * Last Edited:	30 August 2006
+ */
+
+/* Set a block of memory
+ * Accepts: destination pointer
+ *	    value to set
+ *	    length
+ * Returns: destination pointer
+ */
+
+void *memset (void *s,int c,size_t n)
+{
+  if (c) while (n) s[--n] = c;	/* this way if non-zero */
+  else bzero (s,n);		/* they should have this one */
+  return s;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ansilib/strpbrk.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,40 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	String search for break character
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *
+ * Date:	11 May 1989
+ * Last Edited:	30 August 2006
+ */
+
+/* Return pointer to first occurance in string of any delimiter
+ * Accepts: source pointer
+ *	    vector of delimiters pointer
+ * Returns: pointer to delimiter or NIL if not found
+ */
+
+char *strpbrk (char *cs,char *ct)
+{
+  char *s;
+				/* search for delimiter until end of string */
+  for (; *cs; cs++) for (s = ct; *s; s++) if (*s == *cs) return cs;
+  return NIL;			/* not found */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ansilib/strstr.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,45 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Substring search
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *
+ * Date:	11 May 1989
+ * Last Edited:	30 August 2006
+ */
+
+/* Return pointer to first occurance in string of a substring
+ * Accepts: source pointer
+ *	    substring pointer
+ * Returns: pointer to substring in source or NIL if not found
+ */
+
+char *strstr (char *cs,char *ct)
+{
+  char *s;
+  char *t;
+  while (cs = strchr (cs,*ct)) {/* for each occurance of the first character */
+				/* see if remainder of string matches */
+    for (s = cs + 1, t = ct + 1; *t && *s == *t; s++, t++);
+    if (!*t) return cs;		/* if ran out of substring then have match */
+    cs++;			/* try from next character */
+  }
+  return NIL;			/* not found */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ansilib/strtok.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,67 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	String return successive tokens
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *
+ * Date:	11 May 1989
+ * Last Edited:	30 January 2007
+ */
+
+/* Find token in string
+ * Accepts: source pointer or NIL to use previous source
+ *	    vector of token delimiters pointer
+ * Returns: pointer to next token
+ */
+
+static char *state = NIL;	/* string to locate tokens */
+
+char *strtok (char *s,char *ct)
+{
+  return strtok_r (s,ct,&state);/* jacket into reentrant routine */
+}
+
+
+/* Find token in string (reentrant)
+ * Accepts: source pointer or NIL to use previous source
+ *	    vector of token delimiters pointer
+ *	    returned state pointer
+ * Returns: pointer to next token
+ */
+
+char *strtok_r (char *s,char *ct,char **r)
+{   
+  char *t,*ts;
+  if (!s) s = *r;		/* use previous token if none specified */
+  *r = NIL;			/* default to no returned state */
+  if (!(s && *s)) return NIL;	/* no tokens left */
+				/* find any leading delimiters */
+  do for (t = ct, ts = NIL; *t; t++) if (*t == *s) {
+    if (*(ts = ++s)) break;	/* yes, restart search if more in string */
+    return NIL;			/* else no more tokens */
+  } while (ts);			/* continue until no more leading delimiters */
+				/* can we find a new delimiter? */
+  for (ts = s; *ts; ts++) for (t = ct; *t; t++) if (*t == *ts) {
+    *ts++ = '\0';		/* yes, tie off token at that point */
+    *r = ts;			/* save subsequent tokens for future call */
+    return s;			/* return our token */
+  }
+  return s;			/* return final token */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ansilib/strtoul.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,73 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	String to unsigned long
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *
+ * Date:	14 February 1995
+ * Last Edited:	30 August 2006
+ */
+
+/*
+ * Turn a string unsigned long into the real thing
+ * Accepts: source string
+ *	    pointer to place to return end pointer
+ *	    base
+ * Returns: parsed unsigned long integer, end pointer is updated
+ */
+
+unsigned long strtoul (char *t,char **endp,int base)
+{
+  unsigned long value = 0;	/* the accumulated value */
+  int negative = 0;		/* this a negative number? */
+  unsigned char c,*s = t;
+  if (base && (base < 2 || base > 36)) {
+    errno = EINVAL;		/* insist upon valid base */
+    return value;
+  }
+  while (isspace (*s)) s++;	/* skip leading whitespace */
+  switch (*s) {			/* check for leading sign char */
+  case '-':
+    negative = 1;		/* yes, negative #.  fall into '+' */
+  case '+':
+    s++;			/* skip the sign character */
+  }
+  if (!base) {			/* base not specified? */
+    if (*s != '0') base = 10;	/* must be decimal if doesn't start with 0 */
+				/* starts with 0x? */
+    else if (tolower (*++s) == 'x') {
+      base = 16;		/* yes, is hex */
+      s++;			/* skip the x */
+    }
+    else base = 8;		/* ...or octal */
+  }
+  do {				/* convert to numeric form if digit */
+    if (isdigit (*s)) c = *s - '0';
+				/* alphabetic conversion */
+    else if (isalpha (*s)) c = *s - (isupper (*s) ? 'A' : 'a') + 10;
+    else break;			/* else no way it's valid */
+    if (c >= base) break;	/* digit out of range for base? */
+    value = value * base + c;	/* accumulate the digit */
+  } while (*++s);		/* loop until non-numeric character */
+  if (tolower (*s) == 'l') s++;	/* ignore 'l' or 'L' marker */
+  if (endp) *endp = s;		/* save users endp to after number */
+				/* negate number if needed */
+  return negative ? -value : value;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/auth_ext.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,96 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	EXTERNAL authenticator
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	6 April 2005
+ * Last Edited:	30 August 2006
+ */
+
+long auth_external_client (authchallenge_t challenger,authrespond_t responder,
+			  char *service,NETMBX *mb,void *stream,
+			  unsigned long *trial,char *user);
+char *auth_external_server (authresponse_t responder,int argc,char *argv[]);
+
+AUTHENTICATOR auth_ext = {	/* secure, has full auth, hidden */
+  AU_SECURE | AU_AUTHUSER | AU_HIDE,
+  "EXTERNAL",			/* authenticator name */
+  NIL,				/* always valid */
+  auth_external_client,		/* client method */
+  auth_external_server,		/* server method */
+  NIL				/* next authenticator */
+};
+
+/* Client authenticator
+ * Accepts: challenger function
+ *	   responder function
+ *	   SASL service name
+ *	   parsed network mailbox structure
+ *	   stream argument for functions
+ *	   pointer to current trial count
+ *	   returned user name
+ * Returns: T if success, NIL otherwise, number of trials incremented if retry
+ */
+
+long auth_external_client (authchallenge_t challenger,authrespond_t responder,
+			  char *service,NETMBX *mb,void *stream,
+			  unsigned long *trial,char *user)
+{
+  void *challenge;
+  unsigned long clen;
+  long ret = NIL;
+  *trial = 65535;		/* never retry */
+  if (challenge = (*challenger) (stream,&clen)) {
+    fs_give ((void **) &challenge);
+				/* send authorization id (empty string OK) */
+    if ((*responder) (stream,strcpy (user,mb->user),strlen (mb->user))) {
+      if (challenge = (*challenger) (stream,&clen))
+	fs_give ((void **) &challenge);
+      else ret = LONGT;		/* check the authentication */
+    }
+  }
+  return ret;
+}
+
+
+/* Server authenticator
+ * Accepts: responder function
+ *	    argument count
+ *	    argument vector
+ * Returns: authenticated user name or NIL
+ */
+
+char *auth_external_server (authresponse_t responder,int argc,char *argv[])
+{
+  unsigned long len;
+  char *authid;
+  char *authenid = (char *) mail_parameters (NIL,GET_EXTERNALAUTHID,NIL);
+  char *ret = NIL;
+				/* get authorization identity */
+  if (authenid && (authid = (*responder) ("",0,&len))) {
+				/* note: responders null-terminate */
+    if (*authid ? authserver_login (authid,authenid,argc,argv) :
+	authserver_login (authenid,NIL,argc,argv)) ret = myusername ();
+    fs_give ((void **) &authid);
+  }
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/auth_gss.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,423 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	GSSAPI authenticator
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	12 January 1998
+ * Last Edited:	30 August 2006
+ */
+
+
+long auth_gssapi_valid (void);
+long auth_gssapi_client (authchallenge_t challenger,authrespond_t responder,
+			 char *service,NETMBX *mb,void *stream,
+			 unsigned long *trial,char *user);
+long auth_gssapi_client_work (authchallenge_t challenger,gss_buffer_desc chal,
+			      authrespond_t responder,char *service,NETMBX *mb,
+			      void *stream,char *user,kinit_t ki);
+char *auth_gssapi_server (authresponse_t responder,int argc,char *argv[]);
+
+
+AUTHENTICATOR auth_gss = {
+  AU_SECURE | AU_AUTHUSER,	/* secure authenticator */
+  "GSSAPI",			/* authenticator name */
+  auth_gssapi_valid,		/* check if valid */
+  auth_gssapi_client,		/* client method */
+  auth_gssapi_server,		/* server method */
+  NIL				/* next authenticator */
+};
+
+#define AUTH_GSSAPI_P_NONE 1
+#define AUTH_GSSAPI_P_INTEGRITY 2
+#define AUTH_GSSAPI_P_PRIVACY 4
+
+#define AUTH_GSSAPI_C_MAXSIZE 8192
+
+#define SERVER_LOG(x,y) syslog (LOG_ALERT,x,y)
+
+/* Check if GSSAPI valid on this system
+ * Returns: T if valid, NIL otherwise
+ */
+
+long auth_gssapi_valid (void)
+{
+  char tmp[MAILTMPLEN];
+  OM_uint32 smn;
+  gss_buffer_desc buf;
+  gss_name_t name;
+				/* make service name */
+  sprintf (tmp,"%s@%s",(char *) mail_parameters (NIL,GET_SERVICENAME,NIL),
+	   mylocalhost ());
+  buf.length = strlen (buf.value = tmp);
+				/* see if can build a name */
+  if (gss_import_name (&smn,&buf,GSS_C_NT_HOSTBASED_SERVICE,&name) !=
+      GSS_S_COMPLETE) return NIL;
+				/* remove server method if no keytab */
+  if (!kerberos_server_valid ()) auth_gss.server = NIL;
+  gss_release_name (&smn,&name);/* finished with name */
+  return LONGT;
+}
+
+/* Client authenticator
+ * Accepts: challenger function
+ *	    responder function
+ *	    SASL service name
+ *	    parsed network mailbox structure
+ *	    stream argument for functions
+ *	    pointer to current trial count
+ *	    returned user name
+ * Returns: T if success, NIL otherwise, number of trials incremented if retry
+ */
+
+long auth_gssapi_client (authchallenge_t challenger,authrespond_t responder,
+			 char *service,NETMBX *mb,void *stream,
+			 unsigned long *trial,char *user)
+{
+  gss_buffer_desc chal;
+  kinit_t ki = (kinit_t) mail_parameters (NIL,GET_KINIT,NIL);
+  long ret = NIL;
+  *trial = 65535;		/* never retry */
+				/* get initial (empty) challenge */
+  if (chal.value = (*challenger) (stream,(unsigned long *) &chal.length)) {
+    if (chal.length) {		/* abort if challenge non-empty */
+      mm_log ("Server bug: non-empty initial GSSAPI challenge",WARN);
+      (*responder) (stream,NIL,0);
+      ret = LONGT;		/* will get a BAD response back */
+    }
+    else if (mb->authuser[0] && strcmp (mb->authuser,myusername ())) {
+      mm_log ("Can't use Kerberos: invalid /authuser",WARN);
+      (*responder) (stream,NIL,0);
+      ret = LONGT;		/* will get a BAD response back */
+    }
+    else ret = auth_gssapi_client_work (challenger,chal,responder,service,mb,
+					stream,user,ki);
+  }
+  return ret;
+}
+
+/* Client authenticator worker function
+ * Accepts: challenger function
+ *	    responder function
+ *	    SASL service name
+ *	    parsed network mailbox structure
+ *	    stream argument for functions
+ *	    returned user name
+ *	    kinit function pointer if should retry with kinit
+ * Returns: T if success, NIL otherwise
+ */
+
+long auth_gssapi_client_work (authchallenge_t challenger,gss_buffer_desc chal,
+			      authrespond_t responder,char *service,NETMBX *mb,
+			      void *stream,char *user,kinit_t ki)
+{
+  char tmp[MAILTMPLEN];
+  OM_uint32 smj,smn,dsmj,dsmn;
+  OM_uint32 mctx = 0;
+  gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
+  gss_buffer_desc resp,buf;
+  long i;
+  int conf;
+  gss_qop_t qop;
+  gss_name_t crname = NIL;
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  void *data;
+  long ret = NIL;
+  sprintf (tmp,"%s@%s",service,mb->host);
+  buf.length = strlen (buf.value = tmp);
+				/* get service name */
+  if (gss_import_name (&smn,&buf,GSS_C_NT_HOSTBASED_SERVICE,&crname) !=
+       GSS_S_COMPLETE) {
+    mm_log ("Can't import Kerberos service name",WARN);
+    (*responder) (stream,NIL,0);
+  }
+  else {
+    data = (*bn) (BLOCK_SENSITIVE,NIL);
+				/* negotiate with KDC */
+    smj = gss_init_sec_context (&smn,GSS_C_NO_CREDENTIAL,&ctx,crname,NIL,
+				GSS_C_INTEG_FLAG | GSS_C_MUTUAL_FLAG |
+				GSS_C_REPLAY_FLAG,0,GSS_C_NO_CHANNEL_BINDINGS,
+				GSS_C_NO_BUFFER,NIL,&resp,NIL,NIL);
+    (*bn) (BLOCK_NONSENSITIVE,data);
+
+				/* while continuation needed */
+    while (smj == GSS_S_CONTINUE_NEEDED) {
+      if (chal.value) fs_give ((void **) &chal.value);
+				/* send response, get next challenge */
+      i = (*responder) (stream,resp.value,resp.length) &&
+	(chal.value = (*challenger) (stream,(unsigned long *) &chal.length));
+      gss_release_buffer (&smn,&resp);
+      if (i) {			/* negotiate continuation with KDC */
+	data = (*bn) (BLOCK_SENSITIVE,NIL);
+	switch (smj =		/* make sure continuation going OK */
+		gss_init_sec_context (&smn,GSS_C_NO_CREDENTIAL,&ctx,
+				      crname,GSS_C_NO_OID,GSS_C_INTEG_FLAG |
+				      GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,0,
+				      GSS_C_NO_CHANNEL_BINDINGS,&chal,NIL,
+				      &resp,NIL,NIL)) {
+	case GSS_S_CONTINUE_NEEDED:
+	case GSS_S_COMPLETE:
+	  break;
+	default:		/* error, don't need context any more */
+	  gss_delete_sec_context (&smn,&ctx,NIL);
+	}
+	(*bn) (BLOCK_NONSENSITIVE,data);
+      }
+      else {			/* error in continuation */
+	mm_log ("Error in negotiating Kerberos continuation",WARN);
+	(*responder) (stream,NIL,0);
+				/* don't need context any more */
+	gss_delete_sec_context (&smn,&ctx,NIL);
+	break;
+      }
+    }
+
+    switch (smj) {		/* done - deal with final condition */
+    case GSS_S_COMPLETE:
+      if (chal.value) fs_give ((void **) &chal.value);
+				/* get prot mechanisms and max size */
+      if ((*responder) (stream,resp.value ? resp.value : "",resp.length) &&
+	  (chal.value = (*challenger) (stream,(unsigned long *)&chal.length))&&
+	  (gss_unwrap (&smn,ctx,&chal,&resp,&conf,&qop) == GSS_S_COMPLETE) &&
+	  (resp.length >= 4) && (*((char *) resp.value) & AUTH_GSSAPI_P_NONE)){
+				/* make copy of flags and length */
+	memcpy (tmp,resp.value,4);
+	gss_release_buffer (&smn,&resp);
+				/* no session protection */
+	tmp[0] = AUTH_GSSAPI_P_NONE;
+				/* install user name */
+	strcpy (tmp+4,strcpy (user,mb->user[0] ? mb->user : myusername ()));
+	buf.value = tmp; buf.length = strlen (user) + 4;
+				/* successful negotiation */
+	switch (smj = gss_wrap (&smn,ctx,NIL,qop,&buf,&conf,&resp)) {
+	case GSS_S_COMPLETE:
+	  if ((*responder) (stream,resp.value,resp.length)) ret = T;
+	  gss_release_buffer (&smn,&resp);
+	  break;
+	default:
+	  do switch (dsmj = gss_display_status (&dsmn,smj,GSS_C_GSS_CODE,
+						GSS_C_NO_OID,&mctx,&resp)) {
+	  case GSS_S_COMPLETE:
+	    mctx = 0;
+	  case GSS_S_CONTINUE_NEEDED:
+	    sprintf (tmp,"Unknown gss_wrap failure: %s",(char *) resp.value);
+	    mm_log (tmp,WARN);
+	    gss_release_buffer (&dsmn,&resp);
+	  }
+	  while (dsmj == GSS_S_CONTINUE_NEEDED);
+	  do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE,
+						GSS_C_NO_OID,&mctx,&resp)) {
+	  case GSS_S_COMPLETE:
+	  case GSS_S_CONTINUE_NEEDED:
+	    sprintf (tmp,"GSSAPI mechanism status: %s",(char *) resp.value);
+	    mm_log (tmp,WARN);
+	    gss_release_buffer (&dsmn,&resp);
+	  }
+	  while (dsmj == GSS_S_CONTINUE_NEEDED);
+	  (*responder) (stream,NIL,0);
+	}
+      }
+				/* flush final challenge */
+      if (chal.value) fs_give ((void **) &chal.value);
+				/* don't need context any more */
+      gss_delete_sec_context (&smn,&ctx,NIL);
+      break;
+
+    case GSS_S_CREDENTIALS_EXPIRED:
+      if (chal.value) fs_give ((void **) &chal.value);
+				/* retry if application kinits */
+      if (ki && (*ki) (mb->host,"Kerberos credentials expired"))
+	ret = auth_gssapi_client_work (challenger,chal,responder,service,mb,
+				       stream,user,NIL);
+      else {			/* application can't kinit */
+	sprintf (tmp,"Kerberos credentials expired (try running kinit) for %s",
+		 mb->host);
+	mm_log (tmp,WARN);
+	(*responder) (stream,NIL,0);
+      }
+      break;
+    case GSS_S_FAILURE:
+      if (chal.value) fs_give ((void **) &chal.value);
+      do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE,
+					    GSS_C_NO_OID,&mctx,&resp)) {
+      case GSS_S_COMPLETE:	/* end of message, can kinit? */
+	if (ki && kerberos_try_kinit (smn) &&
+	    (*ki) (mb->host,(char *) resp.value)) {
+	  gss_release_buffer (&dsmn,&resp);
+	  ret = auth_gssapi_client_work (challenger,chal,responder,service,mb,
+					 stream,user,NIL);
+	  break;		/* done */
+	}
+	else (*responder) (stream,NIL,0);
+      case GSS_S_CONTINUE_NEEDED:
+	sprintf (tmp,kerberos_try_kinit (smn) ?
+		 "Kerberos error: %.80s (try running kinit) for %.80s" :
+		 "GSSAPI failure: %s for %.80s",(char *) resp.value,mb->host);
+	mm_log (tmp,WARN);
+	gss_release_buffer (&dsmn,&resp);
+      } while (dsmj == GSS_S_CONTINUE_NEEDED);
+      break;
+
+    default:			/* miscellaneous errors */
+      if (chal.value) fs_give ((void **) &chal.value);
+      do switch (dsmj = gss_display_status (&dsmn,smj,GSS_C_GSS_CODE,
+					    GSS_C_NO_OID,&mctx,&resp)) {
+      case GSS_S_COMPLETE:
+	mctx = 0;
+      case GSS_S_CONTINUE_NEEDED:
+	sprintf (tmp,"Unknown GSSAPI failure: %s",(char *) resp.value);
+	mm_log (tmp,WARN);
+	gss_release_buffer (&dsmn,&resp);
+      }
+      while (dsmj == GSS_S_CONTINUE_NEEDED);
+      do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE,
+					    GSS_C_NO_OID,&mctx,&resp)) {
+      case GSS_S_COMPLETE:
+      case GSS_S_CONTINUE_NEEDED:
+	sprintf (tmp,"GSSAPI mechanism status: %s",(char *) resp.value);
+	mm_log (tmp,WARN);
+	gss_release_buffer (&dsmn,&resp);
+      }
+      while (dsmj == GSS_S_CONTINUE_NEEDED);
+      (*responder) (stream,NIL,0);
+      break;
+    }
+				/* finished with credentials name */
+    if (crname) gss_release_name (&smn,&crname);
+  }
+  return ret;			/* return status */
+}
+
+/* Server authenticator
+ * Accepts: responder function
+ *	    argument count
+ *	    argument vector
+ * Returns: authenticated user name or NIL
+ */
+
+char *auth_gssapi_server (authresponse_t responder,int argc,char *argv[])
+{
+  char *ret = NIL;
+  char tmp[MAILTMPLEN];
+  unsigned long maxsize = htonl (AUTH_GSSAPI_C_MAXSIZE);
+  int conf;
+  OM_uint32 smj,smn,dsmj,dsmn,flags;
+  OM_uint32 mctx = 0;
+  gss_name_t crname,name;
+  gss_OID mech;
+  gss_buffer_desc chal,resp,buf;
+  gss_cred_id_t crd;
+  gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
+  gss_qop_t qop = GSS_C_QOP_DEFAULT;
+				/* make service name */
+  sprintf (tmp,"%s@%s",(char *) mail_parameters (NIL,GET_SERVICENAME,NIL),
+	   tcp_serverhost ());
+  buf.length = strlen (buf.value = tmp);
+				/* acquire credentials */
+  if ((gss_import_name (&smn,&buf,GSS_C_NT_HOSTBASED_SERVICE,&crname)) ==
+      GSS_S_COMPLETE) {
+    if ((smj = gss_acquire_cred (&smn,crname,0,NIL,GSS_C_ACCEPT,&crd,NIL,NIL))
+	== GSS_S_COMPLETE) {
+      if (resp.value = (*responder) ("",0,(unsigned long *) &resp.length)) {
+	do {			/* negotiate authentication */
+	  smj = gss_accept_sec_context (&smn,&ctx,crd,&resp,
+					GSS_C_NO_CHANNEL_BINDINGS,&name,&mech,
+					&chal,&flags,NIL,NIL);
+				/* don't need response any more */
+	  fs_give ((void **) &resp.value);
+	  switch (smj) {	/* how did it go? */
+	  case GSS_S_COMPLETE:	/* successful */
+	  case GSS_S_CONTINUE_NEEDED:
+	    if (chal.value) {	/* send challenge, get next response */
+	      resp.value = (*responder) (chal.value,chal.length,
+					 (unsigned long *) &resp.length);
+	      gss_release_buffer (&smn,&chal);
+	    }
+	    break;
+	  }
+	}
+	while (resp.value && resp.length && (smj == GSS_S_CONTINUE_NEEDED));
+
+				/* successful exchange? */
+	if ((smj == GSS_S_COMPLETE) &&
+	    (gss_display_name (&smn,name,&buf,&mech) == GSS_S_COMPLETE)) {
+				/* send security and size */
+	  memcpy (resp.value = tmp,(void *) &maxsize,resp.length = 4);
+	  tmp[0] = AUTH_GSSAPI_P_NONE;
+	  if (gss_wrap (&smn,ctx,NIL,qop,&resp,&conf,&chal) == GSS_S_COMPLETE){
+	    resp.value = (*responder) (chal.value,chal.length,
+				       (unsigned long *) &resp.length);
+	    gss_release_buffer (&smn,&chal);
+	    if (gss_unwrap (&smn,ctx,&resp,&chal,&conf,&qop)==GSS_S_COMPLETE) {
+				/* client request valid */
+	      if (chal.value && (chal.length > 4) &&
+		  (chal.length < (MAILTMPLEN - 1)) &&
+		  memcpy (tmp,chal.value,chal.length) &&
+		  (tmp[0] & AUTH_GSSAPI_P_NONE)) {
+				/* tie off authorization ID */
+		tmp[chal.length] = '\0';
+		ret = kerberos_login (tmp+4,buf.value,argc,argv);
+	      }
+				/* done with user name */
+	      gss_release_buffer (&smn,&chal);
+	    }
+				/* finished with response */
+	    fs_give ((void **) &resp.value);
+	  }
+				/* don't need name buffer any more */
+	  gss_release_buffer (&smn,&buf);
+	}
+				/* don't need client name any more */
+	gss_release_name (&smn,&name);
+				/* don't need context any more */
+	if (ctx != GSS_C_NO_CONTEXT) gss_delete_sec_context (&smn,&ctx,NIL);
+      }
+				/* finished with credentials */
+      gss_release_cred (&smn,&crd);
+    }
+
+    else {			/* can't acquire credentials! */
+      if (gss_display_name (&dsmn,crname,&buf,&mech) == GSS_S_COMPLETE)
+	SERVER_LOG ("Failed to acquire credentials for %s",buf.value);
+      if (smj != GSS_S_FAILURE) do
+	switch (dsmj = gss_display_status (&dsmn,smj,GSS_C_GSS_CODE,
+					   GSS_C_NO_OID,&mctx,&resp)) {
+	case GSS_S_COMPLETE:
+	  mctx = 0;
+	case GSS_S_CONTINUE_NEEDED:
+	  SERVER_LOG ("Unknown GSSAPI failure: %s",resp.value);
+	  gss_release_buffer (&dsmn,&resp);
+	}
+      while (dsmj == GSS_S_CONTINUE_NEEDED);
+      do switch (dsmj = gss_display_status (&dsmn,smn,GSS_C_MECH_CODE,
+					    GSS_C_NO_OID,&mctx,&resp)) {
+      case GSS_S_COMPLETE:
+      case GSS_S_CONTINUE_NEEDED:
+	SERVER_LOG ("GSSAPI mechanism status: %s",resp.value);
+	gss_release_buffer (&dsmn,&resp);
+      }
+      while (dsmj == GSS_S_CONTINUE_NEEDED);
+    }
+				/* finished with credentials name */
+    gss_release_name (&smn,&crname);
+  }
+  return ret;			/* return status */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/auth_log.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,117 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Login authenticator
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	5 December 1995
+ * Last Edited:	30 August 2006
+ */
+
+long auth_login_client (authchallenge_t challenger,authrespond_t responder,
+			char *service,NETMBX *mb,void *stream,
+			unsigned long *trial,char *user);
+char *auth_login_server (authresponse_t responder,int argc,char *argv[]);
+
+AUTHENTICATOR auth_log = {
+  AU_HIDE,			/* hidden */
+  "LOGIN",			/* authenticator name */
+  NIL,				/* always valid */
+  auth_login_client,		/* client method */
+  auth_login_server,		/* server method */
+  NIL				/* next authenticator */
+};
+
+#define PWD_USER "User Name"
+#define PWD_PWD "Password"
+
+/* Client authenticator
+ * Accepts: challenger function
+ *	    responder function
+ *	    SASL service name
+ *	    parsed network mailbox structure
+ *	    stream argument for functions
+ *	    pointer to current trial count
+ *	    returned user name
+ * Returns: T if success, NIL otherwise, number of trials incremented if retry
+ */
+
+long auth_login_client (authchallenge_t challenger,authrespond_t responder,
+			char *service,NETMBX *mb,void *stream,
+			unsigned long *trial,char *user)
+{
+  char pwd[MAILTMPLEN];
+  void *challenge;
+  unsigned long clen;
+  long ret = NIL;
+				/* get user name prompt */
+  if (challenge = (*challenger) (stream,&clen)) {
+    fs_give ((void **) &challenge);
+    pwd[0] = NIL;		/* prompt user */
+    mm_login (mb,user,pwd,*trial);
+    if (!pwd[0]) {		/* user requested abort */
+      (*responder) (stream,NIL,0);
+      *trial = 0;		/* cancel subsequent attempts */
+      ret = LONGT;		/* will get a BAD response back */
+    }
+				/* send user name */
+    else if ((*responder) (stream,user,strlen (user)) &&
+	     (challenge = (*challenger) (stream,&clen))) {
+      fs_give ((void **) &challenge);
+				/* send password */
+      if ((*responder) (stream,pwd,strlen (pwd))) {
+	if (challenge = (*challenger) (stream,&clen))
+	  fs_give ((void **) &challenge);
+	else {
+	  ++*trial;		/* can try again if necessary */
+	  ret = LONGT;		/* check the authentication */
+	}
+      }
+    }
+  }
+  memset (pwd,0,MAILTMPLEN);	/* erase password */
+  if (!ret) *trial = 65535;	/* don't retry if bad protocol */
+  return ret;
+}
+
+
+/* Server authenticator
+ * Accepts: responder function
+ *	    argument count
+ *	    argument vector
+ * Returns: authenticated user name or NIL
+ */
+
+char *auth_login_server (authresponse_t responder,int argc,char *argv[])
+{
+  char *ret = NIL;
+  char *user,*pass,*authuser;
+  if (user = (*responder) (PWD_USER,sizeof (PWD_USER),NIL)) {
+    if (pass = (*responder) (PWD_PWD,sizeof (PWD_PWD),NIL)) {
+				/* delimit user from possible admin */
+      if (authuser = strchr (user,'*')) *authuser++ = '\0';
+      if (server_login (user,pass,authuser,argc,argv)) ret = myusername ();
+      fs_give ((void **) &pass);
+    }
+    fs_give ((void **) &user);
+  }
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/auth_md5.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,495 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	CRAM-MD5 authenticator
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	21 October 1998
+ * Last Edited:	30 January 2007
+ */
+
+/* MD5 context */
+
+#define MD5BLKLEN 64		/* MD5 block length */
+#define MD5DIGLEN 16		/* MD5 digest length */
+
+typedef struct {
+  unsigned long chigh;		/* high 32bits of byte count */
+  unsigned long clow;		/* low 32bits of byte count */
+  unsigned long state[4];	/* state (ABCD) */
+  unsigned char buf[MD5BLKLEN];	/* input buffer */
+  unsigned char *ptr;		/* buffer position */
+} MD5CONTEXT;
+
+
+/* Prototypes */
+
+long auth_md5_valid (void);
+long auth_md5_client (authchallenge_t challenger,authrespond_t responder,
+		      char *service,NETMBX *mb,void *stream,
+		      unsigned long *trial,char *user);
+char *auth_md5_server (authresponse_t responder,int argc,char *argv[]);
+char *auth_md5_pwd (char *user);
+char *apop_login (char *chal,char *user,char *md5,int argc,char *argv[]);
+char *hmac_md5 (char *text,unsigned long tl,char *key,unsigned long kl);
+void md5_init (MD5CONTEXT *ctx);
+void md5_update (MD5CONTEXT *ctx,unsigned char *data,unsigned long len);
+void md5_final (unsigned char *digest,MD5CONTEXT *ctx);
+static void md5_transform (unsigned long *state,unsigned char *block);
+static void md5_encode (unsigned char *dst,unsigned long *src,int len);
+static void md5_decode (unsigned long *dst,unsigned char *src,int len);
+
+
+/* Authenticator linkage */
+
+AUTHENTICATOR auth_md5 = {
+  AU_SECURE,			/* secure authenticator */
+  "CRAM-MD5",			/* authenticator name */
+  auth_md5_valid,		/* check if valid */
+  auth_md5_client,		/* client method */
+  auth_md5_server,		/* server method */
+  NIL				/* next authenticator */
+};
+
+/* Check if CRAM-MD5 valid on this system
+ * Returns: T, always
+ */
+
+long auth_md5_valid (void)
+{
+  struct stat sbuf;
+				/* server forbids MD5 if no MD5 enable file */
+  if (stat (MD5ENABLE,&sbuf)) auth_md5.server = NIL;
+  return T;			/* MD5 is otherwise valid */
+}
+
+
+/* Client authenticator
+ * Accepts: challenger function
+ *	    responder function
+ *	    SASL service name
+ *	    parsed network mailbox structure
+ *	    stream argument for functions
+ *	    pointer to current trial count
+ *	    returned user name
+ * Returns: T if success, NIL otherwise, number of trials incremented if retry
+ */
+
+long auth_md5_client (authchallenge_t challenger,authrespond_t responder,
+		      char *service,NETMBX *mb,void *stream,
+		      unsigned long *trial,char *user)
+{
+  char pwd[MAILTMPLEN];
+  void *challenge;
+  unsigned long clen;
+  long ret = NIL;
+				/* get challenge */
+  if (challenge = (*challenger) (stream,&clen)) {
+    pwd[0] = NIL;		/* prompt user */
+    mm_login (mb,user,pwd,*trial);
+    if (!pwd[0]) {		/* user requested abort */
+      fs_give ((void **) &challenge);
+      (*responder) (stream,NIL,0);
+      *trial = 0;		/* cancel subsequent attempts */
+      ret = LONGT;		/* will get a BAD response back */
+    }
+    else {			/* got password, build response */
+      sprintf (pwd,"%.65s %.33s",user,hmac_md5 (challenge,clen,
+						pwd,strlen (pwd)));
+      fs_give ((void **) &challenge);
+				/* send credentials, allow retry if OK */
+      if ((*responder) (stream,pwd,strlen (pwd))) {
+	if (challenge = (*challenger) (stream,&clen))
+	  fs_give ((void **) &challenge);
+	else {
+	  ++*trial;		/* can try again if necessary */
+	  ret = LONGT;		/* check the authentication */
+	}
+      }
+    }
+  }
+  memset (pwd,0,MAILTMPLEN);	/* erase password in case not overwritten */
+  if (!ret) *trial = 65535;	/* don't retry if bad protocol */
+  return ret;
+}
+
+/* Server authenticator
+ * Accepts: responder function
+ *	    argument count
+ *	    argument vector
+ * Returns: authenticated user name or NIL
+ *
+ * This is much hairier than it needs to be due to the necessary of zapping
+ * the password data.
+ */
+
+static int md5try = MAXLOGINTRIALS;
+
+char *auth_md5_server (authresponse_t responder,int argc,char *argv[])
+{
+  char *ret = NIL;
+  char *p,*u,*user,*authuser,*hash,chal[MAILTMPLEN];
+  unsigned long cl,pl;
+				/* generate challenge */
+  sprintf (chal,"<%lu.%lu@%s>",(unsigned long) getpid (),
+	   (unsigned long) time (0),mylocalhost ());
+				/* send challenge, get user and hash */
+  if (user = (*responder) (chal,cl = strlen (chal),NIL)) {
+				/* got user, locate hash */
+    if (hash = strrchr (user,' ')) {
+      *hash++ = '\0';		/* tie off user */
+				/* see if authentication user */
+      if (authuser = strchr (user,'*')) *authuser++ = '\0';
+				/* get password */
+      if (p = auth_md5_pwd ((authuser && *authuser) ? authuser : user)) {
+	pl = strlen (p);
+	u = (md5try && !strcmp (hash,hmac_md5 (chal,cl,p,pl))) ? user : NIL;
+	memset (p,0,pl);	/* erase sensitive information */
+	fs_give ((void **) &p);	/* flush erased password */
+				/* now log in for real */
+	if (u && authserver_login (u,authuser,argc,argv)) ret = myusername ();
+	else if (md5try) --md5try;
+      }
+    }
+    fs_give ((void **) &user);
+  }
+  if (!ret) sleep (3);		/* slow down possible cracker */
+  return ret;
+}
+
+/* Return MD5 password for user
+ * Accepts: user name
+ * Returns: plaintext password if success, else NIL
+ *
+ * This is much hairier than it needs to be due to the necessary of zapping
+ * the password data.  That's why we don't use stdio here.
+ */
+
+char *auth_md5_pwd (char *user)
+{
+  struct stat sbuf;
+  int fd = open (MD5ENABLE,O_RDONLY,NIL);
+  unsigned char *s,*t,*buf,*lusr,*lret;
+  char *r;
+  char *ret = NIL;
+  if (fd >= 0) {		/* found the file? */
+    fstat (fd,&sbuf);		/* yes, slurp it into memory */
+    read (fd,buf = (char *) fs_get (sbuf.st_size + 1),sbuf.st_size);
+				/* see if any uppercase characters in user */
+    for (s = user; *s && ((*s < 'A') || (*s > 'Z')); s++);
+				/* yes, make lowercase copy */
+    lusr = *s ? lcase (cpystr (user)) : NIL;
+    for (s = strtok_r ((char *) buf,"\015\012",&r),lret = NIL; s;
+	 s = ret ? NIL : strtok_r (NIL,"\015\012",&r))
+				/* must be valid entry line */
+      if (*s && (*s != '#') && (t = strchr (s,'\t')) && t[1]) {
+	*t++ = '\0';		/* found tab, tie off user, point to pwd */
+	if (!strcmp (s,user)) ret = cpystr (t);
+	else if (lusr && !lret) if (!strcmp (s,lusr)) lret = t;
+      }
+				/* accept case-independent name */
+    if (!ret && lret) ret = cpystr (lret);
+				/* don't need lowercase copy any more */
+    if (lusr) fs_give ((void **) &lusr);
+				/* erase sensitive information from buffer */
+    memset (buf,0,sbuf.st_size + 1);
+    fs_give ((void **) &buf);	/* flush the buffer */
+    close (fd);			/* don't need file any longer */
+  }
+  return ret;			/* return password */
+}
+
+/* APOP server login
+ * Accepts: challenge
+ *	    desired user name
+ *	    purported MD5
+ *	    argument count
+ *	    argument vector
+ * Returns: authenticated user name or NIL
+ */
+
+char *apop_login (char *chal,char *user,char *md5,int argc,char *argv[])
+{
+  int i,j;
+  char *ret = NIL;
+  char *s,*authuser,tmp[MAILTMPLEN];
+  unsigned char digest[MD5DIGLEN];
+  MD5CONTEXT ctx;
+  char *hex = "0123456789abcdef";
+				/* see if authentication user */
+  if (authuser = strchr (user,'*')) *authuser++ = '\0';
+				/* get password */
+  if (s = auth_md5_pwd ((authuser && *authuser) ? authuser : user)) {
+    md5_init (&ctx);		/* initialize MD5 context */
+				/* build string to get MD5 digest */
+    sprintf (tmp,"%.128s%.128s",chal,s);
+    memset (s,0,strlen (s));	/* erase sensitive information */
+    fs_give ((void **) &s);	/* flush erased password */
+    md5_update (&ctx,(unsigned char *) tmp,strlen (tmp));
+    memset (tmp,0,MAILTMPLEN);	/* erase sensitive information */
+    md5_final (digest,&ctx);
+				/* convert to printable hex */
+    for (i = 0, s = tmp; i < MD5DIGLEN; i++) {
+      *s++ = hex[(j = digest[i]) >> 4];
+      *s++ = hex[j & 0xf];
+    }
+    *s = '\0';			/* tie off hash text */
+    memset (digest,0,MD5DIGLEN);/* erase sensitive information */
+    if (md5try && !strcmp (md5,tmp) &&
+	authserver_login (user,authuser,argc,argv))
+      ret = cpystr (myusername ());
+    else if (md5try) --md5try;
+    memset (tmp,0,MAILTMPLEN);	/* erase sensitive information */
+  }
+  if (!ret) sleep (3);		/* slow down possible cracker */
+  return ret;
+}
+
+/*
+ * RFC 2104 HMAC hashing
+ * Accepts: text to hash
+ *	    text length
+ *	    key
+ *	    key length
+ * Returns: hash as text, always
+ */
+
+char *hmac_md5 (char *text,unsigned long tl,char *key,unsigned long kl)
+{
+  int i,j;
+  static char hshbuf[2*MD5DIGLEN + 1];
+  char *s;
+  MD5CONTEXT ctx;
+  char *hex = "0123456789abcdef";
+  unsigned char digest[MD5DIGLEN],k_ipad[MD5BLKLEN+1],k_opad[MD5BLKLEN+1];
+  if (kl > MD5BLKLEN) {		/* key longer than pad length? */
+    md5_init (&ctx);		/* yes, set key as MD5(key) */
+    md5_update (&ctx,(unsigned char *) key,kl);
+    md5_final (digest,&ctx);
+    key = (char *) digest;
+    kl = MD5DIGLEN;
+  }
+  memcpy (k_ipad,key,kl);	/* store key in pads */
+  memset (k_ipad+kl,0,(MD5BLKLEN+1)-kl);
+  memcpy (k_opad,k_ipad,MD5BLKLEN+1);
+				/* XOR key with ipad and opad values */
+  for (i = 0; i < MD5BLKLEN; i++) {
+    k_ipad[i] ^= 0x36;
+    k_opad[i] ^= 0x5c;
+  }
+  md5_init (&ctx);		/* inner MD5: hash ipad and text */
+  md5_update (&ctx,k_ipad,MD5BLKLEN);
+  md5_update (&ctx,(unsigned char *) text,tl);
+  md5_final (digest,&ctx);
+  md5_init (&ctx);		/* outer MD5: hash opad and inner results */
+  md5_update (&ctx,k_opad,MD5BLKLEN);
+  md5_update (&ctx,digest,MD5DIGLEN);
+  md5_final (digest,&ctx);
+				/* convert to printable hex */
+  for (i = 0, s = hshbuf; i < MD5DIGLEN; i++) {
+    *s++ = hex[(j = digest[i]) >> 4];
+    *s++ = hex[j & 0xf];
+  }
+  *s = '\0';			/* tie off hash text */
+  return hshbuf;
+}
+
+/* Everything after this point is derived from the RSA Data Security, Inc.
+ * MD5 Message-Digest Algorithm
+ */
+
+/* You may wonder why these strange "a &= 0xffffffff;" statements are here.
+ * This is to ensure correct results on machines with a unsigned long size of
+ * larger than 32 bits.
+ */
+
+#define RND1(a,b,c,d,x,s,ac) \
+ a += ((b & c) | (d & ~b)) + x + (unsigned long) ac; \
+ a &= 0xffffffff; \
+ a = b + ((a << s) | (a >> (32 - s)));
+
+#define RND2(a,b,c,d,x,s,ac) \
+ a += ((b & d) | (c & ~d)) + x + (unsigned long) ac; \
+ a &= 0xffffffff; \
+ a = b + ((a << s) | (a >> (32 - s)));
+
+#define RND3(a,b,c,d,x,s,ac) \
+ a += (b ^ c ^ d) + x + (unsigned long) ac; \
+ a &= 0xffffffff; \
+ a = b + ((a << s) | (a >> (32 - s)));
+
+#define RND4(a,b,c,d,x,s,ac) \
+ a += (c ^ (b | ~d)) + x + (unsigned long) ac; \
+ a &= 0xffffffff; \
+ a = b + ((a << s) | (a >> (32 - s)));
+
+/* Initialize MD5 context
+ * Accepts: context to initialize
+ */
+
+void md5_init (MD5CONTEXT *ctx)
+{
+  ctx->clow = ctx->chigh = 0;	/* initialize byte count to zero */
+				/* initialization constants */
+  ctx->state[0] = 0x67452301; ctx->state[1] = 0xefcdab89;
+  ctx->state[2] = 0x98badcfe; ctx->state[3] = 0x10325476;
+  ctx->ptr = ctx->buf;		/* reset buffer pointer */
+}
+
+
+/* MD5 add data to context
+ * Accepts: context
+ *	    input data
+ *	    length of data
+ */
+
+void md5_update (MD5CONTEXT *ctx,unsigned char *data,unsigned long len)
+{
+  unsigned long i = (ctx->buf + MD5BLKLEN) - ctx->ptr;
+				/* update double precision number of bytes */
+  if ((ctx->clow += len) < len) ctx->chigh++;
+  while (i <= len) {		/* copy/transform data, 64 bytes at a time */
+    memcpy (ctx->ptr,data,i);	/* fill up 64 byte chunk */
+    md5_transform (ctx->state,ctx->ptr = ctx->buf);
+    data += i,len -= i,i = MD5BLKLEN;
+  }
+  memcpy (ctx->ptr,data,len);	/* copy final bit of data in buffer */
+  ctx->ptr += len;		/* update buffer pointer */
+}
+
+/* MD5 Finalization
+ * Accepts: destination digest
+ *	    context
+ */
+
+void md5_final (unsigned char *digest,MD5CONTEXT *ctx)
+{
+  unsigned long i,bits[2];
+  bits[0] = ctx->clow << 3;	/* calculate length in bits (before padding) */
+  bits[1] = (ctx->chigh << 3) + (ctx->clow >> 29);
+  *ctx->ptr++ = 0x80;		/* padding byte */
+  if ((i = (ctx->buf + MD5BLKLEN) - ctx->ptr) < 8) {
+    memset (ctx->ptr,0,i);	/* pad out buffer with zeros */
+    md5_transform (ctx->state,ctx->buf);
+				/* pad out with zeros, leaving 8 bytes */
+    memset (ctx->buf,0,MD5BLKLEN - 8);
+    ctx->ptr = ctx->buf + MD5BLKLEN - 8;
+  }
+  else if (i -= 8) {		/* need to pad this buffer? */
+    memset (ctx->ptr,0,i);	/* yes, pad out with zeros, leaving 8 bytes */
+    ctx->ptr += i;
+  }
+  md5_encode (ctx->ptr,bits,2);	/* make LSB-first length */
+  md5_transform (ctx->state,ctx->buf);
+				/* store state in digest */
+  md5_encode (digest,ctx->state,4);
+				/* erase context */
+  memset (ctx,0,sizeof (MD5CONTEXT));
+}
+
+/* MD5 basic transformation
+ * Accepts: state vector
+ *	    current 64-byte block
+ */
+
+static void md5_transform (unsigned long *state,unsigned char *block)
+{
+  unsigned long a = state[0],b = state[1],c = state[2],d = state[3],x[16];
+  md5_decode (x,block,16);	/* decode into 16 longs */
+				/* round 1 */
+  RND1 (a,b,c,d,x[ 0], 7,0xd76aa478); RND1 (d,a,b,c,x[ 1],12,0xe8c7b756);
+  RND1 (c,d,a,b,x[ 2],17,0x242070db); RND1 (b,c,d,a,x[ 3],22,0xc1bdceee);
+  RND1 (a,b,c,d,x[ 4], 7,0xf57c0faf); RND1 (d,a,b,c,x[ 5],12,0x4787c62a);
+  RND1 (c,d,a,b,x[ 6],17,0xa8304613); RND1 (b,c,d,a,x[ 7],22,0xfd469501);
+  RND1 (a,b,c,d,x[ 8], 7,0x698098d8); RND1 (d,a,b,c,x[ 9],12,0x8b44f7af);
+  RND1 (c,d,a,b,x[10],17,0xffff5bb1); RND1 (b,c,d,a,x[11],22,0x895cd7be);
+  RND1 (a,b,c,d,x[12], 7,0x6b901122); RND1 (d,a,b,c,x[13],12,0xfd987193);
+  RND1 (c,d,a,b,x[14],17,0xa679438e); RND1 (b,c,d,a,x[15],22,0x49b40821);
+				/* round 2 */
+  RND2 (a,b,c,d,x[ 1], 5,0xf61e2562); RND2 (d,a,b,c,x[ 6], 9,0xc040b340);
+  RND2 (c,d,a,b,x[11],14,0x265e5a51); RND2 (b,c,d,a,x[ 0],20,0xe9b6c7aa);
+  RND2 (a,b,c,d,x[ 5], 5,0xd62f105d); RND2 (d,a,b,c,x[10], 9, 0x2441453);
+  RND2 (c,d,a,b,x[15],14,0xd8a1e681); RND2 (b,c,d,a,x[ 4],20,0xe7d3fbc8);
+  RND2 (a,b,c,d,x[ 9], 5,0x21e1cde6); RND2 (d,a,b,c,x[14], 9,0xc33707d6);
+  RND2 (c,d,a,b,x[ 3],14,0xf4d50d87); RND2 (b,c,d,a,x[ 8],20,0x455a14ed);
+  RND2 (a,b,c,d,x[13], 5,0xa9e3e905); RND2 (d,a,b,c,x[ 2], 9,0xfcefa3f8);
+  RND2 (c,d,a,b,x[ 7],14,0x676f02d9); RND2 (b,c,d,a,x[12],20,0x8d2a4c8a);
+				/* round 3 */
+  RND3 (a,b,c,d,x[ 5], 4,0xfffa3942); RND3 (d,a,b,c,x[ 8],11,0x8771f681);
+  RND3 (c,d,a,b,x[11],16,0x6d9d6122); RND3 (b,c,d,a,x[14],23,0xfde5380c);
+  RND3 (a,b,c,d,x[ 1], 4,0xa4beea44); RND3 (d,a,b,c,x[ 4],11,0x4bdecfa9);
+  RND3 (c,d,a,b,x[ 7],16,0xf6bb4b60); RND3 (b,c,d,a,x[10],23,0xbebfbc70);
+  RND3 (a,b,c,d,x[13], 4,0x289b7ec6); RND3 (d,a,b,c,x[ 0],11,0xeaa127fa);
+  RND3 (c,d,a,b,x[ 3],16,0xd4ef3085); RND3 (b,c,d,a,x[ 6],23, 0x4881d05);
+  RND3 (a,b,c,d,x[ 9], 4,0xd9d4d039); RND3 (d,a,b,c,x[12],11,0xe6db99e5);
+  RND3 (c,d,a,b,x[15],16,0x1fa27cf8); RND3 (b,c,d,a,x[ 2],23,0xc4ac5665);
+				/* round 4 */
+  RND4 (a,b,c,d,x[ 0], 6,0xf4292244); RND4 (d,a,b,c,x[ 7],10,0x432aff97);
+  RND4 (c,d,a,b,x[14],15,0xab9423a7); RND4 (b,c,d,a,x[ 5],21,0xfc93a039);
+  RND4 (a,b,c,d,x[12], 6,0x655b59c3); RND4 (d,a,b,c,x[ 3],10,0x8f0ccc92);
+  RND4 (c,d,a,b,x[10],15,0xffeff47d); RND4 (b,c,d,a,x[ 1],21,0x85845dd1);
+  RND4 (a,b,c,d,x[ 8], 6,0x6fa87e4f); RND4 (d,a,b,c,x[15],10,0xfe2ce6e0);
+  RND4 (c,d,a,b,x[ 6],15,0xa3014314); RND4 (b,c,d,a,x[13],21,0x4e0811a1);
+  RND4 (a,b,c,d,x[ 4], 6,0xf7537e82); RND4 (d,a,b,c,x[11],10,0xbd3af235);
+  RND4 (c,d,a,b,x[ 2],15,0x2ad7d2bb); RND4 (b,c,d,a,x[ 9],21,0xeb86d391);
+				/* update state */
+  state[0] += a; state[1] += b; state[2] += c; state[3] += d;
+  memset (x,0,sizeof (x));	/* erase sensitive data */
+}
+
+/* You may wonder why these strange "& 0xff" maskings are here.  This is to
+ * ensure correct results on machines with a char size of larger than 8 bits.
+ * For example, the KCC compiler on the PDP-10 uses 9-bit chars.
+ */
+
+/* MD5 encode unsigned long into LSB-first bytes
+ * Accepts: destination pointer
+ *	    source
+ *	    length of source
+ */ 
+
+static void md5_encode (unsigned char *dst,unsigned long *src,int len)
+{
+  int i;
+  for (i = 0; i < len; i++) {
+    *dst++ = (unsigned char) (src[i] & 0xff);
+    *dst++ = (unsigned char) ((src[i] >> 8) & 0xff);
+    *dst++ = (unsigned char) ((src[i] >> 16) & 0xff);
+    *dst++ = (unsigned char) ((src[i] >> 24) & 0xff);
+  }
+}
+
+
+/* MD5 decode LSB-first bytes into unsigned long
+ * Accepts: destination pointer
+ *	    source
+ *	    length of destination
+ */ 
+
+static void md5_decode (unsigned long *dst,unsigned char *src,int len)
+{
+  int i, j;
+  for (i = 0, j = 0; i < len; i++, j += 4)
+    dst[i] = ((unsigned long) (src[j] & 0xff)) |
+      (((unsigned long) (src[j+1] & 0xff)) << 8) |
+      (((unsigned long) (src[j+2] & 0xff)) << 16) |
+	(((unsigned long) (src[j+3] & 0xff)) << 24);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/auth_pla.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,133 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Plain authenticator
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	22 September 1998
+ * Last Edited:	30 August 2006
+ */
+
+long auth_plain_client (authchallenge_t challenger,authrespond_t responder,
+			char *service,NETMBX *mb,void *stream,
+			unsigned long *trial,char *user);
+char *auth_plain_server (authresponse_t responder,int argc,char *argv[]);
+
+AUTHENTICATOR auth_pla = {
+  AU_AUTHUSER | AU_HIDE,	/* allow authuser, hidden */
+  "PLAIN",			/* authenticator name */
+  NIL,				/* always valid */
+  auth_plain_client,		/* client method */
+  auth_plain_server,		/* server method */
+  NIL				/* next authenticator */
+};
+
+/* Client authenticator
+ * Accepts: challenger function
+ *	    responder function
+ *	    SASL service name
+ *	    parsed network mailbox structure
+ *	    stream argument for functions
+ *	    pointer to current trial count
+ *	    returned user name
+ * Returns: T if success, NIL otherwise, number of trials incremented if retry
+ */
+
+long auth_plain_client (authchallenge_t challenger,authrespond_t responder,
+			char *service,NETMBX *mb,void *stream,
+			unsigned long *trial,char *user)
+{
+  char *u,pwd[MAILTMPLEN];
+  void *challenge;
+  unsigned long clen;
+  long ret = NIL;
+				/* snarl if not SSL/TLS session */
+  if (!mb->sslflag && !mb->tlsflag)
+    mm_log ("SECURITY PROBLEM: insecure server advertised AUTH=PLAIN",WARN);
+				/* get initial (empty) challenge */
+  if (challenge = (*challenger) (stream,&clen)) {
+    fs_give ((void **) &challenge);
+    if (clen) {			/* abort if challenge non-empty */
+      mm_log ("Server bug: non-empty initial PLAIN challenge",WARN);
+      (*responder) (stream,NIL,0);
+      ret = LONGT;		/* will get a BAD response back */
+    }
+    pwd[0] = NIL;		/* prompt user if empty challenge */
+    mm_login (mb,user,pwd,*trial);
+    if (!pwd[0]) {		/* empty challenge or user requested abort */
+      (*responder) (stream,NIL,0);
+      *trial = 0;		/* cancel subsequent attempts */
+      ret = LONGT;		/* will get a BAD response back */
+    }
+    else {
+      unsigned long rlen = 
+	strlen (mb->authuser) + strlen (user) + strlen (pwd) + 2;
+      char *response = (char *) fs_get (rlen);
+      char *t = response;	/* copy authorization id */
+      if (mb->authuser[0]) for (u = user; *u; *t++ = *u++);
+      *t++ = '\0';		/* delimiting NUL */
+				/* copy authentication id */
+      for (u = mb->authuser[0] ? mb->authuser : user; *u; *t++ = *u++);
+      *t++ = '\0';		/* delimiting NUL */
+				/* copy password */
+      for (u = pwd; *u; *t++ = *u++);
+				/* send credentials */
+      if ((*responder) (stream,response,rlen)) {
+	if (challenge = (*challenger) (stream,&clen))
+	  fs_give ((void **) &challenge);
+	else {
+	  ++*trial;		/* can try again if necessary */
+	  ret = LONGT;		/* check the authentication */
+	}
+      }
+      memset (response,0,rlen);	/* erase credentials */
+      fs_give ((void **) &response);
+    }
+  }
+  memset (pwd,0,MAILTMPLEN);	/* erase password */
+  if (!ret) *trial = 65535;	/* don't retry if bad protocol */
+  return ret;
+}
+
+/* Server authenticator
+ * Accepts: responder function
+ *	    argument count
+ *	    argument vector
+ * Returns: authenticated user name or NIL
+ */
+
+char *auth_plain_server (authresponse_t responder,int argc,char *argv[])
+{
+  char *ret = NIL;
+  char *user,*aid,*pass;
+  unsigned long len;
+				/* get user name */
+  if (aid = (*responder) ("",0,&len)) {
+				/* note: responders null-terminate */
+    if ((((unsigned long) ((user = aid + strlen (aid) + 1) - aid)) < len) &&
+	(((unsigned long) ((pass = user + strlen (user) + 1) - aid)) < len) &&
+	(((unsigned long) ((pass + strlen (pass)) - aid)) == len) &&
+	(*aid ? server_login (aid,pass,user,argc,argv) :
+	 server_login (user,pass,NIL,argc,argv))) ret = myusername ();
+    fs_give ((void **) &aid);
+  }
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/c-client.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,55 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	c-client master include for application programs
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	19 May 2000
+ * Last Edited:	6 December 2006
+ */
+
+#ifndef __CCLIENT_H		/* nobody should include this twice... */
+#define __CCLIENT_H
+
+#ifdef __cplusplus		/* help out people who use C++ compilers */
+extern "C" {
+  /* If you use gcc, you may also have to use -fno-operator-names */
+#define private cclientPrivate	/* private to c-client */
+#define and cclientAnd		/* C99 doesn't realize that ISO 646 is dead */
+#define or cclientOr
+#define not cclientNot
+#endif
+
+#include "mail.h"		/* primary interfaces */
+#include "osdep.h"		/* OS-dependent routines */
+#include "rfc822.h"		/* RFC822 and MIME routines */
+#include "smtp.h"		/* SMTP sending routines */
+#include "nntp.h"		/* NNTP sending routines */
+#include "utf8.h"		/* Unicode and charset routines */
+#include "utf8aux.h"		/* Unicode auxillary routines */
+#include "misc.h"		/* miscellaneous utility routines */
+
+#ifdef __cplusplus		/* undo the C++ mischief */
+#undef private
+}
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/env.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,45 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Environment routines
+ *
+ * Author:	Mark Crispin
+ *		UW Technology
+ *		University of Washington
+ *		Seattle, WA  98195
+ *		Internet: MRC@Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	13 February 2008
+ */
+
+/* Function prototypes */
+
+long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim);
+long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim);
+void *env_parameters (long function,void *value);
+void rfc822_date (char *date);
+void rfc822_timezone (char *s,void *t);
+void internal_date (char *date);
+long server_input_wait (long seconds);
+void server_init (char *server,char *service,char *sasl,
+		  void *clkint,void *kodint,void *hupint,void *trmint,
+		  void *staint);
+long server_login (char *user,char *pass,char *authuser,int argc,char *argv[]);
+long authserver_login (char *user,char *authuser,int argc,char *argv[]);
+long anonymous_login (int argc,char *argv[]);
+char *mylocalhost (void);
+char *myhomedir (void);
+char *mailboxfile (char *dst,char *name);
+MAILSTREAM *default_proto (long type);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/flstring.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,91 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	File string routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	15 April 1997
+ * Last Edited:	6 December 2006
+ */
+
+
+#include <stdio.h>
+#include "mail.h"
+#include "flstring.h"
+
+/* String driver for stdio file strings */
+
+static void file_string_init (STRING *s,void *data,unsigned long size);
+static char file_string_next (STRING *s);
+static void file_string_setpos (STRING *s,unsigned long i);
+
+STRINGDRIVER file_string = {
+  file_string_init,		/* initialize string structure */
+  file_string_next,		/* get next byte in string structure */
+  file_string_setpos		/* set position in string structure */
+};
+
+
+/* Initialize mail string structure for file
+ * Accepts: string structure
+ *	    pointer to string
+ *	    size of string
+ */
+
+static void file_string_init (STRING *s,void *data,unsigned long size)
+{
+  s->data = data;		/* note file descriptor */
+				/* big enough for one byte */
+  s->chunk = s->curpos = (char *) &s->data1;
+  s->size = size;		/* data size */
+  s->cursize = s->chunksize = 1;/* always call stdio */
+  file_string_setpos (s,0);	/* initial offset is 0 */
+}
+
+
+/* Get next character from string
+ * Accepts: string structure
+ * Returns: character, string structure chunk refreshed
+ */
+
+static char file_string_next (STRING *s)
+{
+  char ret = *s->curpos;
+  s->offset++;			/* advance position */
+  s->cursize = 1;		/* reset size */
+  *s->curpos = (char) getc ((FILE *) s->data);
+  return ret;
+}
+
+
+/* Set string pointer position
+ * Accepts: string structure
+ *	    new position
+ */
+
+static void file_string_setpos (STRING *s,unsigned long i)
+{
+  s->offset = i;		/* note new offset */
+  fseek ((FILE *) s->data,i,SEEK_SET);
+				/* in case using returnstringstruct hack */
+  s->chunk = s->curpos = (char *) &s->data1;
+  *s->curpos = (char) getc ((FILE *) s->data);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/flstring.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,30 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	File string routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	15 April 1997
+ * Last Edited:	30 August 2006
+ */
+
+
+extern STRINGDRIVER file_string;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/fs.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,34 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Free storage management routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Function prototypes */
+
+void *fs_get (size_t size);
+void fs_resize (void **block,size_t size);
+void fs_give (void **block);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/ftl.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,32 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Crash management routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Function prototypes */
+
+void fatal (char *string);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/imap4r1.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,5670 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Interactive Message Access Protocol 4rev1 (IMAP4R1) routines
+ *
+ * Author:	Mark Crispin
+ *		UW Technology
+ *		University of Washington
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	15 June 1988
+ * Last Edited:	8 May 2008
+ *
+ * This original version of this file is
+ * Copyright 1988 Stanford University
+ * and was developed in the Symbolic Systems Resources Group of the Knowledge
+ * Systems Laboratory at Stanford University in 1987-88, and was funded by the
+ * Biomedical Research Technology Program of the National Institutes of Health
+ * under grant number RR-00785.
+ */
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <time.h>
+#include "c-client.h"
+#include "imap4r1.h"
+
+/* Parameters */
+
+#define IMAPLOOKAHEAD 20	/* envelope lookahead */
+#define IMAPUIDLOOKAHEAD 1000	/* UID lookahead */
+#define IMAPTCPPORT (long) 143	/* assigned TCP contact port */
+#define IMAPSSLPORT (long) 993	/* assigned SSL TCP contact port */
+#define MAXCOMMAND 1000		/* RFC 2683 guideline for cmd line length */
+#define IDLETIMEOUT (long) 30	/* defined in RFC 3501 */
+#define MAXSERVERLIT 0x7ffffffe	/* maximum server literal size
+				 * must be smaller than 4294967295
+				 */
+
+
+/* Parsed reply message from imap_reply */
+
+typedef struct imap_parsed_reply {
+  unsigned char *line;		/* original reply string pointer */
+  unsigned char *tag;		/* command tag this reply is for */
+  unsigned char *key;		/* reply keyword */
+  unsigned char *text;		/* subsequent text */
+} IMAPPARSEDREPLY;
+
+
+#define IMAPTMPLEN 16*MAILTMPLEN
+
+
+/* IMAP4 I/O stream local data */
+	
+typedef struct imap_local {
+  NETSTREAM *netstream;		/* TCP I/O stream */
+  IMAPPARSEDREPLY reply;	/* last parsed reply */
+  MAILSTATUS *stat;		/* status to fill in */
+  IMAPCAP cap;			/* server capabilities */
+  char *appendmailbox;		/* mailbox being appended to */
+  unsigned int uidsearch : 1;	/* UID searching */
+  unsigned int byeseen : 1;	/* saw a BYE response */
+				/* got implicit capabilities */
+  unsigned int gotcapability : 1;
+  unsigned int sensitive : 1;	/* sensitive data in progress */
+  unsigned int tlsflag : 1;	/* TLS session */
+  unsigned int tlssslv23 : 1;	/* TLS using SSLv23 client method */
+  unsigned int notlsflag : 1;	/* TLS not used in session */
+  unsigned int sslflag : 1;	/* SSL session */
+  unsigned int novalidate : 1;	/* certificate not validated */
+  unsigned int filter : 1;	/* filter SEARCH/SORT/THREAD results */
+  unsigned int loser : 1;	/* server is a loser */
+  unsigned int saslcancel : 1;	/* SASL cancelled by protocol */
+  long authflags;		/* required flags for authenticators */
+  unsigned long sortsize;	/* sort return data size */
+  unsigned long *sortdata;	/* sort return data */
+  struct {
+    unsigned long uid;		/* last UID returned */
+    unsigned long msgno;	/* last msgno returned */
+  } lastuid;
+  NAMESPACE **namespace;	/* namespace return data */
+  THREADNODE *threaddata;	/* thread return data */
+  char *referral;		/* last referral */
+  char *prefix;			/* find prefix */
+  char *user;			/* logged-in user */
+  char *reform;			/* reformed sequence */
+  char tmp[IMAPTMPLEN];		/* temporary buffer */
+  SEARCHSET *lookahead;		/* fetch lookahead */
+} IMAPLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((IMAPLOCAL *) stream->local)
+
+/* Arguments to imap_send() */
+
+typedef struct imap_argument {
+  int type;			/* argument type */
+  void *text;			/* argument text */
+} IMAPARG;
+
+
+/* imap_send() argument types */
+
+#define ATOM 0
+#define NUMBER 1
+#define FLAGS 2
+#define ASTRING 3
+#define LITERAL 4
+#define LIST 5
+#define SEARCHPROGRAM 6
+#define SORTPROGRAM 7
+#define BODYTEXT 8
+#define BODYPEEK 9
+#define BODYCLOSE 10
+#define SEQUENCE 11
+#define LISTMAILBOX 12
+#define MULTIAPPEND 13
+#define SNLIST 14
+#define MULTIAPPENDREDO 15
+
+
+/* Append data */
+
+typedef struct append_data {
+  append_t af;
+  void *data;
+  char *flags;
+  char *date;
+  STRING *message;
+} APPENDDATA;
+
+/* Function prototypes */
+
+DRIVER *imap_valid (char *name);
+void *imap_parameters (long function,void *value);
+void imap_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void imap_list (MAILSTREAM *stream,char *ref,char *pat);
+void imap_lsub (MAILSTREAM *stream,char *ref,char *pat);
+void imap_list_work (MAILSTREAM *stream,char *cmd,char *ref,char *pat,
+		     char *contents);
+long imap_subscribe (MAILSTREAM *stream,char *mailbox);
+long imap_unsubscribe (MAILSTREAM *stream,char *mailbox);
+long imap_create (MAILSTREAM *stream,char *mailbox);
+long imap_delete (MAILSTREAM *stream,char *mailbox);
+long imap_rename (MAILSTREAM *stream,char *old,char *newname);
+long imap_manage (MAILSTREAM *stream,char *mailbox,char *command,char *arg2);
+long imap_status (MAILSTREAM *stream,char *mbx,long flags);
+MAILSTREAM *imap_open (MAILSTREAM *stream);
+IMAPPARSEDREPLY *imap_rimap (MAILSTREAM *stream,char *service,NETMBX *mb,
+			     char *usr,char *tmp);
+long imap_anon (MAILSTREAM *stream,char *tmp);
+long imap_auth (MAILSTREAM *stream,NETMBX *mb,char *tmp,char *usr);
+long imap_login (MAILSTREAM *stream,NETMBX *mb,char *pwd,char *usr);
+void *imap_challenge (void *stream,unsigned long *len);
+long imap_response (void *stream,char *s,unsigned long size);
+void imap_close (MAILSTREAM *stream,long options);
+void imap_fast (MAILSTREAM *stream,char *sequence,long flags);
+void imap_flags (MAILSTREAM *stream,char *sequence,long flags);
+long imap_overview (MAILSTREAM *stream,overview_t ofn);
+ENVELOPE *imap_structure (MAILSTREAM *stream,unsigned long msgno,BODY **body,
+			  long flags);
+long imap_msgdata (MAILSTREAM *stream,unsigned long msgno,char *section,
+		   unsigned long first,unsigned long last,STRINGLIST *lines,
+		   long flags);
+unsigned long imap_uid (MAILSTREAM *stream,unsigned long msgno);
+unsigned long imap_msgno (MAILSTREAM *stream,unsigned long uid);
+void imap_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
+long imap_search (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,long flags);
+unsigned long *imap_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
+			  SORTPGM *pgm,long flags);
+THREADNODE *imap_thread (MAILSTREAM *stream,char *type,char *charset,
+			 SEARCHPGM *spg,long flags);
+THREADNODE *imap_thread_work (MAILSTREAM *stream,char *type,char *charset,
+			      SEARCHPGM *spg,long flags);
+long imap_ping (MAILSTREAM *stream);
+void imap_check (MAILSTREAM *stream);
+long imap_expunge (MAILSTREAM *stream,char *sequence,long options);
+long imap_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long imap_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+long imap_append_referral (char *mailbox,char *tmp,append_t af,void *data,
+			   char *flags,char *date,STRING *message,
+			   APPENDDATA *map,long options);
+IMAPPARSEDREPLY *imap_append_single (MAILSTREAM *stream,char *mailbox,
+				     char *flags,char *date,STRING *message);
+
+void imap_gc (MAILSTREAM *stream,long gcflags);
+void imap_gc_body (BODY *body);
+void imap_capability (MAILSTREAM *stream);
+long imap_acl_work (MAILSTREAM *stream,char *command,IMAPARG *args[]);
+
+IMAPPARSEDREPLY *imap_send (MAILSTREAM *stream,char *cmd,IMAPARG *args[]);
+IMAPPARSEDREPLY *imap_sout (MAILSTREAM *stream,char *tag,char *base,char **s);
+long imap_soutr (MAILSTREAM *stream,char *string);
+IMAPPARSEDREPLY *imap_send_astring (MAILSTREAM *stream,char *tag,char **s,
+				    SIZEDTEXT *as,long wildok,char *limit);
+IMAPPARSEDREPLY *imap_send_literal (MAILSTREAM *stream,char *tag,char **s,
+				    STRING *st);
+IMAPPARSEDREPLY *imap_send_spgm (MAILSTREAM *stream,char *tag,char *base,
+				 char **s,SEARCHPGM *pgm,char *limit);
+char *imap_send_spgm_trim (char *base,char *s,char *text);
+IMAPPARSEDREPLY *imap_send_sset (MAILSTREAM *stream,char *tag,char *base,
+				 char **s,SEARCHSET *set,char *prefix,
+				 char *limit);
+IMAPPARSEDREPLY *imap_send_slist (MAILSTREAM *stream,char *tag,char *base,
+				  char **s,char *name,STRINGLIST *list,
+				  char *limit);
+void imap_send_sdate (char **s,char *name,unsigned short date);
+IMAPPARSEDREPLY *imap_reply (MAILSTREAM *stream,char *tag);
+IMAPPARSEDREPLY *imap_parse_reply (MAILSTREAM *stream,char *text);
+IMAPPARSEDREPLY *imap_fake (MAILSTREAM *stream,char *tag,char *text);
+long imap_OK (MAILSTREAM *stream,IMAPPARSEDREPLY *reply);
+void imap_parse_unsolicited (MAILSTREAM *stream,IMAPPARSEDREPLY *reply);
+void imap_parse_response (MAILSTREAM *stream,char *text,long errflg,long ntfy);
+NAMESPACE *imap_parse_namespace (MAILSTREAM *stream,unsigned char **txtptr,
+				 IMAPPARSEDREPLY *reply);
+THREADNODE *imap_parse_thread (MAILSTREAM *stream,unsigned char **txtptr);
+void imap_parse_header (MAILSTREAM *stream,ENVELOPE **env,SIZEDTEXT *hdr,
+			STRINGLIST *stl);
+void imap_parse_envelope (MAILSTREAM *stream,ENVELOPE **env,
+			  unsigned char **txtptr,IMAPPARSEDREPLY *reply);
+ADDRESS *imap_parse_adrlist (MAILSTREAM *stream,unsigned char **txtptr,
+			     IMAPPARSEDREPLY *reply);
+ADDRESS *imap_parse_address (MAILSTREAM *stream,unsigned char **txtptr,
+			     IMAPPARSEDREPLY *reply);
+void imap_parse_flags (MAILSTREAM *stream,MESSAGECACHE *elt,
+		       unsigned char **txtptr);
+unsigned long imap_parse_user_flag (MAILSTREAM *stream,char *flag);
+unsigned char *imap_parse_astring (MAILSTREAM *stream,unsigned char **txtptr,
+			  IMAPPARSEDREPLY *reply,unsigned long *len);
+unsigned char *imap_parse_string (MAILSTREAM *stream,unsigned char **txtptr,
+				  IMAPPARSEDREPLY *reply,GETS_DATA *md,
+				  unsigned long *len,long flags);
+void imap_parse_body (GETS_DATA *md,char *seg,unsigned char **txtptr,
+		      IMAPPARSEDREPLY *reply);
+void imap_parse_body_structure (MAILSTREAM *stream,BODY *body,
+				unsigned char **txtptr,IMAPPARSEDREPLY *reply);
+PARAMETER *imap_parse_body_parameter (MAILSTREAM *stream,
+				      unsigned char **txtptr,
+				      IMAPPARSEDREPLY *reply);
+void imap_parse_disposition (MAILSTREAM *stream,BODY *body,
+			     unsigned char **txtptr,IMAPPARSEDREPLY *reply);
+STRINGLIST *imap_parse_language (MAILSTREAM *stream,unsigned char **txtptr,
+				 IMAPPARSEDREPLY *reply);
+STRINGLIST *imap_parse_stringlist (MAILSTREAM *stream,unsigned char **txtptr,
+				   IMAPPARSEDREPLY *reply);
+void imap_parse_extension (MAILSTREAM *stream,unsigned char **txtptr,
+			   IMAPPARSEDREPLY *reply);
+void imap_parse_capabilities (MAILSTREAM *stream,char *t);
+IMAPPARSEDREPLY *imap_fetch (MAILSTREAM *stream,char *sequence,long flags);
+char *imap_reform_sequence (MAILSTREAM *stream,char *sequence,long flags);
+
+/* Driver dispatch used by MAIL */
+
+DRIVER imapdriver = {
+  "imap",			/* driver name */
+				/* driver flags */
+  DR_MAIL|DR_NEWS|DR_NAMESPACE|DR_CRLF|DR_RECYCLE|DR_HALFOPEN,
+  (DRIVER *) NIL,		/* next driver */
+  imap_valid,			/* mailbox is valid for us */
+  imap_parameters,		/* manipulate parameters */
+  imap_scan,			/* scan mailboxes */
+  imap_list,			/* find mailboxes */
+  imap_lsub,			/* find subscribed mailboxes */
+  imap_subscribe,		/* subscribe to mailbox */
+  imap_unsubscribe,		/* unsubscribe from mailbox */
+  imap_create,			/* create mailbox */
+  imap_delete,			/* delete mailbox */
+  imap_rename,			/* rename mailbox */
+  imap_status,			/* status of mailbox */
+  imap_open,			/* open mailbox */
+  imap_close,			/* close mailbox */
+  imap_fast,			/* fetch message "fast" attributes */
+  imap_flags,			/* fetch message flags */
+  imap_overview,		/* fetch overview */
+  imap_structure,		/* fetch message envelopes */
+  NIL,				/* fetch message header */
+  NIL,				/* fetch message body */
+  imap_msgdata,			/* fetch partial message */
+  imap_uid,			/* unique identifier */
+  imap_msgno,			/* message number */
+  imap_flag,			/* modify flags */
+  NIL,				/* per-message modify flags */
+  imap_search,			/* search for message based on criteria */
+  imap_sort,			/* sort messages */
+  imap_thread,			/* thread messages */
+  imap_ping,			/* ping mailbox to see if still alive */
+  imap_check,			/* check for new messages */
+  imap_expunge,			/* expunge deleted messages */
+  imap_copy,			/* copy messages to another mailbox */
+  imap_append,			/* append string message to mailbox */
+  imap_gc			/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM imapproto = {&imapdriver};
+
+				/* driver parameters */
+static unsigned long imap_maxlogintrials = MAXLOGINTRIALS;
+static long imap_lookahead = IMAPLOOKAHEAD;
+static long imap_uidlookahead = IMAPUIDLOOKAHEAD;
+static long imap_fetchlookaheadlimit = IMAPLOOKAHEAD;
+static long imap_defaultport = 0;
+static long imap_sslport = 0;
+static long imap_tryssl = NIL;
+static long imap_prefetch = IMAPLOOKAHEAD;
+static long imap_closeonerror = NIL;
+static imapenvelope_t imap_envelope = NIL;
+static imapreferral_t imap_referral = NIL;
+static char *imap_extrahdrs = NIL;
+
+				/* constants */
+static char *hdrheader[] = {
+  "BODY.PEEK[HEADER.FIELDS (Newsgroups Content-MD5 Content-Disposition Content-Language Content-Location",
+  "BODY.PEEK[HEADER.FIELDS (Newsgroups Content-Disposition Content-Language Content-Location",
+  "BODY.PEEK[HEADER.FIELDS (Newsgroups Content-Language Content-Location",
+  "BODY.PEEK[HEADER.FIELDS (Newsgroups Content-Location",
+  "BODY.PEEK[HEADER.FIELDS (Newsgroups"
+};
+static char *hdrtrailer ="Followup-To References)]";
+
+/* IMAP validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *imap_valid (char *name)
+{
+  return mail_valid_net (name,&imapdriver,NIL,NIL);
+}
+
+
+/* IMAP manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *imap_parameters (long function,void *value)
+{
+  switch ((int) function) {
+  case GET_NAMESPACE:
+    if (((IMAPLOCAL *) ((MAILSTREAM *) value)->local)->cap.namespace &&
+	!((IMAPLOCAL *) ((MAILSTREAM *) value)->local)->namespace)
+      imap_send (((MAILSTREAM *) value),"NAMESPACE",NIL);
+    value = (void *) &((IMAPLOCAL *) ((MAILSTREAM *) value)->local)->namespace;
+    break;
+  case GET_THREADERS:
+    value = (void *)
+      ((IMAPLOCAL *) ((MAILSTREAM *) value)->local)->cap.threader;
+    break;
+  case SET_FETCHLOOKAHEAD:	/* must use pointer from GET_FETCHLOOKAHEAD */
+    fatal ("SET_FETCHLOOKAHEAD not permitted");
+  case GET_FETCHLOOKAHEAD:
+    value = (void *) &((IMAPLOCAL *) ((MAILSTREAM *) value)->local)->lookahead;
+    break;
+  case SET_MAXLOGINTRIALS:
+    imap_maxlogintrials = (long) value;
+    break;
+  case GET_MAXLOGINTRIALS:
+    value = (void *) imap_maxlogintrials;
+    break;
+  case SET_LOOKAHEAD:
+    imap_lookahead = (long) value;
+    break;
+  case GET_LOOKAHEAD:
+    value = (void *) imap_lookahead;
+    break;
+  case SET_UIDLOOKAHEAD:
+    imap_uidlookahead = (long) value;
+    break;
+  case GET_UIDLOOKAHEAD:
+    value = (void *) imap_uidlookahead;
+    break;
+
+  case SET_IMAPPORT:
+    imap_defaultport = (long) value;
+    break;
+  case GET_IMAPPORT:
+    value = (void *) imap_defaultport;
+    break;
+  case SET_SSLIMAPPORT:
+    imap_sslport = (long) value;
+    break;
+  case GET_SSLIMAPPORT:
+    value = (void *) imap_sslport;
+    break;
+  case SET_PREFETCH:
+    imap_prefetch = (long) value;
+    break;
+  case GET_PREFETCH:
+    value = (void *) imap_prefetch;
+    break;
+  case SET_CLOSEONERROR:
+    imap_closeonerror = (long) value;
+    break;
+  case GET_CLOSEONERROR:
+    value = (void *) imap_closeonerror;
+    break;
+  case SET_IMAPENVELOPE:
+    imap_envelope = (imapenvelope_t) value;
+    break;
+  case GET_IMAPENVELOPE:
+    value = (void *) imap_envelope;
+    break;
+  case SET_IMAPREFERRAL:
+    imap_referral = (imapreferral_t) value;
+    break;
+  case GET_IMAPREFERRAL:
+    value = (void *) imap_referral;
+    break;
+  case SET_IMAPEXTRAHEADERS:
+    imap_extrahdrs = (char *) value;
+    break;
+  case GET_IMAPEXTRAHEADERS:
+    value = (void *) imap_extrahdrs;
+    break;
+  case SET_IMAPTRYSSL:
+    imap_tryssl = (long) value;
+    break;
+  case GET_IMAPTRYSSL:
+    value = (void *) imap_tryssl;
+    break;
+  case SET_FETCHLOOKAHEADLIMIT:
+    imap_fetchlookaheadlimit = (long) value;
+    break;
+  case GET_FETCHLOOKAHEADLIMIT:
+    value = (void *) imap_fetchlookaheadlimit;
+    break;
+
+  case SET_IDLETIMEOUT:
+    fatal ("SET_IDLETIMEOUT not permitted");
+  case GET_IDLETIMEOUT:
+    value = (void *) IDLETIMEOUT;
+    break;
+  default:
+    value = NIL;		/* error case */
+    break;
+  }
+  return value;
+}
+
+/* IMAP scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void imap_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  imap_list_work (stream,"SCAN",ref,pat,contents);
+}
+
+
+/* IMAP list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void imap_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  imap_list_work (stream,"LIST",ref,pat,NIL);
+}
+
+
+/* IMAP list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void imap_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  void *sdb = NIL;
+  char *s,mbx[MAILTMPLEN];
+				/* do it on the server */
+  imap_list_work (stream,"LSUB",ref,pat,NIL);
+  if (*pat == '{') {		/* if remote pattern, must be IMAP */
+    if (!imap_valid (pat)) return;
+    ref = NIL;			/* good IMAP pattern, punt reference */
+  }
+				/* if remote reference, must be valid IMAP */
+  if (ref && (*ref == '{') && !imap_valid (ref)) return;
+				/* kludgy application of reference */
+  if (ref && *ref) sprintf (mbx,"%s%s",ref,pat);
+  else strcpy (mbx,pat);
+
+  if (s = sm_read (&sdb)) do if (imap_valid (s) && pmatch (s,mbx))
+    mm_lsub (stream,NIL,s,NIL);
+  while (s = sm_read (&sdb));	/* until no more subscriptions */
+}
+
+/* IMAP find list of mailboxes
+ * Accepts: mail stream
+ *	    list command
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void imap_list_work (MAILSTREAM *stream,char *cmd,char *ref,char *pat,
+		     char *contents)
+{
+  MAILSTREAM *st = stream;
+  int pl;
+  char *s,prefix[MAILTMPLEN],mbx[MAILTMPLEN];
+  IMAPARG *args[4],aref,apat,acont;
+  if (ref && *ref) {		/* have a reference? */
+    if (!(imap_valid (ref) &&	/* make sure valid IMAP name and open stream */
+	  ((stream && LOCAL && LOCAL->netstream) ||
+	   (stream = mail_open (NIL,ref,OP_HALFOPEN|OP_SILENT))))) return;
+				/* calculate prefix length */
+    pl = strchr (ref,'}') + 1 - ref;
+    strncpy (prefix,ref,pl);	/* build prefix */
+    prefix[pl] = '\0';		/* tie off prefix */
+    ref += pl;			/* update reference */
+  }
+  else {
+    if (!(imap_valid (pat) &&	/* make sure valid IMAP name and open stream */
+	  ((stream && LOCAL && LOCAL->netstream) ||
+	   (stream = mail_open (NIL,pat,OP_HALFOPEN|OP_SILENT))))) return;
+				/* calculate prefix length */
+    pl = strchr (pat,'}') + 1 - pat;
+    strncpy (prefix,pat,pl);	/* build prefix */
+    prefix[pl] = '\0';		/* tie off prefix */
+    pat += pl;			/* update reference */
+  }
+  LOCAL->prefix = prefix;	/* note prefix */
+  if (contents) {		/* want to do a scan? */
+    if (LEVELSCAN (stream)) {	/* make sure permitted */
+      args[0] = &aref; args[1] = &apat; args[2] = &acont; args[3] = NIL;
+      aref.type = ASTRING; aref.text = (void *) (ref ? ref : "");
+      apat.type = LISTMAILBOX; apat.text = (void *) pat;
+      acont.type = ASTRING; acont.text = (void *) contents;
+      imap_send (stream,cmd,args);
+    }
+    else mm_log ("Scan not valid on this IMAP server",ERROR);
+  }
+
+  else if (LEVELIMAP4 (stream)){/* easy if IMAP4 */
+    args[0] = &aref; args[1] = &apat; args[2] = NIL;
+    aref.type = ASTRING; aref.text = (void *) (ref ? ref : "");
+    apat.type = LISTMAILBOX; apat.text = (void *) pat;
+				/* referrals armed? */
+    if (LOCAL->cap.mbx_ref && mail_parameters (stream,GET_IMAPREFERRAL,NIL)) {
+				/* yes, convert LIST -> RLIST */
+      if (!compare_cstring (cmd,"LIST")) cmd = "RLIST";
+				/* and convert LSUB -> RLSUB */
+      else if (!compare_cstring (cmd,"LSUB")) cmd = "RLSUB";
+    }
+    imap_send (stream,cmd,args);
+  }
+  else if (LEVEL1176 (stream)) {/* convert to IMAP2 format wildcard */
+				/* kludgy application of reference */
+    if (ref && *ref) sprintf (mbx,"%s%s",ref,pat);
+    else strcpy (mbx,pat);
+    for (s = mbx; *s; s++) if (*s == '%') *s = '*';
+    args[0] = &apat; args[1] = NIL;
+    apat.type = LISTMAILBOX; apat.text = (void *) mbx;
+    if (!(strstr (cmd,"LIST") &&/* if list, try IMAP2bis, then RFC-1176 */
+	  strcmp (imap_send (stream,"FIND ALL.MAILBOXES",args)->key,"BAD")) &&
+	!strcmp (imap_send (stream,"FIND MAILBOXES",args)->key,"BAD"))
+      LOCAL->cap.rfc1176 = NIL;	/* must be RFC-1064 */
+  }
+  LOCAL->prefix = NIL;		/* no more prefix */
+				/* close temporary stream if we made one */
+  if (stream != st) mail_close (stream);
+}
+
+/* IMAP subscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to add to subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long imap_subscribe (MAILSTREAM *stream,char *mailbox)
+{
+  MAILSTREAM *st = stream;
+  long ret = ((stream && LOCAL && LOCAL->netstream) ||
+	      (stream = mail_open (NIL,mailbox,OP_HALFOPEN|OP_SILENT))) ?
+		imap_manage (stream,mailbox,LEVELIMAP4 (stream) ?
+			     "Subscribe" : "Subscribe Mailbox",NIL) : NIL;
+				/* toss out temporary stream */
+  if (st != stream) mail_close (stream);
+  return ret;
+}
+
+
+/* IMAP unsubscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to delete from manage list
+ * Returns: T on success, NIL on failure
+ */
+
+long imap_unsubscribe (MAILSTREAM *stream,char *mailbox)
+{
+  MAILSTREAM *st = stream;
+  long ret = ((stream && LOCAL && LOCAL->netstream) ||
+	      (stream = mail_open (NIL,mailbox,OP_HALFOPEN|OP_SILENT))) ?
+		imap_manage (stream,mailbox,LEVELIMAP4 (stream) ?
+			     "Unsubscribe" : "Unsubscribe Mailbox",NIL) : NIL;
+				/* toss out temporary stream */
+  if (st != stream) mail_close (stream);
+  return ret;
+}
+
+/* IMAP create mailbox
+ * Accepts: mail stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long imap_create (MAILSTREAM *stream,char *mailbox)
+{
+  return imap_manage (stream,mailbox,"Create",NIL);
+}
+
+
+/* IMAP delete mailbox
+ * Accepts: mail stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long imap_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return imap_manage (stream,mailbox,"Delete",NIL);
+}
+
+
+/* IMAP rename mailbox
+ * Accepts: mail stream
+ *	    old mailbox name
+ *	    new mailbox name
+ * Returns: T on success, NIL on failure
+ */
+
+long imap_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  return imap_manage (stream,old,"Rename",newname);
+}
+
+/* IMAP manage a mailbox
+ * Accepts: mail stream
+ *	    mailbox to manipulate
+ *	    command to execute
+ *	    optional second argument
+ * Returns: T on success, NIL on failure
+ */
+
+long imap_manage (MAILSTREAM *stream,char *mailbox,char *command,char *arg2)
+{
+  MAILSTREAM *st = stream;
+  IMAPPARSEDREPLY *reply;
+  long ret = NIL;
+  char mbx[MAILTMPLEN],mbx2[MAILTMPLEN];
+  IMAPARG *args[3],ambx,amb2;
+  imapreferral_t ir =
+    (imapreferral_t) mail_parameters (stream,GET_IMAPREFERRAL,NIL);
+  ambx.type = amb2.type = ASTRING; ambx.text = (void *) mbx;
+  amb2.text = (void *) mbx2;
+  args[0] = &ambx; args[1] = args[2] = NIL;
+				/* require valid names and open stream */
+  if (mail_valid_net (mailbox,&imapdriver,NIL,mbx) &&
+      (arg2 ? mail_valid_net (arg2,&imapdriver,NIL,mbx2) : &imapdriver) &&
+      ((stream && LOCAL && LOCAL->netstream) ||
+       (stream = mail_open (NIL,mailbox,OP_HALFOPEN|OP_SILENT)))) {
+    if (arg2) args[1] = &amb2;	/* second arg present? */
+    if (!(ret = (imap_OK (stream,reply = imap_send (stream,command,args)))) &&
+	ir && LOCAL->referral) {
+      long code = -1;
+      switch (*command) {	/* which command was it? */
+      case 'S': code = REFSUBSCRIBE; break;
+      case 'U': code = REFUNSUBSCRIBE; break;
+      case 'C': code = REFCREATE; break;
+      case 'D': code = REFDELETE; break;
+      case 'R': code = REFRENAME; break;
+      default:
+	fatal ("impossible referral command");
+      }
+      if ((code >= 0) && (mailbox = (*ir) (stream,LOCAL->referral,code)))
+	ret = imap_manage (NIL,mailbox,command,(*command == 'R') ?
+			   (mailbox + strlen (mailbox) + 1) : NIL);
+    }
+    mm_log (reply->text,ret ? NIL : ERROR);
+				/* toss out temporary stream */
+    if (st != stream) mail_close (stream);
+  }
+  return ret;
+}
+
+/* IMAP status
+ * Accepts: mail stream
+ *	    mailbox name
+ *	    status flags
+ * Returns: T on success, NIL on failure
+ */
+
+long imap_status (MAILSTREAM *stream,char *mbx,long flags)
+{
+  IMAPARG *args[3],ambx,aflg;
+  char tmp[MAILTMPLEN];
+  NETMBX mb;
+  unsigned long i;
+  long ret = NIL;
+  MAILSTREAM *tstream = NIL;
+				/* use given stream if (rev1 or halfopen) and
+				   right host */
+  if (!((stream && (LEVELIMAP4rev1 (stream) || stream->halfopen) &&
+	 mail_usable_network_stream (stream,mbx)) ||
+	(stream = tstream = mail_open (NIL,mbx,OP_HALFOPEN|OP_SILENT))))
+    return NIL;
+				/* parse mailbox name */
+  mail_valid_net_parse (mbx,&mb);
+  args[0] = &ambx;args[1] = NIL;/* set up first argument as mailbox */
+  ambx.type = ASTRING; ambx.text = (void *) mb.mailbox;
+  if (LEVELIMAP4rev1 (stream)) {/* have STATUS command? */
+    imapreferral_t ir;
+    aflg.type = FLAGS; aflg.text = (void *) tmp;
+    args[1] = &aflg; args[2] = NIL;
+    tmp[0] = tmp[1] = '\0';	/* build flag list */
+    if (flags & SA_MESSAGES) strcat (tmp," MESSAGES");
+    if (flags & SA_RECENT) strcat (tmp," RECENT");
+    if (flags & SA_UNSEEN) strcat (tmp," UNSEEN");
+    if (flags & SA_UIDNEXT) strcat (tmp," UIDNEXT");
+    if (flags & SA_UIDVALIDITY) strcat (tmp," UIDVALIDITY");
+    tmp[0] = '(';
+    strcat (tmp,")");
+				/* send "STATUS mailbox flag" */
+    if (imap_OK (stream,imap_send (stream,"STATUS",args))) ret = T;
+    else if ((ir = (imapreferral_t)
+	      mail_parameters (stream,GET_IMAPREFERRAL,NIL)) &&
+	     LOCAL->referral &&
+	     (mbx = (*ir) (stream,LOCAL->referral,REFSTATUS)))
+      ret = imap_status (NIL,mbx,flags | (stream->debug ? SA_DEBUG : NIL));
+  }
+
+				/* IMAP2 way */
+  else if (imap_OK (stream,imap_send (stream,"EXAMINE",args))) {
+    MAILSTATUS status;
+    status.flags = flags & ~ (SA_UIDNEXT | SA_UIDVALIDITY);
+    status.messages = stream->nmsgs;
+    status.recent = stream->recent;
+    status.unseen = 0;
+    if (flags & SA_UNSEEN) {	/* must search to get unseen messages */
+				/* clear search vector */
+      for (i = 1; i <= stream->nmsgs; ++i) mail_elt (stream,i)->searched = NIL;
+      if (imap_OK (stream,imap_send (stream,"SEARCH UNSEEN",NIL)))
+	for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++)
+	  if (mail_elt (stream,i)->searched) status.unseen++;
+    }
+    strcpy (strchr (strcpy (tmp,stream->mailbox),'}') + 1,mb.mailbox);
+				/* pass status to main program */
+    mm_status (stream,tmp,&status);
+    ret = T;			/* note success */
+  }
+  if (tstream) mail_close (tstream);
+  return ret;			/* success */
+}
+
+/* IMAP open
+ * Accepts: stream to open
+ * Returns: stream to use on success, NIL on failure
+ */
+
+MAILSTREAM *imap_open (MAILSTREAM *stream)
+{
+  unsigned long i,j;
+  char *s,tmp[MAILTMPLEN],usr[MAILTMPLEN];
+  NETMBX mb;
+  IMAPPARSEDREPLY *reply = NIL;
+  imapreferral_t ir =
+    (imapreferral_t) mail_parameters (stream,GET_IMAPREFERRAL,NIL);
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return &imapproto;
+  mail_valid_net_parse (stream->mailbox,&mb);
+  usr[0] = '\0';		/* initially no user name */
+  if (LOCAL) {			/* if stream opened earlier by us */
+				/* recycle if still alive */
+    if (LOCAL->netstream && (!stream->halfopen || LOCAL->cap.unselect)) {
+      i = stream->silent;	/* temporarily mark silent */
+      stream->silent = T;	/* don't give mm_exists() events */
+      j = imap_ping (stream);	/* learn if stream still alive */
+      stream->silent = i;	/* restore prior state */
+      if (j) {			/* was stream still alive? */
+	sprintf (tmp,"Reusing connection to %s",net_host (LOCAL->netstream));
+	if (LOCAL->user) sprintf (tmp + strlen (tmp),"/user=\"%s\"",
+				  LOCAL->user);
+	if (!stream->silent) mm_log (tmp,(long) NIL);
+				/* unselect if now want halfopen */
+	if (stream->halfopen) imap_send (stream,"UNSELECT",NIL);
+      }
+      else imap_close (stream,NIL);
+    }
+    else imap_close (stream,NIL);
+  }
+				/* copy flags from name */
+  if (mb.dbgflag) stream->debug = T;
+  if (mb.readonlyflag) stream->rdonly = T;
+  if (mb.anoflag) stream->anonymous = T;
+  if (mb.secflag) stream->secure = T;
+  if (mb.trysslflag || imap_tryssl) stream->tryssl = T;
+
+  if (!LOCAL) {			/* open new connection if no recycle */
+    NETDRIVER *ssld = (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL);
+    unsigned long defprt = imap_defaultport ? imap_defaultport : IMAPTCPPORT;
+    unsigned long sslport = imap_sslport ? imap_sslport : IMAPSSLPORT;
+    stream->local =		/* instantiate localdata */
+      (void *) memset (fs_get (sizeof (IMAPLOCAL)),0,sizeof (IMAPLOCAL));
+				/* assume IMAP2bis server */
+    LOCAL->cap.imap2bis = LOCAL->cap.rfc1176 = T;
+				/* in case server is a loser */
+    if (mb.loser) LOCAL->loser = T;
+				/* desirable authenticators */
+    LOCAL->authflags = (stream->secure ? AU_SECURE : NIL) |
+      (mb.authuser[0] ? AU_AUTHUSER : NIL);
+    /* IMAP connection open logic is more complex than net_open() normally
+     * deals with, because of the simap and rimap hacks.
+     * If the session is anonymous, a specific port is given, or if /ssl or
+     * /tls is set, do net_open() since those conditions override everything
+     * else.
+     */
+    if (stream->anonymous || mb.port || mb.sslflag || mb.tlsflag)
+      reply = (LOCAL->netstream = net_open (&mb,NIL,defprt,ssld,"*imaps",
+					    sslport)) ?
+	imap_reply (stream,NIL) : NIL;
+    /* 
+     * No overriding conditions, so get the best connection that we can.  In
+     * order, attempt to open via simap, tryssl, rimap, and finally TCP.
+     */
+				/* try simap */
+    else if (reply = imap_rimap (stream,"*imap",&mb,usr,tmp));
+    else if (ssld &&		/* try tryssl if enabled */
+	     (stream->tryssl || mail_parameters (NIL,GET_TRYSSLFIRST,NIL)) &&
+	     (LOCAL->netstream =
+	      net_open_work (ssld,mb.host,"*imaps",sslport,mb.port,
+			     (mb.novalidate ? NET_NOVALIDATECERT : 0) |
+			     NET_SILENT | NET_TRYSSL))) {
+      if (net_sout (LOCAL->netstream,"",0)) {
+	mb.sslflag = T;
+	reply = imap_reply (stream,NIL);
+      }
+      else {			/* flush fake SSL stream */
+	net_close (LOCAL->netstream);
+	LOCAL->netstream = NIL;
+      }
+    }
+				/* try rimap first, then TCP */
+    else if (!(reply = imap_rimap (stream,"imap",&mb,usr,tmp)) &&
+	     (LOCAL->netstream = net_open (&mb,NIL,defprt,NIL,NIL,NIL)))
+      reply = imap_reply (stream,NIL);
+				/* make sure greeting is good */
+    if (!reply || strcmp (reply->tag,"*") ||
+	(strcmp (reply->key,"OK") && strcmp (reply->key,"PREAUTH"))) {
+      if (reply) mm_log (reply->text,ERROR);
+      return NIL;		/* lost during greeting */
+    }
+
+				/* if connected and not preauthenticated */
+    if (LOCAL->netstream && strcmp (reply->key,"PREAUTH")) {
+      sslstart_t stls = (sslstart_t) mail_parameters (NIL,GET_SSLSTART,NIL);
+				/* get server capabilities */
+      if (!LOCAL->gotcapability) imap_capability (stream);
+      if (LOCAL->netstream &&	/* does server support STARTTLS? */
+	  stls && LOCAL->cap.starttls && !mb.sslflag && !mb.notlsflag &&
+	  imap_OK (stream,imap_send (stream,"STARTTLS",NIL))) {
+	mb.tlsflag = T;		/* TLS OK, get into TLS at this end */
+	LOCAL->netstream->dtb = ssld;
+	if (!(LOCAL->netstream->stream =
+	      (*stls) (LOCAL->netstream->stream,mb.host,
+		       (mb.tlssslv23 ? NIL : NET_TLSCLIENT) |
+		       (mb.novalidate ? NET_NOVALIDATECERT : NIL)))) {
+				/* drat, drop this connection */
+	  if (LOCAL->netstream) net_close (LOCAL->netstream);
+	  LOCAL->netstream = NIL;
+	}
+				/* get capabilities now that TLS in effect */
+	if (LOCAL->netstream) imap_capability (stream);
+      }
+      else if (mb.tlsflag) {	/* user specified /tls but can't do it */
+	mm_log ("Unable to negotiate TLS with this server",ERROR);
+	return NIL;
+      }
+      if (LOCAL->netstream) {	/* still in the land of the living? */
+	if ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL)) {
+				/* remote name for authentication */
+	  strncpy (mb.host,(long) mail_parameters(NIL,GET_SASLUSESPTRNAME,NIL)?
+		   net_remotehost (LOCAL->netstream) :
+		   net_host (LOCAL->netstream),NETMAXHOST-1);
+	  mb.host[NETMAXHOST-1] = '\0';
+	}
+				/* need new capabilities after login */
+	LOCAL->gotcapability = NIL;
+	if (!(stream->anonymous ? imap_anon (stream,tmp) :
+	      (LOCAL->cap.auth ? imap_auth (stream,&mb,tmp,usr) :
+	       imap_login (stream,&mb,tmp,usr)))) {
+				/* failed, is there a referral? */
+	  if (ir && LOCAL->referral &&
+	      (s = (*ir) (stream,LOCAL->referral,REFAUTHFAILED))) {
+	    imap_close (stream,NIL);
+	    fs_give ((void **) &stream->mailbox);
+				/* set as new mailbox name to open */
+	    stream->mailbox = s;
+	    return imap_open (stream);
+	  }
+	  return NIL;		/* authentication failed */
+	}
+	else if (ir && LOCAL->referral &&
+		 (s = (*ir) (stream,LOCAL->referral,REFAUTH))) {
+	  imap_close (stream,NIL);
+	  fs_give ((void **) &stream->mailbox);
+	  stream->mailbox = s;	/* set as new mailbox name to open */
+				/* recurse to log in on real site */
+	  return imap_open (stream);
+	}
+      }
+    }
+				/* get server capabilities again */
+    if (LOCAL->netstream && !LOCAL->gotcapability) imap_capability (stream);
+				/* save state for future recycling */
+    if (mb.tlsflag) LOCAL->tlsflag = T;
+    if (mb.tlssslv23) LOCAL->tlssslv23 = T;
+    if (mb.notlsflag) LOCAL->notlsflag = T;
+    if (mb.sslflag) LOCAL->sslflag = T;
+    if (mb.novalidate) LOCAL->novalidate = T;
+    if (mb.loser) LOCAL->loser = T;
+  }
+
+  if (LOCAL->netstream) {	/* still have a connection? */
+    stream->perm_seen = stream->perm_deleted = stream->perm_answered =
+      stream->perm_draft = LEVELIMAP4 (stream) ? NIL : T;
+    stream->perm_user_flags = LEVELIMAP4 (stream) ? NIL : 0xffffffff;
+    stream->sequence++;		/* bump sequence number */
+    sprintf (tmp,"{%s",(long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ?
+	     net_host (LOCAL->netstream) : mb.host);
+    if (!((i = net_port (LOCAL->netstream)) & 0xffff0000))
+      sprintf (tmp + strlen (tmp),":%lu",i);
+    strcat (tmp,"/imap");
+    if (LOCAL->tlsflag) strcat (tmp,"/tls");
+    if (LOCAL->tlssslv23) strcat (tmp,"/tls-sslv23");
+    if (LOCAL->notlsflag) strcat (tmp,"/notls");
+    if (LOCAL->sslflag) strcat (tmp,"/ssl");
+    if (LOCAL->novalidate) strcat (tmp,"/novalidate-cert");
+    if (LOCAL->loser) strcat (tmp,"/loser");
+    if (stream->secure) strcat (tmp,"/secure");
+    if (stream->rdonly) strcat (tmp,"/readonly");
+    if (stream->anonymous) strcat (tmp,"/anonymous");
+    else {			/* record user name */
+      if (!LOCAL->user && usr[0]) LOCAL->user = cpystr (usr);
+      if (LOCAL->user) sprintf (tmp + strlen (tmp),"/user=\"%s\"",
+				LOCAL->user);
+    }
+    strcat (tmp,"}");
+
+    if (!stream->halfopen) {	/* wants to open a mailbox? */
+      IMAPARG *args[2];
+      IMAPARG ambx;
+      ambx.type = ASTRING;
+      ambx.text = (void *) mb.mailbox;
+      args[0] = &ambx; args[1] = NIL;
+      stream->nmsgs = 0;
+      if (imap_OK (stream,reply = imap_send (stream,stream->rdonly ?
+					     "EXAMINE": "SELECT",args))) {
+	strcat (tmp,mb.mailbox);/* mailbox name */
+	if (!stream->nmsgs && !stream->silent)
+	  mm_log ("Mailbox is empty",(long) NIL);
+				/* note if an INBOX or not */
+	stream->inbox = !compare_cstring (mb.mailbox,"INBOX");
+      }
+      else if (ir && LOCAL->referral &&
+	       (s = (*ir) (stream,LOCAL->referral,REFSELECT))) {
+	imap_close (stream,NIL);
+	fs_give ((void **) &stream->mailbox);
+	stream->mailbox = s;	/* set as new mailbox name to open */
+	return imap_open (stream);
+      }
+      else {
+	mm_log (reply->text,ERROR);
+	if (imap_closeonerror) return NIL;
+	stream->halfopen = T;	/* let him keep it half-open */
+      }
+    }
+    if (stream->halfopen) {	/* half-open connection? */
+      strcat (tmp,"<no_mailbox>");
+				/* make sure dummy message counts */
+      mail_exists (stream,(long) 0);
+      mail_recent (stream,(long) 0);
+    }
+    fs_give ((void **) &stream->mailbox);
+    stream->mailbox = cpystr (tmp);
+  }
+				/* success if stream open */
+  return LOCAL->netstream ? stream : NIL;
+}
+
+/* IMAP rimap connect
+ * Accepts: MAIL stream
+ *	    NETMBX specification
+ *	    service to use
+ *	    user name
+ *	    scratch buffer
+ * Returns: parsed reply if success, else NIL
+ */
+
+IMAPPARSEDREPLY *imap_rimap (MAILSTREAM *stream,char *service,NETMBX *mb,
+			     char *usr,char *tmp)
+{
+  unsigned long i;
+  char c[2];
+  NETSTREAM *tstream;
+  IMAPPARSEDREPLY *reply = NIL;
+				/* try rimap open */
+  if (!mb->norsh && (tstream = net_aopen (NIL,mb,service,usr))) {
+				/* if success, see if reasonable banner */
+    if (net_getbuffer (tstream,(long) 1,c) && (*c == '*')) {
+      i = 0;			/* copy to buffer */
+      do tmp[i++] = *c;
+      while (net_getbuffer (tstream,(long) 1,c) && (*c != '\015') &&
+	     (*c != '\012') && (i < (MAILTMPLEN-1)));
+      tmp[i] = '\0';		/* tie off */
+				/* snarfed a valid greeting? */
+      if ((*c == '\015') && net_getbuffer (tstream,(long) 1,c) &&
+	  (*c == '\012') &&
+	  !strcmp ((reply = imap_parse_reply (stream,cpystr (tmp)))->tag,"*")){
+				/* parse line as IMAP */
+	imap_parse_unsolicited (stream,reply);
+				/* make sure greeting is good */
+	if (!strcmp (reply->key,"OK") || !strcmp (reply->key,"PREAUTH")) {
+	  LOCAL->netstream = tstream;
+	  return reply;		/* return success */
+	}
+      }
+    }
+    net_close (tstream);	/* failed, punt the temporary netstream */
+  }
+  return NIL;
+}
+
+/* IMAP log in as anonymous
+ * Accepts: stream to authenticate
+ *	    scratch buffer
+ * Returns: T on success, NIL on failure
+ */
+
+long imap_anon (MAILSTREAM *stream,char *tmp)
+{
+  IMAPPARSEDREPLY *reply;
+  char *s = net_localhost (LOCAL->netstream);
+  if (LOCAL->cap.authanon) {
+    char tag[16];
+    unsigned long i;
+    char *broken = "[CLOSED] IMAP connection broken (anonymous auth)";
+    sprintf (tag,"%08lx",0xffffffff & (stream->gensym++));
+				/* build command */
+    sprintf (tmp,"%s AUTHENTICATE ANONYMOUS",tag);
+    if (!imap_soutr (stream,tmp)) {
+      mm_log (broken,ERROR);
+      return NIL;
+    }
+    if (imap_challenge (stream,&i)) imap_response (stream,s,strlen (s));
+				/* get response */
+    if (!(reply = &LOCAL->reply)->tag) reply = imap_fake (stream,tag,broken);
+				/* what we wanted? */
+    if (compare_cstring (reply->tag,tag)) {
+				/* abort if don't have tagged response */
+      while (compare_cstring ((reply = imap_reply (stream,tag))->tag,tag))
+	imap_soutr (stream,"*");
+    }
+  }
+  else {
+    IMAPARG *args[2];
+    IMAPARG ausr;
+    ausr.type = ASTRING;
+    ausr.text = (void *) s;
+    args[0] = &ausr; args[1] = NIL;
+				/* send "LOGIN anonymous <host>" */
+    reply = imap_send (stream,"LOGIN ANONYMOUS",args);
+  }
+				/* success if reply OK */
+  if (imap_OK (stream,reply)) return T;
+  mm_log (reply->text,ERROR);
+  return NIL;
+}
+
+/* IMAP authenticate
+ * Accepts: stream to authenticate
+ *	    parsed network mailbox structure
+ *	    scratch buffer
+ *	    place to return user name
+ * Returns: T on success, NIL on failure
+ */
+
+long imap_auth (MAILSTREAM *stream,NETMBX *mb,char *tmp,char *usr)
+{
+  unsigned long trial,ua;
+  int ok;
+  char tag[16];
+  char *lsterr = NIL;
+  AUTHENTICATOR *at;
+  IMAPPARSEDREPLY *reply;
+  for (ua = LOCAL->cap.auth, LOCAL->saslcancel = NIL; LOCAL->netstream && ua &&
+       (at = mail_lookup_auth (find_rightmost_bit (&ua) + 1));) {
+    if (lsterr) {		/* previous authenticator failed? */
+      sprintf (tmp,"Retrying using %s authentication after %.80s",
+	       at->name,lsterr);
+      mm_log (tmp,NIL);
+      fs_give ((void **) &lsterr);
+    }
+    trial = 0;			/* initial trial count */
+    tmp[0] = '\0';		/* no error */
+    do {			/* gensym a new tag */
+      if (lsterr) {		/* previous attempt with this one failed? */
+	sprintf (tmp,"Retrying %s authentication after %.80s",at->name,lsterr);
+	mm_log (tmp,WARN);
+	fs_give ((void **) &lsterr);
+      }
+      LOCAL->saslcancel = NIL;
+      sprintf (tag,"%08lx",0xffffffff & (stream->gensym++));
+				/* build command */
+      sprintf (tmp,"%s AUTHENTICATE %s",tag,at->name);
+      if (imap_soutr (stream,tmp)) {
+				/* hide client authentication responses */
+	if (!(at->flags & AU_SECURE)) LOCAL->sensitive = T;
+	ok = (*at->client) (imap_challenge,imap_response,"imap",mb,stream,
+			    &trial,usr);
+	LOCAL->sensitive = NIL;	/* unhide */
+				/* make sure have a response */
+	if (!(reply = &LOCAL->reply)->tag)
+	  reply = imap_fake (stream,tag,
+			     "[CLOSED] IMAP connection broken (authenticate)");
+	else if (compare_cstring (reply->tag,tag))
+	  while (compare_cstring ((reply = imap_reply (stream,tag))->tag,tag))
+	    imap_soutr (stream,"*");
+				/* good if SASL ok and success response */
+	if (ok && imap_OK (stream,reply)) return T;
+	if (!trial) {		/* if main program requested cancellation */
+	  mm_log ("IMAP Authentication cancelled",ERROR);
+	  return NIL;
+	}
+				/* no error if protocol-initiated cancel */
+	lsterr = cpystr (reply->text);
+      }
+    }
+    while (LOCAL->netstream && !LOCAL->byeseen && trial &&
+	   (trial < imap_maxlogintrials));
+  }
+  if (lsterr) {			/* previous authenticator failed? */
+    if (!LOCAL->saslcancel) {	/* don't do this if a cancel */
+      sprintf (tmp,"Can not authenticate to IMAP server: %.80s",lsterr);
+      mm_log (tmp,ERROR);
+    }
+    fs_give ((void **) &lsterr);
+  }
+  return NIL;			/* ran out of authenticators */
+}
+
+/* IMAP login
+ * Accepts: stream to login
+ *	    parsed network mailbox structure
+ *	    scratch buffer of length MAILTMPLEN
+ *	    place to return user name
+ * Returns: T on success, NIL on failure
+ */
+
+long imap_login (MAILSTREAM *stream,NETMBX *mb,char *pwd,char *usr)
+{
+  unsigned long trial = 0;
+  IMAPPARSEDREPLY *reply;
+  IMAPARG *args[3];
+  IMAPARG ausr,apwd;
+  long ret = NIL;
+  if (stream->secure)		/* never do LOGIN if want security */
+    mm_log ("Can't do secure authentication with this server",ERROR);
+				/* never do LOGIN if server disabled it */
+  else if (LOCAL->cap.logindisabled)
+    mm_log ("Server disables LOGIN, no recognized SASL authenticator",ERROR);
+  else if (mb->authuser[0])	/* never do LOGIN with /authuser */
+    mm_log ("Can't do /authuser with this server",ERROR);
+  else {			/* OK to try login */
+    ausr.type = apwd.type = ASTRING;
+    ausr.text = (void *) usr;
+    apwd.text = (void *) pwd;
+    args[0] = &ausr; args[1] = &apwd; args[2] = NIL;
+    do {
+      pwd[0] = 0;		/* prompt user for password */
+      mm_login (mb,usr,pwd,trial++);
+      if (pwd[0]) {		/* send login command if have password */
+	LOCAL->sensitive = T;	/* hide this command */
+				/* send "LOGIN usr pwd" */
+	if (imap_OK (stream,reply = imap_send (stream,"LOGIN",args)))
+	  ret = LONGT;		/* success */
+	else {
+	  mm_log (reply->text,WARN);
+	  if (!LOCAL->referral && (trial == imap_maxlogintrials))
+	    mm_log ("Too many login failures",ERROR);
+	}
+	LOCAL->sensitive = NIL;	/* unhide */
+      }
+				/* user refused to give password */
+      else mm_log ("Login aborted",ERROR);
+    } while (!ret && pwd[0] && (trial < imap_maxlogintrials) &&
+	     LOCAL->netstream && !LOCAL->byeseen && !LOCAL->referral);
+  }
+  memset (pwd,0,MAILTMPLEN);	/* erase password */
+  return ret;
+}
+
+/* Get challenge to authenticator in binary
+ * Accepts: stream
+ *	    pointer to returned size
+ * Returns: challenge or NIL if not challenge
+ */
+
+void *imap_challenge (void *s,unsigned long *len)
+{
+  char tmp[MAILTMPLEN];
+  void *ret = NIL;
+  MAILSTREAM *stream = (MAILSTREAM *) s;
+  IMAPPARSEDREPLY *reply = NIL;
+				/* get tagged response or challenge */
+  while (stream && LOCAL->netstream &&
+	 (reply = imap_parse_reply (stream,net_getline (LOCAL->netstream))) &&
+	 !strcmp (reply->tag,"*")) imap_parse_unsolicited (stream,reply);
+				/* parse challenge if have one */
+  if (stream && LOCAL->netstream && reply && reply->tag &&
+      (*reply->tag == '+') && !reply->tag[1] && reply->text &&
+      !(ret = rfc822_base64 ((unsigned char *) reply->text,
+			     strlen (reply->text),len))) {
+    sprintf (tmp,"IMAP SERVER BUG (invalid challenge): %.80s",
+	     (char *) reply->text);
+    mm_log (tmp,ERROR);
+  }
+  return ret;
+}
+
+
+/* Send authenticator response in BASE64
+ * Accepts: MAIL stream
+ *	    string to send
+ *	    length of string
+ * Returns: T if successful, else NIL
+ */
+
+long imap_response (void *s,char *response,unsigned long size)
+{
+  MAILSTREAM *stream = (MAILSTREAM *) s;
+  unsigned long i,j,ret;
+  char *t,*u;
+  if (response) {		/* make CRLFless BASE64 string */
+    if (size) {
+      for (t = (char *) rfc822_binary ((void *) response,size,&i),u = t,j = 0;
+	   j < i; j++) if (t[j] > ' ') *u++ = t[j];
+      *u = '\0';		/* tie off string for mm_dlog() */
+      if (stream->debug) mail_dlog (t,LOCAL->sensitive);
+				/* append CRLF */
+      *u++ = '\015'; *u++ = '\012';
+      ret = net_sout (LOCAL->netstream,t,u - t);
+      fs_give ((void **) &t);
+    }
+    else ret = imap_soutr (stream,"");
+  }
+  else {			/* abort requested */
+    ret = imap_soutr (stream,"*");
+    LOCAL->saslcancel = T;	/* mark protocol-requested SASL cancel */
+  }
+  return ret;
+}
+
+/* IMAP close
+ * Accepts: MAIL stream
+ *	    option flags
+ */
+
+void imap_close (MAILSTREAM *stream,long options)
+{
+  THREADER *thr,*t;
+  IMAPPARSEDREPLY *reply;
+  if (stream && LOCAL) {	/* send "LOGOUT" */
+    if (!LOCAL->byeseen) {	/* don't even think of doing it if saw a BYE */
+				/* expunge silently if requested */
+      if (options & CL_EXPUNGE)
+	imap_send (stream,LEVELIMAP4 (stream) ? "CLOSE" : "EXPUNGE",NIL);
+      if (LOCAL->netstream &&
+	  !imap_OK (stream,reply = imap_send (stream,"LOGOUT",NIL)))
+	mm_log (reply->text,WARN);
+    }
+				/* close NET connection if still open */
+    if (LOCAL->netstream) net_close (LOCAL->netstream);
+    LOCAL->netstream = NIL;
+				/* free up memory */
+    if (LOCAL->sortdata) fs_give ((void **) &LOCAL->sortdata);
+    if (LOCAL->namespace) {
+      mail_free_namespace (&LOCAL->namespace[0]);
+      mail_free_namespace (&LOCAL->namespace[1]);
+      mail_free_namespace (&LOCAL->namespace[2]);
+      fs_give ((void **) &LOCAL->namespace);
+    }
+    if (LOCAL->threaddata) mail_free_threadnode (&LOCAL->threaddata);
+				/* flush threaders */
+    if (thr = LOCAL->cap.threader) while (t = thr) {
+      fs_give ((void **) &t->name);
+      thr = t->next;
+      fs_give ((void **) &t);
+    }
+    if (LOCAL->referral) fs_give ((void **) &LOCAL->referral);
+    if (LOCAL->user) fs_give ((void **) &LOCAL->user);
+    if (LOCAL->reply.line) fs_give ((void **) &LOCAL->reply.line);
+    if (LOCAL->reform) fs_give ((void **) &LOCAL->reform);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+  }
+}
+
+/* IMAP fetch fast information
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ *
+ * Generally, imap_structure is preferred
+ */
+
+void imap_fast (MAILSTREAM *stream,char *sequence,long flags)
+{
+  IMAPPARSEDREPLY *reply = imap_fetch (stream,sequence,flags & FT_UID);
+  if (!imap_OK (stream,reply)) mm_log (reply->text,ERROR);
+}
+
+
+/* IMAP fetch flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ */
+
+void imap_flags (MAILSTREAM *stream,char *sequence,long flags)
+{				/* send "FETCH sequence FLAGS" */
+  char *cmd = (LEVELIMAP4 (stream) && (flags & FT_UID)) ? "UID FETCH":"FETCH";
+  IMAPPARSEDREPLY *reply;
+  IMAPARG *args[3],aseq,aatt;
+  if (LOCAL->loser) sequence = imap_reform_sequence (stream,sequence,
+						     flags & FT_UID);
+  aseq.type = SEQUENCE; aseq.text = (void *) sequence;
+  aatt.type = ATOM; aatt.text = (void *) "FLAGS";
+  args[0] = &aseq; args[1] = &aatt; args[2] = NIL;
+  if (!imap_OK (stream,reply = imap_send (stream,cmd,args)))
+    mm_log (reply->text,ERROR);
+}
+
+/* IMAP fetch overview
+ * Accepts: MAIL stream, sequence bits set
+ *	    pointer to overview return function
+ * Returns: T if successful, NIL otherwise
+ */
+
+long imap_overview (MAILSTREAM *stream,overview_t ofn)
+{
+  MESSAGECACHE *elt;
+  ENVELOPE *env;
+  OVERVIEW ov;
+  char *s,*t;
+  unsigned long i,start,last,len,slen;
+  if (!LOCAL->netstream) return NIL;
+				/* build overview sequence */
+  for (i = 1,len = start = last = 0,s = t = NIL; i <= stream->nmsgs; ++i)
+    if ((elt = mail_elt (stream,i))->sequence) {
+      if (!elt->private.msg.env) {
+	if (s) {		/* continuing a sequence */
+	  if (i == last + 1) last = i;
+	  else {		/* end of range */
+	    if (last != start) sprintf (t,":%lu,%lu",last,i);
+	    else sprintf (t,",%lu",i);
+	    if ((len - (slen = (t += strlen (t)) - s)) < 20) {
+	      fs_resize ((void **) &s,len += MAILTMPLEN);
+	      t = s + slen;	/* relocate current pointer */
+	    }
+	    start = last = i;	/* begin a new range */
+	  }
+	}
+	else {			/* first time, start new buffer */
+	  s = (char *) fs_get (len = MAILTMPLEN);
+	  sprintf (s,"%lu",start = last = i);
+	  t = s + strlen (s);	/* end of buffer */
+	}
+      }
+    }
+				/* last sequence */
+  if (last != start) sprintf (t,":%lu",last);
+  if (s) {			/* prefetch as needed */
+    imap_fetch (stream,s,FT_NEEDENV);
+    fs_give ((void **) &s);
+  }
+  ov.optional.lines = 0;	/* now overview each message */
+  ov.optional.xref = NIL;
+  if (ofn) for (i = 1; i <= stream->nmsgs; i++)
+    if (((elt = mail_elt (stream,i))->sequence) &&
+	(env = mail_fetch_structure (stream,i,NIL,NIL)) && ofn) {
+      ov.subject = env->subject;
+      ov.from = env->from;
+      ov.date = env->date;
+      ov.message_id = env->message_id;
+      ov.references = env->references;
+      ov.optional.octets = elt->rfc822_size;
+      (*ofn) (stream,mail_uid (stream,i),&ov,i);
+    }
+  return LONGT;
+}
+
+/* IMAP fetch structure
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to return body
+ *	    option flags
+ * Returns: envelope of this message, body returned in body value
+ *
+ * Fetches the "fast" information as well
+ */
+
+ENVELOPE *imap_structure (MAILSTREAM *stream,unsigned long msgno,BODY **body,
+			  long flags)
+{
+  unsigned long i,j,k,x;
+  char *s,seq[MAILTMPLEN],tmp[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  ENVELOPE **env;
+  BODY **b;
+  IMAPPARSEDREPLY *reply = NIL;
+  IMAPARG *args[3],aseq,aatt;
+  SEARCHSET *set = LOCAL->lookahead;
+  LOCAL->lookahead = NIL;
+  args[0] = &aseq; args[1] = &aatt; args[2] = NIL;
+  aseq.type = SEQUENCE; aseq.text = (void *) seq;
+  aatt.type = ATOM; aatt.text = NIL;
+  if (flags & FT_UID)		/* see if can find msgno from UID */
+    for (i = 1; i <= stream->nmsgs; i++)
+      if ((elt = mail_elt (stream,i))->private.uid == msgno) {
+	msgno = i;		/* found msgno, use it from now on */
+	flags &= ~FT_UID;	/* no longer a UID fetch */
+      }
+  sprintf (s = seq,"%lu",msgno);/* initial sequence */
+  if (LEVELIMAP4 (stream) && (flags & FT_UID)) {
+    /* UID fetching is requested and we can't map the UID to a message sequence
+     * number.  Assume that the message isn't cached at all.
+     */
+    if (!imap_OK (stream,reply = imap_fetch (stream,seq,FT_NEEDENV +
+					     (body ? FT_NEEDBODY : NIL) +
+					     (flags & (FT_UID + FT_NOHDRS)))))
+      mm_log (reply->text,ERROR);
+				/* now hunt for this UID */
+    for (i = 1; i <= stream->nmsgs; i++)
+      if ((elt = mail_elt (stream,i))->private.uid == msgno) {
+	if (body) *body = elt->private.msg.body;
+	return elt->private.msg.env;
+      }
+    if (body) *body = NIL;	/* can't find the UID */
+    return NIL;
+  }
+  elt = mail_elt (stream,msgno);/* get cache pointer */
+  if (stream->scache) {		/* short caching? */
+    env = &stream->env;		/* use temporaries on the stream */
+    b = &stream->body;
+    if (msgno != stream->msgno){/* flush old poop if a different message */
+      mail_free_envelope (env);
+      mail_free_body (b);
+      stream->msgno = msgno;	/* this is now the current short cache msg */
+    }
+  }
+
+  else {			/* normal cache */
+    env = &elt->private.msg.env;/* get envelope and body pointers */
+    b = &elt->private.msg.body;
+				/* prefetch if don't have envelope */
+    if (!(flags & FT_NOLOOKAHEAD) &&
+	((!*env || (*env)->incomplete) ||
+	 (body && !*b && LEVELIMAP2bis (stream)))) {
+      if (set) {		/* have a lookahead list? */
+	MESSAGE *msg;
+	for (k = imap_fetchlookaheadlimit;
+	     k && set && (((s += strlen (s)) - seq) < (MAXCOMMAND - 30));
+	     set = set->next) {
+	  i = (set->first == 0xffffffff) ? stream->nmsgs :
+	    min (set->first,stream->nmsgs);
+	  if (j = (set->last == 0xffffffff) ? stream->nmsgs :
+	      min (set->last,stream->nmsgs)) {
+	    if (i > j) {	/* swap the range if backwards */
+	      x = i; i = j; j = x;
+	    }
+				/* find first message not msgno or in cache */
+	    while (((i == msgno) ||
+		    ((msg = &(mail_elt (stream,i)->private.msg))->env &&
+		     (!body || msg->body))) && (i++ < j));
+				/* until range or lookahead finished */
+	    while (k && (i <= j)) {
+				/* find first cached message in range */
+	      for (x = i + 1; (x <= j) &&
+		     !((msg = &(mail_elt (stream,x)->private.msg))->env &&
+		       (!body || msg->body)); x++);
+	      if (i == --x) {	/* only one message? */
+		sprintf (s += strlen (s),",%lu",i++);
+		k--;		/* prefetching one message */
+	      }
+	      else {		/* a range to prefetch */
+		sprintf (s += strlen (s),",%lu:%lu",i,x);
+		i = 1 + x - i;	/* number of messages in this range */
+				/* still can look ahead some more? */
+		if (k = (k > i) ? k - i : 0)
+				/* yes, scan further in this range */
+		  for (i = x + 2; (i <= j) &&
+			 ((i == msgno) || 
+			  ((msg = &(mail_elt (stream,i)->private.msg))->env &&
+			   (!body || msg->body)));
+		       i++);
+	      }
+	    }
+	  }
+	  else if ((i != msgno) && !mail_elt (stream,i)->private.msg.env) {
+	    sprintf (s += strlen (s),",%lu",i);
+	    k--;		/* prefetching one message */
+	  }
+      }
+      }
+				/* build message number list */
+      else for (i = msgno+1,k = imap_lookahead; k && (i <= stream->nmsgs); i++)
+	if (!mail_elt (stream,i)->private.msg.env) {
+	  s += strlen (s);	/* find string end, see if nearing end */
+	  if ((s - seq) > (MAILTMPLEN - 20)) break;
+	  sprintf (s,",%lu",i);	/* append message */
+ 	  for (j = i + 1, k--;	/* hunt for last message without an envelope */
+	       k && (j <= stream->nmsgs) &&
+	       !mail_elt (stream,j)->private.msg.env; j++, k--);
+				/* if different, make a range */
+	  if (i != --j) sprintf (s + strlen (s),":%lu",i = j);
+	}
+    }
+  }
+
+  if (!stream->lock) {		/* no-op if stream locked */
+    /* Build the fetch attributes.  Unlike imap_fetch(), this tries not to
+     * fetch data that is already cached.  However, since it is based on the
+     * message requested and not on any of the prefetched messages, it can
+     * goof, either by fetching data already cached or not prefetching data
+     * that isn't cached (but was cached in the message requested).
+     * Fortunately, no great harm is done.  If it doesn't prefetch the data,
+     * it will get it when the affected message(s) are requested.
+     */
+    if (!elt->private.uid && LEVELIMAP4 (stream)) strcpy (tmp," UID");
+    else tmp[0] = '\0';		/* initialize command */
+				/* need envelope? */
+    if (!*env || (*env)->incomplete) {
+      strcat (tmp," ENVELOPE");	/* yes, get it and possible extra poop */
+      if (!(flags & FT_NOHDRS) && LEVELIMAP4rev1 (stream)) {
+	if (imap_extrahdrs) sprintf (tmp + strlen (tmp)," %s %s %s",
+				     hdrheader[LOCAL->cap.extlevel],
+				     imap_extrahdrs,hdrtrailer);
+	else sprintf (tmp + strlen (tmp)," %s %s",
+		      hdrheader[LOCAL->cap.extlevel],hdrtrailer);
+      }
+    }
+				/* need body? */
+    if (body && !*b && LEVELIMAP2bis (stream))
+      strcat (tmp,LEVELIMAP4 (stream) ? " BODYSTRUCTURE" : " BODY");
+    if (!elt->day) strcat (tmp," INTERNALDATE");
+    if (!elt->rfc822_size) strcat (tmp," RFC822.SIZE");
+    if (tmp[0]) {		/* anything to do? */
+      tmp[0] = '(';		/* make into a list */
+      strcat (tmp," FLAGS)");	/* always get current flags */
+      aatt.text = (void *) tmp;	/* do the built command */
+      if (!imap_OK (stream,reply = imap_send (stream,"FETCH",args))) {
+				/* failed, probably RFC-1176 server */
+	if (!LEVELIMAP4 (stream) && LEVELIMAP2bis (stream) && body && !*b){
+	  aatt.text = (void *) "ALL";
+	  if (imap_OK (stream,reply = imap_send (stream,"FETCH",args)))
+				/* doesn't have body capabilities */
+	    LOCAL->cap.imap2bis = NIL;
+	  else mm_log (reply->text,ERROR);
+	}
+	else mm_log (reply->text,ERROR);
+      }
+    }
+  }
+  if (body) {			/* wants to return body */
+    if (!*b && !LEVELIMAP2bis (stream)) {
+				/* simulate body structure fetch for IMAP2 */
+      *b = mail_initbody (mail_newbody ());
+      (*b)->subtype = cpystr (rfc822_default_subtype ((*b)->type));
+      ((*b)->parameter = mail_newbody_parameter ())->attribute =
+	cpystr ("CHARSET");
+      (*b)->parameter->value = cpystr ("US-ASCII");
+      s = mail_fetch_text (stream,msgno,NIL,&i,flags);
+      (*b)->size.bytes = i;
+      while (i--) if (*s++ == '\n') (*b)->size.lines++;
+    }
+    *body = *b;			/* return the body */
+  }
+  return *env;			/* return the envelope */
+}
+
+/* IMAP fetch message data
+ * Accepts: MAIL stream
+ *	    message number
+ *	    section specifier
+ *	    offset of first designated byte or 0 to start at beginning
+ *	    maximum number of bytes or 0 for all bytes
+ *	    lines to fetch if header
+ *	    flags
+ * Returns: T on success, NIL on failure
+ */
+
+long imap_msgdata (MAILSTREAM *stream,unsigned long msgno,char *section,
+		   unsigned long first,unsigned long last,STRINGLIST *lines,
+		   long flags)
+{
+  int i;
+  char *t,tmp[MAILTMPLEN],partial[40],seq[40];
+  char *noextend,*nopartial,*nolines,*nopeek,*nononpeek;
+  char *cmd = (LEVELIMAP4 (stream) && (flags & FT_UID)) ? "UID FETCH":"FETCH";
+  IMAPPARSEDREPLY *reply;
+  IMAPARG *args[5],*auxargs[3],aseq,aatt,alns,acls,aflg;
+  noextend = nopartial = nolines = nopeek = nononpeek = NIL;
+				/* does searching desire a lookahead? */
+  if ((flags & FT_SEARCHLOOKAHEAD) && (msgno < stream->nmsgs) &&
+      !stream->scache) {
+    sprintf (seq,"%lu:%lu",msgno,
+	     (unsigned long) min (msgno + IMAPLOOKAHEAD,stream->nmsgs));
+    aseq.type = SEQUENCE;
+    aseq.text = (void *) seq;
+  }
+  else {			/* no, do it the easy way */
+    aseq.type = NUMBER;
+    aseq.text = (void *) msgno;
+  }
+  aatt.type = ATOM;		/* assume atomic attribute */
+  alns.type = LIST; alns.text = (void *) lines;
+  acls.type = BODYCLOSE; acls.text = (void *) partial;
+  aflg.type = ATOM; aflg.text = (void *) "FLAGS";
+  args[0] = &aseq; args[1] = &aatt; args[2] = args[3] = args[4] = NIL;
+  auxargs[0] = &aseq; auxargs[1] = &aflg; auxargs[2] = NIL;
+  partial[0] = '\0';		/* initially no partial specifier */
+  if (LEVELIMAP4rev1 (stream)) {/* easy if IMAP4rev1 server */
+				/* HEADER fetching with special handling? */
+    if (!strcmp (section,"HEADER") && (lines || (flags & FT_PREFETCHTEXT))) {
+      if (lines) {		/* want specific header lines? */
+	aatt.type = (flags & FT_PEEK) ? BODYPEEK : BODYTEXT;
+	aatt.text = (void *) ((flags & FT_NOT) ?
+			      "HEADER.FIELDS.NOT" : "HEADER.FIELDS");
+	args[2] = &alns; args[3] = &acls;
+      }
+				/* must be prefetching */
+      else aatt.text = (void *) ((flags & FT_PEEK) ?
+				 "(BODY.PEEK[HEADER] BODY.PEEK[TEXT])" :
+				 "(BODY[HEADER] BODY[TEXT])");
+    }
+    else {			/* simple case */
+      aatt.type = (flags & FT_PEEK) ? BODYPEEK : BODYTEXT;
+      aatt.text = (void *) section;
+      args[2] = &acls;
+    }
+    if (first || last) sprintf (partial,"<%lu.%lu>",first,last ? last:-1);
+  }
+
+  /* IMAP4 did not have:
+   * . HEADER body part (can simulate with BODY[0] or BODY.PEEK[0])
+   * . TEXT body part (can simulate top-level with RFC822.TEXT or
+   *			RFC822.TEXT.PEEK)
+   * . MIME body part
+   * . (usable) partial fetching
+   * . (usable) selective header line fetching
+   */
+  else if (LEVEL1730 (stream)) {/* IMAP4 (RFC 1730) compatibility */
+				/* BODY[HEADER] becomes BODY.PEEK[0] */
+    if (!strcmp (section,"HEADER"))
+      aatt.text = (void *)
+	((flags & FT_PREFETCHTEXT) ?
+	 ((flags & FT_PEEK) ? "(BODY.PEEK[0] RFC822.TEXT.PEEK)" :
+	  "(BODY[0] RFC822.TEXT)") :
+	 ((flags & FT_PEEK) ? "BODY.PEEK[0]" : "BODY[0]"));
+				/* BODY[TEXT] becomes RFC822.TEXT */
+    else if (!strcmp (section,"TEXT"))
+      aatt.text = (void *) ((flags & FT_PEEK) ? "RFC822.TEXT.PEEK" :
+			    "RFC822.TEXT");
+    else if (!section[0])	/* BODY[] becomes RFC822 */
+      aatt.text = (void *) ((flags & FT_PEEK) ? "RFC822.PEEK" : "RFC822");
+				/* nested header */
+    else if (t = strstr (section,".HEADER")) {
+      aatt.type = (flags & FT_PEEK) ? BODYPEEK : BODYTEXT;
+      args[2] = &acls;		/* will need to close section */
+      aatt.text = (void *) tmp;	/* convert .HEADER to .0 */
+      strncpy (tmp,section,t-section);
+      strcpy (tmp+(t-section),".0");
+    }
+    else {			/* IMAP4 body part */
+      aatt.type = (flags & FT_PEEK) ? BODYPEEK : BODYTEXT;
+      args[2] = &acls;		/* will need to close section */
+      aatt.text = (void *) section;
+    }
+    if (strstr (section,".MIME") || strstr (section,".TEXT")) noextend = "4";
+    if (first || last) nopartial = "4";
+    if (lines) nolines = "4";
+  }
+
+  /* IMAP2bis did not have:
+   * . HEADER body part (can simulate peeking top-level with RFC822.HEADER)
+   * . TEXT body part (can simulate non-peeking top-level with RFC822.TEXT)
+   * . MIME body part
+   * . partial fetching
+   * . selective header line fetching
+   * . non-peeking header fetching
+   * . peeking body fetching
+   */
+				/* IMAP2bis compatibility */
+  else if (LEVELIMAP2bis (stream)) {
+				/* BODY[HEADER] becomes RFC822.HEADER */
+    if (!strcmp (section,"HEADER")) {
+      aatt.text = (void *)
+	((flags & FT_PREFETCHTEXT) ?
+	 "(RFC822.HEADER RFC822.TEXT)" : "RFC822.HEADER");
+      if (flags & FT_PEEK) flags &= ~FT_PEEK;
+      else nononpeek = "2bis";
+    }
+				/* BODY[TEXT] becomes RFC822.TEXT */
+    else if (!strcmp (section,"TEXT")) aatt.text = (void *) "RFC822.TEXT";
+				/* BODY[] becomes RFC822 */
+    else if (!section[0]) aatt.text = (void *) "RFC822";
+    else {			/* IMAP2bis body part */
+      aatt.type = BODYTEXT;
+      args[2] = &acls;		/* will need to close section */
+      aatt.text = (void *) section;
+    }
+    if (strstr (section,".HEADER") || strstr (section,".MIME") ||
+	     strstr (section,".TEXT")) noextend = "2bis";
+    if (first || last) nopartial = "2bis";
+    if (lines) nolines = "2bis";
+    if (flags & FT_PEEK) nopeek = "2bis";
+  }
+
+  /* IMAP2 did not have:
+   * . HEADER body part (can simulate peeking top-level with RFC822.HEADER)
+   * . TEXT body part (can simulate non-peeking top-level with RFC822.TEXT)
+   * . MIME body part
+   * . multiple body parts (can simulate BODY[1] with RFC822.TEXT)
+   * . partial fetching
+   * . selective header line fetching
+   * . non-peeking header fetching
+   * . peeking body fetching
+   */
+  else {			/* IMAP2 (RFC 1176/1064) compatibility */
+				/* BODY[HEADER] */
+    if (!strcmp (section,"HEADER")) {
+      aatt.text = (void *) ((flags & FT_PREFETCHTEXT) ?
+			    "(RFC822.HEADER RFC822.TEXT)" : "RFC822.HEADER");
+      if (flags & FT_PEEK) flags &= ~FT_PEEK;
+      nononpeek = "2";
+    }
+				/* BODY[TEXT] becomes RFC822.TEXT */
+    else if (!strcmp (section,"TEXT")) aatt.text = (void *) "RFC822.TEXT";
+				/* BODY[1] treated like RFC822.TEXT */
+    else if (!strcmp (section,"1")) {
+      SIZEDTEXT text;
+      MESSAGECACHE *elt = mail_elt (stream,msgno);
+				/* have a cached RFC822.TEXT? */
+      if (elt->private.msg.text.text.data) {
+	text.size = elt->private.msg.text.text.size;
+				/* should move instead of copy */
+	text.data = memcpy (fs_get (text.size+1),
+			    elt->private.msg.text.text.data,text.size);
+	(t = (char *) text.data)[text.size] = '\0';
+	imap_cache (stream,msgno,"1",NIL,&text);
+	return LONGT;		/* don't have to do any fetches */
+      }
+				/* otherwise do RFC822.TEXT */
+      aatt.text = (void *) "RFC822.TEXT";
+    }
+				/* BODY[] becomes RFC822 */
+    else if (!section[0]) aatt.text = (void *) "RFC822";
+    else noextend = "2";	/* how did we get here? */
+    if (flags & FT_PEEK) nopeek = "2";
+    if (first || last) nopartial = "2";
+    if (lines) nolines = "2";
+  }
+
+  /* Report unavailable functionalities.  The application can use the helpful
+   * LEVELIMAPREV1, LEVELIMAP4, and LEVELIMAP2bis operations provided in
+   * imap4r1.h to avoid triggering these errors.  There aren't any workarounds
+   * for these restrictions.
+   */
+  if (noextend) {
+    sprintf (tmp,"[NOTIMAP4REV1] IMAP%s server can't do extended body fetch",
+	     noextend);
+    mm_log (tmp,ERROR);
+    return NIL;			/* can't do anything close either */
+  }
+  if (nopartial) {
+    sprintf (tmp,"[NOTIMAP4REV1] IMAP%s server can't do partial fetch",
+	     nopartial);
+    mm_notify (stream,tmp,WARN);
+  }
+  if (nolines) {
+    sprintf(tmp,"[NOTIMAP4REV1] IMAP%s server can't do selective header fetch",
+	    nolines);
+    mm_notify (stream,tmp,WARN);
+  }
+
+				/* trying to do unsupported peek behavior? */
+  if ((t = nopeek) || (t = nononpeek)) {
+				/* get most recent \Seen setting */
+    if (!imap_OK (stream,reply = imap_send (stream,cmd,auxargs)))
+      mm_log (reply->text,WARN);
+				/* note current setting of \Seen flag */
+    if (!(i = mail_elt (stream,msgno)->seen)) {
+      sprintf (tmp,nopeek ?	/* only babble if \Seen not set */
+	       "[NOTIMAP4] Simulating peeking fetch in IMAP%s" :
+	       "[NOTIMAP4] Simulating non-peeking header fetch in IMAP%s",t);
+      mm_notify (stream,tmp,NIL);
+    }
+				/* send the fetch command */
+    if (!imap_OK (stream,reply = imap_send (stream,cmd,args))) {
+      mm_log (reply->text,ERROR);
+      return NIL;		/* failure */
+    }
+				/* send command if need to reset \Seen */
+    if (((nopeek && !i && mail_elt (stream,msgno)->seen &&
+	  (aflg.text = "-FLAGS \\Seen")) ||
+	 ((nononpeek && !mail_elt (stream,msgno)->seen) &&
+	  (aflg.text = "+FLAGS \\Seen"))) &&
+	!imap_OK (stream,reply = imap_send (stream,"STORE",auxargs)))
+      mm_log (reply->text,WARN);
+  }
+				/* simple case if traditional behavior */
+  else if (!imap_OK (stream,reply = imap_send (stream,cmd,args))) {
+    mm_log (reply->text,ERROR);
+    return NIL;			/* failure */
+  }
+				/* simulate BODY[1] return for RFC 1064/1176 */
+  if (!LEVELIMAP2bis (stream) && !strcmp (section,"1")) {
+    SIZEDTEXT text;
+    MESSAGECACHE *elt = mail_elt (stream,msgno);
+    text.size = elt->private.msg.text.text.size;
+				/* should move instead of copy */
+    text.data = memcpy (fs_get (text.size+1),elt->private.msg.text.text.data,
+			text.size);
+    (t = (char *) text.data)[text.size] = '\0';
+    imap_cache (stream,msgno,"1",NIL,&text);
+  }
+  return LONGT;
+}
+
+/* IMAP fetch UID
+ * Accepts: MAIL stream
+ *	    message number
+ * Returns: UID
+ */
+
+unsigned long imap_uid (MAILSTREAM *stream,unsigned long msgno)
+{
+  MESSAGECACHE *elt;
+  IMAPPARSEDREPLY *reply;
+  IMAPARG *args[3],aseq,aatt;
+  char *s,seq[MAILTMPLEN];
+  unsigned long i,j,k;
+				/* IMAP2 didn't have UIDs */
+  if (!LEVELIMAP4 (stream)) return msgno;
+				/* do we know its UID yet? */
+  if (!(elt = mail_elt (stream,msgno))->private.uid) {
+    aseq.type = SEQUENCE; aseq.text = (void *) seq;
+    aatt.type = ATOM; aatt.text = (void *) "UID";
+    args[0] = &aseq; args[1] = &aatt; args[2] = NIL;
+    sprintf (seq,"%lu",msgno);
+    if (k = imap_uidlookahead) {/* build UID list */
+      for (i = msgno + 1, s = seq; k && (i <= stream->nmsgs); i++)
+	if (!mail_elt (stream,i)->private.uid) {
+	  s += strlen (s);	/* find string end, see if nearing end */
+	  if ((s - seq) > (MAILTMPLEN - 20)) break;
+	  sprintf (s,",%lu",i);	/* append message */
+	  for (j = i + 1, k--;	/* hunt for last message without a UID */
+	       k && (j <= stream->nmsgs) && !mail_elt (stream,j)->private.uid;
+	       j++, k--);
+				/* if different, make a range */
+	  if (i != --j) sprintf (s + strlen (s),":%lu",i = j);
+	}
+    }
+				/* send "FETCH msgno UID" */
+    if (!imap_OK (stream,reply = imap_send (stream,"FETCH",args)))
+      mm_log (reply->text,ERROR);
+  }
+  return elt->private.uid;	/* return our UID now */
+}
+
+/* IMAP fetch message number from UID
+ * Accepts: MAIL stream
+ *	    UID
+ * Returns: message number
+ */
+
+unsigned long imap_msgno (MAILSTREAM *stream,unsigned long uid)
+{
+  IMAPPARSEDREPLY *reply;
+  IMAPARG *args[3],aseq,aatt;
+  char seq[MAILTMPLEN];
+  int holes = 0;
+  unsigned long i,msgno;
+				/* IMAP2 didn't have UIDs */
+  if (!LEVELIMAP4 (stream)) return uid;
+  /* This really should be a binary search, but since there are likely to be
+   * holes in the msgno->UID map it's hard to do.
+   */
+  for (msgno = 1; msgno <= stream->nmsgs; msgno++) {
+    if (!(i = mail_elt (stream,msgno)->private.uid)) holes = T;
+    else if (i == uid) return msgno;
+  }
+  if (holes) {			/* have holes in cache? */
+				/* yes, have server hunt for UID */
+    LOCAL->lastuid.uid = LOCAL->lastuid.msgno = 0;
+    aseq.type = SEQUENCE; aseq.text = (void *) seq;
+    aatt.type = ATOM; aatt.text = (void *) "UID";
+    args[0] = &aseq; args[1] = &aatt; args[2] = NIL;
+    sprintf (seq,"%lu",uid);
+				/* send "UID FETCH uid UID" */
+    if (!imap_OK (stream,reply = imap_send (stream,"UID FETCH",args)))
+      mm_log (reply->text,ERROR);
+    if (LOCAL->lastuid.uid) {	/* got any results from FETCH? */
+      if ((LOCAL->lastuid.uid == uid) &&
+				/* what, me paranoid? */
+	  (LOCAL->lastuid.msgno <= stream->nmsgs) &&
+	  (mail_elt (stream,LOCAL->lastuid.msgno)->private.uid == uid))
+				/* got it the easy way */
+	return LOCAL->lastuid.msgno;
+				/* sigh, do another linear search... */
+      for (msgno = 1; msgno <= stream->nmsgs; msgno++)
+	if (mail_elt (stream,msgno)->private.uid == uid) return msgno;
+    }
+  }
+  return 0;			/* didn't find the UID anywhere */
+}
+
+/* IMAP modify flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    flag(s)
+ *	    option flags
+ */
+
+void imap_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
+{
+  char *cmd = (LEVELIMAP4 (stream) && (flags & ST_UID)) ? "UID STORE":"STORE";
+  IMAPPARSEDREPLY *reply;
+  IMAPARG *args[4],aseq,ascm,aflg;
+  if (LOCAL->loser) sequence = imap_reform_sequence (stream,sequence,
+						     flags & ST_UID);
+  aseq.type = SEQUENCE; aseq.text = (void *) sequence;
+  ascm.type = ATOM; ascm.text = (void *)
+    ((flags & ST_SET) ?
+     ((LEVELIMAP4 (stream) && (flags & ST_SILENT)) ?
+      "+Flags.silent" : "+Flags") :
+     ((LEVELIMAP4 (stream) && (flags & ST_SILENT)) ?
+      "-Flags.silent" : "-Flags"));
+  aflg.type = FLAGS; aflg.text = (void *) flag;
+  args[0] = &aseq; args[1] = &ascm; args[2] = &aflg; args[3] = NIL;
+				/* send "STORE sequence +Flags flag" */
+  if (!imap_OK (stream,reply = imap_send (stream,cmd,args)))
+    mm_log (reply->text,ERROR);
+}
+
+/* IMAP search for messages
+ * Accepts: MAIL stream
+ *	    character set
+ *	    search program
+ *	    option flags
+ * Returns: T on success, NIL on failure
+ */
+
+long imap_search (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,long flags)
+{
+  unsigned long i,j,k;
+  char *s;
+  IMAPPARSEDREPLY *reply;
+  MESSAGECACHE *elt;
+  if ((flags & SE_NOSERVER) ||	/* if want to do local search */
+      LOCAL->loser ||		/* or loser */
+      (!LEVELIMAP4 (stream) &&	/* or old server but new functions... */
+       (charset || (flags & SE_UID) || pgm->msgno || pgm->uid || pgm->or ||
+	pgm->not || pgm->header || pgm->larger || pgm->smaller ||
+	pgm->sentbefore || pgm->senton || pgm->sentsince || pgm->draft ||
+	pgm->undraft || pgm->return_path || pgm->sender || pgm->reply_to ||
+	pgm->message_id || pgm->in_reply_to || pgm->newsgroups ||
+	pgm->followup_to || pgm->references)) ||
+      (!LEVELWITHIN (stream) && (pgm->older || pgm->younger))) {
+    if ((flags & SE_NOLOCAL) ||
+	!mail_search_default (stream,charset,pgm,flags | SE_NOSERVER))
+      return NIL;
+  }
+				/* do silly ALL or seq-only search locally */
+  else if (!(flags & (SE_NOLOCAL|SE_SILLYOK)) &&
+	   !(pgm->uid || pgm->or || pgm->not ||
+	     pgm->header || pgm->from || pgm->to || pgm->cc || pgm->bcc ||
+	     pgm->subject || pgm->body || pgm->text ||
+	     pgm->larger || pgm->smaller ||
+	     pgm->sentbefore || pgm->senton || pgm->sentsince ||
+	     pgm->before || pgm->on || pgm->since ||
+	     pgm->answered || pgm->unanswered ||
+	     pgm->deleted || pgm->undeleted || pgm->draft || pgm->undraft ||
+	     pgm->flagged || pgm->unflagged || pgm->recent || pgm->old ||
+	     pgm->seen || pgm->unseen ||
+	     pgm->keyword || pgm->unkeyword ||
+	     pgm->return_path || pgm->sender ||
+	     pgm->reply_to || pgm->in_reply_to || pgm->message_id ||
+	     pgm->newsgroups || pgm->followup_to || pgm->references)) {
+    if (!mail_search_default (stream,NIL,pgm,flags | SE_NOSERVER))
+      fatal ("impossible mail_search_default() failure");
+  }
+
+  else {			/* do server-based SEARCH */
+    char *cmd = (flags & SE_UID) ? "UID SEARCH" : "SEARCH";
+    IMAPARG *args[4],apgm,aatt,achs;
+    SEARCHSET *ss,*set;
+    args[1] = args[2] = args[3] = NIL;
+    apgm.type = SEARCHPROGRAM; apgm.text = (void *) pgm;
+    if (charset) {		/* optional charset argument requested */
+      args[0] = &aatt; args[1] = &achs; args[2] = &apgm;
+      aatt.type = ATOM; aatt.text = (void *) "CHARSET";
+      achs.type = ASTRING; achs.text = (void *) charset;
+    }
+    else args[0] = &apgm;	/* no charset argument */
+				/* tell receiver that these will be UIDs */
+    LOCAL->uidsearch = (flags & SE_UID) ? T : NIL;
+    reply = imap_send (stream,cmd,args);
+				/* did server barf with that searchpgm? */
+    if (!(flags & SE_UID) && pgm && (ss = pgm->msgno) &&
+	!strcmp (reply->key,"BAD")) {
+      LOCAL->filter = T;	/* retry, filtering SEARCH results */
+      for (i = 1; i <= stream->nmsgs; i++)
+	mail_elt (stream,i)->private.filter = NIL;
+      for (set = ss; set; set = set->next) if (i = set->first) {
+				/* single message becomes one-message range */
+	if (!(j = set->last)) j = i;
+	else if (j < i) {	/* swap reversed range */
+	  i = set->last; j = set->first;
+	}
+	while (i <= j) mail_elt (stream,i++)->private.filter = T;
+      }      
+      pgm->msgno = NIL;		/* and without the searchset */
+      reply = imap_send (stream,cmd,args);
+      pgm->msgno = ss;		/* restore searchset */
+      LOCAL->filter = NIL;	/* turn off filtering */
+    }
+    LOCAL->uidsearch = NIL;
+				/* do locally if server won't grok */
+    if (!strcmp (reply->key,"BAD")) {
+      if ((flags & SE_NOLOCAL) ||
+	  !mail_search_default (stream,charset,pgm,flags | SE_NOSERVER))
+	return NIL;
+    }
+    else if (!imap_OK (stream,reply)) {
+      mm_log (reply->text,ERROR);
+      return NIL;
+    }
+  }
+
+				/* can never pre-fetch with a short cache */
+  if ((k = imap_prefetch) && !(flags & (SE_NOPREFETCH | SE_UID)) &&
+      !stream->scache) {	/* only if prefetching permitted */
+    s = LOCAL->tmp;		/* build sequence in temporary buffer */
+    *s = '\0';			/* initially nothing */
+				/* search through mailbox */
+    for (i = 1; k && (i <= stream->nmsgs); ++i) 
+				/* for searched messages with no envelope */
+      if ((elt = mail_elt (stream,i)) && elt->searched &&
+	  !mail_elt (stream,i)->private.msg.env) {
+				/* prepend with comma if not first time */
+	if (LOCAL->tmp[0]) *s++ = ',';
+	sprintf (s,"%lu",j = i);/* output message number */
+	s += strlen (s);	/* point at end of string */
+	k--;			/* count one up */
+				/* search for possible end of range */
+	while (k && (i < stream->nmsgs) &&
+	       (elt = mail_elt (stream,i+1))->searched &&
+	       !elt->private.msg.env) i++,k--;
+	if (i != j) {		/* if a range */
+	  sprintf (s,":%lu",i);	/* output delimiter and end of range */
+	  s += strlen (s);	/* point at end of string */
+	}
+	if ((s - LOCAL->tmp) > (IMAPTMPLEN - 50)) break;
+      }
+    if (LOCAL->tmp[0]) {	/* anything to pre-fetch? */
+      /* pre-fetch envelopes for the first imap_prefetch number of messages */
+      if (!imap_OK (stream,reply =
+		    imap_fetch (stream,s = cpystr (LOCAL->tmp),FT_NEEDENV +
+				((flags & SE_NOHDRS) ? FT_NOHDRS : NIL) +
+				((flags & SE_NEEDBODY) ? FT_NEEDBODY : NIL))))
+	mm_log (reply->text,ERROR);
+      fs_give ((void **) &s);	/* flush copy of sequence */
+    }
+  }
+  return LONGT;
+}
+
+/* IMAP sort messages
+ * Accepts: mail stream
+ *	    character set
+ *	    search program
+ *	    sort program
+ *	    option flags
+ * Returns: vector of sorted message sequences or NIL if error
+ */
+
+unsigned long *imap_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
+			  SORTPGM *pgm,long flags)
+{
+  unsigned long i,j,start,last;
+  unsigned long *ret = NIL;
+  pgm->nmsgs = 0;		/* start off with no messages */
+				/* can use server-based sort? */
+  if (LEVELSORT (stream) && !(flags & SE_NOSERVER) &&
+      (!spg || (LEVELWITHIN (stream) || !(spg->older || spg->younger)))) {
+    char *cmd = (flags & SE_UID) ? "UID SORT" : "SORT";
+    IMAPARG *args[4],apgm,achs,aspg;
+    IMAPPARSEDREPLY *reply;
+    SEARCHSET *ss = NIL;
+    SEARCHPGM *tsp = NIL;
+    apgm.type = SORTPROGRAM; apgm.text = (void *) pgm;
+    achs.type = ASTRING; achs.text = (void *) (charset ? charset : "US-ASCII");
+    aspg.type = SEARCHPROGRAM;
+				/* did he provide a searchpgm? */
+    if (!(aspg.text = (void *) spg)) {
+      for (i = 1,start = last = 0; i <= stream->nmsgs; ++i)
+	if (mail_elt (stream,i)->searched) {
+	  if (ss) {		/* continuing a sequence */
+	    if (i == last + 1) last = i;
+	    else {		/* end of range */
+	      if (last != start) ss->last = last;
+	      (ss = ss->next = mail_newsearchset ())->first = i;
+	      start = last = i;	/* begin a new range */
+	    }
+	  }
+	  else {		/* first time, start new searchpgm */
+	    (tsp = mail_newsearchpgm ())->msgno = ss = mail_newsearchset ();
+	    ss->first = start = last = i;
+	  }
+	}
+				/* nothing to sort if no messages */
+      if (!(aspg.text = (void *) tsp)) return NIL;
+				/* else install last sequence */
+      if (last != start) ss->last = last;
+    }
+
+    args[0] = &apgm; args[1] = &achs; args[2] = &aspg; args[3] = NIL;
+				/* ask server to do it */
+    reply = imap_send (stream,cmd,args);
+    if (tsp) {			/* was there a temporary searchpgm? */
+      aspg.text = NIL;		/* yes, flush it */
+      mail_free_searchpgm (&tsp);
+				/* did server barf with that searchpgm? */
+      if (!(flags & SE_UID) && !strcmp (reply->key,"BAD")) {
+	LOCAL->filter = T;	/* retry, filtering SORT/THREAD results */
+	reply = imap_send (stream,cmd,args);
+	LOCAL->filter = NIL;	/* turn off filtering */
+      }
+    }
+				/* do locally if server barfs */
+    if (!strcmp (reply->key,"BAD"))
+      return (flags & SE_NOLOCAL) ? NIL :
+	imap_sort (stream,charset,spg,pgm,flags | SE_NOSERVER);
+				/* server sorted OK? */
+    else if (imap_OK (stream,reply)) {
+      pgm->nmsgs = LOCAL->sortsize;
+      ret = LOCAL->sortdata;
+      LOCAL->sortdata = NIL;	/* mail program is responsible for flushing */
+    }
+    else mm_log (reply->text,ERROR);
+  }
+
+				/* not much can do if short caching */
+  else if (stream->scache) ret = mail_sort_msgs (stream,charset,spg,pgm,flags);
+  else {			/* try to be a bit more clever */
+    char *s,*t;
+    unsigned long len;
+    MESSAGECACHE *elt;
+    SORTCACHE **sc;
+    SORTPGM *sp;
+    long ftflags = 0;
+				/* see if need envelopes */
+    for (sp = pgm; sp && !ftflags; sp = sp->next) switch (sp->function) {
+    case SORTDATE: case SORTFROM: case SORTSUBJECT: case SORTTO: case SORTCC:
+      ftflags = FT_NEEDENV + ((flags & SE_NOHDRS) ? FT_NOHDRS : NIL);
+    }
+    if (spg) {			/* only if a search needs to be done */
+      int silent = stream->silent;
+      stream->silent = T;	/* don't pass up mm_searched() events */
+				/* search for messages */
+      mail_search_full (stream,charset,spg,flags & SE_NOSERVER);
+      stream->silent = silent;	/* restore silence state */
+    }
+				/* initialize progress counters */
+    pgm->nmsgs = pgm->progress.cached = 0;
+				/* pass 1: count messages to sort */
+    for (i = 1,len = start = last = 0,s = t = NIL; i <= stream->nmsgs; ++i)
+      if ((elt = mail_elt (stream,i))->searched) {
+	pgm->nmsgs++;
+	if (ftflags ? !elt->private.msg.env : !elt->day) {
+	  if (s) {		/* continuing a sequence */
+	    if (i == last + 1) last = i;
+	    else {		/* end of range */
+	      if (last != start) sprintf (t,":%lu,%lu",last,i);
+	      else sprintf (t,",%lu",i);
+	      start = last = i;	/* begin a new range */
+	      if ((len - (j = ((t += strlen (t)) - s)) < 20)) {
+		fs_resize ((void **) &s,len += MAILTMPLEN);
+		t = s + j;	/* relocate current pointer */
+	      }
+	    }
+	  }
+	  else {		/* first time, start new buffer */
+	    s = (char *) fs_get (len = MAILTMPLEN);
+	    sprintf (s,"%lu",start = last = i);
+	    t = s + strlen (s);	/* end of buffer */
+	  }
+	}
+      }
+				/* last sequence */
+    if (last != start) sprintf (t,":%lu",last);
+    if (s) {			/* load cache for all messages being sorted */
+      imap_fetch (stream,s,ftflags);
+      fs_give ((void **) &s);
+    }
+    if (pgm->nmsgs) {		/* pass 2: sort cache */
+      sortresults_t sr = (sortresults_t)
+	mail_parameters (NIL,GET_SORTRESULTS,NIL);
+      sc = mail_sort_loadcache (stream,pgm);
+				/* pass 3: sort messages */
+      if (!pgm->abort) ret = mail_sort_cache (stream,pgm,sc,flags);
+      fs_give ((void **) &sc);	/* don't need sort vector any more */
+				/* also return via callback if requested */
+      if (sr) (*sr) (stream,ret,pgm->nmsgs);
+    }
+  }
+  return ret;
+}
+
+/* IMAP thread messages
+ * Accepts: mail stream
+ *	    thread type
+ *	    character set
+ *	    search program
+ *	    option flags
+ * Returns: thread node tree or NIL if error
+ */
+
+THREADNODE *imap_thread (MAILSTREAM *stream,char *type,char *charset,
+			 SEARCHPGM *spg,long flags)
+{
+  THREADER *thr;
+  if (!(flags & SE_NOSERVER) &&
+      (!spg || (LEVELWITHIN (stream) || !(spg->older || spg->younger))))
+				/* does server have this threader type? */
+    for (thr = LOCAL->cap.threader; thr; thr = thr->next)
+      if (!compare_cstring (thr->name,type)) 
+	return imap_thread_work (stream,type,charset,spg,flags);
+				/* server doesn't support it, do locally */
+  return (flags & SE_NOLOCAL) ? NIL: 
+    mail_thread_msgs (stream,type,charset,spg,flags | SE_NOSERVER,imap_sort);
+}
+
+/* IMAP thread messages worker routine
+ * Accepts: mail stream
+ *	    thread type
+ *	    character set
+ *	    search program
+ *	    option flags
+ * Returns: thread node tree
+ */
+
+THREADNODE *imap_thread_work (MAILSTREAM *stream,char *type,char *charset,
+			      SEARCHPGM *spg,long flags)
+{
+  unsigned long i,start,last;
+  char *cmd = (flags & SE_UID) ? "UID THREAD" : "THREAD";
+  IMAPARG *args[4],apgm,achs,aspg;
+  IMAPPARSEDREPLY *reply;
+  THREADNODE *ret = NIL;
+  SEARCHSET *ss = NIL;
+  SEARCHPGM *tsp = NIL;
+  apgm.type = ATOM; apgm.text = (void *) type;
+  achs.type = ASTRING;
+  achs.text = (void *) (charset ? charset : "US-ASCII");
+  aspg.type = SEARCHPROGRAM;
+				/* did he provide a searchpgm? */
+  if (!(aspg.text = (void *) spg)) {
+    for (i = 1,start = last = 0; i <= stream->nmsgs; ++i)
+      if (mail_elt (stream,i)->searched) {
+	if (ss) {		/* continuing a sequence */
+	  if (i == last + 1) last = i;
+	  else {		/* end of range */
+	    if (last != start) ss->last = last;
+	    (ss = ss->next = mail_newsearchset ())->first = i;
+	    start = last =i;	/* begin a new range */
+	  }
+	}
+	else {			/* first time, start new searchpgm */
+	  (tsp = mail_newsearchpgm ())->msgno = ss = mail_newsearchset ();
+	  ss->first = start = last = i;
+	}
+      }
+				/* nothing to sort if no messages */
+    if (!(aspg.text = (void *) tsp)) return NIL;
+				/* else install last sequence */
+    if (last != start) ss->last = last;
+  }
+
+  args[0] = &apgm; args[1] = &achs; args[2] = &aspg; args[3] = NIL;
+				/* ask server to do it */
+  reply = imap_send (stream,cmd,args);
+  if (tsp) {			/* was there a temporary searchpgm? */
+    aspg.text = NIL;		/* yes, flush it */
+    mail_free_searchpgm (&tsp);
+				/* did server barf with that searchpgm? */
+    if (!(flags & SE_UID) && !strcmp (reply->key,"BAD")) {
+      LOCAL->filter = T;	/* retry, filtering SORT/THREAD results */
+      reply = imap_send (stream,cmd,args);
+      LOCAL->filter = NIL;	/* turn off filtering */
+    }
+  }
+				/* do locally if server barfs */
+  if (!strcmp (reply->key,"BAD"))
+    ret = (flags & SE_NOLOCAL) ? NIL: 
+    mail_thread_msgs (stream,type,charset,spg,flags | SE_NOSERVER,imap_sort);
+				/* server threaded OK? */
+  else if (imap_OK (stream,reply)) {
+    ret = LOCAL->threaddata;
+    LOCAL->threaddata = NIL;	/* mail program is responsible for flushing */
+  }
+  else mm_log (reply->text,ERROR);
+  return ret;
+}
+
+/* IMAP ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream still alive, else NIL
+ */
+
+long imap_ping (MAILSTREAM *stream)
+{
+  return (LOCAL->netstream &&	/* send "NOOP" */
+	  imap_OK (stream,imap_send (stream,"NOOP",NIL))) ? T : NIL;
+}
+
+
+/* IMAP check mailbox
+ * Accepts: MAIL stream
+ */
+
+void imap_check (MAILSTREAM *stream)
+{
+				/* send "CHECK" */
+  IMAPPARSEDREPLY *reply = imap_send (stream,"CHECK",NIL);
+  mm_log (reply->text,imap_OK (stream,reply) ? (long) NIL : ERROR);
+}
+
+/* IMAP expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T if success, NIL if failure
+ */
+
+long imap_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  long ret = NIL;
+  IMAPPARSEDREPLY *reply = NIL;
+  if (sequence) {		/* wants selective expunging? */
+    if (options & EX_UID) {	/* UID EXPUNGE form? */
+      if (LEVELUIDPLUS (stream)) {/* server support UIDPLUS? */
+	IMAPARG *args[2],aseq;
+	aseq.type = SEQUENCE; aseq.text = (void *) sequence;
+	args[0] = &aseq; args[1] = NIL;
+	ret = imap_OK (stream,reply = imap_send (stream,"UID EXPUNGE",args));
+      }
+      else mm_log ("[NOTUIDPLUS] Can't do UID EXPUNGE with this server",ERROR);
+    }
+				/* otherwise try to make into UID EXPUNGE */
+    else if (mail_sequence (stream,sequence)) {
+      unsigned long i,j;
+      char *t = (char *) fs_get (IMAPTMPLEN);
+      char *s = t;
+				/* search through mailbox */
+      for (*s = '\0', i = 1; i <= stream->nmsgs; ++i)
+	if (mail_elt (stream,i)->sequence) {
+	  if (t[0]) *s++ = ',';	/* prepend with comma if not first time */
+	  sprintf (s,"%lu",mail_uid (stream,j = i));
+	  s += strlen (s);	/* point at end of string */
+				/* search for possible end of range */
+	  while ((i < stream->nmsgs) && mail_elt (stream,i+1)->sequence) i++;
+	  if (i != j) {		/* output end of range */
+	    sprintf (s,":%lu",mail_uid (stream,i));
+	    s += strlen (s);	/* point at end of string */
+	  }
+	  if ((s - t) > (IMAPTMPLEN - 50)) {
+	    mm_log ("Excessively complex sequence",ERROR);
+	    return NIL;
+	  }
+	}
+				/* now do as UID EXPUNGE */
+      ret = imap_expunge (stream,t,EX_UID);
+      fs_give ((void **) &t);
+    }
+  }
+				/* ordinary EXPUNGE */
+  else ret = imap_OK (stream,reply = imap_send (stream,"EXPUNGE",NIL));
+  if (reply) mm_log (reply->text,ret ? (long) NIL : ERROR);
+  return ret;
+}
+
+/* IMAP copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    option flags
+ * Returns: T if successful else NIL
+ */
+
+long imap_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long flags)
+{
+  char *cmd = (LEVELIMAP4 (stream) && (flags & CP_UID)) ? "UID COPY" : "COPY";
+  char *s;
+  long ret = NIL;
+  IMAPPARSEDREPLY *reply;
+  IMAPARG *args[3],aseq,ambx;
+  imapreferral_t ir =
+    (imapreferral_t) mail_parameters (stream,GET_IMAPREFERRAL,NIL);
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+  if (LOCAL->loser) sequence = imap_reform_sequence (stream,sequence,
+						     flags & CP_UID);
+  aseq.type = SEQUENCE; aseq.text = (void *) sequence;
+  ambx.type = ASTRING; ambx.text = (void *) mailbox;
+  args[0] = &aseq; args[1] = &ambx; args[2] = NIL;
+				/* note mailbox in case APPENDUID */
+  LOCAL->appendmailbox = mailbox;
+				/* send "COPY sequence mailbox" */
+  ret = imap_OK (stream,reply = imap_send (stream,cmd,args));
+  LOCAL->appendmailbox = NIL;	/* no longer appending */
+  if (ret) {			/* success, delete messages if move */
+    if (flags & CP_MOVE) imap_flag (stream,sequence,"\\Deleted",
+				    ST_SET + ((flags&CP_UID) ? ST_UID : NIL));
+  }
+				/* failed, do referral action if any */
+  else if (ir && pc && LOCAL->referral && mail_sequence (stream,sequence) &&
+	   (s = (*ir) (stream,LOCAL->referral,REFCOPY)))
+    ret = (*pc) (stream,sequence,s,flags | (stream->debug ? CP_DEBUG : NIL));
+				/* otherwise issue error message */
+  else mm_log (reply->text,ERROR);
+  return ret;
+}
+
+/* IMAP mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long imap_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  MAILSTREAM *st = stream;
+  IMAPARG *args[3],ambx,amap;
+  IMAPPARSEDREPLY *reply = NIL;
+  APPENDDATA map;
+  char tmp[MAILTMPLEN];
+  long debug = stream ? stream->debug : NIL;
+  long ret = NIL;
+  imapreferral_t ir =
+    (imapreferral_t) mail_parameters (stream,GET_IMAPREFERRAL,NIL);
+				/* mailbox must be good */
+  if (mail_valid_net (mailbox,&imapdriver,NIL,tmp)) {
+				/* create a stream if given one no good */
+    if ((stream && LOCAL && LOCAL->netstream) ||
+	(stream = mail_open (NIL,mailbox,OP_HALFOPEN|OP_SILENT |
+			     (debug ? OP_DEBUG : NIL)))) {
+				/* note mailbox in case APPENDUID */
+      LOCAL->appendmailbox = mailbox;
+				/* use multi-append? */
+      if (LEVELMULTIAPPEND (stream)) {
+	ambx.type = ASTRING; ambx.text = (void *) tmp;
+	amap.type = MULTIAPPEND; amap.text = (void *) &map;
+	map.af = af; map.data = data;
+	args[0] = &ambx; args[1] = &amap; args[2] = NIL;
+				/* success if OK */
+	ret = imap_OK (stream,reply = imap_send (stream,"APPEND",args));
+	LOCAL->appendmailbox = NIL;
+      }
+				/* do succession of single appends */
+      else while ((*af) (stream,data,&map.flags,&map.date,&map.message) &&
+		  map.message &&
+		  (ret = imap_OK (stream,reply =
+				  imap_append_single (stream,tmp,map.flags,
+						      map.date,map.message))));
+      LOCAL->appendmailbox = NIL;
+				/* don't do referrals if success or no reply */
+      if (ret || !reply) mailbox = NIL;
+				/* otherwise generate referral */
+      else if (!(mailbox = (ir && LOCAL->referral) ?
+		 (*ir) (stream,LOCAL->referral,REFAPPEND) : NIL))
+	mm_log (reply->text,ERROR);
+				/* close temporary stream */
+      if (st != stream) stream = mail_close (stream);
+      if (mailbox)		/* chase referral if any */
+	ret = imap_append_referral (mailbox,tmp,af,data,map.flags,map.date,
+				    map.message,&map,debug);
+    }
+    else mm_log ("Can't access server for append",ERROR);
+  }
+  return ret;			/* return */
+}
+
+/* IMAP mail append message referral retry
+ * Accepts: destination mailbox
+ *	    temporary buffer
+ *	    append callback
+ *	    data for callback
+ *	    flags from previous attempt
+ *	    date from previous attempt
+ *	    message stringstruct from previous attempt
+ *	    options (currently non-zero to set OP_DEBUG)
+ * Returns: T if append successful, else NIL
+ */
+
+long imap_append_referral (char *mailbox,char *tmp,append_t af,void *data,
+			   char *flags,char *date,STRING *message,
+			   APPENDDATA *map,long options)
+{
+  MAILSTREAM *stream;
+  IMAPARG *args[3],ambx,amap;
+  IMAPPARSEDREPLY *reply;
+  imapreferral_t ir =
+    (imapreferral_t) mail_parameters (NIL,GET_IMAPREFERRAL,NIL);
+				/* barf if bad mailbox */
+  while (mailbox && mail_valid_net (mailbox,&imapdriver,NIL,tmp)) {
+				/* create a stream if given one no good */
+    if (!(stream = mail_open (NIL,mailbox,OP_HALFOPEN|OP_SILENT |
+			      (options ? OP_DEBUG : NIL)))) {
+      sprintf (tmp,"Can't access referral server: %.80s",mailbox);
+      mm_log (tmp,ERROR);
+      return NIL;
+    }
+				/* got referral server, use multi-append? */
+    if (LEVELMULTIAPPEND (stream)) {
+      ambx.type = ASTRING; ambx.text = (void *) tmp;
+      amap.type = MULTIAPPENDREDO; amap.text = (void *) map;
+      args[0] = &ambx; args[1] = &amap; args[2] = NIL;
+				/* do multiappend on referral site */
+      if (imap_OK (stream,reply = imap_send (stream,"APPEND",args))) {
+	mail_close (stream);	/* multiappend OK, close stream */
+	return LONGT;		/* all done */
+      }
+    }
+				/* do multiple single appends */
+    else while (imap_OK (stream,reply =
+			 imap_append_single (stream,tmp,flags,date,message)))
+      if (!((*af) (stream,data,&flags,&date,&message) && message)) {
+	mail_close (stream);	/* last message, close stream */
+	return LONGT;		/* all done */
+      }
+				/* generate error if no nested referral */
+    if (!(mailbox = (ir && LOCAL->referral) ?
+	  (*ir) (stream,LOCAL->referral,REFAPPEND) : NIL))
+      mm_log (reply->text,ERROR);
+    mail_close (stream);	/* close previous referral stream */
+  }
+  return NIL;			/* bogus mailbox */
+}
+
+/* IMAP append single message
+ * Accepts: mail stream
+ *	    destination mailbox
+ *	    initial flags
+ *	    internal date
+ *	    stringstruct of message to append
+ * Returns: reply from append
+ */
+
+IMAPPARSEDREPLY *imap_append_single (MAILSTREAM *stream,char *mailbox,
+				     char *flags,char *date,STRING *message)
+{
+  MESSAGECACHE elt;
+  IMAPARG *args[5],ambx,aflg,adat,amsg;
+  IMAPPARSEDREPLY *reply;
+  char tmp[MAILTMPLEN];
+  int i;
+  ambx.type = ASTRING; ambx.text = (void *) mailbox;
+  args[i = 0] = &ambx;
+  if (flags) {
+    aflg.type = FLAGS; aflg.text = (void *) flags;
+    args[++i] = &aflg;
+  }
+  if (date) {			/* ensure date in INTERNALDATE format */
+    if (!mail_parse_date (&elt,date)) {
+				/* flush previous reply */
+      if (LOCAL->reply.line) fs_give ((void **) &LOCAL->reply.line);
+				/* build new fake reply */
+      LOCAL->reply.tag = LOCAL->reply.line = cpystr ("*");
+      LOCAL->reply.key = "BAD";
+      LOCAL->reply.text = "Bad date in append";
+      return &LOCAL->reply;
+    }
+    adat.type = ASTRING;
+    adat.text = (void *) (date = mail_date (tmp,&elt));
+    args[++i] = &adat;
+  }
+  amsg.type = LITERAL; amsg.text = (void *) message;
+  args[++i] = &amsg;
+  args[++i] = NIL;
+				/* easy if IMAP4[rev1] */
+  if (LEVELIMAP4 (stream)) reply = imap_send (stream,"APPEND",args);
+  else {			/* try the IMAP2bis way */
+    args[1] = &amsg; args[2] = NIL;
+    reply = imap_send (stream,"APPEND",args);
+  }
+  return reply;
+}
+
+/* IMAP garbage collect stream
+ * Accepts: Mail stream
+ *	    garbage collection flags
+ */
+
+void imap_gc (MAILSTREAM *stream,long gcflags)
+{
+  unsigned long i;
+  MESSAGECACHE *elt;
+  mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL);
+				/* make sure the cache is large enough */
+  (*mc) (stream,stream->nmsgs,CH_SIZE);
+  if (gcflags & GC_TEXTS) {	/* garbage collect texts? */
+    if (!stream->scache) for (i = 1; i <= stream->nmsgs; ++i)
+      if (elt = (MESSAGECACHE *) (*mc) (stream,i,CH_ELT))
+	imap_gc_body (elt->private.msg.body);
+    imap_gc_body (stream->body);
+  }
+				/* gc cache if requested and unlocked */
+  if (gcflags & GC_ELT) for (i = 1; i <= stream->nmsgs; ++i)
+    if ((elt = (MESSAGECACHE *) (*mc) (stream,i,CH_ELT)) &&
+	(elt->lockcount == 1)) (*mc) (stream,i,CH_FREE);
+}
+
+/* IMAP garbage collect body texts
+ * Accepts: body to GC
+ */
+
+void imap_gc_body (BODY *body)
+{
+  PART *part;
+  if (body) {			/* have a body? */
+    if (body->mime.text.data)	/* flush MIME data */
+      fs_give ((void **) &body->mime.text.data);
+				/* flush text contents */
+    if (body->contents.text.data)
+      fs_give ((void **) &body->contents.text.data);
+    body->mime.text.size = body->contents.text.size = 0;
+				/* multipart? */
+    if (body->type == TYPEMULTIPART)
+      for (part = body->nested.part; part; part = part->next)
+	imap_gc_body (&part->body);
+				/* MESSAGE/RFC822? */
+    else if ((body->type == TYPEMESSAGE) && !strcmp (body->subtype,"RFC822")) {
+      imap_gc_body (body->nested.msg->body);
+      if (body->nested.msg->full.text.data)
+	fs_give ((void **) &body->nested.msg->full.text.data);
+      if (body->nested.msg->header.text.data)
+	fs_give ((void **) &body->nested.msg->header.text.data);
+      if (body->nested.msg->text.text.data)
+	fs_give ((void **) &body->nested.msg->text.text.data);
+      body->nested.msg->full.text.size = body->nested.msg->header.text.size =
+	body->nested.msg->text.text.size = 0;
+    }
+  }
+}
+
+/* IMAP get capabilities
+ * Accepts: mail stream
+ */
+
+void imap_capability (MAILSTREAM *stream)
+{
+  THREADER *thr,*t;
+  LOCAL->gotcapability = NIL;	/* flush any previous capabilities */
+				/* request new capabilities */
+  imap_send (stream,"CAPABILITY",NIL);
+  if (!LOCAL->gotcapability) {	/* did server get any? */
+				/* no, flush threaders just in case */
+    if (thr = LOCAL->cap.threader) while (t = thr) {
+      fs_give ((void **) &t->name);
+      thr = t->next;
+      fs_give ((void **) &t);
+    }
+				/* zap most capabilities */
+    memset (&LOCAL->cap,0,sizeof (LOCAL->cap));
+				/* assume IMAP2bis server if failure */
+    LOCAL->cap.imap2bis = LOCAL->cap.rfc1176 = T;
+  }
+}
+
+/* IMAP set ACL
+ * Accepts: mail stream
+ *	    mailbox name
+ *	    authentication identifer
+ *	    new access rights
+ * Returns: T on success, NIL on failure
+ */
+
+long imap_setacl (MAILSTREAM *stream,char *mailbox,char *id,char *rights)
+{
+  IMAPARG *args[4],ambx,aid,art;
+  ambx.type = aid.type = art.type = ASTRING;
+  ambx.text = (void *) mailbox; aid.text = (void *) id;
+  art.text = (void *) rights;
+  args[0] = &ambx; args[1] = &aid; args[2] = &art; args[3] = NIL;
+  return imap_acl_work (stream,"SETACL",args);
+}
+
+
+/* IMAP delete ACL
+ * Accepts: mail stream
+ *	    mailbox name
+ *	    authentication identifer
+ * Returns: T on success, NIL on failure
+ */
+
+long imap_deleteacl (MAILSTREAM *stream,char *mailbox,char *id)
+{
+  IMAPARG *args[3],ambx,aid;
+  ambx.type = aid.type = ASTRING;
+  ambx.text = (void *) mailbox; aid.text = (void *) id;
+  args[0] = &ambx; args[1] = &aid; args[2] = NIL;
+  return imap_acl_work (stream,"DELETEACL",args);
+}
+
+
+/* IMAP get ACL
+ * Accepts: mail stream
+ *	    mailbox name
+ * Returns: T on success with data returned via callback, NIL on failure
+ */
+
+long imap_getacl (MAILSTREAM *stream,char *mailbox)
+{
+  IMAPARG *args[2],ambx;
+  ambx.type = ASTRING; ambx.text = (void *) mailbox;
+    args[0] = &ambx; args[1] = NIL;
+  return imap_acl_work (stream,"GETACL",args);
+}
+
+/* IMAP list rights
+ * Accepts: mail stream
+ *	    mailbox name
+ *	    authentication identifer
+ * Returns: T on success with data returned via callback, NIL on failure
+ */
+
+long imap_listrights (MAILSTREAM *stream,char *mailbox,char *id)
+{
+  IMAPARG *args[3],ambx,aid;
+  ambx.type = aid.type = ASTRING;
+  ambx.text = (void *) mailbox; aid.text = (void *) id;
+  args[0] = &ambx; args[1] = &aid; args[2] = NIL;
+  return imap_acl_work (stream,"LISTRIGHTS",args);
+}
+
+
+/* IMAP my rights
+ * Accepts: mail stream
+ *	    mailbox name
+ * Returns: T on success with data returned via callback, NIL on failure
+ */
+
+long imap_myrights (MAILSTREAM *stream,char *mailbox)
+{
+  IMAPARG *args[2],ambx;
+  ambx.type = ASTRING; ambx.text = (void *) mailbox;
+  args[0] = &ambx; args[1] = NIL;
+  return imap_acl_work (stream,"MYRIGHTS",args);
+}
+
+
+/* IMAP ACL worker routine
+ * Accepts: mail stream
+ *	    command
+ *	    command arguments
+ * Returns: T on success, NIL on failure
+ */
+
+long imap_acl_work (MAILSTREAM *stream,char *command,IMAPARG *args[])
+{
+  long ret = NIL;
+  if (LEVELACL (stream)) {	/* send command */
+    IMAPPARSEDREPLY *reply;
+    if (imap_OK (stream,reply = imap_send (stream,command,args)))
+      ret = LONGT;
+    else mm_log (reply->text,ERROR);
+  }
+  else mm_log ("ACL not available on this IMAP server",ERROR);
+  return ret;
+}
+
+/* IMAP set quota
+ * Accepts: mail stream
+ *	    quota root name
+ *	    resource limit list as a stringlist
+ * Returns: T on success with data returned via callback, NIL on failure
+ */
+
+long imap_setquota (MAILSTREAM *stream,char *qroot,STRINGLIST *limits)
+{
+  long ret = NIL;
+  if (LEVELQUOTA (stream)) {	/* send "SETQUOTA" */
+    IMAPPARSEDREPLY *reply;
+    IMAPARG *args[3],aqrt,alim;
+    aqrt.type = ASTRING; aqrt.text = (void *) qroot;
+    alim.type = SNLIST; alim.text = (void *) limits;
+    args[0] = &aqrt; args[1] = &alim; args[2] = NIL;
+    if (imap_OK (stream,reply = imap_send (stream,"SETQUOTA",args)))
+      ret = LONGT;
+    else mm_log (reply->text,ERROR);
+  }
+  else mm_log ("Quota not available on this IMAP server",ERROR);
+  return ret;
+}
+
+/* IMAP get quota
+ * Accepts: mail stream
+ *	    quota root name
+ * Returns: T on success with data returned via callback, NIL on failure
+ */
+
+long imap_getquota (MAILSTREAM *stream,char *qroot)
+{
+  long ret = NIL;
+  if (LEVELQUOTA (stream)) {	/* send "GETQUOTA" */
+    IMAPPARSEDREPLY *reply;
+    IMAPARG *args[2],aqrt;
+    aqrt.type = ASTRING; aqrt.text = (void *) qroot;
+    args[0] = &aqrt; args[1] = NIL;
+    if (imap_OK (stream,reply = imap_send (stream,"GETQUOTA",args)))
+      ret = LONGT;
+    else mm_log (reply->text,ERROR);
+  }
+  else mm_log ("Quota not available on this IMAP server",ERROR);
+  return ret;
+}
+
+
+/* IMAP get quota root
+ * Accepts: mail stream
+ *	    mailbox name
+ * Returns: T on success with data returned via callback, NIL on failure
+ */
+
+long imap_getquotaroot (MAILSTREAM *stream,char *mailbox)
+{
+  long ret = NIL;
+  if (LEVELQUOTA (stream)) {	/* send "GETQUOTAROOT" */
+    IMAPPARSEDREPLY *reply;
+    IMAPARG *args[2],ambx;
+    ambx.type = ASTRING; ambx.text = (void *) mailbox;
+    args[0] = &ambx; args[1] = NIL;
+    if (imap_OK (stream,reply = imap_send (stream,"GETQUOTAROOT",args)))
+      ret = LONGT;
+    else mm_log (reply->text,ERROR);
+  }
+  else mm_log ("Quota not available on this IMAP server",ERROR);
+  return ret;
+}
+
+/* Internal routines */
+
+
+/* IMAP send command
+ * Accepts: MAIL stream
+ *	    command
+ *	    argument list
+ * Returns: parsed reply
+ */
+
+#define CMDBASE LOCAL->tmp	/* command base */
+
+IMAPPARSEDREPLY *imap_send (MAILSTREAM *stream,char *cmd,IMAPARG *args[])
+{
+  IMAPPARSEDREPLY *reply;
+  IMAPARG *arg,**arglst;
+  SORTPGM *spg;
+  STRINGLIST *list;
+  SIZEDTEXT st;
+  APPENDDATA *map;
+  sendcommand_t sc = (sendcommand_t) mail_parameters (NIL,GET_SENDCOMMAND,NIL);
+  size_t i;
+  void *a;
+  char c,*s,*t,tag[10];
+  stream->unhealthy = NIL;	/* make stream healthy again */
+  				/* gensym a new tag */
+  sprintf (tag,"%08lx",0xffffffff & (stream->gensym++));
+  if (!LOCAL->netstream)	/* make sure have a session */
+    return imap_fake (stream,tag,"[CLOSED] IMAP connection lost");
+  mail_lock (stream);		/* lock up the stream */
+  if (sc)			/* tell client sending a command */
+    (*sc) (stream,cmd,((compare_cstring (cmd,"FETCH") &&
+			compare_cstring (cmd,"STORE") &&
+			compare_cstring (cmd,"SEARCH")) ? 
+		       NIL : SC_EXPUNGEDEFERRED));
+				/* ignore referral from previous command */
+  if (LOCAL->referral) fs_give ((void **) &LOCAL->referral);
+  sprintf (CMDBASE,"%s %s",tag,cmd);
+  s = CMDBASE + strlen (CMDBASE);
+  if (arglst = args) while (arg = *arglst++) {
+    *s++ = ' ';			/* delimit argument with space */
+    switch (arg->type) {
+    case ATOM:			/* atom */
+      for (t = (char *) arg->text; *t; *s++ = *t++);
+      break;
+    case NUMBER:		/* number */
+      sprintf (s,"%lu",(unsigned long) arg->text);
+      s += strlen (s);
+      break;
+    case FLAGS:			/* flag list as a single string */
+      if (*(t = (char *) arg->text) != '(') {
+	*s++ = '(';		/* wrap parens around string */
+	while (*t) *s++ = *t++;
+	*s++ = ')';		/* wrap parens around string */
+      }
+      else while (*t) *s++ = *t++;
+      break;
+    case ASTRING:		/* atom or string, must be literal? */
+      st.size = strlen ((char *) (st.data = (unsigned char *) arg->text));
+      if (reply = imap_send_astring (stream,tag,&s,&st,NIL,CMDBASE+MAXCOMMAND))
+	return reply;
+      break;
+    case LITERAL:		/* literal, as a stringstruct */
+      if (reply = imap_send_literal (stream,tag,&s,arg->text)) return reply;
+      break;
+
+    case LIST:			/* list of strings */
+      list = (STRINGLIST *) arg->text;
+      c = '(';			/* open paren */
+      do {			/* for each list item */
+	*s++ = c;		/* write prefix character */
+	if (reply = imap_send_astring (stream,tag,&s,&list->text,NIL,
+				       CMDBASE+MAXCOMMAND)) return reply;
+	c = ' ';		/* prefix character for subsequent strings */
+      }
+      while (list = list->next);
+      *s++ = ')';		/* close list */
+      break;
+    case SEARCHPROGRAM:		/* search program */
+      if (reply = imap_send_spgm (stream,tag,CMDBASE,&s,arg->text,
+				  CMDBASE+MAXCOMMAND))
+	return reply;
+      break;
+    case SORTPROGRAM:		/* search program */
+      c = '(';			/* open paren */
+      for (spg = (SORTPGM *) arg->text; spg; spg = spg->next) {
+	*s++ = c;		/* write prefix */
+	if (spg->reverse) for (t = "REVERSE "; *t; *s++ = *t++);
+	switch (spg->function) {
+	case SORTDATE:
+	  for (t = "DATE"; *t; *s++ = *t++);
+	  break;
+	case SORTARRIVAL:
+	  for (t = "ARRIVAL"; *t; *s++ = *t++);
+	  break;
+	case SORTFROM:
+	  for (t = "FROM"; *t; *s++ = *t++);
+	  break;
+	case SORTSUBJECT:
+	  for (t = "SUBJECT"; *t; *s++ = *t++);
+	  break;
+	case SORTTO:
+	  for (t = "TO"; *t; *s++ = *t++);
+	  break;
+	case SORTCC:
+	  for (t = "CC"; *t; *s++ = *t++);
+	  break;
+	case SORTSIZE:
+	  for (t = "SIZE"; *t; *s++ = *t++);
+	  break;
+	default:
+	  fatal ("Unknown sort program function in imap_send()!");
+	}
+	c = ' ';		/* prefix character for subsequent items */
+      }
+      *s++ = ')';		/* close list */
+      break;
+
+    case BODYTEXT:		/* body section */
+      for (t = "BODY["; *t; *s++ = *t++);
+      for (t = (char *) arg->text; *t; *s++ = *t++);
+      break;
+    case BODYPEEK:		/* body section */
+      for (t = "BODY.PEEK["; *t; *s++ = *t++);
+      for (t = (char *) arg->text; *t; *s++ = *t++);
+      break;
+    case BODYCLOSE:		/* close bracket and possible length */
+      s[-1] = ']';		/* no leading space */
+      for (t = (char *) arg->text; *t; *s++ = *t++);
+      break;
+    case SEQUENCE:		/* sequence */
+      if ((i = strlen (t = (char *) arg->text)) <= (size_t) MAXCOMMAND)
+	while (*t) *s++ = *t++;	/* easy case */
+      else {
+	mail_unlock (stream);	/* unlock stream */
+	a = arg->text;		/* save original sequence pointer */
+	arg->type = ATOM;	/* make recursive call be faster */
+	do {			/* break up into multiple commands */
+	  if (i <= MAXCOMMAND) {/* final part? */
+	    reply = imap_send (stream,cmd,args);
+	    i = 0;		/* and mark as done */
+	  }
+	  else {		/* still needs to be split further */
+	    if (!(t = strchr (t + MAXCOMMAND - 30,',')) ||
+		((t - (char *) arg->text) > MAXCOMMAND))
+	      fatal ("impossible over-long sequence");
+	    *t = '\0';		/* tie off sequence at point of split*/
+				/* recurse to do this part */
+	    reply = imap_send (stream,cmd,args);
+	    *t++ = ',';		/* restore the comma in case something cares */
+				/* punt if error */
+	    if (!imap_OK (stream,reply)) break;
+				/* calculate size of remaining sequence */
+	    i -= (t - (char *) arg->text);
+				/* point to new remaining sequence */
+	    arg->text = (void *) t;
+	  }
+	} while (i);
+	arg->type = SEQUENCE;	/* restore in case something cares */
+	arg->text = a;
+	return reply;		/* return result */
+      }
+      break;
+    case LISTMAILBOX:		/* astring with wildcards */
+      st.size = strlen ((char *) (st.data = (unsigned char *) arg->text));
+      if (reply = imap_send_astring (stream,tag,&s,&st,T,CMDBASE+MAXCOMMAND))
+	return reply;
+      break;
+
+    case MULTIAPPEND:		/* append multiple messages */
+				/* get package pointer */
+      map = (APPENDDATA *) arg->text;
+      if (!(*map->af) (stream,map->data,&map->flags,&map->date,&map->message)||
+	  !map->message) {
+	STRING es;
+	INIT (&es,mail_string,"",0);
+	return (reply = imap_send_literal (stream,tag,&s,&es)) ?
+	  reply : imap_fake (stream,tag,"Server zero-length literal error");
+      }
+    case MULTIAPPENDREDO:	/* redo multiappend */
+				/* get package pointer */
+      map = (APPENDDATA *) arg->text;
+      do {			/* make sure date valid if given */
+	char datetmp[MAILTMPLEN];
+	MESSAGECACHE elt;
+	STRING es;
+	if (!map->date || mail_parse_date (&elt,map->date)) {
+	  if (t = map->flags) {	/* flags given? */
+	    if (*t != '(') {
+	      *s++ = '(';	/* wrap parens around string */
+	      while (*t) *s++ = *t++;
+	      *s++ = ')';	/* wrap parens around string */
+	    }
+	    else while (*t) *s++ = *t++;
+	    *s++ = ' ';		/* delimit with space */
+	  }
+	  if (map->date) {	/* date given? */
+	    st.size = strlen ((char *) (st.data = (unsigned char *)
+					mail_date (datetmp,&elt)));
+	    if (reply = imap_send_astring (stream,tag,&s,&st,NIL,
+					   CMDBASE+MAXCOMMAND)) return reply;
+	    *s++ = ' ';		/* delimit with space */
+	  }
+	  if (reply = imap_send_literal (stream,tag,&s,map->message))
+	    return reply;
+				/* get next message */
+	  if ((*map->af) (stream,map->data,&map->flags,&map->date,
+			  &map->message)) {
+				/* have a message, delete next in command */
+	    if (map->message) *s++ = ' ';
+	    continue;		/* loop back for next message */
+	  }
+	}
+				/* bad date or need to abort */
+	INIT (&es,mail_string,"",0);
+	return (reply = imap_send_literal (stream,tag,&s,&es)) ?
+	  reply : imap_fake (stream,tag,"Server zero-length literal error");
+	break;			/* exit the loop */
+      } while (map->message);
+      break;
+
+    case SNLIST:		/* list of string/number pairs */
+      list = (STRINGLIST *) arg->text;
+      c = '(';			/* open paren */
+      do {			/* for each list item */
+	*s++ = c;		/* write prefix character */
+	if (list) {		/* sigh, QUOTA has bizarre syntax! */
+	  for (t = (char *) list->text.data; *t; *s++ = *t++);
+	  sprintf (s," %lu",list->text.size);
+	  s += strlen (s);
+	  c = ' ';		/* prefix character for subsequent strings */
+	}
+      }
+      while (list = list->next);
+      *s++ = ')';		/* close list */
+      break;
+    default:
+      fatal ("Unknown argument type in imap_send()!");
+    }
+  }
+				/* send the command */
+  reply = imap_sout (stream,tag,CMDBASE,&s);
+  mail_unlock (stream);		/* unlock stream */
+  return reply;
+}
+
+/* IMAP send atom-string
+ * Accepts: MAIL stream
+ *	    reply tag
+ *	    pointer to current position pointer of output bigbuf
+ *	    atom-string to output
+ *	    flag if list_wildcards allowed
+ *	    maximum to write as atom or qstring
+ * Returns: error reply or NIL if success
+ */
+
+IMAPPARSEDREPLY *imap_send_astring (MAILSTREAM *stream,char *tag,char **s,
+				    SIZEDTEXT *as,long wildok,char *limit)
+{
+  unsigned long j;
+  char c;
+  STRING st;
+				/* default to atom unless empty or loser */
+  int qflag = (as->size && !LOCAL->loser) ? NIL : T;
+				/* in case needed */
+  INIT (&st,mail_string,(void *) as->data,as->size);
+				/* always write literal if no space */
+  if ((*s + as->size) > limit) return imap_send_literal (stream,tag,s,&st);
+  for (j = 0; j < as->size; j++) switch (c = as->data[j]) {
+  default:			/* all other characters */
+    if (!(c & 0x80)) {		/* must not be 8bit */
+      if (c <= ' ') qflag = T;	/* must quote if a CTL */
+      break;
+    }
+  case '\0':			/* not a CHAR */
+  case '\012': case '\015':	/* not a TEXT-CHAR */
+  case '"': case '\\':		/* quoted-specials (IMAP2 required this) */
+    return imap_send_literal (stream,tag,s,&st);
+  case '*': case '%':		/* list_wildcards */
+    if (wildok) break;		/* allowed if doing the wild thing */
+				/* atom_specials */
+  case '(': case ')': case '{': case ' ': case 0x7f:
+#if 0
+  case '"': case '\\':		/* quoted-specials (could work in IMAP4) */
+#endif
+    qflag = T;			/* must use quoted string format */
+    break;
+  }
+  if (qflag) *(*s)++ = '"';	/* write open quote */
+  for (j = 0; j < as->size; j++) *(*s)++ = as->data[j];
+  if (qflag) *(*s)++ = '"';	/* write close quote */
+  return NIL;
+}
+
+/* IMAP send literal
+ * Accepts: MAIL stream
+ *	    reply tag
+ *	    pointer to current position pointer of output bigbuf
+ *	    literal to output as stringstruct
+ * Returns: error reply or NIL if success
+ */
+
+IMAPPARSEDREPLY *imap_send_literal (MAILSTREAM *stream,char *tag,char **s,
+				    STRING *st)
+{
+  IMAPPARSEDREPLY *reply;
+  unsigned long i = SIZE (st);
+  unsigned long j;
+  sprintf (*s,"{%lu}",i);	/* write literal count */
+  *s += strlen (*s);		/* size of literal count */
+				/* send the command */
+  reply = imap_sout (stream,tag,CMDBASE,s);
+  if (strcmp (reply->tag,"+")) {/* prompt for more data? */
+    mail_unlock (stream);	/* no, give up */
+    return reply;
+  }
+  while (i) {			/* dump the text */
+    if (st->cursize) {		/* if text to do in this chunk */
+      /* RFC 3501 technically forbids NULs in literals.  Normally, the
+       * delivering MTA would take care of MIME converting the message text
+       * so that it is NUL-free.  If it doesn't, then we have the choice of
+       * either violating IMAP by sending NULs, corrupting the data, or going
+       * to lots of work to do MIME conversion in the IMAP server.
+       *
+       * No current stringstruct driver objects to having its buffer patched.
+       * If this ever changes, it will be necessary to change this kludge.
+       */
+				/* patch NULs to C1 control */
+      for (j = 0; j < st->cursize; ++j)
+	if (!st->curpos[j]) st->curpos[j] = 0x80;
+      if (!net_sout (LOCAL->netstream,st->curpos,st->cursize)) {
+	mail_unlock (stream);
+	return imap_fake (stream,tag,"[CLOSED] IMAP connection broken (data)");
+      }
+      i -= st->cursize;		/* note that we wrote out this much */
+      st->curpos += (st->cursize - 1);
+      st->cursize = 0;
+    }
+    (*st->dtb->next) (st);	/* advance to next buffer's worth */
+  }
+  return NIL;			/* success */
+}
+
+/* IMAP send search program
+ * Accepts: MAIL stream
+ *	    reply tag
+ *	    base pointer if trimming needed
+ *	    pointer to current position pointer of output bigbuf
+ *	    search program to output
+ *	    pointer to limit guideline
+ * Returns: error reply or NIL if success
+ */
+
+
+IMAPPARSEDREPLY *imap_send_spgm (MAILSTREAM *stream,char *tag,char *base,
+				 char **s,SEARCHPGM *pgm,char *limit)
+{
+  IMAPPARSEDREPLY *reply;
+  SEARCHHEADER *hdr;
+  SEARCHOR *pgo;
+  SEARCHPGMLIST *pgl;
+  char *t;
+				/* trim if called recursively */
+  if (base) *s = imap_send_spgm_trim (base,*s,NIL);
+  base = *s;			/* this is the new base */
+				/* default searchpgm */
+  for (t = "ALL"; *t; *(*s)++ = *t++);
+  if (!pgm) return NIL;		/* done if NIL searchpgm */
+  if ((pgm->msgno &&		/* message sequences */
+       (pgm->msgno->next ||	/* trim away first:last */
+	(pgm->msgno->first != 1) || (pgm->msgno->last != stream->nmsgs)) &&
+       (reply = imap_send_sset (stream,tag,base,s,pgm->msgno," ",limit))) ||
+      (pgm->uid &&
+       (reply = imap_send_sset (stream,tag,base,s,pgm->uid," UID ",limit))))
+    return reply;
+				/* message sizes */
+  if (pgm->larger) {
+    sprintf (*s," LARGER %lu",pgm->larger);
+    *s += strlen (*s);
+  }
+  if (pgm->smaller) {
+    sprintf (*s," SMALLER %lu",pgm->smaller);
+    *s += strlen (*s);
+  }
+
+				/* message flags */
+  if (pgm->answered) for (t = " ANSWERED"; *t; *(*s)++ = *t++);
+  if (pgm->unanswered) for (t =" UNANSWERED"; *t; *(*s)++ = *t++);
+  if (pgm->deleted) for (t =" DELETED"; *t; *(*s)++ = *t++);
+  if (pgm->undeleted) for (t =" UNDELETED"; *t; *(*s)++ = *t++);
+  if (pgm->draft) for (t =" DRAFT"; *t; *(*s)++ = *t++);
+  if (pgm->undraft) for (t =" UNDRAFT"; *t; *(*s)++ = *t++);
+  if (pgm->flagged) for (t =" FLAGGED"; *t; *(*s)++ = *t++);
+  if (pgm->unflagged) for (t =" UNFLAGGED"; *t; *(*s)++ = *t++);
+  if (pgm->recent) for (t =" RECENT"; *t; *(*s)++ = *t++);
+  if (pgm->old) for (t =" OLD"; *t; *(*s)++ = *t++);
+  if (pgm->seen) for (t =" SEEN"; *t; *(*s)++ = *t++);
+  if (pgm->unseen) for (t =" UNSEEN"; *t; *(*s)++ = *t++);
+  if ((pgm->keyword &&		/* keywords */
+       (reply = imap_send_slist (stream,tag,base,s," KEYWORD ",pgm->keyword,
+				 limit))) ||
+      (pgm->unkeyword &&
+       (reply = imap_send_slist (stream,tag,base,s," UNKEYWORD ",
+				 pgm->unkeyword,limit))))
+    return reply;
+				/* sent date ranges */
+  if (pgm->sentbefore) imap_send_sdate (s,"SENTBEFORE",pgm->sentbefore);
+  if (pgm->senton) imap_send_sdate (s,"SENTON",pgm->senton);
+  if (pgm->sentsince) imap_send_sdate (s,"SENTSINCE",pgm->sentsince);
+				/* internal date ranges */
+  if (pgm->before) imap_send_sdate (s,"BEFORE",pgm->before);
+  if (pgm->on) imap_send_sdate (s,"ON",pgm->on);
+  if (pgm->since) imap_send_sdate (s,"SINCE",pgm->since);
+  if (pgm->older) {
+    sprintf (*s," OLDER %lu",pgm->older);
+    *s += strlen (*s);
+  }
+  if (pgm->younger) {
+    sprintf (*s," YOUNGER %lu",pgm->younger);
+    *s += strlen (*s);
+  }
+				/* search texts */
+  if ((pgm->bcc && (reply = imap_send_slist (stream,tag,base,s," BCC ",
+					     pgm->bcc,limit))) ||
+      (pgm->cc && (reply = imap_send_slist (stream,tag,base,s," CC ",pgm->cc,
+					    limit))) ||
+      (pgm->from && (reply = imap_send_slist (stream,tag,base,s," FROM ",
+					      pgm->from,limit))) ||
+      (pgm->to && (reply = imap_send_slist (stream,tag,base,s," TO ",pgm->to,
+					    limit))))
+    return reply;
+  if ((pgm->subject && (reply = imap_send_slist (stream,tag,base,s," SUBJECT ",
+						 pgm->subject,limit))) ||
+      (pgm->body && (reply = imap_send_slist (stream,tag,base,s," BODY ",
+					      pgm->body,limit))) ||
+      (pgm->text && (reply = imap_send_slist (stream,tag,base,s," TEXT ",
+					      pgm->text,limit))))
+    return reply;
+
+  /* Note that these criteria are not supported by IMAP and have to be
+     emulated */
+  if ((pgm->return_path &&
+       (reply = imap_send_slist (stream,tag,base,s," HEADER Return-Path ",
+				 pgm->return_path,limit))) ||
+      (pgm->sender &&
+       (reply = imap_send_slist (stream,tag,base,s," HEADER Sender ",
+				 pgm->sender,limit))) ||
+      (pgm->reply_to &&
+       (reply = imap_send_slist (stream,tag,base,s," HEADER Reply-To ",
+				 pgm->reply_to,limit))) ||
+      (pgm->in_reply_to &&
+       (reply = imap_send_slist (stream,tag,base,s," HEADER In-Reply-To ",
+				 pgm->in_reply_to,limit))) ||
+      (pgm->message_id &&
+       (reply = imap_send_slist (stream,tag,base,s," HEADER Message-ID ",
+				 pgm->message_id,limit))) ||
+      (pgm->newsgroups &&
+       (reply = imap_send_slist (stream,tag,base,s," HEADER Newsgroups ",
+				 pgm->newsgroups,limit))) ||
+      (pgm->followup_to &&
+       (reply = imap_send_slist (stream,tag,base,s," HEADER Followup-To ",
+				 pgm->followup_to,limit))) ||
+      (pgm->references &&
+       (reply = imap_send_slist (stream,tag,base,s," HEADER References ",
+				 pgm->references,limit)))) return reply;
+
+				/* all other headers */
+  if (hdr = pgm->header) do {
+    *s = imap_send_spgm_trim (base,*s," HEADER ");
+    if (reply = imap_send_astring (stream,tag,s,&hdr->line,NIL,limit))
+      return reply;
+    *(*s)++ = ' ';
+    if (reply = imap_send_astring (stream,tag,s,&hdr->text,NIL,limit))
+      return reply;
+  } while (hdr = hdr->next);
+  for (pgo = pgm->or; pgo; pgo = pgo->next) {
+    *s = imap_send_spgm_trim (base,*s," OR (");
+    if (reply = imap_send_spgm (stream,tag,base,s,pgo->first,limit))
+      return reply;
+    for (t = ") ("; *t; *(*s)++ = *t++);
+    if (reply = imap_send_spgm (stream,tag,base,s,pgo->second,limit))
+      return reply;
+    *(*s)++ = ')';
+  }
+  for (pgl = pgm->not; pgl; pgl = pgl->next) {
+    *s = imap_send_spgm_trim (base,*s," NOT (");
+    if (reply = imap_send_spgm (stream,tag,base,s,pgl->pgm,limit))
+      return reply;
+    *(*s)++ = ')';
+  }
+				/* trim if needed */
+  *s = imap_send_spgm_trim (base,*s,NIL);
+  return NIL;			/* search program written OK */
+}
+
+
+/* Write new text and trim extraneous "ALL" from searchpgm
+ * Accepts: pointer to start of searchpgm or NIL
+ *	    current end pointer
+ *	    new text to write or NIL
+ * Returns: new end pointer, trimmed if needed
+ */
+
+char *imap_send_spgm_trim (char *base,char *s,char *text)
+{
+  char *t;
+				/* write new text */
+  if (text) for (t = text; *t; *s++ = *t++);
+				/* need to trim? */
+  if (base && (s > (t = (base + 4))) && (*base == 'A') && (base[1] == 'L') &&
+      (base[2] == 'L') && (base[3] == ' ')) {
+    memmove (base,t,s - t);	/* yes, blat down remaining text */
+    s -= 4;			/* and reduce current pointer */
+  }
+  return s;			/* return new end pointer */
+}
+
+/* IMAP send search set
+ * Accepts: MAIL stream
+ *	    current command tag
+ *	    base pointer if trimming needed
+ *	    pointer to current position pointer of output bigbuf
+ *	    search set to output
+ *	    message prefix
+ *	    maximum output pointer
+ * Returns: NIL if success, error reply if error
+ */
+
+IMAPPARSEDREPLY *imap_send_sset (MAILSTREAM *stream,char *tag,char *base,
+				 char **s,SEARCHSET *set,char *prefix,
+				 char *limit)
+{
+  IMAPPARSEDREPLY *reply;
+  STRING st;
+  char c,*t;
+  char *start = *s;
+				/* trim and write prefix */
+  *s = imap_send_spgm_trim (base,*s,prefix);
+				/* run down search list */
+  for (c = NIL; set && (*s < limit); set = set->next, c = ',') {
+    if (c) *(*s)++ = c;		/* write delimiter and first value */
+    if (set->first == 0xffffffff) *(*s)++ = '*';
+    else {
+      sprintf (*s,"%lu",set->first);
+      *s += strlen (*s);
+    }
+				/* have a second value? */
+    if (set->last && (set->first != set->last)) {
+      *(*s)++ = ':';		/* write delimiter and second value */
+      if (set->last == 0xffffffff) *(*s)++ = '*';
+      else {
+	sprintf (*s,"%lu",set->last);
+	*s += strlen (*s);
+      }
+    }
+  }
+  if (set) {			/* insert "OR" in front of incomplete set */
+    memmove (start + 3,start,*s - start);
+    memcpy (start," OR",3);
+    *s += 3;			/* point to end of buffer */
+				/* write glue that is equivalent to ALL */
+    for (t =" ((OR BCC FOO NOT BCC "; *t; *(*s)++ = *t++);
+				/* but broken by a literal */
+    INIT (&st,mail_string,(void *) "FOO",3);
+    if (reply = imap_send_literal (stream,tag,s,&st)) return reply;
+    *(*s)++ = ')';		/* close glue */
+    if (reply = imap_send_sset (stream,tag,NIL,s,set,prefix,limit))
+      return reply;
+    *(*s)++ = ')';		/* close second OR argument */
+  }
+  return NIL;
+}
+
+/* IMAP send search list
+ * Accepts: MAIL stream
+ *	    reply tag
+ *	    base pointer if trimming needed
+ *	    pointer to current position pointer of output bigbuf
+ *	    name of search list
+ *	    search list to output
+ *	    maximum output pointer
+ * Returns: NIL if success, error reply if error
+ */
+
+IMAPPARSEDREPLY *imap_send_slist (MAILSTREAM *stream,char *tag,char *base,
+				  char **s,char *name,STRINGLIST *list,
+				  char *limit)
+{
+  IMAPPARSEDREPLY *reply;
+  do {
+    *s = imap_send_spgm_trim (base,*s,name);
+    base = NIL;			/* no longer need trimming */
+    reply = imap_send_astring (stream,tag,s,&list->text,NIL,limit);
+  }
+  while (!reply && (list = list->next));
+  return reply;
+}
+
+
+/* IMAP send search date
+ * Accepts: pointer to current position pointer of output bigbuf
+ *	    field name
+ *	    search date to output
+ */
+
+void imap_send_sdate (char **s,char *name,unsigned short date)
+{
+  sprintf (*s," %s %d-%s-%d",name,date & 0x1f,
+	   months[((date >> 5) & 0xf) - 1],BASEYEAR + (date >> 9));
+  *s += strlen (*s);
+}
+
+/* IMAP send buffered command to sender
+ * Accepts: MAIL stream
+ *	    reply tag
+ *	    string
+ *	    pointer to string tail pointer
+ * Returns: reply
+ */
+
+IMAPPARSEDREPLY *imap_sout (MAILSTREAM *stream,char *tag,char *base,char **s)
+{
+  IMAPPARSEDREPLY *reply;
+  if (stream->debug) {		/* output debugging telemetry */
+    **s = '\0';
+    mail_dlog (base,LOCAL->sensitive);
+  }
+  *(*s)++ = '\015';		/* append CRLF */
+  *(*s)++ = '\012';
+  **s = '\0';
+  reply = net_sout (LOCAL->netstream,base,*s - base) ?
+    imap_reply (stream,tag) :
+      imap_fake (stream,tag,"[CLOSED] IMAP connection broken (command)");
+  *s = base;			/* restart buffer */
+  return reply;
+}
+
+
+/* IMAP send null-terminated string to sender
+ * Accepts: MAIL stream
+ *	    string
+ * Returns: T if success, else NIL
+ */
+
+long imap_soutr (MAILSTREAM *stream,char *string)
+{
+  long ret;
+  unsigned long i;
+  char *s;
+  if (stream->debug) mm_dlog (string);
+  sprintf (s = (char *) fs_get ((i = strlen (string) + 2) + 1),
+	   "%s\015\012",string);
+  ret = net_sout (LOCAL->netstream,s,i);
+  fs_give ((void **) &s);
+  return ret;
+}
+
+/* IMAP get reply
+ * Accepts: MAIL stream
+ *	    tag to search or NIL if want a greeting
+ * Returns: parsed reply, never NIL
+ */
+
+IMAPPARSEDREPLY *imap_reply (MAILSTREAM *stream,char *tag)
+{
+  IMAPPARSEDREPLY *reply;
+  while (LOCAL->netstream) {	/* parse reply from server */
+    if (reply = imap_parse_reply (stream,net_getline (LOCAL->netstream))) {
+				/* continuation ready? */
+      if (!strcmp (reply->tag,"+")) return reply;
+				/* untagged data? */
+      else if (!strcmp (reply->tag,"*")) {
+	imap_parse_unsolicited (stream,reply);
+	if (!tag) return reply;	/* return if just wanted greeting */
+      }
+      else {			/* tagged data */
+	if (tag && !compare_cstring (tag,reply->tag)) return reply;
+				/* report bogon */
+	sprintf (LOCAL->tmp,"Unexpected tagged response: %.80s %.80s %.80s",
+		 (char *) reply->tag,(char *) reply->key,(char *) reply->text);
+	mm_notify (stream,LOCAL->tmp,WARN);
+	stream->unhealthy = T;
+      }
+    }
+  }
+  return imap_fake (stream,tag,
+		    "[CLOSED] IMAP connection broken (server response)");
+}
+
+/* IMAP parse reply
+ * Accepts: MAIL stream
+ *	    text of reply
+ * Returns: parsed reply, or NIL if can't parse at least a tag and key
+ */
+
+
+IMAPPARSEDREPLY *imap_parse_reply (MAILSTREAM *stream,char *text)
+{
+  char *r;
+  if (LOCAL->reply.line) fs_give ((void **) &LOCAL->reply.line);
+				/* init fields in case error */
+  LOCAL->reply.key = LOCAL->reply.text = LOCAL->reply.tag = NIL;
+  if (!(LOCAL->reply.line = text)) {
+				/* NIL text means the stream died */
+    if (LOCAL->netstream) net_close (LOCAL->netstream);
+    LOCAL->netstream = NIL;
+    return NIL;
+  }
+  if (stream->debug) mm_dlog (LOCAL->reply.line);
+  if (!(LOCAL->reply.tag = strtok_r (LOCAL->reply.line," ",&r))) {
+    mm_notify (stream,"IMAP server sent a blank line",WARN);
+    stream->unhealthy = T;
+    return NIL;
+  }
+				/* non-continuation replies */
+  if (strcmp (LOCAL->reply.tag,"+")) {
+				/* parse key */
+    if (!(LOCAL->reply.key = strtok_r (NIL," ",&r))) {
+				/* determine what is missing */
+      sprintf (LOCAL->tmp,"Missing IMAP reply key: %.80s",
+	       (char *) LOCAL->reply.tag);
+      mm_notify (stream,LOCAL->tmp,WARN);
+      stream->unhealthy = T;
+      return NIL;		/* can't parse this text */
+    }
+    ucase (LOCAL->reply.key);	/* canonicalize key to upper */
+				/* get text as well, allow empty text */
+    if (!(LOCAL->reply.text = strtok_r (NIL,"\n",&r)))
+      LOCAL->reply.text = LOCAL->reply.key + strlen (LOCAL->reply.key);
+  }
+  else {			/* special handling of continuation */
+    LOCAL->reply.key = "BAD";	/* so it barfs if not expecting continuation */
+    if (!(LOCAL->reply.text = strtok_r (NIL,"\n",&r)))
+      LOCAL->reply.text = "";
+  }
+  return &LOCAL->reply;		/* return parsed reply */
+}
+
+/* IMAP fake reply when stream determined to be dead
+ * Accepts: MAIL stream
+ *	    tag
+ *	    text of fake reply (must start with "[CLOSED]")
+ * Returns: parsed reply
+ */
+
+IMAPPARSEDREPLY *imap_fake (MAILSTREAM *stream,char *tag,char *text)
+{
+  mm_notify (stream,text,BYE);	/* send bye alert */
+  if (LOCAL->netstream) net_close (LOCAL->netstream);
+  LOCAL->netstream = NIL;	/* farewell, dear NET stream... */
+				/* flush previous reply */
+  if (LOCAL->reply.line) fs_give ((void **) &LOCAL->reply.line);
+				/* build new fake reply */
+  LOCAL->reply.tag = LOCAL->reply.line = cpystr (tag ? tag : "*");
+  LOCAL->reply.key = "NO";
+  LOCAL->reply.text = text;
+  return &LOCAL->reply;		/* return parsed reply */
+}
+
+
+/* IMAP check for OK response in tagged reply
+ * Accepts: MAIL stream
+ *	    parsed reply
+ * Returns: T if OK else NIL
+ */
+
+long imap_OK (MAILSTREAM *stream,IMAPPARSEDREPLY *reply)
+{
+  long ret = NIL;
+				/* OK - operation succeeded */
+  if (!strcmp (reply->key,"OK")) {
+    imap_parse_response (stream,reply->text,NIL,NIL);
+    ret = T;
+  }
+				/* NO - operation failed */
+  else if (!strcmp (reply->key,"NO"))
+    imap_parse_response (stream,reply->text,WARN,NIL);
+  else {			/* BAD - operation rejected */
+    if (!strcmp (reply->key,"BAD")) {
+      imap_parse_response (stream,reply->text,ERROR,NIL);
+      sprintf (LOCAL->tmp,"IMAP protocol error: %.80s",(char *) reply->text);
+    }
+				/* bad protocol received */
+    else sprintf (LOCAL->tmp,"Unexpected IMAP response: %.80s %.80s",
+		  (char *) reply->key,(char *) reply->text);
+    mm_log (LOCAL->tmp,ERROR);	/* either way, this is not good */
+  }
+  return ret;
+}
+
+/* IMAP parse and act upon unsolicited reply
+ * Accepts: MAIL stream
+ *	    parsed reply
+ */
+
+void imap_parse_unsolicited (MAILSTREAM *stream,IMAPPARSEDREPLY *reply)
+{
+  unsigned long i = 0;
+  unsigned long j,msgno;
+  unsigned char *s,*t;
+  char *r;
+				/* see if key is a number */
+  if (isdigit (*reply->key)) {
+    msgno = strtoul (reply->key,(char **) &s,10);
+    if (*s) {			/* better be nothing after number */
+      sprintf (LOCAL->tmp,"Unexpected untagged message: %.80s",
+	       (char *) reply->key);
+      mm_notify (stream,LOCAL->tmp,WARN);
+      stream->unhealthy = T;
+      return;
+    }
+    if (!reply->text) {		/* better be some data */
+      mm_notify (stream,"Missing message data",WARN);
+      stream->unhealthy = T;
+      return;
+    }
+				/* get message data type, canonicalize upper */
+    s = ucase (strtok_r (reply->text," ",&r));
+				/* and locate the text after it */
+    t = strtok_r (NIL,"\n",&r);
+				/* now take the action */
+				/* change in size of mailbox */
+    if (!strcmp (s,"EXISTS") && (msgno >= stream->nmsgs))
+      mail_exists (stream,msgno);
+    else if (!strcmp (s,"RECENT") && (msgno <= stream->nmsgs))
+      mail_recent (stream,msgno);
+    else if (!strcmp (s,"EXPUNGE") && msgno && (msgno <= stream->nmsgs)) {
+      mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL);
+      MESSAGECACHE *elt = (MESSAGECACHE *) (*mc) (stream,msgno,CH_ELT);
+      if (elt) imap_gc_body (elt->private.msg.body);
+				/* notify upper level */
+      mail_expunged (stream,msgno);
+    }
+
+    else if ((!strcmp (s,"FETCH") || !strcmp (s,"STORE")) &&
+	     msgno && (msgno <= stream->nmsgs)) {
+      char *prop;
+      GETS_DATA md;
+      ENVELOPE **e;
+      MESSAGECACHE *elt = mail_elt (stream,msgno);
+      ENVELOPE *env = NIL;
+      imapenvelope_t ie =
+	(imapenvelope_t) mail_parameters (stream,GET_IMAPENVELOPE,NIL);
+      ++t;			/* skip past open parenthesis */
+				/* parse Lisp-form property list */
+      while (prop = (strtok_r (t," )",&r))) {
+	t = strtok_r (NIL,"\n",&r);
+	INIT_GETS (md,stream,elt->msgno,NIL,0,0);
+	e = NIL;		/* not pointing at any envelope yet */
+				/* canonicalize property, parse it */
+	if (!strcmp (ucase (prop),"FLAGS")) imap_parse_flags (stream,elt,&t);
+	else if (!strcmp (prop,"INTERNALDATE") &&
+		 (s = imap_parse_string (stream,&t,reply,NIL,NIL,LONGT))) {
+	  if (!mail_parse_date (elt,s)) {
+	    sprintf (LOCAL->tmp,"Bogus date: %.80s",(char *) s);
+	    mm_notify (stream,LOCAL->tmp,WARN);
+	    stream->unhealthy = T;
+				/* slam in default so we don't try again */
+	    mail_parse_date (elt,"01-Jan-1970 00:00:00 +0000");
+	  }
+	  fs_give ((void **) &s);
+	}
+				/* unique identifier */
+	else if (!strcmp (prop,"UID")) {
+	  LOCAL->lastuid.uid = elt->private.uid = strtoul (t,(char **) &t,10);
+	  LOCAL->lastuid.msgno = elt->msgno;
+	}
+	else if (!strcmp (prop,"ENVELOPE")) {
+	  if (stream->scache) {	/* short cache, flush old stuff */
+	    mail_free_body (&stream->body);
+	    stream->msgno = elt->msgno;
+	    e = &stream->env;	/* get pointer to envelope */
+	  }
+	  else e = &elt->private.msg.env;
+	  imap_parse_envelope (stream,e,&t,reply);
+	}
+	else if (!strncmp (prop,"BODY",4)) {
+	  if (!prop[4] || !strcmp (prop+4,"STRUCTURE")) {
+	    BODY **body;
+	    if (stream->scache){/* short cache, flush old stuff */
+	      if (stream->msgno != msgno) {
+		mail_free_envelope (&stream->env);
+		sprintf (LOCAL->tmp,"Body received for %lu but current is %lu",
+			 msgno,stream->msgno);
+		stream->msgno = msgno;
+	      }
+				/* get pointer to body */
+	      body = &stream->body;
+	    }
+	    else body = &elt->private.msg.body;
+				/* flush any prior body */
+	    mail_free_body (body);
+				/* instantiate and parse a new body */
+	    imap_parse_body_structure (stream,*body = mail_newbody(),&t,reply);
+	  }
+
+	  else if (prop[4] == '[') {
+	    STRINGLIST *stl = NIL;
+	    SIZEDTEXT text;
+				/* will want to return envelope data */
+	    if (!strcmp (md.what = cpystr (prop + 5),"HEADER]") ||
+		!strcmp (md.what,"0]"))
+	      e = stream->scache ? &stream->env : &elt->private.msg.env;
+	    LOCAL->tmp[0] ='\0';/* no errors yet */
+				/* found end of section? */
+	    if (!(s = strchr (md.what,']'))) {
+				/* skip leading nesting */
+	      for (s = md.what; *s && (isdigit (*s) || (*s == '.')); s++);
+				/* better be one of these */
+	      if (strncmp (s,"HEADER.FIELDS",13) &&
+		  (!s[13] || strcmp (s+13,".NOT")))
+		sprintf (LOCAL->tmp,"Unterminated section: %.80s",md.what);
+				/* get list of headers */
+	      else if (!(stl = imap_parse_stringlist (stream,&t,reply)))
+		sprintf (LOCAL->tmp,"Bogus header field list: %.80s",
+			 (char *) t);
+	      else if (*t != ']')
+		sprintf (LOCAL->tmp,"Unterminated header section: %.80s",
+			 (char *) t);
+				/* point after the text */
+	      else if (t = strchr (s = t,' ')) *t++ = '\0';
+	    }
+	    if (s && !LOCAL->tmp[0]) {
+	      *s++ = '\0';	/* tie off section specifier */
+	      if (*s == '<') {	/* partial specifier? */
+		md.first = strtoul (s+1,(char **) &s,10) + 1;
+		if (*s++ != '>')	/* make sure properly terminated */
+		  sprintf (LOCAL->tmp,"Unterminated partial data: %.80s",
+			   (char *) s-1);
+	      }
+	      if (!LOCAL->tmp[0] && *s)
+		sprintf (LOCAL->tmp,"Junk after section: %.80s",(char *) s);
+	    }
+	    if (LOCAL->tmp[0]) { /* got any errors? */
+	      mm_notify (stream,LOCAL->tmp,WARN);
+	      stream->unhealthy = T;
+	      mail_free_stringlist (&stl);
+	    }
+	    else {		/* parse text from server */
+	      text.data = (unsigned char *)
+		imap_parse_string (stream,&t,reply,
+				   ((md.what[0] && (md.what[0] != 'H')) ||
+				    md.first || md.last) ? &md : NIL,
+				   &text.size,NIL);
+				/* all done if partial */
+	      if (md.first || md.last) mail_free_stringlist (&stl);
+				/* otherwise register it in the cache */
+	      else imap_cache (stream,msgno,md.what,stl,&text);
+	    }
+	    fs_give ((void **) &md.what);
+	  }
+	  else {
+	    sprintf (LOCAL->tmp,"Unknown body message property: %.80s",prop);
+	    mm_notify (stream,LOCAL->tmp,WARN);
+	    stream->unhealthy = T;
+	  }
+	}
+
+				/* one of the RFC822 props? */
+	else if (!strncmp (prop,"RFC822",6) && (!prop[6] || (prop[6] == '.'))){
+	  SIZEDTEXT text;
+	  if (!prop[6]) {	/* cache full message */
+	    md.what = "";
+	    text.data = (unsigned char *)
+	      imap_parse_string (stream,&t,reply,&md,&text.size,NIL);
+	    imap_cache (stream,msgno,md.what,NIL,&text);
+	  }
+	  else if (!strcmp (prop+7,"SIZE"))
+	    elt->rfc822_size = strtoul (t,(char **) &t,10);
+				/* legacy properties */
+	  else if (!strcmp (prop+7,"HEADER")) {
+	    text.data = (unsigned char *)
+	      imap_parse_string (stream,&t,reply,NIL,&text.size,NIL);
+	    imap_cache (stream,msgno,"HEADER",NIL,&text);
+	    e = stream->scache ? &stream->env : &elt->private.msg.env;
+	  }
+	  else if (!strcmp (prop+7,"TEXT")) {
+	    md.what = "TEXT";
+	    text.data = (unsigned char *)
+	      imap_parse_string (stream,&t,reply,&md,&text.size,NIL);
+	    imap_cache (stream,msgno,md.what,NIL,&text);
+	  }
+	  else {
+	    sprintf (LOCAL->tmp,"Unknown RFC822 message property: %.80s",prop);
+	    mm_notify (stream,LOCAL->tmp,WARN);
+	    stream->unhealthy = T;
+	  }
+	}
+	else {
+	  sprintf (LOCAL->tmp,"Unknown message property: %.80s",prop);
+	  mm_notify (stream,LOCAL->tmp,WARN);
+	  stream->unhealthy = T;
+	}
+	if (e && *e) env = *e;	/* note envelope if we got one */
+      }
+				/* do callback if requested */
+      if (ie && env) (*ie) (stream,msgno,env);
+    }
+				/* obsolete response to COPY */
+    else if (strcmp (s,"COPY")) {
+      sprintf (LOCAL->tmp,"Unknown message data: %lu %.80s",msgno,(char *) s);
+      mm_notify (stream,LOCAL->tmp,WARN);
+      stream->unhealthy = T;
+    }
+  }
+
+  else if (!strcmp (reply->key,"FLAGS") && reply->text &&
+	   (*reply->text == '(') &&
+	   (s = strtok_r (reply->text+1," )",&r)))
+    do if (*s != '\\') {
+      for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i] &&
+	     compare_cstring (s,stream->user_flags[i]); i++);
+      if (i > NUSERFLAGS) {
+	sprintf (LOCAL->tmp,"Too many server flags, discarding: %.80s",
+		 (char *) s);
+	mm_notify (stream,LOCAL->tmp,WARN);
+      }
+      else if (!stream->user_flags[i]) stream->user_flags[i++] = cpystr (s);
+    }
+    while (s = strtok_r (NIL," )",&r));
+  else if (!strcmp (reply->key,"SEARCH")) {
+				/* only do something if have text */
+    if (reply->text && (t = strtok_r (reply->text," ",&r))) do
+      if (i = strtoul (t,NIL,10)) {
+				/* UIDs always passed to main program */
+	if (LOCAL->uidsearch) mm_searched (stream,i);
+				/* should be a msgno then */
+	else if ((i <= stream->nmsgs) &&
+		 (!LOCAL->filter || mail_elt (stream,i)->private.filter)) {
+	  mail_elt (stream,i)->searched = T;
+	  if (!stream->silent) mm_searched (stream,i);
+	}
+      } while (t = strtok_r (NIL," ",&r));
+  }
+  else if (!strcmp (reply->key,"SORT")) {
+    sortresults_t sr = (sortresults_t)
+      mail_parameters (NIL,GET_SORTRESULTS,NIL);
+    LOCAL->sortsize = 0;	/* initialize sort data */
+    if (LOCAL->sortdata) fs_give ((void **) &LOCAL->sortdata);
+    LOCAL->sortdata = (unsigned long *)
+      fs_get ((stream->nmsgs + 1) * sizeof (unsigned long));
+				/* only do something if have text */
+    if (reply->text && (t = strtok_r (reply->text," ",&r))) {
+      do if ((i = atol (t)) && (LOCAL->filter ?
+				mail_elt (stream,i)->searched : T))
+	LOCAL->sortdata[LOCAL->sortsize++] = i;
+      while ((t = strtok_r (NIL," ",&r)) && (LOCAL->sortsize < stream->nmsgs));
+    }
+    LOCAL->sortdata[LOCAL->sortsize] = 0;
+				/* also return via callback if requested */
+    if (sr) (*sr) (stream,LOCAL->sortdata,LOCAL->sortsize);
+  }
+  else if (!strcmp (reply->key,"THREAD")) {
+    threadresults_t tr = (threadresults_t)
+      mail_parameters (NIL,GET_THREADRESULTS,NIL);
+    if (LOCAL->threaddata) mail_free_threadnode (&LOCAL->threaddata);
+    if (s = reply->text) {
+      LOCAL->threaddata = imap_parse_thread (stream,&s);
+      if (tr) (*tr) (stream,LOCAL->threaddata);
+      if (s && *s) {
+	sprintf (LOCAL->tmp,"Junk at end of thread: %.80s",(char *) s);
+	mm_notify (stream,LOCAL->tmp,WARN);
+	stream->unhealthy = T;
+      }
+    }
+  }
+
+  else if (!strcmp (reply->key,"STATUS") && reply->text) {
+    MAILSTATUS status;
+    unsigned char *txt = reply->text;
+    if ((t = imap_parse_astring (stream,&txt,reply,&j)) && txt &&
+	(*txt++ == ' ') && (*txt++ == '(') && (s = strchr (txt,')')) &&
+	(s - txt) && !s[1]) {
+      *s = '\0';		/* tie off status data */
+				/* initialize data block */
+      status.flags = status.messages = status.recent = status.unseen =
+	status.uidnext = status.uidvalidity = 0;
+      while (*txt && (s = strchr (txt,' '))) {
+	*s++ = '\0';		/* tie off status attribute name */
+				/* get attribute value */
+	i = strtoul (s,(char **) &s,10);
+	if (!compare_cstring (txt,"MESSAGES")) {
+	  status.flags |= SA_MESSAGES;
+	  status.messages = i;
+	}
+	else if (!compare_cstring (txt,"RECENT")) {
+	  status.flags |= SA_RECENT;
+	  status.recent = i;
+	}
+	else if (!compare_cstring (txt,"UNSEEN")) {
+	  status.flags |= SA_UNSEEN;
+	  status.unseen = i;
+	}
+	else if (!compare_cstring (txt,"UIDNEXT")) {
+	  status.flags |= SA_UIDNEXT;
+	  status.uidnext = i;
+	}
+	else if (!compare_cstring (txt,"UIDVALIDITY")) {
+	  status.flags |= SA_UIDVALIDITY;
+	  status.uidvalidity = i;
+	}
+				/* next attribute */
+	txt = (*s == ' ') ? s + 1 : s;
+      }
+      if (((i = 1 + strchr (stream->mailbox,'}') - stream->mailbox) + j) <
+	  IMAPTMPLEN) {
+	strcpy (strncpy (LOCAL->tmp,stream->mailbox,i) + i,t);
+				/* pass status to main program */
+	mm_status (stream,LOCAL->tmp,&status);
+      }
+    }
+    if (t) fs_give ((void **) &t);
+  }
+
+  else if ((!strcmp (reply->key,"LIST") || !strcmp (reply->key,"LSUB")) &&
+	   reply->text && (*reply->text == '(') &&
+	   (s = strchr (reply->text,')')) && (s[1] == ' ')) {
+    char delimiter = '\0';
+    *s++ = '\0';		/* tie off attribute list */
+				/* parse attribute list */
+    if (t = strtok_r (reply->text+1," ",&r)) do {
+      if (!compare_cstring (t,"\\NoInferiors")) i |= LATT_NOINFERIORS;
+      else if (!compare_cstring (t,"\\NoSelect")) i |= LATT_NOSELECT;
+      else if (!compare_cstring (t,"\\Marked")) i |= LATT_MARKED;
+      else if (!compare_cstring (t,"\\Unmarked")) i |= LATT_UNMARKED;
+      else if (!compare_cstring (t,"\\HasChildren")) i |= LATT_HASCHILDREN;
+      else if (!compare_cstring (t,"\\HasNoChildren")) i |= LATT_HASNOCHILDREN;
+				/* ignore extension flags */
+    }
+    while (t = strtok_r (NIL," ",&r));
+    switch (*++s) {		/* process delimiter */
+    case 'N':			/* NIL */
+    case 'n':
+      s += 4;			/* skip over NIL<space> */
+      break;
+    case '"':			/* have a delimiter */
+      delimiter = (*++s == '\\') ? *++s : *s;
+      s += 3;			/* skip over <delimiter><quote><space> */
+    }
+				/* parse the mailbox name */
+    if (t = imap_parse_astring (stream,&s,reply,&j)) {
+				/* prepend prefix if requested */
+      if (LOCAL->prefix && ((strlen (LOCAL->prefix) + j) < IMAPTMPLEN))
+	sprintf (s = LOCAL->tmp,"%s%s",LOCAL->prefix,(char *) t);
+      else s = t;		/* otherwise just mailbox name */
+				/* pass data to main program */
+      if (reply->key[1] == 'S') mm_lsub (stream,delimiter,s,i);
+      else mm_list (stream,delimiter,s,i);
+      fs_give ((void **) &t);	/* flush mailbox name */
+    }
+  }
+  else if (!strcmp (reply->key,"NAMESPACE")) {
+    if (LOCAL->namespace) {
+      mail_free_namespace (&LOCAL->namespace[0]);
+      mail_free_namespace (&LOCAL->namespace[1]);
+      mail_free_namespace (&LOCAL->namespace[2]);
+    }
+    else LOCAL->namespace = (NAMESPACE **) fs_get (3 * sizeof (NAMESPACE *));
+    if (s = reply->text) {	/* parse namespace results */
+      LOCAL->namespace[0] = imap_parse_namespace (stream,&s,reply);
+      LOCAL->namespace[1] = imap_parse_namespace (stream,&s,reply);
+      LOCAL->namespace[2] = imap_parse_namespace (stream,&s,reply);
+      if (s && *s) {
+	sprintf (LOCAL->tmp,"Junk after namespace list: %.80s",(char *) s);
+	mm_notify (stream,LOCAL->tmp,WARN);
+	stream->unhealthy = T;
+      }
+    }
+    else {
+      mm_notify (stream,"Missing namespace list",WARN);
+      stream->unhealthy = T;
+    }
+  }
+
+  else if (!strcmp (reply->key,"ACL") && (s = reply->text) &&
+	   (t = imap_parse_astring (stream,&s,reply,NIL))) {
+    getacl_t ar = (getacl_t) mail_parameters (NIL,GET_ACL,NIL);
+    if (s && (*s++ == ' ')) {
+      ACLLIST *al = mail_newacllist ();
+      ACLLIST *ac = al;
+      do if ((ac->identifier = imap_parse_astring (stream,&s,reply,NIL)) &&
+	     s && (*s++ == ' '))
+	ac->rights = imap_parse_astring (stream,&s,reply,NIL);
+      while (ac->rights && s && (*s == ' ') && s++ &&
+	     (ac = ac->next = mail_newacllist ()));
+      if (!ac->rights || (s && *s)) {
+	sprintf (LOCAL->tmp,"Invalid ACL identifer/rights for %.80s",
+		 (char *) t);
+	mm_notify (stream,LOCAL->tmp,WARN);
+	stream->unhealthy = T;
+      }
+      else if (ar) (*ar) (stream,t,al);
+      mail_free_acllist (&al);	/* clean up */
+    }
+				/* no optional rights */
+    else if (ar) (*ar) (stream,t,NIL);
+    fs_give ((void **) &t);	/* free mailbox name */
+  }
+
+  else if (!strcmp (reply->key,"LISTRIGHTS") && (s = reply->text) &&
+	   (t = imap_parse_astring (stream,&s,reply,NIL))) {
+    listrights_t lr = (listrights_t) mail_parameters (NIL,GET_LISTRIGHTS,NIL);
+    char *id,*r;
+    if (s && (*s++ == ' ') && (id = imap_parse_astring (stream,&s,reply,NIL))){
+      if (s && (*s++ == ' ') &&
+	  (r = imap_parse_astring (stream,&s,reply,NIL))) {
+	if (s && (*s++ == ' ')) {
+	  STRINGLIST *rl = mail_newstringlist ();
+	  STRINGLIST *rc = rl;
+	  do rc->text.data = (unsigned char *)
+	    imap_parse_astring (stream,&s,reply,&rc->text.size);
+	  while (rc->text.data && s && (*s == ' ') && s++ &&
+		 (rc = rc->next = mail_newstringlist ()));
+	  if (!rc->text.data || (s && *s)) {
+	    sprintf (LOCAL->tmp,"Invalid optional LISTRIGHTS for %.80s",
+		     (char *) t);
+	    mm_notify (stream,LOCAL->tmp,WARN);
+	    stream->unhealthy = T;
+	  }
+	  else if (lr) (*lr) (stream,t,id,r,rl);
+				/* clean up */
+	  mail_free_stringlist (&rl);
+	}
+				/* no optional rights */
+	else if (lr) (*lr) (stream,t,id,r,NIL);
+	fs_give ((void **) &r);	/* free rights */
+      }
+      else {
+	sprintf (LOCAL->tmp,"Missing LISTRIGHTS rights for %.80s",(char *) t);
+	mm_notify (stream,LOCAL->tmp,WARN);
+	stream->unhealthy = T;
+      }
+      fs_give ((void **) &id);	/* free identifier */
+    }
+    else {
+      sprintf (LOCAL->tmp,"Missing LISTRIGHTS identifer for %.80s",(char *) t);
+      mm_notify (stream,LOCAL->tmp,WARN);
+      stream->unhealthy = T;
+    }
+    fs_give ((void **) &t);	/* free mailbox name */
+  }
+
+  else if (!strcmp (reply->key,"MYRIGHTS") && (s = reply->text) &&
+	   (t = imap_parse_astring (stream,&s,reply,NIL))) {
+    myrights_t mr = (myrights_t) mail_parameters (NIL,GET_MYRIGHTS,NIL);
+    char *r;
+    if (s && (*s++ == ' ') && (r = imap_parse_astring (stream,&s,reply,NIL))) {
+      if (s && *s) {
+	sprintf (LOCAL->tmp,"Junk after MYRIGHTS for %.80s",(char *) t);
+	mm_notify (stream,LOCAL->tmp,WARN);
+	stream->unhealthy = T;
+      }
+      else if (mr) (*mr) (stream,t,r);
+      fs_give ((void **) &r);	/* free rights */
+    }
+    else {
+      sprintf (LOCAL->tmp,"Missing MYRIGHTS for %.80s",(char *) t);
+      mm_notify (stream,LOCAL->tmp,WARN);
+      stream->unhealthy = T;
+    }
+    fs_give ((void **) &t);	/* free mailbox name */
+  }
+
+				/* this response has a bizarre syntax! */
+  else if (!strcmp (reply->key,"QUOTA") && (s = reply->text) &&
+	   (t = imap_parse_astring (stream,&s,reply,NIL))) {
+				/* in case error */
+    sprintf (LOCAL->tmp,"Bad quota resource list for %.80s",(char *) t);
+    if (s && (*s++ == ' ') && (*s++ == '(') && *s && ((*s != ')') || !s[1])) {
+      quota_t qt = (quota_t) mail_parameters (NIL,GET_QUOTA,NIL);
+      QUOTALIST *ql = NIL;
+      QUOTALIST *qc;
+				/* parse non-empty quota resource list */
+      if (*s != ')') for (ql = qc = mail_newquotalist (); T;
+			  qc = qc->next = mail_newquotalist ()) {
+	if ((qc->name = imap_parse_astring (stream,&s,reply,NIL)) && s &&
+	    (*s++ == ' ') && (isdigit (*s) || (LOCAL->loser && (*s == '-')))) {
+	  if (isdigit (*s)) qc->usage = strtoul (s,(char **) &s,10);
+	  else if (t = strchr (s,' ')) t = s;
+	  if ((*s++ == ' ') && (isdigit (*s) || (LOCAL->loser &&(*s == '-')))){
+	    if (isdigit (*s)) qc->limit = strtoul (s,(char **) &s,10);
+	    else if (t = strpbrk (s," )")) t = s;
+				/* another resource follows? */
+	    if (*s == ' ') continue;
+				/* end of resource list? */
+	    if ((*s == ')') && !s[1]) {
+	      if (qt) (*qt) (stream,t,ql);
+	      break;		/* all done */
+	    }
+	  }
+	}
+				/* something bad happened */
+	mm_notify (stream,LOCAL->tmp,WARN);
+	stream->unhealthy = T;
+	break;			/* parse failed */
+      }
+				/* all done with quota resource list now */
+      if (ql) mail_free_quotalist (&ql);
+    }
+    else {
+      mm_notify (stream,LOCAL->tmp,WARN);
+      stream->unhealthy = T;
+    }
+    fs_give ((void **) &t);	/* free root name */
+  }
+  else if (!strcmp (reply->key,"QUOTAROOT") && (s = reply->text) &&
+	   (t = imap_parse_astring (stream,&s,reply,NIL))) {
+    sprintf (LOCAL->tmp,"Bad quota root list for %.80s",(char *) t);
+    if (s && (*s++ == ' ')) {
+      quotaroot_t qr = (quotaroot_t) mail_parameters (NIL,GET_QUOTAROOT,NIL);
+      STRINGLIST *rl = mail_newstringlist ();
+      STRINGLIST *rc = rl;
+      do rc->text.data = (unsigned char *)
+	imap_parse_astring (stream,&s,reply,&rc->text.size);
+      while (rc->text.data && *s && (*s++ == ' ') &&
+	       (rc = rc->next = mail_newstringlist ()));
+      if (!rc->text.data || (s && *s)) {
+	mm_notify (stream,LOCAL->tmp,WARN);
+	stream->unhealthy = T;
+      }
+      else if (qr) (*qr) (stream,t,rl);
+				/* clean up */
+      mail_free_stringlist (&rl);
+    }
+    else {
+      mm_notify (stream,LOCAL->tmp,WARN);
+      stream->unhealthy = T;
+    }
+    fs_give ((void **) &t);
+  }
+
+  else if (!strcmp (reply->key,"OK") || !strcmp (reply->key,"PREAUTH"))
+    imap_parse_response (stream,reply->text,NIL,T);
+  else if (!strcmp (reply->key,"NO"))
+    imap_parse_response (stream,reply->text,WARN,T);
+  else if (!strcmp (reply->key,"BAD"))
+    imap_parse_response (stream,reply->text,ERROR,T);
+  else if (!strcmp (reply->key,"BYE")) {
+    LOCAL->byeseen = T;		/* note that a BYE seen */
+    imap_parse_response (stream,reply->text,BYE,T);
+  }
+  else if (!strcmp (reply->key,"CAPABILITY") && reply->text)
+    imap_parse_capabilities (stream,reply->text);
+  else if (!strcmp (reply->key,"MAILBOX") && reply->text) {
+    if (LOCAL->prefix &&
+	((strlen (LOCAL->prefix) + strlen (reply->text)) < IMAPTMPLEN))
+      sprintf (t = LOCAL->tmp,"%s%s",LOCAL->prefix,(char *) reply->text);
+    else t = reply->text;
+    mm_list (stream,NIL,t,NIL);
+  }
+  else {
+    sprintf (LOCAL->tmp,"Unexpected untagged message: %.80s",
+	     (char *) reply->key);
+    mm_notify (stream,LOCAL->tmp,WARN);
+    stream->unhealthy = T;
+  }
+}
+
+/* Parse human-readable response text
+ * Accepts: mail stream
+ *	    text
+ *	    error level for mm_notify()
+ *	    non-NIL if want mm_notify() event even if no response code
+ */
+
+void imap_parse_response (MAILSTREAM *stream,char *text,long errflg,long ntfy)
+{
+  char *s,*t,*r;
+  size_t i;
+  unsigned long j;
+  MESSAGECACHE *elt;
+  copyuid_t cu;
+  appenduid_t au;
+  SEARCHSET *source = NIL;
+  SEARCHSET *dest = NIL;
+  if (text && (*text == '[') && (t = strchr (s = text + 1,']')) &&
+      ((i = t - s) < IMAPTMPLEN)) {
+    LOCAL->tmp[i] = '\0';	/* make mungable copy of text code */
+    if (s = strchr (strncpy (t = LOCAL->tmp,s,i),' ')) *s++ = '\0';
+    if (s) {			/* have argument? */
+      ntfy = NIL;		/* suppress mm_notify if normal SELECT data */
+      if (!compare_cstring (t,"UIDVALIDITY") &&
+	  ((j = strtoul (s,NIL,10)) != stream->uid_validity)) {
+	mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL);
+	stream->uid_validity = j;
+				/* purge any UIDs in cache */
+	for (j = 1; j <= stream->nmsgs; j++)
+	  if (elt = (MESSAGECACHE *) (*mc) (stream,j,CH_ELT))
+	    elt->private.uid = 0;
+      }
+      else if (!compare_cstring (t,"UIDNEXT"))
+	stream->uid_last = strtoul (s,NIL,10) - 1;
+      else if (!compare_cstring (t,"PERMANENTFLAGS") && (*s == '(') &&
+	       (t[i-1] == ')')) {
+	t[i-1] = '\0';		/* tie off flags */
+	stream->perm_seen = stream->perm_deleted = stream->perm_answered =
+	  stream->perm_draft = stream->kwd_create = NIL;
+	stream->perm_user_flags = NIL;
+	if (s = strtok_r (s+1," ",&r)) do {
+	  if (*s == '\\') {	/* system flags */
+	    if (!compare_cstring (s,"\\Seen")) stream->perm_seen = T;
+	    else if (!compare_cstring (s,"\\Deleted"))
+	      stream->perm_deleted = T;
+	    else if (!compare_cstring (s,"\\Flagged"))
+	      stream->perm_flagged = T;
+	    else if (!compare_cstring (s,"\\Answered"))
+	      stream->perm_answered = T;
+	    else if (!compare_cstring (s,"\\Draft")) stream->perm_draft = T;
+	    else if (!strcmp (s,"\\*")) stream->kwd_create = T;
+	  }
+	  else stream->perm_user_flags |= imap_parse_user_flag (stream,s);
+	}
+	while (s = strtok_r (NIL," ",&r));
+      }
+
+      else if (!compare_cstring (t,"CAPABILITY"))
+	imap_parse_capabilities (stream,s);
+      else if ((j = LEVELUIDPLUS (stream) && LOCAL->appendmailbox) &&
+	       !compare_cstring (t,"COPYUID") &&
+	       (cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL)) &&
+	       isdigit (*s) && (j = strtoul (s,&s,10)) && (*s++ == ' ') &&
+	       (source = mail_parse_set (s,&s)) && (*s++ == ' ') &&
+	       (dest = mail_parse_set (s,&s)) && !*s)
+	(*cu) (stream,LOCAL->appendmailbox,j,source,dest);
+      else if (j && !compare_cstring (t,"APPENDUID") &&
+	       (au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL)) &&
+	       isdigit (*s) && (j = strtoul (s,&s,10)) && (*s++ == ' ') &&
+	       (dest = mail_parse_set (s,&s)) && !*s)
+	(*au) (LOCAL->appendmailbox,j,dest);
+      else {			/* all other response code events */
+	ntfy = T;		/* must mm_notify() */
+	if (!compare_cstring (t,"REFERRAL"))
+	  LOCAL->referral = cpystr (t + 9);
+      }
+      mail_free_searchset (&source);
+      mail_free_searchset (&dest);
+    }
+    else {			/* no arguments */
+      if (!compare_cstring (t,"UIDNOTSTICKY")) {
+	ntfy = NIL;
+	stream->uid_nosticky = T;
+      }
+      else if (!compare_cstring (t,"READ-ONLY")) stream->rdonly = T;
+      else if (!compare_cstring (t,"READ-WRITE"))
+	stream->rdonly = NIL;
+      else if (!compare_cstring (t,"PARSE") && !errflg)
+	errflg = PARSE;
+    }
+  }
+				/* give event to main program */
+  if (ntfy && !stream->silent) mm_notify (stream,text ? text : "",errflg);
+}
+
+/* Parse a namespace
+ * Accepts: mail stream
+ *	    current text pointer
+ *	    parsed reply
+ * Returns: namespace list, text pointer updated
+ */
+
+NAMESPACE *imap_parse_namespace (MAILSTREAM *stream,unsigned char **txtptr,
+				 IMAPPARSEDREPLY *reply)
+{
+  NAMESPACE *ret = NIL;
+  NAMESPACE *nam = NIL;
+  NAMESPACE *prev = NIL;
+  PARAMETER *par = NIL;
+  if (*txtptr) {		/* only if argument given */
+				/* ignore leading space */
+    while (**txtptr == ' ') ++*txtptr;
+    switch (**txtptr) {
+    case 'N':			/* if NIL */
+    case 'n':
+      ++*txtptr;		/* bump past "N" */
+      ++*txtptr;		/* bump past "I" */
+      ++*txtptr;		/* bump past "L" */
+      break;
+    case '(':
+      ++*txtptr;		/* skip past open paren */
+      while (**txtptr == '(') {
+	++*txtptr;		/* skip past open paren */
+	prev = nam;		/* note previous if any */
+	nam = (NAMESPACE *) memset (fs_get (sizeof (NAMESPACE)),0,
+				  sizeof (NAMESPACE));
+	if (!ret) ret = nam;	/* if first time note first namespace */
+				/* if previous link new block to it */
+	if (prev) prev->next = nam;
+	nam->name = imap_parse_string (stream,txtptr,reply,NIL,NIL,NIL);
+				/* ignore whitespace */
+	while (**txtptr == ' ') ++*txtptr;
+	switch (**txtptr) {	/* parse delimiter */
+	case 'N':
+	case 'n':
+	  *txtptr += 3;		/* bump past "NIL" */
+	  break;
+	case '"':
+	  if (*++*txtptr == '\\') nam->delimiter = *++*txtptr;
+	  else nam->delimiter = **txtptr;
+	  *txtptr += 2;		/* bump past character and closing quote */
+	  break;
+	default:
+	  sprintf (LOCAL->tmp,"Missing delimiter in namespace: %.80s",
+		   (char *) *txtptr);
+	  mm_notify (stream,LOCAL->tmp,WARN);
+	  stream->unhealthy = T;
+	  *txtptr = NIL;	/* stop parse */
+	  return ret;
+	}
+
+	while (**txtptr == ' '){/* append new parameter to tail */
+	  if (nam->param) par = par->next = mail_newbody_parameter ();
+	  else nam->param = par = mail_newbody_parameter ();
+	  if (!(par->attribute = imap_parse_string (stream,txtptr,reply,NIL,
+						    NIL,NIL))) {
+	    mm_notify (stream,"Missing namespace extension attribute",WARN);
+	    stream->unhealthy = T;
+	    par->attribute = cpystr ("UNKNOWN");
+	  }
+				/* skip space */
+	  while (**txtptr == ' ') ++*txtptr;
+	  if (**txtptr == '(') {/* have value list?  */
+	    char *att = par->attribute;
+	    ++*txtptr;		/* yes */
+	    do {		/* parse each value */
+	      if (!(par->value = imap_parse_string (stream,txtptr,reply,NIL,
+						    NIL,LONGT))) {
+		sprintf (LOCAL->tmp,
+			 "Missing value for namespace attribute %.80s",att);
+		mm_notify (stream,LOCAL->tmp,WARN);
+		stream->unhealthy = T;
+		par->value = cpystr ("UNKNOWN");
+	      }
+				/* is there another value? */
+	      if (**txtptr == ' ') par = par->next = mail_newbody_parameter ();
+	    } while (!par->value);
+	  }
+	  else {
+	    sprintf (LOCAL->tmp,"Missing values for namespace attribute %.80s",
+		     par->attribute);
+	    mm_notify (stream,LOCAL->tmp,WARN);
+	    stream->unhealthy = T;
+	    par->value = cpystr ("UNKNOWN");
+	  }
+	}
+	if (**txtptr == ')') ++*txtptr;
+	else {			/* missing trailing paren */
+	  sprintf (LOCAL->tmp,"Junk at end of namespace: %.80s",
+		   (char *) *txtptr);
+	  mm_notify (stream,LOCAL->tmp,WARN);
+	  stream->unhealthy = T;
+	  return ret;
+	}
+      }
+      if (**txtptr == ')') {	/* expected trailing paren? */
+	++*txtptr;		/* got it! */
+	break;
+      }
+    default:
+      sprintf (LOCAL->tmp,"Not a namespace: %.80s",(char *) *txtptr);
+      mm_notify (stream,LOCAL->tmp,WARN);
+      stream->unhealthy = T;
+      *txtptr = NIL;		/* stop parse now */
+      break;
+    }
+  }
+  return ret;
+}
+
+/* Parse a thread node list
+ * Accepts: mail stream
+ *	    current text pointer
+ * Returns: thread node list, text pointer updated
+ */
+
+THREADNODE *imap_parse_thread (MAILSTREAM *stream,unsigned char **txtptr)
+{
+  char *s;
+  THREADNODE *ret = NIL;	/* returned tree */
+  THREADNODE *last = NIL;	/* last branch in this tree */
+  THREADNODE *parent = NIL;	/* parent of current node */
+  THREADNODE *cur;		/* current node */
+  while (**txtptr == '(') {	/* see a thread? */
+    ++*txtptr;			/* skip past open paren */
+    while (**txtptr != ')') {	/* parse thread */
+      if (**txtptr == '(') {	/* thread branch */
+	cur = imap_parse_thread (stream,txtptr);
+				/* add to parent */
+	if (parent) parent = parent->next = cur;
+	else {			/* no parent, create dummy */
+	  if (last) last = last->branch = mail_newthreadnode (NIL);
+				/* new tree */
+	  else ret = last = mail_newthreadnode (NIL);
+				/* add to dummy parent */
+	  last->next = parent = cur;
+	}
+      }
+				/* threaded message number */
+      else if (isdigit (*(s = *txtptr)) &&
+	       ((cur = mail_newthreadnode (NIL))->num =
+		strtoul (*txtptr,(char **) txtptr,10))) {
+	if (LOCAL->filter && !mail_elt (stream,cur->num)->searched)
+	  cur->num = NIL;	/* make dummy if filtering and not searched */
+				/* add to parent */
+	if (parent) parent = parent->next = cur;
+				/* no parent, start new thread */
+	else if (last) last = last->branch = parent = cur;
+				/* create new tree */
+	else ret = last = parent = cur;
+      }
+      else {			/* anything else is a bogon */
+	char tmp[MAILTMPLEN];
+	sprintf (tmp,"Bogus thread member: %.80s",s);
+	mm_notify (stream,tmp,WARN);
+	stream->unhealthy = T;
+	return ret;
+      }
+				/* skip past any space */
+      if (**txtptr == ' ') ++*txtptr;
+    }
+    ++*txtptr;			/* skip pase end of thread */
+    parent = NIL;		/* close this thread */
+  }
+  return ret;			/* return parsed thread */
+}
+
+/* Parse RFC822 message header
+ * Accepts: MAIL stream
+ *	    envelope to parse into
+ *	    header as sized text
+ *	    stringlist if partial header
+ */
+
+void imap_parse_header (MAILSTREAM *stream,ENVELOPE **env,SIZEDTEXT *hdr,
+			STRINGLIST *stl)
+{
+  ENVELOPE *nenv;
+				/* parse what we can from this header */
+  rfc822_parse_msg (&nenv,NIL,(char *) hdr->data,hdr->size,NIL,
+		    net_host (LOCAL->netstream),stream->dtb->flags);
+  if (*env) {			/* need to merge this header into envelope? */
+    if (!(*env)->newsgroups) {	/* need Newsgroups? */
+      (*env)->newsgroups = nenv->newsgroups;
+      nenv->newsgroups = NIL;
+    }
+    if (!(*env)->followup_to) {	/* need Followup-To? */
+      (*env)->followup_to = nenv->followup_to;
+      nenv->followup_to = NIL;
+    }
+    if (!(*env)->references) {	/* need References? */
+      (*env)->references = nenv->references;
+      nenv->references = NIL;
+    }
+    if (!(*env)->sparep) {	/* need spare pointer? */
+      (*env)->sparep = nenv->sparep;
+      nenv->sparep = NIL;
+    }
+    mail_free_envelope (&nenv);
+    (*env)->imapenvonly = NIL;	/* have complete envelope now */
+  }
+				/* otherwise set it to this envelope */
+  else (*env = nenv)->incomplete = stl ? T : NIL;
+}
+
+/* IMAP parse envelope
+ * Accepts: MAIL stream
+ *	    pointer to envelope pointer
+ *	    current text pointer
+ *	    parsed reply
+ *
+ * Updates text pointer
+ */
+
+void imap_parse_envelope (MAILSTREAM *stream,ENVELOPE **env,
+			  unsigned char **txtptr,IMAPPARSEDREPLY *reply)
+{
+  ENVELOPE *oenv = *env;
+  char c = *((*txtptr)++);	/* grab first character */
+				/* ignore leading spaces */
+  while (c == ' ') c = *((*txtptr)++);
+  switch (c) {			/* dispatch on first character */
+  case '(':			/* if envelope S-expression */
+    *env = mail_newenvelope ();	/* parse the new envelope */
+    (*env)->date = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT);
+    (*env)->subject = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT);
+    (*env)->from = imap_parse_adrlist (stream,txtptr,reply);
+    (*env)->sender = imap_parse_adrlist (stream,txtptr,reply);
+    (*env)->reply_to = imap_parse_adrlist (stream,txtptr,reply);
+    (*env)->to = imap_parse_adrlist (stream,txtptr,reply);
+    (*env)->cc = imap_parse_adrlist (stream,txtptr,reply);
+    (*env)->bcc = imap_parse_adrlist (stream,txtptr,reply);
+    (*env)->in_reply_to = imap_parse_string (stream,txtptr,reply,NIL,NIL,
+					     LONGT);
+    (*env)->message_id = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT);
+    if (oenv) {			/* need to merge old envelope? */
+      (*env)->newsgroups = oenv->newsgroups;
+      oenv->newsgroups = NIL;
+      (*env)->followup_to = oenv->followup_to;
+      oenv->followup_to = NIL;
+      (*env)->references = oenv->references;
+      oenv->references = NIL;
+      mail_free_envelope(&oenv);/* free old envelope */
+    }
+				/* have IMAP envelope components only */
+    else (*env)->imapenvonly = T;
+    if (**txtptr != ')') {
+      sprintf (LOCAL->tmp,"Junk at end of envelope: %.80s",(char *) *txtptr);
+      mm_notify (stream,LOCAL->tmp,WARN);
+      stream->unhealthy = T;
+    }
+    else ++*txtptr;		/* skip past delimiter */
+    break;
+  case 'N':			/* if NIL */
+  case 'n':
+    ++*txtptr;			/* bump past "I" */
+    ++*txtptr;			/* bump past "L" */
+    break;
+  default:
+    sprintf (LOCAL->tmp,"Not an envelope: %.80s",(char *) *txtptr);
+    mm_notify (stream,LOCAL->tmp,WARN);
+    stream->unhealthy = T;
+    break;
+  }
+}
+
+/* IMAP parse address list
+ * Accepts: MAIL stream
+ *	    current text pointer
+ *	    parsed reply
+ * Returns: address list, NIL on failure
+ *
+ * Updates text pointer
+ */
+
+ADDRESS *imap_parse_adrlist (MAILSTREAM *stream,unsigned char **txtptr,
+			     IMAPPARSEDREPLY *reply)
+{
+  ADDRESS *adr = NIL;
+  char c = **txtptr;		/* sniff at first character */
+				/* ignore leading spaces */
+  while (c == ' ') c = *++*txtptr;
+  ++*txtptr;			/* skip past open paren */
+  switch (c) {
+  case '(':			/* if envelope S-expression */
+    adr = imap_parse_address (stream,txtptr,reply);
+    if (**txtptr != ')') {
+      sprintf (LOCAL->tmp,"Junk at end of address list: %.80s",
+	       (char *) *txtptr);
+      mm_notify (stream,LOCAL->tmp,WARN);
+      stream->unhealthy = T;
+    }
+    else ++*txtptr;		/* skip past delimiter */
+    break;
+  case 'N':			/* if NIL */
+  case 'n':
+    ++*txtptr;			/* bump past "I" */
+    ++*txtptr;			/* bump past "L" */
+    break;
+  default:
+    sprintf (LOCAL->tmp,"Not an address: %.80s",(char *) *txtptr);
+    mm_notify (stream,LOCAL->tmp,WARN);
+    stream->unhealthy = T;
+    break;
+  }
+  return adr;
+}
+
+/* IMAP parse address
+ * Accepts: MAIL stream
+ *	    current text pointer
+ *	    parsed reply
+ * Returns: address, NIL on failure
+ *
+ * Updates text pointer
+ */
+
+ADDRESS *imap_parse_address (MAILSTREAM *stream,unsigned char **txtptr,
+			     IMAPPARSEDREPLY *reply)
+{
+  long ingroup = 0;
+  ADDRESS *adr = NIL;
+  ADDRESS *ret = NIL;
+  ADDRESS *prev = NIL;
+  char c = **txtptr;		/* sniff at first address character */
+  switch (c) {
+  case '(':			/* if envelope S-expression */
+    while (c == '(') {		/* recursion dies on small stack machines */
+      ++*txtptr;		/* skip past open paren */
+      if (adr) prev = adr;	/* note previous if any */
+      adr = mail_newaddr ();	/* instantiate address and parse its fields */
+      adr->personal = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT);
+      adr->adl = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT);
+      adr->mailbox = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT);
+      adr->host = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT);
+      if (**txtptr != ')') {	/* handle trailing paren */
+	sprintf (LOCAL->tmp,"Junk at end of address: %.80s",(char *) *txtptr);
+	mm_notify (stream,LOCAL->tmp,WARN);
+	stream->unhealthy = T;
+      }
+      else ++*txtptr;		/* skip past close paren */
+      c = **txtptr;		/* set up for while test */
+				/* ignore leading spaces in front of next */
+      while (c == ' ') c = *++*txtptr;
+
+      if (!adr->mailbox) {	/* end of group? */
+				/* decrement group if all looks well */
+	if (ingroup && !(adr->personal || adr->adl || adr->host)) --ingroup;
+	else {
+	  if (ingroup) {	/* in a group? */
+	    sprintf (LOCAL->tmp,/* yes, must be bad syntax */
+		     "Junk in end of group: pn=%.80s al=%.80s dn=%.80s",
+		     adr->personal ? adr->personal : "",
+		     adr->adl ? adr->adl : "",
+		     adr->host ? adr->host : "");
+	    mm_notify (stream,LOCAL->tmp,WARN);
+	  }
+	  else mm_notify (stream,"End of group encountered when not in group",
+			  WARN);
+	  stream->unhealthy = T;
+	  mail_free_address (&adr);
+	  adr = prev;
+	  prev = NIL;
+	}
+      }
+      else if (!adr->host) {	/* start of group? */
+	if (adr->personal || adr->adl) {
+	  sprintf (LOCAL->tmp,"Junk in start of group: pn=%.80s al=%.80s",
+		   adr->personal ? adr->personal : "",
+		   adr->adl ? adr->adl : "");
+	  mm_notify (stream,LOCAL->tmp,WARN);
+	  stream->unhealthy = T;
+	  mail_free_address (&adr);
+	  adr = prev;
+	  prev = NIL;
+	}
+	else ++ingroup;		/* in a group now */
+      }
+      if (adr) {		/* good address */
+	if (!ret) ret = adr;	/* if first time note first adr */
+				/* if previous link new block to it */
+	if (prev) prev->next = adr;
+				/* flush bogus personal name */
+	if (LOCAL->loser && adr->personal && strchr (adr->personal,'@'))
+	  fs_give ((void **) &adr->personal);
+      }
+    }
+    break;
+  case 'N':			/* if NIL */
+  case 'n':
+    *txtptr += 3;		/* bump past NIL */
+    break;
+  default:
+    sprintf (LOCAL->tmp,"Not an address: %.80s",(char *) *txtptr);
+    mm_notify (stream,LOCAL->tmp,WARN);
+    stream->unhealthy = T;
+    break;
+  }
+  return ret;
+}
+
+/* IMAP parse flags
+ * Accepts: current message cache
+ *	    current text pointer
+ *
+ * Updates text pointer
+ */
+
+void imap_parse_flags (MAILSTREAM *stream,MESSAGECACHE *elt,
+		       unsigned char **txtptr)
+{
+  char *flag;
+  char c = '\0';
+  struct {			/* old flags */
+    unsigned int valid : 1;
+    unsigned int seen : 1;
+    unsigned int deleted : 1;
+    unsigned int flagged : 1;
+    unsigned int answered : 1;
+    unsigned int draft : 1;
+    unsigned long user_flags;
+  } old;
+  old.valid = elt->valid; old.seen = elt->seen; old.deleted = elt->deleted;
+  old.flagged = elt->flagged; old.answered = elt->answered;
+  old.draft = elt->draft; old.user_flags = elt->user_flags;
+  elt->valid = T;		/* mark have valid flags now */
+  elt->user_flags = NIL;	/* zap old flag values */
+  elt->seen = elt->deleted = elt->flagged = elt->answered = elt->draft =
+    elt->recent = NIL;
+  while (c != ')') {		/* parse list of flags */
+				/* point at a flag */
+    while (*(flag = ++*txtptr) == ' ');
+				/* scan for end of flag */
+    while (**txtptr != ' ' && **txtptr != ')') ++*txtptr;
+    c = **txtptr;		/* save delimiter */
+    **txtptr = '\0';		/* tie off flag */
+    if (!*flag) break;		/* null flag */
+				/* if starts with \ must be sys flag */
+    else if (*flag == '\\') {
+      if (!compare_cstring (flag,"\\Seen")) elt->seen = T;
+      else if (!compare_cstring (flag,"\\Deleted")) elt->deleted = T;
+      else if (!compare_cstring (flag,"\\Flagged")) elt->flagged = T;
+      else if (!compare_cstring (flag,"\\Answered")) elt->answered = T;
+      else if (!compare_cstring (flag,"\\Recent")) elt->recent = T;
+      else if (!compare_cstring (flag,"\\Draft")) elt->draft = T;
+    }
+				/* otherwise user flag */
+    else elt->user_flags |= imap_parse_user_flag (stream,flag);
+  }
+  ++*txtptr;			/* bump past delimiter */
+  if (!old.valid || (old.seen != elt->seen) ||
+      (old.deleted != elt->deleted) || (old.flagged != elt->flagged) ||
+      (old.answered != elt->answered) || (old.draft != elt->draft) ||
+      (old.user_flags != elt->user_flags)) mm_flags (stream,elt->msgno);
+}
+
+
+/* IMAP parse user flag
+ * Accepts: MAIL stream
+ *	    flag name
+ * Returns: flag bit position
+ */
+
+unsigned long imap_parse_user_flag (MAILSTREAM *stream,char *flag)
+{
+  long i;
+				/* sniff through all user flags */
+  for (i = 0; i < NUSERFLAGS; ++i) if (stream->user_flags[i])
+    if (!compare_cstring (flag,stream->user_flags[i])) return (1 << i);
+  return (unsigned long) 0;	/* not found */
+}
+
+/* IMAP parse atom-string
+ * Accepts: MAIL stream
+ *	    current text pointer
+ *	    parsed reply
+ *	    returned string length
+ * Returns: string
+ *
+ * Updates text pointer
+ */
+
+unsigned char *imap_parse_astring (MAILSTREAM *stream,unsigned char **txtptr,
+				   IMAPPARSEDREPLY *reply,unsigned long *len)
+{
+  unsigned long i;
+  unsigned char c,*s,*ret;
+				/* ignore leading spaces */
+  for (c = **txtptr; c == ' '; c = *++*txtptr);
+  switch (c) {
+  case '"':			/* quoted string? */
+  case '{':			/* literal? */
+    ret = imap_parse_string (stream,txtptr,reply,NIL,len,NIL);
+    break;
+  default:			/* must be atom */
+    for (c = *(s = *txtptr);	/* find end of atom */
+	 c && (c > ' ') && (c != '(') && (c != ')') && (c != '{') &&
+	   (c != '%') && (c != '*') && (c != '"') && (c != '\\') && (c < 0x80);
+	 c = *++*txtptr);
+    if (i = *txtptr - s) {	/* atom ends at atom_special */
+      if (len) *len = i;	/* return length of atom */
+      ret = strncpy ((char *) fs_get (i + 1),s,i);
+      ret[i] = '\0';		/* tie off string */
+    }
+    else {			/* no atom found */
+      sprintf (LOCAL->tmp,"Not an atom: %.80s",(char *) *txtptr);
+      mm_notify (stream,LOCAL->tmp,WARN);
+      stream->unhealthy = T;
+      if (len) *len = 0;
+      ret = NIL;
+    }
+    break;
+  }
+  return ret;
+}
+
+/* IMAP parse string
+ * Accepts: MAIL stream
+ *	    current text pointer
+ *	    parsed reply
+ *	    mailgets data
+ *	    returned string length
+ *	    filter newline flag
+ * Returns: string
+ *
+ * Updates text pointer
+ */
+
+unsigned char *imap_parse_string (MAILSTREAM *stream,unsigned char **txtptr,
+				  IMAPPARSEDREPLY *reply,GETS_DATA *md,
+				  unsigned long *len,long flags)
+{
+  char *st;
+  char *string = NIL;
+  unsigned long i,j,k;
+  int bogon = NIL;
+  unsigned char c = **txtptr;	/* sniff at first character */
+  mailgets_t mg = (mailgets_t) mail_parameters (NIL,GET_GETS,NIL);
+  readprogress_t rp =
+    (readprogress_t) mail_parameters (NIL,GET_READPROGRESS,NIL);
+				/* ignore leading spaces */
+  while (c == ' ') c = *++*txtptr;
+  st = ++*txtptr;		/* remember start of string */
+  switch (c) {
+  case '"':			/* if quoted string */
+    i = 0;			/* initial byte count */
+				/* search for end of string */
+    for (c = **txtptr; c != '"'; ++i,c = *++*txtptr) {
+				/* backslash quotes next character */
+      if (c == '\\') c = *++*txtptr;
+				/* CHAR8 not permitted in quoted string */
+      if (!bogon && (bogon = (c & 0x80))) {
+	sprintf (LOCAL->tmp,"Invalid CHAR in quoted string: %x",
+		 (unsigned int) c);
+	mm_notify (stream,LOCAL->tmp,WARN);
+	stream->unhealthy = T;
+      }
+      else if (!c) {		/* NUL not permitted either */
+	mm_notify (stream,"Unterminated quoted string",WARN);
+	stream->unhealthy = T;
+	if (len) *len = 0;	/* punt, since may be at end of string */
+	return NIL;
+      }
+    }
+    ++*txtptr;			/* bump past delimiter */
+    string = (char *) fs_get ((size_t) i + 1);
+    for (j = 0; j < i; j++) {	/* copy the string */
+      if (*st == '\\') ++st;	/* quoted character */
+      string[j] = *st++;
+    }
+    string[j] = '\0';		/* tie off string */
+    if (len) *len = i;		/* set return value too */
+    if (md && mg) {		/* have special routine to slurp string? */
+      STRING bs;
+      if (md->first) {		/* partial fetch? */
+	md->first--;		/* restore origin octet */
+	md->last = i;		/* number of octets that we got */
+      }
+      INIT (&bs,mail_string,string,i);
+      (*mg) (mail_read,&bs,i,md);
+    }
+    break;
+
+  case 'N':			/* if NIL */
+  case 'n':
+    ++*txtptr;			/* bump past "I" */
+    ++*txtptr;			/* bump past "L" */
+    if (len) *len = 0;
+    break;
+  case '{':			/* if literal string */
+				/* get size of string */ 
+    if ((i = strtoul (*txtptr,(char **) txtptr,10)) > MAXSERVERLIT) {
+      sprintf (LOCAL->tmp,"Absurd server literal length %lu",i);
+      mm_notify (stream,LOCAL->tmp,WARN);
+      stream->unhealthy = T;	/* read and discard */
+      do net_getbuffer (LOCAL->netstream,j = min (i,(long) IMAPTMPLEN - 1),
+			LOCAL->tmp);
+      while (i -= j);
+    }
+    if (len) *len = i;		/* set return value */
+    if (md && mg) {		/* have special routine to slurp string? */
+      if (md->first) {		/* partial fetch? */
+	md->first--;		/* restore origin octet */
+	md->last = i;		/* number of octets that we got */
+      }
+      else md->flags |= MG_COPY;/* otherwise flag need to copy */
+      string = (*mg) (net_getbuffer,LOCAL->netstream,i,md);
+    }
+    else {			/* must slurp into free storage */
+      string = (char *) fs_get ((size_t) i + 1);
+      *string = '\0';		/* init in case getbuffer fails */
+				/* get the literal */
+      if (rp) for (k = 0; j = min ((long) MAILTMPLEN,(long) i); i -= j) {
+	net_getbuffer (LOCAL->netstream,j,string + k);
+	(*rp) (md,k += j);
+      }
+      else net_getbuffer (LOCAL->netstream,i,string);
+    }
+    fs_give ((void **) &reply->line);
+    if (flags && string)	/* need to filter newlines? */
+      for (st = string; st = strpbrk (st,"\015\012\011"); *st++ = ' ');
+				/* get new reply text line */
+    if (!(reply->line = net_getline (LOCAL->netstream)))
+      reply->line = cpystr ("");
+    if (stream->debug) mm_dlog (reply->line);
+    *txtptr = reply->line;	/* set text pointer to point at it */
+    break;
+  default:
+    sprintf (LOCAL->tmp,"Not a string: %c%.80s",c,(char *) *txtptr);
+    mm_notify (stream,LOCAL->tmp,WARN);
+    stream->unhealthy = T;
+    if (len) *len = 0;
+    break;
+  }
+  return (unsigned char *) string;
+}
+
+/* Register text in IMAP cache
+ * Accepts: MAIL stream
+ *	    message number
+ *	    IMAP segment specifier
+ *	    header string list (if a HEADER section specifier)
+ *	    sized text to register
+ * Returns: non-zero if cache non-empty
+ */
+
+long imap_cache (MAILSTREAM *stream,unsigned long msgno,char *seg,
+		 STRINGLIST *stl,SIZEDTEXT *text)
+{
+  char *t,tmp[MAILTMPLEN];
+  unsigned long i;
+  BODY *b;
+  SIZEDTEXT *ret;
+  STRINGLIST *stc;
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+				/* top-level header never does mailgets */
+  if (!strcmp (seg,"HEADER") || !strcmp (seg,"0") ||
+      !strcmp (seg,"HEADER.FIELDS") || !strcmp (seg,"HEADER.FIELDS.NOT")) {
+    ret = &elt->private.msg.header.text;
+    if (text) {			/* don't do this if no text */
+      if (ret->data) fs_give ((void **) &ret->data);
+      mail_free_stringlist (&elt->private.msg.lines);
+      elt->private.msg.lines = stl;
+				/* prevent cache reuse of .NOT */
+      if ((seg[0] == 'H') && (seg[6] == '.') && (seg[13] == '.'))
+	for (stc = stl; stc; stc = stc->next) stc->text.size = 0;
+      if (stream->scache) {	/* short caching puts it in the stream */
+	if (stream->msgno != msgno) {
+				/* flush old stuff */
+	  mail_free_envelope (&stream->env);
+	  mail_free_body (&stream->body);
+	  stream->msgno = msgno;
+	}
+	imap_parse_header (stream,&stream->env,text,stl);
+      }
+				/* regular caching */
+      else imap_parse_header (stream,&elt->private.msg.env,text,stl);
+    }
+  }
+				/* top level text */
+  else if (!strcmp (seg,"TEXT")) {
+    ret = &elt->private.msg.text.text;
+    if (text && ret->data) fs_give ((void **) &ret->data);
+  }
+  else if (!*seg) {		/* full message */
+    ret = &elt->private.msg.full.text;
+    if (text && ret->data) fs_give ((void **) &ret->data);
+  }
+
+  else {			/* nested, find non-contents specifier */
+    for (t = seg; *t && !((*t == '.') && (isalpha(t[1]) || !atol (t+1))); t++);
+    if (*t) *t++ = '\0';	/* tie off section from data specifier */
+    if (!(b = mail_body (stream,msgno,seg))) {
+      sprintf (tmp,"Unknown section number: %.80s",seg);
+      mm_notify (stream,tmp,WARN);
+      stream->unhealthy = T;
+      return NIL;
+    }
+    if (*t) {			/* if a non-numberic subpart */
+      if ((i = (b->type == TYPEMESSAGE) && (!strcmp (b->subtype,"RFC822"))) &&
+	  (!strcmp (t,"HEADER") || !strcmp (t,"0") ||
+	   !strcmp (t,"HEADER.FIELDS") || !strcmp (t,"HEADER.FIELDS.NOT"))) {
+	ret = &b->nested.msg->header.text;
+	if (text) {
+	  if (ret->data) fs_give ((void **) &ret->data);
+	  mail_free_stringlist (&b->nested.msg->lines);
+	  b->nested.msg->lines = stl;
+				/* prevent cache reuse of .NOT */
+	  if ((t[0] == 'H') && (t[6] == '.') && (t[13] == '.'))
+	    for (stc = stl; stc; stc = stc->next) stc->text.size = 0;
+	  imap_parse_header (stream,&b->nested.msg->env,text,stl);
+	}
+      }
+      else if (i && !strcmp (t,"TEXT")) {
+	ret = &b->nested.msg->text.text;
+	if (text && ret->data) fs_give ((void **) &ret->data);
+      }
+				/* otherwise it must be MIME */
+      else if (!strcmp (t,"MIME")) {
+	ret = &b->mime.text;
+	if (text && ret->data) fs_give ((void **) &ret->data);
+      }
+      else {
+	sprintf (tmp,"Unknown section specifier: %.80s.%.80s",seg,t);
+	mm_notify (stream,tmp,WARN);
+	stream->unhealthy = T;
+	return NIL;
+      }
+    }
+    else {			/* ordinary contents */
+      ret = &b->contents.text;
+      if (text && ret->data) fs_give ((void **) &ret->data);
+    }
+  }
+  if (text) {			/* update cache if requested */
+    ret->data = text->data;
+    ret->size = text->size;
+  }
+  return ret->data ? LONGT : NIL;
+}
+
+/* IMAP parse body structure
+ * Accepts: MAIL stream
+ *	    body structure to write into
+ *	    current text pointer
+ *	    parsed reply
+ *
+ * Updates text pointer
+ */
+
+void imap_parse_body_structure (MAILSTREAM *stream,BODY *body,
+				unsigned char **txtptr,IMAPPARSEDREPLY *reply)
+{
+  int i;
+  char *s;
+  PART *part = NIL;
+  char c = *((*txtptr)++);	/* grab first character */
+				/* ignore leading spaces */
+  while (c == ' ') c = *((*txtptr)++);
+  switch (c) {			/* dispatch on first character */
+  case '(':			/* body structure list */
+    if (**txtptr == '(') {	/* multipart body? */
+      body->type= TYPEMULTIPART;/* yes, set its type */
+      do {			/* instantiate new body part */
+	if (part) part = part->next = mail_newbody_part ();
+	else body->nested.part = part = mail_newbody_part ();
+				/* parse it */
+	imap_parse_body_structure (stream,&part->body,txtptr,reply);
+      } while (**txtptr == '(');/* for each body part */
+      if (body->subtype = imap_parse_string(stream,txtptr,reply,NIL,NIL,LONGT))
+	ucase (body->subtype);
+      else {
+	mm_notify (stream,"Missing multipart subtype",WARN);
+	stream->unhealthy = T;
+	body->subtype = cpystr (rfc822_default_subtype (body->type));
+      }
+      if (**txtptr == ' ')	/* multipart parameters */
+	body->parameter = imap_parse_body_parameter (stream,txtptr,reply);
+      if (**txtptr == ' ') {	/* disposition */
+	imap_parse_disposition (stream,body,txtptr,reply);
+	if (LOCAL->cap.extlevel < BODYEXTDSP) LOCAL->cap.extlevel = BODYEXTDSP;
+      }
+      if (**txtptr == ' ') {	/* language */
+	body->language = imap_parse_language (stream,txtptr,reply);
+	if (LOCAL->cap.extlevel < BODYEXTLANG)
+	  LOCAL->cap.extlevel = BODYEXTLANG;
+      }
+      if (**txtptr == ' ') {	/* location */
+	body->location = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT);
+	if (LOCAL->cap.extlevel < BODYEXTLOC) LOCAL->cap.extlevel = BODYEXTLOC;
+      }
+      while (**txtptr == ' ') imap_parse_extension (stream,txtptr,reply);
+      if (**txtptr != ')') {	/* validate ending */
+	sprintf (LOCAL->tmp,"Junk at end of multipart body: %.80s",
+		 (char *) *txtptr);
+	mm_notify (stream,LOCAL->tmp,WARN);
+	stream->unhealthy = T;
+      }
+      else ++*txtptr;		/* skip past delimiter */
+    }
+
+    else {			/* not multipart, parse type name */
+      if (**txtptr == ')') {	/* empty body? */
+	++*txtptr;		/* bump past it */
+	break;			/* and punt */
+      }
+      body->type = TYPEOTHER;	/* assume unknown type */
+      body->encoding = ENCOTHER;/* and unknown encoding */
+				/* parse type */
+      if (s = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT)) {
+	ucase (s);		/* application always gets uppercase form */
+	for (i = 0;		/* look in existing table */
+	     (i <= TYPEMAX) && body_types[i] && strcmp (s,body_types[i]); i++);
+	if (i <= TYPEMAX) {	/* only if found a slot */
+	  body->type = i;	/* set body type */
+	  if (body_types[i]) fs_give ((void **) &s);
+	  else body_types[i]=s;	/* assign empty slot */
+	}
+      }
+      if (body->subtype = imap_parse_string(stream,txtptr,reply,NIL,NIL,LONGT))
+	ucase (body->subtype);	/* parse subtype */
+      else {
+	mm_notify (stream,"Missing body subtype",WARN);
+	stream->unhealthy = T;
+	body->subtype = cpystr (rfc822_default_subtype (body->type));
+      }
+      body->parameter = imap_parse_body_parameter (stream,txtptr,reply);
+      body->id = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT);
+      body->description = imap_parse_string (stream,txtptr,reply,NIL,NIL,
+					     LONGT);
+      if (s = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT)) {
+	ucase (s);		/* application always gets uppercase form */
+	for (i = 0;		/* search for body encoding */
+	     (i <= ENCMAX) && body_encodings[i] && strcmp(s,body_encodings[i]);
+	     i++);
+	if (i > ENCMAX) body->encoding = ENCOTHER;
+	else {			/* only if found a slot */
+	  body->encoding = i;	/* set body encoding */
+	  if (body_encodings[i]) fs_give ((void **) &s);
+				/* assign empty slot */
+	  else body_encodings[i] = s;
+	}
+      }
+				/* parse size of contents in bytes */
+      body->size.bytes = strtoul (*txtptr,(char **) txtptr,10);
+      switch (body->type) {	/* possible extra stuff */
+      case TYPEMESSAGE:		/* message envelope and body */
+				/* non MESSAGE/RFC822 is basic type */
+	if (strcmp (body->subtype,"RFC822")) break;
+	{			/* make certain server sends an envelope */
+	  ENVELOPE *env = NIL;
+	  imap_parse_envelope (stream,&env,txtptr,reply);
+	  if (!env) {
+	    mm_notify (stream,"Missing body message envelope",WARN);
+	    stream->unhealthy = T;
+	    body->subtype = cpystr ("RFC822_MISSING_ENVELOPE");
+	    break;
+	  }
+	  (body->nested.msg = mail_newmsg ())->env = env;
+	}
+	body->nested.msg->body = mail_newbody ();
+	imap_parse_body_structure (stream,body->nested.msg->body,txtptr,reply);
+				/* drop into text case */
+      case TYPETEXT:		/* size in lines */
+	body->size.lines = strtoul (*txtptr,(char **) txtptr,10);
+	break;
+      default:			/* otherwise nothing special */
+	break;
+      }
+
+      if (**txtptr == ' ') {	/* extension data - md5 */
+	body->md5 = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT);
+	if (LOCAL->cap.extlevel < BODYEXTMD5) LOCAL->cap.extlevel = BODYEXTMD5;
+      }
+      if (**txtptr == ' ') {	/* disposition */
+	imap_parse_disposition (stream,body,txtptr,reply);
+	if (LOCAL->cap.extlevel < BODYEXTDSP) LOCAL->cap.extlevel = BODYEXTDSP;
+      }
+      if (**txtptr == ' ') {	/* language */
+	body->language = imap_parse_language (stream,txtptr,reply);
+	if (LOCAL->cap.extlevel < BODYEXTLANG)
+	  LOCAL->cap.extlevel = BODYEXTLANG;
+      }
+      if (**txtptr == ' ') {	/* location */
+	body->location = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT);
+	if (LOCAL->cap.extlevel < BODYEXTLOC) LOCAL->cap.extlevel = BODYEXTLOC;
+      }
+      while (**txtptr == ' ') imap_parse_extension (stream,txtptr,reply);
+      if (**txtptr != ')') {	/* validate ending */
+	sprintf (LOCAL->tmp,"Junk at end of body part: %.80s",
+		 (char *) *txtptr);
+	mm_notify (stream,LOCAL->tmp,WARN);
+	stream->unhealthy = T;
+      }
+      else ++*txtptr;		/* skip past delimiter */
+    }
+    break;
+  case 'N':			/* if NIL */
+  case 'n':
+    ++*txtptr;			/* bump past "I" */
+    ++*txtptr;			/* bump past "L" */
+    break;
+  default:			/* otherwise quite bogus */
+    sprintf (LOCAL->tmp,"Bogus body structure: %.80s",(char *) *txtptr);
+    mm_notify (stream,LOCAL->tmp,WARN);
+    stream->unhealthy = T;
+    break;
+  }
+}
+
+/* IMAP parse body parameter
+ * Accepts: MAIL stream
+ *	    current text pointer
+ *	    parsed reply
+ * Returns: body parameter
+ * Updates text pointer
+ */
+
+PARAMETER *imap_parse_body_parameter (MAILSTREAM *stream,
+				      unsigned char **txtptr,
+				      IMAPPARSEDREPLY *reply)
+{
+  PARAMETER *ret = NIL;
+  PARAMETER *par = NIL;
+  char c,*s;
+				/* ignore leading spaces */
+  while ((c = *(*txtptr)++) == ' ');
+				/* parse parameter list */
+  if (c == '(') while (c != ')') {
+				/* append new parameter to tail */
+    if (ret) par = par->next = mail_newbody_parameter ();
+    else ret = par = mail_newbody_parameter ();
+    if(!(par->attribute=imap_parse_string (stream,txtptr,reply,NIL,NIL,
+					   LONGT))) {
+      mm_notify (stream,"Missing parameter attribute",WARN);
+      stream->unhealthy = T;
+      par->attribute = cpystr ("UNKNOWN");
+    }
+    if (!(par->value = imap_parse_string (stream,txtptr,reply,NIL,NIL,LONGT))){
+      sprintf (LOCAL->tmp,"Missing value for parameter %.80s",par->attribute);
+      mm_notify (stream,LOCAL->tmp,WARN);
+      stream->unhealthy = T;
+      par->value = cpystr ("UNKNOWN");
+    }
+    switch (c = **txtptr) {	/* see what comes after */
+    case ' ':			/* flush whitespace */
+      while ((c = *++*txtptr) == ' ');
+      break;
+    case ')':			/* end of attribute/value pairs */
+      ++*txtptr;		/* skip past closing paren */
+      break;
+    default:
+      sprintf (LOCAL->tmp,"Junk at end of parameter: %.80s",(char *) *txtptr);
+      mm_notify (stream,LOCAL->tmp,WARN);
+      stream->unhealthy = T;
+      break;
+    }
+  }
+				/* empty parameter, must be NIL */
+  else if (((c == 'N') || (c == 'n')) &&
+	   ((*(s = *txtptr) == 'I') || (*s == 'i')) &&
+	   ((s[1] == 'L') || (s[1] == 'l'))) *txtptr += 2;
+  else {
+    sprintf (LOCAL->tmp,"Bogus body parameter: %c%.80s",c,
+	     (char *) (*txtptr) - 1);
+    mm_notify (stream,LOCAL->tmp,WARN);
+    stream->unhealthy = T;
+  }
+  return ret;
+}
+
+/* IMAP parse body disposition
+ * Accepts: MAIL stream
+ *	    body structure to write into
+ *	    current text pointer
+ *	    parsed reply
+ */
+
+void imap_parse_disposition (MAILSTREAM *stream,BODY *body,
+			     unsigned char **txtptr,IMAPPARSEDREPLY *reply)
+{
+  switch (*++*txtptr) {
+  case '(':
+    ++*txtptr;			/* skip open paren */
+    body->disposition.type = imap_parse_string (stream,txtptr,reply,NIL,NIL,
+						LONGT);
+    body->disposition.parameter =
+      imap_parse_body_parameter (stream,txtptr,reply);
+    if (**txtptr != ')') {	/* validate ending */
+      sprintf (LOCAL->tmp,"Junk at end of disposition: %.80s",
+	       (char *) *txtptr);
+      mm_notify (stream,LOCAL->tmp,WARN);
+      stream->unhealthy = T;
+    }
+    else ++*txtptr;		/* skip past delimiter */
+    break;
+  case 'N':			/* if NIL */
+  case 'n':
+    ++*txtptr;			/* bump past "N" */
+    ++*txtptr;			/* bump past "I" */
+    ++*txtptr;			/* bump past "L" */
+    break;
+  default:
+    sprintf (LOCAL->tmp,"Unknown body disposition: %.80s",(char *) *txtptr);
+    mm_notify (stream,LOCAL->tmp,WARN);
+    stream->unhealthy = T;
+				/* try to skip to next space */
+    while ((*++*txtptr != ' ') && (**txtptr != ')') && **txtptr);
+    break;
+  }
+}
+
+/* IMAP parse body language
+ * Accepts: MAIL stream
+ *	    current text pointer
+ *	    parsed reply
+ * Returns: string list or NIL if empty or error
+ */
+
+STRINGLIST *imap_parse_language (MAILSTREAM *stream,unsigned char **txtptr,
+				 IMAPPARSEDREPLY *reply)
+{
+  unsigned long i;
+  char *s;
+  STRINGLIST *ret = NIL;
+				/* language is a list */
+  if (*++*txtptr == '(') ret = imap_parse_stringlist (stream,txtptr,reply);
+  else if (s = imap_parse_string (stream,txtptr,reply,NIL,&i,LONGT)) {
+    (ret = mail_newstringlist ())->text.data = (unsigned char *) s;
+    ret->text.size = i;
+  }
+  return ret;
+}
+
+/* IMAP parse string list
+ * Accepts: MAIL stream
+ *	    current text pointer
+ *	    parsed reply
+ * Returns: string list or NIL if empty or error
+ */
+
+STRINGLIST *imap_parse_stringlist (MAILSTREAM *stream,unsigned char **txtptr,
+				   IMAPPARSEDREPLY *reply)
+{
+  STRINGLIST *stl = NIL;
+  STRINGLIST *stc = NIL;
+  unsigned char *t = *txtptr;
+				/* parse the list */
+  if (*t++ == '(') while (*t != ')') {
+    if (stl) stc = stc->next = mail_newstringlist ();
+    else stc = stl = mail_newstringlist ();
+				/* parse astring */
+    if (!(stc->text.data =
+	  imap_parse_astring (stream,&t,reply,&stc->text.size))) {
+      sprintf (LOCAL->tmp,"Bogus string list member: %.80s",(char *) t);
+      mm_notify (stream,LOCAL->tmp,WARN);
+      stream->unhealthy = T;
+      mail_free_stringlist (&stl);
+      break;
+    }
+    else if (*t == ' ') ++t;	/* another token follows */
+  }
+  if (stl) *txtptr = ++t;	/* update return string */
+  return stl;
+}
+
+/* IMAP parse unknown body extension data
+ * Accepts: MAIL stream
+ *	    current text pointer
+ *	    parsed reply
+ *
+ * Updates text pointer
+ */
+
+void imap_parse_extension (MAILSTREAM *stream,unsigned char **txtptr,
+			   IMAPPARSEDREPLY *reply)
+{
+  unsigned long i,j;
+  switch (*++*txtptr) {		/* action depends upon first character */
+  case '(':
+    while (**txtptr != ')') imap_parse_extension (stream,txtptr,reply);
+    ++*txtptr;			/* bump past closing parenthesis */
+    break;
+  case '"':			/* if quoted string */
+    while (*++*txtptr != '"') if (**txtptr == '\\') ++*txtptr;
+    ++*txtptr;			/* bump past closing quote */
+    break;
+  case 'N':			/* if NIL */
+  case 'n':
+    ++*txtptr;			/* bump past "N" */
+    ++*txtptr;			/* bump past "I" */
+    ++*txtptr;			/* bump past "L" */
+    break;
+  case '{':			/* get size of literal */
+    ++*txtptr;			/* bump past open squiggle */
+    if (i = strtoul (*txtptr,(char **) txtptr,10)) do
+      net_getbuffer (LOCAL->netstream,j = min (i,(long) IMAPTMPLEN - 1),
+		     LOCAL->tmp);
+    while (i -= j);
+				/* get new reply text line */
+    if (!(reply->line = net_getline (LOCAL->netstream)))
+      reply->line = cpystr ("");
+    if (stream->debug) mm_dlog (reply->line);
+    *txtptr = reply->line;	/* set text pointer to point at it */
+    break;
+  case '0': case '1': case '2': case '3': case '4':
+  case '5': case '6': case '7': case '8': case '9':
+    strtoul (*txtptr,(char **) txtptr,10);
+    break;
+  default:
+    sprintf (LOCAL->tmp,"Unknown extension token: %.80s",(char *) *txtptr);
+    mm_notify (stream,LOCAL->tmp,WARN);
+    stream->unhealthy = T;
+				/* try to skip to next space */
+    while ((*++*txtptr != ' ') && (**txtptr != ')') && **txtptr);
+    break;
+  }
+}
+
+/* IMAP parse capabilities
+ * Accepts: MAIL stream
+ *	    capability list
+ */
+
+void imap_parse_capabilities (MAILSTREAM *stream,char *t)
+{
+  char *s,*r;
+  unsigned long i;
+  THREADER *thr,*th;
+  if (!LOCAL->gotcapability) {	/* need to save previous capabilities? */
+				/* no, flush threaders */
+    if (thr = LOCAL->cap.threader) while (th = thr) {
+      fs_give ((void **) &th->name);
+      thr = th->next;
+      fs_give ((void **) &th);
+    }
+				/* zap capabilities */
+    memset (&LOCAL->cap,0,sizeof (LOCAL->cap));
+    LOCAL->gotcapability = T;	/* flag that capabilities arrived */
+  }
+  for (t = strtok_r (t," ",&r); t; t = strtok_r (NIL," ",&r)) {
+    if (!compare_cstring (t,"IMAP4"))
+      LOCAL->cap.imap4 = LOCAL->cap.imap2bis = LOCAL->cap.rfc1176 = T;
+    else if (!compare_cstring (t,"IMAP4rev1"))
+      LOCAL->cap.imap4rev1 = LOCAL->cap.imap2bis = LOCAL->cap.rfc1176 = T;
+    else if (!compare_cstring (t,"IMAP2")) LOCAL->cap.rfc1176 = T;
+    else if (!compare_cstring (t,"IMAP2bis"))
+      LOCAL->cap.imap2bis = LOCAL->cap.rfc1176 = T;
+    else if (!compare_cstring (t,"ACL")) LOCAL->cap.acl = T;
+    else if (!compare_cstring (t,"QUOTA")) LOCAL->cap.quota = T;
+    else if (!compare_cstring (t,"LITERAL+")) LOCAL->cap.litplus = T;
+    else if (!compare_cstring (t,"IDLE")) LOCAL->cap.idle = T;
+    else if (!compare_cstring (t,"MAILBOX-REFERRALS")) LOCAL->cap.mbx_ref = T;
+    else if (!compare_cstring (t,"LOGIN-REFERRALS")) LOCAL->cap.log_ref = T;
+    else if (!compare_cstring (t,"NAMESPACE")) LOCAL->cap.namespace = T;
+    else if (!compare_cstring (t,"UIDPLUS")) LOCAL->cap.uidplus = T;
+    else if (!compare_cstring (t,"STARTTLS")) LOCAL->cap.starttls = T;
+    else if (!compare_cstring (t,"LOGINDISABLED"))LOCAL->cap.logindisabled = T;
+    else if (!compare_cstring (t,"ID")) LOCAL->cap.id = T;
+    else if (!compare_cstring (t,"CHILDREN")) LOCAL->cap.children = T;
+    else if (!compare_cstring (t,"MULTIAPPEND")) LOCAL->cap.multiappend = T;
+    else if (!compare_cstring (t,"BINARY")) LOCAL->cap.binary = T;
+    else if (!compare_cstring (t,"UNSELECT")) LOCAL->cap.unselect = T;
+    else if (!compare_cstring (t,"SASL-IR")) LOCAL->cap.sasl_ir = T;
+    else if (!compare_cstring (t,"SCAN")) LOCAL->cap.scan = T;
+    else if (!compare_cstring (t,"URLAUTH")) LOCAL->cap.urlauth = T;
+    else if (!compare_cstring (t,"CATENATE")) LOCAL->cap.catenate = T;
+    else if (!compare_cstring (t,"CONDSTORE")) LOCAL->cap.condstore = T;
+    else if (!compare_cstring (t,"ESEARCH")) LOCAL->cap.esearch = T;
+    else if (((t[0] == 'S') || (t[0] == 's')) &&
+	     ((t[1] == 'O') || (t[1] == 'o')) &&
+	     ((t[2] == 'R') || (t[2] == 'r')) &&
+	     ((t[3] == 'T') || (t[3] == 't'))) LOCAL->cap.sort = T;
+				/* capability with value? */
+    else if (s = strchr (t,'=')) {
+      *s++ = '\0';		/* separate token from value */
+      if (!compare_cstring (t,"THREAD") && !LOCAL->loser) {
+	THREADER *thread = (THREADER *) fs_get (sizeof (THREADER));
+	thread->name = cpystr (s);
+	thread->dispatch = NIL;
+	thread->next = LOCAL->cap.threader;
+	LOCAL->cap.threader = thread;
+      }
+      else if (!compare_cstring (t,"AUTH")) {
+	if ((i = mail_lookup_auth_name (s,LOCAL->authflags)) &&
+	    (--i < MAXAUTHENTICATORS)) LOCAL->cap.auth |= (1 << i);
+	else if (!compare_cstring (s,"ANONYMOUS")) LOCAL->cap.authanon = T;
+      }
+    }
+				/* ignore other capabilities */
+  }
+				/* disable LOGIN if PLAIN also advertised */
+  if ((i = mail_lookup_auth_name ("PLAIN",NIL)) && (--i < MAXAUTHENTICATORS) &&
+      (LOCAL->cap.auth & (1 << i)) &&
+      (i = mail_lookup_auth_name ("LOGIN",NIL)) && (--i < MAXAUTHENTICATORS))
+    LOCAL->cap.auth &= ~(1 << i);
+}
+
+/* IMAP load cache
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    flags
+ * Returns: parsed reply from fetch
+ */
+
+IMAPPARSEDREPLY *imap_fetch (MAILSTREAM *stream,char *sequence,long flags)
+{
+  int i = 2;
+  char *cmd = (LEVELIMAP4 (stream) && (flags & FT_UID)) ?
+    "UID FETCH" : "FETCH";
+  IMAPARG *args[9],aseq,aarg,aenv,ahhr,axtr,ahtr,abdy,atrl;
+  if (LOCAL->loser) sequence = imap_reform_sequence (stream,sequence,
+						     flags & FT_UID);
+  args[0] = &aseq; aseq.type = SEQUENCE; aseq.text = (void *) sequence;
+  args[1] = &aarg; aarg.type = ATOM;
+  aenv.type = ATOM; aenv.text = (void *) "ENVELOPE";
+  ahhr.type = ATOM; ahhr.text = (void *) hdrheader[LOCAL->cap.extlevel];
+  axtr.type = ATOM; axtr.text = (void *) imap_extrahdrs;
+  ahtr.type = ATOM; ahtr.text = (void *) hdrtrailer;
+  abdy.type = ATOM; abdy.text = (void *) "BODYSTRUCTURE";
+  atrl.type = ATOM; atrl.text = (void *) "INTERNALDATE RFC822.SIZE FLAGS)";
+  if (LEVELIMAP4 (stream)) {	/* include UID if IMAP4 or IMAP4rev1 */
+    aarg.text = (void *) "(UID";
+    if (flags & FT_NEEDENV) {	/* if need envelopes */
+      args[i++] = &aenv;	/* include envelope */
+				/* extra header poop if IMAP4rev1 */
+      if (!(flags & FT_NOHDRS) && LEVELIMAP4rev1 (stream)) {
+	args[i++] = &ahhr;	/* header header */
+	if (axtr.text) args[i++] = &axtr;
+	args[i++] = &ahtr;	/* header trailer */
+      }
+				/* fetch body if requested */
+      if (flags & FT_NEEDBODY) args[i++] = &abdy;
+    }
+    args[i++] = &atrl;		/* fetch trailer */
+  }
+				/* easy if IMAP2 */
+  else aarg.text = (void *) (flags & FT_NEEDENV) ?
+    ((flags & FT_NEEDBODY) ?
+     "(RFC822.HEADER BODY INTERNALDATE RFC822.SIZE FLAGS)" :
+     "(RFC822.HEADER INTERNALDATE RFC822.SIZE FLAGS)") : "FAST";
+  args[i] = NIL;		/* tie off command */
+  return imap_send (stream,cmd,args);
+}
+
+/* Reform sequence for losing server that doesn't handle ranges right
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    non-zero if UID
+ * Returns: sequence
+ */
+
+char *imap_reform_sequence (MAILSTREAM *stream,char *sequence,long flags)
+{
+  unsigned long i,j,star;
+  char *s,*t,*tl,*rs;
+				/* can't win if empty */
+  if (!stream->nmsgs) return sequence;
+				/* get highest possible range value */
+  star = flags ? mail_uid (stream,stream->nmsgs) : stream->nmsgs;
+				/* flush old reformed sequence */
+  if (LOCAL->reform) fs_give ((void **) &LOCAL->reform);
+  rs = LOCAL->reform = (char *) fs_get (1+ strlen (sequence));
+  for (s = sequence; t = strpbrk (s,",:"); ) switch (*t++) {
+  case ',':			/* single message */
+    strncpy (rs,s,i = t - s);	/* copy string up to that point */
+    rs += i;			/* advance destination pointer */
+    s += i;			/* and source */
+    break;
+  case ':':			/* message range */
+    i = (*s == '*') ? star : strtoul (s,NIL,10);
+    if (*t == '*') {		/* range ends with star */
+      j = star;
+      tl = t+1;
+    }
+    else {			/* numeric range end */
+      j = strtoul (t,(char **) &tl,10);
+      if (!tl) tl = t + strlen (t);
+    }
+    if (i <= j) {		/* if first less than second */
+      if (*tl) tl++;		/* skip past end of range if present */
+      strncpy (rs,s,i = tl - s);/* copy string up to that point */
+      rs += i;			/* advance destination and source pointers */
+      s += i;
+    }
+    else {			/* here's the workaround for losing servers */
+      strncpy (rs,t,i = tl - t);/* swap the order */
+      rs[i] = ':';		/* delimit */
+      strncpy (rs+i+1,s,j = (t-1) - s);
+      rs += i + 1 + j;		/* advance destination pointer */
+      if (*tl) *rs++ = *tl++;	/* write trailing delimiter if present */
+      s = tl;			/* advance source pointer */
+    }
+  }
+  if (*s) strcpy (rs,s);	/* write remainder of sequence */
+  else *rs = '\0';		/* tie off string */
+  return LOCAL->reform;
+}
+
+/* IMAP return host name
+ * Accepts: MAIL stream
+ * Returns: host name
+ */
+
+char *imap_host (MAILSTREAM *stream)
+{
+  if (stream->dtb != &imapdriver)
+    fatal ("imap_host called on non-IMAP stream!");
+				/* return host name on stream if open */
+  return (LOCAL && LOCAL->netstream) ? net_host (LOCAL->netstream) :
+    ".NO-IMAP-CONNECTION.";
+}
+
+
+/* IMAP return IMAP capability structure
+ * Accepts: MAIL stream
+ * Returns: IMAP capability structure
+ */
+
+IMAPCAP *imap_cap (MAILSTREAM *stream)
+{
+  if (stream->dtb != &imapdriver)
+    fatal ("imap_cap called on non-IMAP stream!");
+  return &LOCAL->cap;		/* return capability structure */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/imap4r1.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,281 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Interactive Mail Access Protocol 4rev1 (IMAP4R1) routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	14 October 1988
+ * Last Edited:	5 September 2007
+ */
+
+
+/* This include file is provided for applications which need to look under
+ * the covers at the IMAP driver and in particular want to do different
+ * operations depending upon the IMAP server's protocol level and
+ * capabilities.  It is NOT included in the normal c-client.h application
+ * export, and most applications do NOT need the definitions in this file.
+ *
+ * As of October 15, 2003, it is believed that:
+ *
+ * Version	RFC		Status		Known Implementations
+ * -------	---		------		---------------------
+ * IMAP1	none		extinct		experimental TOPS-20 server
+ * IMAP2	1064		extinct		old TOPS-20, SUMEX servers
+ * IMAP2	1176		rare		TOPS-20, old UW servers
+ * IMAP2bis	expired I-D	uncommon	old UW, Cyrus servers
+ * IMAP3	1203		extinct		none (never implemented)
+ * IMAP4	1730		rare		old UW, Cyrus, Netscape servers
+ * IMAP4rev1	2060, 3501	ubiquitous	UW, Cyrus, and many others
+ *
+ * Most client implementations will only interoperate with an IMAP4rev1
+ * server.  c-client based client implementations can interoperate with IMAP2,
+ * IMAP2bis, IMAP4, and IMAP4rev1 servers, but only if they are very careful.
+ *
+ * The LEVELxxx() macros in this file enable the client to determine the
+ * server protocol level and capabilities.  This file also contains a few
+ * backdoor calls into the IMAP driver.
+ */
+
+/* Server protocol level and capabilities */
+
+typedef struct imap_cap {
+  unsigned int rfc1176 : 1;	/* server is RFC-1176 IMAP2 */
+  unsigned int imap2bis : 1;	/* server is IMAP2bis */
+  unsigned int imap4 : 1;	/* server is IMAP4 (RFC 1730) */
+  unsigned int imap4rev1 : 1;	/* server is IMAP4rev1 */
+  unsigned int acl : 1;		/* server has ACL (RFC 2086) */
+  unsigned int quota : 1;	/* server has QUOTA (RFC 2087) */
+  unsigned int litplus : 1;	/* server has LITERAL+ (RFC 2088) */
+  unsigned int idle : 1;	/* server has IDLE (RFC 2177) */
+  unsigned int mbx_ref : 1;	/* server has mailbox referrals (RFC 2193) */
+  unsigned int log_ref : 1;	/* server has login referrals (RFC 2221) */
+  unsigned int authanon : 1;	/* server has anonymous SASL (RFC 2245) */
+  unsigned int namespace :1;	/* server has NAMESPACE (RFC 2342) */
+  unsigned int uidplus : 1;	/* server has UIDPLUS (RFC 2359) */
+  unsigned int starttls : 1;	/* server has STARTTLS (RFC 2595) */
+				/* server disallows LOGIN command (RFC 2595) */
+  unsigned int logindisabled : 1;
+  unsigned int id : 1;		/* server has ID (RFC 2971) */
+  unsigned int children : 1;	/* server has CHILDREN (RFC 3348) */
+  unsigned int multiappend : 1;	/* server has multi-APPEND (RFC 3502) ;*/
+  unsigned int binary : 1;	/* server has BINARY (RFC 3516) */
+  unsigned int unselect : 1;	/* server has UNSELECT */
+  unsigned int sasl_ir : 1;	/* server has SASL-IR initial response */
+  unsigned int sort : 1;	/* server has SORT */
+  unsigned int scan : 1;	/* server has SCAN */
+  unsigned int urlauth : 1;	/* server has URLAUTH (RFC 4467) */
+  unsigned int catenate : 1;	/* server has CATENATE (RFC 4469) */
+  unsigned int condstore : 1;	/* server has CONDSTORE (RFC 4551) */
+  unsigned int esearch : 1;	/* server has ESEARCH (RFC 4731) */
+  unsigned int within : 1;	/* server has WITHIN (RFC 5032) */
+  unsigned int extlevel;	/* extension data level supported by server */
+				/* supported authenticators */
+  unsigned int auth : MAXAUTHENTICATORS;
+  THREADER *threader;		/* list of threaders */
+} IMAPCAP;
+
+/* IMAP4rev1 level or better */
+
+#define LEVELIMAP4rev1(stream) imap_cap (stream)->imap4rev1
+
+#define LEVELSTATUS LEVELIMAP4rev1
+
+
+/* IMAP4 level or better (not including RFC 1730 design mistakes) */
+
+#define LEVELIMAP4(stream) (imap_cap (stream)->imap4rev1 || \
+			    imap_cap (stream)->imap4)
+
+
+/* IMAP4 RFC-1730 level */
+
+#define LEVEL1730(stream) imap_cap (stream)->imap4
+
+
+/* IMAP2bis level or better */
+
+#define LEVELIMAP2bis(stream) imap_cap (stream)->imap2bis
+
+
+/* IMAP2 RFC-1176 level or better */
+
+#define LEVEL1176(stream) imap_cap (stream)->rfc1176
+
+
+/* IMAP2 RFC-1064 or better */
+
+#define LEVEL1064(stream) 1
+
+/* Has ACL extension */
+
+#define LEVELACL(stream) imap_cap (stream)->acl
+
+
+/* Has QUOTA extension */
+
+#define LEVELQUOTA(stream) imap_cap (stream)->quota
+
+
+/* Has LITERALPLUS extension */
+
+#define LEVELLITERALPLUS(stream) imap_cap (stream)->litplus
+
+
+/* Has IDLE extension */
+
+#define LEVELIDLE(stream) imap_cap (stream)->idle
+
+
+/* Has mailbox referrals */
+
+#define LEVELMBX_REF(stream) imap_cap (stream)->mbx_ref
+
+
+/* Has login referrals */
+
+#define LEVELLOG_REF(stream) imap_cap (stream)->log_ref
+
+
+/* Has AUTH=ANONYMOUS extension */
+
+#define LEVELANONYMOUS(stream) imap_cap (stream)->authanon
+
+
+/* Has NAMESPACE extension */
+
+#define LEVELNAMESPACE(stream) imap_cap (stream)->namespace
+
+
+/* Has UIDPLUS extension */
+
+#define LEVELUIDPLUS(stream) imap_cap (stream)->uidplus
+
+
+/* Has STARTTLS extension */
+
+#define LEVELSTARTTLS(stream) imap_cap (stream)->starttls
+
+
+/* Has LOGINDISABLED extension */
+
+#define LEVELLOGINDISABLED(stream) imap_cap (stream)->logindisabled
+
+/* Has ID extension */
+
+#define LEVELID(stream) imap_cap (stream)->id
+
+
+/* Has CHILDREN extension */
+
+#define LEVELCHILDREN(stream) imap_cap (stream)->children
+
+
+/* Has MULTIAPPEND extension */
+
+#define LEVELMULTIAPPEND(stream) imap_cap (stream)->multiappend
+
+
+/* Has BINARY extension */
+
+#define LEVELBINARY(stream) imap_cap (stream)->binary
+
+
+/* Has UNSELECT extension */
+
+#define LEVELUNSELECT(stream) imap_cap (stream)->unselect
+
+
+/* Has SASL initial response extension */
+
+#define LEVELSASLIR(stream) imap_cap (stream)->sasl_ir
+
+
+/* Has SORT extension */
+
+#define LEVELSORT(stream) imap_cap (stream)->sort
+
+
+/* Has at least one THREAD extension */
+
+#define LEVELTHREAD(stream) ((imap_cap (stream)->threader) ? T : NIL)
+
+
+/* Has SCAN extension */
+
+#define LEVELSCAN(stream) imap_cap (stream)->scan
+
+
+/* Has URLAUTH extension */
+
+#define LEVELURLAUTH(stream) imap_cap (stream)->urlauth
+
+
+/* Has CATENATE extension */
+
+#define LEVELCATENATE(stream) imap_cap (stream)->catenate
+
+
+/* Has CONDSTORE extension */
+
+#define LEVELCONDSTORE(stream) imap_cap (stream)->condstore
+
+
+/* Has ESEARCH extension */
+
+#define LEVELESEARCH(stream) imap_cap (stream)->esearch
+
+
+/* Has WITHIN extension */
+
+#define LEVELWITHIN(stream) imap_cap (stream)->within
+
+/* Body structure extension levels */
+
+/* These are in BODYSTRUCTURE order.  Note that multipart bodies do not have
+ * body-fld-md5.  This is alright, since all subsequent body structure
+ * extensions are in both singlepart and multipart bodies.  If that ever
+ * changes, this will have to be split.
+ */
+
+#define BODYEXTMD5 1		/* body-fld-md5 */
+#define BODYEXTDSP 2		/* body-fld-dsp */
+#define BODYEXTLANG 3		/* body-fld-lang */
+#define BODYEXTLOC 4		/* body-fld-loc */
+
+
+/* Function prototypes */
+
+IMAPCAP *imap_cap (MAILSTREAM *stream);
+char *imap_host (MAILSTREAM *stream);
+long imap_cache (MAILSTREAM *stream,unsigned long msgno,char *seg,
+		 STRINGLIST *stl,SIZEDTEXT *text);
+
+
+/* Temporary */
+
+long imap_setacl (MAILSTREAM *stream,char *mailbox,char *id,char *rights);
+long imap_deleteacl (MAILSTREAM *stream,char *mailbox,char *id);
+long imap_getacl (MAILSTREAM *stream,char *mailbox);
+long imap_listrights (MAILSTREAM *stream,char *mailbox,char *id);
+long imap_myrights (MAILSTREAM *stream,char *mailbox);
+long imap_setquota (MAILSTREAM *stream,char *qroot,STRINGLIST *limits);
+long imap_getquota (MAILSTREAM *stream,char *qroot);
+long imap_getquotaroot (MAILSTREAM *stream,char *mailbox);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/mail.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,6331 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Mailbox Access routines
+ *
+ * Author:	Mark Crispin
+ *		UW Technology
+ *		University of Washington
+ *		Seattle, WA  98195
+ *		Internet: MRC@Washington.EDU
+ *
+ * Date:	22 November 1989
+ * Last Edited:	15 April 2008
+ */
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <time.h>
+#include "c-client.h"
+
+char *UW_copyright = "Copyright 1988-2007 University of Washington\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n";
+
+/* c-client global data */
+
+				/* version of this library */
+static char *mailcclientversion = CCLIENTVERSION;
+				/* list of mail drivers */
+static DRIVER *maildrivers = NIL;
+				/* list of authenticators */
+static AUTHENTICATOR *mailauthenticators = NIL;
+				/* SSL driver pointer */
+static NETDRIVER *mailssldriver = NIL;
+				/* pointer to alternate gets function */
+static mailgets_t mailgets = NIL;
+				/* pointer to read progress function */
+static readprogress_t mailreadprogress = NIL;
+				/* mail cache manipulation function */
+static mailcache_t mailcache = mm_cache;
+				/* RFC-822 output generator */
+static rfc822out_t mail822out = NIL;
+				/* RFC-822 output generator (new style) */
+static rfc822outfull_t mail822outfull = NIL;
+				/* SMTP verbose callback */
+static smtpverbose_t mailsmtpverbose = mm_dlog;
+				/* proxy copy routine */
+static mailproxycopy_t mailproxycopy = NIL;
+				/* RFC-822 external line parse */
+static parseline_t mailparseline = NIL;
+				/* RFC-822 external phrase parser */
+static parsephrase_t mailparsephrase = NIL;
+static kinit_t mailkinit = NIL;	/* application kinit callback */
+				/* note network sent command */
+static sendcommand_t mailsendcommand = NIL;
+				/* newsrc file name decision function */
+static newsrcquery_t mailnewsrcquery = NIL;
+				/* ACL results callback */
+static getacl_t mailaclresults = NIL;
+				/* list rights results callback */
+static listrights_t maillistrightsresults = NIL;
+				/* my rights results callback */
+static myrights_t mailmyrightsresults = NIL;
+				/* quota results callback */
+static quota_t mailquotaresults = NIL;
+				/* quota root results callback */
+static quotaroot_t mailquotarootresults = NIL;
+				/* sorted results callback */
+static sortresults_t mailsortresults = NIL;
+				/* threaded results callback */
+static threadresults_t mailthreadresults = NIL;
+				/* COPY UID results */
+static copyuid_t mailcopyuid = NIL;
+				/* APPEND UID results */
+static appenduid_t mailappenduid = NIL;
+				/* free elt extra stuff callback */
+static freeeltsparep_t mailfreeeltsparep = NIL;
+				/* free envelope extra stuff callback */
+static freeenvelopesparep_t mailfreeenvelopesparep = NIL;
+				/* free body extra stuff callback */
+static freebodysparep_t mailfreebodysparep = NIL;
+				/* free stream extra stuff callback */
+static freestreamsparep_t mailfreestreamsparep = NIL;
+				/* SSL start routine */
+static sslstart_t mailsslstart = NIL;
+				/* SSL certificate query */
+static sslcertificatequery_t mailsslcertificatequery = NIL;
+				/* SSL client certificate */
+static sslclientcert_t mailsslclientcert = NIL;
+				/* SSL client private key */
+static sslclientkey_t mailsslclientkey = NIL;
+				/* SSL failure notify */
+static sslfailure_t mailsslfailure = NIL;
+				/* snarf interval */
+static long mailsnarfinterval = 60;
+				/* snarf preservation */
+static long mailsnarfpreserve = NIL;
+				/* newsrc name uses canonical host */
+static long mailnewsrccanon = LONGT;
+
+				/* supported threaders */
+static THREADER mailthreadordsub = {
+  "ORDEREDSUBJECT",mail_thread_orderedsubject,NIL
+};
+static THREADER mailthreadlist = {
+  "REFERENCES",mail_thread_references,&mailthreadordsub
+};
+
+				/* server name */
+static char *servicename = "unknown";
+				/* server externally-set authentication ID */
+static char *externalauthid = NIL;
+static int expungeatping = T;	/* mail_ping() may call mm_expunged() */
+static int trysslfirst = NIL;	/* always try SSL first */
+static int notimezones = NIL;	/* write timezones in "From " header */
+static int trustdns = T;	/* do DNS canonicalization */
+static int saslusesptrname = T;	/* SASL uses name from DNS PTR lookup */
+				/* trustdns also must be set */
+static int debugsensitive = NIL;/* debug telemetry includes sensitive data */
+
+/* Default mail cache handler
+ * Accepts: pointer to cache handle
+ *	    message number
+ *	    caching function
+ * Returns: cache data
+ */
+
+void *mm_cache (MAILSTREAM *stream,unsigned long msgno,long op)
+{
+  size_t n;
+  void *ret = NIL;
+  unsigned long i;
+  switch ((int) op) {		/* what function? */
+  case CH_INIT:			/* initialize cache */
+    if (stream->cache) {	/* flush old cache contents */
+      while (stream->cachesize) {
+	mm_cache (stream,stream->cachesize,CH_FREE);
+	mm_cache (stream,stream->cachesize--,CH_FREESORTCACHE);
+      }
+      fs_give ((void **) &stream->cache);
+      fs_give ((void **) &stream->sc);
+      stream->nmsgs = 0;	/* can't have any messages now */
+    }
+    break;
+  case CH_SIZE:			/* (re-)size the cache */
+    if (!stream->cache)	{	/* have a cache already? */
+				/* no, create new cache */
+      n = (stream->cachesize = msgno + CACHEINCREMENT) * sizeof (void *);
+      stream->cache = (MESSAGECACHE **) memset (fs_get (n),0,n);
+      stream->sc = (SORTCACHE **) memset (fs_get (n),0,n);
+    }
+				/* is existing cache size large neough */
+    else if (msgno > stream->cachesize) {
+      i = stream->cachesize;	/* remember old size */
+      n = (stream->cachesize = msgno + CACHEINCREMENT) * sizeof (void *);
+      fs_resize ((void **) &stream->cache,n);
+      fs_resize ((void **) &stream->sc,n);
+      while (i < stream->cachesize) {
+	stream->cache[i] = NIL;
+	stream->sc[i++] = NIL;
+      }
+    }
+    break;
+
+  case CH_MAKEELT:		/* return elt, make if necessary */
+    if (!stream->cache[msgno - 1])
+      stream->cache[msgno - 1] = mail_new_cache_elt (msgno);
+				/* falls through */
+  case CH_ELT:			/* return elt */
+    ret = (void *) stream->cache[msgno - 1];
+    break;
+  case CH_SORTCACHE:		/* return sortcache entry, make if needed */
+    if (!stream->sc[msgno - 1]) stream->sc[msgno - 1] =
+      (SORTCACHE *) memset (fs_get (sizeof (SORTCACHE)),0,sizeof (SORTCACHE));
+    ret = (void *) stream->sc[msgno - 1];
+    break;
+  case CH_FREE:			/* free elt */
+    mail_free_elt (&stream->cache[msgno - 1]);
+    break;
+  case CH_FREESORTCACHE:
+    if (stream->sc[msgno - 1]) {
+      if (stream->sc[msgno - 1]->from)
+	fs_give ((void **) &stream->sc[msgno - 1]->from);
+      if (stream->sc[msgno - 1]->to)
+	fs_give ((void **) &stream->sc[msgno - 1]->to);
+      if (stream->sc[msgno - 1]->cc)
+	fs_give ((void **) &stream->sc[msgno - 1]->cc);
+      if (stream->sc[msgno - 1]->subject)
+	fs_give ((void **) &stream->sc[msgno - 1]->subject);
+      if (stream->sc[msgno - 1]->unique &&
+	  (stream->sc[msgno - 1]->unique != stream->sc[msgno - 1]->message_id))
+	fs_give ((void **) &stream->sc[msgno - 1]->unique);
+      if (stream->sc[msgno - 1]->message_id)
+	fs_give ((void **) &stream->sc[msgno - 1]->message_id);
+      if (stream->sc[msgno - 1]->references)
+	mail_free_stringlist (&stream->sc[msgno - 1]->references);
+      fs_give ((void **) &stream->sc[msgno - 1]);
+    }
+    break;
+  case CH_EXPUNGE:		/* expunge cache slot */
+    for (i = msgno - 1; msgno < stream->nmsgs; i++,msgno++) {
+      if (stream->cache[i] = stream->cache[msgno])
+	stream->cache[i]->msgno = msgno;
+      stream->sc[i] = stream->sc[msgno];
+    }
+    stream->cache[i] = NIL;	/* top of cache goes away */
+    stream->sc[i] = NIL;
+    break;
+  default:
+    fatal ("Bad mm_cache op");
+    break;
+  }
+  return ret;
+}
+
+/* Dummy string driver for complete in-memory strings */
+
+static void mail_string_init (STRING *s,void *data,unsigned long size);
+static char mail_string_next (STRING *s);
+static void mail_string_setpos (STRING *s,unsigned long i);
+
+STRINGDRIVER mail_string = {
+  mail_string_init,		/* initialize string structure */
+  mail_string_next,		/* get next byte in string structure */
+  mail_string_setpos		/* set position in string structure */
+};
+
+
+/* Initialize mail string structure for in-memory string
+ * Accepts: string structure
+ *	    pointer to string
+ *	    size of string
+ */
+
+static void mail_string_init (STRING *s,void *data,unsigned long size)
+{
+				/* set initial string pointers */
+  s->chunk = s->curpos = (char *) (s->data = data);
+				/* and sizes */
+  s->size = s->chunksize = s->cursize = size;
+  s->data1 = s->offset = 0;	/* never any offset */
+}
+
+
+/* Get next character from string
+ * Accepts: string structure
+ * Returns: character, string structure chunk refreshed
+ */
+
+static char mail_string_next (STRING *s)
+{
+  return *s->curpos++;		/* return the last byte */
+}
+
+
+/* Set string pointer position
+ * Accepts: string structure
+ *	    new position
+ */
+
+static void mail_string_setpos (STRING *s,unsigned long i)
+{
+  s->curpos = s->chunk + i;	/* set new position */
+  s->cursize = s->chunksize - i;/* and new size */
+}
+
+/* Mail routines
+ *
+ *  mail_xxx routines are the interface between this module and the outside
+ * world.  Only these routines should be referenced by external callers.
+ *
+ *  Note that there is an important difference between a "sequence" and a
+ * "message #" (msgno).  A sequence is a string representing a sequence in
+ * {"n", "n:m", or combination separated by commas} format, whereas a msgno
+ * is a single integer.
+ *
+ */
+
+/* Mail version check
+ * Accepts: version
+ */
+
+void mail_versioncheck (char *version)
+{
+				/* attempt to protect again wrong .h */
+  if (strcmp (version,mailcclientversion)) {
+    char tmp[MAILTMPLEN];
+    sprintf (tmp,"c-client library version skew, app=%.100s library=%.100s",
+	     version,mailcclientversion);
+    fatal (tmp);
+  }
+}
+
+
+/* Mail link driver
+ * Accepts: driver to add to list
+ */
+
+void mail_link (DRIVER *driver)
+{
+  DRIVER **d = &maildrivers;
+  while (*d) d = &(*d)->next;	/* find end of list of drivers */
+  *d = driver;			/* put driver at the end */
+  driver->next = NIL;		/* this driver is the end of the list */
+}
+
+/* Mail manipulate driver parameters
+ * Accepts: mail stream
+ *	    function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *mail_parameters (MAILSTREAM *stream,long function,void *value)
+{
+  void *r,*ret = NIL;
+  DRIVER *d;
+  AUTHENTICATOR *a;
+  switch ((int) function) {
+  case SET_INBOXPATH:
+    fatal ("SET_INBOXPATH not permitted");
+  case GET_INBOXPATH:
+    if ((stream || (stream = mail_open (NIL,"INBOX",OP_PROTOTYPE))) &&
+	stream->dtb) ret = (*stream->dtb->parameters) (function,value);
+    break;
+  case SET_THREADERS:
+    fatal ("SET_THREADERS not permitted");
+  case GET_THREADERS:		/* use stream dtb instead of global */
+    ret = (stream && stream->dtb) ?
+				/* KLUDGE ALERT: note stream passed as value */
+      (*stream->dtb->parameters) (function,stream) : (void *) &mailthreadlist;
+    break;
+  case SET_NAMESPACE:
+    fatal ("SET_NAMESPACE not permitted");
+    break;
+  case SET_NEWSRC:		/* too late on open stream */
+    if (stream && stream->dtb && (stream != ((*stream->dtb->open) (NIL))))
+      fatal ("SET_NEWSRC not permitted");
+    else ret = env_parameters (function,value);
+    break;
+  case GET_NAMESPACE:
+  case GET_NEWSRC:		/* use stream dtb instead of environment */
+    ret = (stream && stream->dtb) ?
+				/* KLUDGE ALERT: note stream passed as value */
+      (*stream->dtb->parameters) (function,stream) :
+	env_parameters (function,value);
+    break;
+  case ENABLE_DEBUG:
+    fatal ("ENABLE_DEBUG not permitted");
+  case DISABLE_DEBUG:
+    fatal ("DISABLE_DEBUG not permitted");
+  case SET_DIRFMTTEST:
+    fatal ("SET_DIRFMTTEST not permitted");
+  case GET_DIRFMTTEST:
+    if (!(stream && stream->dtb &&
+	  (ret = (*stream->dtb->parameters) (function,NIL))))
+      fatal ("GET_DIRFMTTEST not permitted");
+    break;
+
+  case SET_DRIVERS:
+    fatal ("SET_DRIVERS not permitted");
+  case GET_DRIVERS:		/* always return global */
+    ret = (void *) maildrivers;
+    break;
+  case SET_DRIVER:
+    fatal ("SET_DRIVER not permitted");
+  case GET_DRIVER:
+    for (d = maildrivers; d && compare_cstring (d->name,(char *) value);
+	 d = d->next);
+    ret = (void *) d;
+    break;
+  case ENABLE_DRIVER:
+    for (d = maildrivers; d && compare_cstring (d->name,(char *) value);
+	 d = d->next);
+    if (ret = (void *) d) d->flags &= ~DR_DISABLE;
+    break;
+  case DISABLE_DRIVER:
+    for (d = maildrivers; d && compare_cstring (d->name,(char *) value);
+	 d = d->next);
+    if (ret = (void *) d) d->flags |= DR_DISABLE;
+    break;
+  case ENABLE_AUTHENTICATOR:
+    for (a = mailauthenticators;/* scan authenticators */
+	 a && compare_cstring (a->name,(char *) value); a = a->next);
+    if (ret = (void *) a) a->flags &= ~AU_DISABLE;
+    break;
+  case DISABLE_AUTHENTICATOR:
+    for (a = mailauthenticators;/* scan authenticators */
+	 a && compare_cstring (a->name,(char *) value); a = a->next);
+    if (ret = (void *) a) a->flags |= AU_DISABLE;
+    break;
+  case UNHIDE_AUTHENTICATOR:
+    for (a = mailauthenticators;/* scan authenticators */
+	 a && compare_cstring (a->name,(char *) value); a = a->next);
+    if (ret = (void *) a) a->flags &= ~AU_HIDE;
+    break;
+  case HIDE_AUTHENTICATOR:
+    for (a = mailauthenticators;/* scan authenticators */
+	 a && compare_cstring (a->name,(char *) value); a = a->next);
+    if (ret = (void *) a) a->flags |= AU_HIDE;
+    break;
+  case SET_EXTERNALAUTHID:
+    if (value) {		/* setting external authentication ID */
+      externalauthid = cpystr ((char *) value);
+      mail_parameters (NIL,UNHIDE_AUTHENTICATOR,"EXTERNAL");
+    }
+    else {			/* clearing external authentication ID */
+      if (externalauthid) fs_give ((void **) &externalauthid);
+      mail_parameters (NIL,HIDE_AUTHENTICATOR,"EXTERNAL");
+    }
+  case GET_EXTERNALAUTHID:
+    ret = (void *) externalauthid;
+    break;
+
+  case SET_GETS:
+    mailgets = (mailgets_t) value;
+  case GET_GETS:
+    ret = (void *) mailgets;
+    break;
+  case SET_READPROGRESS:
+    mailreadprogress = (readprogress_t) value;
+  case GET_READPROGRESS:
+    ret = (void *) mailreadprogress;
+    break;
+  case SET_CACHE:
+    mailcache = (mailcache_t) value;
+  case GET_CACHE:
+    ret = (void *) mailcache;
+    break;
+  case SET_RFC822OUTPUT:
+    mail822out = (rfc822out_t) value;
+  case GET_RFC822OUTPUT:
+    ret = (void *) mail822out;
+    break;
+  case SET_RFC822OUTPUTFULL:
+    mail822outfull = (rfc822outfull_t) value;
+  case GET_RFC822OUTPUTFULL:
+    ret = (void *) mail822outfull;
+    break;
+  case SET_SMTPVERBOSE:
+    mailsmtpverbose = (smtpverbose_t) value;
+  case GET_SMTPVERBOSE:
+    ret = (void *) mailsmtpverbose;
+    break;
+  case SET_MAILPROXYCOPY:
+    mailproxycopy = (mailproxycopy_t) value;
+  case GET_MAILPROXYCOPY:
+    ret = (void *) mailproxycopy;
+    break;
+  case SET_PARSELINE:
+    mailparseline = (parseline_t) value;
+  case GET_PARSELINE:
+    ret = (void *) mailparseline;
+    break;
+  case SET_PARSEPHRASE:
+    mailparsephrase = (parsephrase_t) value;
+  case GET_PARSEPHRASE:
+    ret = (void *) mailparsephrase;
+    break;
+  case SET_NEWSRCQUERY:
+    mailnewsrcquery = (newsrcquery_t) value;
+  case GET_NEWSRCQUERY:
+    ret = (void *) mailnewsrcquery;
+    break;
+  case SET_NEWSRCCANONHOST:
+    mailnewsrccanon = (long) value;
+  case GET_NEWSRCCANONHOST:
+    ret = (void *) mailnewsrccanon;
+    break;
+
+  case SET_COPYUID:
+    mailcopyuid = (copyuid_t) value;
+  case GET_COPYUID:
+    ret = (void *) mailcopyuid;
+    break;
+  case SET_APPENDUID:
+    mailappenduid = (appenduid_t) value;
+  case GET_APPENDUID:
+    ret = (void *) mailappenduid;
+    break;
+  case SET_FREEENVELOPESPAREP:
+    mailfreeenvelopesparep = (freeenvelopesparep_t) value;
+  case GET_FREEENVELOPESPAREP:
+    ret = (void *) mailfreeenvelopesparep;
+    break;
+  case SET_FREEELTSPAREP:
+    mailfreeeltsparep = (freeeltsparep_t) value;
+  case GET_FREEELTSPAREP:
+    ret = (void *) mailfreeeltsparep;
+    break;
+  case SET_FREESTREAMSPAREP:
+    mailfreestreamsparep = (freestreamsparep_t) value;
+  case GET_FREESTREAMSPAREP:
+    ret = (void *) mailfreestreamsparep;
+    break;
+  case SET_FREEBODYSPAREP:
+    mailfreebodysparep = (freebodysparep_t) value;
+  case GET_FREEBODYSPAREP:
+    ret = (void *) mailfreebodysparep;
+    break;
+
+  case SET_SSLSTART:
+    mailsslstart = (sslstart_t) value;
+  case GET_SSLSTART:
+    ret = (void *) mailsslstart;
+    break;
+  case SET_SSLCERTIFICATEQUERY:
+    mailsslcertificatequery = (sslcertificatequery_t) value;
+  case GET_SSLCERTIFICATEQUERY:
+    ret = (void *) mailsslcertificatequery;
+    break;
+  case SET_SSLCLIENTCERT:
+    mailsslclientcert = (sslclientcert_t) value;
+  case GET_SSLCLIENTCERT:
+    ret = (void *) mailsslclientcert;
+    break;
+  case SET_SSLCLIENTKEY:
+    mailsslclientkey = (sslclientkey_t) value;
+  case GET_SSLCLIENTKEY:
+    ret = (void *) mailsslclientkey;
+    break;
+  case SET_SSLFAILURE:
+    mailsslfailure = (sslfailure_t) value;
+  case GET_SSLFAILURE:
+    ret = (void *) mailsslfailure;
+    break;
+  case SET_KINIT:
+    mailkinit = (kinit_t) value;
+  case GET_KINIT:
+    ret = (void *) mailkinit;
+    break;
+  case SET_SENDCOMMAND:
+    mailsendcommand = (sendcommand_t) value;
+  case GET_SENDCOMMAND:
+    ret = (void *) mailsendcommand;
+    break;
+
+  case SET_SERVICENAME:
+    servicename = (char *) value;
+  case GET_SERVICENAME:
+    ret = (void *) servicename;
+    break;
+  case SET_EXPUNGEATPING:
+    expungeatping = (value ? T : NIL);
+  case GET_EXPUNGEATPING:
+    ret = (void *) (expungeatping ? VOIDT : NIL);
+    break;
+  case SET_SORTRESULTS:
+    mailsortresults = (sortresults_t) value;
+  case GET_SORTRESULTS:
+    ret = (void *) mailsortresults;
+    break;
+  case SET_THREADRESULTS:
+    mailthreadresults = (threadresults_t) value;
+  case GET_THREADRESULTS:
+    ret = (void *) mailthreadresults;
+    break;
+  case SET_SSLDRIVER:
+    mailssldriver = (NETDRIVER *) value;
+  case GET_SSLDRIVER:
+    ret = (void *) mailssldriver;
+    break;
+  case SET_TRYSSLFIRST:
+    trysslfirst = (value ? T : NIL);
+  case GET_TRYSSLFIRST:
+    ret = (void *) (trysslfirst ? VOIDT : NIL);
+    break;
+  case SET_NOTIMEZONES:
+    notimezones = (value ? T : NIL);
+  case GET_NOTIMEZONES:
+    ret = (void *) (notimezones ? VOIDT : NIL);
+    break;
+  case SET_TRUSTDNS:
+    trustdns = (value ? T : NIL);
+  case GET_TRUSTDNS:
+    ret = (void *) (trustdns ? VOIDT : NIL);
+    break;
+  case SET_SASLUSESPTRNAME:
+    saslusesptrname = (value ? T : NIL);
+  case GET_SASLUSESPTRNAME:
+    ret = (void *) (saslusesptrname ? VOIDT : NIL);
+    break;
+  case SET_DEBUGSENSITIVE:
+    debugsensitive = (value ? T : NIL);
+  case GET_DEBUGSENSITIVE:
+    ret = (void *) (debugsensitive ? VOIDT : NIL);
+    break;
+
+  case SET_ACL:
+    mailaclresults = (getacl_t) value;
+  case GET_ACL:
+    ret = (void *) mailaclresults;
+    break;
+  case SET_LISTRIGHTS:
+    maillistrightsresults = (listrights_t) value;
+  case GET_LISTRIGHTS:
+    ret = (void *) maillistrightsresults;
+    break;
+  case SET_MYRIGHTS:
+    mailmyrightsresults = (myrights_t) value;
+  case GET_MYRIGHTS:
+    ret = (void *) mailmyrightsresults;
+    break;
+  case SET_QUOTA:
+    mailquotaresults = (quota_t) value;
+  case GET_QUOTA:
+    ret = (void *) mailquotaresults;
+    break;
+  case SET_QUOTAROOT:
+    mailquotarootresults = (quotaroot_t) value;
+  case GET_QUOTAROOT:
+    ret = (void *) mailquotarootresults;
+    break;
+  case SET_SNARFINTERVAL:
+    mailsnarfinterval = (long) value;
+  case GET_SNARFINTERVAL:
+    ret = (void *) mailsnarfinterval;
+    break;
+  case SET_SNARFPRESERVE:
+    mailsnarfpreserve = (long) value;
+  case GET_SNARFPRESERVE:
+    ret = (void *) mailsnarfpreserve;
+    break;
+  case SET_SNARFMAILBOXNAME:
+    if (stream) {		/* have a stream? */
+      if (stream->snarf.name) fs_give ((void **) &stream->snarf.name);
+      stream->snarf.name = cpystr ((char *) value);
+    }
+    else fatal ("SET_SNARFMAILBOXNAME with no stream");
+  case GET_SNARFMAILBOXNAME:
+    if (stream) ret = (void *) stream->snarf.name;
+    break;
+  default:
+    if (r = smtp_parameters (function,value)) ret = r;
+    if (r = env_parameters (function,value)) ret = r;
+    if (r = tcp_parameters (function,value)) ret = r;
+    if (stream && stream->dtb) {/* if have stream, do for its driver only */
+      if (r = (*stream->dtb->parameters) (function,value)) ret = r;
+    }
+				/* else do all drivers */
+    else for (d = maildrivers; d; d = d->next)
+      if (r = (d->parameters) (function,value)) ret = r;
+    break;
+  }
+  return ret;
+}
+
+/* Mail validate mailbox name
+ * Accepts: MAIL stream
+ *	    mailbox name
+ *	    purpose string for error message
+ * Return: driver factory on success, NIL on failure
+ */
+
+DRIVER *mail_valid (MAILSTREAM *stream,char *mailbox,char *purpose)
+{
+  char tmp[MAILTMPLEN];
+  DRIVER *factory = NIL;
+				/* never allow names with newlines */
+  if (strpbrk (mailbox,"\015\012")) {
+    if (purpose) {		/* if want an error message */
+      sprintf (tmp,"Can't %s with such a name",purpose);
+      MM_LOG (tmp,ERROR);
+    }
+    return NIL;
+  }
+				/* validate name, find driver factory */
+  if (strlen (mailbox) < (NETMAXHOST+(NETMAXUSER*2)+NETMAXMBX+NETMAXSRV+50))
+    for (factory = maildrivers; factory && 
+	 ((factory->flags & DR_DISABLE) ||
+	  ((factory->flags & DR_LOCAL) && (*mailbox == '{')) ||
+	  !(*factory->valid) (mailbox));
+	 factory = factory->next);
+				/* validate factory against non-dummy stream */
+  if (factory && stream && stream->dtb && (stream->dtb != factory) &&
+      strcmp (stream->dtb->name,"dummy"))
+				/* factory invalid; if dummy, use stream */
+    factory = strcmp (factory->name,"dummy") ? NIL : stream->dtb;
+  if (!factory && purpose) {	/* if want an error message */
+    sprintf (tmp,"Can't %s %.80s: %s",purpose,mailbox,(*mailbox == '{') ?
+	     "invalid remote specification" : "no such mailbox");
+    MM_LOG (tmp,ERROR);
+  }
+  return factory;		/* return driver factory */
+}
+
+/* Mail validate network mailbox name
+ * Accepts: mailbox name
+ *	    mailbox driver to validate against
+ *	    pointer to where to return host name if non-NIL
+ *	    pointer to where to return mailbox name if non-NIL
+ * Returns: driver on success, NIL on failure
+ */
+
+DRIVER *mail_valid_net (char *name,DRIVER *drv,char *host,char *mailbox)
+{
+  NETMBX mb;
+  if (!mail_valid_net_parse (name,&mb) || strcmp (mb.service,drv->name))
+    return NIL;
+  if (host) strcpy (host,mb.host);
+  if (mailbox) strcpy (mailbox,mb.mailbox);
+  return drv;
+}
+
+
+/* Mail validate network mailbox name
+ * Accepts: mailbox name
+ *	    NETMBX structure to return values
+ * Returns: T on success, NIL on failure
+ */
+
+long mail_valid_net_parse (char *name,NETMBX *mb)
+{
+  return mail_valid_net_parse_work (name,mb,"imap");
+}
+
+/* Mail validate network mailbox name worker routine
+ * Accepts: mailbox name
+ *	    NETMBX structure to return values
+ *	    default service
+ * Returns: T on success, NIL on failure
+ */
+
+long mail_valid_net_parse_work (char *name,NETMBX *mb,char *service)
+{
+  int i,j;
+  char c,*s,*t,*v,tmp[MAILTMPLEN],arg[MAILTMPLEN];
+				/* initialize structure */
+  memset (mb,'\0',sizeof (NETMBX));
+				/* must have host specification */
+  if (*name++ != '{') return NIL;
+  if (*name == '[') {		/* if domain literal, find its ending */
+    if (!((v = strpbrk (name,"]}")) && (*v++ == ']'))) return NIL;
+  }
+				/* find end of host name */
+  else if (!(v = strpbrk (name,"/:}"))) return NIL;
+				/* validate length, find mailbox part */
+  if (!((i = v - name) && (i < NETMAXHOST) && (t = strchr (v,'}')) &&
+	((j = t - v) < MAILTMPLEN) && (strlen (t+1) < (size_t) NETMAXMBX)))
+    return NIL;			/* invalid mailbox */
+  strncpy (mb->host,name,i);	/* set host name */
+  strncpy (mb->orighost,name,i);
+  mb->host[i] = mb->orighost[i] = '\0';
+  strcpy (mb->mailbox,t+1);	/* set mailbox name */
+  if (t - v) {			/* any switches or port specification? */
+    strncpy (t = tmp,v,j);	/* copy it */
+    tmp[j] = '\0';		/* tie it off */
+    c = *t++;			/* get first delimiter */
+    do switch (c) {		/* act based upon the character */
+    case ':':			/* port specification */
+      if (mb->port || !(mb->port = strtoul (t,&t,10))) return NIL;
+      c = t ? *t++ : '\0';	/* get delimiter, advance pointer */
+      break;
+    case '/':			/* switch */
+				/* find delimiter */
+      if (t = strpbrk (s = t,"/:=")) {
+	c = *t;			/* remember delimiter for later */
+	*t++ = '\0';		/* tie off switch name */
+      }
+      else c = '\0';		/* no delimiter */
+      if (c == '=') {		/* parse switches which take arguments */
+	if (*t == '"') {	/* quoted string? */
+	  for (v = arg,i = 0,++t; (c = *t++) != '"';) {
+	    if (!c) return NIL;	/* unterminated string */
+				/* quote next character */
+	    if (c == '\\') c = *t++;
+	    if (!c) return NIL;	/* can't quote NUL either */
+	    arg[i++] = c;
+	  }
+	  c = *t++;		/* remember delimiter for later */
+	  arg[i] = '\0';	/* tie off argument */
+	}
+	else {			/* non-quoted argument */
+	  if (t = strpbrk (v = t,"/:")) {
+	    c = *t;		/* remember delimiter for later */
+	    *t++ = '\0';	/* tie off switch name */
+	  }
+	  else c = '\0';	/* no delimiter */
+	  i = strlen (v);	/* length of argument */
+	}
+	if (!compare_cstring (s,"service") && (i < NETMAXSRV) && !*mb->service)
+	  lcase (strcpy (mb->service,v));
+	else if (!compare_cstring (s,"user") && (i < NETMAXUSER) && !*mb->user)
+	  strcpy (mb->user,v);
+	else if (!compare_cstring (s,"authuser") && (i < NETMAXUSER) &&
+		 !*mb->authuser) strcpy (mb->authuser,v);
+	else return NIL;
+      }
+
+      else {			/* non-argument switch */
+	if (!compare_cstring (s,"anonymous")) mb->anoflag = T;
+	else if (!compare_cstring (s,"debug")) mb->dbgflag = T;
+	else if (!compare_cstring (s,"readonly")) mb->readonlyflag = T;
+	else if (!compare_cstring (s,"secure")) mb->secflag = T;
+	else if (!compare_cstring (s,"norsh")) mb->norsh = T;
+	else if (!compare_cstring (s,"loser")) mb->loser = T;
+	else if (!compare_cstring (s,"tls") && !mb->notlsflag)
+	  mb->tlsflag = T;
+	else if (!compare_cstring (s,"tls-sslv23") && !mb->notlsflag)
+	  mb->tlssslv23 = mb->tlsflag = T;
+	else if (!compare_cstring (s,"notls") && !mb->tlsflag)
+	  mb->notlsflag = T;
+	else if (!compare_cstring (s,"tryssl"))
+	  mb->trysslflag = mailssldriver? T : NIL;
+	else if (mailssldriver && !compare_cstring (s,"ssl") && !mb->tlsflag)
+	  mb->sslflag = mb->notlsflag = T;
+	else if (mailssldriver && !compare_cstring (s,"novalidate-cert"))
+	  mb->novalidate = T;
+				/* hack for compatibility with the past */
+	else if (mailssldriver && !compare_cstring (s,"validate-cert"));
+				/* service switches below here */
+	else if (*mb->service) return NIL;
+	else if (!compare_cstring (s,"imap") ||
+		 !compare_cstring (s,"nntp") ||
+		 !compare_cstring (s,"pop3") ||
+		 !compare_cstring (s,"smtp") ||
+		 !compare_cstring (s,"submit"))
+	  lcase (strcpy (mb->service,s));
+	else if (!compare_cstring (s,"imap2") ||
+		 !compare_cstring (s,"imap2bis") ||
+		 !compare_cstring (s,"imap4") ||
+		 !compare_cstring (s,"imap4rev1"))
+	  strcpy (mb->service,"imap");
+	else if (!compare_cstring (s,"pop"))
+	  strcpy (mb->service,"pop3");
+	else return NIL;	/* invalid non-argument switch */
+      }
+      break;
+    default:			/* anything else is bogus */
+      return NIL;
+    } while (c);		/* see if anything more to parse */
+  }
+				/* default mailbox name */
+  if (!*mb->mailbox) strcpy (mb->mailbox,"INBOX");
+				/* default service name */
+  if (!*mb->service) strcpy (mb->service,service);
+				/* /norsh only valid if imap */
+  if (mb->norsh && strcmp (mb->service,"imap")) return NIL;
+  return T;
+}
+
+/* Mail scan mailboxes for string
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    contents to search
+ */
+
+void mail_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  int remote = ((*pat == '{') || (ref && *ref == '{'));
+  DRIVER *d;
+  if (ref && (strlen (ref) > NETMAXMBX)) {
+    char tmp[MAILTMPLEN];
+    sprintf (tmp,"Invalid LIST reference specification: %.80s",ref);
+    MM_LOG (tmp,ERROR);
+    return;
+  }
+  if (strlen (pat) > NETMAXMBX) {
+    char tmp[MAILTMPLEN];
+    sprintf (tmp,"Invalid LIST pattern specification: %.80s",pat);
+    MM_LOG (tmp,ERROR);
+    return;
+  }
+  if (*pat == '{') ref = NIL;	/* ignore reference if pattern is remote */
+  if (stream) {			/* if have a stream, do it for that stream */
+    if ((d = stream->dtb) && d->scan &&
+	!(((d->flags & DR_LOCAL) && remote)))
+      (*d->scan) (stream,ref,pat,contents);
+  }
+				/* otherwise do for all DTB's */
+  else for (d = maildrivers; d; d = d->next)
+    if (d->scan && !((d->flags & DR_DISABLE) ||
+		     ((d->flags & DR_LOCAL) && remote)))
+      (d->scan) (NIL,ref,pat,contents);
+}
+
+/* Mail list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mail_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  int remote = ((*pat == '{') || (ref && *ref == '{'));
+  DRIVER *d = maildrivers;
+  if (ref && (strlen (ref) > NETMAXMBX)) {
+    char tmp[MAILTMPLEN];
+    sprintf (tmp,"Invalid LIST reference specification: %.80s",ref);
+    MM_LOG (tmp,ERROR);
+    return;
+  }
+  if (strlen (pat) > NETMAXMBX) {
+    char tmp[MAILTMPLEN];
+    sprintf (tmp,"Invalid LIST pattern specification: %.80s",pat);
+    MM_LOG (tmp,ERROR);
+    return;
+  }
+  if (*pat == '{') ref = NIL;	/* ignore reference if pattern is remote */
+  if (stream && stream->dtb) {	/* if have a stream, do it for that stream */
+    if (!(((d = stream->dtb)->flags & DR_LOCAL) && remote))
+      (*d->list) (stream,ref,pat);
+  }
+				/* otherwise do for all DTB's */
+  else do if (!((d->flags & DR_DISABLE) ||
+		((d->flags & DR_LOCAL) && remote)))
+    (d->list) (NIL,ref,pat);
+  while (d = d->next);		/* until at the end */
+}
+
+/* Mail list subscribed mailboxes
+ * Accepts: mail stream
+ *	    pattern to search
+ */
+
+void mail_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  int remote = ((*pat == '{') || (ref && *ref == '{'));
+  DRIVER *d = maildrivers;
+  if (ref && (strlen (ref) > NETMAXMBX)) {
+    char tmp[MAILTMPLEN];
+    sprintf (tmp,"Invalid LSUB reference specification: %.80s",ref);
+    MM_LOG (tmp,ERROR);
+    return;
+  }
+  if (strlen (pat) > NETMAXMBX) {
+    char tmp[MAILTMPLEN];
+    sprintf (tmp,"Invalid LSUB pattern specification: %.80s",pat);
+    MM_LOG (tmp,ERROR);
+    return;
+  }
+  if (*pat == '{') ref = NIL;	/* ignore reference if pattern is remote */
+  if (stream && stream->dtb) {	/* if have a stream, do it for that stream */
+    if (!(((d = stream->dtb)->flags & DR_LOCAL) && remote))
+      (*d->lsub) (stream,ref,pat);
+  }
+				/* otherwise do for all DTB's */
+  else do if (!((d->flags & DR_DISABLE) ||
+		((d->flags & DR_LOCAL) && remote)))
+    (d->lsub) (NIL,ref,pat);
+  while (d = d->next);		/* until at the end */
+}
+
+/* Mail subscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to add to subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long mail_subscribe (MAILSTREAM *stream,char *mailbox)
+{
+  DRIVER *factory = mail_valid (stream,mailbox,"subscribe to mailbox");
+  return factory ?
+    (factory->subscribe ?
+     (*factory->subscribe) (stream,mailbox) : sm_subscribe (mailbox)) : NIL;
+}
+
+
+/* Mail unsubscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to delete from subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long mail_unsubscribe (MAILSTREAM *stream,char *mailbox)
+{
+  DRIVER *factory = mail_valid (stream,mailbox,NIL);
+  return (factory && factory->unsubscribe) ?
+    (*factory->unsubscribe) (stream,mailbox) : sm_unsubscribe (mailbox);
+}
+
+/* Mail create mailbox
+ * Accepts: mail stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long mail_create (MAILSTREAM *stream,char *mailbox)
+{
+  MAILSTREAM *ts;
+  char *s,*t,tmp[MAILTMPLEN];
+  size_t i;
+  DRIVER *d;
+				/* never allow names with newlines */
+  if (s = strpbrk (mailbox,"\015\012")) {
+    MM_LOG ("Can't create mailbox with such a name",ERROR);
+    return NIL;
+  }
+  if (strlen (mailbox) >= (NETMAXHOST+(NETMAXUSER*2)+NETMAXMBX+NETMAXSRV+50)) {
+    sprintf (tmp,"Can't create %.80s: %s",mailbox,(*mailbox == '{') ?
+	     "invalid remote specification" : "no such mailbox");
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+				/* create of INBOX invalid */
+  if (!compare_cstring (mailbox,"INBOX")) {
+    MM_LOG ("Can't create INBOX",ERROR);
+    return NIL;
+  }
+				/* validate name */
+  if (s = mail_utf7_valid (mailbox)) {
+    sprintf (tmp,"Can't create %s: %.80s",s,mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+
+				/* see if special driver hack */
+  if ((mailbox[0] == '#') && ((mailbox[1] == 'd') || (mailbox[1] == 'D')) &&
+      ((mailbox[2] == 'r') || (mailbox[2] == 'R')) &&
+      ((mailbox[3] == 'i') || (mailbox[3] == 'I')) &&
+      ((mailbox[4] == 'v') || (mailbox[4] == 'V')) &&
+      ((mailbox[5] == 'e') || (mailbox[5] == 'E')) &&
+      ((mailbox[6] == 'r') || (mailbox[6] == 'R')) && (mailbox[7] == '.')) {
+				/* copy driver until likely delimiter */
+    if ((s = strpbrk (t = mailbox+8,"/\\:")) && (i = s - t)) {
+      strncpy (tmp,t,i);
+      tmp[i] = '\0';
+    } 
+    else {
+      sprintf (tmp,"Can't create mailbox %.80s: bad driver syntax",mailbox);
+      MM_LOG (tmp,ERROR);
+      return NIL;
+    }
+    for (d = maildrivers; d && strcmp (d->name,tmp); d = d->next);
+    if (d) mailbox = ++s;	/* skip past driver specification */
+    else {
+      sprintf (tmp,"Can't create mailbox %.80s: unknown driver",mailbox);
+      MM_LOG (tmp,ERROR);
+      return NIL;
+    }
+  }
+				/* use stream if one given or deterministic */
+  else if ((stream && stream->dtb) ||
+	   (((*mailbox == '{') || (*mailbox == '#')) &&
+	    (stream = mail_open (NIL,mailbox,OP_PROTOTYPE | OP_SILENT))))
+    d = stream->dtb;
+  else if ((*mailbox != '{') && (ts = default_proto (NIL))) d = ts->dtb;
+  else {			/* failed utterly */
+    sprintf (tmp,"Can't create mailbox %.80s: indeterminate format",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+  return (*d->create) (stream,mailbox);
+}
+
+/* Mail delete mailbox
+ * Accepts: mail stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long mail_delete (MAILSTREAM *stream,char *mailbox)
+{
+  DRIVER *dtb = mail_valid (stream,mailbox,"delete mailbox");
+  if (!dtb) return NIL;
+  if (((mailbox[0] == 'I') || (mailbox[0] == 'i')) &&
+      ((mailbox[1] == 'N') || (mailbox[1] == 'n')) &&
+      ((mailbox[2] == 'B') || (mailbox[2] == 'b')) &&
+      ((mailbox[3] == 'O') || (mailbox[3] == 'o')) &&
+      ((mailbox[4] == 'X') || (mailbox[4] == 'x')) && !mailbox[5]) {
+    MM_LOG ("Can't delete INBOX",ERROR);
+    return NIL;
+  }
+  return SAFE_DELETE (dtb,stream,mailbox);
+}
+
+
+/* Mail rename mailbox
+ * Accepts: mail stream
+ *	    old mailbox name
+ *	    new mailbox name
+ * Returns: T on success, NIL on failure
+ */
+
+long mail_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  char *s,tmp[MAILTMPLEN];
+  DRIVER *dtb = mail_valid (stream,old,"rename mailbox");
+  if (!dtb) return NIL;
+				/* validate name */
+  if (s = mail_utf7_valid (newname)) {
+    sprintf (tmp,"Can't rename to %s: %.80s",s,newname);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+  if ((*old != '{') && (*old != '#') && mail_valid (NIL,newname,NIL)) {
+    sprintf (tmp,"Can't rename %.80s: mailbox %.80s already exists",
+	     old,newname);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+  return SAFE_RENAME (dtb,stream,old,newname);
+}
+
+/* Validate mailbox as Modified UTF-7
+ * Accepts: candidate mailbox name
+ * Returns: error string if error, NIL if valid
+ */
+
+char *mail_utf7_valid (char *mailbox)
+{
+  char *s;
+  for (s = mailbox; *s; s++) {	/* make sure valid name */
+				/* reserved for future use with UTF-8 */
+    if (*s & 0x80) return "mailbox name with 8-bit octet";
+				/* validate modified UTF-7 */
+    else if (*s == '&') while (*++s != '-') switch (*s) {
+    case '\0':
+      return "unterminated modified UTF-7 name";
+    case '+':			/* valid modified BASE64 */
+    case ',':
+      break;			/* all OK so far */
+    default:			/* must be alphanumeric */
+      if (!isalnum (*s)) return "invalid modified UTF-7 name";
+      break;
+    }
+  }
+  return NIL;			/* all OK */
+}
+
+/* Mail status of mailbox
+ * Accepts: mail stream if open on this mailbox
+ *	    mailbox name
+ *	    status flags
+ * Returns: T on success, NIL on failure
+ */
+
+long mail_status (MAILSTREAM *stream,char *mbx,long flags)
+{
+  DRIVER *dtb = mail_valid (stream,mbx,"get status of mailbox");
+  if (!dtb) return NIL;		/* only if valid */
+  if (stream && ((dtb != stream->dtb) ||
+		 ((dtb->flags & DR_LOCAL) && strcmp (mbx,stream->mailbox) &&
+		  strcmp (mbx,stream->original_mailbox))))
+    stream = NIL;		/* stream not suitable */
+  return SAFE_STATUS (dtb,stream,mbx,flags);
+}
+
+
+/* Mail status of mailbox default handler
+ * Accepts: mail stream
+ *	    mailbox name
+ *	    status flags
+ * Returns: T on success, NIL on failure
+ */
+
+long mail_status_default (MAILSTREAM *stream,char *mbx,long flags)
+{
+  MAILSTATUS status;
+  unsigned long i;
+  MAILSTREAM *tstream = NIL;
+				/* make temporary stream (unless this mbx) */
+  if (!stream && !(stream = tstream =
+		   mail_open (NIL,mbx,OP_READONLY|OP_SILENT))) return NIL;
+  status.flags = flags;		/* return status values */
+  status.messages = stream->nmsgs;
+  status.recent = stream->recent;
+  if (flags & SA_UNSEEN)	/* must search to get unseen messages */
+    for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++)
+      if (!mail_elt (stream,i)->seen) status.unseen++;
+  status.uidnext = stream->uid_last + 1;
+  status.uidvalidity = stream->uid_validity;
+  MM_STATUS(stream,mbx,&status);/* pass status to main program */
+  if (tstream) mail_close (tstream);
+  return T;			/* success */
+}
+
+/* Mail open
+ * Accepts: candidate stream for recycling
+ *	    mailbox name
+ *	    open options
+ * Returns: stream to use on success, NIL on failure
+ */
+
+MAILSTREAM *mail_open (MAILSTREAM *stream,char *name,long options)
+{
+  int i;
+  char c,*s,tmp[MAILTMPLEN];
+  NETMBX mb;
+  DRIVER *d;
+  switch (name[0]) {		/* see if special handling */
+  case '#':			/* possible special hacks */
+    if (((name[1] == 'M') || (name[1] == 'm')) &&
+	((name[2] == 'O') || (name[2] == 'o')) &&
+	((name[3] == 'V') || (name[3] == 'v')) &&
+	((name[4] == 'E') || (name[4] == 'e')) && (c = name[5]) &&
+	(s = strchr (name+6,c)) && (i = s - (name + 6)) && (i < MAILTMPLEN)) {
+      if (stream = mail_open (stream,s+1,options)) {
+	strncpy (tmp,name+6,i);	/* copy snarf mailbox name */
+	tmp[i] = '\0';		/* tie off name */
+	mail_parameters (stream,SET_SNARFMAILBOXNAME,(void *) tmp);
+	stream->snarf.options = options;
+	mail_ping (stream);	/* do initial snarf */
+				/* punt if can't do initial snarf */
+	if (!stream->snarf.time) stream = mail_close (stream);
+      }
+      return stream;
+    }
+				/* special POP hack */
+    else if (((name[1] == 'P') || (name[1] == 'p')) &&
+	     ((name[2] == 'O') || (name[2] == 'o')) &&
+	     ((name[3] == 'P') || (name[3] == 'p')) &&
+	     mail_valid_net_parse_work (name+4,&mb,"pop3") &&
+	!strcmp (mb.service,"pop3") && !mb.anoflag && !mb.readonlyflag) {
+      if (stream = mail_open (stream,mb.mailbox,options)) {
+	sprintf (tmp,"{%.255s",mb.host);
+	if (mb.port) sprintf (tmp + strlen (tmp),":%lu",mb.port);
+	if (mb.user[0]) sprintf (tmp + strlen (tmp),"/user=%.64s",mb.user);
+	if (mb.dbgflag) strcat (tmp,"/debug");
+	if (mb.secflag) strcat (tmp,"/secure");
+	if (mb.tlsflag) strcat (tmp,"/tls");
+	if (mb.notlsflag) strcat (tmp,"/notls");
+	if (mb.sslflag) strcat (tmp,"/ssl");
+	if (mb.trysslflag) strcat (tmp,"/tryssl");
+	if (mb.novalidate) strcat (tmp,"/novalidate-cert");
+	strcat (tmp,"/pop3/loser}");
+	mail_parameters (stream,SET_SNARFMAILBOXNAME,(void *) tmp);
+	mail_ping (stream);	/* do initial snarf */
+      }
+      return stream;		/* return local mailbox stream */
+    }
+
+    else if ((options & OP_PROTOTYPE) &&
+	     ((name[1] == 'D') || (name[1] == 'd')) &&
+	     ((name[2] == 'R') || (name[2] == 'r')) &&
+	     ((name[3] == 'I') || (name[3] == 'i')) &&
+	     ((name[4] == 'V') || (name[4] == 'v')) &&
+	     ((name[5] == 'E') || (name[5] == 'e')) &&
+	     ((name[6] == 'R') || (name[6] == 'r')) && (name[7] == '.')) {
+      sprintf (tmp,"%.80s",name+8);
+				/* tie off name at likely delimiter */
+      if (s = strpbrk (tmp,"/\\:")) *s++ = '\0';
+      else {
+	sprintf (tmp,"Can't resolve mailbox %.80s: bad driver syntax",name);
+	MM_LOG (tmp,ERROR);
+	return mail_close (stream);
+      }
+      for (d = maildrivers; d && compare_cstring (d->name,tmp); d = d->next);
+      if (d) return (*d->open) (NIL);
+      sprintf (tmp,"Can't resolve mailbox %.80s: unknown driver",name);
+      MM_LOG (tmp,ERROR);
+      return mail_close (stream);
+    }
+				/* fall through to default case */
+  default:			/* not special hack (but could be # name */
+    d = mail_valid (NIL,name,(options & OP_SILENT) ?
+		    (char *) NIL : "open mailbox");
+  }
+  return d ? mail_open_work (d,stream,name,options) : stream;
+}
+
+/* Mail open worker routine
+ * Accepts: factory
+ *	    candidate stream for recycling
+ *	    mailbox name
+ *	    open options
+ * Returns: stream to use on success, NIL on failure
+ */
+
+MAILSTREAM *mail_open_work (DRIVER *d,MAILSTREAM *stream,char *name,
+			    long options)
+{
+  int i;
+  char tmp[MAILTMPLEN];
+  NETMBX mb;
+  if (options & OP_PROTOTYPE) return (*d->open) (NIL);
+  /* name is copied here in case the caller does a re-open using
+   * stream->mailbox or stream->original_mailbox as the argument.
+   */
+  name = cpystr (name);		/* make copy of name */
+  if (stream) {			/* recycling requested? */
+    if ((stream->dtb == d) && (d->flags & DR_RECYCLE) &&
+	((d->flags & DR_HALFOPEN) || !(options & OP_HALFOPEN)) &&
+	mail_usable_network_stream (stream,name)) {
+				/* yes, checkpoint if needed */
+      if (d->flags & DR_XPOINT) mail_check (stream);
+      mail_free_cache (stream);	/* clean up stream */
+      if (stream->mailbox) fs_give ((void **) &stream->mailbox);
+      if (stream->original_mailbox)
+	fs_give ((void **) &stream->original_mailbox);
+				/* flush user flags */
+      for (i = 0; i < NUSERFLAGS; i++)
+	if (stream->user_flags[i]) fs_give ((void **) &stream->user_flags[i]);
+    }
+    else {			/* stream not recycleable, babble if net */
+      if (!stream->silent && stream->dtb && !(stream->dtb->flags&DR_LOCAL) &&
+	  mail_valid_net_parse (stream->mailbox,&mb)) {
+	sprintf (tmp,"Closing connection to %.80s",mb.host);
+	MM_LOG (tmp,(long) NIL);
+      }
+				/* flush the old stream */
+      stream = mail_close (stream);
+    }
+  }
+				/* check if driver does not support halfopen */
+  else if ((options & OP_HALFOPEN) && !(d->flags & DR_HALFOPEN)) {
+    fs_give ((void **) &name);
+    return NIL;
+  }
+
+				/* instantiate new stream if not recycling */
+  if (!stream) (*mailcache) (stream = (MAILSTREAM *)
+			     memset (fs_get (sizeof (MAILSTREAM)),0,
+				     sizeof (MAILSTREAM)),(long) 0,CH_INIT);
+  stream->dtb = d;		/* set dispatch */
+				/* set mailbox name */
+  stream->mailbox = cpystr (stream->original_mailbox = name);
+				/* initialize stream flags */
+  stream->inbox = stream->lock = NIL;
+  stream->debug = (options & OP_DEBUG) ? T : NIL;
+  stream->rdonly = (options & OP_READONLY) ? T : NIL;
+  stream->anonymous = (options & OP_ANONYMOUS) ? T : NIL;
+  stream->scache = (options & OP_SHORTCACHE) ? T : NIL;
+  stream->silent = (options & OP_SILENT) ? T : NIL;
+  stream->halfopen = (options & OP_HALFOPEN) ? T : NIL;
+  stream->secure = (options & OP_SECURE) ? T : NIL;
+  stream->tryssl = (options & OP_TRYSSL) ? T : NIL;
+  stream->mulnewsrc = (options & OP_MULNEWSRC) ? T : NIL;
+  stream->nokod = (options & OP_NOKOD) ? T : NIL;
+  stream->sniff = (options & OP_SNIFF) ? T : NIL;
+  stream->perm_seen = stream->perm_deleted = stream->perm_flagged =
+    stream->perm_answered = stream->perm_draft = stream->kwd_create = NIL;
+  stream->uid_nosticky = (d->flags & DR_NOSTICKY) ? T : NIL;
+  stream->uid_last = 0;		/* default UID validity */
+  stream->uid_validity = (unsigned long) time (0);
+				/* have driver open, flush if failed */
+  return ((*d->open) (stream)) ? stream : mail_close (stream);
+}
+
+/* Mail close
+ * Accepts: mail stream
+ *	    close options
+ * Returns: NIL, always
+ */
+
+MAILSTREAM *mail_close_full (MAILSTREAM *stream,long options)
+{
+  int i;
+  if (stream) {			/* make sure argument given */
+				/* do the driver's close action */
+    if (stream->dtb) (*stream->dtb->close) (stream,options);
+    stream->dtb = NIL;		/* resign driver */
+    if (stream->mailbox) fs_give ((void **) &stream->mailbox);
+    if (stream->original_mailbox)
+      fs_give ((void **) &stream->original_mailbox);
+    if (stream->snarf.name) fs_give ((void **) &stream->snarf.name);
+    stream->sequence++;		/* invalidate sequence */
+				/* flush user flags */
+    for (i = 0; i < NUSERFLAGS; i++)
+      if (stream->user_flags[i]) fs_give ((void **) &stream->user_flags[i]);
+    mail_free_cache (stream);	/* finally free the stream's storage */
+    if (mailfreestreamsparep && stream->sparep)
+      (*mailfreestreamsparep) (&stream->sparep);
+    if (!stream->use) fs_give ((void **) &stream);
+  }
+  return NIL;
+}
+
+/* Mail make handle
+ * Accepts: mail stream
+ * Returns: handle
+ *
+ *  Handles provide a way to have multiple pointers to a stream yet allow the
+ * stream's owner to nuke it or recycle it.
+ */
+
+MAILHANDLE *mail_makehandle (MAILSTREAM *stream)
+{
+  MAILHANDLE *handle = (MAILHANDLE *) fs_get (sizeof (MAILHANDLE));
+  handle->stream = stream;	/* copy stream */
+				/* and its sequence */
+  handle->sequence = stream->sequence;
+  stream->use++;		/* let stream know another handle exists */
+  return handle;
+}
+
+
+/* Mail release handle
+ * Accepts: Mail handle
+ */
+
+void mail_free_handle (MAILHANDLE **handle)
+{
+  MAILSTREAM *s;
+  if (*handle) {		/* only free if exists */
+				/* resign stream, flush unreferenced zombies */
+    if ((!--(s = (*handle)->stream)->use) && !s->dtb) fs_give ((void **) &s);
+    fs_give ((void **) handle);	/* now flush the handle */
+  }
+}
+
+
+/* Mail get stream handle
+ * Accepts: Mail handle
+ * Returns: mail stream or NIL if stream gone
+ */
+
+MAILSTREAM *mail_stream (MAILHANDLE *handle)
+{
+  MAILSTREAM *s = handle->stream;
+  return (s->dtb && (handle->sequence == s->sequence)) ? s : NIL;
+}
+
+/* Mail fetch cache element
+ * Accepts: mail stream
+ *	    message # to fetch
+ * Returns: cache element of this message
+ * Can also be used to create cache elements for new messages.
+ */
+
+MESSAGECACHE *mail_elt (MAILSTREAM *stream,unsigned long msgno)
+{
+  if (msgno < 1 || msgno > stream->nmsgs) {
+    char tmp[MAILTMPLEN];
+    sprintf (tmp,"Bad msgno %lu in mail_elt, nmsgs = %lu, mbx=%.80s",
+	     msgno,stream->nmsgs,stream->mailbox ? stream->mailbox : "???");
+    fatal (tmp);
+  }
+  return (MESSAGECACHE *) (*mailcache) (stream,msgno,CH_MAKEELT);
+}
+
+
+/* Mail fetch fast information
+ * Accepts: mail stream
+ *	    sequence
+ *	    option flags
+ *
+ * Generally, mail_fetch_structure is preferred
+ */
+
+void mail_fetch_fast (MAILSTREAM *stream,char *sequence,long flags)
+{
+  				/* do the driver's action */
+  if (stream->dtb && stream->dtb->fast)
+    (*stream->dtb->fast) (stream,sequence,flags);
+}
+
+
+/* Mail fetch flags
+ * Accepts: mail stream
+ *	    sequence
+ *	    option flags
+ */
+
+void mail_fetch_flags (MAILSTREAM *stream,char *sequence,long flags)
+{
+  				/* do the driver's action */
+  if (stream->dtb && stream->dtb->msgflags)
+    (*stream->dtb->msgflags) (stream,sequence,flags);
+}
+
+/* Mail fetch message overview
+ * Accepts: mail stream
+ *	    UID sequence to fetch
+ *	    pointer to overview return function
+ */
+
+void mail_fetch_overview (MAILSTREAM *stream,char *sequence,overview_t ofn)
+{
+  if (stream->dtb && mail_uid_sequence (stream,sequence) &&
+      !(stream->dtb->overview && (*stream->dtb->overview) (stream,ofn)) &&
+      mail_ping (stream))
+    mail_fetch_overview_default (stream,ofn);
+}
+
+
+/* Mail fetch message overview using sequence numbers instead of UIDs
+ * Accepts: mail stream
+ *	    sequence to fetch
+ *	    pointer to overview return function
+ */
+
+void mail_fetch_overview_sequence (MAILSTREAM *stream,char *sequence,
+				   overview_t ofn)
+{
+  if (stream->dtb && mail_sequence (stream,sequence) &&
+      !(stream->dtb->overview && (*stream->dtb->overview) (stream,ofn)) &&
+      mail_ping (stream))
+    mail_fetch_overview_default (stream,ofn);
+}
+
+
+/* Mail fetch message overview default handler
+ * Accepts: mail stream with sequence bits lit
+ *	    pointer to overview return function
+ */
+
+void mail_fetch_overview_default (MAILSTREAM *stream,overview_t ofn)
+{
+  MESSAGECACHE *elt;
+  ENVELOPE *env;
+  OVERVIEW ov;
+  unsigned long i;
+  ov.optional.lines = 0;
+  ov.optional.xref = NIL;
+  for (i = 1; i <= stream->nmsgs; i++)
+    if (((elt = mail_elt (stream,i))->sequence) &&
+	(env = mail_fetch_structure (stream,i,NIL,NIL)) && ofn) {
+      ov.subject = env->subject;
+      ov.from = env->from;
+      ov.date = env->date;
+      ov.message_id = env->message_id;
+      ov.references = env->references;
+      ov.optional.octets = elt->rfc822_size;
+      (*ofn) (stream,mail_uid (stream,i),&ov,i);
+    }
+}
+
+/* Mail fetch message structure
+ * Accepts: mail stream
+ *	    message # to fetch
+ *	    pointer to return body
+ *	    option flags
+ * Returns: envelope of this message, body returned in body value
+ *
+ * Fetches the "fast" information as well
+ */
+
+ENVELOPE *mail_fetch_structure (MAILSTREAM *stream,unsigned long msgno,
+				BODY **body,long flags)
+{
+  ENVELOPE **env;
+  BODY **b;
+  MESSAGECACHE *elt;
+  char c,*s,*hdr;
+  unsigned long hdrsize;
+  STRING bs;
+				/* do the driver's action if specified */
+  if (stream->dtb && stream->dtb->structure)
+    return (*stream->dtb->structure) (stream,msgno,body,flags);
+  if (flags & FT_UID) {		/* UID form of call */
+    if (msgno = mail_msgno (stream,msgno)) flags &= ~FT_UID;
+    else return NIL;		/* must get UID/msgno map first */
+  }
+  elt = mail_elt (stream,msgno);/* get elt for real message number */
+  if (stream->scache) {		/* short caching */
+    if (msgno != stream->msgno){/* garbage collect if not same message */
+      mail_gc (stream,GC_ENV | GC_TEXTS);
+      stream->msgno = msgno;	/* this is the current message now */
+    }
+    env = &stream->env;		/* get pointers to envelope and body */
+    b = &stream->body;
+  }
+  else {			/* get pointers to elt envelope and body */
+    env = &elt->private.msg.env;
+    b = &elt->private.msg.body;
+  }
+
+  if (stream->dtb && ((body && !*b) || !*env || (*env)->incomplete)) {
+    mail_free_envelope (env);	/* flush old envelope and body */
+    mail_free_body (b);
+				/* see if need to fetch the whole thing */
+    if (body || !elt->rfc822_size) {
+      s = (*stream->dtb->header) (stream,msgno,&hdrsize,flags & ~FT_INTERNAL);
+				/* make copy in case body fetch smashes it */
+      hdr = (char *) memcpy (fs_get ((size_t) hdrsize+1),s,(size_t) hdrsize);
+      hdr[hdrsize] = '\0';	/* tie off header */
+      (*stream->dtb->text) (stream,msgno,&bs,(flags & ~FT_INTERNAL) | FT_PEEK);
+      if (!elt->rfc822_size) elt->rfc822_size = hdrsize + SIZE (&bs);
+      if (body)			/* only parse body if requested */
+	rfc822_parse_msg (env,b,hdr,hdrsize,&bs,BADHOST,stream->dtb->flags);
+      else
+	rfc822_parse_msg (env,NIL,hdr,hdrsize,NIL,BADHOST,stream->dtb->flags);
+      fs_give ((void **) &hdr);	/* flush header */
+    }
+    else {			/* can save memory doing it this way */
+      hdr = (*stream->dtb->header) (stream,msgno,&hdrsize,flags | FT_INTERNAL);
+      if (hdrsize) {		/* in case null header */
+	c = hdr[hdrsize];	/* preserve what's there */
+	hdr[hdrsize] = '\0';	/* tie off header */
+	rfc822_parse_msg (env,NIL,hdr,hdrsize,NIL,BADHOST,stream->dtb->flags);
+	hdr[hdrsize] = c;	/* restore in case cached data */
+      }
+      else *env = mail_newenvelope ();
+    }
+  }
+				/* if need date, have date in envelope? */
+  if (!elt->day && *env && (*env)->date) mail_parse_date (elt,(*env)->date);
+				/* sigh, fill in bogus default */
+  if (!elt->day) elt->day = elt->month = 1;
+  if (body) *body = *b;		/* return the body */
+  return *env;			/* return the envelope */
+}
+
+/* Mail mark single message (internal use only)
+ * Accepts: mail stream
+ *	    elt to mark
+ *	    fetch flags
+ */
+
+static void markseen (MAILSTREAM *stream,MESSAGECACHE *elt,long flags)
+{
+  unsigned long i;
+  char sequence[20];
+  MESSAGECACHE *e;
+				/* non-peeking and needs to set \Seen? */
+  if (!(flags & FT_PEEK) && !elt->seen) {
+    if (stream->dtb->flagmsg){	/* driver wants per-message call? */
+      elt->valid = NIL;		/* do pre-alteration driver call */
+      (*stream->dtb->flagmsg) (stream,elt);
+				/* set seen, do post-alteration driver call */
+      elt->seen = elt->valid = T;
+      (*stream->dtb->flagmsg) (stream,elt);
+    }
+    if (stream->dtb->flag) {	/* driver wants one-time call?  */
+				/* better safe than sorry, save seq bits */
+      for (i = 1; i <= stream->nmsgs; i++) {
+	e = mail_elt (stream,i);
+	e->private.sequence = e->sequence;
+      }
+				/* call driver to set the message */
+      sprintf (sequence,"%lu",elt->msgno);
+      (*stream->dtb->flag) (stream,sequence,"\\Seen",ST_SET);
+				/* restore sequence bits */
+      for (i = 1; i <= stream->nmsgs; i++) {
+	e = mail_elt (stream,i);
+	e->sequence = e->private.sequence;
+      }
+    }
+				/* notify mail program of flag change */
+    MM_FLAGS (stream,elt->msgno);
+  }
+}
+
+/* Mail fetch message
+ * Accepts: mail stream
+ *	    message # to fetch
+ *	    pointer to returned length
+ *	    flags
+ * Returns: message text
+ */
+
+char *mail_fetch_message (MAILSTREAM *stream,unsigned long msgno,
+			  unsigned long *len,long flags)
+{
+  GETS_DATA md;
+  SIZEDTEXT *t;
+  STRING bs;
+  MESSAGECACHE *elt;
+  char *s,*u;
+  unsigned long i,j;
+  if (len) *len = 0;		/* default return size */
+  if (flags & FT_UID) {		/* UID form of call */
+    if (msgno = mail_msgno (stream,msgno)) flags &= ~FT_UID;
+    else return "";		/* must get UID/msgno map first */
+  }
+				/* initialize message data identifier */
+  INIT_GETS (md,stream,msgno,"",0,0);
+				/* is data already cached? */
+  if ((t = &(elt = mail_elt (stream,msgno))->private.msg.full.text)->data) {
+    markseen (stream,elt,flags);/* mark message seen */
+    return mail_fetch_text_return (&md,t,len);
+  }
+  if (!stream->dtb) return "";	/* not in cache, must have live driver */
+  if (stream->dtb->msgdata) return
+    ((*stream->dtb->msgdata) (stream,msgno,"",0,0,NIL,flags) && t->data) ?
+      mail_fetch_text_return (&md,t,len) : "";
+				/* ugh, have to do this the crufty way */
+  u = mail_fetch_header (stream,msgno,NIL,NIL,&i,flags);
+				/* copy in case text method stomps on it */
+  s = (char *) memcpy (fs_get ((size_t) i),u,(size_t) i);
+  if ((*stream->dtb->text) (stream,msgno,&bs,flags)) {
+    t = &stream->text;		/* build combined copy */
+    if (t->data) fs_give ((void **) &t->data);
+    t->data = (unsigned char *) fs_get ((t->size = i + SIZE (&bs)) + 1);
+    if (!elt->rfc822_size) elt->rfc822_size = t->size;
+    else if (elt->rfc822_size != t->size) {
+      char tmp[MAILTMPLEN];
+      sprintf (tmp,"Calculated RFC822.SIZE (%lu) != reported size (%lu)",
+	       t->size,elt->rfc822_size);
+      mm_log (tmp,WARN);	/* bug trap */
+    }
+    memcpy (t->data,s,(size_t) i);
+    for (u = (char *) t->data + i, j = SIZE (&bs); j;) {
+      memcpy (u,bs.curpos,bs.cursize);
+      u += bs.cursize;		/* update text */
+      j -= bs.cursize;
+      bs.curpos += (bs.cursize -1);
+      bs.cursize = 0;
+      (*bs.dtb->next) (&bs);	/* advance to next buffer's worth */
+    } 
+    *u = '\0';			/* tie off data */
+    u = mail_fetch_text_return (&md,t,len);
+  }
+  else u = "";
+  fs_give ((void **) &s);	/* finished with copy of header */
+  return u;
+}
+
+/* Mail fetch message header
+ * Accepts: mail stream
+ *	    message # to fetch
+ *	    MIME section specifier (#.#.#...#)
+ *	    list of lines to fetch
+ *	    pointer to returned length
+ *	    flags
+ * Returns: message header in RFC822 format
+ *
+ * Note: never calls a mailgets routine
+ */
+
+char *mail_fetch_header (MAILSTREAM *stream,unsigned long msgno,char *section,
+			 STRINGLIST *lines,unsigned long *len,long flags)
+{
+  STRING bs;
+  BODY *b = NIL;
+  SIZEDTEXT *t = NIL,rt;
+  MESSAGE *m = NIL;
+  MESSAGECACHE *elt;
+  char tmp[MAILTMPLEN];
+  if (len) *len = 0;		/* default return size */
+  if (section && (strlen (section) > (MAILTMPLEN - 20))) return "";
+  if (flags & FT_UID) {		/* UID form of call */
+    if (msgno = mail_msgno (stream,msgno)) flags &= ~FT_UID;
+    else return "";		/* must get UID/msgno map first */
+  }
+  elt = mail_elt (stream,msgno);/* get cache data */
+  if (section && *section) {	/* nested body header wanted? */
+    if (!((b = mail_body (stream,msgno,section)) &&
+	  (b->type == TYPEMESSAGE) && !strcmp (b->subtype,"RFC822")))
+      return "";		/* lose if no body or not MESSAGE/RFC822 */
+    m = b->nested.msg;		/* point to nested message */
+  }
+				/* else top-level message header wanted */
+  else m = &elt->private.msg;
+  if (m->header.text.data && mail_match_lines (lines,m->lines,flags)) {
+    if (lines) textcpy (t = &stream->text,&m->header.text);
+    else t = &m->header.text;	/* in cache, and cache is valid */
+    markseen (stream,elt,flags);/* mark message seen */
+  }
+
+  else if (stream->dtb) {	/* not in cache, has live driver? */
+    if (stream->dtb->msgdata) {	/* has driver section fetch? */
+				/* build driver section specifier */
+      if (section && *section) sprintf (tmp,"%s.HEADER",section);
+      else strcpy (tmp,"HEADER");
+      if ((*stream->dtb->msgdata) (stream,msgno,tmp,0,0,lines,flags)) {
+	t = &m->header.text;	/* fetch data */
+				/* don't need to postprocess lines */
+	if (m->lines) lines = NIL;
+	else if (lines) textcpy (t = &stream->text,&m->header.text);
+      }
+    }
+    else if (b) {		/* nested body wanted? */
+      if (stream->private.search.text) {
+	rt.data = (unsigned char *) stream->private.search.text +
+	  b->nested.msg->header.offset;
+	rt.size = b->nested.msg->header.text.size;
+	t = &rt;
+      }
+      else if ((*stream->dtb->text) (stream,msgno,&bs,flags & ~FT_INTERNAL)) {
+	if ((bs.dtb->next == mail_string_next) && !lines) {
+	  rt.data = (unsigned char *) bs.curpos + b->nested.msg->header.offset;
+	  rt.size = b->nested.msg->header.text.size;
+	  if (stream->private.search.string)
+	    stream->private.search.text = bs.curpos;
+	  t = &rt;		/* special hack to avoid extra copy */
+	}
+	else textcpyoffstring (t = &stream->text,&bs,
+			       b->nested.msg->header.offset,
+			       b->nested.msg->header.text.size);
+      }
+    }
+    else {			/* top-level header fetch */
+				/* mark message seen */
+      markseen (stream,elt,flags);
+      if (rt.data = (unsigned char *)
+	  (*stream->dtb->header) (stream,msgno,&rt.size,flags)) {
+				/* make a safe copy if need to filter */
+	if (lines) textcpy (t = &stream->text,&rt);
+	else t = &rt;		/* top level header */
+      }
+    }
+  }
+  if (!t || !t->data) return "";/* error if no string */
+				/* filter headers if requested */
+  if (lines) t->size = mail_filter ((char *) t->data,t->size,lines,flags);
+  if (len) *len = t->size;	/* return size if requested */
+  return (char *) t->data;	/* and text */
+}
+
+/* Mail fetch message text
+ * Accepts: mail stream
+ *	    message # to fetch
+ *	    MIME section specifier (#.#.#...#)
+ *	    pointer to returned length
+ *	    flags
+ * Returns: message text
+ */
+
+char *mail_fetch_text (MAILSTREAM *stream,unsigned long msgno,char *section,
+		       unsigned long *len,long flags)
+{
+  GETS_DATA md;
+  PARTTEXT *p;
+  STRING bs;
+  MESSAGECACHE *elt;
+  BODY *b = NIL;
+  char tmp[MAILTMPLEN];
+  unsigned long i;
+  if (len) *len = 0;		/* default return size */
+  memset (&stream->private.string,NIL,sizeof (STRING));
+  if (section && (strlen (section) > (MAILTMPLEN - 20))) return "";
+  if (flags & FT_UID) {		/* UID form of call */
+    if (msgno = mail_msgno (stream,msgno)) flags &= ~FT_UID;
+    else return "";		/* must get UID/msgno map first */
+  }
+  elt = mail_elt (stream,msgno);/* get cache data */
+  if (section && *section) {	/* nested body text wanted? */
+    if (!((b = mail_body (stream,msgno,section)) &&
+	  (b->type == TYPEMESSAGE) && !strcmp (b->subtype,"RFC822")))
+      return "";		/* lose if no body or not MESSAGE/RFC822 */
+    p = &b->nested.msg->text;	/* point at nested message */
+				/* build IMAP-format section specifier */
+    sprintf (tmp,"%s.TEXT",section);
+    flags &= ~FT_INTERNAL;	/* can't win with this set */
+  }
+  else {			/* top-level message text wanted */
+    p = &elt->private.msg.text;
+    strcpy (tmp,"TEXT");
+  }
+				/* initialize message data identifier */
+  INIT_GETS (md,stream,msgno,section,0,0);
+  if (p->text.data) {		/* is data already cached? */
+    markseen (stream,elt,flags);/* mark message seen */
+    return mail_fetch_text_return (&md,&p->text,len);
+  }
+  if (!stream->dtb) return "";	/* not in cache, must have live driver */
+  if (stream->dtb->msgdata) return
+    ((*stream->dtb->msgdata) (stream,msgno,tmp,0,0,NIL,flags) && p->text.data)?
+      mail_fetch_text_return (&md,&p->text,len) : "";
+  if (!(*stream->dtb->text) (stream,msgno,&bs,flags)) return "";
+  if (section && *section) {	/* nested is more complex */
+    SETPOS (&bs,p->offset);
+    i = p->text.size;		/* just want this much */
+  }
+  else i = SIZE (&bs);		/* want entire text */
+  return mail_fetch_string_return (&md,&bs,i,len,flags);
+}
+
+/* Mail fetch message body part MIME headers
+ * Accepts: mail stream
+ *	    message # to fetch
+ *	    MIME section specifier (#.#.#...#)
+ *	    pointer to returned length
+ *	    flags
+ * Returns: message text
+ */
+
+char *mail_fetch_mime (MAILSTREAM *stream,unsigned long msgno,char *section,
+		       unsigned long *len,long flags)
+{
+  PARTTEXT *p;
+  STRING bs;
+  BODY *b;
+  char tmp[MAILTMPLEN];
+  if (len) *len = 0;		/* default return size */
+  if (section && (strlen (section) > (MAILTMPLEN - 20))) return "";
+  if (flags & FT_UID) {		/* UID form of call */
+    if (msgno = mail_msgno (stream,msgno)) flags &= ~FT_UID;
+    else return "";		/* must get UID/msgno map first */
+  }
+  flags &= ~FT_INTERNAL;	/* can't win with this set */
+  if (!(section && *section && (b = mail_body (stream,msgno,section))))
+    return "";			/* not valid section */
+				/* in cache? */
+  if ((p = &b->mime)->text.data) {
+				/* mark message seen */
+    markseen (stream,mail_elt (stream,msgno),flags);
+    if (len) *len = p->text.size;
+    return (char *) p->text.data;
+  }
+  if (!stream->dtb) return "";	/* not in cache, must have live driver */
+  if (stream->dtb->msgdata) {	/* has driver fetch? */
+				/* build driver section specifier */
+    sprintf (tmp,"%s.MIME",section);
+    if ((*stream->dtb->msgdata) (stream,msgno,tmp,0,0,NIL,flags) &&
+	p->text.data) {
+      if (len) *len = p->text.size;
+      return (char *) p->text.data;
+    }
+    else return "";
+  }
+  if (len) *len = b->mime.text.size;
+  if (!b->mime.text.size) {	/* empty MIME header -- mark seen anyway */
+    markseen (stream,mail_elt (stream,msgno),flags);
+    return "";
+  }
+				/* have to get it from offset */
+  if (stream->private.search.text)
+    return stream->private.search.text + b->mime.offset;
+  if (!(*stream->dtb->text) (stream,msgno,&bs,flags)) {
+    if (len) *len = 0;
+    return "";
+  }
+  if (bs.dtb->next == mail_string_next) {
+    if (stream->private.search.string) stream->private.search.text = bs.curpos;
+    return bs.curpos + b->mime.offset;
+  }
+  return textcpyoffstring (&stream->text,&bs,b->mime.offset,b->mime.text.size);
+}
+
+/* Mail fetch message body part
+ * Accepts: mail stream
+ *	    message # to fetch
+ *	    MIME section specifier (#.#.#...#)
+ *	    pointer to returned length
+ *	    flags
+ * Returns: message body
+ */
+
+char *mail_fetch_body (MAILSTREAM *stream,unsigned long msgno,char *section,
+		       unsigned long *len,long flags)
+{
+  GETS_DATA md;
+  PARTTEXT *p;
+  STRING bs;
+  BODY *b;
+  SIZEDTEXT *t;
+  char *s,tmp[MAILTMPLEN];
+  memset (&stream->private.string,NIL,sizeof (STRING));
+  if (!(section && *section))	/* top-level text wanted? */
+    return mail_fetch_message (stream,msgno,len,flags);
+  else if (strlen (section) > (MAILTMPLEN - 20)) return "";
+  flags &= ~FT_INTERNAL;	/* can't win with this set */
+				/* initialize message data identifier */
+  INIT_GETS (md,stream,msgno,section,0,0);
+				/* kludge for old section 0 header */
+  if (!strcmp (s = strcpy (tmp,section),"0") ||
+      ((s = strstr (tmp,".0")) && !s[2])) {
+    SIZEDTEXT ht;
+    *s = '\0';			/* tie off section */
+				/* this silly way so it does mailgets */
+    ht.data = (unsigned char *) mail_fetch_header (stream,msgno,
+						   tmp[0] ? tmp : NIL,NIL,
+						   &ht.size,flags);
+				/* may have UIDs here */
+    md.flags = (flags & FT_UID) ? MG_UID : NIL;
+    return mail_fetch_text_return (&md,&ht,len);
+  }
+  if (len) *len = 0;		/* default return size */
+  if (flags & FT_UID) {		/* UID form of call */
+    if (msgno = mail_msgno (stream,msgno)) flags &= ~FT_UID;
+    else return "";		/* must get UID/msgno map first */
+  }
+				/* must have body */
+  if (!(b = mail_body (stream,msgno,section))) return "";
+				/* have cached text? */
+  if ((t = &(p = &b->contents)->text)->data) {
+				/* mark message seen */
+    markseen (stream,mail_elt (stream,msgno),flags);
+    return mail_fetch_text_return (&md,t,len);
+  }
+  if (!stream->dtb) return "";	/* not in cache, must have live driver */
+  if (stream->dtb->msgdata) return
+    ((*stream->dtb->msgdata)(stream,msgno,section,0,0,NIL,flags) && t->data) ?
+      mail_fetch_text_return (&md,t,len) : "";
+  if (len) *len = t->size;
+  if (!t->size) {		/* empty body part -- mark seen anyway */
+    markseen (stream,mail_elt (stream,msgno),flags);
+    return "";
+  }
+				/* copy body from stringstruct offset */
+  if (stream->private.search.text)
+    return stream->private.search.text + p->offset;
+  if (!(*stream->dtb->text) (stream,msgno,&bs,flags)) {
+    if (len) *len = 0;
+    return "";
+  }
+  if (bs.dtb->next == mail_string_next) {
+    if (stream->private.search.string) stream->private.search.text = bs.curpos;
+    return bs.curpos + p->offset;
+  }
+  SETPOS (&bs,p->offset);
+  return mail_fetch_string_return (&md,&bs,t->size,len,flags);
+}
+
+/* Mail fetch partial message text
+ * Accepts: mail stream
+ *	    message # to fetch
+ *	    MIME section specifier (#.#.#...#)
+ *	    offset of first designed byte or 0 to start at beginning
+ *	    maximum number of bytes or 0 for all bytes
+ *	    flags
+ * Returns: T if successful, else NIL
+ */
+
+long mail_partial_text (MAILSTREAM *stream,unsigned long msgno,char *section,
+			unsigned long first,unsigned long last,long flags)
+{
+  GETS_DATA md;
+  PARTTEXT *p = NIL;
+  MESSAGECACHE *elt;
+  STRING bs;
+  BODY *b;
+  char tmp[MAILTMPLEN];
+  unsigned long i;
+  if (!mailgets) fatal ("mail_partial_text() called without a mailgets!");
+  if (section && (strlen (section) > (MAILTMPLEN - 20))) return NIL;
+  if (flags & FT_UID) {		/* UID form of call */
+    if (msgno = mail_msgno (stream,msgno)) flags &= ~FT_UID;
+    else return NIL;		/* must get UID/msgno map first */
+  }
+  elt = mail_elt (stream,msgno);/* get cache data */
+  flags &= ~FT_INTERNAL;	/* bogus if this is set */
+  if (section && *section) {	/* nested body text wanted? */
+    if (!((b = mail_body (stream,msgno,section)) &&
+	  (b->type == TYPEMESSAGE) && !strcmp (b->subtype,"RFC822")))
+      return NIL;		/* lose if no body or not MESSAGE/RFC822 */
+    p = &b->nested.msg->text;	/* point at nested message */
+				/* build IMAP-format section specifier */
+    sprintf (tmp,"%s.TEXT",section);
+  }
+  else {			/* else top-level message text wanted */
+    p = &elt->private.msg.text;
+    strcpy (tmp,"TEXT");
+  }
+
+				/* initialize message data identifier */
+  INIT_GETS (md,stream,msgno,tmp,first,last);
+  if (p->text.data) {		/* is data already cached? */
+    INIT (&bs,mail_string,p->text.data,i = p->text.size);
+    markseen (stream,elt,flags);/* mark message seen */
+  }
+  else {			/* else get data from driver */
+    if (!stream->dtb) return NIL;
+    if (stream->dtb->msgdata)	/* driver will handle this */
+      return (*stream->dtb->msgdata) (stream,msgno,tmp,first,last,NIL,flags);
+    if (!(*stream->dtb->text) (stream,msgno,&bs,flags)) return NIL;
+    if (section && *section) {	/* nexted if more complex */
+      SETPOS (&bs,p->offset);	/* offset stringstruct to data */
+      i = p->text.size;		/* maximum size of data */
+    }
+    else i = SIZE (&bs);	/* just want this much */
+  }
+  if (i <= first) i = first = 0;/* first byte is beyond end of text */
+				/* truncate as needed */
+  else {			/* offset and truncate */
+    SETPOS (&bs,first + GETPOS (&bs));
+    i -= first;			/* reduced size */
+    if (last && (i > last)) i = last;
+  }
+				/* do the mailgets thing */
+  (*mailgets) (mail_read,&bs,i,&md);
+  return T;			/* success */
+}
+
+/* Mail fetch partial message body part
+ * Accepts: mail stream
+ *	    message # to fetch
+ *	    MIME section specifier (#.#.#...#)
+ *	    offset of first designed byte or 0 to start at beginning
+ *	    maximum number of bytes or 0 for all bytes
+ *	    flags
+ * Returns: T if successful, else NIL
+ */
+
+long mail_partial_body (MAILSTREAM *stream,unsigned long msgno,char *section,
+			unsigned long first,unsigned long last,long flags)
+{
+  GETS_DATA md;
+  PARTTEXT *p;
+  STRING bs;
+  BODY *b;
+  SIZEDTEXT *t;
+  unsigned long i;
+  if (!(section && *section))	/* top-level text wanted? */
+    return mail_partial_text (stream,msgno,NIL,first,last,flags);
+  if (!mailgets) fatal ("mail_partial_body() called without a mailgets!");
+  if (flags & FT_UID) {		/* UID form of call */
+    if (msgno = mail_msgno (stream,msgno)) flags &= ~FT_UID;
+    else return NIL;		/* must get UID/msgno map first */
+  }
+				/* must have body */
+  if (!(b = mail_body (stream,msgno,section))) return NIL;
+  flags &= ~FT_INTERNAL;	/* bogus if this is set */
+
+				/* initialize message data identifier */
+  INIT_GETS (md,stream,msgno,section,first,last);
+				/* have cached text? */
+  if ((t = &(p = &b->contents)->text)->data) {
+				/* mark message seen */
+    markseen (stream,mail_elt (stream,msgno),flags);
+    INIT (&bs,mail_string,t->data,i = t->size);
+  }
+  else {			/* else get data from driver */
+    if (!stream->dtb) return NIL;
+    if (stream->dtb->msgdata)	/* driver will handle this */
+      return (*stream->dtb->msgdata) (stream,msgno,section,first,last,NIL,
+				      flags);
+    if (!(*stream->dtb->text) (stream,msgno,&bs,flags)) return NIL;
+    if (section && *section) {	/* nexted if more complex */
+      SETPOS (&bs,p->offset);	/* offset stringstruct to data */
+      i = t->size;		/* maximum size of data */
+    }
+    else i = SIZE (&bs);	/* just want this much */
+  }
+  if (i <= first) i = first = 0;/* first byte is beyond end of text */
+  else {			/* offset and truncate */
+    SETPOS (&bs,first + GETPOS (&bs));
+    i -= first;			/* reduced size */
+    if (last && (i > last)) i = last;
+  }
+				/* do the mailgets thing */
+  (*mailgets) (mail_read,&bs,i,&md);
+  return T;			/* success */
+}
+
+/* Mail return message text
+ * Accepts: identifier data
+ *	    sized text
+ *	    pointer to returned length
+ * Returns: text
+ */
+
+char *mail_fetch_text_return (GETS_DATA *md,SIZEDTEXT *t,unsigned long *len)
+{
+  STRING bs;
+  if (len) *len = t->size;	/* return size */
+  if (t->size && mailgets) {	/* have to do the mailgets thing? */
+				/* silly but do it anyway for consistency */
+    INIT (&bs,mail_string,t->data,t->size);
+    return (*mailgets) (mail_read,&bs,t->size,md);
+  }
+  return t->size ? (char *) t->data : "";
+}
+
+
+/* Mail return message string
+ * Accepts: identifier data
+ *	    stringstruct
+ *	    text length
+ *	    pointer to returned length
+ *	    flags
+ * Returns: text, or NIL if stringstruct returned
+ */
+
+char *mail_fetch_string_return (GETS_DATA *md,STRING *bs,unsigned long i,
+				unsigned long *len,long flags)
+{
+  char *ret = NIL;
+  if (len) *len = i;		/* return size */
+				/* return stringstruct hack */
+  if (flags & FT_RETURNSTRINGSTRUCT) {
+    memcpy (&md->stream->private.string,bs,sizeof (STRING));
+    SETPOS (&md->stream->private.string,GETPOS (&md->stream->private.string));
+  }
+				/* have to do the mailgets thing? */
+  else if (mailgets) ret = (*mailgets) (mail_read,bs,i,md);
+				/* special hack to avoid extra copy */
+  else if (bs->dtb->next == mail_string_next) ret = bs->curpos;
+				/* make string copy in memory */
+  else ret = textcpyoffstring (&md->stream->text,bs,GETPOS (bs),i);
+  return ret;
+}
+
+/* Read data from stringstruct
+ * Accepts: stringstruct
+ *	    size of data to read
+ *	    buffer to read into
+ * Returns: T, always, stringstruct updated
+ */
+
+long mail_read (void *stream,unsigned long size,char *buffer)
+{
+  unsigned long i;
+  STRING *s = (STRING *) stream;
+  while (size) {		/* until satisfied */
+    memcpy (buffer,s->curpos,i = min (s->cursize,size));
+    buffer += i;		/* update buffer */
+    size -= i;			/* note that we read this much */
+    s->curpos += --i;		/* advance that many spaces minus 1 */
+    s->cursize -= i;
+    SNX (s);			/* now use SNX to advance the last byte */
+  }
+  return T;
+}
+
+/* Mail fetch UID
+ * Accepts: mail stream
+ *	    message number
+ * Returns: UID or zero if dead stream
+ */
+
+unsigned long mail_uid (MAILSTREAM *stream,unsigned long msgno)
+{
+  unsigned long uid = mail_elt (stream,msgno)->private.uid;
+  return uid ? uid :
+    (stream->dtb && stream->dtb->uid) ? (*stream->dtb->uid) (stream,msgno) : 0;
+}
+
+
+/* Mail fetch msgno from UID
+ * Accepts: mail stream
+ *	    UID
+ * Returns: msgno or zero if failed
+ */
+
+unsigned long mail_msgno (MAILSTREAM *stream,unsigned long uid)
+{
+  unsigned long msgno,delta,first,firstuid,last,lastuid,middle,miduid;
+  if (stream->dtb) {		/* active stream? */
+    if (stream->dtb->msgno)	/* direct way */
+      return (*stream->dtb->msgno) (stream,uid);
+    else if (stream->dtb->uid) {/* indirect way */
+      /* Placeholder for now, since currently there are no drivers which
+       * have a uid method but not a msgno method
+       */
+      for (msgno = 1; msgno <= stream->nmsgs; msgno++)
+	if ((*stream->dtb->uid) (stream,msgno) == uid) return msgno;
+    }
+				/* binary search since have full map */
+    else for (first = 1,last = stream->nmsgs, delta = (first <= last) ? 1 : 0;
+	      delta &&
+	      (uid >= (firstuid = mail_elt (stream,first)->private.uid)) &&
+		(uid <= (lastuid = mail_elt (stream,last)->private.uid));) {
+				/* done if match at an endpoint */
+	if (uid == firstuid) return first;
+	if (uid == lastuid) return last;
+				/* have anything between endpoints? */
+	if (delta = ((last - first) / 2)) {
+	  if ((miduid = mail_elt (stream,middle = first + delta)->private.uid)
+	      == uid)
+	    return middle;	/* found match in middle */
+	  else if (uid < miduid) last = middle - 1;
+	  else first = middle + 1;
+	}
+    }
+  }
+  else {			/* dead stream, do linear search for UID */
+    for (msgno = 1; msgno <= stream->nmsgs; msgno++)
+      if (mail_elt (stream,msgno)->private.uid == uid) return msgno;
+  }
+  return 0;			/* didn't find the UID anywhere */
+}
+
+/* Mail fetch From string for menu
+ * Accepts: destination string
+ *	    mail stream
+ *	    message # to fetch
+ *	    desired string length
+ * Returns: string of requested length
+ */
+
+void mail_fetchfrom (char *s,MAILSTREAM *stream,unsigned long msgno,
+		     long length)
+{
+  char *t;
+  char tmp[MAILTMPLEN];
+  ENVELOPE *env = mail_fetchenvelope (stream,msgno);
+  ADDRESS *adr = env ? env->from : NIL;
+  memset (s,' ',(size_t)length);/* fill it with spaces */
+  s[length] = '\0';		/* tie off with null */
+				/* get first from address from envelope */
+  while (adr && !adr->host) adr = adr->next;
+  if (adr) {			/* if a personal name exists use it */
+    if (!(t = adr->personal))
+      sprintf (t = tmp,"%.256s@%.256s",adr->mailbox,adr->host);
+    memcpy (s,t,(size_t) min (length,(long) strlen (t)));
+  }
+}
+
+
+/* Mail fetch Subject string for menu
+ * Accepts: destination string
+ *	    mail stream
+ *	    message # to fetch
+ *	    desired string length
+ * Returns: string of no more than requested length
+ */
+
+void mail_fetchsubject (char *s,MAILSTREAM *stream,unsigned long msgno,
+			long length)
+{
+  ENVELOPE *env = mail_fetchenvelope (stream,msgno);
+  memset (s,'\0',(size_t) length+1);
+				/* copy subject from envelope */
+  if (env && env->subject) strncpy (s,env->subject,(size_t) length);
+  else *s = ' ';		/* if no subject then just a space */
+}
+
+/* Mail modify flags
+ * Accepts: mail stream
+ *	    sequence
+ *	    flag(s)
+ *	    option flags
+ */
+
+void mail_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
+{
+  MESSAGECACHE *elt;
+  unsigned long i,uf;
+  long f;
+  short nf;
+  if (!stream->dtb) return;	/* no-op if no stream */
+  if ((stream->dtb->flagmsg || !stream->dtb->flag) &&
+      ((flags & ST_UID) ? mail_uid_sequence (stream,sequence) :
+       mail_sequence (stream,sequence)) &&
+      ((f = mail_parse_flags (stream,flag,&uf)) || uf))
+    for (i = 1,nf = (flags & ST_SET) ? T : NIL; i <= stream->nmsgs; i++)
+      if ((elt = mail_elt (stream,i))->sequence) {
+	struct {		/* old flags */
+	  unsigned int valid : 1;
+	  unsigned int seen : 1;
+	  unsigned int deleted : 1;
+	  unsigned int flagged : 1;
+	  unsigned int answered : 1;
+	  unsigned int draft : 1;
+	  unsigned long user_flags;
+	} old;
+	old.valid = elt->valid; old.seen = elt->seen;
+	old.deleted = elt->deleted; old.flagged = elt->flagged;
+	old.answered = elt->answered; old.draft = elt->draft;
+	old.user_flags = elt->user_flags;
+	elt->valid = NIL;	/* prepare for flag alteration */
+	if (stream->dtb->flagmsg) (*stream->dtb->flagmsg) (stream,elt);
+	if (f&fSEEN) elt->seen = nf;
+	if (f&fDELETED) elt->deleted = nf;
+	if (f&fFLAGGED) elt->flagged = nf;
+	if (f&fANSWERED) elt->answered = nf;
+	if (f&fDRAFT) elt->draft = nf;
+				/* user flags */
+	if (flags & ST_SET) elt->user_flags |= uf;
+	else elt->user_flags &= ~uf;
+	elt->valid = T;		/* flags now altered */
+	if ((old.valid != elt->valid) || (old.seen != elt->seen) ||
+	    (old.deleted != elt->deleted) || (old.flagged != elt->flagged) ||
+	    (old.answered != elt->answered) || (old.draft != elt->draft) ||
+	    (old.user_flags != elt->user_flags))
+	  MM_FLAGS (stream,elt->msgno);
+	if (stream->dtb->flagmsg) (*stream->dtb->flagmsg) (stream,elt);
+      }
+				/* call driver once */
+  if (stream->dtb->flag) (*stream->dtb->flag) (stream,sequence,flag,flags);
+}
+
+/* Mail search for messages
+ * Accepts: mail stream
+ *	    character set
+ *	    search program
+ *	    option flags
+ * Returns: T if successful, NIL if dead stream, NIL searchpgm or bad charset
+ */
+
+long mail_search_full (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,
+		       long flags)
+{
+  unsigned long i;
+  long ret = NIL;
+  if (!(flags & SE_RETAIN))	/* clear search vector unless retaining */
+    for (i = 1; i <= stream->nmsgs; ++i) mail_elt (stream,i)->searched = NIL;
+  if (pgm && stream->dtb)	/* must have a search program and driver */
+    ret = (*(stream->dtb->search ? stream->dtb->search : mail_search_default))
+      (stream,charset,pgm,flags);
+				/* flush search program if requested */
+  if (flags & SE_FREE) mail_free_searchpgm (&pgm);
+  return ret;
+}
+
+
+/* Mail search for messages default handler
+ * Accepts: mail stream
+ *	    character set
+ *	    search program
+ *	    option flags
+ * Returns: T if successful, NIL if bad charset
+ */
+
+long mail_search_default (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,
+			  long flags)
+{
+  unsigned long i;
+  char *msg;
+				/* make sure that charset is good */
+  if (msg = utf8_badcharset (charset)) {
+    MM_LOG (msg,ERROR);		/* output error */
+    fs_give ((void **) &msg);
+    return NIL;
+  }
+  utf8_searchpgm (pgm,charset);
+  for (i = 1; i <= stream->nmsgs; ++i)
+    if (mail_search_msg (stream,i,NIL,pgm)) {
+      if (flags & SE_UID) mm_searched (stream,mail_uid (stream,i));
+      else {			/* mark as searched, notify mail program */
+	mail_elt (stream,i)->searched = T;
+	if (!stream->silent) mm_searched (stream,i);
+      }
+    }
+  return LONGT;		/* search completed */
+}
+
+/* Mail ping mailbox
+ * Accepts: mail stream
+ * Returns: stream if still open else NIL
+ */
+
+long mail_ping (MAILSTREAM *stream)
+{
+  unsigned long i,n,uf,len;
+  char *s,*f,tmp[MAILTMPLEN],flags[MAILTMPLEN];
+  MAILSTREAM *snarf;
+  MESSAGECACHE *elt;
+  STRING bs;
+  long ret;
+				/* do driver action */
+  if ((ret = ((stream && stream->dtb) ? (stream->dtb->ping) (stream) : NIL)) &&
+      stream->snarf.name &&	/* time to snarf? */
+				/* prohibit faster than once/min */
+      (time (0) > (time_t) (stream->snarf.time + min(60,mailsnarfinterval))) &&
+      (snarf = mail_open (NIL,stream->snarf.name,
+			  stream->snarf.options | OP_SILENT))) {
+    if ((n = snarf->nmsgs) &&	/* yes, have messages to snarf? */
+	mail_search_full (snarf,NIL,mail_criteria ("UNDELETED"),SE_FREE)) {
+      for (i = 1; ret && (i <= n); i++)	/* for each message */
+	if ((elt = mail_elt (snarf,i))->searched &&
+	    (s = mail_fetch_message (snarf,i,&len,FT_PEEK)) && len) {
+	  INIT (&bs,mail_string,s,len);
+	  if (mailsnarfpreserve) {
+				/* yes, make sure have fast data */
+	    if (!elt->valid || !elt->day) {
+	      sprintf (tmp,"%lu",n);
+	      mail_fetch_fast (snarf,tmp,NIL);
+	    }
+				/* initialize flag string */
+	    memset (flags,0,MAILTMPLEN);
+				/* output system flags except \Deleted */
+	    if (elt->seen) strcat (flags," \\Seen");
+	    if (elt->flagged) strcat (flags," \\Flagged");
+	    if (elt->answered) strcat (flags," \\Answered");
+	    if (elt->draft) strcat (flags," \\Draft");
+				/* any user flags? */
+	    for (uf = elt->user_flags,s = flags + strlen (flags);
+		 uf && (f = stream->user_flags[find_rightmost_bit (&uf)]) &&
+		   ((MAILTMPLEN - (s - tmp)) > (long) (2 + strlen (f)));
+		 s += strlen (s)) sprintf (s," %s",f);
+	    ret = mail_append_full (stream,stream->mailbox,flags + 1,
+				    mail_date (tmp,elt),&bs);
+	  }
+	  else ret = mail_append (stream,stream->mailbox,&bs);
+
+	  if (ret) {		/* did snarf succeed? */
+				/* driver has per-message (or no) flag call */
+	    if (snarf->dtb->flagmsg || !snarf->dtb->flag) {
+	      elt->valid = NIL;	/* prepare for flag alteration */
+	      if (snarf->dtb->flagmsg) (*snarf->dtb->flagmsg) (snarf,elt);
+				/* flags now altered */
+	      elt->deleted = elt->seen = elt->valid = T;
+	      if (snarf->dtb->flagmsg) (*snarf->dtb->flagmsg) (snarf,elt);
+	    }
+				/* driver has one-time flag call */
+	    if (snarf->dtb->flag) {
+	      sprintf (tmp,"%lu",i);
+	      (*snarf->dtb->flag) (snarf,tmp,"\\Deleted \\Seen",ST_SET);
+	    }
+	  }
+	  else {		/* copy failed */
+	    sprintf (tmp,"Unable to move message %lu from %s mailbox",
+		     i,snarf->dtb->name);
+	    mm_log (tmp,WARN);
+	  }
+	}
+    }
+				/* expunge the messages */
+    mail_close_full (snarf,n ? CL_EXPUNGE : NIL);
+    stream->snarf.time = (unsigned long) time (0);
+    /* Even if the snarf failed, we don't want to return NIL if the stream
+     * is still alive.  Or at least that's what we currently think.
+     */
+  				/* redo the driver's action */
+    ret = stream->dtb ? (*stream->dtb->ping) (stream) : NIL;
+  }
+  return ret;
+}
+
+/* Mail check mailbox
+ * Accepts: mail stream
+ */
+
+void mail_check (MAILSTREAM *stream)
+{
+  				/* do the driver's action */
+  if (stream->dtb) (*stream->dtb->check) (stream);
+}
+
+
+/* Mail expunge mailbox
+ * Accepts: mail stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T on success, NIL on failure
+ */
+
+long mail_expunge_full (MAILSTREAM *stream,char *sequence,long options)
+{
+  				/* do the driver's action */
+  return stream->dtb ? (*stream->dtb->expunge) (stream,sequence,options) : NIL;
+}
+
+
+/* Mail copy message(s)
+ * Accepts: mail stream
+ *	    sequence
+ *	    destination mailbox
+ *	    flags
+ */
+
+long mail_copy_full (MAILSTREAM *stream,char *sequence,char *mailbox,
+		     long options)
+{
+  return stream->dtb ?
+    SAFE_COPY (stream->dtb,stream,sequence,mailbox,options) : NIL;
+}
+
+/* Append data package to use for old single-message mail_append() interface */
+
+typedef struct mail_append_package {
+  char *flags;			/* initial flags */
+  char *date;			/* message internal date */
+  STRING *message;		/* stringstruct of message */
+} APPENDPACKAGE;
+
+
+/* Single append message string
+ * Accepts: mail stream
+ *	    package pointer (cast as a void *)
+ *	    pointer to return initial flags
+ *	    pointer to return message internal date
+ *	    pointer to return stringstruct of message to append
+ * Returns: T, always
+ */
+
+static long mail_append_single (MAILSTREAM *stream,void *data,char **flags,
+				char **date,STRING **message)
+{
+  APPENDPACKAGE *ap = (APPENDPACKAGE *) data;
+  *flags = ap->flags;		/* get desired data from the package */
+  *date = ap->date;
+  *message = ap->message;
+  ap->message = NIL;		/* so next callback puts a stop to it */
+  return LONGT;			/* always return success */
+}
+
+
+/* Mail append message string
+ * Accepts: mail stream
+ *	    destination mailbox
+ *	    initial flags
+ *	    message internal date
+ *	    stringstruct of message to append
+ * Returns: T on success, NIL on failure
+ */
+
+long mail_append_full (MAILSTREAM *stream,char *mailbox,char *flags,char *date,
+		       STRING *message)
+{
+  APPENDPACKAGE ap;
+  ap.flags = flags;		/* load append package */
+  ap.date = date;
+  ap.message = message;
+  return mail_append_multiple (stream,mailbox,mail_append_single,(void *) &ap);
+}
+
+/* Mail append message(s)
+ * Accepts: mail stream
+ *	    destination mailbox
+ *	    append data callback
+ *	    arbitrary data for callback use
+ * Returns: T on success, NIL on failure
+ */
+
+long mail_append_multiple (MAILSTREAM *stream,char *mailbox,append_t af,
+			   void *data)
+{
+  char *s,tmp[MAILTMPLEN];
+  DRIVER *d = NIL;
+  long ret = NIL;
+				/* never allow names with newlines */
+  if (strpbrk (mailbox,"\015\012"))
+    MM_LOG ("Can't append to mailbox with such a name",ERROR);
+  else if (strlen (mailbox) >=
+	   (NETMAXHOST+(NETMAXUSER*2)+NETMAXMBX+NETMAXSRV+50)) {
+    sprintf (tmp,"Can't append %.80s: %s",mailbox,(*mailbox == '{') ?
+	     "invalid remote specification" : "no such mailbox");
+    MM_LOG (tmp,ERROR);
+  }
+				/* special driver hack? */
+  else if (!strncmp (lcase (strcpy (tmp,mailbox)),"#driver.",8)) {
+				/* yes, tie off name at likely delimiter */
+    if (!(s = strpbrk (tmp+8,"/\\:"))) {
+      sprintf (tmp,"Can't append to mailbox %.80s: bad driver syntax",mailbox);
+      MM_LOG (tmp,ERROR);
+      return NIL;
+    }
+    *s++ = '\0';		/* tie off at delimiter */
+    if (!(d = (DRIVER *) mail_parameters (NIL,GET_DRIVER,tmp+8))) {
+      sprintf (tmp,"Can't append to mailbox %.80s: unknown driver",mailbox);
+      MM_LOG (tmp,ERROR);
+    }
+    else ret = SAFE_APPEND (d,stream,mailbox + (s - tmp),af,data);
+  }
+  else if (d = mail_valid (stream,mailbox,NIL))
+    ret = SAFE_APPEND (d,stream,mailbox,af,data);
+  /* No driver, try for TRYCREATE if no stream.  Note that we use the
+   * createProto here, not the appendProto, since the dummy driver already
+   * took care of the appendProto case.  Otherwise, if appendProto is set to
+   * NIL, we won't get a TRYCREATE.
+   */
+  else if (!stream && (stream = default_proto (NIL)) && stream->dtb &&
+	   SAFE_APPEND (stream->dtb,stream,mailbox,af,data))
+				/* timing race? */
+    MM_NOTIFY (stream,"Append validity confusion",WARN);
+				/* generate error message */
+  else mail_valid (stream,mailbox,"append to mailbox");
+  return ret;
+}
+
+/* Mail garbage collect stream
+ * Accepts: mail stream
+ *	    garbage collection flags
+ */
+
+void mail_gc (MAILSTREAM *stream,long gcflags)
+{
+  MESSAGECACHE *elt;
+  unsigned long i;
+  				/* do the driver's action first */
+  if (stream->dtb && stream->dtb->gc) (*stream->dtb->gc) (stream,gcflags);
+  stream->msgno = 0;		/* nothing cached now */
+  if (gcflags & GC_ENV) {	/* garbage collect envelopes? */
+    if (stream->env) mail_free_envelope (&stream->env);
+    if (stream->body) mail_free_body (&stream->body);
+  }
+  if (gcflags & GC_TEXTS) {	/* free texts */
+    if (stream->text.data) fs_give ((void **) &stream->text.data);
+    stream->text.size = 0;
+  }
+				/* garbage collect per-message stuff */
+  for (i = 1; i <= stream->nmsgs; i++) 
+    if (elt = (MESSAGECACHE *) (*mailcache) (stream,i,CH_ELT))
+      mail_gc_msg (&elt->private.msg,gcflags);
+}
+
+
+/* Mail garbage collect message
+ * Accepts: message structure
+ *	    garbage collection flags
+ */
+
+void mail_gc_msg (MESSAGE *msg,long gcflags)
+{
+  if (gcflags & GC_ENV) {	/* garbage collect envelopes? */
+    mail_free_envelope (&msg->env);
+    mail_free_body (&msg->body);
+  }
+  if (gcflags & GC_TEXTS) {	/* garbage collect texts */
+    if (msg->full.text.data) fs_give ((void **) &msg->full.text.data);
+    if (msg->header.text.data) {
+      mail_free_stringlist (&msg->lines);
+      fs_give ((void **) &msg->header.text.data);
+    }
+    if (msg->text.text.data) fs_give ((void **) &msg->text.text.data);
+				/* now GC all body components */
+    if (msg->body) mail_gc_body (msg->body);
+  }
+}
+
+/* Mail garbage collect texts in BODY structure
+ * Accepts: BODY structure
+ */
+
+void mail_gc_body (BODY *body)
+{
+  PART *part;
+  switch (body->type) {		/* free contents */
+  case TYPEMULTIPART:		/* multiple part */
+    for (part = body->nested.part; part; part = part->next)
+      mail_gc_body (&part->body);
+    break;
+  case TYPEMESSAGE:		/* encapsulated message */
+    if (body->subtype && !strcmp (body->subtype,"RFC822")) {
+      mail_free_stringlist (&body->nested.msg->lines);
+      mail_gc_msg (body->nested.msg,GC_TEXTS);
+    }
+    break;
+  default:
+    break;
+  }
+  if (body->mime.text.data) fs_give ((void **) &body->mime.text.data);
+  if (body->contents.text.data) fs_give ((void **) &body->contents.text.data);
+}
+
+/* Mail get body part
+ * Accepts: mail stream
+ *	    message number
+ *	    section specifier
+ * Returns: pointer to body
+ */
+
+BODY *mail_body (MAILSTREAM *stream,unsigned long msgno,unsigned char *section)
+{
+  BODY *b = NIL;
+  PART *pt;
+  unsigned long i;
+				/* make sure have a body */
+  if (section && *section && mail_fetchstructure (stream,msgno,&b) && b)
+    while (*section) {		/* find desired section */
+      if (isdigit (*section)) {	/* get section specifier */
+				/* make sure what follows is valid */
+	if (!(i = strtoul (section,(char **) &section,10)) ||
+	    (*section && ((*section++ != '.') || !*section))) return NIL;
+				/* multipart content? */
+	if (b->type == TYPEMULTIPART) {
+				/* yes, find desired part */
+	  if (pt = b->nested.part) while (--i && (pt = pt->next));
+	  if (!pt) return NIL;	/* bad specifier */
+	  b = &pt->body;	/* note new body */
+	}
+				/* otherwise must be section 1 */
+	else if (i != 1) return NIL;
+				/* need to go down further? */
+	if (*section) switch (b->type) {
+	case TYPEMULTIPART:	/* multipart */
+	  break;
+	case TYPEMESSAGE:	/* embedded message */
+	  if (!strcmp (b->subtype,"RFC822")) {
+	    b = b->nested.msg->body;
+	    break;
+	  }
+	default:		/* bogus subpart specification */
+	  return NIL;
+	}
+      }
+      else return NIL;		/* unknown section specifier */
+    }
+  return b;
+}  
+
+/* Mail output date from elt fields
+ * Accepts: character string to write into
+ *	    elt to get data data from
+ * Returns: the character string
+ */
+
+const char *days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+
+const char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+			"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+
+char *mail_date (char *string,MESSAGECACHE *elt)
+{
+  sprintf (string,"%2d-%s-%d %02d:%02d:%02d %c%02d%02d",
+	   elt->day ? elt->day : 1,
+	   months[elt->month ? (elt->month - 1) : 0],
+	   elt->year + BASEYEAR,elt->hours,elt->minutes,elt->seconds,
+	   elt->zoccident ? '-' : '+',elt->zhours,elt->zminutes);
+  return string;
+}
+
+
+/* Mail output extended-ctime format date from elt fields
+ * Accepts: character string to write into
+ *	    elt to get data data from
+ * Returns: the character string
+ */
+
+char *mail_cdate (char *string,MESSAGECACHE *elt)
+{
+  char *fmt = "%s %s %2d %02d:%02d:%02d %4d %s%02d%02d\n";
+  int d = elt->day ? elt->day : 1;
+  int m = elt->month ? (elt->month - 1) : 0;
+  int y = elt->year + BASEYEAR;
+  const char *s = months[m];
+  if (m < 2) {			/* if before March, */
+    m += 10;			/* January = month 10 of previous year */
+    y--;
+  }
+  else m -= 2;			/* March is month 0 */
+  sprintf (string,fmt,days[(int) (d + 2 + ((7 + 31 * m) / 12)
+#ifndef USEJULIANCALENDAR
+#ifndef USEORTHODOXCALENDAR	/* Gregorian calendar */
+				  + (y / 400)
+#ifdef Y4KBUGFIX
+				  - (y / 4000)
+#endif
+#else				/* Orthodox calendar */
+				  + (2 * (y / 900)) + ((y % 900) >= 200)
+				  + ((y % 900) >= 600)
+#endif
+				  - (y / 100)
+#endif
+				  + y + (y / 4)) % 7],
+	   s,d,elt->hours,elt->minutes,elt->seconds,elt->year + BASEYEAR,
+	   elt->zoccident ? "-" : "+",elt->zhours,elt->zminutes);
+  return string;
+}
+
+/* Mail parse date into elt fields
+ * Accepts: elt to write into
+ *	    date string to parse
+ * Returns: T if parse successful, else NIL 
+ * This routine parses dates as follows:
+ * . leading three alphas followed by comma and space are ignored
+ * . date accepted in format: mm/dd/yy, mm/dd/yyyy, dd-mmm-yy, dd-mmm-yyyy,
+ *    dd mmm yy, dd mmm yyyy, yyyy-mm-dd, yyyymmdd
+ * . two and three digit years interpreted according to RFC 2822 rules
+ * . mandatory end of string if yyyy-mm-dd or yyyymmdd; otherwise optional
+ *    space followed by time:
+ * . time accepted in format hh:mm:ss or hh:mm
+ * . end of string accepted
+ * . timezone accepted: hyphen followed by symbolic timezone, or space
+ *    followed by signed numeric timezone or symbolic timezone
+ * Examples of normal input:
+ * . IMAP date-only (SEARCH):
+ *    dd-mmm-yyyy
+ * . IMAP date-time (INTERNALDATE):
+ *    dd-mmm-yyyy hh:mm:ss +zzzz
+ * . RFC-822:
+ *    www, dd mmm yy hh:mm:ss zzz
+ * . RFC-2822:
+ *    www, dd mmm yyyy hh:mm:ss +zzzz
+ */
+
+long mail_parse_date (MESSAGECACHE *elt,unsigned char *s)
+{
+  unsigned long d,m,y;
+  int mi,ms;
+  struct tm *t;
+  time_t tn;
+  char tmp[MAILTMPLEN];
+  static unsigned long maxyear = 0;
+  if (!maxyear) {		/* know the end of time yet? */
+    MESSAGECACHE tmpelt;
+    memset (&tmpelt,0xff,sizeof (MESSAGECACHE));
+    maxyear = BASEYEAR + tmpelt.year;
+  }
+				/* clear elt */
+  elt->zoccident = elt->zhours = elt->zminutes =
+    elt->hours = elt->minutes = elt->seconds =
+      elt->day = elt->month = elt->year = 0;
+				/* make a writeable uppercase copy */
+  if (s && *s && (strlen (s) < (size_t)MAILTMPLEN)) s = ucase (strcpy (tmp,s));
+  else return NIL;
+				/* skip over possible day of week */
+  if (isalpha (*s) && isalpha (s[1]) && isalpha (s[2]) && (s[3] == ',') &&
+      (s[4] == ' ')) s += 5;
+  while (*s == ' ') s++;	/* parse first number (probable month) */
+  if (!(m = strtoul (s,(char **) &s,10))) return NIL;
+
+  switch (*s) {			/* different parse based on delimiter */
+  case '/':			/* mm/dd/yy format */
+    if (isdigit (*++s) && (d = strtoul (s,(char **) &s,10)) &&
+	(*s == '/') && isdigit (*++s)) {
+      y = strtoul (s,(char **) &s,10);
+      if (*s == '\0') break;	/* must end here */
+    }
+    return NIL;			/* bogon */
+  case ' ':			/* dd mmm yy format */
+    while (s[1] == ' ') s++;	/* slurp extra whitespace */
+  case '-':
+    if (isdigit (s[1])) {	/* possible ISO 8601 date format? */
+      y = m;			/* yes, first number is year */
+				/* get month and day */
+      if ((m = strtoul (s+1,(char **) &s,10)) && (*s++ == '-') && 
+	  (d = strtoul (s,(char **) &s,10)) && !*s) break;
+      return NIL;		/* syntax error or time present */
+    }
+    d = m;			/* dd-mmm-yy[yy], so first number is a day */
+				/* make sure string long enough! */
+    if (strlen (s) < (size_t) 5) return NIL;
+    /* Some compilers don't allow `<<' and/or longs in case statements. */
+				/* slurp up the month string */
+    ms = ((s[1] - 'A') * 1024) + ((s[2] - 'A') * 32) + (s[3] - 'A');
+    switch (ms) {		/* determine the month */
+    case (('J'-'A') * 1024) + (('A'-'A') * 32) + ('N'-'A'): m = 1; break;
+    case (('F'-'A') * 1024) + (('E'-'A') * 32) + ('B'-'A'): m = 2; break;
+    case (('M'-'A') * 1024) + (('A'-'A') * 32) + ('R'-'A'): m = 3; break;
+    case (('A'-'A') * 1024) + (('P'-'A') * 32) + ('R'-'A'): m = 4; break;
+    case (('M'-'A') * 1024) + (('A'-'A') * 32) + ('Y'-'A'): m = 5; break;
+    case (('J'-'A') * 1024) + (('U'-'A') * 32) + ('N'-'A'): m = 6; break;
+    case (('J'-'A') * 1024) + (('U'-'A') * 32) + ('L'-'A'): m = 7; break;
+    case (('A'-'A') * 1024) + (('U'-'A') * 32) + ('G'-'A'): m = 8; break;
+    case (('S'-'A') * 1024) + (('E'-'A') * 32) + ('P'-'A'): m = 9; break;
+    case (('O'-'A') * 1024) + (('C'-'A') * 32) + ('T'-'A'): m = 10; break;
+    case (('N'-'A') * 1024) + (('O'-'A') * 32) + ('V'-'A'): m = 11; break;
+    case (('D'-'A') * 1024) + (('E'-'A') * 32) + ('C'-'A'): m = 12; break;
+    default: return NIL;	/* unknown month */
+    }
+    if (s[4] == *s) s += 5;	/* advance to year */
+    else {			/* first three were OK, possibly full name */
+      mi = *s;			/* note delimiter, skip alphas */
+      for (s += 4; isalpha (*s); s++);
+				/* error if delimiter not here */
+      if (mi != *s++) return NIL;
+    }
+    while (*s == ' ') s++;	/* parse year */
+    if (isdigit (*s)) {		/* must be a digit here */
+      y = strtoul (s,(char **) &s,10);
+      if (*s == '\0' || *s == ' ') break;
+    }
+  case '\0':			/* ISO 8601 compact date */
+    if (m < (BASEYEAR * 10000)) return NIL;
+    y = m / 10000;		/* get year */
+    d = (m %= 10000) % 100;	/* get day */
+    m /= 100;			/* and month */
+    break;
+  default:
+    return NIL;			/* unknown date format */
+  }
+
+				/* minimal validity check of date */
+  if ((d > 31) || (m > 12)) return NIL; 
+  if (y < 49) y += 2000;	/* RFC 2282 rules for two digit years 00-49 */
+  else if (y < 999) y += 1900;	/* 2-digit years 50-99 and 3-digit years */
+				/* reject prehistoric and far future years */
+  if ((y < BASEYEAR) || (y > maxyear)) return NIL;
+				/* set values in elt */
+  elt->day = d; elt->month = m; elt->year = y - BASEYEAR;
+  ms = '\0';			/* initially no time zone string */
+  if (*s) {			/* time specification present? */
+				/* parse time */
+    d = strtoul (s+1,(char **) &s,10);
+    if (*s != ':') return NIL;
+    m = strtoul (++s,(char **) &s,10);
+    y = (*s == ':') ? strtoul (++s,(char **) &s,10) : 0;
+				/* validity check time */
+    if ((d > 23) || (m > 59) || (y > 60)) return NIL; 
+				/* set values in elt */
+    elt->hours = d; elt->minutes = m; elt->seconds = y;
+    switch (*s) {		/* time zone specifier? */
+    case ' ':			/* numeric time zone */
+      while (s[1] == ' ') s++;	/* slurp extra whitespace */
+      if (!isalpha (s[1])) {	/* treat as '-' case if alphabetic */
+				/* test for sign character */
+	if ((elt->zoccident = (*++s == '-')) || (*s == '+')) s++;
+				/* validate proper timezone */
+	if (isdigit(*s) && isdigit(s[1]) && isdigit(s[2]) && (s[2] < '6') &&
+	    isdigit(s[3])) {
+	  elt->zhours = (*s - '0') * 10 + (s[1] - '0');
+	  elt->zminutes = (s[2] - '0') * 10 + (s[3] - '0');
+	}
+	return T;		/* all done! */
+      }
+				/* falls through */
+    case '-':			/* symbolic time zone */
+      if (!(ms = *++s)) ms = 'Z';
+      else if (*++s) {		/* multi-character? */
+	ms -= 'A'; ms *= 1024;	/* yes, make compressed three-byte form */
+	ms += ((*s++ - 'A') * 32);
+	if (*s) ms += *s++ - 'A';
+	if (*s) ms = '\0';	/* more than three characters */
+      }
+    default:			/* ignore anything else */
+      break;
+    }
+  }
+
+  /*  This is not intended to be a comprehensive list of all possible
+   * timezone strings.  Such a list would be impractical.  Rather, this
+   * listing is intended to incorporate all military, North American, and
+   * a few special cases such as Japan and the major European zone names,
+   * such as what might be expected to be found in a Tenex format mailbox
+   * and spewed from an IMAP server.  The trend is to migrate to numeric
+   * timezones which lack the flavor but also the ambiguity of the names.
+   *
+   *  RFC-822 only recognizes UT, GMT, 1-letter military timezones, and the
+   * 4 CONUS timezones and their summer time variants.  [Sorry, Canadian
+   * Atlantic Provinces, Alaska, and Hawaii.]
+   */
+  switch (ms) {			/* determine the timezone */
+				/* Universal */
+  case (('U'-'A')*1024)+(('T'-'A')*32):
+#ifndef STRICT_RFC822_TIMEZONES
+  case (('U'-'A')*1024)+(('T'-'A')*32)+'C'-'A':
+#endif
+				/* Greenwich */
+  case (('G'-'A')*1024)+(('M'-'A')*32)+'T'-'A':
+  case 'Z': elt->zhours = 0; break;
+
+    /* oriental (from Greenwich) timezones */
+#ifndef STRICT_RFC822_TIMEZONES
+				/* Middle Europe */
+  case (('M'-'A')*1024)+(('E'-'A')*32)+'T'-'A':
+#endif
+#ifdef BRITISH_SUMMER_TIME
+				/* British Summer */
+  case (('B'-'A')*1024)+(('S'-'A')*32)+'T'-'A':
+#endif
+  case 'A': elt->zhours = 1; break;
+#ifndef STRICT_RFC822_TIMEZONES
+				/* Eastern Europe */
+  case (('E'-'A')*1024)+(('E'-'A')*32)+'T'-'A':
+#endif
+  case 'B': elt->zhours = 2; break;
+  case 'C': elt->zhours = 3; break;
+  case 'D': elt->zhours = 4; break;
+  case 'E': elt->zhours = 5; break;
+  case 'F': elt->zhours = 6; break;
+  case 'G': elt->zhours = 7; break;
+  case 'H': elt->zhours = 8; break;
+#ifndef STRICT_RFC822_TIMEZONES
+				/* Japan */
+  case (('J'-'A')*1024)+(('S'-'A')*32)+'T'-'A':
+#endif
+  case 'I': elt->zhours = 9; break;
+  case 'K': elt->zhours = 10; break;
+  case 'L': elt->zhours = 11; break;
+  case 'M': elt->zhours = 12; break;
+
+	/* occidental (from Greenwich) timezones */
+  case 'N': elt->zoccident = 1; elt->zhours = 1; break;
+  case 'O': elt->zoccident = 1; elt->zhours = 2; break;
+#ifndef STRICT_RFC822_TIMEZONES
+  case (('A'-'A')*1024)+(('D'-'A')*32)+'T'-'A':
+#endif
+  case 'P': elt->zoccident = 1; elt->zhours = 3; break;
+#ifdef NEWFOUNDLAND_STANDARD_TIME
+				/* Newfoundland */
+  case (('N'-'A')*1024)+(('S'-'A')*32)+'T'-'A':
+    elt->zoccident = 1; elt->zhours = 3; elt->zminutes = 30; break;
+#endif
+#ifndef STRICT_RFC822_TIMEZONES
+				/* Atlantic */
+  case (('A'-'A')*1024)+(('S'-'A')*32)+'T'-'A':
+#endif
+	/* CONUS */
+  case (('E'-'A')*1024)+(('D'-'A')*32)+'T'-'A':
+  case 'Q': elt->zoccident = 1; elt->zhours = 4; break;
+				/* Eastern */
+  case (('E'-'A')*1024)+(('S'-'A')*32)+'T'-'A':
+  case (('C'-'A')*1024)+(('D'-'A')*32)+'T'-'A':
+  case 'R': elt->zoccident = 1; elt->zhours = 5; break;
+				/* Central */
+  case (('C'-'A')*1024)+(('S'-'A')*32)+'T'-'A':
+  case (('M'-'A')*1024)+(('D'-'A')*32)+'T'-'A':
+  case 'S': elt->zoccident = 1; elt->zhours = 6; break;
+				/* Mountain */
+  case (('M'-'A')*1024)+(('S'-'A')*32)+'T'-'A':
+  case (('P'-'A')*1024)+(('D'-'A')*32)+'T'-'A':
+  case 'T': elt->zoccident = 1; elt->zhours = 7; break;
+				/* Pacific */
+  case (('P'-'A')*1024)+(('S'-'A')*32)+'T'-'A':
+#ifndef STRICT_RFC822_TIMEZONES
+  case (('Y'-'A')*1024)+(('D'-'A')*32)+'T'-'A':
+#endif
+  case 'U': elt->zoccident = 1; elt->zhours = 8; break;
+#ifndef STRICT_RFC822_TIMEZONES
+				/* Yukon */
+  case (('Y'-'A')*1024)+(('S'-'A')*32)+'T'-'A':
+#endif
+  case 'V': elt->zoccident = 1; elt->zhours = 9; break;
+#ifndef STRICT_RFC822_TIMEZONES
+				/* Hawaii */
+  case (('H'-'A')*1024)+(('S'-'A')*32)+'T'-'A':
+#endif
+  case 'W': elt->zoccident = 1; elt->zhours = 10; break;
+				/* Nome/Bering/Samoa */
+#ifdef NOME_STANDARD_TIME
+  case (('N'-'A')*1024)+(('S'-'A')*32)+'T'-'A':
+#endif
+#ifdef BERING_STANDARD_TIME
+  case (('B'-'A')*1024)+(('S'-'A')*32)+'T'-'A':
+#endif
+#ifdef SAMOA_STANDARD_TIME
+  case (('S'-'A')*1024)+(('S'-'A')*32)+'T'-'A':
+#endif
+  case 'X': elt->zoccident = 1; elt->zhours = 11; break;
+  case 'Y': elt->zoccident = 1; elt->zhours = 12; break;
+
+  default:			/* unknown time zones treated as local */
+    tn = time (0);		/* time now... */
+    t = localtime (&tn);	/* get local minutes since midnight */
+    mi = t->tm_hour * 60 + t->tm_min;
+    ms = t->tm_yday;		/* note Julian day */
+    if (t = gmtime (&tn)) {	/* minus UTC minutes since midnight */
+      mi -= t->tm_hour * 60 + t->tm_min;
+	/* ms can be one of:
+	 *  36x  local time is December 31, UTC is January 1, offset -24 hours
+	 *    1  local time is 1 day ahead of UTC, offset +24 hours
+	 *    0  local time is same day as UTC, no offset
+	 *   -1  local time is 1 day behind UTC, offset -24 hours
+	 * -36x  local time is January 1, UTC is December 31, offset +24 hours
+	 */
+      if (ms -= t->tm_yday)	/* correct offset if different Julian day */
+	mi += ((ms < 0) == (abs (ms) == 1)) ? -24*60 : 24*60;
+      if (mi < 0) {		/* occidental? */
+	mi = abs (mi);		/* yup, make positive number */
+	elt->zoccident = 1;	/* and note west of UTC */
+      }
+      elt->zhours = mi / 60;	/* now break into hours and minutes */
+      elt->zminutes = mi % 60;
+    }
+    break;
+  }
+  return T;
+}
+
+/* Mail n messages exist
+ * Accepts: mail stream
+ *	    number of messages
+ */
+
+void mail_exists (MAILSTREAM *stream,unsigned long nmsgs)
+{
+  char tmp[MAILTMPLEN];
+  if (nmsgs > MAXMESSAGES) {
+    sprintf (tmp,"Mailbox has more messages (%lu) exist than maximum (%lu)",
+	     nmsgs,MAXMESSAGES);
+    mm_log (tmp,ERROR);
+    nmsgs = MAXMESSAGES;	/* cap to maximum */
+    /* probably will crash in mail_elt() soon enough... */
+  }
+				/* make sure cache is large enough */
+  (*mailcache) (stream,nmsgs,CH_SIZE);
+  stream->nmsgs = nmsgs;	/* update stream status */
+				/* notify main program of change */
+  if (!stream->silent) MM_EXISTS (stream,nmsgs);
+}
+
+
+/* Mail n messages are recent
+ * Accepts: mail stream
+ *	    number of recent messages
+ */
+
+void mail_recent (MAILSTREAM *stream,unsigned long recent)
+{
+  char tmp[MAILTMPLEN];
+  if (recent <= stream->nmsgs) stream->recent = recent;
+  else {
+    sprintf (tmp,"Non-existent recent message(s) %lu, nmsgs=%lu",
+	     recent,stream->nmsgs);
+    mm_log (tmp,ERROR);
+  }
+}
+
+
+/* Mail message n is expunged
+ * Accepts: mail stream
+ *	    message #
+ */
+
+void mail_expunged (MAILSTREAM *stream,unsigned long msgno)
+{
+  char tmp[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  if (msgno > stream->nmsgs) {
+    sprintf (tmp,"Expunge of non-existent message %lu, nmsgs=%lu",
+	     msgno,stream->nmsgs);
+    mm_log (tmp,ERROR);
+  }
+  else {
+    elt = (MESSAGECACHE *) (*mailcache) (stream,msgno,CH_ELT);
+				/* notify main program of change */
+    if (!stream->silent) MM_EXPUNGED (stream,msgno);
+    if (elt) {			/* if an element is there */
+      elt->msgno = 0;		/* invalidate its message number and free */
+      (*mailcache) (stream,msgno,CH_FREE);
+      (*mailcache) (stream,msgno,CH_FREESORTCACHE);
+    }
+				/* expunge the slot */
+    (*mailcache) (stream,msgno,CH_EXPUNGE);
+    --stream->nmsgs;		/* update stream status */
+    if (stream->msgno) {	/* have stream pointers? */
+				/* make sure the short cache is nuked */
+      if (stream->scache) mail_gc (stream,GC_ENV | GC_TEXTS);
+      else stream->msgno = 0;	/* make sure invalidated in any case */
+    }
+  }
+}
+
+/* Mail stream status routines */
+
+
+/* Mail lock stream
+ * Accepts: mail stream
+ */
+
+void mail_lock (MAILSTREAM *stream)
+{
+  if (stream->lock) {
+    char tmp[MAILTMPLEN];
+    sprintf (tmp,"Lock when already locked, mbx=%.80s",
+	     stream->mailbox ? stream->mailbox : "???");
+    fatal (tmp);
+  }
+  else stream->lock = T;	/* lock stream */
+}
+
+
+/* Mail unlock stream
+ * Accepts: mail stream
+ */
+ 
+void mail_unlock (MAILSTREAM *stream)
+{
+  if (!stream->lock) fatal ("Unlock when not locked");
+  else stream->lock = NIL;	/* unlock stream */
+}
+
+
+/* Mail turn on debugging telemetry
+ * Accepts: mail stream
+ */
+
+void mail_debug (MAILSTREAM *stream)
+{
+  stream->debug = T;		/* turn on debugging telemetry */
+  if (stream->dtb) (*stream->dtb->parameters) (ENABLE_DEBUG,stream);
+}
+
+
+/* Mail turn off debugging telemetry
+ * Accepts: mail stream
+ */
+
+void mail_nodebug (MAILSTREAM *stream)
+{
+  stream->debug = NIL;		/* turn off debugging telemetry */
+  if (stream->dtb) (*stream->dtb->parameters) (DISABLE_DEBUG,stream);
+}
+
+
+/* Mail log to debugging telemetry
+ * Accepts: message
+ *	    flag that data is "sensitive"
+ */
+
+void mail_dlog (char *string,long flag)
+{
+  mm_dlog ((debugsensitive || !flag) ? string : "<suppressed>");
+}
+
+/* Mail parse UID sequence
+ * Accepts: mail stream
+ *	    sequence to parse
+ * Returns: T if parse successful, else NIL
+ */
+
+long mail_uid_sequence (MAILSTREAM *stream,unsigned char *sequence)
+{
+  unsigned long i,j,k,x,y;
+  for (i = 1; i <= stream->nmsgs; i++) mail_elt (stream,i)->sequence = NIL;
+  while (sequence && *sequence){/* while there is something to parse */
+    if (*sequence == '*') {	/* maximum message */
+      i = stream->nmsgs ? mail_uid (stream,stream->nmsgs) : stream->uid_last;
+      sequence++;		/* skip past * */
+    }
+				/* parse and validate message number */
+				/* parse and validate message number */
+    else if (!isdigit (*sequence)) {
+      MM_LOG ("Syntax error in sequence",ERROR);
+      return NIL;
+    }
+    else if (!(i = strtoul (sequence,(char **) &sequence,10))) {
+      MM_LOG ("UID may not be zero",ERROR);
+      return NIL;
+    }
+    switch (*sequence) {	/* see what the delimiter is */
+    case ':':			/* sequence range */
+      if (*++sequence == '*') {	/* maximum message */
+	j = stream->nmsgs ? mail_uid (stream,stream->nmsgs) : stream->uid_last;
+	sequence++;		/* skip past * */
+      }
+				/* parse end of range */
+      else if (!(j = strtoul (sequence,(char **) &sequence,10))) {
+	MM_LOG ("UID sequence range invalid",ERROR);
+	return NIL;
+      }
+      if (*sequence && *sequence++ != ',') {
+	MM_LOG ("UID sequence range syntax error",ERROR);
+	return NIL;
+      }
+      if (i > j) {		/* swap the range if backwards */
+	x = i; i = j; j = x;
+      }
+      x = mail_msgno (stream,i);/* get msgnos */
+      y = mail_msgno (stream,j);/* for both UIDS (don't && it) */
+				/* easy if both UIDs valid */
+      if (x && y) while (x <= y) mail_elt (stream,x++)->sequence = T;
+				/* start UID valid, end is not */
+      else if (x) while ((x <= stream->nmsgs) && (mail_uid (stream,x) <= j))
+	mail_elt (stream,x++)->sequence = T;
+				/* end UID valid, start is not */
+      else if (y) for (x = 1; x <= y; x++) {
+	if (mail_uid (stream,x) >= i) mail_elt (stream,x)->sequence = T;
+      }
+				/* neither is valid, ugh */
+      else for (x = 1; x <= stream->nmsgs; x++)
+	if (((k = mail_uid (stream,x)) >= i) && (k <= j))
+	  mail_elt (stream,x)->sequence = T;
+      break;
+    case ',':			/* single message */
+      ++sequence;		/* skip the delimiter, fall into end case */
+    case '\0':			/* end of sequence, mark this message */
+      if (x = mail_msgno (stream,i)) mail_elt (stream,x)->sequence = T;
+      break;
+    default:			/* anything else is a syntax error! */
+      MM_LOG ("UID sequence syntax error",ERROR);
+      return NIL;
+    }
+  }
+  return T;			/* successfully parsed sequence */
+}
+
+/* Mail see if line list matches that in cache
+ * Accepts: candidate line list
+ *	    cached line list
+ *	    matching flags
+ * Returns: T if match, NIL if no match
+ */
+
+long mail_match_lines (STRINGLIST *lines,STRINGLIST *msglines,long flags)
+{
+  unsigned long i;
+  unsigned char *s,*t;
+  STRINGLIST *m;
+  if (!msglines) return T;	/* full header is in cache */
+				/* need full header but filtered in cache */
+  if ((flags & FT_NOT) || !lines) return NIL;
+  do {				/* make sure all present & accounted for */
+    for (m = msglines; m; m = m->next) if (lines->text.size == m->text.size) {
+      for (s = lines->text.data,t = m->text.data,i = lines->text.size;
+	   i && !compare_uchar (*s,*t); s++,t++,i--);
+      if (!i) break;		/* this line matches */
+    }
+    if (!m) return NIL;		/* didn't find in the list */
+  }
+  while (lines = lines->next);
+  return T;			/* all lines found */
+}
+
+/* Mail filter text by header lines
+ * Accepts: text to filter, with trailing null
+ *	    length of text
+ *	    list of lines
+ *	    fetch flags
+ * Returns: new text size, text overwritten
+ */
+
+unsigned long mail_filter (char *text,unsigned long len,STRINGLIST *lines,
+			   long flags)
+{
+  STRINGLIST *hdrs;
+  int notfound;
+  unsigned long i;
+  char c,*s,*e,*t,tmp[MAILTMPLEN];
+  char *src = text;
+  char *dst = src;
+  char *end = text + len;
+  text[len] = '\012';		/* guard against running off buffer */
+  while (src < end) {		/* process header */
+				/* slurp header line name */
+    for (s = src,e = s + MAILTMPLEN - 1,e = (e < end ? e : end),t = tmp;
+	 (s < e) && ((c = (*s ? *s : (*s = ' '))) != ':') &&
+	 ((c > ' ') ||
+	  ((c != ' ') && (c != '\t') && (c != '\015') && (c != '\012')));
+	 *t++ = *s++);
+    *t = '\0';			/* tie off */
+    notfound = T;		/* not found yet */
+    if (i = t - tmp)		/* see if found in header */
+      for (hdrs = lines; hdrs && notfound; hdrs = hdrs->next)
+	if ((hdrs->text.size == i) && !compare_csizedtext (tmp,&hdrs->text))
+	  notfound = NIL;
+				/* skip header line if not wanted */
+    if (i && ((flags & FT_NOT) ? !notfound : notfound))
+      while (((*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012') &&
+	      (*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012') &&
+	      (*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012') &&
+	      (*src++ != '\012')) || ((*src == ' ') || (*src == '\t')));
+    else if (src == dst) {	/* copy to self */
+      while (((*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012') &&
+	      (*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012') &&
+	      (*src++ != '\012') && (*src++ != '\012') && (*src++ != '\012') &&
+	      (*src++ != '\012')) || ((*src == ' ') || (*src == '\t')));
+      dst = src;		/* update destination */
+    }
+    else {			/* copy line and any continuation line */
+      while ((((*dst++ = *src++) != '\012') && ((*dst++ = *src++) != '\012') &&
+	      ((*dst++ = *src++) != '\012') && ((*dst++ = *src++) != '\012') &&
+	      ((*dst++ = *src++) != '\012') && ((*dst++ = *src++) != '\012') &&
+	      ((*dst++ = *src++) != '\012') && ((*dst++ = *src++) != '\012') &&
+	      ((*dst++ = *src++) != '\012') && ((*dst++ = *src++) != '\012'))||
+	     ((*src == ' ') || (*src == '\t')));
+				/* in case hit the guard LF */
+      if (src > end) dst -= (src - end);
+    }
+  }
+  *dst = '\0';			/* tie off destination */
+  return dst - text;
+}
+
+/* Local mail search message
+ * Accepts: MAIL stream
+ *	    message number
+ *	    optional section specification
+ *	    search program
+ * Returns: T if found, NIL otherwise
+ */
+
+long mail_search_msg (MAILSTREAM *stream,unsigned long msgno,char *section,
+		      SEARCHPGM *pgm)
+{
+  unsigned short d;
+  char tmp[MAILTMPLEN];
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  SEARCHHEADER *hdr;
+  SEARCHOR *or;
+  SEARCHPGMLIST *not;
+  unsigned long now = (unsigned long) time (0);
+  if (pgm->msgno || pgm->uid) {	/* message set searches */
+    SEARCHSET *set;
+				/* message sequences */
+    if (pgm->msgno) {		/* inside this message sequence set */
+      for (set = pgm->msgno; set; set = set->next)
+	if (set->last ? ((set->first <= set->last) ?
+			 ((msgno >= set->first) && (msgno <= set->last)) :
+			 ((msgno >= set->last) && (msgno <= set->first))) :
+	    msgno == set->first) break;
+      if (!set) return NIL;	/* not found within sequence */
+    }
+    if (pgm->uid) {		/* inside this unique identifier set */
+      unsigned long uid = mail_uid (stream,msgno);
+      for (set = pgm->uid; set; set = set->next)
+	if (set->last ? ((set->first <= set->last) ?
+			 ((uid >= set->first) && (uid <= set->last)) :
+			 ((uid >= set->last) && (uid <= set->first))) :
+	    uid == set->first) break;
+      if (!set) return NIL;	/* not found within sequence */
+    }
+  }
+
+  /* Fast data searches */
+				/* need to fetch fast data? */
+  if ((!elt->rfc822_size && (pgm->larger || pgm->smaller)) ||
+      (!elt->year && (pgm->before || pgm->on || pgm->since ||
+		      pgm->older || pgm->younger)) ||
+      (!elt->valid && (pgm->answered || pgm->unanswered ||
+		       pgm->deleted || pgm->undeleted ||
+		       pgm->draft || pgm->undraft ||
+		       pgm->flagged || pgm->unflagged ||
+		       pgm->recent || pgm->old ||
+		       pgm->seen || pgm->unseen ||
+		       pgm->keyword || pgm->unkeyword))) {
+    unsigned long i;
+    MESSAGECACHE *ielt;
+    for (i = elt->msgno;	/* find last unloaded message in range */
+	 (i < stream->nmsgs) && (ielt = mail_elt (stream,i+1)) &&
+	   ((!ielt->rfc822_size && (pgm->larger || pgm->smaller)) ||
+	    (!ielt->year && (pgm->before || pgm->on || pgm->since ||
+			     pgm->older || pgm->younger)) ||
+	    (!ielt->valid && (pgm->answered || pgm->unanswered ||
+			      pgm->deleted || pgm->undeleted ||
+			      pgm->draft || pgm->undraft ||
+			      pgm->flagged || pgm->unflagged ||
+			      pgm->recent || pgm->old ||
+			      pgm->seen || pgm->unseen ||
+			      pgm->keyword || pgm->unkeyword))); ++i);
+    if (i == elt->msgno) sprintf (tmp,"%lu",elt->msgno);
+    else sprintf (tmp,"%lu:%lu",elt->msgno,i);
+    mail_fetch_fast (stream,tmp,NIL);
+  }
+				/* size ranges */
+  if ((pgm->larger && (elt->rfc822_size <= pgm->larger)) ||
+      (pgm->smaller && (elt->rfc822_size >= pgm->smaller))) return NIL;
+				/* message flags */
+  if ((pgm->answered && !elt->answered) ||
+      (pgm->unanswered && elt->answered) ||
+      (pgm->deleted && !elt->deleted) ||
+      (pgm->undeleted && elt->deleted) ||
+      (pgm->draft && !elt->draft) ||
+      (pgm->undraft && elt->draft) ||
+      (pgm->flagged && !elt->flagged) ||
+      (pgm->unflagged && elt->flagged) ||
+      (pgm->recent && !elt->recent) ||
+      (pgm->old && elt->recent) ||
+      (pgm->seen && !elt->seen) ||
+      (pgm->unseen && elt->seen)) return NIL;
+				/* keywords */
+  if ((pgm->keyword && !mail_search_keyword (stream,elt,pgm->keyword,LONGT)) ||
+      (pgm->unkeyword && !mail_search_keyword (stream,elt,pgm->unkeyword,NIL)))
+    return NIL;
+				/* internal date ranges */
+  if (pgm->before || pgm->on || pgm->since) {
+    d = mail_shortdate (elt->year,elt->month,elt->day);
+    if (pgm->before && (d >= pgm->before)) return NIL;
+    if (pgm->on && (d != pgm->on)) return NIL;
+    if (pgm->since && (d < pgm->since)) return NIL;
+  }
+  if (pgm->older || pgm->younger) {
+    unsigned long msgd = mail_longdate (elt);
+    if (pgm->older && msgd > (now - pgm->older)) return NIL;
+    if (pgm->younger && msgd < (now - pgm->younger)) return NIL;
+  }
+
+				/* envelope searches */
+  if (pgm->sentbefore || pgm->senton || pgm->sentsince ||
+      pgm->bcc || pgm->cc || pgm->from || pgm->to || pgm->subject ||
+      pgm->return_path || pgm->sender || pgm->reply_to || pgm->in_reply_to ||
+      pgm->message_id || pgm->newsgroups || pgm->followup_to ||
+      pgm->references) {
+    ENVELOPE *env;
+    MESSAGECACHE delt;
+    if (section) {		/* use body part envelope */
+      BODY *body = mail_body (stream,msgno,section);
+      env = (body && (body->type == TYPEMESSAGE) && body->subtype &&
+	     !strcmp (body->subtype,"RFC822")) ? body->nested.msg->env : NIL;
+    }
+    else {			/* use top level envelope if no section */
+      if (pgm->header && !stream->scache && !(stream->dtb->flags & DR_LOCAL))
+	mail_fetch_header(stream,msgno,NIL,NIL,NIL,FT_PEEK|FT_SEARCHLOOKAHEAD);
+      env = mail_fetchenvelope (stream,msgno);
+    }
+    if (!env) return NIL;	/* no envelope obtained */
+				/* sent date ranges */
+    if ((pgm->sentbefore || pgm->senton || pgm->sentsince) &&
+	(!mail_parse_date (&delt,env->date) ||
+	 !(d = mail_shortdate (delt.year,delt.month,delt.day)) ||
+	 (pgm->sentbefore && (d >= pgm->sentbefore)) ||
+	 (pgm->senton && (d != pgm->senton)) ||
+	 (pgm->sentsince && (d < pgm->sentsince)))) return NIL;
+				/* search headers */
+    if ((pgm->bcc && !mail_search_addr (env->bcc,pgm->bcc)) ||
+	(pgm->cc && !mail_search_addr (env->cc,pgm->cc)) ||
+	(pgm->from && !mail_search_addr (env->from,pgm->from)) ||
+	(pgm->to && !mail_search_addr (env->to,pgm->to)) ||
+	(pgm->subject && !mail_search_header_text (env->subject,pgm->subject)))
+      return NIL;
+    /* These criteria are not supported by IMAP and have to be emulated */
+    if ((pgm->return_path &&
+	 !mail_search_addr (env->return_path,pgm->return_path)) ||
+	(pgm->sender && !mail_search_addr (env->sender,pgm->sender)) ||
+	(pgm->reply_to && !mail_search_addr (env->reply_to,pgm->reply_to)) ||
+	(pgm->in_reply_to &&
+	 !mail_search_header_text (env->in_reply_to,pgm->in_reply_to)) ||
+	(pgm->message_id &&
+	!mail_search_header_text (env->message_id,pgm->message_id)) ||
+	(pgm->newsgroups &&
+	 !mail_search_header_text (env->newsgroups,pgm->newsgroups)) ||
+	(pgm->followup_to &&
+	 !mail_search_header_text (env->followup_to,pgm->followup_to)) ||
+	(pgm->references &&
+	 !mail_search_header_text (env->references,pgm->references)))
+      return NIL;
+  }
+
+				/* search header lines */
+  for (hdr = pgm->header; hdr; hdr = hdr->next) {
+    char *t,*e,*v;
+    SIZEDTEXT s;
+    STRINGLIST sth,stc;
+    sth.next = stc.next = NIL;	/* only one at a time */
+    sth.text.data = hdr->line.data;
+    sth.text.size = hdr->line.size;
+				/* get the header text */
+    if ((t = mail_fetch_header (stream,msgno,NIL,&sth,&s.size,
+				FT_INTERNAL | FT_PEEK |
+				(section ? NIL : FT_SEARCHLOOKAHEAD))) &&
+	strchr (t,':')) {
+      if (hdr->text.size) {	/* anything matches empty search string */
+				/* non-empty, copy field data */
+	s.data = (unsigned char *) fs_get (s.size + 1);
+				/* for each line */
+	for (v = (char *) s.data, e = t + s.size; t < e;) switch (*t) {
+	default:		/* non-continuation, skip leading field name */
+	  while ((t < e) && (*t++ != ':'));
+	  if ((t < e) && (*t == ':')) t++;
+	case '\t': case ' ':	/* copy field data  */
+	  while ((t < e) && (*t != '\015') && (*t != '\012')) *v++ = *t++;
+	  *v++ = '\n';		/* tie off line */
+	  while (((*t == '\015') || (*t == '\012')) && (t < e)) t++;
+	}
+				/* calculate true size */
+	s.size = v - (char *) s.data;
+	*v = '\0';		/* tie off results */
+	stc.text.data = hdr->text.data;
+	stc.text.size = hdr->text.size;
+				/* search header */
+	if (mail_search_header (&s,&stc)) fs_give ((void **) &s.data);
+	else {			/* search failed */
+	  fs_give ((void **) &s.data);
+	  return NIL;
+	}
+      }
+    }
+    else return NIL;		/* no matching header text */
+  }
+				/* search strings */
+  if ((pgm->text && !mail_search_text (stream,msgno,section,pgm->text,LONGT))||
+      (pgm->body && !mail_search_text (stream,msgno,section,pgm->body,NIL)))
+    return NIL;
+				/* logical conditions */
+  for (or = pgm->or; or; or = or->next)
+    if (!(mail_search_msg (stream,msgno,section,or->first) ||
+	  mail_search_msg (stream,msgno,section,or->second))) return NIL;
+  for (not = pgm->not; not; not = not->next)
+    if (mail_search_msg (stream,msgno,section,not->pgm)) return NIL;
+  return T;
+}
+
+/* Mail search message header null-terminated text
+ * Accepts: header text
+ *	    strings to search
+ * Returns: T if search found a match
+ */
+
+long mail_search_header_text (char *s,STRINGLIST *st)
+{
+  SIZEDTEXT h;
+				/* have any text? */
+  if (h.data = (unsigned char *) s) {
+    h.size = strlen (s);	/* yes, get its size */
+    return mail_search_header (&h,st);
+  }
+  return NIL;
+}
+
+
+/* Mail search message header
+ * Accepts: header as sized text
+ *	    strings to search
+ * Returns: T if search found a match
+ */
+
+long mail_search_header (SIZEDTEXT *hdr,STRINGLIST *st)
+{
+  SIZEDTEXT h;
+  long ret = LONGT;
+				/* make UTF-8 version of header */
+  utf8_mime2text (hdr,&h,U8T_CANONICAL);
+  while (h.size && ((h.data[h.size-1]=='\015') || (h.data[h.size-1]=='\012')))
+    --h.size;			/* slice off trailing newlines */
+  do if (h.size ?		/* search non-empty string */
+	 !ssearch (h.data,h.size,st->text.data,st->text.size) : st->text.size)
+    ret = NIL;
+  while (ret && (st = st->next));
+  if (h.data != hdr->data) fs_give ((void **) &h.data);
+  return ret;
+}
+
+/* Mail search message body
+ * Accepts: MAIL stream
+ *	    message number
+ *	    optional section specification
+ *	    string list
+ *	    flags
+ * Returns: T if search found a match
+ */
+
+long mail_search_text (MAILSTREAM *stream,unsigned long msgno,char *section,
+		       STRINGLIST *st,long flags)
+{
+  BODY *body;
+  long ret = NIL;
+  STRINGLIST *s = mail_newstringlist ();
+  mailgets_t omg = mailgets;
+  if (stream->dtb->flags & DR_LOWMEM) mailgets = mail_search_gets;
+				/* strings to search */
+  for (stream->private.search.string = s; st;) {
+    s->text.data = st->text.data;
+    s->text.size = st->text.size;
+    if (st = st->next) s = s->next = mail_newstringlist ();
+  }
+  stream->private.search.text = NIL;
+  if (flags) {			/* want header? */
+    SIZEDTEXT s,t;
+    s.data = (unsigned char *)
+      mail_fetch_header (stream,msgno,section,NIL,&s.size,FT_INTERNAL|FT_PEEK);
+    utf8_mime2text (&s,&t,U8T_CANONICAL);
+    ret = mail_search_string_work (&t,&stream->private.search.string);
+    if (t.data != s.data) fs_give ((void **) &t.data);
+  }
+  if (!ret) {			/* still looking for match? */
+				/* no section, get top-level body */
+    if (!section) mail_fetchstructure (stream,msgno,&body);
+				/* get body of nested message */
+    else if ((body = mail_body (stream,msgno,section)) &&
+	     (body->type == TYPEMULTIPART) && body->subtype &&
+	     !strcmp (body->subtype,"RFC822")) body = body->nested.msg->body;
+    if (body) ret = mail_search_body (stream,msgno,body,NIL,1,flags);
+  }
+  mailgets = omg;		/* restore former gets routine */
+				/* clear searching */
+  for (s = stream->private.search.string; s; s = s->next) s->text.data = NIL;
+  mail_free_stringlist (&stream->private.search.string);
+  stream->private.search.text = NIL;
+  return ret;
+}
+
+/* Mail search message body text parts
+ * Accepts: MAIL stream
+ *	    message number
+ *	    current body pointer
+ *	    hierarchical level prefix
+ *	    position at current hierarchical level
+ *	    string list
+ *	    flags
+ * Returns: T if search found a match
+ */
+
+long mail_search_body (MAILSTREAM *stream,unsigned long msgno,BODY *body,
+		       char *prefix,unsigned long section,long flags)
+{
+  long ret = NIL;
+  unsigned long i;
+  char *s,*t,sect[MAILTMPLEN];
+  SIZEDTEXT st,h;
+  PART *part;
+  PARAMETER *param;
+  if (prefix && (strlen (prefix) > (MAILTMPLEN - 20))) return NIL;
+  sprintf (sect,"%s%lu",prefix ? prefix : "",section++);
+  if (flags && prefix) {	/* want to search MIME header too? */
+    st.data = (unsigned char *) mail_fetch_mime (stream,msgno,sect,&st.size,
+						 FT_INTERNAL | FT_PEEK);
+    if (stream->dtb->flags & DR_LOWMEM) ret = stream->private.search.result;
+    else {
+				/* make UTF-8 version of header */
+      utf8_mime2text (&st,&h,U8T_CANONICAL);
+      ret = mail_search_string_work (&h,&stream->private.search.string);
+      if (h.data != st.data) fs_give ((void **) &h.data);
+    }
+  }
+  if (!ret) switch (body->type) {
+  case TYPEMULTIPART:
+				/* extend prefix if not first time */
+    s = prefix ? strcat (sect,".") : "";
+    for (i = 1,part = body->nested.part; part && !ret; i++,part = part->next)
+      ret = mail_search_body (stream,msgno,&part->body,s,i,flags);
+    break;
+  case TYPEMESSAGE:
+    if (!strcmp (body->subtype,"RFC822")) {
+      if (flags) {		/* want to search nested message header? */
+	st.data = (unsigned char *)
+	  mail_fetch_header (stream,msgno,sect,NIL,&st.size,
+			     FT_INTERNAL | FT_PEEK);
+	if (stream->dtb->flags & DR_LOWMEM) ret =stream->private.search.result;
+	else {
+				/* make UTF-8 version of header */
+	  utf8_mime2text (&st,&h,U8T_CANONICAL);
+	  ret = mail_search_string_work (&h,&stream->private.search.string);
+	  if (h.data != st.data) fs_give ((void **) &h.data);
+	}
+      }
+      if (body = body->nested.msg->body)
+	ret = (body->type == TYPEMULTIPART) ?
+	  mail_search_body (stream,msgno,body,(prefix ? prefix : ""),
+			    section - 1,flags) :
+	mail_search_body (stream,msgno,body,strcat (sect,"."),1,flags);
+      break;
+    }
+				/* non-MESSAGE/RFC822 falls into text case */
+
+  case TYPETEXT:
+    s = mail_fetch_body (stream,msgno,sect,&i,FT_INTERNAL | FT_PEEK);
+    if (stream->dtb->flags & DR_LOWMEM) ret = stream->private.search.result;
+    else {
+      for (t = NIL,param = body->parameter; param && !t; param = param->next)
+	if (!strcmp (param->attribute,"CHARSET")) t = param->value;
+      switch (body->encoding) {	/* what encoding? */
+      case ENCBASE64:
+	if (st.data = (unsigned char *)
+	    rfc822_base64 ((unsigned char *) s,i,&st.size)) {
+	  ret = mail_search_string (&st,t,&stream->private.search.string);
+	  fs_give ((void **) &st.data);
+	}
+	break;
+      case ENCQUOTEDPRINTABLE:
+	if (st.data = rfc822_qprint ((unsigned char *) s,i,&st.size)) {
+	  ret = mail_search_string (&st,t,&stream->private.search.string);
+	  fs_give ((void **) &st.data);
+	}
+	break;
+      default:
+	st.data = (unsigned char *) s;
+	st.size = i;
+	ret = mail_search_string (&st,t,&stream->private.search.string);
+	break;
+      }
+    }
+    break;
+  }
+  return ret;
+}
+
+/* Mail search text
+ * Accepts: sized text to search
+ *	    character set of sized text
+ *	    string list of search keys
+ * Returns: T if search found a match
+ */
+
+long mail_search_string (SIZEDTEXT *s,char *charset,STRINGLIST **st)
+{
+  SIZEDTEXT u;
+  long ret;
+  STRINGLIST **sc = st;
+				/* convert to UTF-8 as best we can */
+  if (!utf8_text (s,charset,&u,U8T_CANONICAL))
+    utf8_text (s,NIL,&u,U8T_CANONICAL);
+  ret = mail_search_string_work (&u,st);
+  if (u.data != s->data) fs_give ((void **) &u.data);
+  return ret;
+}
+
+
+/* Mail search text worker routine
+ * Accepts: sized text to search
+ *	    string list of search keys
+ * Returns: T if search found a match
+ */
+
+long mail_search_string_work (SIZEDTEXT *s,STRINGLIST **st)
+{
+  void *t;
+  STRINGLIST **sc = st;
+  while (*sc) {			/* run down criteria list */
+    if (ssearch (s->data,s->size,(*sc)->text.data,(*sc)->text.size)) {
+      t = (void *) (*sc);	/* found one, need to flush this */
+      *sc = (*sc)->next;	/* remove it from the list */
+      fs_give (&t);		/* flush the buffer */
+    }
+    else sc = &(*sc)->next;	/* move to next in list */
+  }
+  return *st ? NIL : LONGT;
+}
+
+
+/* Mail search keyword
+ * Accepts: MAIL stream
+ *	    elt to get flags from
+ *	    keyword list
+ *	    T for keyword search, NIL for unkeyword search
+ * Returns: T if search found a match
+ */
+
+long mail_search_keyword (MAILSTREAM *stream,MESSAGECACHE *elt,STRINGLIST *st,
+			  long flag)
+{
+  int i,j;
+  unsigned long f = 0;
+  unsigned long tf;
+  do {
+    for (i = 0; (j = (i < NUSERFLAGS) && stream->user_flags[i]); ++i)
+      if (!compare_csizedtext (stream->user_flags[i],&st->text)) {
+	f |= (1 << i);
+	break;
+      }
+    if (flag && !j) return NIL;
+  } while (st = st->next);
+  tf = elt->user_flags & f;	/* get set flags which match */
+  return flag ? (f == tf) : !tf;
+}
+
+/* Mail search an address list
+ * Accepts: address list
+ *	    string list
+ * Returns: T if search found a match
+ */
+
+#define SEARCHBUFLEN (size_t) 2000
+#define SEARCHBUFSLOP (size_t) 5
+
+long mail_search_addr (ADDRESS *adr,STRINGLIST *st)
+{
+  ADDRESS *a,tadr;
+  SIZEDTEXT txt;
+  char tmp[SENDBUFLEN + 1];
+  size_t i = SEARCHBUFLEN;
+  size_t k;
+  long ret = NIL;
+  if (adr) {
+    txt.data = (unsigned char *) fs_get (i + SEARCHBUFSLOP);
+				/* never an error or next */
+    tadr.error = NIL,tadr.next = NIL;
+				/* write address list */
+    for (txt.size = 0,a = adr; a; a = a->next) {
+      k = (tadr.mailbox = a->mailbox) ? 4 + 2*strlen (a->mailbox) : 3;
+      if (tadr.personal = a->personal) k += 3 + 2*strlen (a->personal);
+      if (tadr.adl = a->adl) k += 3 + 2*strlen (a->adl);
+      if (tadr.host = a->host) k += 3 + 2*strlen (a->host);
+      if (tadr.personal || tadr.adl) k += 2;
+      if (k < (SENDBUFLEN-10)) {/* ignore ridiculous addresses */
+	tmp[0] = '\0';
+	rfc822_write_address (tmp,&tadr);
+				/* resize buffer if necessary */
+	if (((k = strlen (tmp)) + txt.size) > i)
+	  fs_resize ((void **) &txt.data,SEARCHBUFSLOP + (i += SEARCHBUFLEN));
+				/* add new address */
+	memcpy (txt.data + txt.size,tmp,k);
+	txt.size += k;
+				/* another address follows */
+	if (a->next) txt.data[txt.size++] = ',';
+      }
+    }
+    txt.data[txt.size] = '\0';	/* tie off string */
+    ret = mail_search_header (&txt,st);
+    fs_give ((void **) &txt.data);
+  }
+  return ret;
+}
+
+/* Get string for low-memory searching
+ * Accepts: readin function pointer
+ *	    stream to use
+ *	    number of bytes
+ *	    gets data packet
+
+ *	    mail stream
+ *	    message number
+ *	    descriptor string
+ *	    option flags
+ * Returns: NIL, always
+ */
+
+#define SEARCHSLOP 128
+
+char *mail_search_gets (readfn_t f,void *stream,unsigned long size,
+			GETS_DATA *md)
+{
+  unsigned long i;
+  char tmp[MAILTMPLEN+SEARCHSLOP+1];
+  SIZEDTEXT st;
+				/* better not be called unless searching */
+  if (!md->stream->private.search.string) {
+    sprintf (tmp,"Search botch, mbx = %.80s, %s = %lu[%.80s]",
+	     md->stream->mailbox,
+	     (md->flags & FT_UID) ? "UID" : "msg",md->msgno,md->what);
+    fatal (tmp);
+  }
+				/* initially no match for search */
+  md->stream->private.search.result = NIL;
+				/* make sure buffer clear */
+  memset (st.data = (unsigned char *) tmp,'\0',
+	  (size_t) MAILTMPLEN+SEARCHSLOP+1);
+				/* read first buffer */
+  (*f) (stream,st.size = i = min (size,(long) MAILTMPLEN),tmp);
+				/* search for text */
+  if (mail_search_string (&st,NIL,&md->stream->private.search.string))
+    md->stream->private.search.result = T;
+  else if (size -= i) {		/* more to do, blat slop down */
+    memmove (tmp,tmp+MAILTMPLEN-SEARCHSLOP,(size_t) SEARCHSLOP);
+    do {			/* read subsequent buffers one at a time */
+      (*f) (stream,i = min (size,(long) MAILTMPLEN),tmp+SEARCHSLOP);
+      st.size = i + SEARCHSLOP;
+      if (mail_search_string (&st,NIL,&md->stream->private.search.string))
+	md->stream->private.search.result = T;
+      else memmove (tmp,tmp+MAILTMPLEN,(size_t) SEARCHSLOP);
+    }
+    while ((size -= i) && !md->stream->private.search.result);
+  }
+  if (size) {			/* toss out everything after that */
+    do (*f) (stream,i = min (size,(long) MAILTMPLEN),tmp);
+    while (size -= i);
+  }
+  return NIL;
+}
+
+/* Mail parse search criteria
+ * Accepts: criteria
+ * Returns: search program if parse successful, else NIL
+ */
+
+SEARCHPGM *mail_criteria (char *criteria)
+{
+  SEARCHPGM *pgm = NIL;
+  char *criterion,*r,tmp[MAILTMPLEN];
+  int f;
+  if (criteria) {		/* only if criteria defined */
+				/* make writeable copy of criteria */
+    criteria = cpystr (criteria);
+				/* for each criterion */
+    for (pgm = mail_newsearchpgm (), criterion = strtok_r (criteria," ",&r);
+	 criterion; (criterion = strtok_r (NIL," ",&r))) {
+      f = NIL;			/* init then scan the criterion */
+      switch (*ucase (criterion)) {
+      case 'A':			/* possible ALL, ANSWERED */
+	if (!strcmp (criterion+1,"LL")) f = T;
+	else if (!strcmp (criterion+1,"NSWERED")) f = pgm->answered = T;
+	break;
+      case 'B':			/* possible BCC, BEFORE, BODY */
+	if (!strcmp (criterion+1,"CC"))
+	  f = mail_criteria_string (&pgm->bcc,&r);
+	else if (!strcmp (criterion+1,"EFORE"))
+	  f = mail_criteria_date (&pgm->before,&r);
+	else if (!strcmp (criterion+1,"ODY"))
+	  f = mail_criteria_string (&pgm->body,&r);
+	break;
+      case 'C':			/* possible CC */
+	if (!strcmp (criterion+1,"C")) f = mail_criteria_string (&pgm->cc,&r);
+	break;
+      case 'D':			/* possible DELETED */
+	if (!strcmp (criterion+1,"ELETED")) f = pgm->deleted = T;
+	break;
+      case 'F':			/* possible FLAGGED, FROM */
+	if (!strcmp (criterion+1,"LAGGED")) f = pgm->flagged = T;
+	else if (!strcmp (criterion+1,"ROM"))
+	  f = mail_criteria_string (&pgm->from,&r);
+	break;
+      case 'K':			/* possible KEYWORD */
+	if (!strcmp (criterion+1,"EYWORD"))
+	  f = mail_criteria_string (&pgm->keyword,&r);
+	break;
+
+      case 'N':			/* possible NEW */
+	if (!strcmp (criterion+1,"EW")) f = pgm->recent = pgm->unseen = T;
+	break;
+      case 'O':			/* possible OLD, ON */
+	if (!strcmp (criterion+1,"LD")) f = pgm->old = T;
+	else if (!strcmp (criterion+1,"N"))
+	  f = mail_criteria_date (&pgm->on,&r);
+	break;
+      case 'R':			/* possible RECENT */
+	if (!strcmp (criterion+1,"ECENT")) f = pgm->recent = T;
+	break;
+      case 'S':			/* possible SEEN, SINCE, SUBJECT */
+	if (!strcmp (criterion+1,"EEN")) f = pgm->seen = T;
+	else if (!strcmp (criterion+1,"INCE"))
+	  f = mail_criteria_date (&pgm->since,&r);
+	else if (!strcmp (criterion+1,"UBJECT"))
+	  f = mail_criteria_string (&pgm->subject,&r);
+	break;
+      case 'T':			/* possible TEXT, TO */
+	if (!strcmp (criterion+1,"EXT"))
+	  f = mail_criteria_string (&pgm->text,&r);
+	else if (!strcmp (criterion+1,"O"))
+	  f = mail_criteria_string (&pgm->to,&r);
+	break;
+      case 'U':			/* possible UN* */
+	if (criterion[1] == 'N') {
+	  if (!strcmp (criterion+2,"ANSWERED")) f = pgm->unanswered = T;
+	  else if (!strcmp (criterion+2,"DELETED")) f = pgm->undeleted = T;
+	  else if (!strcmp (criterion+2,"FLAGGED")) f = pgm->unflagged = T;
+	  else if (!strcmp (criterion+2,"KEYWORD"))
+	    f = mail_criteria_string (&pgm->unkeyword,&r);
+	  else if (!strcmp (criterion+2,"SEEN")) f = pgm->unseen = T;
+	}
+	break;
+      default:			/* we will barf below */
+	break;
+      }
+      if (!f) {			/* if can't identify criterion */
+	sprintf (tmp,"Unknown search criterion: %.30s",criterion);
+	MM_LOG (tmp,ERROR);
+	mail_free_searchpgm (&pgm);
+	break;
+      }
+    }
+				/* no longer need copy of criteria */
+    fs_give ((void **) &criteria);
+  }
+  return pgm;
+}
+
+/* Parse a date
+ * Accepts: pointer to date integer to return
+ *	    pointer to strtok state
+ * Returns: T if successful, else NIL
+ */
+
+int mail_criteria_date (unsigned short *date,char **r)
+{
+  STRINGLIST *s = NIL;
+  MESSAGECACHE elt;
+				/* parse the date and return fn if OK */
+  int ret = (mail_criteria_string (&s,r) &&
+	     mail_parse_date (&elt,(char *) s->text.data) &&
+	     (*date = mail_shortdate (elt.year,elt.month,elt.day))) ?
+	       T : NIL;
+  if (s) mail_free_stringlist (&s);
+  return ret;
+}
+
+/* Calculate shortdate from elt values
+ * Accepts: year (0 = BASEYEAR)
+ *	    month (1 = January)
+ *	    day
+ * Returns: shortdate
+ */
+
+unsigned short mail_shortdate (unsigned int year,unsigned int month,
+			       unsigned int day)
+{
+  return (year << 9) + (month << 5) + day;
+}
+
+/* Parse a string
+ * Accepts: pointer to stringlist
+ *	    pointer to strtok state
+ * Returns: T if successful, else NIL
+ */
+
+int mail_criteria_string (STRINGLIST **s,char **r)
+{
+  unsigned long n;
+  char e,*d,*end = " ",*c = strtok_r (NIL,"",r);
+  if (!c) return NIL;		/* missing argument */
+  switch (*c) {			/* see what the argument is */
+  case '{':			/* literal string */
+    n = strtoul (c+1,&d,10);	/* get its length */
+    if ((*d++ == '}') && (*d++ == '\015') && (*d++ == '\012') &&
+	(!(*(c = d + n)) || (*c == ' '))) {
+      e = *--c;			/* store old delimiter */
+      *c = '\377';		/* make sure not a space */
+      strtok_r (c," ",r);	/* reset the strtok mechanism */
+      *c = e;			/* put character back */
+      break;
+    }
+  case '\0':			/* catch bogons */
+  case ' ':
+    return NIL;
+  case '"':			/* quoted string */
+    if (strchr (c+1,'"')) end = "\"";
+    else return NIL;		/* falls through */
+  default:			/* atomic string */
+    if (d = strtok_r (c,end,r)) n = strlen (d);
+    else return NIL;
+    break;
+  }
+  while (*s) s = &(*s)->next;	/* find tail of list */
+  *s = mail_newstringlist ();	/* make new entry */
+				/* return the data */
+  (*s)->text.data = (unsigned char *) cpystr (d);
+  (*s)->text.size = n;
+  return T;
+}
+
+/* Mail parse set from string
+ * Accepts: string to parse
+ *	    pointer to updated string pointer for return
+ * Returns: set with pointer updated, or NIL if error
+ */
+
+SEARCHSET *mail_parse_set (char *s,char **ret)
+{
+  SEARCHSET *cur;
+  SEARCHSET *set = NIL;
+  while (isdigit (*s)) {
+    if (!set) cur = set = mail_newsearchset ();
+    else cur = cur->next = mail_newsearchset ();
+				/* parse value */
+    if (!(cur->first = strtoul (s,&s,10)) ||
+	((*s == ':') && !(isdigit (*++s) && (cur->last = strtoul (s,&s,10)))))
+      break;			/* bad value or range */
+    if (*s == ',') ++s;		/* point to next value if more */
+    else {			/* end of set */
+      *ret = s;			/* set return pointer */
+      return set;		/* return set */
+    }
+  }
+  mail_free_searchset (&set);	/* failure, punt partial set */
+  return NIL;
+}
+
+
+/* Mail append to set
+ * Accepts: head of search set or NIL to do nothing
+ *	    message to add
+ * Returns: tail of search set or NIL if did nothing
+ */
+
+SEARCHSET *mail_append_set (SEARCHSET *set,unsigned long msgno)
+{
+  if (set) {			/* find tail */
+    while (set->next) set = set->next;
+				/* start of set if no first member */
+    if (!set->first) set->first = msgno;
+    else if (msgno == (set->last ? set->last : set->first) + 1)
+      set->last = msgno;	/* extend range if 1 past current */
+    else (set = set->next = mail_newsearchset ())->first = msgno;
+  }
+  return set;
+}
+
+/* Mail sort messages
+ * Accepts: mail stream
+ *	    character set
+ *	    search program
+ *	    sort program
+ *	    option flags
+ * Returns: vector of sorted message sequences or NIL if error
+ */
+
+unsigned long *mail_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
+			  SORTPGM *pgm,long flags)
+{
+  unsigned long *ret = NIL;
+  if (stream->dtb)		/* do the driver's action */
+    ret = (*(stream->dtb->sort ? stream->dtb->sort : mail_sort_msgs))
+      (stream,charset,spg,pgm,flags);
+				/* flush search/sort programs if requested */
+  if (spg && (flags & SE_FREE)) mail_free_searchpgm (&spg);
+  if (flags & SO_FREE) mail_free_sortpgm (&pgm);
+  return ret;
+}
+
+/* Mail sort messages work routine
+ * Accepts: mail stream
+ *	    character set
+ *	    search program
+ *	    sort program
+ *	    option flags
+ * Returns: vector of sorted message sequences or NIL if error
+ */
+
+unsigned long *mail_sort_msgs (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
+			       SORTPGM *pgm,long flags)
+{
+  unsigned long i;
+  SORTCACHE **sc;
+  unsigned long *ret = NIL;
+  if (spg) {			/* only if a search needs to be done */
+    int silent = stream->silent;
+    stream->silent = T;		/* don't pass up mm_searched() events */
+				/* search for messages */
+    mail_search_full (stream,charset,spg,NIL);
+    stream->silent = silent;	/* restore silence state */
+  }
+				/* initialize progress counters */
+  pgm->nmsgs = pgm->progress.cached = 0;
+				/* pass 1: count messages to sort */
+  for (i = 1; i <= stream->nmsgs; ++i)
+    if (mail_elt (stream,i)->searched) pgm->nmsgs++;
+  if (pgm->nmsgs) {		/* pass 2: sort cache */
+    sc = mail_sort_loadcache (stream,pgm);
+				/* pass 3: sort messages */
+    if (!pgm->abort) ret = mail_sort_cache (stream,pgm,sc,flags);
+    fs_give ((void **) &sc);	/* don't need sort vector any more */
+  }
+				/* empty sort results */
+  else ret = (unsigned long *) memset (fs_get (sizeof (unsigned long)),0,
+				       sizeof (unsigned long));
+				/* also return via callback if requested */
+  if (mailsortresults) (*mailsortresults) (stream,ret,pgm->nmsgs);
+  return ret;			/* return sort results */
+}
+
+/* Mail sort sortcache vector
+ * Accepts: mail stream
+ *	    sort program
+ *	    sortcache vector
+ *	    option flags
+ * Returns: vector of sorted message sequences or NIL if error
+ */
+
+unsigned long *mail_sort_cache (MAILSTREAM *stream,SORTPGM *pgm,SORTCACHE **sc,
+				long flags)
+{
+  unsigned long i,*ret;
+				/* pass 3: sort messages */
+  qsort ((void *) sc,pgm->nmsgs,sizeof (SORTCACHE *),mail_sort_compare);
+				/* optional post sorting */
+  if (pgm->postsort) (*pgm->postsort) ((void *) sc);
+				/* pass 4: return results */
+  ret = (unsigned long *) fs_get ((pgm->nmsgs+1) * sizeof (unsigned long));
+  if (flags & SE_UID)		/* UID or msgno? */
+    for (i = 0; i < pgm->nmsgs; i++) ret[i] = mail_uid (stream,sc[i]->num);
+  else for (i = 0; i < pgm->nmsgs; i++) ret[i] = sc[i]->num;
+  ret[pgm->nmsgs] = 0;		/* tie off message list */
+  return ret;
+}
+
+/* Mail load sortcache
+ * Accepts: mail stream, already searched
+ *	    sort program
+ * Returns: vector of sortcache pointers matching search
+ */
+
+static STRINGLIST maildateline = {{(unsigned char *) "date",4},NIL};
+static STRINGLIST mailrnfromline = {{(unsigned char *) ">from",5},NIL};
+static STRINGLIST mailfromline = {{(unsigned char *) "from",4},
+				    &mailrnfromline};
+static STRINGLIST mailtonline = {{(unsigned char *) "to",2},NIL};
+static STRINGLIST mailccline = {{(unsigned char *) "cc",2},NIL};
+static STRINGLIST mailsubline = {{(unsigned char *) "subject",7},NIL};
+
+SORTCACHE **mail_sort_loadcache (MAILSTREAM *stream,SORTPGM *pgm)
+{
+  char *t,*v,*x,tmp[MAILTMPLEN];
+  SORTPGM *pg;
+  SORTCACHE *s,**sc;
+  MESSAGECACHE *elt,telt;
+  ENVELOPE *env;
+  ADDRESS *adr = NIL;
+  unsigned long i = (pgm->nmsgs) * sizeof (SORTCACHE *);
+  sc = (SORTCACHE **) memset (fs_get ((size_t) i),0,(size_t) i);
+				/* see what needs to be loaded */
+  for (i = 1; !pgm->abort && (i <= stream->nmsgs); i++)
+    if ((elt = mail_elt (stream,i))->searched) {
+      sc[pgm->progress.cached++] =
+	s = (SORTCACHE *) (*mailcache) (stream,i,CH_SORTCACHE);
+      s->pgm = pgm;		/* note sort program */
+      s->num = i;
+				/* get envelope if cached */
+      if (stream->scache) env = (i == stream->msgno) ? stream->env : NIL;
+      else env = elt->private.msg.env;
+      for (pg = pgm; pg; pg = pg->next) switch (pg->function) {
+      case SORTARRIVAL:		/* sort by arrival date */
+	if (!s->arrival) {
+				/* internal date unknown but can get? */
+	  if (!elt->day && !(stream->dtb->flags & DR_NOINTDATE)) {
+	    sprintf (tmp,"%lu",i);
+	    mail_fetch_fast (stream,tmp,NIL);
+	  }
+				/* wrong thing before 3-Jan-1970 */
+	  s->arrival = elt->day ? mail_longdate (elt) : 1;
+	  s->dirty = T;
+	}
+	break;
+      case SORTSIZE:		/* sort by message size */
+	if (!s->size) {
+	  if (!elt->rfc822_size) {
+	    sprintf (tmp,"%lu",i);
+	    mail_fetch_fast (stream,tmp,NIL);
+	  }
+	  s->size = elt->rfc822_size ? elt->rfc822_size : 1;
+	  s->dirty = T;
+	}
+	break;
+
+      case SORTDATE:		/* sort by date */
+	if (!s->date) {
+	  if (env) t = env->date;
+	  else if ((t = mail_fetch_header (stream,i,NIL,&maildateline,NIL,
+					   FT_INTERNAL | FT_PEEK)) &&
+		   (t = strchr (t,':')))
+	    for (x = ++t; x = strpbrk (x,"\012\015"); x++)
+	      switch (*(v = ((*x == '\015') && (x[1] == '\012')) ? x+2 : x+1)){
+	      case ' ':		/* erase continuation newlines */
+	      case '\t':
+		memmove (x,v,strlen (v));
+		break;
+	      default:		/* tie off extraneous text */
+		*x = x[1] = '\0';
+	      }
+				/* skip leading whitespace */
+	  if (t) while ((*t == ' ') || (*t == '\t')) t++;
+				/* parse date from Date: header */
+	  if (!(t && mail_parse_date (&telt,t) && 
+		(s->date = mail_longdate (&telt)))) {
+				/* failed, use internal date */
+	    if (!(s->date = s->arrival)) {
+				/* internal date unknown but can get? */
+	      if (!elt->day && !(stream->dtb->flags & DR_NOINTDATE)) {
+		sprintf (tmp,"%lu",i);
+		mail_fetch_fast (stream,tmp,NIL);
+	      }
+				/* wrong thing before 3-Jan-1970 */
+	      s->date = (s->arrival = elt->day ? mail_longdate (elt) : 1);
+	    }
+	  }
+	  s->dirty = T;
+	}
+	break;
+
+      case SORTFROM:		/* sort by first from */
+	if (!s->from) {
+	  if (env) s->from = env->from && env->from->mailbox ?
+	    cpystr (env->from->mailbox) : NIL;
+	  else if ((t = mail_fetch_header (stream,i,NIL,&mailfromline,NIL,
+					   FT_INTERNAL | FT_PEEK)) &&
+		   (t = strchr (t,':'))) {
+	    for (x = ++t; x = strpbrk (x,"\012\015"); x++)
+	      switch (*(v = ((*x == '\015') && (x[1] == '\012')) ? x+2 : x+1)){
+	      case ' ':		/* erase continuation newlines */
+	      case '\t':
+		memmove (x,v,strlen (v));
+		break;
+	      case 'f':		/* continuation but with extra "From:" */
+	      case 'F':
+		if (v = strchr (v,':')) {
+		  memmove (x,v+1,strlen (v+1));
+		  break;
+		}
+	      default:		/* tie off extraneous text */
+		*x = x[1] = '\0';
+	      }
+	    if (adr = rfc822_parse_address (&adr,adr,&t,BADHOST,0)) {
+	      s->from = adr->mailbox;
+	      adr->mailbox = NIL;
+	      mail_free_address (&adr);
+	    }
+	  }
+	  if (!s->from) s->from = cpystr ("");
+	  s->dirty = T;
+	}
+	break;
+
+      case SORTTO:		/* sort by first to */
+	if (!s->to) {
+	  if (env) s->to = env->to && env->to->mailbox ?
+	    cpystr (env->to->mailbox) : NIL;
+	  else if ((t = mail_fetch_header (stream,i,NIL,&mailtonline,NIL,
+					   FT_INTERNAL | FT_PEEK)) &&
+		   (t = strchr (t,':'))) {
+	    for (x = ++t; x = strpbrk (x,"\012\015"); x++)
+	      switch (*(v = ((*x == '\015') && (x[1] == '\012')) ? x+2 : x+1)){
+	      case ' ':		/* erase continuation newlines */
+	      case '\t':
+		memmove (x,v,strlen (v));
+		break;
+	      case 't':		/* continuation but with extra "To:" */
+	      case 'T':
+		if (v = strchr (v,':')) {
+		  memmove (x,v+1,strlen (v+1));
+		  break;
+		}
+	      default:		/* tie off extraneous text */
+		*x = x[1] = '\0';
+	      }
+	    if (adr = rfc822_parse_address (&adr,adr,&t,BADHOST,0)) {
+	      s->to = adr->mailbox;
+	      adr->mailbox = NIL;
+	      mail_free_address (&adr);
+	    }
+	  }
+	  if (!s->to) s->to = cpystr ("");
+	  s->dirty = T;
+	}
+	break;
+
+      case SORTCC:		/* sort by first cc */
+	if (!s->cc) {
+	  if (env) s->cc = env->cc && env->cc->mailbox ?
+	    cpystr (env->cc->mailbox) : NIL;
+	  else if ((t = mail_fetch_header (stream,i,NIL,&mailccline,NIL,
+					   FT_INTERNAL | FT_PEEK)) &&
+		   (t = strchr (t,':'))) {
+	    for (x = ++t; x = strpbrk (x,"\012\015"); x++)
+	      switch (*(v = ((*x == '\015') && (x[1] == '\012')) ? x+2 : x+1)){
+	      case ' ':		/* erase continuation newlines */
+	      case '\t':
+		memmove (x,v,strlen (v));
+		break;
+	      case 't':		/* continuation but with extra "To:" */
+	      case 'T':
+		if (v = strchr (v,':')) {
+		  memmove (x,v+1,strlen (v+1));
+		  break;
+		}
+	      default:		/* tie off extraneous text */
+		*x = x[1] = '\0';
+	      }
+	    if (adr = rfc822_parse_address (&adr,adr,&t,BADHOST,0)) {
+	      s->cc = adr->mailbox;
+	      adr->mailbox = NIL;
+	      mail_free_address (&adr);
+	    }
+	  }
+	  if (!s->cc) s->cc = cpystr ("");
+	  s->dirty = T;
+	}
+	break;
+
+      case SORTSUBJECT:		/* sort by subject */
+	if (!s->subject) {
+				/* get subject from envelope if have one */
+	  if (env) t = env->subject ? env->subject : "";
+				/* otherwise snarf from header text */
+	  else if ((t = mail_fetch_header (stream,i,NIL,&mailsubline,
+					   NIL,FT_INTERNAL | FT_PEEK)) &&
+		   (t = strchr (t,':')))
+	    for (x = ++t; x = strpbrk (x,"\012\015"); x++)
+	      switch (*(v = ((*x == '\015') && (x[1] == '\012')) ? x+2 : x+1)){
+	      case ' ':		/* erase continuation newlines */
+	      case '\t':
+		memmove (x,v,strlen (v));
+		break;
+	      default:		/* tie off extraneous text */
+		*x = x[1] = '\0';
+	      }
+	  else t = "";		/* empty subject */
+				/* strip and cache subject */
+	  s->refwd = mail_strip_subject (t,&s->subject);
+	  s->dirty = T;
+	}
+	break;
+      default:
+	fatal ("Unknown sort function");
+      }
+    }
+  return sc;
+}
+
+/* Strip subjects of extra spaces and leading and trailing cruft for sorting
+ * Accepts: unstripped subject
+ *	    pointer to return stripped subject, in cpystr form
+ * Returns: T if subject had a re/fwd, NIL otherwise
+ */
+
+unsigned int mail_strip_subject (char *t,char **ret)
+{
+  SIZEDTEXT src,dst;
+  unsigned long i,slen;
+  char c,*s,*x;
+  unsigned int refwd = NIL;
+  if (src.size = strlen (t)) {	/* have non-empty subject? */
+    src.data = (unsigned char *) t;
+			/* Step 1 */
+				/* make copy, convert MIME2 if needed */
+    *ret = s = (utf8_mime2text (&src,&dst,U8T_CANONICAL) &&
+		(src.data != dst.data)) ? (char *) dst.data : cpystr (t);
+				/* convert spaces to tab, strip extra spaces */
+    for (x = t = s, c = 'x'; *t; t++) {
+      if (c != ' ') c = *x++ = ((*t == '\t') ? ' ' : *t);
+      else if ((*t != '\t') && (*t != ' ')) c = *x++ = *t;
+    }
+    *x = '\0';			/* tie off string */
+			/* Step 2 */
+    for (slen = dst.size; s; slen = strlen (s))  {
+      for (t = s + slen; t > s; ) switch (t[-1]) {
+      case ' ': case '\t':	/* WSP */
+	*--t = '\0';		/* just remove it */
+	break;
+      case ')':			/* possible "(fwd)" */
+	if ((t >= (s + 5)) && (t[-5] == '(') &&
+	    ((t[-4] == 'F') || (t[-4] == 'f')) &&
+	    ((t[-3] == 'W') || (t[-3] == 'w')) &&
+	    ((t[-2] == 'D') || (t[-2] == 'd'))) {
+	  *(t -= 5) = '\0';	/* remove "(fwd)" */
+	  refwd = T;		/* note a re/fwd */
+	  break;
+	}
+      default:			/* not a subj-trailer */
+	t = s;
+	break;
+      }
+			/* Steps 3-5 */
+      for (t = s; t; ) switch (*s) {
+      case ' ': case '\t':	/* WSP */
+	s = t = mail_strip_subject_wsp (s + 1);
+	break;
+      case 'r': case 'R':	/* possible "re" */
+	if (((s[1] == 'E') || (s[1] == 'e')) &&
+	    (t = mail_strip_subject_wsp (s + 2)) &&
+	    (t = mail_strip_subject_blob (t)) && (*t == ':')) {
+	  s = ++t;		/* found "re" */
+	  refwd = T;		/* definitely a re/fwd at this point */
+	}
+	else t = NIL;		/* found subj-middle */
+	break;
+      case 'f': case 'F':	/* possible "fw" or "fwd" */
+	if (((s[1] == 'w') || (s[1] == 'W')) &&
+	    (((s[2] == 'd') || (s[2] == 'D')) ?
+	     (t = mail_strip_subject_wsp (s + 3)) :
+	     (t = mail_strip_subject_wsp (s + 2))) &&
+	    (t = mail_strip_subject_blob (t)) && (*t == ':')) {
+	  s = ++t;		/* found "fwd" */
+	  refwd = T;		/* definitely a re/fwd at this point */
+	}
+	else t = NIL;		/* found subj-middle */
+	break;
+      case '[':			/* possible subj-blob */
+	if ((t = mail_strip_subject_blob (s)) && *t) s = t;
+	else t = NIL;		/* found subj-middle */
+	break;
+      default:
+	t = NIL;		/* found subj-middle */
+	break;
+      }
+			/* Step 6 */
+				/* Netscape-style "[Fwd: ...]"? */
+      if ((*s == '[') && ((s[1] == 'F') || (s[1] == 'f')) &&
+	  ((s[2] == 'W') || (s[2] == 'w')) &&
+	  ((s[3] == 'D') || (s[3] == 'd')) && (s[4] == ':') &&
+	  (s[i = strlen (s) - 1] == ']')) {
+	s[i] = '\0';		/* flush closing "]" */
+	s += 5;			/* and leading "[Fwd:" */
+	refwd = T;		/* definitely a re/fwd at this point */
+      }
+      else break;		/* don't need to loop back to step 2 */
+    }
+    if (s != (t = *ret)) {	/* removed leading text? */
+      s = *ret = cpystr (s);	/* yes, make a fresh return copy */
+      fs_give ((void **) &t);	/* flush old copy */
+    }
+  }
+  else *ret = cpystr ("");	/* empty subject */
+  return refwd;			/* return re/fwd state */
+}
+
+/* Strip subject wsp helper routine
+ * Accepts: text
+ * Returns: pointer to text after blob
+ */
+
+char *mail_strip_subject_wsp (char *s)
+{
+  while ((*s == ' ') || (*s == '\t')) s++;
+  return s;
+}
+
+
+/* Strip subject blob helper routine
+ * Accepts: text
+ * Returns: pointer to text after any blob, NIL if blob-like but not blob
+ */
+
+char *mail_strip_subject_blob (char *s)
+{
+  if (*s != '[') return s;	/* not a blob, ignore */
+				/* search for end of blob */
+  while (*++s != ']') if ((*s == '[') || !*s) return NIL;
+  return mail_strip_subject_wsp (s + 1);
+}
+
+/* Sort compare messages
+ * Accept: first message sort cache element
+ *	   second message sort cache element
+ * Returns: -1 if a1 < a2, 0 if a1 == a2, 1 if a1 > a2
+ */
+
+int mail_sort_compare (const void *a1,const void *a2)
+{
+  int i = 0;
+  SORTCACHE *s1 = *(SORTCACHE **) a1;
+  SORTCACHE *s2 = *(SORTCACHE **) a2;
+  SORTPGM *pgm = s1->pgm;
+  if (!s1->sorted) {		/* this one sorted yet? */
+    s1->sorted = T;
+    pgm->progress.sorted++;	/* another sorted message */
+  }
+  if (!s2->sorted) {		/* this one sorted yet? */
+    s2->sorted = T;
+    pgm->progress.sorted++;	/* another sorted message */
+  }
+  do {
+    switch (pgm->function) {	/* execute search program */
+    case SORTDATE:		/* sort by date */
+      i = compare_ulong (s1->date,s2->date);
+      break;
+    case SORTARRIVAL:		/* sort by arrival date */
+      i = compare_ulong (s1->arrival,s2->arrival);
+      break;
+    case SORTSIZE:		/* sort by message size */
+      i = compare_ulong (s1->size,s2->size);
+      break;
+    case SORTFROM:		/* sort by first from */
+      i = compare_cstring (s1->from,s2->from);
+      break;
+    case SORTTO:		/* sort by first to */
+      i = compare_cstring (s1->to,s2->to);
+      break;
+    case SORTCC:		/* sort by first cc */
+      i = compare_cstring (s1->cc,s2->cc);
+      break;
+    case SORTSUBJECT:		/* sort by subject */
+      i = compare_cstring (s1->subject,s2->subject);
+      break;
+    }
+    if (pgm->reverse) i = -i;	/* flip results if necessary */
+  }
+  while (pgm = i ? NIL : pgm->next);
+				/* return result, avoid 0 if at all possible */
+  return i ? i : compare_ulong (s1->num,s2->num);
+}
+
+/* Return message date as an unsigned long seconds since time began
+ * Accepts: message cache pointer
+ * Returns: unsigned long of date
+ *
+ * This routine, like most UNIX systems, is clueless about leap seconds.
+ * Thus, it treats 23:59:60 as equivalent to 00:00:00 the next day.
+ *
+ * This routine forces any early hours on 1-Jan-1970 in oriental timezones
+ * to be 1-Jan-1970 00:00:00 UTC, so as to avoid negative longdates.
+ */
+
+unsigned long mail_longdate (MESSAGECACHE *elt)
+{
+  unsigned long m = elt->month ? elt->month : 1;
+  unsigned long yr = elt->year + BASEYEAR;
+				/* number of days since time began */
+  unsigned long ret = (elt->day ? (elt->day - 1) : 0)
+    + 30 * (m - 1) + ((m + (m > 8)) / 2)
+#ifndef USEJULIANCALENDAR
+#ifndef USEORTHODOXCALENDAR	/* Gregorian calendar */
+    + ((yr / 400) - (BASEYEAR / 400)) - ((yr / 100) - (BASEYEAR / 100))
+#ifdef Y4KBUGFIX
+    - ((yr / 4000) - (BASEYEAR / 4000))
+#endif
+    - ((m < 3) ?
+       !(yr % 4) && ((yr % 100) || (!(yr % 400)
+#ifdef Y4KBUGFIX
+				    && (yr % 4000)
+#endif
+				    )) : 2)
+#else				/* Orthodox calendar */
+    + ((2*(yr / 900)) - (2*(BASEYEAR / 900)))
+    + (((yr % 900) >= 200) - ((BASEYEAR % 900) >= 200))
+    + (((yr % 900) >= 600) - ((BASEYEAR % 900) >= 600))
+    - ((yr / 100) - (BASEYEAR / 100))
+    - ((m < 3) ?
+       !(yr % 4) && ((yr % 100) || ((yr % 900) == 200) || ((yr % 900) == 600))
+       : 2)
+#endif
+#endif
+    + elt->year * 365 + (((unsigned long) (elt->year + (BASEYEAR % 4))) / 4);
+  ret *= 24; ret += elt->hours;	/* date value in hours */
+  ret *= 60; ret +=elt->minutes;/* date value in minutes */
+  yr = (elt->zhours * 60) + elt->zminutes;
+  if (elt->zoccident) ret += yr;/* occidental timezone, make UTC */
+  else if (ret < yr) return 0;	/* still 31-Dec-1969 in UTC */
+  else ret -= yr;		/* oriental timezone, make UTC */
+  ret *= 60; ret += elt->seconds;
+  return ret;
+}
+
+/* Mail thread messages
+ * Accepts: mail stream
+ *	    thread type
+ *	    character set
+ *	    search program
+ *	    option flags
+ * Returns: thread node tree or NIL if error
+ */
+
+THREADNODE *mail_thread (MAILSTREAM *stream,char *type,char *charset,
+			 SEARCHPGM *spg,long flags)
+{
+  THREADNODE *ret = NIL;
+  if (stream->dtb)		/* must have a live driver */
+    ret = stream->dtb->thread ?	/* do driver's action if available */
+      (*stream->dtb->thread) (stream,type,charset,spg,flags) :
+	mail_thread_msgs (stream,type,charset,spg,flags,mail_sort_msgs);
+				/* flush search/sort programs if requested */
+  if (spg && (flags & SE_FREE)) mail_free_searchpgm (&spg);
+  return ret;
+}
+
+
+/* Mail thread messages
+ * Accepts: mail stream
+ *	    thread type
+ *	    character set
+ *	    search program
+ *	    option flags
+ *	    sorter routine
+ * Returns: thread node tree or NIL if error
+ */
+
+THREADNODE *mail_thread_msgs (MAILSTREAM *stream,char *type,char *charset,
+			      SEARCHPGM *spg,long flags,sorter_t sorter)
+{
+  THREADER *t;
+  for (t = &mailthreadlist; t; t = t->next)
+    if (!compare_cstring (type,t->name)) {
+      THREADNODE *ret = (*t->dispatch) (stream,charset,spg,flags,sorter);
+      if (mailthreadresults) (*mailthreadresults) (stream,ret);
+      return ret;
+    }
+  MM_LOG ("No such thread type",ERROR);
+  return NIL;
+}
+
+/* Mail thread ordered subject
+ * Accepts: mail stream
+ *	    character set
+ *	    search program
+ *	    option flags
+ *	    sorter routine
+ * Returns: thread node tree
+ */
+
+THREADNODE *mail_thread_orderedsubject (MAILSTREAM *stream,char *charset,
+					SEARCHPGM *spg,long flags,
+					sorter_t sorter)
+{
+  THREADNODE *thr = NIL;
+  THREADNODE *cur,*top,**tc;
+  SORTPGM pgm,pgm2;
+  SORTCACHE *s;
+  unsigned long i,j,*lst,*ls;
+				/* sort by subject+date */
+  memset (&pgm,0,sizeof (SORTPGM));
+  memset (&pgm2,0,sizeof (SORTPGM));
+  pgm.function = SORTSUBJECT;
+  pgm.next = &pgm2;
+  pgm2.function = SORTDATE;
+  if (lst = (*sorter) (stream,charset,spg,&pgm,flags & ~(SE_FREE | SE_UID))){
+    if (*(ls = lst)) {		/* create thread */
+				/* note first subject */
+      cur = top = thr = mail_newthreadnode
+	((SORTCACHE *) (*mailcache) (stream,*ls++,CH_SORTCACHE));
+				/* note its number */
+      cur->num = (flags & SE_UID) ? mail_uid (stream,*lst) : *lst;
+      i = 1;			/* number of threads */
+      while (*ls) {		/* build tree */
+				/* subjects match? */
+	s = (SORTCACHE *) (*mailcache) (stream,*ls++,CH_SORTCACHE);
+	if (compare_cstring (top->sc->subject,s->subject)) {
+	  i++;			/* have a new thread */
+	  top = top->branch = cur = mail_newthreadnode (s);
+	}
+				/* start a child of the top */
+	else if (cur == top) cur = cur->next = mail_newthreadnode (s);
+				/* sibling of child */
+	else cur = cur->branch = mail_newthreadnode (s);
+				/* set to msgno or UID as needed */
+	cur->num = (flags & SE_UID) ? mail_uid (stream,s->num) : s->num;
+      }
+				/* make threadnode cache */
+      tc = (THREADNODE **) fs_get (i * sizeof (THREADNODE *));
+				/* load threadnode cache */
+      for (j = 0, cur = thr; cur; cur = cur->branch) tc[j++] = cur;
+      if (i != j) fatal ("Threadnode cache confusion");
+      qsort ((void *) tc,i,sizeof (THREADNODE *),mail_thread_compare_date);
+      for (j = 0, --i; j < i; j++) tc[j]->branch = tc[j+1];
+      tc[j]->branch = NIL;	/* end of root */
+      thr = tc[0];		/* head of data */
+      fs_give ((void **) &tc);
+    }
+    fs_give ((void **) &lst);
+  }
+  return thr;
+}
+
+/* Mail thread references
+ * Accepts: mail stream
+ *	    character set
+ *	    search program
+ *	    option flags
+ *	    sorter routine
+ * Returns: thread node tree
+ */
+
+#define REFHASHSIZE 1009	/* arbitrary prime for hash table size */
+
+/*  Reference threading container, as described in Jamie Zawinski's web page
+ * (http://www.jwz.org/doc/threading.html) for this algorithm.  These are
+ * stored as extended data in the hash table (called "id_table" in JWZ's
+ * document) and are maintained by the hash table routines.  The hash table
+ * routines implement extended data as additional void* words at the end of
+ * each bucket, hence these strange macros instead of a struct which would
+ * have been more straightforward.
+ */
+
+#define THREADLINKS 3		/* number of thread links */
+
+#define CACHE(data) ((SORTCACHE *) (data)[0])
+#define PARENT(data) ((container_t) (data)[1])
+#define SETPARENT(data,value) ((container_t) (data[1] = value))
+#define SIBLING(data) ((container_t) (data)[2])
+#define SETSIBLING(data,value) ((container_t) (data[2] = value))
+#define CHILD(data) ((container_t) (data)[3])
+#define SETCHILD(data,value) ((container_t) (data[3] = value))
+
+THREADNODE *mail_thread_references (MAILSTREAM *stream,char *charset,
+				    SEARCHPGM *spg,long flags,sorter_t sorter)
+{
+  MESSAGECACHE *elt,telt;
+  ENVELOPE *env;
+  SORTCACHE *s;
+  STRINGLIST *st;
+  HASHENT *he;
+  THREADNODE **tc,*cur,*lst,*nxt,*sis,*msg;
+  container_t con,nxc,prc,sib;
+  void **sub;
+  char *t,tmp[MAILTMPLEN];
+  unsigned long j,nmsgs;
+  unsigned long i = stream->nmsgs * sizeof (SORTCACHE *);
+  SORTCACHE **sc = (SORTCACHE **) memset (fs_get ((size_t) i),0,(size_t) i);
+  HASHTAB *ht = hash_create (REFHASHSIZE);
+  THREADNODE *root = NIL;
+  if (spg) {			/* only if a search needs to be done */
+    int silent = stream->silent;
+    stream->silent = T;		/* don't pass up mm_searched() events */
+				/* search for messages */
+    mail_search_full (stream,charset,spg,NIL);
+    stream->silent = silent;	/* restore silence state */
+  }
+
+				/* create SORTCACHE vector of requested msgs */
+  for (i = 1, nmsgs = 0; i <= stream->nmsgs; ++i)
+    if (mail_elt (stream,i)->searched)
+      (sc[nmsgs++] = (SORTCACHE *)(*mailcache)(stream,i,CH_SORTCACHE))->num =i;
+	/* separate pass so can do overview fetch lookahead */
+  for (i = 0; i < nmsgs; ++i) {	/* for each requested message */
+				/* is anything missing in its SORTCACHE? */
+    if (!((s = sc[i])->date && s->subject && s->message_id && s->references)) {
+				/* driver has an overview mechanism? */
+      if (stream->dtb && stream->dtb->overview) {
+				/* yes, find following unloaded entries */
+	for (j = i + 1; (j < nmsgs) && !sc[j]->references; ++j);
+	sprintf (tmp,"%lu",mail_uid (stream,s->num));
+	if (i != --j)		/* end of range different? */
+	  sprintf (tmp + strlen (tmp),":%lu",mail_uid (stream,sc[j]->num));
+				/* load via overview mechanism */
+	mail_fetch_overview (stream,tmp,mail_thread_loadcache);
+      }
+				/* still missing data? */
+      if (!s->date || !s->subject || !s->message_id || !s->references) {
+				/* try to load data from envelope */
+	if (env = mail_fetch_structure (stream,s->num,NIL,NIL)) {
+	  if (!s->date && env->date && mail_parse_date (&telt,env->date))
+	    s->date = mail_longdate (&telt);
+	  if (!s->subject && env->subject)
+	    s->refwd =
+	      mail_strip_subject (env->subject,&s->subject);
+	  if (!s->message_id && env->message_id && *env->message_id)
+	    s->message_id = mail_thread_parse_msgid (env->message_id,NIL);
+	  if (!s->references &&	/* use References: or In-Reply-To: */
+	      !(s->references = 
+		mail_thread_parse_references (env->references,T)))
+	    s->references = mail_thread_parse_references(env->in_reply_to,NIL);
+	}
+				/* last resort */
+	if (!s->date && !(s->date = s->arrival)) {
+				/* internal date unknown but can get? */
+	  if (!(elt = mail_elt (stream,s->num))->day &&
+	      !(stream->dtb->flags & DR_NOINTDATE)) {
+	    sprintf (tmp,"%lu",s->num);
+	    mail_fetch_fast (stream,tmp,NIL);
+	  }
+				/* wrong thing before 3-Jan-1970 */
+	  s->date = (s->arrival = elt->day ? mail_longdate (elt) : 1);
+	}
+	if (!s->subject) s->subject = cpystr ("");
+	if (!s->references) s->references = mail_newstringlist ();
+	s->dirty = T;
+      }
+    }
+
+			/* Step 1 (preliminary) */
+				/* generate unique string */
+    sprintf (tmp,"%s.%lx.%lx@%s",stream->mailbox,stream->uid_validity,
+	     mail_uid (stream,s->num),mylocalhost ());
+				/* flush old unique string if not message-id */
+    if (s->unique && (s->unique != s->message_id))
+      fs_give ((void **) &s->unique);
+    s->unique = s->message_id ?	/* don't permit Message ID duplicates */
+      (hash_lookup (ht,s->message_id) ? cpystr (tmp) : s->message_id) :
+	(s->message_id = cpystr (tmp));
+				/* add unique string to hash table */
+    hash_add (ht,s->unique,s,THREADLINKS);
+  }
+			/* Step 1 */
+  for (i = 0; i < nmsgs; ++i) {	/* for each message in sortcache */
+			/* Step 1A */
+    if ((st = (s = sc[i])->references) && st->text.data)
+      for (con = hash_lookup_and_add (ht,(char *) st->text.data,NIL,
+				      THREADLINKS); st = st->next; con = nxc) {
+	nxc = hash_lookup_and_add (ht,(char *) st->text.data,NIL,THREADLINKS);
+				/* only if no parent & won't introduce loop */
+	if (!PARENT (nxc) && !mail_thread_check_child (con,nxc)) {
+	  SETPARENT (nxc,con);	/* establish parent/child link */
+				/* other children become sibling of this one */
+	  SETSIBLING (nxc,CHILD (con));
+	  SETCHILD (con,nxc);	/* set as child of parent */
+	}
+      }
+    else con = NIL;		/* else message has no ancestors */
+			/* Step 1B */
+    if ((prc = PARENT ((nxc = hash_lookup (ht,s->unique)))) &&
+	(prc != con)) {		/* break links if have a different parent */
+      SETPARENT (nxc,NIL);	/* easy if direct child */
+      if (nxc == CHILD (prc)) SETCHILD (prc,SIBLING (nxc));
+      else {			/* otherwise hunt through sisters */
+	for (sib = CHILD (prc); nxc != SIBLING (sib); sib = SIBLING (sib));
+	SETSIBLING (sib,SIBLING (nxc));
+      }
+      SETSIBLING (nxc,NIL);	/* no more little sisters either */
+      prc = NIL;		/* no more parent set */
+    }
+				/* need to set parent, and parent is good? */
+    if (!prc && !mail_thread_check_child (con,nxc)) {
+      SETPARENT (nxc,con);	/* establish parent/child link */
+      if (con) {		/* if non-root parent, set parent's child */
+	if (CHILD (con)) {	/* have a child already */
+				/* find youngest daughter */
+	  for (con = CHILD (con); SIBLING (con); con = SIBLING (con));
+	  SETSIBLING (con,nxc);	/* add new baby sister */
+	}
+	else SETCHILD (con,nxc);/* set as only child */
+      }
+    }
+  }
+  fs_give ((void **) &sc);	/* finished with sortcache vector */
+
+			/* Step 2 */
+				/* search hash table for parentless messages */
+  for (i = 0, prc = con = NIL; i < ht->size; i++)
+    for (he = ht->table[i]; he; he = he->next)
+      if (!PARENT ((nxc = he->data))) {
+				/* sibling of previous parentless message */
+	if (con) con = SETSIBLING (con,nxc);
+	else prc = con = nxc;	/* first parentless message */
+      }
+  /*  Once the dummy containers are pruned, we no longer need the parent
+   * information, so we can convert the containers to THREADNODEs.  Since
+   * we don't need the id_table any more either, we can reset the hash table
+   * and reuse it as a subject_table.  Resetting the hash table will also
+   * destroy the containers.
+   */
+			/* Step 3 */
+				/* prune dummies, convert to threadnode */
+  root = mail_thread_c2node (stream,mail_thread_prune_dummy (prc,NIL),flags);
+			/* Step 4 */
+				/* make buffer for sorting */
+  tc = (THREADNODE **) fs_get (nmsgs * sizeof (THREADNODE *));
+				/* load threadcache and count nodes to sort */
+  for (i = 0, cur = root; cur ; cur = cur->branch) tc[i++] = cur;
+  if (i > 1) {			/* only if need to sort */
+    qsort ((void *) tc,i,sizeof (THREADNODE *),mail_thread_compare_date);
+				/* relink siblings */
+    for (j = 0, --i; j < i; j++) tc[j]->branch = tc[j+1];
+    tc[j]->branch = NIL;	/* end of root */
+    root = tc[0];		/* establish new root */
+  }
+			/* Step 5A */
+  hash_reset (ht);		/* discard containers, reset ht */
+			/* Step 5B */
+  for (cur = root; cur; cur = cur->branch)
+    if ((t = (nxt = (cur->sc ? cur : cur->next))->sc->subject) && *t) {
+				/* add new subject to hash table */
+      if (!(sub = hash_lookup (ht,t))) hash_add (ht,t,cur,0);
+				/* if one in table not dummy and */
+      else if ((s = (lst = (THREADNODE *) sub[0])->sc) &&
+				/* current dummy, or not re/fwd and table is */
+	       (!cur->sc || (!nxt->sc->refwd && s->refwd)))
+	sub[0] = (void *) cur;	/* replace with this message */
+    }
+
+			/* Step 5C */
+  for (cur = root, sis = NIL; cur; cur = msg) {
+				/* do nothing if current message or no sub */
+    if (!(t = (cur->sc ? cur : cur->next)->sc->subject) || !*t ||
+	((lst = (THREADNODE *) (sub = hash_lookup (ht,t))[0]) == cur))
+      msg = (sis = cur)->branch;
+    else if (!lst->sc) {	/* is message in the table a dummy? */
+				/* find youngest daughter of msg in table */
+      for (msg = lst->next; msg->branch; msg = msg->branch);
+      if (!cur->sc) {		/* current message a dummy? */
+	msg->branch = cur->next;/* current's daughter now dummy's youngest */
+	msg = cur->branch;	/* continue scan at younger sister */
+				/* now delete this node */
+	cur->branch = cur->next = NIL;
+	mail_free_threadnode (&cur);
+      }
+      else {			/* current message not a dummy */
+	msg->branch = cur;	/* append as youngest daughter */
+	msg = cur->branch;	/* continue scan at younger sister */
+	cur->branch = NIL;	/* lose our younger sisters */
+      }
+    }
+    else {			/* no dummies, is current re/fwd, table not? */
+      if (cur->sc->refwd && !lst->sc->refwd) {
+	if (lst->next) {	/* find youngest daughter of msg in table */
+	  for (msg = lst->next; msg->branch; msg = msg->branch);
+	  msg->branch = cur;	/* append as youngest daughter */
+	}
+	else lst->next = cur;	/* no children, so make the eldest daughter */
+      }
+
+      else {			/* no re/fwd, create a new dummy */
+	msg = mail_newthreadnode (NIL);
+	if (lst == root) {	/* msg in table is root? */
+	  root = lst->branch;	/* younger sister becomes new root */
+				/* no longer older sister either */
+	  if (lst == sis) sis = NIL;
+	}
+	else {			/* find older sister of msg in table */
+	  for (nxt = root; lst != nxt->branch; nxt = nxt->branch);
+				/* remove from older sister */
+	  nxt->branch = lst->branch;
+	}
+	msg->next = lst;	/* msg in table becomes child */
+	lst->branch = cur;	/* current now little sister of msg in table */
+	if (sis) {		/* have an elder sister? */
+	  if (sis == lst)	/* rescan if lost her */
+	    for (sis = root; cur != sis->branch; sis = sis->branch);
+	  sis->branch = msg;	/* make dummy younger sister of big sister */
+	}
+	else root = msg;	/* otherwise this is the new root */
+	sub[0] = sis = msg;	/* set new msg in table and new big sister */
+      }
+      msg = cur->branch;	/* continue scan at younger sister */
+      cur->branch = NIL;	/* lose our younger sisters */
+    }
+    if (sis) sis->branch = msg;	/* older sister gets this as younger sister */
+    else root = msg;		/* otherwise this is the new root */
+  }
+  hash_destroy (&ht);		/* finished with hash table */
+			/* Step 6 */
+				/* sort threads */
+  root = mail_thread_sort (root,tc);
+  fs_give ((void **) &tc);	/* finished with sort buffer */
+  return root;			/* return sorted list */
+}
+
+/* Fetch overview callback to load sortcache for threading
+ * Accepts: MAIL stream
+ *	    UID of this message
+ *	    overview of this message
+ *	    msgno of this message
+ */
+
+void mail_thread_loadcache (MAILSTREAM *stream,unsigned long uid,OVERVIEW *ov,
+			    unsigned long msgno)
+{
+  if (msgno && ov) {		/* just in case */
+    MESSAGECACHE telt;
+    SORTCACHE *s = (SORTCACHE *) (*mailcache) (stream,msgno,CH_SORTCACHE);
+    if (!s->subject && ov->subject) {
+      s->refwd = mail_strip_subject (ov->subject,&s->subject);
+      s->dirty = T;
+    }
+    if (!s->from && ov->from && ov->from->mailbox) {
+      s->from = cpystr (ov->from->mailbox);
+      s->dirty = T;
+    }
+    if (!s->date && ov->date && mail_parse_date (&telt,ov->date)) {
+      s->date = mail_longdate (&telt);
+      s->dirty = T;
+    }
+    if (!s->message_id && ov->message_id) {
+      s->message_id = mail_thread_parse_msgid (ov->message_id,NIL);
+      s->dirty = T;
+    }
+    if (!s->references &&
+	!(s->references = mail_thread_parse_references (ov->references,T))) {
+				/* don't do In-Reply-To with NNTP mailboxes */
+      s->references = mail_newstringlist ();
+      s->dirty = T;
+    }
+    if (!s->size && ov->optional.octets) {
+      s->size = ov->optional.octets;
+      s->dirty = T;
+    }
+  }
+}
+
+/* Thread parse Message ID
+ * Accepts: pointer to purported Message ID
+ *	    pointer to return pointer
+ * Returns: Message ID or NIL, return pointer updated
+ */
+
+char *mail_thread_parse_msgid (char *s,char **ss)
+{
+  char *ret = NIL;
+  char *t = NIL;
+  ADDRESS *adr;
+  if (s) {			/* only for non-NIL strings */
+    rfc822_skipws (&s);		/* skip whitespace */
+				/* ignore phrases */
+    if (((*s == '<') || (s = rfc822_parse_phrase (s))) &&
+	(adr = rfc822_parse_routeaddr (s,&t,BADHOST))) {
+				/* make return msgid */
+      if (adr->mailbox && adr->host)
+	sprintf (ret = (char *) fs_get (strlen (adr->mailbox) +
+					strlen (adr->host) + 2),"%s@%s",
+		 adr->mailbox,adr->host);
+      mail_free_address (&adr);	/* don't need temporary address */
+    }
+  }
+  if (ss) *ss = t;		/* update return pointer */
+  return ret;
+}
+
+
+/* Thread parse references
+ * Accepts: pointer to purported references
+ *	    parse multiple references flag
+ * Returns: references or NIL
+ */
+
+STRINGLIST *mail_thread_parse_references (char *s,long flag)
+{
+  char *t;
+  STRINGLIST *ret = NIL;
+  STRINGLIST *cur;
+				/* found first reference? */
+  if (t = mail_thread_parse_msgid (s,&s)) {
+    (ret = mail_newstringlist ())->text.data = (unsigned char *) t;
+    ret->text.size = strlen (t);
+    if (flag)			/* parse subsequent references */
+      for (cur = ret; t = mail_thread_parse_msgid (s,&s); cur = cur->next) {
+	(cur->next = mail_newstringlist ())->text.data = (unsigned char *) t;
+	cur->next->text.size = strlen (t);
+      }
+  }
+  return ret;
+}
+
+/* Prune dummy messages
+ * Accepts: candidate container to prune
+ *	    older sibling of container, if any
+ * Returns: container in this position, possibly pruned
+ * All children and younger siblings are also pruned
+ */
+
+container_t mail_thread_prune_dummy (container_t msg,container_t ane)
+{
+				/* prune container and children */
+  container_t ret = msg ? mail_thread_prune_dummy_work (msg,ane) : NIL;
+				/* prune all younger sisters */
+  if (ret) for (ane = ret; ane && (msg = SIBLING (ane)); ane = msg)
+    msg = mail_thread_prune_dummy_work (msg,ane);
+  return ret;
+}
+
+
+/* Prune dummy messages worker routine
+ * Accepts: candidate container to prune
+ *	    older sibling of container, if any
+ * Returns: container in this position, possibly pruned
+ * All children are also pruned
+ */
+
+container_t mail_thread_prune_dummy_work (container_t msg,container_t ane)
+{
+  container_t cur;
+				/* get children, if any */
+  container_t nxt = mail_thread_prune_dummy (CHILD (msg),NIL);
+				/* just update children if container has msg */
+  if (CACHE (msg)) SETCHILD (msg,nxt);
+  else if (!nxt) {		/* delete dummy with no children */
+    nxt = SIBLING (msg);	/* get younger sister */
+    if (ane) SETSIBLING (ane,nxt);
+				/* prune younger sister if exists */
+    msg = nxt ? mail_thread_prune_dummy_work (nxt,ane) : NIL;
+  }
+				/* not if parent root & multiple children */
+  else if ((cur = PARENT (msg)) || !SIBLING (nxt)) {
+				/* OK to promote, try younger sister of aunt */
+    if (ane) SETSIBLING (ane,nxt);
+				/* otherwise promote to child of grandmother */
+    else if (cur) SETCHILD (cur,nxt);
+    SETPARENT (nxt,cur);	/* set parent as well */
+				/* look for end of siblings in new container */
+    for (cur = nxt; SIBLING (cur); cur = SIBLING (cur));
+				/* reattach deleted container's siblings */
+    SETSIBLING (cur,SIBLING (msg));
+				/* prune and return new container */
+    msg = mail_thread_prune_dummy_work (nxt,ane);
+  }
+  else SETCHILD (msg,nxt);	/* in case child pruned */
+  return msg;			/* return this message */
+}
+
+/* Test that purported mother is not a child of purported daughter
+ * Accepts: mother
+ *	    purported daugher
+ * Returns: T if circular parentage exists, else NIL
+ */
+
+long mail_thread_check_child (container_t mother,container_t daughter)
+{
+  if (mother) {			/* only if mother non-NIL */
+    if (mother == daughter) return T;
+    for (daughter = CHILD (daughter); daughter; daughter = SIBLING (daughter))
+      if (mail_thread_check_child (mother,daughter)) return T;
+  }
+  return NIL;
+}
+
+
+/* Generate threadnodes from containers
+ * Accepts: Mail stream
+ *	    container
+ *	    flags
+ * Return: threadnode list
+ */
+
+THREADNODE *mail_thread_c2node (MAILSTREAM *stream,container_t con,long flags)
+{
+  THREADNODE *ret,*cur;
+  SORTCACHE *s;
+  container_t nxt;
+				/* for each container */
+  for (ret = cur = NIL; con; con = SIBLING (con)) {
+    s = CACHE (con);		/* yes, get its sortcache */
+				/* create node for it */
+    if (ret) cur = cur->branch = mail_newthreadnode (s);
+    else ret = cur = mail_newthreadnode (s);
+				/* attach sequence or UID for non-dummy */
+    if (s) cur->num = (flags & SE_UID) ? mail_uid (stream,s->num) : s->num;
+				/* attach the children */
+    if (nxt = CHILD (con)) cur->next = mail_thread_c2node (stream,nxt,flags);
+  }
+  return ret;
+}
+
+/* Sort thread tree by date
+ * Accepts: thread tree to sort
+ *	    qsort vector to sort
+ * Returns: sorted thread tree
+ */
+
+THREADNODE *mail_thread_sort (THREADNODE *thr,THREADNODE **tc)
+{
+  unsigned long i,j;
+  THREADNODE *cur;
+				/* sort children of each thread */
+  for (cur = thr; cur; cur = cur->branch)
+    if (cur->next) cur->next = mail_thread_sort (cur->next,tc);
+  /* Must do this in a separate pass since recursive call will clobber tc */
+				/* load threadcache and count nodes to sort */
+  for (i = 0, cur = thr; cur; cur = cur->branch) tc[i++] = cur;
+  if (i > 1) {			/* only if need to sort */
+    qsort ((void *) tc,i,sizeof (THREADNODE *),mail_thread_compare_date);
+				/* relink root siblings */
+    for (j = 0, --i; j < i; j++) tc[j]->branch = tc[j+1];
+    tc[j]->branch = NIL;	/* end of root */
+  }
+  return i ? tc[0] : NIL;	/* return new head of list */
+}
+
+
+/* Thread compare date
+ * Accept: first message sort cache element
+ *	   second message sort cache element
+ * Returns: -1 if a1 < a2, 1 if a1 > a2
+ *
+ * This assumes that a sort cache element is either a message (with a
+ * sortcache entry) or a dummy with a message (with sortcache entry) child.
+ * This is true of both the ORDEREDSUBJECT (no dummies) and REFERENCES
+ * (dummies only at top-level, and with non-dummy children).
+ *
+ * If a new algorithm allows a dummy parent to have a dummy child, this
+ * routine must be changed if it is to be used by that algorithm.
+ *
+ * Messages with bogus dates are always sorted at the top.
+ */
+
+int mail_thread_compare_date (const void *a1,const void *a2)
+{
+  THREADNODE *t1 = *(THREADNODE **) a1;
+  THREADNODE *t2 = *(THREADNODE **) a2;
+  SORTCACHE *s1 = t1->sc ? t1->sc : t1->next->sc;
+  SORTCACHE *s2 = t2->sc ? t2->sc : t2->next->sc;
+  int ret = compare_ulong (s1->date,s2->date);
+				/* use number as final tie-breaker */
+  return ret ? ret : compare_ulong (s1->num,s2->num);
+}
+
+/* Mail parse sequence
+ * Accepts: mail stream
+ *	    sequence to parse
+ * Returns: T if parse successful, else NIL
+ */
+
+long mail_sequence (MAILSTREAM *stream,unsigned char *sequence)
+{
+  unsigned long i,j,x;
+  for (i = 1; i <= stream->nmsgs; i++) mail_elt (stream,i)->sequence = NIL;
+  while (sequence && *sequence){/* while there is something to parse */
+    if (*sequence == '*') {	/* maximum message */
+      if (stream->nmsgs) i = stream->nmsgs;
+      else {
+	MM_LOG ("No messages, so no maximum message number",ERROR);
+	return NIL;
+      }
+      sequence++;		/* skip past * */
+    }
+				/* parse and validate message number */
+    else if (!isdigit (*sequence)) {
+      MM_LOG ("Syntax error in sequence",ERROR);
+      return NIL;
+    }
+    else if (!(i = strtoul (sequence,(char **) &sequence,10)) ||
+	     (i > stream->nmsgs)) {
+      MM_LOG ("Sequence out of range",ERROR);
+      return NIL;
+    }
+    switch (*sequence) {	/* see what the delimiter is */
+    case ':':			/* sequence range */
+      if (*++sequence == '*') {	/* maximum message */
+	if (stream->nmsgs) j = stream->nmsgs;
+	else {
+	  MM_LOG ("No messages, so no maximum message number",ERROR);
+	  return NIL;
+	}
+	sequence++;		/* skip past * */
+      }
+				/* parse end of range */
+      else if (!(j = strtoul (sequence,(char **) &sequence,10)) ||
+	       (j > stream->nmsgs)) {
+	MM_LOG ("Sequence range invalid",ERROR);
+	return NIL;
+      }
+      if (*sequence && *sequence++ != ',') {
+	MM_LOG ("Sequence range syntax error",ERROR);
+	return NIL;
+      }
+      if (i > j) {		/* swap the range if backwards */
+	x = i; i = j; j = x;
+      }
+				/* mark each item in the sequence */
+      while (i <= j) mail_elt (stream,j--)->sequence = T;
+      break;
+    case ',':			/* single message */
+      ++sequence;		/* skip the delimiter, fall into end case */
+    case '\0':			/* end of sequence, mark this message */
+      mail_elt (stream,i)->sequence = T;
+      break;
+    default:			/* anything else is a syntax error! */
+      MM_LOG ("Sequence syntax error",ERROR);
+      return NIL;
+    }
+  }
+  return T;			/* successfully parsed sequence */
+}
+
+/* Parse flag list
+ * Accepts: MAIL stream
+ *	    flag list as a character string
+ *	    pointer to user flags to return
+ * Returns: system flags
+ */
+
+long mail_parse_flags (MAILSTREAM *stream,char *flag,unsigned long *uf)
+{
+  char *t,*n,*s,tmp[MAILTMPLEN],msg[MAILTMPLEN];
+  short f = 0;
+  long i,j;
+  *uf = 0;			/* initially no user flags */
+  if (flag && *flag) {		/* no-op if no flag string */
+				/* check if a list and make sure valid */
+    if (((i = (*flag == '(')) ^ (flag[strlen (flag)-1] == ')')) ||
+	(strlen (flag) >= MAILTMPLEN)) {
+      MM_LOG ("Bad flag list",ERROR);
+      return NIL;
+    }
+				/* copy the flag string w/o list construct */
+    strncpy (n = tmp,flag+i,(j = strlen (flag) - (2*i)));
+    tmp[j] = '\0';
+    while ((t = n) && *t) {	/* parse the flags */
+				/* find end of flag */
+      if (n = strchr (t,' ')) *n++ = '\0';
+      if (*t == '\\') {		/* system flag? */
+	if (!compare_cstring (t+1,"SEEN")) f |= fSEEN;
+	else if (!compare_cstring (t+1,"DELETED")) f |= fDELETED;
+	else if (!compare_cstring (t+1,"FLAGGED")) f |= fFLAGGED;
+	else if (!compare_cstring (t+1,"ANSWERED")) f |= fANSWERED;
+	else if (!compare_cstring (t+1,"DRAFT")) f |= fDRAFT;
+	else {
+	  sprintf (msg,"Unsupported system flag: %.80s",t);
+	  MM_LOG (msg,WARN);
+	}
+      }
+
+      else {			/* keyword flag */
+	for (i = j = 0;		/* user flag, search through table */
+	     !i && (j < NUSERFLAGS) && (s = stream->user_flags[j]); ++j)
+	  if (!compare_cstring (t,s)) *uf |= i = 1 << j;
+	if (!i) {		/* flag not found, can it be created? */
+	  if (stream->kwd_create && (j < NUSERFLAGS) && *t &&
+	      (strlen (t) <= MAXUSERFLAG)) {
+	    for (s = t; t && *s; s++) switch (*s) {
+	    default:		/* all other characters */
+				/* SPACE, CTL, or not CHAR */
+	      if ((*s > ' ') && (*s < 0x7f)) break;
+	    case '*': case '%':	/* list_wildcards */
+	    case '"': case '\\':/* quoted-specials */
+				/* atom_specials */
+	    case '(': case ')': case '{':
+	    case ']':		/* resp-specials */
+	      sprintf (msg,"Invalid flag: %.80s",t);
+	      MM_LOG (msg,WARN);
+	      t = NIL;
+	    }
+	    if (t) {		/* only if valid */
+	      *uf |= 1 << j;	/* set the bit */
+	      stream->user_flags[j] = cpystr (t);
+				/* if out of user flags */
+	      if (j == NUSERFLAGS - 1) stream->kwd_create = NIL;
+	    }
+	  }
+	  else {
+	    if (*t) sprintf (msg,"Unknown flag: %.80s",t);
+	    else strcpy (msg,"Empty flag invalid");
+	    MM_LOG (msg,WARN);
+	  }
+	}
+      }
+    }
+  }
+  return f;
+}
+
+/* Mail check network stream for usability with new name
+ * Accepts: MAIL stream
+ *	    candidate new name
+ * Returns: T if stream can be used, NIL otherwise
+ */
+
+long mail_usable_network_stream (MAILSTREAM *stream,char *name)
+{
+  NETMBX smb,nmb,omb;
+  return (stream && stream->dtb && !(stream->dtb->flags & DR_LOCAL) &&
+	  mail_valid_net_parse (name,&nmb) &&
+	  mail_valid_net_parse (stream->mailbox,&smb) &&
+	  mail_valid_net_parse (stream->original_mailbox,&omb) &&
+	  ((!compare_cstring (smb.host,
+			      trustdns ? tcp_canonical (nmb.host) : nmb.host)&&
+	    !strcmp (smb.service,nmb.service) &&
+	    (!nmb.port || (smb.port == nmb.port)) &&
+	    (nmb.anoflag == stream->anonymous) &&
+	    (!nmb.user[0] || !strcmp (smb.user,nmb.user))) ||
+	   (!compare_cstring (omb.host,nmb.host) &&
+	    !strcmp (omb.service,nmb.service) &&
+	    (!nmb.port || (omb.port == nmb.port)) &&
+	    (nmb.anoflag == stream->anonymous) &&
+	    (!nmb.user[0] || !strcmp (omb.user,nmb.user))))) ? LONGT : NIL;
+}
+
+/* Mail data structure instantiation routines */
+
+
+/* Mail instantiate cache elt
+ * Accepts: initial message number
+ * Returns: new cache elt
+ */
+
+MESSAGECACHE *mail_new_cache_elt (unsigned long msgno)
+{
+  MESSAGECACHE *elt = (MESSAGECACHE *) memset (fs_get (sizeof (MESSAGECACHE)),
+					       0,sizeof (MESSAGECACHE));
+  elt->lockcount = 1;		/* initially only cache references it */
+  elt->msgno = msgno;		/* message number */
+  return elt;
+}
+
+
+/* Mail instantiate envelope
+ * Returns: new envelope
+ */
+
+ENVELOPE *mail_newenvelope (void)
+{
+  return (ENVELOPE *) memset (fs_get (sizeof (ENVELOPE)),0,sizeof (ENVELOPE));
+}
+
+
+/* Mail instantiate address
+ * Returns: new address
+ */
+
+ADDRESS *mail_newaddr (void)
+{
+  return (ADDRESS *) memset (fs_get (sizeof (ADDRESS)),0,sizeof (ADDRESS));
+}
+
+/* Mail instantiate body
+ * Returns: new body
+ */
+
+BODY *mail_newbody (void)
+{
+  return mail_initbody ((BODY *) fs_get (sizeof (BODY)));
+}
+
+
+/* Mail initialize body
+ * Accepts: body
+ * Returns: body
+ */
+
+BODY *mail_initbody (BODY *body)
+{
+  memset ((void *) body,0,sizeof (BODY));
+  body->type = TYPETEXT;	/* content type */
+  body->encoding = ENC7BIT;	/* content encoding */
+  return body;
+}
+
+
+/* Mail instantiate body parameter
+ * Returns: new body part
+ */
+
+PARAMETER *mail_newbody_parameter (void)
+{
+  return (PARAMETER *) memset (fs_get (sizeof(PARAMETER)),0,sizeof(PARAMETER));
+}
+
+
+/* Mail instantiate body part
+ * Returns: new body part
+ */
+
+PART *mail_newbody_part (void)
+{
+  PART *part = (PART *) memset (fs_get (sizeof (PART)),0,sizeof (PART));
+  mail_initbody (&part->body);	/* initialize the body */
+  return part;
+}
+
+
+/* Mail instantiate body message part
+ * Returns: new body message part
+ */
+
+MESSAGE *mail_newmsg (void)
+{
+  return (MESSAGE *) memset (fs_get (sizeof (MESSAGE)),0,sizeof (MESSAGE));
+}
+
+/* Mail instantiate string list
+ * Returns: new string list
+ */
+
+STRINGLIST *mail_newstringlist (void)
+{
+  return (STRINGLIST *) memset (fs_get (sizeof (STRINGLIST)),0,
+				sizeof (STRINGLIST));
+}
+
+
+/* Mail instantiate new search program
+ * Returns: new search program
+ */
+
+SEARCHPGM *mail_newsearchpgm (void)
+{
+  return (SEARCHPGM *) memset (fs_get (sizeof(SEARCHPGM)),0,sizeof(SEARCHPGM));
+}
+
+
+/* Mail instantiate new search program
+ * Accepts: header line name   
+ * Returns: new search program
+ */
+
+SEARCHHEADER *mail_newsearchheader (char *line,char *text)
+{
+  SEARCHHEADER *hdr = (SEARCHHEADER *) memset (fs_get (sizeof (SEARCHHEADER)),
+					       0,sizeof (SEARCHHEADER));
+  hdr->line.size = strlen ((char *) (hdr->line.data =
+				     (unsigned char *) cpystr (line)));
+  hdr->text.size = strlen ((char *) (hdr->text.data =
+				     (unsigned char *) cpystr (text)));
+  return hdr;
+}
+
+
+/* Mail instantiate new search set
+ * Returns: new search set
+ */
+
+SEARCHSET *mail_newsearchset (void)
+{
+  return (SEARCHSET *) memset (fs_get (sizeof(SEARCHSET)),0,sizeof(SEARCHSET));
+}
+
+
+/* Mail instantiate new search or
+ * Returns: new search or
+ */
+
+SEARCHOR *mail_newsearchor (void)
+{
+  SEARCHOR *or = (SEARCHOR *) memset (fs_get (sizeof (SEARCHOR)),0,
+				      sizeof (SEARCHOR));
+  or->first = mail_newsearchpgm ();
+  or->second = mail_newsearchpgm ();
+  return or;
+}
+
+/* Mail instantiate new searchpgmlist
+ * Returns: new searchpgmlist
+ */
+
+SEARCHPGMLIST *mail_newsearchpgmlist (void)
+{
+  SEARCHPGMLIST *pgl = (SEARCHPGMLIST *)
+    memset (fs_get (sizeof (SEARCHPGMLIST)),0,sizeof (SEARCHPGMLIST));
+  pgl->pgm = mail_newsearchpgm ();
+  return pgl;
+}
+
+
+/* Mail instantiate new sortpgm
+ * Returns: new sortpgm
+ */
+
+SORTPGM *mail_newsortpgm (void)
+{
+  return (SORTPGM *) memset (fs_get (sizeof (SORTPGM)),0,sizeof (SORTPGM));
+}
+
+
+/* Mail instantiate new threadnode
+ * Accepts: sort cache for thread node
+ * Returns: new threadnode
+ */
+
+THREADNODE *mail_newthreadnode (SORTCACHE *sc)
+{
+  THREADNODE *thr = (THREADNODE *) memset (fs_get (sizeof (THREADNODE)),0,
+					   sizeof (THREADNODE));
+  if (sc) thr->sc = sc;		/* initialize sortcache */
+  return thr;
+}
+
+
+/* Mail instantiate new acllist
+ * Returns: new acllist
+ */
+
+ACLLIST *mail_newacllist (void)
+{
+  return (ACLLIST *) memset (fs_get (sizeof (ACLLIST)),0,sizeof (ACLLIST));
+}
+
+
+/* Mail instantiate new quotalist
+ * Returns: new quotalist
+ */
+
+QUOTALIST *mail_newquotalist (void)
+{
+  return (QUOTALIST *) memset (fs_get (sizeof (QUOTALIST)),0,
+			       sizeof (QUOTALIST));
+}
+
+/* Mail garbage collection routines */
+
+
+/* Mail garbage collect body
+ * Accepts: pointer to body pointer
+ */
+
+void mail_free_body (BODY **body)
+{
+  if (*body) {			/* only free if exists */
+    mail_free_body_data (*body);/* free its data */
+    fs_give ((void **) body);	/* return body to free storage */
+  }
+}
+
+
+/* Mail garbage collect body data
+ * Accepts: body pointer
+ */
+
+void mail_free_body_data (BODY *body)
+{
+  switch (body->type) {		/* free contents */
+  case TYPEMULTIPART:		/* multiple part */
+    mail_free_body_part (&body->nested.part);
+    break;
+  case TYPEMESSAGE:		/* encapsulated message */
+    if (body->subtype && !strcmp (body->subtype,"RFC822")) {
+      mail_free_stringlist (&body->nested.msg->lines);
+      mail_gc_msg (body->nested.msg,GC_ENV | GC_TEXTS);
+    }
+    if (body->nested.msg) fs_give ((void **) &body->nested.msg);
+    break;
+  default:
+    break;
+  }
+  if (body->subtype) fs_give ((void **) &body->subtype);
+  mail_free_body_parameter (&body->parameter);
+  if (body->id) fs_give ((void **) &body->id);
+  if (body->description) fs_give ((void **) &body->description);
+  if (body->disposition.type) fs_give ((void **) &body->disposition.type);
+  if (body->disposition.parameter)
+    mail_free_body_parameter (&body->disposition.parameter);
+  if (body->language) mail_free_stringlist (&body->language);
+  if (body->location) fs_give ((void **) &body->location);
+  if (body->mime.text.data) fs_give ((void **) &body->mime.text.data);
+  if (body->contents.text.data) fs_give ((void **) &body->contents.text.data);
+  if (body->md5) fs_give ((void **) &body->md5);
+  if (mailfreebodysparep && body->sparep)
+      (*mailfreebodysparep) (&body->sparep);
+}
+
+/* Mail garbage collect body parameter
+ * Accepts: pointer to body parameter pointer
+ */
+
+void mail_free_body_parameter (PARAMETER **parameter)
+{
+  if (*parameter) {		/* only free if exists */
+    if ((*parameter)->attribute) fs_give ((void **) &(*parameter)->attribute);
+    if ((*parameter)->value) fs_give ((void **) &(*parameter)->value);
+				/* run down the list as necessary */
+    mail_free_body_parameter (&(*parameter)->next);
+				/* return body part to free storage */
+    fs_give ((void **) parameter);
+  }
+}
+
+
+/* Mail garbage collect body part
+ * Accepts: pointer to body part pointer
+ */
+
+void mail_free_body_part (PART **part)
+{
+  if (*part) {			/* only free if exists */
+    mail_free_body_data (&(*part)->body);
+				/* run down the list as necessary */
+    mail_free_body_part (&(*part)->next);
+    fs_give ((void **) part);	/* return body part to free storage */
+  }
+}
+
+/* Mail garbage collect message cache
+ * Accepts: mail stream
+ *
+ * The message cache is set to NIL when this function finishes.
+ */
+
+void mail_free_cache (MAILSTREAM *stream)
+{
+				/* do driver specific stuff first */
+  mail_gc (stream,GC_ELT | GC_ENV | GC_TEXTS);
+				/* flush the cache */
+  (*mailcache) (stream,(long) 0,CH_INIT);
+}
+
+
+/* Mail garbage collect cache element
+ * Accepts: pointer to cache element pointer
+ */
+
+void mail_free_elt (MESSAGECACHE **elt)
+{
+				/* only free if exists and no sharers */
+  if (*elt && !--(*elt)->lockcount) {
+    mail_gc_msg (&(*elt)->private.msg,GC_ENV | GC_TEXTS);
+    if (mailfreeeltsparep && (*elt)->sparep)
+      (*mailfreeeltsparep) (&(*elt)->sparep);
+    fs_give ((void **) elt);
+  }
+  else *elt = NIL;		/* else simply drop pointer */
+}
+
+/* Mail garbage collect envelope
+ * Accepts: pointer to envelope pointer
+ */
+
+void mail_free_envelope (ENVELOPE **env)
+{
+  if (*env) {			/* only free if exists */
+    if ((*env)->remail) fs_give ((void **) &(*env)->remail);
+    mail_free_address (&(*env)->return_path);
+    if ((*env)->date) fs_give ((void **) &(*env)->date);
+    mail_free_address (&(*env)->from);
+    mail_free_address (&(*env)->sender);
+    mail_free_address (&(*env)->reply_to);
+    if ((*env)->subject) fs_give ((void **) &(*env)->subject);
+    mail_free_address (&(*env)->to);
+    mail_free_address (&(*env)->cc);
+    mail_free_address (&(*env)->bcc);
+    if ((*env)->in_reply_to) fs_give ((void **) &(*env)->in_reply_to);
+    if ((*env)->message_id) fs_give ((void **) &(*env)->message_id);
+    if ((*env)->newsgroups) fs_give ((void **) &(*env)->newsgroups);
+    if ((*env)->followup_to) fs_give ((void **) &(*env)->followup_to);
+    if ((*env)->references) fs_give ((void **) &(*env)->references);
+    if (mailfreeenvelopesparep && (*env)->sparep)
+      (*mailfreeenvelopesparep) (&(*env)->sparep);
+    fs_give ((void **) env);	/* return envelope to free storage */
+  }
+}
+
+
+/* Mail garbage collect address
+ * Accepts: pointer to address pointer
+ */
+
+void mail_free_address (ADDRESS **address)
+{
+  if (*address) {		/* only free if exists */
+    if ((*address)->personal) fs_give ((void **) &(*address)->personal);
+    if ((*address)->adl) fs_give ((void **) &(*address)->adl);
+    if ((*address)->mailbox) fs_give ((void **) &(*address)->mailbox);
+    if ((*address)->host) fs_give ((void **) &(*address)->host);
+    if ((*address)->error) fs_give ((void **) &(*address)->error);
+    if ((*address)->orcpt.type) fs_give ((void **) &(*address)->orcpt.type);
+    if ((*address)->orcpt.addr) fs_give ((void **) &(*address)->orcpt.addr);
+    mail_free_address (&(*address)->next);
+    fs_give ((void **) address);/* return address to free storage */
+  }
+}
+
+
+/* Mail garbage collect stringlist
+ * Accepts: pointer to stringlist pointer
+ */
+
+void mail_free_stringlist (STRINGLIST **string)
+{
+  if (*string) {		/* only free if exists */
+    if ((*string)->text.data) fs_give ((void **) &(*string)->text.data);
+    mail_free_stringlist (&(*string)->next);
+    fs_give ((void **) string);	/* return string to free storage */
+  }
+}
+
+/* Mail garbage collect searchpgm
+ * Accepts: pointer to searchpgm pointer
+ */
+
+void mail_free_searchpgm (SEARCHPGM **pgm)
+{
+  if (*pgm) {			/* only free if exists */
+    mail_free_searchset (&(*pgm)->msgno);
+    mail_free_searchset (&(*pgm)->uid);
+    mail_free_searchor (&(*pgm)->or);
+    mail_free_searchpgmlist (&(*pgm)->not);
+    mail_free_searchheader (&(*pgm)->header);
+    mail_free_stringlist (&(*pgm)->bcc);
+    mail_free_stringlist (&(*pgm)->body);
+    mail_free_stringlist (&(*pgm)->cc);
+    mail_free_stringlist (&(*pgm)->from);
+    mail_free_stringlist (&(*pgm)->keyword);
+    mail_free_stringlist (&(*pgm)->subject);
+    mail_free_stringlist (&(*pgm)->text);
+    mail_free_stringlist (&(*pgm)->to);
+    fs_give ((void **) pgm);	/* return program to free storage */
+  }
+}
+
+
+/* Mail garbage collect searchheader
+ * Accepts: pointer to searchheader pointer
+ */
+
+void mail_free_searchheader (SEARCHHEADER **hdr)
+{
+  if (*hdr) {			/* only free if exists */
+    if ((*hdr)->line.data) fs_give ((void **) &(*hdr)->line.data);
+    if ((*hdr)->text.data) fs_give ((void **) &(*hdr)->text.data);
+    mail_free_searchheader (&(*hdr)->next);
+    fs_give ((void **) hdr);	/* return header to free storage */
+  }
+}
+
+
+/* Mail garbage collect searchset
+ * Accepts: pointer to searchset pointer
+ */
+
+void mail_free_searchset (SEARCHSET **set)
+{
+  if (*set) {			/* only free if exists */
+    mail_free_searchset (&(*set)->next);
+    fs_give ((void **) set);	/* return set to free storage */
+  }
+}
+
+/* Mail garbage collect searchor
+ * Accepts: pointer to searchor pointer
+ */
+
+void mail_free_searchor (SEARCHOR **orl)
+{
+  if (*orl) {			/* only free if exists */
+    mail_free_searchpgm (&(*orl)->first);
+    mail_free_searchpgm (&(*orl)->second);
+    mail_free_searchor (&(*orl)->next);
+    fs_give ((void **) orl);	/* return searchor to free storage */
+  }
+}
+
+
+/* Mail garbage collect search program list
+ * Accepts: pointer to searchpgmlist pointer
+ */
+
+void mail_free_searchpgmlist (SEARCHPGMLIST **pgl)
+{
+  if (*pgl) {			/* only free if exists */
+    mail_free_searchpgm (&(*pgl)->pgm);
+    mail_free_searchpgmlist (&(*pgl)->next);
+    fs_give ((void **) pgl);	/* return searchpgmlist to free storage */
+  }
+}
+
+
+/* Mail garbage collect namespace
+ * Accepts: poiner to namespace
+ */
+
+void mail_free_namespace (NAMESPACE **n)
+{
+  if (*n) {
+    fs_give ((void **) &(*n)->name);
+    mail_free_namespace (&(*n)->next);
+    mail_free_body_parameter (&(*n)->param);
+    fs_give ((void **) n);	/* return namespace to free storage */
+  }
+}
+
+/* Mail garbage collect sort program
+ * Accepts: pointer to sortpgm pointer
+ */
+
+void mail_free_sortpgm (SORTPGM **pgm)
+{
+  if (*pgm) {			/* only free if exists */
+    mail_free_sortpgm (&(*pgm)->next);
+    fs_give ((void **) pgm);	/* return sortpgm to free storage */
+  }
+}
+
+
+/* Mail garbage collect thread node
+ * Accepts: pointer to threadnode pointer
+ */
+
+void mail_free_threadnode (THREADNODE **thr)
+{
+  if (*thr) {			/* only free if exists */
+    mail_free_threadnode (&(*thr)->branch);
+    mail_free_threadnode (&(*thr)->next);
+    fs_give ((void **) thr);	/* return threadnode to free storage */
+  }
+}
+
+
+/* Mail garbage collect acllist
+ * Accepts: pointer to acllist pointer
+ */
+
+void mail_free_acllist (ACLLIST **al)
+{
+  if (*al) {			/* only free if exists */
+    if ((*al)->identifier) fs_give ((void **) &(*al)->identifier);
+    if ((*al)->rights) fs_give ((void **) &(*al)->rights);
+    mail_free_acllist (&(*al)->next);
+    fs_give ((void **) al);	/* return acllist to free storage */
+  }
+}
+
+
+/* Mail garbage collect quotalist
+ * Accepts: pointer to quotalist pointer
+ */
+
+void mail_free_quotalist (QUOTALIST **ql)
+{
+  if (*ql) {			/* only free if exists */
+    if ((*ql)->name) fs_give ((void **) &(*ql)->name);
+    mail_free_quotalist (&(*ql)->next);
+    fs_give ((void **) ql);	/* return quotalist to free storage */
+  }
+}
+
+/* Link authenicator
+ * Accepts: authenticator to add to list
+ */
+
+void auth_link (AUTHENTICATOR *auth)
+{
+  if (!auth->valid || (*auth->valid) ()) {
+    AUTHENTICATOR **a = &mailauthenticators;
+    while (*a) a = &(*a)->next;	/* find end of list of authenticators */
+    *a = auth;			/* put authenticator at the end */
+    auth->next = NIL;		/* this authenticator is the end of the list */
+  }
+}
+
+
+/* Authenticate access
+ * Accepts: mechanism name
+ *	    responder function
+ *	    argument count
+ *	    argument vector
+ * Returns: authenticated user name or NIL
+ */
+
+char *mail_auth (char *mechanism,authresponse_t resp,int argc,char *argv[])
+{
+  AUTHENTICATOR *auth;
+  for (auth = mailauthenticators; auth; auth = auth->next)
+    if (auth->server && !compare_cstring (auth->name,mechanism))
+      return (!(auth->flags & AU_DISABLE) &&
+	      ((auth->flags & AU_SECURE) ||
+	       !mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL))) ?
+	(*auth->server) (resp,argc,argv) : NIL;
+  return NIL;			/* no authenticator found */
+}
+
+/* Lookup authenticator index
+ * Accepts: authenticator index
+ * Returns: authenticator, or 0 if not found
+ */
+
+AUTHENTICATOR *mail_lookup_auth (unsigned long i)
+{
+  AUTHENTICATOR *auth = mailauthenticators;
+  while (auth && --i) auth = auth->next;
+  return auth;
+}
+
+
+/* Lookup authenticator name
+ * Accepts: authenticator name
+ *	    required authenticator flags
+ * Returns: index in authenticator chain, or 0 if not found
+ */
+
+unsigned int mail_lookup_auth_name (char *mechanism,long flags)
+{
+  int i;
+  AUTHENTICATOR *auth;
+  for (i = 1, auth = mailauthenticators; auth; i++, auth = auth->next)
+    if (auth->client && !(flags & ~auth->flags) &&
+	!(auth->flags & AU_DISABLE) && !compare_cstring (auth->name,mechanism))
+      return i;
+  return 0;
+}
+
+/* Standard TCP/IP network driver */
+
+static NETDRIVER tcpdriver = {
+  tcp_open,			/* open connection */
+  tcp_aopen,			/* open preauthenticated connection */
+  tcp_getline,			/* get a line */
+  tcp_getbuffer,		/* get a buffer */
+  tcp_soutr,			/* output pushed data */
+  tcp_sout,			/* output string */
+  tcp_close,			/* close connection */
+  tcp_host,			/* return host name */
+  tcp_remotehost,		/* return remote host name */
+  tcp_port,			/* return port number */
+  tcp_localhost			/* return local host name */
+};
+
+
+/* Network open
+ * Accepts: NETMBX specifier to open
+ *	    default network driver
+ *	    default port
+ *	    SSL driver
+ *	    SSL service name
+ *	    SSL driver port
+ * Returns: Network stream if success, else NIL
+ */
+
+NETSTREAM *net_open (NETMBX *mb,NETDRIVER *dv,unsigned long port,
+		     NETDRIVER *ssld,char *ssls,unsigned long sslp)
+{
+  NETSTREAM *stream = NIL;
+  char tmp[MAILTMPLEN];
+  unsigned long flags = mb->novalidate ? NET_NOVALIDATECERT : 0;
+  if (strlen (mb->host) >= NETMAXHOST) {
+    sprintf (tmp,"Invalid host name: %.80s",mb->host);
+    MM_LOG (tmp,ERROR);
+  }
+				/* use designated driver if given */
+  else if (dv) stream = net_open_work (dv,mb->host,mb->service,port,mb->port,
+				       flags);
+  else if (mb->sslflag && ssld)	/* use ssl if sslflag lit */
+    stream = net_open_work (ssld,mb->host,ssls,sslp,mb->port,flags);
+				/* if trysslfirst and can open ssl... */
+  else if ((mb->trysslflag || trysslfirst) && ssld &&
+	   (stream = net_open_work (ssld,mb->host,ssls,sslp,mb->port,
+				    flags | NET_SILENT | NET_TRYSSL))) {
+    if (net_sout (stream,"",0)) mb->sslflag = T;
+    else {
+      net_close (stream);	/* flush fake SSL stream */
+      stream = NIL;
+    }
+  }
+				/* default to TCP driver */
+  else stream = net_open_work (&tcpdriver,mb->host,mb->service,port,mb->port,
+			       flags);
+  return stream;
+}
+
+/* Network open worker routine
+ * Accepts: network driver
+ *	    host name
+ *	    service name to look up port
+ *	    port number if service name not found
+ *	    port number to override service name
+ *	    flags (passed on top of port)
+ * Returns: Network stream if success, else NIL
+ */
+
+NETSTREAM *net_open_work (NETDRIVER *dv,char *host,char *service,
+			  unsigned long port,unsigned long portoverride,
+			  unsigned long flags)
+{
+  NETSTREAM *stream = NIL;
+  void *tstream;
+  if (service && (*service == '*')) {
+    flags |= NET_NOOPENTIMEOUT;	/* mark that no timeout is desired */
+    ++service;			/* no longer need the no timeout indicator */
+  }
+  if (portoverride) {		/* explicit port number? */
+    service = NIL;		/* yes, override service name */
+    port = portoverride;	/* use that instead of default port */
+  }
+  if (tstream = (*dv->open) (host,service,port | flags)) {
+    stream = (NETSTREAM *) fs_get (sizeof (NETSTREAM));
+    stream->stream = tstream;
+    stream->dtb = dv;
+  }
+  return stream;
+}
+
+
+/* Network authenticated open
+ * Accepts: network driver
+ *	    NETMBX specifier
+ *	    service specifier
+ *	    return user name buffer
+ * Returns: Network stream if success else NIL
+ */
+
+NETSTREAM *net_aopen (NETDRIVER *dv,NETMBX *mb,char *service,char *user)
+{
+  NETSTREAM *stream = NIL;
+  void *tstream;
+  if (!dv) dv = &tcpdriver;	/* default to TCP driver */
+  if (tstream = (*dv->aopen) (mb,service,user)) {
+    stream = (NETSTREAM *) fs_get (sizeof (NETSTREAM));
+    stream->stream = tstream;
+    stream->dtb = dv;
+  }
+  return stream;
+}
+
+/* Network receive line
+ * Accepts: Network stream
+ * Returns: text line string or NIL if failure
+ */
+
+char *net_getline (NETSTREAM *stream)
+{
+  return (*stream->dtb->getline) (stream->stream);
+}
+
+
+/* Network receive buffer
+ * Accepts: Network stream (must be void * for use as readfn_t)
+ *	    size in bytes
+ *	    buffer to read into
+ * Returns: T if success, NIL otherwise
+ */
+
+long net_getbuffer (void *st,unsigned long size,char *buffer)
+{
+  NETSTREAM *stream = (NETSTREAM *) st;
+  return (*stream->dtb->getbuffer) (stream->stream,size,buffer);
+}
+
+
+/* Network send null-terminated string
+ * Accepts: Network stream
+ *	    string pointer
+ * Returns: T if success else NIL
+ */
+
+long net_soutr (NETSTREAM *stream,char *string)
+{
+  return (*stream->dtb->soutr) (stream->stream,string);
+}
+
+
+/* Network send string
+ * Accepts: Network stream
+ *	    string pointer
+ *	    byte count
+ * Returns: T if success else NIL
+ */
+
+long net_sout (NETSTREAM *stream,char *string,unsigned long size)
+{
+  return (*stream->dtb->sout) (stream->stream,string,size);
+}
+
+/* Network close
+ * Accepts: Network stream
+ */
+
+void net_close (NETSTREAM *stream)
+{
+  if (stream->stream) (*stream->dtb->close) (stream->stream);
+  fs_give ((void **) &stream);
+}
+
+
+/* Network get host name
+ * Accepts: Network stream
+ * Returns: host name for this stream
+ */
+
+char *net_host (NETSTREAM *stream)
+{
+  return (*stream->dtb->host) (stream->stream);
+}
+
+
+/* Network get remote host name
+ * Accepts: Network stream
+ * Returns: host name for this stream
+ */
+
+char *net_remotehost (NETSTREAM *stream)
+{
+  return (*stream->dtb->remotehost) (stream->stream);
+}
+
+/* Network return port for this stream
+ * Accepts: Network stream
+ * Returns: port number for this stream
+ */
+
+unsigned long net_port (NETSTREAM *stream)
+{
+  return (*stream->dtb->port) (stream->stream);
+}
+
+
+/* Network get local host name
+ * Accepts: Network stream
+ * Returns: local host name
+ */
+
+char *net_localhost (NETSTREAM *stream)
+{
+  return (*stream->dtb->localhost) (stream->stream);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/mail.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1837 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Mailbox Access routines
+ *
+ * Author:	Mark Crispin
+ *		UW Technology
+ *		University of Washington
+ *		Seattle, WA  98195
+ *		Internet: MRC@Washington.EDU
+ *
+ * Date:	22 November 1989
+ * Last Edited:	16 December 2008
+ */
+
+/* The Version */
+
+#define CCLIENTVERSION "2007e"
+
+/* Build parameters */
+
+#define CACHEINCREMENT 250	/* cache growth increments */
+#define MAILTMPLEN 1024		/* size of a temporary buffer */
+#define SENDBUFLEN 16385	/* size of temporary sending buffer, also
+				 * used for SMTP commands and NETMBX generation
+				 * buffer so shouldn't be made smaller than
+				 * MAILTMPLEN.  Note that there's a guard byte,
+				 * so this is actually len+1. */
+#define MAXAUTHENTICATORS 8	/* maximum number of SASL authenticators */
+				/* maximum number of messages */
+#define MAXMESSAGES (unsigned long) 1000000
+#define MAXLOGINTRIALS 3	/* maximum number of client login attempts */
+#define MAXWILDCARDS 10		/* maximum wildcards allowed in LIST/LSUB */
+
+
+/* These can't be changed without changing code */
+
+#define NUSERFLAGS 30		/* maximum number of user flags */
+#define MAXUSERFLAG 50		/* maximum length of a user flag */
+#define BASEYEAR 1970		/* the year time began on Unix DON'T CHANGE */
+				/* default for unqualified addresses */
+#define BADHOST ".MISSING-HOST-NAME."
+				/* default for syntax errors in addresses */
+#define ERRHOST ".SYNTAX-ERROR."
+
+
+/* Coddle certain compilers' 6-character symbol limitation */
+
+#ifdef __COMPILER_KCC__
+#include "shortsym.h"
+#endif
+
+
+/* Function status code */
+
+#define NIL 0			/* convenient name */
+#define T 1			/* opposite of NIL */
+#define LONGT (long) 1		/* long T to pacify some compilers */
+#define VOIDT (void *) ""	/* void T ditto */
+
+/* Global and Driver Parameters */
+
+	/* 0xx: driver and authenticator flags */
+#define ENABLE_DRIVER (long) 1
+#define DISABLE_DRIVER (long) 2
+#define ENABLE_AUTHENTICATOR (long) 3
+#define DISABLE_AUTHENTICATOR (long) 4
+#define ENABLE_DEBUG (long) 5
+#define DISABLE_DEBUG (long) 6
+#define HIDE_AUTHENTICATOR (long) 7
+#define UNHIDE_AUTHENTICATOR (long) 8
+	/* 1xx: c-client globals */
+#define GET_DRIVERS (long) 101
+#define SET_DRIVERS (long) 102
+#define GET_GETS (long) 103
+#define SET_GETS (long) 104
+#define GET_CACHE (long) 105
+#define SET_CACHE (long) 106
+#define GET_SMTPVERBOSE (long) 107
+#define SET_SMTPVERBOSE (long) 108
+#define GET_RFC822OUTPUT (long) 109
+#define SET_RFC822OUTPUT (long) 110
+#define GET_READPROGRESS (long) 111
+#define SET_READPROGRESS (long) 112
+#define GET_THREADERS (long) 113
+#define SET_THREADERS (long) 114
+#define GET_NAMESPACE (long) 115
+#define SET_NAMESPACE (long) 116
+#define GET_MAILPROXYCOPY (long) 117
+#define SET_MAILPROXYCOPY (long) 118
+#define GET_SERVICENAME (long) 119
+#define SET_SERVICENAME (long) 120
+#define GET_DRIVER (long) 121
+#define SET_DRIVER (long) 122
+#define GET_EXPUNGEATPING (long) 123
+#define SET_EXPUNGEATPING (long) 124
+#define GET_PARSEPHRASE (long) 125
+#define SET_PARSEPHRASE (long) 126
+#define GET_SSLDRIVER (long) 127
+#define SET_SSLDRIVER (long) 128
+#define GET_TRYSSLFIRST (long) 129
+#define SET_TRYSSLFIRST (long) 130
+#define GET_BLOCKNOTIFY (long) 131
+#define SET_BLOCKNOTIFY (long) 132
+#define GET_SORTRESULTS (long) 133
+#define SET_SORTRESULTS (long) 134
+#define GET_THREADRESULTS (long) 135
+#define SET_THREADRESULTS (long) 136
+#define GET_PARSELINE (long) 137
+#define SET_PARSELINE (long) 138
+#define GET_NEWSRCQUERY (long) 139
+#define SET_NEWSRCQUERY (long) 140
+#define GET_FREEENVELOPESPAREP (long) 141
+#define SET_FREEENVELOPESPAREP (long) 142
+#define GET_FREEELTSPAREP (long) 143
+#define SET_FREEELTSPAREP (long) 144
+#define GET_SSLSTART (long) 145
+#define SET_SSLSTART (long) 146
+#define GET_DEBUGSENSITIVE (long) 147
+#define SET_DEBUGSENSITIVE (long) 148
+#define GET_TCPDEBUG (long) 149
+#define SET_TCPDEBUG (long) 150
+#define GET_FREESTREAMSPAREP (long) 151
+#define SET_FREESTREAMSPAREP (long) 152
+#define GET_FREEBODYSPAREP (long) 153
+#define SET_FREEBODYSPAREP (long) 154
+#define GET_COPYUID (long) 155
+#define SET_COPYUID (long) 156
+#define GET_APPENDUID (long) 157
+#define SET_APPENDUID (long) 158
+#define GET_RFC822OUTPUTFULL (long) 159
+#define SET_RFC822OUTPUTFULL (long) 160
+#define GET_BLOCKENVINIT (long) 161
+#define SET_BLOCKENVINIT (long) 162
+
+	/* 2xx: environment */
+#define GET_USERNAME (long) 201
+#define SET_USERNAME (long) 202
+#define GET_HOMEDIR (long) 203
+#define SET_HOMEDIR (long) 204
+#define GET_LOCALHOST (long) 205
+#define SET_LOCALHOST (long) 206
+#define GET_SYSINBOX (long) 207
+#define SET_SYSINBOX (long) 208
+#define GET_USERPROMPT (long) 209
+#define SET_USERPROMPT (long) 210
+#define GET_DISABLEPLAINTEXT (long) 211
+#define SET_DISABLEPLAINTEXT (long) 212
+#define GET_CHROOTSERVER (long) 213
+#define SET_CHROOTSERVER (long) 214
+#define GET_ADVERTISETHEWORLD (long) 215
+#define SET_ADVERTISETHEWORLD (long) 216
+#define GET_DISABLEAUTOSHAREDNS (long) 217
+#define SET_DISABLEAUTOSHAREDNS (long) 218
+#define GET_MAILSUBDIR 219
+#define SET_MAILSUBDIR 220
+#define GET_DISABLE822TZTEXT 221
+#define SET_DISABLE822TZTEXT 222
+#define GET_LIMITEDADVERTISE (long) 223
+#define SET_LIMITEDADVERTISE (long) 224
+#define GET_LOGOUTHOOK (long) 225
+#define SET_LOGOUTHOOK (long) 226
+#define GET_LOGOUTDATA (long) 227
+#define SET_LOGOUTDATA (long) 228
+#define GET_EXTERNALAUTHID (long) 229
+#define SET_EXTERNALAUTHID (long) 230
+#define GET_SSLCAPATH (long) 231
+#define SET_SSLCAPATH (long) 232
+
+	/* 3xx: TCP/IP */
+#define GET_OPENTIMEOUT (long) 300
+#define SET_OPENTIMEOUT (long) 301
+#define GET_READTIMEOUT (long) 302
+#define SET_READTIMEOUT (long) 303
+#define GET_WRITETIMEOUT (long) 304
+#define SET_WRITETIMEOUT (long) 305
+#define GET_CLOSETIMEOUT (long) 306
+#define SET_CLOSETIMEOUT (long) 307
+#define GET_TIMEOUT (long) 308
+#define SET_TIMEOUT (long) 309
+#define GET_RSHTIMEOUT (long) 310
+#define SET_RSHTIMEOUT (long) 311
+#define GET_ALLOWREVERSEDNS (long) 312
+#define SET_ALLOWREVERSEDNS (long) 313
+#define GET_RSHCOMMAND (long) 314
+#define SET_RSHCOMMAND (long) 315
+#define GET_RSHPATH (long) 316
+#define SET_RSHPATH (long) 317
+#define GET_SSHTIMEOUT (long) 318
+#define SET_SSHTIMEOUT (long) 319
+#define GET_SSHCOMMAND (long) 320
+#define SET_SSHCOMMAND (long) 321
+#define GET_SSHPATH (long) 322
+#define SET_SSHPATH (long) 323
+#define GET_SSLCERTIFICATEQUERY (long) 324
+#define SET_SSLCERTIFICATEQUERY (long) 325
+#define GET_SSLFAILURE (long) 326
+#define SET_SSLFAILURE (long) 327
+#define GET_NEWSRCCANONHOST (long) 328
+#define SET_NEWSRCCANONHOST (long) 329
+#define GET_KINIT (long) 330
+#define SET_KINIT (long) 331
+#define GET_SSLCLIENTCERT (long) 332
+#define SET_SSLCLIENTCERT (long) 333
+#define GET_SSLCLIENTKEY (long) 334
+#define SET_SSLCLIENTKEY (long) 335
+#define GET_KERBEROS_CP_SVR_NAME (long) 336
+#define SET_KERBEROS_CP_SVR_NAME (long) 337
+
+	/* 4xx: network drivers */
+#define GET_MAXLOGINTRIALS (long) 400
+#define SET_MAXLOGINTRIALS (long) 401
+#define GET_LOOKAHEAD (long) 402
+#define SET_LOOKAHEAD (long) 403
+#define GET_IMAPPORT (long) 404
+#define SET_IMAPPORT (long) 405
+#define GET_PREFETCH (long) 406
+#define SET_PREFETCH (long) 407
+#define GET_CLOSEONERROR (long) 408
+#define SET_CLOSEONERROR (long) 409
+#define GET_POP3PORT (long) 410
+#define SET_POP3PORT (long) 411
+#define GET_UIDLOOKAHEAD (long) 412
+#define SET_UIDLOOKAHEAD (long) 413
+#define GET_NNTPPORT (long) 414
+#define SET_NNTPPORT (long) 415
+#define GET_IMAPENVELOPE (long) 416
+#define SET_IMAPENVELOPE (long) 417
+#define GET_IMAPREFERRAL (long) 418
+#define SET_IMAPREFERRAL (long) 419
+#define GET_SSLIMAPPORT (long) 420
+#define SET_SSLIMAPPORT (long) 421
+#define GET_SSLPOPPORT (long) 422
+#define SET_SSLPOPPORT (long) 423
+#define GET_SSLNNTPPORT (long) 424
+#define SET_SSLNNTPPORT (long) 425
+#define GET_SSLSMTPPORT (long) 426
+#define SET_SSLSMTPPORT (long) 427
+#define GET_SMTPPORT (long) 428
+#define SET_SMTPPORT (long) 429
+#define GET_IMAPEXTRAHEADERS (long) 430
+#define SET_IMAPEXTRAHEADERS (long) 431
+#define GET_ACL (long) 432
+#define SET_ACL (long) 433
+#define GET_LISTRIGHTS (long) 434
+#define SET_LISTRIGHTS (long) 435
+#define GET_MYRIGHTS (long) 436
+#define SET_MYRIGHTS (long) 437
+#define GET_QUOTA (long) 438
+#define SET_QUOTA (long) 439
+#define GET_QUOTAROOT (long) 440
+#define SET_QUOTAROOT (long) 441
+#define GET_IMAPTRYSSL (long) 442
+#define SET_IMAPTRYSSL (long) 443
+#define GET_FETCHLOOKAHEAD (long) 444
+#define SET_FETCHLOOKAHEAD (long) 445
+#define GET_NNTPRANGE (long) 446
+#define SET_NNTPRANGE (long) 447
+#define GET_NNTPHIDEPATH (long) 448
+#define SET_NNTPHIDEPATH (long) 449
+#define GET_SENDCOMMAND (long) 450
+#define SET_SENDCOMMAND (long) 451
+#define GET_IDLETIMEOUT (long) 452
+#define SET_IDLETIMEOUT (long) 453
+#define GET_FETCHLOOKAHEADLIMIT (long) 454
+#define SET_FETCHLOOKAHEADLIMIT (long) 455
+
+	/* 5xx: local file drivers */
+#define GET_MBXPROTECTION (long) 500
+#define SET_MBXPROTECTION (long) 501
+#define GET_DIRPROTECTION (long) 502
+#define SET_DIRPROTECTION (long) 503
+#define GET_LOCKPROTECTION (long) 504
+#define SET_LOCKPROTECTION (long) 505
+#define GET_FROMWIDGET (long) 506
+#define SET_FROMWIDGET (long) 507
+#define GET_NEWSACTIVE (long) 508
+#define SET_NEWSACTIVE (long) 509
+#define GET_NEWSSPOOL (long) 510
+#define SET_NEWSSPOOL (long) 511
+#define GET_NEWSRC (long) 512
+#define SET_NEWSRC (long) 513
+#define GET_EXTENSION (long) 514
+#define SET_EXTENSION (long) 515
+#define GET_DISABLEFCNTLLOCK (long) 516
+#define SET_DISABLEFCNTLLOCK (long) 517
+#define GET_LOCKEACCESERROR (long) 518
+#define SET_LOCKEACCESERROR (long) 519
+#define GET_LISTMAXLEVEL (long) 520
+#define SET_LISTMAXLEVEL (long) 521
+#define GET_ANONYMOUSHOME (long) 522
+#define SET_ANONYMOUSHOME (long) 523
+#define GET_FTPHOME (long) 524
+#define SET_FTPHOME (long) 525
+#define GET_PUBLICHOME (long) 526
+#define SET_PUBLICHOME (long) 527
+#define GET_SHAREDHOME (long) 528
+#define SET_SHAREDHOME (long) 529
+#define GET_MHPROFILE (long) 530
+#define SET_MHPROFILE (long) 531
+#define GET_MHPATH (long) 532
+#define SET_MHPATH (long) 533
+#define GET_ONETIMEEXPUNGEATPING (long) 534
+#define SET_ONETIMEEXPUNGEATPING (long) 535
+#define GET_USERHASNOLIFE (long) 536
+#define SET_USERHASNOLIFE (long) 537
+#define GET_FTPPROTECTION (long) 538
+#define SET_FTPPROTECTION (long) 539
+#define GET_PUBLICPROTECTION (long) 540
+#define SET_PUBLICPROTECTION (long) 541
+#define GET_SHAREDPROTECTION (long) 542
+#define SET_SHAREDPROTECTION (long) 543
+#define GET_LOCKTIMEOUT (long) 544
+#define SET_LOCKTIMEOUT (long) 545
+#define GET_NOTIMEZONES (long) 546
+#define SET_NOTIMEZONES (long) 547
+#define GET_HIDEDOTFILES (long) 548
+#define SET_HIDEDOTFILES (long) 549
+#define GET_FTPDIRPROTECTION (long) 550
+#define SET_FTPDIRPROTECTION (long) 551
+#define GET_PUBLICDIRPROTECTION (long) 552
+#define SET_PUBLICDIRPROTECTION (long) 553
+#define GET_SHAREDDIRPROTECTION (long) 554
+#define SET_SHAREDDIRPROTECTION (long) 555
+#define GET_TRUSTDNS (long) 556
+#define SET_TRUSTDNS (long) 557
+#define GET_SASLUSESPTRNAME (long) 558
+#define SET_SASLUSESPTRNAME (long) 559
+#define GET_NETFSSTATBUG (long) 560
+#define SET_NETFSSTATBUG (long) 561
+#define GET_SNARFMAILBOXNAME (long) 562
+#define SET_SNARFMAILBOXNAME (long) 563
+#define GET_SNARFINTERVAL (long) 564
+#define SET_SNARFINTERVAL (long) 565
+#define GET_SNARFPRESERVE (long) 566
+#define SET_SNARFPRESERVE (long) 567
+#define GET_INBOXPATH (long) 568
+#define SET_INBOXPATH (long) 569
+#define GET_DIRFMTTEST (long) 570
+#define SET_DIRFMTTEST (long) 571
+#define GET_SCANCONTENTS (long) 572
+#define SET_SCANCONTENTS (long) 573
+#define GET_MHALLOWINBOX (long) 574
+#define SET_MHALLOWINBOX (long) 575
+
+/* Driver flags */
+
+#define DR_DISABLE (long) 0x1	/* driver is disabled */
+#define DR_LOCAL (long) 0x2	/* local file driver */
+#define DR_MAIL (long) 0x4	/* supports mail */
+#define DR_NEWS (long) 0x8	/* supports news */
+#define DR_READONLY (long) 0x10	/* driver only allows readonly access */
+#define DR_NOFAST (long) 0x20	/* "fast" data is slow (whole msg fetch) */
+#define DR_NAMESPACE (long) 0x40/* driver has a special namespace */
+#define DR_LOWMEM (long) 0x80	/* low amounts of memory available */
+#define DR_LOCKING (long) 0x100	/* driver does locking */
+#define DR_CRLF (long) 0x200	/* driver internal form uses CRLF newlines */
+#define DR_NOSTICKY (long) 0x400/* driver does not support sticky UIDs */
+#define DR_RECYCLE (long) 0x800	/* driver does stream recycling */
+#define DR_XPOINT (long) 0x1000	/* needs to be checkpointed */
+				/* driver has no real internal date */
+#define DR_NOINTDATE (long) 0x2000
+				/* driver does not announce new mail */
+#define DR_NONEWMAIL (long) 0x4000
+				/* driver does not announce new mail when RO */
+#define DR_NONEWMAILRONLY (long) 0x8000
+				/* driver can be halfopen */
+#define DR_HALFOPEN (long) 0x10000
+#define DR_DIRFMT (long) 0x20000/* driver is a directory-format */
+#define DR_MODSEQ (long) 0x40000/* driver supports modseqs */
+
+
+/* Cache management function codes */
+
+#define CH_INIT (long) 10	/* initialize cache */
+#define CH_SIZE (long) 11	/* (re-)size the cache */
+#define CH_MAKEELT (long) 30	/* return elt, make if needed */
+#define CH_ELT (long) 31	/* return elt if exists */
+#define CH_SORTCACHE (long) 35	/* return sortcache entry, make if needed */
+#define CH_FREE (long) 40	/* free space used by elt */
+				/* free space used by sortcache */
+#define CH_FREESORTCACHE (long) 43
+#define CH_EXPUNGE (long) 45	/* delete elt pointer from list */
+
+
+/* Mailbox open options
+ * For compatibility with the past, OP_DEBUG must always be 1.
+ */
+
+#define OP_DEBUG (long) 0x1	/* debug protocol negotiations */
+#define OP_READONLY (long) 0x2	/* read-only open */
+#define OP_ANONYMOUS (long) 0x4	/* anonymous open of newsgroup */
+#define OP_SHORTCACHE (long) 0x8/* short (elt-only) caching */
+#define OP_SILENT (long) 0x10	/* don't pass up events (internal use) */
+#define OP_PROTOTYPE (long) 0x20/* return driver prototype */
+#define OP_HALFOPEN (long) 0x40	/* half-open (IMAP connect but no select) */
+#define OP_EXPUNGE (long) 0x80	/* silently expunge recycle stream */
+#define OP_SECURE (long) 0x100	/* don't do non-secure authentication */
+#define OP_TRYSSL (long) 0x200	/* try SSL first */
+				/* use multiple newsrc files */
+#define OP_MULNEWSRC (long) 0x400
+#define OP_NOKOD (long) 0x800	/* suppress kiss-of-death */
+#define OP_SNIFF (long) 0x1000	/* metadata only open */
+				/* reserved for application use */
+#define OP_RESERVED (unsigned long) 0xff000000
+
+
+/* Net open options */
+
+				/* no error messages */
+#define NET_SILENT ((unsigned long) 0x80000000)
+				/* no validation of SSL certificates */
+#define NET_NOVALIDATECERT ((unsigned long) 0x40000000)
+				/* no open timeout */
+#define NET_NOOPENTIMEOUT ((unsigned long) 0x20000000)
+				/* TLS not SSL */
+#define NET_TLSCLIENT ((unsigned long) 0x10000000)
+				/* try SSL mode */
+#define NET_TRYSSL ((unsigned long) 0x8000000)
+
+/* Close options */
+
+#define CL_EXPUNGE (long) 1	/* expunge silently */
+
+
+/* Fetch options */
+
+#define FT_UID (long) 0x1	/* argument is a UID */
+#define FT_PEEK (long) 0x2	/* peek at data */
+#define FT_NOT (long) 0x4	/* NOT flag for header lines fetch */
+#define FT_INTERNAL (long) 0x8	/* text can be internal strings */
+				/* IMAP prefetch text when fetching header */
+#define FT_PREFETCHTEXT (long) 0x20
+#define FT_NOHDRS (long) 0x40	/* suppress fetching extra headers (note that
+				   this breaks news handling) */
+#define FT_NEEDENV (long) 0x80	/* (internal use) include envelope */
+#define FT_NEEDBODY (long) 0x100/* (internal use) include body structure */
+				/* no fetch lookahead */
+#define FT_NOLOOKAHEAD (long) 0x200
+				/* (internal use) lookahead in hdr searching */
+#define FT_SEARCHLOOKAHEAD (long) 0x400
+				/* stringstruct return hack */
+#define FT_RETURNSTRINGSTRUCT (long) 0x800
+
+
+/* Flagging options */
+
+#define ST_UID (long) 0x1	/* argument is a UID sequence */
+#define ST_SILENT (long) 0x2	/* don't return results */
+#define ST_SET (long) 0x4	/* set vs. clear */
+
+
+/* Expunge options */
+
+#define EX_UID (long) 0x1	/* argument is a UID sequence */
+
+
+/* Copy options */
+
+#define CP_UID (long) 0x1	/* argument is a UID sequence */
+#define CP_MOVE (long) 0x2	/* delete from source after copying */
+				/* set debug in any created stream */
+#define CP_DEBUG (long) 0x20000000
+
+/* Search/sort/thread options */
+
+#define SE_UID (long) 0x1	/* return UID */
+#define SE_FREE (long) 0x2	/* free search program after finished */
+#define SE_NOPREFETCH (long) 0x4/* no search prefetching */
+#define SO_FREE (long) 0x8	/* free sort program after finished */
+#define SE_NOSERVER (long) 0x10	/* don't do server-based search/sort/thread */
+#define SE_RETAIN (long) 0x20	/* retain previous search results */
+#define SO_OVERVIEW (long) 0x40	/* use overviews in searching (NNTP only) */
+#define SE_NEEDBODY (long) 0x80	/* include body structure in prefetch */
+#define SE_NOHDRS (long) 0x100	/* suppress prefetching extra headers (note
+				   that this breaks news handling) */
+#define SE_NOLOCAL (long) 0x200	/* no local retry (IMAP only) */
+
+#define SO_NOSERVER SE_NOSERVER	/* compatibility name */
+#define SE_SILLYOK (long) 0x400	/* allow silly searches */
+
+
+/* Status options */
+
+#define SA_MESSAGES (long) 0x1	/* number of messages */
+#define SA_RECENT (long) 0x2	/* number of recent messages */
+#define SA_UNSEEN (long) 0x4	/* number of unseen messages */
+#define SA_UIDNEXT (long) 0x8	/* next UID to be assigned */
+				/* UID validity value */
+#define SA_UIDVALIDITY (long) 0x10
+				/* set OP_DEBUG on any created stream */
+#define SA_DEBUG (long) 0x10000000
+				/* use multiple newsrcs */
+#define SA_MULNEWSRC (long) 0x20000000
+
+/* Mailgets flags */
+
+#define MG_UID (long) 0x1	/* message number is a UID */
+#define MG_COPY (long) 0x2	/* must return copy of argument */
+
+/* SASL authenticator categories */
+
+#define AU_SECURE (long) 0x1	/* /secure allowed */
+#define AU_AUTHUSER (long) 0x2	/* /authuser=xxx allowed */
+				/* authenticator hidden */
+#define AU_HIDE (long) 0x10000000
+				/* authenticator disabled */
+#define AU_DISABLE (long) 0x20000000
+
+
+/* Garbage collection flags */
+
+#define GC_ELT (long) 0x1	/* message cache elements */
+#define GC_ENV (long) 0x2	/* envelopes and bodies */
+#define GC_TEXTS (long) 0x4	/* cached texts */
+
+
+/* mm_log()/mm_notify() condition codes */
+
+#define WARN (long) 1		/* mm_log warning type */
+#define ERROR (long) 2		/* mm_log error type */
+#define PARSE (long) 3		/* mm_log parse error type */
+#define BYE (long) 4		/* mm_notify stream dying */
+#define TCPDEBUG (long) 5	/* mm_log TCP debug babble */
+
+
+/* Bits from mail_parse_flags().  Don't change these, since the header format
+ * used by tenex, mtx, and mbx corresponds to these bits.
+ */
+
+#define fSEEN 0x1
+#define fDELETED 0x2
+#define fFLAGGED 0x4
+#define fANSWERED 0x8
+#define fOLD 0x10
+#define fDRAFT 0x20
+
+#define fEXPUNGED 0x8000	/* internal flag */
+
+/* Bits for mm_list() and mm_lsub() */
+
+/* Note that (LATT_NOINFERIORS LATT_HASCHILDREN LATT_HASNOCHILDREN) and
+ * (LATT_NOSELECT LATT_MARKED LATT_UNMARKED) each have eight possible states,
+ * but only four of these are valid.  The other four are silly states which
+ * while invalid can unfortunately be expressed in the IMAP protocol.
+ */
+
+				/* terminal node in hierarchy */
+#define LATT_NOINFERIORS (long) 0x1
+				/* name can not be selected */
+#define LATT_NOSELECT (long) 0x2
+				/* changed since last accessed */
+#define LATT_MARKED (long) 0x4
+				/* accessed since last changed */
+#define LATT_UNMARKED (long) 0x8
+				/* name has referral to remote mailbox */
+#define LATT_REFERRAL (long) 0x10
+				/* has selectable inferiors */
+#define LATT_HASCHILDREN (long) 0x20
+				/* has no selectable inferiors */
+#define LATT_HASNOCHILDREN (long) 0x40
+
+
+/* Sort functions */
+
+#define SORTDATE 0		/* date */
+#define SORTARRIVAL 1		/* arrival date */
+#define SORTFROM 2		/* from */
+#define SORTSUBJECT 3		/* subject */
+#define SORTTO 4		/* to */
+#define SORTCC 5		/* cc */
+#define SORTSIZE 6		/* size */
+
+
+/* imapreferral_t codes */
+
+#define REFAUTHFAILED (long) 0	/* authentication referral -- not logged in */
+#define REFAUTH (long) 1	/* authentication referral -- logged in */
+#define REFSELECT (long) 2	/* select referral */
+#define REFCREATE (long) 3
+#define REFDELETE (long) 4
+#define REFRENAME (long) 5
+#define REFSUBSCRIBE (long) 6
+#define REFUNSUBSCRIBE (long) 7
+#define REFSTATUS (long) 8
+#define REFCOPY (long) 9
+#define REFAPPEND (long) 10
+
+
+/* sendcommand_t codes */
+
+				/* expunge response deferred */
+#define SC_EXPUNGEDEFERRED (long) 1
+
+/* Block notification codes */
+
+#define BLOCK_NONE 0		/* not blocked */
+#define BLOCK_SENSITIVE 1	/* sensitive code, disallow alarms */
+#define BLOCK_NONSENSITIVE 2	/* non-sensitive code, allow alarms */
+#define BLOCK_DNSLOOKUP 10	/* blocked on DNS lookup */
+#define BLOCK_TCPOPEN 11	/* blocked on TCP open */
+#define BLOCK_TCPREAD 12	/* blocked on TCP read */
+#define BLOCK_TCPWRITE 13	/* blocked on TCP write */
+#define BLOCK_TCPCLOSE 14	/* blocked on TCP close */
+#define BLOCK_FILELOCK 20	/* blocked on file locking */
+
+
+/* In-memory sized-text */
+
+#define SIZEDTEXT struct mail_sizedtext
+
+SIZEDTEXT {
+  unsigned char *data;		/* text */
+  unsigned long size;		/* size of text in octets */
+};
+
+
+/* String list */
+
+#define STRINGLIST struct string_list
+
+STRINGLIST {
+  SIZEDTEXT text;		/* string text */
+  STRINGLIST *next;
+};
+
+
+/* Parse results from mail_valid_net_parse */
+
+#define NETMAXHOST 256
+#define NETMAXUSER 65
+#define NETMAXMBX (MAILTMPLEN/4)
+#define NETMAXSRV 21
+typedef struct net_mailbox {
+  char host[NETMAXHOST];	/* host name (may be canonicalized) */
+  char orighost[NETMAXHOST];	/* host name before canonicalization */
+  char user[NETMAXUSER];	/* user name */
+  char authuser[NETMAXUSER];	/* authentication user name */
+  char mailbox[NETMAXMBX];	/* mailbox name */
+  char service[NETMAXSRV];	/* service name */
+  unsigned long port;		/* TCP port number */
+  unsigned int anoflag : 1;	/* anonymous */
+  unsigned int dbgflag : 1;	/* debug flag */
+  unsigned int secflag : 1;	/* secure flag */
+  unsigned int sslflag : 1;	/* SSL driver flag */
+  unsigned int trysslflag : 1;	/* try SSL driver first flag */
+  unsigned int novalidate : 1;	/* don't validate certificates */
+  unsigned int tlsflag : 1;	/* TLS flag */
+  unsigned int notlsflag : 1;	/* do not do TLS flag */
+  unsigned int readonlyflag : 1;/* want readonly */
+  unsigned int norsh : 1;	/* don't use rsh/ssh */
+  unsigned int loser : 1;	/* server is a loser */
+  unsigned int tlssslv23 : 1;	/* force SSLv23 client method over TLS */
+} NETMBX;
+
+/* Item in an address list */
+
+#define ADDRESS struct mail_address
+
+ADDRESS {
+  char *personal;		/* personal name phrase */
+  char *adl;			/* at-domain-list source route */
+  char *mailbox;		/* mailbox name */
+  char *host;			/* domain name of mailbox's host */
+  char *error;			/* error in address from SMTP module */
+  struct {
+    char *type;			/* address type (default "rfc822") */
+    char *addr;			/* address as xtext */
+  } orcpt;
+  ADDRESS *next;		/* pointer to next address in list */
+};
+
+
+/* Message envelope */
+
+typedef struct mail_envelope {
+  unsigned int incomplete : 1;	/* envelope may be incomplete */
+  unsigned int imapenvonly : 1;	/* envelope only has IMAP envelope */
+  char *remail;			/* remail header if any */
+  ADDRESS *return_path;		/* error return address */
+  unsigned char *date;		/* message composition date string */
+  ADDRESS *from;		/* originator address list */
+  ADDRESS *sender;		/* sender address list */
+  ADDRESS *reply_to;		/* reply address list */
+  char *subject;		/* message subject string */
+  ADDRESS *to;			/* primary recipient list */
+  ADDRESS *cc;			/* secondary recipient list */
+  ADDRESS *bcc;			/* blind secondary recipient list */
+  char *in_reply_to;		/* replied message ID */
+  char *message_id;		/* message ID */
+  char *newsgroups;		/* USENET newsgroups */
+  char *followup_to;		/* USENET reply newsgroups */
+  char *references;		/* USENET references */
+  void *sparep;			/* spare pointer reserved for main program */
+} ENVELOPE;
+
+/* Primary body types */
+/* If you change any of these you must also change body_types in rfc822.c */
+
+#define TYPETEXT 0		/* unformatted text */
+#define TYPEMULTIPART 1		/* multiple part */
+#define TYPEMESSAGE 2		/* encapsulated message */
+#define TYPEAPPLICATION 3	/* application data */
+#define TYPEAUDIO 4		/* audio */
+#define TYPEIMAGE 5		/* static image */
+#define TYPEVIDEO 6		/* video */
+#define TYPEMODEL 7		/* model */
+#define TYPEOTHER 8		/* unknown */
+#define TYPEMAX 15		/* maximum type code */
+
+
+/* Body encodings */
+/* If you change any of these you must also change body_encodings in rfc822.c
+ */
+
+#define ENC7BIT 0		/* 7 bit SMTP semantic data */
+#define ENC8BIT 1		/* 8 bit SMTP semantic data */
+#define ENCBINARY 2		/* 8 bit binary data */
+#define ENCBASE64 3		/* base-64 encoded data */
+#define ENCQUOTEDPRINTABLE 4	/* human-readable 8-as-7 bit data */
+#define ENCOTHER 5		/* unknown */
+#define ENCMAX 10		/* maximum encoding code */
+
+
+/* Body contents */
+
+#define BODY struct mail_bodystruct
+#define MESSAGE struct mail_body_message
+#define PARAMETER struct mail_body_parameter
+#define PART struct mail_body_part
+#define PARTTEXT struct mail_body_text
+
+/* Message body text */
+
+PARTTEXT {
+  unsigned long offset;		/* offset from body origin */
+  SIZEDTEXT text;		/* text */
+};
+
+
+/* Message body structure */
+
+BODY {
+  unsigned short type;		/* body primary type */
+  unsigned short encoding;	/* body transfer encoding */
+  char *subtype;		/* subtype string */
+  PARAMETER *parameter;		/* parameter list */
+  char *id;			/* body identifier */
+  char *description;		/* body description */
+  struct {			/* body disposition */
+    char *type;			/* disposition type */
+    PARAMETER *parameter;	/* disposition parameters */
+  } disposition;
+  STRINGLIST *language;		/* body language */
+  char *location;		/* body content URI */
+  PARTTEXT mime;		/* MIME header */
+  PARTTEXT contents;		/* body part contents */
+  union {			/* different ways of accessing contents */
+    PART *part;			/* body part list */
+    MESSAGE *msg;		/* body encapsulated message */
+  } nested;
+  struct {
+    unsigned long lines;	/* size of text in lines */
+    unsigned long bytes;	/* size of text in octets */
+  } size;
+  char *md5;			/* MD5 checksum */
+  void *sparep;			/* spare pointer reserved for main program */
+};
+
+
+/* Parameter list */
+
+PARAMETER {
+  char *attribute;		/* parameter attribute name */
+  char *value;			/* parameter value */
+  PARAMETER *next;		/* next parameter in list */
+};
+
+
+/* Multipart content list */
+
+PART {
+  BODY body;			/* body information for this part */
+  PART *next;			/* next body part */
+};
+
+
+/* RFC-822 Message */
+
+MESSAGE {
+  ENVELOPE *env;		/* message envelope */
+  BODY *body;			/* message body */
+  PARTTEXT full;		/* full message */
+  STRINGLIST *lines;		/* lines used to filter header */
+  PARTTEXT header;		/* header text */
+  PARTTEXT text;		/* body text */
+};
+
+/* Entry in the message cache array */
+
+typedef struct message_cache {
+  unsigned long msgno;		/* message number */
+  unsigned int lockcount : 8;	/* non-zero if multiple references */
+  unsigned long rfc822_size;	/* # of bytes of message as raw RFC822 */
+  struct {			/* c-client internal use only */
+    unsigned long uid;		/* message unique ID */
+    unsigned long mod;		/* modseq */
+    PARTTEXT special;		/* special text pointers */
+    MESSAGE msg;		/* internal message pointers */
+    union {			/* driver internal use */
+      unsigned long data;
+      void *ptr;
+    } spare;
+    unsigned int sequence : 1;	/* saved sequence bit */
+    unsigned int dirty : 1;	/* driver internal use */
+    unsigned int filter : 1;	/* driver internal use */
+    unsigned int ghost : 1;	/* driver internal use */
+  } private;
+			/* internal date */
+  unsigned int day : 5;		/* day of month (1-31) */
+  unsigned int month : 4;	/* month of year (1-12) */
+  unsigned int year : 7;	/* year since BASEYEAR (expires in 127 yrs) */
+  unsigned int hours: 5;	/* hours (0-23) */
+  unsigned int minutes: 6;	/* minutes (0-59) */
+  unsigned int seconds: 6;	/* seconds (0-59) */
+  unsigned int zoccident : 1;	/* non-zero if west of UTC */
+  unsigned int zhours : 4;	/* hours from UTC (0-12) */
+  unsigned int zminutes: 6;	/* minutes (0-59) */
+			/* system flags */
+  unsigned int seen : 1;	/* system Seen flag */
+  unsigned int deleted : 1;	/* system Deleted flag */
+  unsigned int flagged : 1; 	/* system Flagged flag */
+  unsigned int answered : 1;	/* system Answered flag */
+  unsigned int draft : 1;	/* system Draft flag */
+  unsigned int recent : 1;	/* system Recent flag */
+			/* message status */
+  unsigned int valid : 1;	/* elt has valid flags */
+  unsigned int searched : 1;	/* message was searched */
+  unsigned int sequence : 1;	/* message is in sequence */
+			/* reserved for use by main program */
+  unsigned int spare : 1;	/* first spare bit */
+  unsigned int spare2 : 1;	/* second spare bit */
+  unsigned int spare3 : 1;	/* third spare bit */
+  unsigned int spare4 : 1;	/* fourth spare bit */
+  unsigned int spare5 : 1;	/* fifth spare bit */
+  unsigned int spare6 : 1;	/* sixth spare bit */
+  unsigned int spare7 : 1;	/* seventh spare bit */
+  unsigned int spare8 : 1;	/* eighth spare bit */
+  void *sparep;			/* spare pointer */
+  unsigned long user_flags;	/* user-assignable flags */
+} MESSAGECACHE;
+
+/* String structure */
+
+#define STRINGDRIVER struct string_driver
+
+typedef struct mailstring {
+  void *data;			/* driver-dependent data */
+  unsigned long data1;		/* driver-dependent data */
+  unsigned long size;		/* total length of string */
+  char *chunk;			/* base address of chunk */
+  unsigned long chunksize;	/* size of chunk */
+  unsigned long offset;		/* offset of this chunk in base */
+  char *curpos;			/* current position in chunk */
+  unsigned long cursize;	/* number of bytes remaining in chunk */
+  STRINGDRIVER *dtb;		/* driver that handles this type of string */
+} STRING;
+
+
+/* Dispatch table for string driver */
+
+STRINGDRIVER {
+				/* initialize string driver */
+  void (*init) (STRING *s,void *data,unsigned long size);
+				/* get next character in string */
+  char (*next) (STRING *s);
+				/* set position in string */
+  void (*setpos) (STRING *s,unsigned long i);
+};
+
+
+/* Stringstruct access routines */
+
+#define INIT(s,d,data,size) ((*((s)->dtb = &d)->init) (s,data,size))
+#define SIZE(s) ((s)->size - GETPOS (s))
+#define CHR(s) (*(s)->curpos)
+#define SNX(s) (--(s)->cursize ? *(s)->curpos++ : (*(s)->dtb->next) (s))
+#define GETPOS(s) ((s)->offset + ((s)->curpos - (s)->chunk))
+#define SETPOS(s,i) (*(s)->dtb->setpos) (s,i)
+
+/* Search program */
+
+#define SEARCHPGM struct search_program
+#define SEARCHHEADER struct search_header
+#define SEARCHSET struct search_set
+#define SEARCHOR struct search_or
+#define SEARCHPGMLIST struct search_pgm_list
+
+
+SEARCHHEADER {			/* header search */
+  SIZEDTEXT line;		/* header line */
+  SIZEDTEXT text;		/* text in header */
+  SEARCHHEADER *next;		/* next in list */
+};
+
+
+SEARCHSET {			/* message set */
+  unsigned long first;		/* sequence number */
+  unsigned long last;		/* last value, if a range */
+  SEARCHSET *next;		/* next in list */
+};
+
+
+SEARCHOR {
+  SEARCHPGM *first;		/* first program */
+  SEARCHPGM *second;		/* second program */
+  SEARCHOR *next;		/* next in list */
+};
+
+
+SEARCHPGMLIST {
+  SEARCHPGM *pgm;		/* search program */
+  SEARCHPGMLIST *next;		/* next in list */
+};
+
+SEARCHPGM {			/* search program */
+  SEARCHSET *msgno;		/* message numbers */
+  SEARCHSET *uid;		/* unique identifiers */
+  SEARCHOR *or;			/* or'ed in programs */
+  SEARCHPGMLIST *not;		/* and'ed not program */
+  SEARCHHEADER *header;		/* list of headers */
+  STRINGLIST *bcc;		/* bcc recipients */
+  STRINGLIST *body;		/* text in message body */
+  STRINGLIST *cc;		/* cc recipients */
+  STRINGLIST *from;		/* originator */
+  STRINGLIST *keyword;		/* keywords */
+  STRINGLIST *unkeyword;	/* unkeywords */
+  STRINGLIST *subject;		/* text in subject */
+  STRINGLIST *text;		/* text in headers and body */
+  STRINGLIST *to;		/* to recipients */
+  unsigned long larger;		/* larger than this size */
+  unsigned long smaller;	/* smaller than this size */
+  unsigned long older;		/* older than this interval */
+  unsigned long younger;	/* younger than this interval */
+  unsigned short sentbefore;	/* sent before this date */
+  unsigned short senton;	/* sent on this date */
+  unsigned short sentsince;	/* sent since this date */
+  unsigned short before;	/* before this date */
+  unsigned short on;		/* on this date */
+  unsigned short since;		/* since this date */
+  unsigned int answered : 1;	/* answered messages */
+  unsigned int unanswered : 1;	/* unanswered messages */
+  unsigned int deleted : 1;	/* deleted messages */
+  unsigned int undeleted : 1;	/* undeleted messages */
+  unsigned int draft : 1;	/* message draft */
+  unsigned int undraft : 1;	/* message undraft */
+  unsigned int flagged : 1;	/* flagged messages */
+  unsigned int unflagged : 1;	/* unflagged messages */
+  unsigned int recent : 1;	/* recent messages */
+  unsigned int old : 1;		/* old messages */
+  unsigned int seen : 1;	/* seen messages */
+  unsigned int unseen : 1;	/* unseen messages */
+  /* These must be simulated in IMAP */
+  STRINGLIST *return_path;	/* error return address */
+  STRINGLIST *sender;		/* sender address list */
+  STRINGLIST *reply_to;		/* reply address list */
+  STRINGLIST *in_reply_to;	/* replied message ID */
+  STRINGLIST *message_id;	/* message ID */
+  STRINGLIST *newsgroups;	/* USENET newsgroups */
+  STRINGLIST *followup_to;	/* USENET reply newsgroups */
+  STRINGLIST *references;	/* USENET references */
+};
+
+
+/* Mailbox status */
+
+typedef struct mbx_status {
+  long flags;			/* validity flags */
+  unsigned long messages;	/* number of messages */
+  unsigned long recent;		/* number of recent messages */
+  unsigned long unseen;		/* number of unseen messages */
+  unsigned long uidnext;	/* next UID to be assigned */
+  unsigned long uidvalidity;	/* UID validity value */
+} MAILSTATUS;
+
+/* Sort program */
+
+typedef void (*postsort_t) (void *sc);
+
+#define SORTPGM struct sort_program
+
+SORTPGM {
+  unsigned int reverse : 1;	/* sort function is to be reversed */
+  unsigned int abort : 1;	/* abort sorting */
+  short function;		/* sort function */
+  unsigned long nmsgs;		/* number of messages being sorted */
+  struct {
+    unsigned long cached;	/* number of messages cached so far */
+    unsigned long sorted;	/* number of messages sorted so far */
+    unsigned long postsorted;	/* number of postsorted messages so far */
+  } progress;
+  postsort_t postsort;		/* post sorter */
+  SORTPGM *next;		/* next function */
+};
+
+
+/* Sort cache */
+
+#define SORTCACHE struct sort_cache
+
+SORTCACHE {
+  unsigned int sorted : 1;	/* message has been sorted */
+  unsigned int postsorted : 1;	/* message has been postsorted */
+  unsigned int refwd : 1;	/* subject is a re or fwd */
+  unsigned int dirty : 1;	/* has data not written to backup */
+  SORTPGM *pgm;			/* sort program */
+  unsigned long num;		/* message number (sequence or UID) */
+  unsigned long date;		/* sent date */
+  unsigned long arrival;	/* arrival date */
+  unsigned long size;		/* message size */
+  char *from;			/* from string */
+  char *to;			/* to string */
+  char *cc;			/* cc string */
+  char *subject;		/* extracted subject string */
+  char *message_id;		/* message-id string */
+  char *unique;			/* unique string, normally message-id */
+  STRINGLIST *references;	/* references string */
+};
+
+/* ACL list */
+
+#define ACLLIST struct acl_list
+
+ACLLIST {
+  char *identifier;		/* authentication identifier */
+  char *rights;			/* access rights */
+  ACLLIST *next;
+};
+
+/* Quota resource list */
+
+#define QUOTALIST struct quota_list
+
+QUOTALIST {
+  char *name;			/* resource name */
+  unsigned long usage;		/* resource usage */
+  unsigned long limit;		/* resource limit */
+  QUOTALIST *next;		/* next resource */
+};
+
+/* Mail Access I/O stream */
+
+
+/* Structure for mail driver dispatch */
+
+#define DRIVER struct driver	
+
+
+/* Mail I/O stream */
+	
+typedef struct mail_stream {
+  DRIVER *dtb;			/* dispatch table for this driver */
+  void *local;			/* pointer to driver local data */
+  char *mailbox;		/* mailbox name (canonicalized) */
+  char *original_mailbox;	/* mailbox name (non-canonicalized) */
+  unsigned short use;		/* stream use count */
+  unsigned short sequence;	/* stream sequence */
+  unsigned int inbox : 1;	/* stream open on an INBOX */
+  unsigned int lock : 1;	/* stream lock flag */
+  unsigned int debug : 1;	/* stream debug flag */
+  unsigned int silent : 1;	/* don't pass events to main program */
+  unsigned int rdonly : 1;	/* stream read-only flag */
+  unsigned int anonymous : 1;	/* stream anonymous access flag */
+  unsigned int scache : 1;	/* stream short cache flag */
+  unsigned int halfopen : 1;	/* stream half-open flag */
+  unsigned int secure : 1;	/* stream secure flag */
+  unsigned int tryssl : 1;	/* stream tryssl flag */
+  unsigned int mulnewsrc : 1;	/* stream use multiple newsrc files */
+  unsigned int perm_seen : 1;	/* permanent Seen flag */
+  unsigned int perm_deleted : 1;/* permanent Deleted flag */
+  unsigned int perm_flagged : 1;/* permanent Flagged flag */
+  unsigned int perm_answered :1;/* permanent Answered flag */
+  unsigned int perm_draft : 1;	/* permanent Draft flag */
+  unsigned int kwd_create : 1;	/* can create new keywords */
+  unsigned int uid_nosticky : 1;/* UIDs are not preserved */
+  unsigned int unhealthy : 1;	/* unhealthy protocol negotiations */
+  unsigned int nokod : 1;	/* suppress kiss-of-death */
+  unsigned int sniff : 1;	/* metadata only */
+  unsigned long perm_user_flags;/* mask of permanent user flags */
+  unsigned long gensym;		/* generated tag */
+  unsigned long nmsgs;		/* # of associated msgs */
+  unsigned long recent;		/* # of recent msgs */
+  unsigned long uid_validity;	/* UID validity sequence */
+  unsigned long uid_last;	/* last assigned UID */
+  char *user_flags[NUSERFLAGS];	/* pointers to user flags in bit order */
+  unsigned long cachesize;	/* size of message cache */
+  MESSAGECACHE **cache;		/* message cache array */
+  SORTCACHE **sc;		/* sort cache array */
+  unsigned long msgno;		/* message number of `current' message */
+  ENVELOPE *env;		/* scratch buffer for envelope */
+  BODY *body;			/* scratch buffer for body */
+  SIZEDTEXT text;		/* scratch buffer for text */
+  struct {
+    char *name;			/* mailbox name to snarf from */
+    unsigned long time;		/* last snarf time */
+    long options;		/* snarf open options */
+  } snarf;
+  struct {			/* internal use only */
+    struct {			/* search temporaries */
+      STRINGLIST *string;	/* string(s) to search */
+      long result;		/* search result */
+      char *text;		/* cache of fetched text */
+    } search;
+    STRING string;		/* stringstruct return hack */
+  } private;
+			/* reserved for use by main program */
+  void *sparep;			/* spare pointer */
+  unsigned int spare : 1;	/* first spare bit */
+  unsigned int spare2 : 1;	/* second spare bit */
+  unsigned int spare3 : 1;	/* third spare bit */
+  unsigned int spare4 : 1;	/* fourth spare bit */
+  unsigned int spare5 : 1;	/* fifth spare bit */
+  unsigned int spare6 : 1;	/* sixth spare bit */
+  unsigned int spare7 : 1;	/* seventh spare bit */
+  unsigned int spare8 : 1;	/* eighth spare bit */
+} MAILSTREAM;
+
+/* Mail I/O stream handle */
+
+typedef struct mail_stream_handle {
+  MAILSTREAM *stream;		/* pointer to mail stream */
+  unsigned short sequence;	/* sequence of what we expect stream to be */
+} MAILHANDLE;
+
+
+/* Message overview */
+
+typedef struct mail_overview {
+  char *subject;		/* message subject string */
+  ADDRESS *from;		/* originator address list */
+  char *date;			/* message composition date string */
+  char *message_id;		/* message ID */
+  char *references;		/* USENET references */
+  struct {			/* may be 0 or NUL if unknown/undefined */
+    unsigned long octets;	/* message octets (probably LF-newline form) */
+    unsigned long lines;	/* message lines */
+    char *xref;			/* cross references */
+  } optional;
+} OVERVIEW;
+
+/* Network access I/O stream */
+
+
+/* Structure for network driver dispatch */
+
+#define NETDRIVER struct net_driver
+
+
+/* Network transport I/O stream */
+
+typedef struct net_stream {
+  void *stream;			/* driver's I/O stream */
+  NETDRIVER *dtb;		/* network driver */
+} NETSTREAM;
+
+
+/* Network transport driver dispatch */
+
+NETDRIVER {
+  void *(*open) (char *host,char *service,unsigned long port);
+  void *(*aopen) (NETMBX *mb,char *service,char *usrbuf);
+  char *(*getline) (void *stream);
+  long (*getbuffer) (void *stream,unsigned long size,char *buffer);
+  long (*soutr) (void *stream,char *string);
+  long (*sout) (void *stream,char *string,unsigned long size);
+  void (*close) (void *stream);
+  char *(*host) (void *stream);
+  char *(*remotehost) (void *stream);
+  unsigned long (*port) (void *stream);
+  char *(*localhost) (void *stream);
+};
+
+
+/* Mailgets data identifier */
+
+typedef struct getsdata {
+  MAILSTREAM *stream;
+  unsigned long msgno;
+  char *what;
+  STRINGLIST *stl;
+  unsigned long first;
+  unsigned long last;
+  long flags;
+} GETS_DATA;
+
+
+#define INIT_GETS(md,s,m,w,f,l) \
+  md.stream = s, md.msgno = m, md.what = w, md.first = f, md.last = l, \
+  md.stl = NIL, md.flags = NIL;
+
+/* Mail delivery I/O stream */
+
+typedef struct send_stream {
+  NETSTREAM *netstream;		/* network I/O stream */
+  char *host;			/* SMTP service host */
+  char *reply;			/* last reply string */
+  long replycode;		/* last reply code */
+  unsigned int debug : 1;	/* stream debug flag */
+  unsigned int sensitive : 1;	/* sensitive data in progress */
+  unsigned int loser : 1;	/* server is a loser */
+  unsigned int saslcancel : 1;	/* SASL cancelled by protocol */
+  union {			/* protocol specific */
+    struct {			/* SMTP specific */
+      unsigned int ok : 1;	/* supports ESMTP */
+      struct {			/* service extensions */
+	unsigned int send : 1;	/* supports SEND */
+	unsigned int soml : 1;	/* supports SOML */
+	unsigned int saml : 1;	/* supports SAML */
+	unsigned int expn : 1;	/* supports EXPN */
+	unsigned int help : 1;	/* supports HELP */
+	unsigned int turn : 1;	/* supports TURN */
+	unsigned int etrn : 1;	/* supports ETRN */
+	unsigned int starttls:1;/* supports STARTTLS */
+	unsigned int relay : 1;	/* supports relaying */
+	unsigned int pipe : 1;	/* supports pipelining */
+	unsigned int ensc : 1;	/* supports enhanced status codes */
+	unsigned int bmime : 1;	/* supports BINARYMIME */
+	unsigned int chunk : 1;	/* supports CHUNKING */
+      } service;
+      struct {			/* 8-bit MIME transport */
+	unsigned int ok : 1;	/* supports 8-bit MIME */
+	unsigned int want : 1;	/* want 8-bit MIME */
+      } eightbit;
+      struct {			/* delivery status notification */
+	unsigned int ok : 1;	/* supports DSN */
+	unsigned int want : 1;	/* want DSN */
+	struct {		/* notification options */
+				/* notify on failure */
+	  unsigned int failure : 1;
+				/* notify on delay */
+	  unsigned int delay : 1;
+				/* notify on success */
+	  unsigned int success : 1;
+	} notify;
+	unsigned int full : 1;	/* return full headers */
+	char *envid;		/* envelope identifier as xtext */
+      } dsn;
+      struct {			/* size declaration */
+	unsigned int ok : 1;	/* supports SIZE */
+	unsigned long limit;	/* maximum size supported */
+      } size;
+      struct {			/* deliverby declaration */
+	unsigned int ok : 1;	/* supports DELIVERBY */
+	unsigned long minby;	/* minimum by-time */
+      } deliverby;
+      struct {			/* authenticated turn */
+	unsigned int ok : 1;	/* supports ATRN */
+	char *domains;		/* domains */
+      } atrn;
+				/* supported SASL authenticators */
+      unsigned int auth : MAXAUTHENTICATORS;
+    } esmtp;
+    struct {			/* NNTP specific */
+      unsigned int post : 1;	/* supports POST */
+      struct {			/* NNTP extensions */
+	unsigned int ok : 1;	/* supports extensions */
+				/* supports LISTGROUP */
+	unsigned int listgroup : 1;
+	unsigned int over : 1;	/* supports OVER */
+	unsigned int hdr : 1;	/* supports HDR */
+	unsigned int pat : 1;	/* supports PAT */
+				/* supports STARTTLS */
+	unsigned int starttls : 1;
+				/* server has MULTIDOMAIN */
+	unsigned int multidomain : 1;
+				/* supports AUTHINFO USER */
+	unsigned int authuser : 1;
+				/* supported authenticators */
+	unsigned int sasl : MAXAUTHENTICATORS;
+      } ext;
+    } nntp;
+  } protocol;
+} SENDSTREAM;
+
+/* Jacket into external interfaces */
+
+typedef long (*readfn_t) (void *stream,unsigned long size,char *buffer);
+typedef char *(*mailgets_t) (readfn_t f,void *stream,unsigned long size,
+			     GETS_DATA *md);
+typedef char *(*readprogress_t) (GETS_DATA *md,unsigned long octets);
+typedef void *(*mailcache_t) (MAILSTREAM *stream,unsigned long msgno,long op);
+typedef long (*mailproxycopy_t) (MAILSTREAM *stream,char *sequence,
+				 char *mailbox,long options);
+typedef long (*tcptimeout_t) (long overall,long last);
+typedef void *(*authchallenge_t) (void *stream,unsigned long *len);
+typedef long (*authrespond_t) (void *stream,char *s,unsigned long size);
+typedef long (*authcheck_t) (void);
+typedef long (*authclient_t) (authchallenge_t challenger,
+			      authrespond_t responder,char *service,NETMBX *mb,
+			      void *s,unsigned long *trial,char *user);
+typedef char *(*authresponse_t) (void *challenge,unsigned long clen,
+				 unsigned long *rlen);
+typedef char *(*authserver_t) (authresponse_t responder,int argc,char *argv[]);
+typedef void (*smtpverbose_t) (char *buffer);
+typedef void (*imapenvelope_t) (MAILSTREAM *stream,unsigned long msgno,
+				ENVELOPE *env);
+typedef char *(*imapreferral_t) (MAILSTREAM *stream,char *url,long code);
+typedef void (*overview_t) (MAILSTREAM *stream,unsigned long uid,OVERVIEW *ov,
+			    unsigned long msgno);
+typedef unsigned long *(*sorter_t) (MAILSTREAM *stream,char *charset,
+				    SEARCHPGM *spg,SORTPGM *pgm,long flags);
+typedef void (*parseline_t) (ENVELOPE *env,char *hdr,char *data,char *host);
+typedef ADDRESS *(*parsephrase_t) (char *phrase,char *end,char *host);
+typedef void *(*blocknotify_t) (int reason,void *data);
+typedef long (*kinit_t) (char *host,char *reason);
+typedef void (*sendcommand_t) (MAILSTREAM *stream,char *cmd,long flags);
+typedef char *(*newsrcquery_t) (MAILSTREAM *stream,char *mulname,char *name);
+typedef void (*getacl_t) (MAILSTREAM *stream,char *mailbox,ACLLIST *acl);
+typedef void (*listrights_t) (MAILSTREAM *stream,char *mailbox,char *id,
+			      char *alwaysrights,STRINGLIST *possiblerights);
+typedef void (*myrights_t) (MAILSTREAM *stream,char *mailbox,char *rights);
+typedef void (*quota_t) (MAILSTREAM *stream,char *qroot,QUOTALIST *qlist);
+typedef void (*quotaroot_t) (MAILSTREAM *stream,char *mbx,STRINGLIST *qroot);
+typedef void (*sortresults_t) (MAILSTREAM *stream,unsigned long *list,
+			       unsigned long size);
+typedef char *(*userprompt_t) (void);
+typedef long (*append_t) (MAILSTREAM *stream,void *data,char **flags,
+			  char **date,STRING **message);
+typedef void (*copyuid_t) (MAILSTREAM *stream,char *mailbox,
+			   unsigned long uidvalidity,SEARCHSET *sourceset,
+			   SEARCHSET *destset);
+typedef void (*appenduid_t) (char *mailbox,unsigned long uidvalidity,
+			     SEARCHSET *set);
+typedef long (*dirfmttest_t) (char *name);
+typedef long (*scancontents_t) (char *name,char *contents,unsigned long csiz,
+				unsigned long fsiz);
+
+typedef void (*freeeltsparep_t) (void **sparep);
+typedef void (*freeenvelopesparep_t) (void **sparep);
+typedef void (*freebodysparep_t) (void **sparep);
+typedef void (*freestreamsparep_t) (void **sparep);
+typedef void *(*sslstart_t) (void *stream,char *host,unsigned long flags);
+typedef long (*sslcertificatequery_t) (char *reason,char *host,char *cert);
+typedef void (*sslfailure_t) (char *host,char *reason,unsigned long flags);
+typedef void (*logouthook_t) (void *data);
+typedef char *(*sslclientcert_t) (void);
+typedef char *(*sslclientkey_t) (void);
+
+/* Globals */
+
+extern char *body_types[];	/* defined body type strings */
+extern char *body_encodings[];	/* defined body encoding strings */
+extern const char *days[];	/* day name strings */
+extern const char *months[];	/* month name strings */
+
+/* Threading */
+
+/* Thread node */
+
+#define THREADNODE struct thread_node
+
+THREADNODE {
+  unsigned long num;		/* message number */
+  SORTCACHE *sc;		/* (internal use) sortcache entry */
+  THREADNODE *branch;		/* branch at this point in tree */
+  THREADNODE *next;		/* next node */
+};
+
+typedef void (*threadresults_t) (MAILSTREAM *stream,THREADNODE *tree);
+
+
+/* Thread dispatch */
+
+#define THREADER struct threader_list
+
+THREADER {
+  char *name;			/* name of threader */
+  THREADNODE *(*dispatch) (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
+			   long flags,sorter_t sorter);
+  THREADER *next;
+};
+
+
+/* Container for references threading */
+
+typedef void ** container_t;
+
+/* Namespaces */
+
+#define NAMESPACE struct mail_namespace
+
+NAMESPACE {
+  char *name;			/* name of this namespace */
+  int delimiter;		/* hierarchy delimiter */
+  PARAMETER *param;		/* namespace parameters */
+  NAMESPACE *next;		/* next namespace */
+};
+
+
+/* Authentication */
+
+#define AUTHENTICATOR struct mail_authenticator
+
+AUTHENTICATOR {
+  long flags;			/* authenticator flags */
+  char *name;			/* name of this authenticator */
+  authcheck_t valid;		/* authenticator valid on this system */
+  authclient_t client;		/* client function that supports it */
+  authserver_t server;		/* server function that supports it */
+  AUTHENTICATOR *next;		/* next authenticator */
+};
+
+/* Mail driver dispatch */
+
+DRIVER {
+  char *name;			/* driver name */
+  unsigned long flags;		/* driver flags */
+  DRIVER *next;			/* next driver */
+				/* mailbox is valid for us */
+  DRIVER *(*valid) (char *mailbox);
+				/* manipulate driver parameters */
+  void *(*parameters) (long function,void *value);
+				/* scan mailboxes */
+  void (*scan) (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+				/* list mailboxes */
+  void (*list) (MAILSTREAM *stream,char *ref,char *pat);
+				/* list subscribed mailboxes */
+  void (*lsub) (MAILSTREAM *stream,char *ref,char *pat);
+				/* subscribe to mailbox */
+  long (*subscribe) (MAILSTREAM *stream,char *mailbox);
+				/* unsubscribe from mailbox */
+  long (*unsubscribe) (MAILSTREAM *stream,char *mailbox);
+				/* create mailbox */
+  long (*create) (MAILSTREAM *stream,char *mailbox);
+				/* delete mailbox */
+  long (*mbxdel) (MAILSTREAM *stream,char *mailbox);
+				/* rename mailbox */
+  long (*mbxren) (MAILSTREAM *stream,char *old,char *newname);
+				/* status of mailbox */
+  long (*status) (MAILSTREAM *stream,char *mbx,long flags);
+
+				/* open mailbox */
+  MAILSTREAM *(*open) (MAILSTREAM *stream);
+				/* close mailbox */
+  void (*close) (MAILSTREAM *stream,long options);
+				/* fetch message "fast" attributes */
+  void (*fast) (MAILSTREAM *stream,char *sequence,long flags);
+				/* fetch message flags */
+  void (*msgflags) (MAILSTREAM *stream,char *sequence,long flags);
+				/* fetch message overview */
+  long (*overview) (MAILSTREAM *stream,overview_t ofn);
+				/* fetch message envelopes */
+  ENVELOPE *(*structure) (MAILSTREAM *stream,unsigned long msgno,BODY **body,
+			  long flags);
+				/* return RFC-822 header */
+  char *(*header) (MAILSTREAM *stream,unsigned long msgno,
+		   unsigned long *length,long flags);
+				/* return RFC-822 text */
+  long (*text) (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+				/* load cache */
+  long (*msgdata) (MAILSTREAM *stream,unsigned long msgno,char *section,
+		   unsigned long first,unsigned long last,STRINGLIST *lines,
+		   long flags);
+				/* return UID for message */
+  unsigned long (*uid) (MAILSTREAM *stream,unsigned long msgno);
+				/* return message number from UID */
+  unsigned long (*msgno) (MAILSTREAM *stream,unsigned long uid);
+				/* modify flags */
+  void (*flag) (MAILSTREAM *stream,char *sequence,char *flag,long flags);
+				/* per-message modify flags */
+  void (*flagmsg) (MAILSTREAM *stream,MESSAGECACHE *elt);
+				/* search for message based on criteria */
+  long (*search) (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,long flags);
+				/* sort messages */
+  unsigned long *(*sort) (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
+			  SORTPGM *pgm,long flags);
+				/* thread messages */
+  THREADNODE *(*thread) (MAILSTREAM *stream,char *type,char *charset,
+			 SEARCHPGM *spg,long flag);
+				/* ping mailbox to see if still alive */
+  long (*ping) (MAILSTREAM *stream);
+				/* check for new messages */
+  void (*check) (MAILSTREAM *stream);
+				/* expunge deleted messages */
+  long (*expunge) (MAILSTREAM *stream,char *sequence,long options);
+				/* copy messages to another mailbox */
+  long (*copy) (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+				/* append string message to mailbox */
+  long (*append) (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+				/* garbage collect stream */
+  void (*gc) (MAILSTREAM *stream,long gcflags);
+};
+
+
+#include "linkage.h"
+
+/* Compatibility support names for old interfaces */
+
+#define GET_TRYALTFIRST GET_TRYSSLFIRST
+#define SET_TRYALTFIRST SET_TRYSSLFIRST
+#define GET_IMAPTRYALT GET_IMAPTRYSSL
+#define SET_IMAPTRYALT SET_IMAPTRYSSL
+#define OP_TRYALT OP_TRYSSL
+#define altflag sslflag
+
+#define mail_close(stream) \
+  mail_close_full (stream,NIL)
+#define mail_fetchfast(stream,sequence) \
+  mail_fetch_fast (stream,sequence,NIL)
+#define mail_fetchfast_full mail_fetch_fast
+#define mail_fetchflags(stream,sequence) \
+  mail_fetch_flags (stream,sequence,NIL)
+#define mail_fetchflags_full mail_fetch_flags
+#define mail_fetchenvelope(stream,msgno) \
+  mail_fetch_structure (stream,msgno,NIL,NIL)
+#define mail_fetchstructure(stream,msgno,body) \
+  mail_fetch_structure (stream,msgno,body,NIL)
+#define mail_fetchstructure_full mail_fetch_structure
+#define mail_fetchheader(stream,msgno) \
+  mail_fetch_header (stream,msgno,NIL,NIL,NIL,FT_PEEK)
+#define mail_fetchheader_full(stream,msgno,lines,len,flags) \
+  mail_fetch_header (stream,msgno,NIL,lines,len,FT_PEEK | (flags))
+#define mail_fetchtext(stream,msgno) \
+  mail_fetch_text (stream,msgno,NIL,NIL,NIL)
+#define mail_fetchtext_full(stream,msgno,length,flags) \
+  mail_fetch_text (stream,msgno,NIL,length,flags)
+#define mail_fetchbody(stream,msgno,section,length) \
+  mail_fetch_body (stream,msgno,section,length,NIL)
+#define mail_fetchbody_full mail_fetch_body
+#define mail_setflag(stream,sequence,flag) \
+  mail_flag (stream,sequence,flag,ST_SET)
+#define mail_setflag_full(stream,sequence,flag,flags) \
+  mail_flag (stream,sequence,flag,ST_SET | (flags))
+#define mail_clearflag(stream,sequence,flag) \
+  mail_flag (stream,sequence,flag,NIL)
+#define mail_clearflag_full mail_flag
+#define mail_search(stream,criteria) \
+  mail_search_full (stream,NIL,mail_criteria (criteria),SE_FREE);
+#define mail_expunge(stream) \
+  mail_expunge_full (stream,NIL,NIL)
+#define mail_copy(stream,sequence,mailbox) \
+  mail_copy_full (stream,sequence,mailbox,NIL)
+#define mail_move(stream,sequence,mailbox) \
+  mail_copy_full (stream,sequence,mailbox,CP_MOVE)
+#define mail_append(stream,mailbox,message) \
+  mail_append_full (stream,mailbox,NIL,NIL,message)
+
+/* Interfaces for SVR4 locking brain-damage workaround */
+
+/* Driver dispatching */
+
+#define SAFE_DELETE(dtb,stream,mailbox) (*dtb->mbxdel) (stream,mailbox)
+#define SAFE_RENAME(dtb,stream,old,newname) (*dtb->mbxren) (stream,old,newname)
+#define SAFE_STATUS(dtb,stream,mbx,flags) (*dtb->status) (stream,mbx,flags)
+#define SAFE_COPY(dtb,stream,sequence,mailbox,options) \
+  (*dtb->copy) (stream,sequence,mailbox,options)
+#define SAFE_APPEND(dtb,stream,mailbox,af,data) \
+  (*dtb->append) (stream,mailbox,af,data)
+#define SAFE_SCAN_CONTENTS(dtb,name,contents,csiz,fsiz) \
+  scan_contents (dtb,name,contents,csiz,fsiz)
+
+
+/* Driver callbacks */
+
+#define MM_EXISTS mm_exists
+#define MM_EXPUNGED mm_expunged
+#define MM_FLAGS mm_flags
+#define MM_NOTIFY mm_notify
+#define MM_STATUS mm_status
+#define MM_LOG mm_log
+#define MM_CRITICAL mm_critical
+#define MM_NOCRITICAL mm_nocritical
+#define MM_DISKERROR mm_diskerror
+#define MM_FATAL mm_fatal
+#define MM_APPEND(af) (*af)
+
+/* Function prototypes */
+
+void mm_searched (MAILSTREAM *stream,unsigned long number);
+void mm_exists (MAILSTREAM *stream,unsigned long number);
+void mm_expunged (MAILSTREAM *stream,unsigned long number);
+void mm_flags (MAILSTREAM *stream,unsigned long number);
+void mm_notify (MAILSTREAM *stream,char *string,long errflg);
+void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes);
+void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes);
+void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status);
+void mm_log (char *string,long errflg);
+void mm_dlog (char *string);
+void mm_login (NETMBX *mb,char *user,char *pwd,long trial);
+void mm_critical (MAILSTREAM *stream);
+void mm_nocritical (MAILSTREAM *stream);
+long mm_diskerror (MAILSTREAM *stream,long errcode,long serious);
+void mm_fatal (char *string);
+void *mm_cache (MAILSTREAM *stream,unsigned long msgno,long op);
+
+extern STRINGDRIVER mail_string;
+void mail_versioncheck (char *version);
+void mail_link (DRIVER *driver);
+void *mail_parameters (MAILSTREAM *stream,long function,void *value);
+DRIVER *mail_valid (MAILSTREAM *stream,char *mailbox,char *purpose);
+DRIVER *mail_valid_net (char *name,DRIVER *drv,char *host,char *mailbox);
+long mail_valid_net_parse (char *name,NETMBX *mb);
+long mail_valid_net_parse_work (char *name,NETMBX *mb,char *service);
+void mail_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void mail_list (MAILSTREAM *stream,char *ref,char *pat);
+void mail_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long mail_subscribe (MAILSTREAM *stream,char *mailbox);
+long mail_unsubscribe (MAILSTREAM *stream,char *mailbox);
+long mail_create (MAILSTREAM *stream,char *mailbox);
+long mail_delete (MAILSTREAM *stream,char *mailbox);
+long mail_rename (MAILSTREAM *stream,char *old,char *newname);
+char *mail_utf7_valid (char *mailbox);
+long mail_status (MAILSTREAM *stream,char *mbx,long flags);
+long mail_status_default (MAILSTREAM *stream,char *mbx,long flags);
+MAILSTREAM *mail_open (MAILSTREAM *stream,char *name,long options);
+MAILSTREAM *mail_open_work (DRIVER *d,MAILSTREAM *stream,char *name,
+			    long options);
+MAILSTREAM *mail_close_full (MAILSTREAM *stream,long options);
+MAILHANDLE *mail_makehandle (MAILSTREAM *stream);
+void mail_free_handle (MAILHANDLE **handle);
+MAILSTREAM *mail_stream (MAILHANDLE *handle);
+
+void mail_fetch_fast (MAILSTREAM *stream,char *sequence,long flags);
+void mail_fetch_flags (MAILSTREAM *stream,char *sequence,long flags);
+void mail_fetch_overview (MAILSTREAM *stream,char *sequence,overview_t ofn);
+void mail_fetch_overview_sequence (MAILSTREAM *stream,char *sequence,
+				   overview_t ofn);
+void mail_fetch_overview_default (MAILSTREAM *stream,overview_t ofn);
+ENVELOPE *mail_fetch_structure (MAILSTREAM *stream,unsigned long msgno,
+				BODY **body,long flags);
+char *mail_fetch_message (MAILSTREAM *stream,unsigned long msgno,
+			  unsigned long *len,long flags);
+char *mail_fetch_header (MAILSTREAM *stream,unsigned long msgno,char *section,
+			 STRINGLIST *lines,unsigned long *len,long flags);
+char *mail_fetch_text (MAILSTREAM *stream,unsigned long msgno,char *section,
+		       unsigned long *len,long flags);
+char *mail_fetch_mime (MAILSTREAM *stream,unsigned long msgno,char *section,
+		       unsigned long *len,long flags);
+char *mail_fetch_body (MAILSTREAM *stream,unsigned long msgno,char *section,
+		       unsigned long *len,long flags);
+long mail_partial_text (MAILSTREAM *stream,unsigned long msgno,char *section,
+			unsigned long first,unsigned long last,long flags);
+long mail_partial_body (MAILSTREAM *stream,unsigned long msgno,char *section,
+			unsigned long first,unsigned long last,long flags);
+char *mail_fetch_text_return (GETS_DATA *md,SIZEDTEXT *t,unsigned long *len);
+char *mail_fetch_string_return (GETS_DATA *md,STRING *bs,unsigned long i,
+				unsigned long *len,long flags);
+long mail_read (void *stream,unsigned long size,char *buffer);
+unsigned long mail_uid (MAILSTREAM *stream,unsigned long msgno);
+unsigned long mail_msgno (MAILSTREAM *stream,unsigned long uid);
+void mail_fetchfrom (char *s,MAILSTREAM *stream,unsigned long msgno,
+		     long length);
+void mail_fetchsubject (char *s,MAILSTREAM *stream,unsigned long msgno,
+			long length);
+MESSAGECACHE *mail_elt (MAILSTREAM *stream,unsigned long msgno);
+void mail_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
+long mail_search_full (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,
+		       long flags);
+long mail_search_default (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,
+			  long flags);
+long mail_ping (MAILSTREAM *stream);
+void mail_check (MAILSTREAM *stream);
+long mail_expunge_full (MAILSTREAM *stream,char *sequence,long options);
+long mail_copy_full (MAILSTREAM *stream,char *sequence,char *mailbox,
+		     long options);
+long mail_append_full (MAILSTREAM *stream,char *mailbox,char *flags,char *date,
+		       STRING *message);
+long mail_append_multiple (MAILSTREAM *stream,char *mailbox,append_t af,
+			   void *data);
+void mail_gc (MAILSTREAM *stream,long gcflags);
+void mail_gc_msg (MESSAGE *msg,long gcflags);
+void mail_gc_body (BODY *body);
+
+BODY *mail_body (MAILSTREAM *stream,unsigned long msgno,
+		 unsigned char *section);
+char *mail_date (char *string,MESSAGECACHE *elt);
+char *mail_cdate (char *string,MESSAGECACHE *elt);
+long mail_parse_date (MESSAGECACHE *elt,unsigned char *string);
+void mail_exists (MAILSTREAM *stream,unsigned long nmsgs);
+void mail_recent (MAILSTREAM *stream,unsigned long recent);
+void mail_expunged (MAILSTREAM *stream,unsigned long msgno);
+void mail_lock (MAILSTREAM *stream);
+void mail_unlock (MAILSTREAM *stream);
+void mail_debug (MAILSTREAM *stream);
+void mail_nodebug (MAILSTREAM *stream);
+void mail_dlog (char *string,long flag);
+long mail_match_lines (STRINGLIST *lines,STRINGLIST *msglines,long flags);
+unsigned long mail_filter (char *text,unsigned long len,STRINGLIST *lines,
+			   long flags);
+long mail_search_msg (MAILSTREAM *stream,unsigned long msgno,char *section,
+		      SEARCHPGM *pgm);
+long mail_search_header_text (char *s,STRINGLIST *st);
+long mail_search_header (SIZEDTEXT *hdr,STRINGLIST *st);
+long mail_search_text (MAILSTREAM *stream,unsigned long msgno,char *section,
+		       STRINGLIST *st,long flags);
+long mail_search_body (MAILSTREAM *stream,unsigned long msgno,BODY *body,
+		       char *prefix,unsigned long section,long flags);
+long mail_search_string (SIZEDTEXT *s,char *charset,STRINGLIST **st);
+long mail_search_string_work (SIZEDTEXT *s,STRINGLIST **st);
+long mail_search_keyword (MAILSTREAM *stream,MESSAGECACHE *elt,STRINGLIST *st,
+			  long flag);
+long mail_search_addr (ADDRESS *adr,STRINGLIST *st);
+char *mail_search_gets (readfn_t f,void *stream,unsigned long size,
+			GETS_DATA *md);
+SEARCHPGM *mail_criteria (char *criteria);
+int mail_criteria_date (unsigned short *date,char **r);
+int mail_criteria_string (STRINGLIST **s,char **r);
+unsigned short mail_shortdate (unsigned int year,unsigned int month,
+			       unsigned int day);
+SEARCHSET *mail_parse_set (char *s,char **ret);
+SEARCHSET *mail_append_set (SEARCHSET *set,unsigned long msgno);
+unsigned long *mail_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
+			  SORTPGM *pgm,long flags);
+unsigned long *mail_sort_cache (MAILSTREAM *stream,SORTPGM *pgm,SORTCACHE **sc,
+				long flags);
+unsigned long *mail_sort_msgs (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
+			       SORTPGM *pgm,long flags);
+SORTCACHE **mail_sort_loadcache (MAILSTREAM *stream,SORTPGM *pgm);
+unsigned int mail_strip_subject (char *t,char **ret);
+char *mail_strip_subject_wsp (char *s);
+char *mail_strip_subject_blob (char *s);
+int mail_sort_compare (const void *a1,const void *a2);
+unsigned long mail_longdate (MESSAGECACHE *elt);
+THREADNODE *mail_thread (MAILSTREAM *stream,char *type,char *charset,
+			 SEARCHPGM *spg,long flags);
+THREADNODE *mail_thread_msgs (MAILSTREAM *stream,char *type,char *charset,
+			      SEARCHPGM *spg,long flags,sorter_t sorter);
+THREADNODE *mail_thread_orderedsubject (MAILSTREAM *stream,char *charset,
+					SEARCHPGM *spg,long flags,
+					sorter_t sorter);
+THREADNODE *mail_thread_references (MAILSTREAM *stream,char *charset,
+				    SEARCHPGM *spg,long flags,
+				    sorter_t sorter);
+void mail_thread_loadcache (MAILSTREAM *stream,unsigned long uid,OVERVIEW *ov,
+			    unsigned long msgno);
+char *mail_thread_parse_msgid (char *s,char **ss);
+STRINGLIST *mail_thread_parse_references (char *s,long flag);
+long mail_thread_check_child (container_t mother,container_t daughter);
+container_t mail_thread_prune_dummy (container_t msg,container_t ane);
+container_t mail_thread_prune_dummy_work (container_t msg,container_t ane);
+THREADNODE *mail_thread_c2node (MAILSTREAM *stream,container_t con,long flags);
+THREADNODE *mail_thread_sort (THREADNODE *thr,THREADNODE **tc);
+int mail_thread_compare_date (const void *a1,const void *a2);
+long mail_sequence (MAILSTREAM *stream,unsigned char *sequence);
+long mail_uid_sequence (MAILSTREAM *stream,unsigned char *sequence);
+long mail_parse_flags (MAILSTREAM *stream,char *flag,unsigned long *uf);
+long mail_usable_network_stream (MAILSTREAM *stream,char *name);
+
+MESSAGECACHE *mail_new_cache_elt (unsigned long msgno);
+ENVELOPE *mail_newenvelope (void);
+ADDRESS *mail_newaddr (void);
+BODY *mail_newbody (void);
+BODY *mail_initbody (BODY *body);
+PARAMETER *mail_newbody_parameter (void);
+PART *mail_newbody_part (void);
+MESSAGE *mail_newmsg (void);
+STRINGLIST *mail_newstringlist (void);
+SEARCHPGM *mail_newsearchpgm (void);
+SEARCHHEADER *mail_newsearchheader (char *line,char *text);
+SEARCHSET *mail_newsearchset (void);
+SEARCHOR *mail_newsearchor (void);
+SEARCHPGMLIST *mail_newsearchpgmlist (void);
+SORTPGM *mail_newsortpgm (void);
+THREADNODE *mail_newthreadnode (SORTCACHE *sc);
+ACLLIST *mail_newacllist (void);
+QUOTALIST *mail_newquotalist (void);
+void mail_free_body (BODY **body);
+void mail_free_body_data (BODY *body);
+void mail_free_body_parameter (PARAMETER **parameter);
+void mail_free_body_part (PART **part);
+void mail_free_cache (MAILSTREAM *stream);
+void mail_free_elt (MESSAGECACHE **elt);
+void mail_free_envelope (ENVELOPE **env);
+void mail_free_address (ADDRESS **address);
+void mail_free_stringlist (STRINGLIST **string);
+void mail_free_searchpgm (SEARCHPGM **pgm);
+void mail_free_searchheader (SEARCHHEADER **hdr);
+void mail_free_searchset (SEARCHSET **set);
+void mail_free_searchor (SEARCHOR **orl);
+void mail_free_searchpgmlist (SEARCHPGMLIST **pgl);
+void mail_free_namespace (NAMESPACE **n);
+void mail_free_sortpgm (SORTPGM **pgm);
+void mail_free_threadnode (THREADNODE **thr);
+void mail_free_acllist (ACLLIST **al);
+void mail_free_quotalist (QUOTALIST **ql);
+void auth_link (AUTHENTICATOR *auth);
+char *mail_auth (char *mechanism,authresponse_t resp,int argc,char *argv[]);
+AUTHENTICATOR *mail_lookup_auth (unsigned long i);
+unsigned int mail_lookup_auth_name (char *mechanism,long flags);
+
+NETSTREAM *net_open (NETMBX *mb,NETDRIVER *dv,unsigned long port,
+		     NETDRIVER *ssld,char *ssls,unsigned long sslp);
+NETSTREAM *net_open_work (NETDRIVER *dv,char *host,char *service,
+			  unsigned long port,unsigned long portoverride,
+			  unsigned long flags);
+NETSTREAM *net_aopen (NETDRIVER *dv,NETMBX *mb,char *service,char *usrbuf);
+char *net_getline (NETSTREAM *stream);
+				/* stream must be void* for use as readfn_t */
+long net_getbuffer (void *stream,unsigned long size,char *buffer);
+long net_soutr (NETSTREAM *stream,char *string);
+long net_sout (NETSTREAM *stream,char *string,unsigned long size);
+void net_close (NETSTREAM *stream);
+char *net_host (NETSTREAM *stream);
+char *net_remotehost (NETSTREAM *stream);
+unsigned long net_port (NETSTREAM *stream);
+char *net_localhost (NETSTREAM *stream);
+
+long sm_subscribe (char *mailbox);
+long sm_unsubscribe (char *mailbox);
+char *sm_read (void **sdb);
+
+void ssl_onceonlyinit (void);
+char *ssl_start_tls (char *s);
+void ssl_server_init (char *server);
+
+
+/* Server I/O functions */
+
+int PBIN (void);
+char *PSIN (char *s,int n);
+long PSINR (char *s,unsigned long n);
+int PBOUT (int c);
+long INWAIT (long seconds);
+int PSOUT (char *s);
+int PSOUTR (SIZEDTEXT *s);
+int PFLUSH (void);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/misc.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,475 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Miscellaneous utility routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	5 July 1988
+ * Last Edited:	6 December 2006
+ *
+ * This original version of this file is
+ * Copyright 1988 Stanford University
+ * and was developed in the Symbolic Systems Resources Group of the Knowledge
+ * Systems Laboratory at Stanford University in 1987-88, and was funded by the
+ * Biomedical Research Technology Program of the NationalInstitutes of Health
+ * under grant number RR-00785.
+ */
+
+
+#include <ctype.h>
+#include "c-client.h"
+
+/* Convert ASCII string to all uppercase
+ * Accepts: string pointer
+ * Returns: string pointer
+ *
+ * Don't use islower/toupper since this function must be ASCII only.
+ */
+
+unsigned char *ucase (unsigned char *s)
+{
+  unsigned char *t;
+				/* if lowercase covert to upper */
+  for (t = s; *t; t++) if ((*t >= 'a') && (*t <= 'z')) *t -= ('a' - 'A');
+  return s;			/* return string */
+}
+
+
+/* Convert string to all lowercase
+ * Accepts: string pointer
+ * Returns: string pointer
+ *
+ * Don't use isupper/tolower since this function must be ASCII only.
+ */
+
+unsigned char *lcase (unsigned char *s)
+{
+  unsigned char *t;
+				/* if uppercase covert to lower */
+  for (t = s; *t; t++) if ((*t >= 'A') && (*t <= 'Z')) *t += ('a' - 'A');
+  return s;			/* return string */
+}
+
+/* Copy string to free storage
+ * Accepts: source string
+ * Returns: free storage copy of string
+ */
+
+char *cpystr (const char *string)
+{
+  return string ? strcpy ((char *) fs_get (1 + strlen (string)),string) : NIL;
+}
+
+
+/* Copy text/size to free storage as sized text
+ * Accepts: destination sized text
+ *	    pointer to source text
+ *	    size of source text
+ * Returns: text as a char *
+ */
+
+char *cpytxt (SIZEDTEXT *dst,char *text,unsigned long size)
+{
+				/* flush old space */
+  if (dst->data) fs_give ((void **) &dst->data);
+				/* copy data in sized text */
+  memcpy (dst->data = (unsigned char *)
+	  fs_get ((size_t) (dst->size = size) + 1),text,(size_t) size);
+  dst->data[size] = '\0';	/* tie off text */
+  return (char *) dst->data;	/* convenience return */
+}
+
+/* Copy sized text to free storage as sized text
+ * Accepts: destination sized text
+ *	    source sized text
+ * Returns: text as a char *
+ */
+
+char *textcpy (SIZEDTEXT *dst,SIZEDTEXT *src)
+{
+				/* flush old space */
+  if (dst->data) fs_give ((void **) &dst->data);
+				/* copy data in sized text */
+  memcpy (dst->data = (unsigned char *)
+	  fs_get ((size_t) (dst->size = src->size) + 1),
+	  src->data,(size_t) src->size);
+  dst->data[dst->size] = '\0';	/* tie off text */
+  return (char *) dst->data;	/* convenience return */
+}
+
+
+/* Copy stringstruct to free storage as sized text
+ * Accepts: destination sized text
+ *	    source stringstruct
+ * Returns: text as a char *
+ */
+
+char *textcpystring (SIZEDTEXT *text,STRING *bs)
+{
+  unsigned long i = 0;
+				/* clear old space */
+  if (text->data) fs_give ((void **) &text->data);
+				/* make free storage space in sized text */
+  text->data = (unsigned char *) fs_get ((size_t) (text->size = SIZE (bs)) +1);
+  while (i < text->size) text->data[i++] = SNX (bs);
+  text->data[i] = '\0';		/* tie off text */
+  return (char *) text->data;	/* convenience return */
+}
+
+
+/* Copy stringstruct from offset to free storage as sized text
+ * Accepts: destination sized text
+ *	    source stringstruct
+ *	    offset into stringstruct
+ *	    size of source text
+ * Returns: text as a char *
+ */
+
+char *textcpyoffstring (SIZEDTEXT *text,STRING *bs,unsigned long offset,
+			unsigned long size)
+{
+  unsigned long i = 0;
+				/* clear old space */
+  if (text->data) fs_give ((void **) &text->data);
+  SETPOS (bs,offset);		/* offset the string */
+				/* make free storage space in sized text */
+  text->data = (unsigned char *) fs_get ((size_t) (text->size = size) + 1);
+  while (i < size) text->data[i++] = SNX (bs);
+  text->data[i] = '\0';		/* tie off text */
+  return (char *) text->data;	/* convenience return */
+}
+
+/* Returns index of rightmost bit in word
+ * Accepts: pointer to a 32 bit value
+ * Returns: -1 if word is 0, else index of rightmost bit
+ *
+ * Bit is cleared in the word
+ */
+
+unsigned long find_rightmost_bit (unsigned long *valptr)
+{
+  unsigned long value = *valptr;
+  unsigned long bit = 0;
+  if (!(value & 0xffffffff)) return 0xffffffff;
+				/* binary search for rightmost bit */
+  if (!(value & 0xffff)) value >>= 16, bit += 16;
+  if (!(value & 0xff)) value >>= 8, bit += 8;
+  if (!(value & 0xf)) value >>= 4, bit += 4;
+  if (!(value & 0x3)) value >>= 2, bit += 2;
+  if (!(value & 0x1)) value >>= 1, bit += 1;
+  *valptr ^= (1 << bit);	/* clear specified bit */
+  return bit;
+}
+
+
+/* Return minimum of two integers
+ * Accepts: integer 1
+ *	    integer 2
+ * Returns: minimum
+ */
+
+long min (long i,long j)
+{
+  return ((i < j) ? i : j);
+}
+
+
+/* Return maximum of two integers
+ * Accepts: integer 1
+ *	    integer 2
+ * Returns: maximum
+ */
+
+long max (long i,long j)
+{
+  return ((i > j) ? i : j);
+}
+
+/* Search, case-insensitive for ASCII characters
+ * Accepts: base string
+ *	    length of base string
+ *	    pattern string
+ *	    length of pattern string
+ * Returns: T if pattern exists inside base, else NIL
+ */
+
+long search (unsigned char *base,long basec,unsigned char *pat,long patc)
+{
+  long i,j,k;
+  int c;
+  unsigned char mask[256];
+  static unsigned char alphatab[256] = {
+    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+    255,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,
+    223,223,223,223,223,223,223,223,223,223,223,255,255,255,255,255,
+    255,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,
+    223,223,223,223,223,223,223,223,223,223,223,255,255,255,255,255,
+    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
+    };
+				/* validate arguments */
+  if (base && (basec > 0) && pat && (basec >= patc)) {
+    if (patc <= 0) return T;	/* empty pattern always succeeds */
+    memset (mask,0,256);	/* initialize search validity mask */
+    for (i = 0; i < patc; i++) if (!mask[c = pat[i]]) {
+				/* mark single character if non-alphabetic */
+      if (alphatab[c] & 0x20) mask[c] = T;
+				/* else mark both cases */
+      else mask[c & 0xdf] = mask[c | 0x20] = T;
+    }
+				/* Boyer-Moore type search */
+    for (i = --patc; i < basec; i += (mask[c] ? 1 : (j + 1)))
+      for (j = patc,c = base[k = i]; !((c ^ pat[j]) & alphatab[c]);
+	   j--,c = base[--k])
+	if (!j) return T;	/* found a match! */
+  }
+  return NIL;			/* pattern not found */
+}
+
+/* Boyer-Moore string search
+ * Accepts: base string
+ *	    length of base string
+ *	    pattern string
+ *	    length of pattern string
+ * Returns: T if pattern exists inside base, else NIL
+ */
+
+long ssearch (unsigned char *base,long basec,unsigned char *pat,long patc)
+{
+  long i,j,k;
+  int c;
+  unsigned char mask[256];
+				/* validate arguments */
+  if (base && (basec > 0) && pat && (basec >= patc)) {
+    if (patc <= 0) return T;	/* empty pattern always succeeds */
+    memset (mask,0,256);	/* initialize search validity mask */
+    for (i = 0; i < patc; i++) mask[pat[i]] = T;
+				/* Boyer-Moore type search */
+    for (i = --patc, c = pat[i]; i < basec; i += (mask[c] ? 1 : (j + 1)))
+      for (j = patc,c = base[k = i]; (c == pat[j]); j--,c = base[--k])
+	if (!j) return T;	/* found a match! */
+  }
+  return NIL;			/* pattern not found */
+}
+
+/* Create a hash table
+ * Accepts: size of new table (note: should be a prime)
+ * Returns: hash table
+ */
+
+HASHTAB *hash_create (size_t size)
+{
+  size_t i = sizeof (size_t) + size * sizeof (HASHENT *);
+  HASHTAB *ret = (HASHTAB *) memset (fs_get (i),0,i);
+  ret->size = size;
+  return ret;
+}
+
+
+/* Destroy hash table
+ * Accepts: hash table
+ */
+
+void hash_destroy (HASHTAB **hashtab)
+{
+  if (*hashtab) {
+    hash_reset (*hashtab);	/* reset hash table */
+    fs_give ((void **) hashtab);
+  }
+}
+
+
+/* Reset hash table
+ * Accepts: hash table
+ */
+
+void hash_reset (HASHTAB *hashtab)
+{
+  size_t i;
+  HASHENT *ent,*nxt;
+				/* free each hash entry */
+  for (i = 0; i < hashtab->size; i++) if (ent = hashtab->table[i])
+    for (hashtab->table[i] = NIL; ent; ent = nxt) {
+      nxt = ent->next;		/* get successor */
+      fs_give ((void **) &ent);	/* flush this entry */
+    }
+}
+
+/* Calculate index into hash table
+ * Accepts: hash table
+ *	    entry name
+ * Returns: index
+ */
+
+unsigned long hash_index (HASHTAB *hashtab,char *key)
+{
+  unsigned long i,ret;
+				/* polynomial of letters of the word */
+  for (ret = 0; i = (unsigned int) *key++; ret += i) ret *= HASHMULT;
+  return ret % (unsigned long) hashtab->size;
+}
+
+
+/* Look up name in hash table
+ * Accepts: hash table
+ *	    key
+ * Returns: associated data
+ */
+
+void **hash_lookup (HASHTAB *hashtab,char *key)
+{
+  HASHENT *ret;
+  for (ret = hashtab->table[hash_index (hashtab,key)]; ret; ret = ret->next)
+    if (!strcmp (key,ret->name)) return ret->data;
+  return NIL;
+}
+
+/* Add entry to hash table
+ * Accepts: hash table
+ *	    key
+ *	    associated data
+ *	    number of extra data slots
+ * Returns: hash entry
+ * Caller is responsible for ensuring that entry isn't already in table
+ */
+
+HASHENT *hash_add (HASHTAB *hashtab,char *key,void *data,long extra)
+{
+  unsigned long i = hash_index (hashtab,key);
+  size_t j = sizeof (HASHENT) + (extra * sizeof (void *));
+  HASHENT *ret = (HASHENT *) memset (fs_get (j),0,j);
+  ret->next = hashtab->table[i];/* insert as new head in this index */
+  ret->name = key;		/* set up hash key */
+  ret->data[0] = data;		/* and first data */
+  return hashtab->table[i] = ret;
+}
+
+
+/* Look up name in hash table
+ * Accepts: hash table
+ *	    key
+ *	    associated data
+ *	    number of extra data slots
+ * Returns: associated data
+ */
+
+void **hash_lookup_and_add (HASHTAB *hashtab,char *key,void *data,long extra)
+{
+  HASHENT *ret;
+  unsigned long i = hash_index (hashtab,key);
+  size_t j = sizeof (HASHENT) + (extra * sizeof (void *));
+  for (ret = hashtab->table[i]; ret; ret = ret->next)
+    if (!strcmp (key,ret->name)) return ret->data;
+  ret = (HASHENT *) memset (fs_get (j),0,j);
+  ret->next = hashtab->table[i];/* insert as new head in this index */
+  ret->name = key;		/* set up hash key */
+  ret->data[0] = data;		/* and first data */
+  return (hashtab->table[i] = ret)->data;
+}
+
+/* Convert two hex characters into byte
+ * Accepts: char for high nybble
+ *	    char for low nybble
+ * Returns: byte
+ *
+ * Arguments must be isxdigit validated
+ */
+
+unsigned char hex2byte (unsigned char c1,unsigned char c2)
+{
+				/* merge the two nybbles */
+  return ((c1 -= (isdigit (c1) ? '0' : ((c1 <= 'Z') ? 'A' : 'a') - 10)) << 4) +
+    (c2 - (isdigit (c2) ? '0' : ((c2 <= 'Z') ? 'A' : 'a') - 10));
+}
+
+
+/* Compare two unsigned longs
+ * Accepts: first value
+ *	    second value
+ * Returns: -1 if l1 < l2, 0 if l1 == l2, 1 if l1 > l2
+ */
+
+int compare_ulong (unsigned long l1,unsigned long l2)
+{
+  if (l1 < l2) return -1;
+  if (l1 > l2) return 1;
+  return 0;
+}
+
+
+/* Compare two unsigned chars, case-independent
+ * Accepts: first value
+ *	    second value
+ * Returns: -1 if c1 < c2, 0 if c1 == c2, 1 if c1 > c2
+ *
+ * Don't use isupper/tolower since this function must be ASCII only.
+ */
+
+int compare_uchar (unsigned char c1,unsigned char c2)
+{
+  return compare_ulong (((c1 >= 'A') && (c1 <= 'Z')) ? c1 + ('a' - 'A') : c1,
+			((c2 >= 'A') && (c2 <= 'Z')) ? c2 + ('a' - 'A') : c2);
+}
+
+/* Compare two case-independent ASCII strings
+ * Accepts: first string
+ *	    second string
+ * Returns: -1 if s1 < s2, 0 if s1 == s2, 1 if s1 > s2
+ */
+
+int compare_cstring (unsigned char *s1,unsigned char *s2)
+{
+  int i;
+  if (!s1) return s2 ? -1 : 0;	/* empty string cases */
+  else if (!s2) return 1;
+  for (; *s1 && *s2; s1++,s2++) if (i = (compare_uchar (*s1,*s2))) return i;
+  if (*s1) return 1;		/* first string is longer */
+  return *s2 ? -1 : 0;		/* second string longer : strings identical */
+}
+
+
+/* Compare case-independent string with sized text
+ * Accepts: first string
+ *	    sized text
+ * Returns: -1 if s1 < s2, 0 if s1 == s2, 1 if s1 > s2
+ */
+
+int compare_csizedtext (unsigned char *s1,SIZEDTEXT *s2)
+{
+  int i;
+  unsigned char *s;
+  unsigned long j;
+  if (!s1) return s2 ? -1 : 0;	/* null string cases */
+  else if (!s2) return 1;
+  for (s = (char *) s2->data,j = s2->size; *s1 && j; ++s1,++s,--j)
+    if (i = (compare_uchar (*s1,*s))) return i;
+  if (*s1) return 1;		/* first string is longer */
+  return j ? -1 : 0;		/* second string longer : strings identical */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/misc.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,110 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Miscellaneous utility routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	5 July 1988
+ * Last Edited:	30 August 2006
+ *
+ * This original version of this file is
+ * Copyright 1988 Stanford University
+ * and was developed in the Symbolic Systems Resources Group of the Knowledge
+ * Systems Laboratory at Stanford University in 1987-88, and was funded by the
+ * Biomedical Research Technology Program of the NationalInstitutes of Health
+ * under grant number RR-00785.
+ */
+
+/* Hash table operations */
+
+#define HASHMULT 29		/* hash polynomial multiplier */
+
+#define HASHENT struct hash_entry
+
+HASHENT {
+  HASHENT *next;		/* next entry with same hash code */
+  char *name;			/* name of this hash entry */
+  void *data[1];		/* data of this hash entry */
+};
+
+
+#define HASHTAB struct hash_table
+
+HASHTAB {
+  size_t size;			/* size of this table */
+  HASHENT *table[1];		/* table */
+};
+
+
+/* KLUDGE ALERT!!!
+ *
+ * Yes, write() is overridden here instead of in osdep.  This
+ * is because misc.h is one of the last files that most things #include, so
+ * this should avoid problems with some system #include file.
+ */
+
+#define write safe_write
+
+
+/* Some C compilers have these as macros */
+
+#undef min
+#undef max
+
+
+/* And some C libraries have these as int functions */
+
+#define min Min
+#define max Max
+
+
+/* Compatibility definitions */
+
+#define pmatch(s,pat) \
+  pmatch_full (s,pat,NIL)
+
+/* Function prototypes */
+
+unsigned char *ucase (unsigned char *string);
+unsigned char *lcase (unsigned char *string);
+char *cpystr (const char *string);
+char *cpytxt (SIZEDTEXT *dst,char *text,unsigned long size);
+char *textcpy (SIZEDTEXT *dst,SIZEDTEXT *src);
+char *textcpystring (SIZEDTEXT *text,STRING *bs);
+char *textcpyoffstring (SIZEDTEXT *text,STRING *bs,unsigned long offset,
+			unsigned long size);
+unsigned long find_rightmost_bit (unsigned long *valptr);
+long min (long i,long j);
+long max (long i,long j);
+long search (unsigned char *base,long basec,unsigned char *pat,long patc);
+long ssearch (unsigned char *base,long basec,unsigned char *pat,long patc);
+HASHTAB *hash_create (size_t size);
+void hash_destroy (HASHTAB **hashtab);
+void hash_reset (HASHTAB *hashtab);
+unsigned long hash_index (HASHTAB *hashtab,char *key);
+void **hash_lookup (HASHTAB *hashtab,char *key);
+HASHENT *hash_add (HASHTAB *hashtab,char *key,void *data,long extra);
+void **hash_lookup_and_add (HASHTAB *hashtab,char *key,void *data,long extra);
+unsigned char hex2byte (unsigned char c1,unsigned char c2);
+int compare_ulong (unsigned long l1,unsigned long l2);
+int compare_uchar (unsigned char c1,unsigned char c2);
+int compare_cstring (unsigned char *s1,unsigned char *s2);
+int compare_csizedtext (unsigned char *s1,SIZEDTEXT *s2);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/netmsg.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,104 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Network message (SMTP/NNTP/POP2/POP3) routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	8 June 1995
+ * Last Edited:	6 December 2006
+ */
+
+
+#include <stdio.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "c-client.h"
+#include "netmsg.h"
+#include "flstring.h"
+
+/* Network message read
+ * Accepts: file
+ *	    number of bytes to read
+ *	    buffer address
+ * Returns: T if success, NIL otherwise
+ */
+
+long netmsg_read (void *stream,unsigned long count,char *buffer)
+{
+  return (fread (buffer,(size_t) 1,(size_t) count,(FILE *) stream) == count) ?
+    T : NIL;
+}
+
+/* Slurp dot-terminated text from NET
+ * Accepts: NET stream
+ *	    place to return size
+ *	    place to return header size
+ * Returns: file descriptor
+ */
+
+FILE *netmsg_slurp (NETSTREAM *stream,unsigned long *size,unsigned long *hsiz)
+{
+  unsigned long i;
+  char *s,*t,tmp[MAILTMPLEN];
+  FILE *f = tmpfile ();
+  if (!f) {
+    sprintf (tmp,".%lx.%lx",(unsigned long) time (0),(unsigned long)getpid ());
+    if (f = fopen (tmp,"wb+")) unlink (tmp);
+    else {
+      sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno));
+      MM_LOG (tmp,ERROR);
+      return NIL;
+    }
+  }
+  *size = 0;			/* initially emtpy */
+  if (hsiz) *hsiz = 0;
+  while (s = net_getline (stream)) {
+    if (*s == '.') {		/* possible end of text? */
+      if (s[1]) t = s + 1;	/* pointer to true start of line */
+      else {
+	fs_give ((void **) &s);	/* free the line */
+	break;			/* end of data */
+      }
+    }
+    else t = s;			/* want the entire line */
+    if (f) {			/* copy it to the file */
+      i = strlen (t);		/* size of line */
+      if ((fwrite (t,(size_t) 1,(size_t) i,f) == i) &&
+	  (fwrite ("\015\012",(size_t) 1,(size_t) 2,f) == 2)) {
+	*size += i + 2;		/* tally up size of data */
+				/* note header position */
+	if (!i && hsiz && !*hsiz) *hsiz = *size;
+      }
+      else {
+	sprintf (tmp,"Error writing scratch file at byte %lu",*size);
+	MM_LOG (tmp,ERROR);
+	fclose (f);		/* forget it */
+	f = NIL;		/* failure now */
+      }
+    }
+    fs_give ((void **) &s);	/* free the line */
+  }
+				/* if making a file, rewind to start of file */
+  if (f) fseek (f,(unsigned long) 0,SEEK_SET);
+				/* header consumes entire message */
+  if (hsiz && !*hsiz) *hsiz = *size;
+  return f;			/* return the file descriptor */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/netmsg.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,32 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Network message (SMTP/NNTP/POP2/POP3) routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	8 June 1995
+ * Last Edited:	30 August 2006
+ */
+
+
+				/* stream must be void* for use as readfn_t */
+long netmsg_read (void *stream,unsigned long count,char *buffer);
+FILE *netmsg_slurp (NETSTREAM *stream,unsigned long *size,unsigned long *hsiz);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/newsrc.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,510 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Newsrc manipulation routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	12 September 1994
+ * Last Edited:	30 August 2006
+ */
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include "c-client.h"
+#include "newsrc.h"
+
+#ifndef OLDFILESUFFIX
+#define OLDFILESUFFIX ".old"
+#endif
+
+/* Error message
+ * Accepts: message format
+ *	    additional message string
+ *	    message level
+ * Returns: NIL, always
+ */
+
+long newsrc_error (char *fmt,char *text,long errflg)
+{
+  char tmp[MAILTMPLEN];
+  sprintf (tmp,fmt,text);
+  MM_LOG (tmp,errflg);
+  return NIL;
+}
+
+
+/* Write error message
+ * Accepts: newsrc name
+ *	    file designator
+ *	    file designator
+ * Returns: NIL, always
+ */
+
+long newsrc_write_error (char *name,FILE *f1,FILE *f2)
+{
+  if (f1) fclose (f1);		/* close file designators */
+  if (f2) fclose (f2);
+  return newsrc_error ("Error writing to %.80s",name,ERROR);
+}
+
+
+/* Create newsrc file in local form
+ * Accepts: MAIL stream
+ *	    notification flag
+ * Returns: file designator of newsrc
+ */
+
+FILE *newsrc_create (MAILSTREAM *stream,int notify)
+{
+  char *newsrc = (char *) mail_parameters (stream,GET_NEWSRC,stream);
+  FILE *f = fopen (newsrc,"wb");
+  if (!f) newsrc_error ("Unable to create news state %.80s",newsrc,ERROR);
+  else if (notify) newsrc_error ("Creating news state %.80s",newsrc,WARN);
+  return f;
+}
+
+/* Write new state in newsrc
+ * Accepts: file designator of newsrc
+ *	    group
+ *	    new subscription status character
+ *	    newline convention
+ * Returns: T if successful, NIL otherwise
+ */
+
+long newsrc_newstate (FILE *f,char *group,char state,char *nl)
+{
+  long ret = (f && (fputs (group,f) != EOF) && ((putc (state,f)) != EOF) &&
+	      ((putc (' ',f)) != EOF) && (fputs (nl,f) != EOF)) ? LONGT : NIL;
+  if (fclose (f) == EOF) ret = NIL;
+  return ret;
+}
+
+
+/* Write messages in newsrc
+ * Accepts: file designator of newsrc
+ *	    MAIL stream
+ *	    message number/newsgroup message map
+ *	    newline convention
+ * Returns: T if successful, NIL otherwise
+ */
+
+long newsrc_newmessages (FILE *f,MAILSTREAM *stream,char *nl)
+{
+  unsigned long i,j,k;
+  char tmp[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  int c = ' ';
+  if (stream->nmsgs) {		/* have any messages? */
+    for (i = 1,j = k = (mail_elt (stream,i)->private.uid > 1) ? 1 : 0;
+	 i <= stream->nmsgs; ++i) {
+				/* deleted message? */
+      if ((elt = mail_elt (stream,i))->deleted) {
+	k = elt->private.uid;	/* this is the top of the current range */
+	if (!j) j = k;		/* if no range in progress, start one */
+      }
+      else if (j) {		/* unread message, ending a range */
+				/* calculate end of range */
+	if (k = elt->private.uid - 1) {
+				/* dump range */
+	  sprintf (tmp,(j == k) ? "%c%ld" : "%c%ld-%ld",c,j,k);
+	  if (fputs (tmp,f) == EOF) return NIL;
+	  c = ',';		/* need a comma after the first time */
+	}
+	j = 0;			/* no more range in progress */
+      }
+    }
+    if (j) {			/* dump trailing range */
+      sprintf (tmp,(j == k) ? "%c%ld" : "%c%ld-%ld",c,j,k);
+      if (fputs (tmp,f) == EOF) return NIL;
+    }
+  }
+				/* write trailing newline, return */
+  return (fputs (nl,f) == EOF) ? NIL : LONGT;
+}
+
+/* List subscribed newsgroups
+ * Accepts: MAIL stream
+ *	    prefix to append name
+ * 	    pattern to search
+ */
+
+void newsrc_lsub (MAILSTREAM *stream,char *pattern)
+{
+  char *s,*t,*lcl,name[MAILTMPLEN];
+  int c = ' ';
+  int showuppers = pattern[strlen (pattern) - 1] == '%';
+  FILE *f = fopen ((char *) mail_parameters (stream,GET_NEWSRC,stream),"rb");
+  if (f) {			/* got file? */
+				/* remote name? */
+    if (*(lcl = strcpy (name,pattern)) == '{') lcl = strchr (lcl,'}') + 1;
+    if (*lcl == '#') lcl += 6;	/* namespace format name? */
+    while (c != EOF) {		/* yes, read newsrc */
+      for (s = lcl; (s < (name + MAILTMPLEN - 1)) && ((c = getc (f)) != EOF) &&
+	   (c != ':') && (c != '!') && (c != '\015') && (c != '\012');
+	   *s++ = c);
+      if (c == ':') {		/* found a subscribed newsgroup? */
+	*s = '\0';		/* yes, tie off name */
+				/* report if match */
+	if (pmatch_full (name,pattern,'.')) mm_lsub (stream,'.',name,NIL);
+	else while (showuppers && (t = strrchr (lcl,'.'))) {
+	  *t = '\0';		/* tie off the name */
+	  if (pmatch_full (name,pattern,'.'))
+	    mm_lsub (stream,'.',name,LATT_NOSELECT);
+	}
+      }
+      while ((c != '\015') && (c != '\012') && (c != EOF)) c = getc (f);
+    }
+    fclose (f);
+  }
+}
+
+/* Update subscription status of newsrc
+ * Accepts: MAIL stream
+ * 	    group
+ *	    new subscription status character
+ * Returns: T if successful, NIL otherwise
+ */
+
+long newsrc_update (MAILSTREAM *stream,char *group,char state)
+{
+  char tmp[MAILTMPLEN];
+  char *newsrc = (char *) mail_parameters (stream,GET_NEWSRC,stream);
+  long ret = NIL;
+  FILE *f = fopen (newsrc,"r+b");
+  if (f) {			/* update existing file */
+    int c = 0;
+    char *s,nl[3];
+    long pos = 0;
+    nl[0] = nl[1] = nl[2]='\0';	/* no newline known yet */
+    do {			/* read newsrc */
+      for (s = tmp; (s < (tmp + MAILTMPLEN - 1)) && ((c = getc (f)) != EOF) &&
+	   (c != ':') && (c != '!') && (c != '\015') && (c != '\012');
+	   *s++ = c) pos = ftell (f);
+      *s = '\0';		/* tie off name */
+				/* found the newsgroup? */
+      if (((c == ':') || (c == '!')) && !strcmp (tmp,group)) {
+	if (c == state) {	/* already at that state? */
+	  if (c == ':') newsrc_error("Already subscribed to %.80s",group,WARN);
+	  ret = LONGT;		/* noop the update */
+	}
+				/* write the character */
+	else if (!fseek (f,pos,0)) ret = ((putc (state,f)) == EOF) ? NIL:LONGT;
+	if (fclose (f) == EOF) ret = NIL;
+	f = NIL;		/* done with file */
+	break;
+      }
+				/* gobble remainder of this line */
+      while ((c != '\015') && (c != '\012') && (c != EOF)) c = getc (f);
+				/* need to know about newlines and found it? */
+      if (!nl[0] && ((c == '\015') || (c == '\012')) && ((nl[0]=c) == '\015')){
+				/* sniff and see if an LF */
+	if ((c = getc (f)) == '\012') nl[1] = c;
+	else ungetc (c,f);	/* nope, push it back */
+      }
+    } while (c != EOF);
+
+    if (f) {			/* still haven't written it yet? */
+      if (nl[0]) {		/* know its newline convention? */
+	fseek (f,0L,2);		/* yes, seek to end of file */
+	ret = newsrc_newstate (f,group,state,nl);
+      }
+      else {			/* can't find a newline convention */
+	fclose (f);		/* punt the file */
+				/* can't win if read something */
+	if (pos) newsrc_error ("Unknown newline convention in %.80s",
+			       newsrc,ERROR);
+				/* file must have been empty, rewrite it */
+	else ret = newsrc_newstate(newsrc_create(stream,NIL),group,state,"\n");
+      }
+    }
+  }
+				/* create new file */
+  else ret = newsrc_newstate (newsrc_create (stream,T),group,state,"\n");
+  return ret;			/* return with update status */
+}
+
+/* Update newsgroup status in stream
+ * Accepts: newsgroup name
+ *	    MAIL stream
+ * Returns: number of recent messages
+ */
+
+long newsrc_read (char *group,MAILSTREAM *stream)
+{
+  int c = 0;
+  char *s,tmp[MAILTMPLEN];
+  unsigned long i,j;
+  MESSAGECACHE *elt;
+  unsigned long m = 1,recent = 0,unseen = 0;
+  FILE *f = fopen ((char *) mail_parameters (stream,GET_NEWSRC,stream),"rb");
+  if (f) do {			/* read newsrc */
+    for (s = tmp; (s < (tmp + MAILTMPLEN - 1)) && ((c = getc (f)) != EOF) &&
+	 (c != ':') && (c != '!') && (c != '\015') && (c != '\012'); *s++ = c);
+    *s = '\0';			/* tie off name */
+    if ((c==':') || (c=='!')) {	/* found newsgroup? */
+      if (strcmp (tmp,group))	/* group name match? */
+	while ((c != '\015') && (c != '\012') && (c != EOF)) c = getc (f);
+      else {			/* yes, skip leading whitespace */
+	while ((c = getc (f)) == ' ');
+				/* only if unprocessed messages */
+	if (stream->nmsgs) while (f && (m <= stream->nmsgs)) {
+				/* collect a number */
+	  if (isdigit (c)) {	/* better have a number */
+	    for (i = 0,j = 0; isdigit (c); c = getc (f)) i = i*10 + (c-'0');
+	    if (c == '-') for (c = getc (f); isdigit (c); c = getc (f))
+	      j = j*10 +(c-'0');/* collect second value if range */
+	    if (!unseen && (mail_elt (stream,m)->private.uid < i)) unseen = m;
+				/* skip messages before first value */
+	    while ((m <= stream->nmsgs) &&
+		   ((elt = mail_elt (stream,m))->private.uid < i) && m++)
+	      elt->valid = T;
+				/* do all messages in range */
+	    while ((m <= stream->nmsgs) && (elt = mail_elt (stream,m)) &&
+		   (j ? ((elt->private.uid >= i) && (elt->private.uid <= j)) :
+		    (elt->private.uid == i)) && m++)
+	      elt->valid = elt->deleted = T;
+	  }
+
+	  switch (c) {		/* what is the delimiter? */
+	  case ',':		/* more to come */
+	    c = getc (f);	/* get first character of number */
+	    break;
+	  default:		/* bogus character */
+	    sprintf (tmp,"Bogus character 0x%x in news state",(unsigned int)c);
+	    MM_LOG (tmp,ERROR);
+	  case EOF: case '\015': case '\012':
+	    fclose (f);		/* all done - close the file */
+	    f = NIL;
+	    break;
+	  }
+	}
+	else {			/* empty newsgroup */
+	  while ((c != '\015') && (c != '\012') && (c != EOF)) c = getc (f);
+	  fclose (f);		/* all done - close the file */
+	  f = NIL;
+	}
+      }
+    }
+  } while (f && (c != EOF));	/* until file closed or EOF */
+  if (f) {			/* still have file open? */
+    sprintf (tmp,"No state for newsgroup %.80s found, reading as new",group);
+    MM_LOG (tmp,WARN);
+    fclose (f);			/* close the file */
+  }
+  if (m <= stream->nmsgs) {	/* any messages beyond newsrc range? */
+    if (!unseen) unseen = m;	/* then this must be the first unseen one */
+    do {
+      elt = mail_elt (stream,m++);
+      elt->valid = elt->recent = T;
+      ++recent;			/* count another recent message */
+    }
+    while (m <= stream->nmsgs);
+  }
+  if (unseen) {			/* report first unseen message */
+    sprintf (tmp,"[UNSEEN] %lu is first unseen message in %.80s",unseen,group);
+    MM_NOTIFY (stream,tmp,(long) NIL);
+  }
+  return recent;
+}
+
+/* Update newsgroup entry in newsrc
+ * Accepts: newsgroup name
+ *	    MAIL stream
+ * Returns: T if successful, NIL otherwise
+ */
+
+long newsrc_write (char *group,MAILSTREAM *stream)
+{
+  long ret = NIL;
+  int c = 0,d = EOF;
+  char *newsrc = (char *) mail_parameters (stream,GET_NEWSRC,stream);
+  char *s,tmp[MAILTMPLEN],backup[MAILTMPLEN],nl[3];
+  FILE *f,*bf;
+  nl[0] = nl[1] = nl[2] = '\0';	/* no newline known yet */
+  if (f = fopen (newsrc,"rb")) {/* have existing newsrc file? */
+    if (!(bf = fopen ((strcat (strcpy (backup,newsrc),OLDFILESUFFIX)),"wb"))) {
+      fclose (f);		/* punt input file */
+      return newsrc_error("Can't create backup news state %.80s",backup,ERROR);
+    }
+				/* copy to backup file */
+    while ((c = getc (f)) != EOF) {
+				/* need to know about newlines and found it? */
+      if (!nl[0] && ((c == '\015') || (c == '\012')) && ((nl[0]=c) == '\015')){
+				/* sniff and see if an LF */
+	if ((c = getc (f)) == '\012') nl[1] = c;
+	ungetc (c,f);		/* push it back */
+      }
+				/* write to backup file */
+      if ((d = putc (c,bf)) == EOF) {
+	fclose (f);		/* punt input file */
+	return newsrc_error ("Error writing backup news state %.80s",
+			     newsrc,ERROR);
+      }
+    }
+    fclose (f);			/* close existing file */
+    if (fclose (bf) == EOF)	/* and backup file */
+      return newsrc_error ("Error closing backup news state %.80s",
+			   newsrc,ERROR);
+    if (d == EOF) {		/* open for write if empty file */
+      if (f = newsrc_create (stream,NIL)) bf = NIL;
+      else return NIL;
+    }
+    else if (!nl[0])		/* make sure newlines valid */
+      return newsrc_error ("Unknown newline convention in %.80s",newsrc,ERROR);
+				/* now read backup file */
+    else if (!(bf = fopen (backup,"rb")))
+      return newsrc_error ("Error reading backup news state %.80s",
+			   backup,ERROR);
+				/* open newsrc for writing */
+    else if (!(f = fopen (newsrc,"wb"))) {
+      fclose (bf);		/* punt backup */
+      return newsrc_error ("Can't rewrite news state %.80s",newsrc,ERROR);
+    }
+  }
+  else {			/* create new newsrc file */
+    if (f = newsrc_create (stream,T)) bf = NIL;
+    else return NIL;		/* can't create newsrc */
+  }
+  
+  while (bf) {			/* read newsrc */
+    for (s = tmp; (s < (tmp + MAILTMPLEN - 1)) && ((c = getc (bf)) != EOF) &&
+	 (c != ':') && (c != '!') && (c != '\015') && (c != '\012'); *s++ = c);
+    *s = '\0';			/* tie off name */
+				/* saw correct end of group delimiter? */
+    if (tmp[0] && ((c == ':') || (c == '!'))) {
+				/* yes, write newsgroup name and delimiter */
+      if ((tmp[0] && (fputs (tmp,f) == EOF)) || ((putc (c,f)) == EOF))
+	return newsrc_write_error (newsrc,bf,f);
+      if (!strcmp (tmp,group)) {/* found correct group? */
+				/* yes, write new status */
+	if (!newsrc_newmessages (f,stream,nl[0] ? nl : "\n"))
+	  return newsrc_write_error (newsrc,bf,f);
+				/* skip past old data */
+	while (((c = getc (bf)) != EOF) && (c != '\015') && (c != '\012'));
+				/* skip past newline */
+	while ((c == '\015') || (c == '\012')) c = getc (bf);
+	while (c != EOF) {	/* copy remainder of file */
+	  if (putc (c,f) == EOF) return newsrc_write_error (newsrc,bf,f);
+	  c = getc (bf);	/* get next character */
+	}
+				/* done with file */
+	if (fclose (f) == EOF) return newsrc_write_error (newsrc,bf,NIL);
+	f = NIL;
+      }
+				/* copy remainder of line */
+      else while (((c = getc (bf)) != EOF) && (c != '\015') && (c != '\012'))
+	if (putc (c,f) == EOF) return newsrc_write_error (newsrc,bf,f);
+      if (c == '\015') {	/* write CR if seen */
+	if (putc (c,f) == EOF) return newsrc_write_error (newsrc,bf,f);
+				/* sniff to see if LF */
+	if (((c = getc (bf)) != EOF) && (c != '\012')) ungetc (c,bf);
+      }
+				/* write LF if seen */
+      if ((c == '\012') && (putc (c,f) == EOF))
+	return newsrc_write_error (newsrc,bf,f);
+    }
+    if (c == EOF) {		/* hit end of file? */
+      fclose (bf);		/* yup, close the file */
+      bf = NIL;
+    }
+  }
+  if (f) {			/* still have newsrc file open? */
+    ret = ((fputs (group,f) != EOF) && ((putc (':',f)) != EOF) &&
+	   newsrc_newmessages (f,stream,nl[0] ? nl : "\n")) ? LONGT : NIL;
+    if (fclose (f) == EOF) ret = newsrc_write_error (newsrc,NIL,NIL);
+  }
+  else ret = LONGT;
+  return ret;
+}
+
+/* Get newsgroup state as text stream
+ * Accepts: MAIL stream
+ *	    newsgroup name
+ * Returns: string containing newsgroup state, or NIL if not found
+ */
+
+char *newsrc_state (MAILSTREAM *stream,char *group)
+{
+  int c = 0;
+  char *s,tmp[MAILTMPLEN];
+  long pos;
+  size_t size;
+  FILE *f = fopen ((char *) mail_parameters (stream,GET_NEWSRC,stream),"rb");
+  if (f) do {			/* read newsrc */
+    for (s = tmp; (s < (tmp + MAILTMPLEN - 1)) && ((c = getc (f)) != EOF) &&
+	 (c != ':') && (c != '!') && (c != '\015') && (c != '\012'); *s++ = c);
+    *s = '\0';			/* tie off name */
+    if ((c==':') || (c=='!')) {	/* found newsgroup? */
+      if (strcmp (tmp,group))	/* group name match? */
+	while ((c != '\015') && (c != '\012') && (c != EOF)) c = getc (f);
+      else {			/* yes, skip leading whitespace */
+	do pos = ftell (f);
+	while ((c = getc (f)) == ' ');
+				/* count characters in state */
+	for (size = 0; (c != '\015') && (c != '\012') && (c != EOF); size++)
+	  c = getc (f);
+				/* now copy it */
+	s = (char *) fs_get (size + 1);
+	fseek (f,pos,SEEK_SET);
+	fread (s,(size_t) 1,size,f);
+	s[size] = '\0';		/* tie off string */
+	fclose (f);		/* all done - close the file */
+	return s;
+      }
+    }
+  } while (f && (c != EOF));	/* until file closed or EOF */
+  sprintf (tmp,"No state for newsgroup %.80s found",group);
+  MM_LOG (tmp,WARN);
+  if (f) fclose (f);		/* close the file */
+  return NIL;			/* not found return */
+}
+
+/* Check UID in newsgroup state
+ * Accepts: newsgroup state string
+ *	    uid
+ *	    returned recent count
+ *	    returned unseen count
+ */
+
+void newsrc_check_uid (unsigned char *state,unsigned long uid,
+		       unsigned long *recent,unsigned long *unseen)
+{
+  unsigned long i,j;
+  while (*state) {		/* until run out of state string */
+				/* collect a number */
+    for (i = 0; isdigit (*state); i = i*10 + (*state++ - '0'));
+    if (*state != '-') j = i;	/* coerce single mesage into range */
+    else {			/* have a range */
+      for (j = 0; isdigit (*++state); j = j*10 + (*state - '0'));
+      if (!j) j = i;		/* guard against -0 */
+      if (j < i) return;	/* bogon if end less than start */
+    }
+    if (*state == ',') state++;	/* skip past comma */
+    else if (*state) return;	/* otherwise it's a bogon */
+    if (uid <= j) {		/* covered by upper bound? */
+      if (uid < i) ++*unseen;	/* unseen if not covered by lower bound */
+      return;			/* don't need to look further */
+    }
+  }
+  ++*unseen;			/* not found in any range, message is unseen */
+  ++*recent;			/* and recent */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/newsrc.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,43 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Newsrc manipulation routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	12 September 1994
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Function prototypes */
+
+long newsrc_error (char *fmt,char *text,long errflg);
+long newsrc_write_error (char *name,FILE *f1,FILE *f2);
+FILE *newsrc_create (MAILSTREAM *stream,int notify);
+long newsrc_newstate (FILE *f,char *group,char state,char *nl);
+long newsrc_newmessages (FILE *f,MAILSTREAM *stream,char *nl);
+void newsrc_lsub (MAILSTREAM *stream,char *pattern);
+long newsrc_update (MAILSTREAM *stream,char *group,char state);
+long newsrc_read (char *group,MAILSTREAM *stream);
+long newsrc_write (char *group,MAILSTREAM *stream);
+char *newsrc_state (MAILSTREAM *stream,char *group);
+void newsrc_check_uid (unsigned char *state,unsigned long uid,
+		       unsigned long *recent,unsigned long *unseen);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/nl.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,34 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Newline routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Function prototypes */
+
+unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl,
+			  unsigned char *src,unsigned long srcl);
+unsigned long strcrlflen (STRING *s);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/nntp.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,2224 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Network News Transfer Protocol (NNTP) routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 February 1992
+ * Last Edited:	6 September 2007
+ */
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include "c-client.h"
+#include "newsrc.h"
+#include "netmsg.h"
+#include "flstring.h"
+
+/* Constants */
+
+#define NNTPSSLPORT (long) 563	/* assigned SSL TCP contact port */
+#define NNTPGREET (long) 200	/* NNTP successful greeting */
+				/* NNTP successful greeting w/o posting priv */
+#define NNTPGREETNOPOST (long) 201
+#define NNTPEXTOK (long) 202	/* NNTP extensions OK */
+#define NNTPGOK (long) 211	/* NNTP group selection OK */
+#define NNTPGLIST (long) 215	/* NNTP group list being returned */
+#define NNTPARTICLE (long) 220	/* NNTP article file */
+#define NNTPHEAD (long) 221	/* NNTP header text */
+#define NNTPBODY (long) 222	/* NNTP body text */
+#define NNTPOVER (long) 224	/* NNTP overview text */
+#define NNTPOK (long) 240	/* NNTP OK code */
+#define NNTPAUTHED (long) 281	/* NNTP successful authentication */
+				/* NNTP successful authentication with data */
+#define NNTPAUTHEDDATA (long) 282
+#define NNTPREADY (long) 340	/* NNTP ready for data */
+#define NNTPWANTAUTH2 (long) 380/* NNTP authentication needed (old) */
+#define NNTPWANTPASS (long) 381	/* NNTP password needed */
+#define NNTPTLSSTART (long) 382	/* NNTP continue with TLS negotiation */
+#define NNTPCHALLENGE (long) 383/* NNTP challenge, want response */
+#define NNTPSOFTFATAL (long) 400/* NNTP soft fatal code */
+#define NNTPWANTAUTH (long) 480	/* NNTP authentication needed */
+#define NNTPBADCMD (long) 500	/* NNTP unrecognized command */
+#define IDLETIMEOUT (long) 3	/* defined in NNTPEXT WG base draft */
+
+
+/* NNTP I/O stream local data */
+	
+typedef struct nntp_local {
+  SENDSTREAM *nntpstream;	/* NNTP stream for I/O */
+  unsigned int dirty : 1;	/* disk copy of .newsrc needs updating */
+  unsigned int tlsflag : 1;	/* TLS session */
+  unsigned int tlssslv23 : 1;	/* TLS using SSLv23 client method */
+  unsigned int notlsflag : 1;	/* TLS not used in session */
+  unsigned int sslflag : 1;	/* SSL session */
+  unsigned int novalidate : 1;	/* certificate not validated */
+  unsigned int xover : 1;	/* supports XOVER */
+  unsigned int xhdr : 1;	/* supports XHDR */
+  char *name;			/* remote newsgroup name */
+  char *user;			/* mailbox user */
+  char *newsrc;			/* newsrc file */
+  char *over_fmt;		/* overview format */
+  unsigned long msgno;		/* current text message number */
+  FILE *txt;			/* current text */
+  unsigned long txtsize;	/* current text size */
+} NNTPLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((NNTPLOCAL *) stream->local)
+
+
+/* Convenient access to protocol-specific data */
+
+#define NNTP stream->protocol.nntp
+
+
+/* Convenient access to extensions */
+
+#define EXTENSION LOCAL->nntpstream->protocol.nntp.ext
+
+/* Function prototypes */
+
+DRIVER *nntp_valid (char *name);
+DRIVER *nntp_isvalid (char *name,char *mbx);
+void *nntp_parameters (long function,void *value);
+void nntp_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void nntp_list (MAILSTREAM *stream,char *ref,char *pat);
+void nntp_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long nntp_canonicalize (char *ref,char *pat,char *pattern,char *wildmat);
+long nntp_subscribe (MAILSTREAM *stream,char *mailbox);
+long nntp_unsubscribe (MAILSTREAM *stream,char *mailbox);
+long nntp_create (MAILSTREAM *stream,char *mailbox);
+long nntp_delete (MAILSTREAM *stream,char *mailbox);
+long nntp_rename (MAILSTREAM *stream,char *old,char *newname);
+long nntp_status (MAILSTREAM *stream,char *mbx,long flags);
+long nntp_getmap (MAILSTREAM *stream,char *name,
+		  unsigned long first,unsigned long last,
+		  unsigned long rnmsgs,unsigned long nmsgs,char *tmp);
+MAILSTREAM *nntp_mopen (MAILSTREAM *stream);
+void nntp_mclose (MAILSTREAM *stream,long options);
+void nntp_fetchfast (MAILSTREAM *stream,char *sequence,long flags);
+void nntp_flags (MAILSTREAM *stream,char *sequence,long flags);
+long nntp_overview (MAILSTREAM *stream,overview_t ofn);
+long nntp_parse_overview (OVERVIEW *ov,char *text,MESSAGECACHE *elt);
+long nntp_over (MAILSTREAM *stream,char *sequence);
+char *nntp_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *size,
+		   long flags);
+long nntp_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+FILE *nntp_article (MAILSTREAM *stream,char *msgid,unsigned long *size,
+		    unsigned long *hsiz);
+void nntp_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
+long nntp_search (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,long flags);
+long nntp_search_msg (MAILSTREAM *stream,unsigned long msgno,SEARCHPGM *pgm,
+		      OVERVIEW *ov);
+unsigned long *nntp_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
+			  SORTPGM *pgm,long flags);
+SORTCACHE **nntp_sort_loadcache (MAILSTREAM *stream,SORTPGM *pgm,
+				 unsigned long start,unsigned long last,
+				 long flags);
+THREADNODE *nntp_thread (MAILSTREAM *stream,char *type,char *charset,
+			 SEARCHPGM *spg,long flags);
+long nntp_ping (MAILSTREAM *stream);
+void nntp_check (MAILSTREAM *stream);
+long nntp_expunge (MAILSTREAM *stream,char *sequence,long options);
+long nntp_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long nntp_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+long nntp_extensions (SENDSTREAM *stream,long flags);
+long nntp_send (SENDSTREAM *stream,char *command,char *args);
+long nntp_send_work (SENDSTREAM *stream,char *command,char *args);
+long nntp_send_auth (SENDSTREAM *stream,long flags);
+long nntp_send_auth_work (SENDSTREAM *stream,NETMBX *mb,char *pwd,long flags);
+void *nntp_challenge (void *s,unsigned long *len);
+long nntp_response (void *s,char *response,unsigned long size);
+long nntp_reply (SENDSTREAM *stream);
+long nntp_fake (SENDSTREAM *stream,char *text);
+long nntp_soutr (void *stream,char *s);
+
+/* Driver dispatch used by MAIL */
+
+DRIVER nntpdriver = {
+  "nntp",			/* driver name */
+				/* driver flags */
+#ifdef INADEQUATE_MEMORY
+  DR_LOWMEM |
+#endif
+  DR_NEWS|DR_READONLY|DR_NOFAST|DR_NAMESPACE|DR_CRLF|DR_RECYCLE|DR_XPOINT |
+    DR_NOINTDATE|DR_NONEWMAIL|DR_HALFOPEN,
+  (DRIVER *) NIL,		/* next driver */
+  nntp_valid,			/* mailbox is valid for us */
+  nntp_parameters,		/* manipulate parameters */
+  nntp_scan,			/* scan mailboxes */
+  nntp_list,			/* find mailboxes */
+  nntp_lsub,			/* find subscribed mailboxes */
+  nntp_subscribe,		/* subscribe to mailbox */
+  nntp_unsubscribe,		/* unsubscribe from mailbox */
+  nntp_create,			/* create mailbox */
+  nntp_delete,			/* delete mailbox */
+  nntp_rename,			/* rename mailbox */
+  nntp_status,			/* status of mailbox */
+  nntp_mopen,			/* open mailbox */
+  nntp_mclose,			/* close mailbox */
+  nntp_fetchfast,		/* fetch message "fast" attributes */
+  nntp_flags,			/* fetch message flags */
+  nntp_overview,		/* fetch overview */
+  NIL,				/* fetch message structure */
+  nntp_header,			/* fetch message header */
+  nntp_text,			/* fetch message text */
+  NIL,				/* fetch message */
+  NIL,				/* unique identifier */
+  NIL,				/* message number from UID */
+  NIL,				/* modify flags */
+  nntp_flagmsg,			/* per-message modify flags */
+  nntp_search,			/* search for message based on criteria */
+  nntp_sort,			/* sort messages */
+  nntp_thread,			/* thread messages */
+  nntp_ping,			/* ping mailbox to see if still alive */
+  nntp_check,			/* check for new messages */
+  nntp_expunge,			/* expunge deleted messages */
+  nntp_copy,			/* copy messages to another mailbox */
+  nntp_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM nntpproto = {&nntpdriver};
+
+
+				/* driver parameters */
+static unsigned long nntp_maxlogintrials = MAXLOGINTRIALS;
+static long nntp_port = 0;
+static long nntp_sslport = 0;
+static unsigned long nntp_range = 0;
+static long nntp_hidepath = 0;
+
+/* NNTP validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *nntp_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+  return nntp_isvalid (name,tmp);
+}
+
+
+/* NNTP validate mailbox work routine
+ * Accepts: mailbox name
+ *	    buffer for returned mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *nntp_isvalid (char *name,char *mbx)
+{
+  NETMBX mb;
+  if (!mail_valid_net_parse (name,&mb) || strcmp (mb.service,nntpdriver.name)||
+      mb.anoflag) return NIL;
+  if (mb.mailbox[0] != '#') strcpy (mbx,mb.mailbox);
+			/* namespace format name */
+  else if ((mb.mailbox[1] == 'n') && (mb.mailbox[2] == 'e') &&
+	   (mb.mailbox[3] == 'w') && (mb.mailbox[4] == 's') &&
+	   (mb.mailbox[5] == '.')) strcpy (mbx,mb.mailbox+6);
+  else return NIL;		/* bogus name */
+  return &nntpdriver;
+}
+
+/* News manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *nntp_parameters (long function,void *value)
+{
+  switch ((int) function) {
+  case SET_MAXLOGINTRIALS:
+    nntp_maxlogintrials = (unsigned long) value;
+    break;
+  case GET_MAXLOGINTRIALS:
+    value = (void *) nntp_maxlogintrials;
+    break;
+  case SET_NNTPPORT:
+    nntp_port = (long) value;
+    break;
+  case GET_NNTPPORT:
+    value = (void *) nntp_port;
+    break;
+  case SET_SSLNNTPPORT:
+    nntp_sslport = (long) value;
+    break;
+  case GET_SSLNNTPPORT:
+    value = (void *) nntp_sslport;
+    break;
+  case SET_NNTPRANGE:
+    nntp_range = (unsigned long) value;
+    break;
+  case GET_NNTPRANGE:
+    value = (void *) nntp_range;
+    break;
+  case SET_NNTPHIDEPATH:
+    nntp_hidepath = (long) value;
+    break;
+  case GET_NNTPHIDEPATH:
+    value = (void *) nntp_hidepath;
+    break;
+  case GET_NEWSRC:
+    if (value)
+      value = (void *) ((NNTPLOCAL *) ((MAILSTREAM *) value)->local)->newsrc;
+    break;
+  case GET_IDLETIMEOUT:
+    value = (void *) IDLETIMEOUT;
+    break;
+  case ENABLE_DEBUG:
+    if (value)
+      ((NNTPLOCAL *) ((MAILSTREAM *) value)->local)->nntpstream->debug = T;
+    break;
+  case DISABLE_DEBUG:
+    if (value)
+      ((NNTPLOCAL *) ((MAILSTREAM *) value)->local)->nntpstream->debug = NIL;
+    break;
+  default:
+    value = NIL;		/* error case */
+    break;
+  }
+  return value;
+}
+
+/* NNTP mail scan mailboxes for string
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void nntp_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  char tmp[MAILTMPLEN];
+  if (nntp_canonicalize (ref,pat,tmp,NIL))
+    mm_log ("Scan not valid for NNTP mailboxes",ERROR);
+}
+
+
+/* NNTP list newsgroups
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void nntp_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  MAILSTREAM *st = stream;
+  char *s,*t,*lcl,pattern[MAILTMPLEN],name[MAILTMPLEN],wildmat[MAILTMPLEN];
+  int showuppers = pat[strlen (pat) - 1] == '%';
+  if (!*pat) {
+    if (nntp_canonicalize (ref,"*",pattern,NIL)) {
+				/* tie off name at root */
+      if ((s = strchr (pattern,'}')) && (s = strchr (s+1,'.'))) *++s = '\0';
+      else pattern[0] = '\0';
+      mm_list (stream,'.',pattern,NIL);
+    }
+  }
+				/* ask server for open newsgroups */
+  else if (nntp_canonicalize (ref,pat,pattern,wildmat) &&
+	   ((stream && LOCAL && LOCAL->nntpstream) ||
+	    (stream = mail_open (NIL,pattern,OP_HALFOPEN|OP_SILENT))) &&
+	   ((nntp_send (LOCAL->nntpstream,"LIST ACTIVE",
+			wildmat[0] ? wildmat : NIL) == NNTPGLIST) ||
+	    (nntp_send (LOCAL->nntpstream,"LIST",NIL) == NNTPGLIST))) {
+				/* namespace format name? */
+    if (*(lcl = strchr (strcpy (name,pattern),'}') + 1) == '#') lcl += 6;
+				/* process data until we see final dot */
+    while (s = net_getline (LOCAL->nntpstream->netstream)) {
+      if ((*s == '.') && !s[1]){/* end of text */
+	fs_give ((void **) &s);
+	break;
+      }
+      if (t = strchr (s,' ')) {	/* tie off after newsgroup name */
+	*t = '\0';
+	strcpy (lcl,s);		/* make full form of name */
+				/* report if match */
+	if (pmatch_full (name,pattern,'.')) mm_list (stream,'.',name,NIL);
+	else while (showuppers && (t = strrchr (lcl,'.'))) {
+	  *t = '\0';		/* tie off the name */
+	  if (pmatch_full (name,pattern,'.'))
+	    mm_list (stream,'.',name,LATT_NOSELECT);
+	}
+      }
+      fs_give ((void **) &s);	/* clean up */
+    }
+    if (stream != st) mail_close (stream);
+  }
+}
+
+/* NNTP list subscribed newsgroups
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void nntp_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  void *sdb = NIL;
+  char *s,mbx[MAILTMPLEN];
+				/* return data from newsrc */
+  if (nntp_canonicalize (ref,pat,mbx,NIL)) newsrc_lsub (stream,mbx);
+  if (*pat == '{') {		/* if remote pattern, must be NNTP */
+    if (!nntp_valid (pat)) return;
+    ref = NIL;			/* good NNTP pattern, punt reference */
+  }
+				/* if remote reference, must be valid NNTP */
+  if (ref && (*ref == '{') && !nntp_valid (ref)) return;
+				/* kludgy application of reference */
+  if (ref && *ref) sprintf (mbx,"%s%s",ref,pat);
+  else strcpy (mbx,pat);
+
+  if (s = sm_read (&sdb)) do if (nntp_valid (s) && pmatch (s,mbx))
+    mm_lsub (stream,NIL,s,NIL);
+  while (s = sm_read (&sdb));	/* until no more subscriptions */
+}
+
+/* NNTP canonicalize newsgroup name
+ * Accepts: reference
+ *	    pattern
+ *	    returned single pattern
+ *	    returned wildmat pattern
+ * Returns: T on success, NIL on failure
+ */
+
+long nntp_canonicalize (char *ref,char *pat,char *pattern,char *wildmat)
+{
+  char *s;
+  DRIVER *ret;
+  if (ref && *ref) {		/* have a reference */
+    if (!nntp_valid (ref)) return NIL;
+    strcpy (pattern,ref);	/* copy reference to pattern */
+				/* # overrides mailbox field in reference */
+    if (*pat == '#') strcpy (strchr (pattern,'}') + 1,pat);
+				/* pattern starts, reference ends, with . */
+    else if ((*pat == '.') && (pattern[strlen (pattern) - 1] == '.'))
+      strcat (pattern,pat + 1);	/* append, omitting one of the period */
+    else strcat (pattern,pat);	/* anything else is just appended */
+  }
+  else strcpy (pattern,pat);	/* just have basic name */
+  if ((ret = wildmat ?		/* if valid and wildmat */
+       nntp_isvalid (pattern,wildmat) : nntp_valid (pattern)) && wildmat) {
+				/* don't return wildmat if specials present */
+    if (strpbrk (wildmat,",?![\\]")) wildmat[0] = '\0';
+				/* replace all % with * */
+    for (s = wildmat; s = strchr (s,'%'); *s = '*');
+  }
+  return ret ? LONGT : NIL;
+}
+
+/* NNTP subscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to add to subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long nntp_subscribe (MAILSTREAM *stream,char *mailbox)
+{
+  char mbx[MAILTMPLEN];
+  return nntp_isvalid (mailbox,mbx) ? newsrc_update (stream,mbx,':') : NIL;
+}
+
+
+/* NNTP unsubscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to delete from subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long nntp_unsubscribe (MAILSTREAM *stream,char *mailbox)
+{
+  char mbx[MAILTMPLEN];
+  return nntp_isvalid (mailbox,mbx) ? newsrc_update (stream,mbx,'!') : NIL;
+}
+
+/* NNTP create mailbox
+ * Accepts: mail stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long nntp_create (MAILSTREAM *stream,char *mailbox)
+{
+  return NIL;			/* never valid for NNTP */
+}
+
+
+/* NNTP delete mailbox
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long nntp_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return NIL;			/* never valid for NNTP */
+}
+
+
+/* NNTP rename mailbox
+ * Accepts: mail stream
+ *	    old mailbox name
+ *	    new mailbox name
+ * Returns: T on success, NIL on failure
+ */
+
+long nntp_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  return NIL;			/* never valid for NNTP */
+}
+
+/* NNTP status
+ * Accepts: mail stream
+ *	    mailbox name
+ *	    status flags
+ * Returns: T on success, NIL on failure
+ */
+
+long nntp_status (MAILSTREAM *stream,char *mbx,long flags)
+{
+  MAILSTATUS status;
+  NETMBX mb;
+  unsigned long i,j,k,rnmsgs;
+  long ret = NIL;
+  char *s,*name,*state,tmp[MAILTMPLEN];
+  char *old = (stream && !stream->halfopen) ? LOCAL->name : NIL;
+  MAILSTREAM *tstream = NIL;
+  if (!(mail_valid_net_parse (mbx,&mb) && !strcmp (mb.service,"nntp") &&
+	*mb.mailbox &&
+	((mb.mailbox[0] != '#') ||
+	 ((mb.mailbox[1] == 'n') && (mb.mailbox[2] == 'e') &&
+	  (mb.mailbox[3] == 'w') && (mb.mailbox[4] == 's') &&
+	  (mb.mailbox[5] == '.'))))) {
+    sprintf (tmp,"Invalid NNTP name %s",mbx);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* note mailbox name */
+  name = (*mb.mailbox == '#') ? mb.mailbox+6 : mb.mailbox;
+				/* stream to reuse? */
+  if (!(stream && LOCAL->nntpstream &&
+	mail_usable_network_stream (stream,mbx)) &&
+      !(tstream = stream =
+	mail_open (NIL,mbx,OP_HALFOPEN|OP_SILENT|
+		   ((flags & SA_MULNEWSRC) ? OP_MULNEWSRC : NIL))))
+    return NIL;			/* can't reuse or make a new one */
+
+  if (nntp_send (LOCAL->nntpstream,"GROUP",name) == NNTPGOK) {
+    status.flags = flags;	/* status validity flags */
+    k = strtoul (LOCAL->nntpstream->reply + 4,&s,10);
+    i = strtoul (s,&s,10);	/* first assigned UID */
+				/* next UID to be assigned */
+    status.uidnext = (j = strtoul (s,NIL,10)) + 1;
+				/* maximum number of messages */
+    rnmsgs = status.messages = (i | j) ? status.uidnext - i : 0;
+    if (k > status.messages) {	/* check for absurdity */
+      sprintf (tmp,"NNTP SERVER BUG (impossible message count): %lu > %lu",
+	       k,status.messages);
+      mm_log (tmp,WARN);
+    }
+				/* restrict article range if needed */
+    if (nntp_range && (status.messages > nntp_range)) {
+      i = status.uidnext - (status.messages = nntp_range);
+      if (k > nntp_range) k = nntp_range;
+    }
+				/* initially zero */
+    status.recent = status.unseen = 0;
+    if (!status.messages);	/* empty case */
+				/* use server guesstimate in simple case */
+    else if (!(flags & (SA_RECENT | SA_UNSEEN))) status.messages = k;
+
+				/* have newsrc state? */
+    else if (state = newsrc_state (stream,name)) {
+				/* yes, get the UID/sequence map */
+      if (nntp_getmap (stream,name,i,status.uidnext - 1,rnmsgs,
+		       status.messages,tmp)) {
+				/* calculate true count */
+	for (status.messages = 0;
+	     (s = net_getline (LOCAL->nntpstream->netstream)) &&
+	       strcmp (s,"."); ) {
+				/* only count if in range */
+	  if (((k = atol (s)) >= i) && (k < status.uidnext)) {
+	    newsrc_check_uid (state,k,&status.recent,&status.unseen);
+	    status.messages++;
+	  }
+	  fs_give ((void **) &s);
+	}
+	if (s) fs_give ((void **) &s);
+      }
+				/* assume c-client/NNTP map is entire range */
+      else while (i < status.uidnext)
+	newsrc_check_uid (state,i++,&status.recent,&status.unseen);
+      fs_give ((void **) &state);
+    }
+				/* no .newsrc state, all messages new */
+    else status.recent = status.unseen = status.messages;
+				/* UID validity is a constant */
+    status.uidvalidity = stream->uid_validity;
+				/* pass status to main program */
+    mm_status (stream,mbx,&status);
+    ret = T;			/* succes */
+  }
+				/* flush temporary stream */
+  if (tstream) mail_close (tstream);
+				/* else reopen old newsgroup */
+  else if (old && nntp_send (LOCAL->nntpstream,"GROUP",old) != NNTPGOK) {
+    mm_log (LOCAL->nntpstream->reply,ERROR);
+    stream->halfopen = T;	/* go halfopen */
+  }
+  return ret;			/* success */
+}
+
+/* NNTP get map
+ * Accepts: stream
+ *	    newsgroup name
+ *	    first UID in map range
+ *	    last UID in map range
+ *	    reported total number of messages in newsgroup
+ *	    calculated number of messages in range
+ *	    temporary buffer
+ * Returns: T on success, NIL on failure
+ */
+
+long nntp_getmap (MAILSTREAM *stream,char *name,
+		  unsigned long first,unsigned long last,
+		  unsigned long rnmsgs,unsigned long nmsgs,char *tmp)
+{
+  short trylistgroup = NIL;
+  if (rnmsgs > (nmsgs * 8))	/* small subrange? */
+    trylistgroup = T;		/* yes, can try LISTGROUP if [X]HDR fails */
+  else switch ((int) nntp_send (LOCAL->nntpstream,"LISTGROUP",name)) {
+  case NNTPGOK:			/* got data */
+    return LONGT;
+  default:			/* else give up if server claims LISTGROUP */
+    if (EXTENSION.listgroup) return NIL;
+  }
+				/* build range */
+  sprintf (tmp,"%lu-%lu",first,last);
+  if (EXTENSION.hdr)		/* have HDR extension? */
+    return (nntp_send (LOCAL->nntpstream,"HDR Date",tmp) == NNTPHEAD) ?
+      LONGT : NIL;
+  if (LOCAL->xhdr)		/* try the experimental extension then */
+    switch ((int) nntp_send (LOCAL->nntpstream,"XHDR Date",tmp)) {
+    case NNTPHEAD:		/* got an overview? */
+      return LONGT;
+    case NNTPBADCMD:		/* unknown command? */
+      LOCAL->xhdr = NIL;	/* disable future XHDR attempts */
+    }
+  if (trylistgroup &&		/* no [X]HDR, maybe do LISTGROUP after all */
+      (nntp_send (LOCAL->nntpstream,"LISTGROUP",name) == NNTPGOK))
+    return LONGT;
+  return NIL;
+}
+
+/* NNTP open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *nntp_mopen (MAILSTREAM *stream)
+{
+  unsigned long i,j,k,nmsgs,rnmsgs;
+  char *s,*mbx,tmp[MAILTMPLEN];
+  FILE *f;
+  NETMBX mb;
+  char *newsrc = (char *) mail_parameters (NIL,GET_NEWSRC,NIL);
+  newsrcquery_t nq = (newsrcquery_t) mail_parameters (NIL,GET_NEWSRCQUERY,NIL);
+  SENDSTREAM *nstream = NIL;
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return &nntpproto;
+  mail_valid_net_parse (stream->mailbox,&mb);
+				/* note mailbox anme */
+  mbx = (*mb.mailbox == '#') ? mb.mailbox+6 : mb.mailbox;
+  if (LOCAL) {			/* recycle stream */
+    nstream = LOCAL->nntpstream;/* remember NNTP protocol stream */
+    sprintf (tmp,"Reusing connection to %s",net_host (nstream->netstream));
+    if (!stream->silent) mm_log (tmp,(long) NIL);
+    if (stream->rdonly) mb.readonlyflag = T;
+    if (LOCAL->tlsflag) mb.tlsflag = T;
+    if (LOCAL->tlssslv23) mb.tlssslv23 = T;
+    if (LOCAL->notlsflag) mb.notlsflag = T;
+    if (LOCAL->sslflag) mb.sslflag = T;
+    if (LOCAL->novalidate) mb.novalidate = T;
+    if (LOCAL->nntpstream->loser) mb.loser = T;
+    if (stream->secure) mb.secflag = T;
+    LOCAL->nntpstream = NIL;	/* keep nntp_mclose() from punting it */
+    nntp_mclose (stream,NIL);	/* do close action */
+    stream->dtb = &nntpdriver;	/* reattach this driver */
+  }
+				/* copy flags */
+  if (mb.dbgflag) stream->debug = T;
+  if (mb.readonlyflag) stream->rdonly = T;
+  if (mb.secflag) stream->secure = T;
+  mb.trysslflag = stream->tryssl = (mb.trysslflag || stream->tryssl) ? T : NIL;
+  if (!nstream) {		/* open NNTP now if not already open */
+    char *hostlist[2];
+    hostlist[0] = strcpy (tmp,mb.host);
+    if (mb.port || nntp_port)
+      sprintf (tmp + strlen (tmp),":%lu",mb.port ? mb.port : nntp_port);
+    if (mb.tlsflag) strcat (tmp,"/tls");
+    if (mb.tlssslv23) strcat (tmp,"/tls-sslv23");
+    if (mb.notlsflag) strcat (tmp,"/notls");
+    if (mb.sslflag) strcat (tmp,"/ssl");
+    if (mb.novalidate) strcat (tmp,"/novalidate-cert");
+    if (mb.loser) strcat (tmp,"/loser");
+    if (mb.secflag) strcat (tmp,"/secure");
+    if (mb.user[0]) sprintf (tmp + strlen (tmp),"/user=\"%s\"",mb.user);
+    hostlist[1] = NIL;
+    if (!(nstream = nntp_open (hostlist,NOP_READONLY |
+			       (stream->debug ? NOP_DEBUG : NIL)))) return NIL;
+  }
+
+				/* always zero messages if halfopen */
+  if (stream->halfopen) i = j = k = rnmsgs = nmsgs = 0;
+				/* otherwise open the newsgroup */
+  else if (nntp_send (nstream,"GROUP",mbx) == NNTPGOK) {
+    k = strtoul (nstream->reply + 4,&s,10);
+    i = strtoul (s,&s,10);
+    stream->uid_last = j = strtoul (s,&s,10);
+    rnmsgs = nmsgs = (i | j) ? 1 + j - i : 0;
+    if (k > nmsgs) {		/* check for absurdity */
+      sprintf (tmp,"NNTP SERVER BUG (impossible message count): %lu > %lu",
+	       k,nmsgs);
+      mm_log (tmp,WARN);
+    }
+				/* restrict article range if needed */
+    if (nntp_range && (nmsgs > nntp_range)) i = 1 + j - (nmsgs = nntp_range);
+  }
+  else {			/* no such newsgroup */
+    mm_log (nstream->reply,ERROR);
+    nntp_close (nstream);	/* punt stream */
+    return NIL;
+  }
+				/* instantiate local data */
+  stream->local = memset (fs_get (sizeof (NNTPLOCAL)),0,sizeof (NNTPLOCAL));
+  LOCAL->nntpstream = nstream;
+				/* save state for future recycling */
+  if (mb.tlsflag) LOCAL->tlsflag = T;
+  if (mb.tlssslv23) LOCAL->tlssslv23 = T;
+  if (mb.notlsflag) LOCAL->notlsflag = T;
+  if (mb.sslflag) LOCAL->sslflag = T;
+  if (mb.novalidate) LOCAL->novalidate = T;
+  if (mb.loser) LOCAL->nntpstream->loser = T;
+				/* assume present until proven otherwise */
+  LOCAL->xhdr = LOCAL->xover = T;
+  LOCAL->name = cpystr (mbx);	/* copy newsgroup name */
+  if (stream->mulnewsrc) {	/* want to use multiple .newsrc files? */
+    strcpy (tmp,newsrc);
+    s = tmp + strlen (tmp);	/* end of string */
+    *s++ = '-';			/* hyphen delimiter and host */
+    lcase (strcpy (s,(long) mail_parameters (NIL,GET_NEWSRCCANONHOST,NIL) ?
+		   net_host (nstream->netstream) : mb.host));
+    LOCAL->newsrc = cpystr (nq ? (*nq) (stream,tmp,newsrc) : tmp);
+  }
+  else LOCAL->newsrc = cpystr (newsrc);
+  if (mb.user[0]) LOCAL->user = cpystr (mb.user);
+  stream->sequence++;		/* bump sequence number */
+  stream->rdonly = stream->perm_deleted = T;
+				/* UIDs are always valid */
+  stream->uid_validity = 0xbeefface;
+  sprintf (tmp,"{%s:%lu/nntp",(long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ?
+	   net_host (nstream->netstream) : mb.host,
+	   net_port (nstream->netstream));
+  if (LOCAL->tlsflag) strcat (tmp,"/tls");
+  if (LOCAL->tlssslv23) strcat (tmp,"/tls-sslv23");
+  if (LOCAL->notlsflag) strcat (tmp,"/notls");
+  if (LOCAL->sslflag) strcat (tmp,"/ssl");
+  if (LOCAL->novalidate) strcat (tmp,"/novalidate-cert");
+  if (LOCAL->nntpstream->loser) strcat (tmp,"/loser");
+  if (stream->secure) strcat (tmp,"/secure");
+  if (stream->rdonly) strcat (tmp,"/readonly");
+  if (LOCAL->user) sprintf (tmp + strlen (tmp),"/user=\"%s\"",LOCAL->user);
+  if (stream->halfopen) strcat (tmp,"}<no_mailbox>");
+  else sprintf (tmp + strlen (tmp),"}#news.%s",mbx);
+  fs_give ((void **) &stream->mailbox);
+  stream->mailbox = cpystr (tmp);
+
+  if (EXTENSION.over &&		/* get overview format if have OVER */
+      (nntp_send (LOCAL->nntpstream,"LIST","OVERVIEW.FMT") == NNTPGLIST) &&
+      (f = netmsg_slurp (LOCAL->nntpstream->netstream,&k,NIL))) {
+    fread (LOCAL->over_fmt = (char *) fs_get ((size_t) k + 3),
+	   (size_t) 1,(size_t) k,f);
+    LOCAL->over_fmt[k] = '\0';
+    fclose (f);			/* flush temp file */
+  }
+  if (nmsgs) {			/* if any messages exist */
+    short silent = stream->silent;
+    stream->silent = T;		/* don't notify main program yet */
+    mail_exists (stream,nmsgs);	/* silently set the cache to the guesstimate */
+				/* get UID/sequence map, nuke holes */
+    if (nntp_getmap (stream,mbx,i,j,rnmsgs,nmsgs,tmp)) {
+      for (nmsgs = 0;		/* calculate true count */
+	   (s = net_getline (nstream->netstream)) && strcmp (s,"."); ) {
+	if ((k = atol (s)) > j){/* discard too high article numbers */
+	  sprintf (tmp,"NNTP SERVER BUG (out of range article ID): %lu > %lu",
+		   k,j);
+	  mm_notify (stream,tmp,NIL);
+	  stream->unhealthy = T;
+	}
+	else if (k >= i) {	/* silently ignore too-low article numbers */
+				/* guard against server returning extra msgs */
+	  if (nmsgs == stream->nmsgs) mail_exists (stream,nmsgs+1);
+				/* create elt for this message, set UID */
+	  mail_elt (stream,++nmsgs)->private.uid = k;
+	}
+	fs_give ((void **) &s);
+      }
+      if (s) fs_give ((void **) &s);
+    }
+				/* assume c-client/NNTP map is entire range */
+    else for (k = 1; k <= nmsgs; k++) mail_elt (stream,k)->private.uid = i++;
+    stream->unhealthy = NIL;	/* set healthy */
+    stream->nmsgs = 0;		/* whack it back down */
+    stream->silent = silent;	/* restore old silent setting */
+    mail_exists (stream,nmsgs);	/* notify upper level that messages exist */
+				/* read .newsrc entries */
+    mail_recent (stream,newsrc_read (mbx,stream));
+  }
+  else {			/* empty newsgroup or halfopen */
+    if (!(stream->silent || stream->halfopen)) {
+      sprintf (tmp,"Newsgroup %s is empty",mbx);
+      mm_log (tmp,WARN);
+    }
+    mail_exists (stream,(long) 0);
+    mail_recent (stream,(long) 0);
+  }
+  return stream;		/* return stream to caller */
+}
+
+/* NNTP close
+ * Accepts: MAIL stream
+ *	    option flags
+ */
+
+void nntp_mclose (MAILSTREAM *stream,long options)
+{
+  unsigned long i;
+  MESSAGECACHE *elt;
+  if (LOCAL) {			/* only if a file is open */
+    nntp_check (stream);	/* dump final checkpoint */
+    if (LOCAL->over_fmt) fs_give ((void **) &LOCAL->over_fmt);
+    if (LOCAL->name) fs_give ((void **) &LOCAL->name);
+    if (LOCAL->user) fs_give ((void **) &LOCAL->user);
+    if (LOCAL->newsrc) fs_give ((void **) &LOCAL->newsrc);
+    if (LOCAL->txt) fclose (LOCAL->txt);
+				/* close NNTP connection */
+    if (LOCAL->nntpstream) nntp_close (LOCAL->nntpstream);
+    for (i = 1; i <= stream->nmsgs; i++)
+      if ((elt = mail_elt (stream,i))->private.spare.ptr)
+	fs_give ((void **) &elt->private.spare.ptr);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+/* NNTP fetch fast information
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ * This is ugly and slow
+ */
+
+void nntp_fetchfast (MAILSTREAM *stream,char *sequence,long flags)
+{
+  unsigned long i;
+  MESSAGECACHE *elt;
+				/* get sequence */
+  if (stream && LOCAL && ((flags & FT_UID) ?
+			  mail_uid_sequence (stream,sequence) :
+			  mail_sequence (stream,sequence)))
+    for (i = 1; i <= stream->nmsgs; i++) {
+      if ((elt = mail_elt (stream,i))->sequence && (elt->valid = T) &&
+	  !(elt->day && elt->rfc822_size)) {
+	ENVELOPE **env = NIL;
+	ENVELOPE *e = NIL;
+	if (!stream->scache) env = &elt->private.msg.env;
+	else if (stream->msgno == i) env = &stream->env;
+	else env = &e;
+	if (!*env || !elt->rfc822_size) {
+	  STRING bs;
+	  unsigned long hs;
+	  char *ht = (*stream->dtb->header) (stream,i,&hs,NIL);
+				/* need to make an envelope? */
+	  if (!*env) rfc822_parse_msg (env,NIL,ht,hs,NIL,BADHOST,
+				       stream->dtb->flags);
+				/* need message size too, ugh */
+	  if (!elt->rfc822_size) {
+	    (*stream->dtb->text) (stream,i,&bs,FT_PEEK);
+	    elt->rfc822_size = hs + SIZE (&bs) - GETPOS (&bs);
+	  }
+	}
+				/* if need date, have date in envelope? */
+	if (!elt->day && *env && (*env)->date)
+	  mail_parse_date (elt,(*env)->date);
+				/* sigh, fill in bogus default */
+	if (!elt->day) elt->day = elt->month = 1;
+	mail_free_envelope (&e);
+      }
+    }
+}
+
+/* NNTP fetch flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ */
+
+void nntp_flags (MAILSTREAM *stream,char *sequence,long flags)
+{
+  unsigned long i;
+  if ((flags & FT_UID) ?	/* validate all elts */
+      mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))
+    for (i = 1; i <= stream->nmsgs; i++) mail_elt (stream,i)->valid = T;
+}
+
+/* NNTP fetch overview
+ * Accepts: MAIL stream, sequence bits set
+ *	    overview return function
+ * Returns: T if successful, NIL otherwise
+ */
+
+long nntp_overview (MAILSTREAM *stream,overview_t ofn)
+{
+  unsigned long i,j,k,uid;
+  char c,*s,*t,*v,tmp[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  OVERVIEW ov;
+  if (!LOCAL->nntpstream->netstream) return NIL;
+				/* scan sequence to load cache */
+  for (i = 1; i <= stream->nmsgs; i++)
+				/* have cached overview yet? */
+    if ((elt = mail_elt (stream,i))->sequence && !elt->private.spare.ptr) {
+      for (j = i + 1;		/* no, find end of cache gap range */
+	   (j <= stream->nmsgs) && (elt = mail_elt (stream,j))->sequence &&
+	   !elt->private.spare.ptr; j++);
+				/* make NNTP range */
+      sprintf (tmp,(i == (j - 1)) ? "%lu" : "%lu-%lu",mail_uid (stream,i),
+	       mail_uid (stream,j - 1));
+      i = j;			/* advance beyond gap */
+				/* ask server for overview data to cache */
+      if (nntp_over (stream,tmp)) {
+	while ((s = net_getline (LOCAL->nntpstream->netstream)) &&
+	       strcmp (s,".")) {
+				/* death to embedded newlines */
+	  for (t = v = s; c = *v++;)
+	    if ((c != '\012') && (c != '\015')) *t++ = c;
+	  *t++ = '\0';		/* tie off string in case it was shortened */
+				/* cache the overview if found its sequence */
+	  if ((uid = atol (s)) && (k = mail_msgno (stream,uid)) &&
+	      (t = strchr (s,'\t'))) {
+	    if ((elt = mail_elt (stream,k))->private.spare.ptr)
+	      fs_give ((void **) &elt->private.spare.ptr);
+	    elt->private.spare.ptr = cpystr (t + 1);
+	  }
+	  else {		/* shouldn't happen, snarl if it does */
+	    sprintf (tmp,"Server returned data for unknown UID %lu",uid);
+	    mm_notify (stream,tmp,WARN);
+	    stream->unhealthy = T;
+	  }
+				/* flush the overview */
+	  fs_give ((void **) &s);
+	}
+	stream->unhealthy = NIL;/* set healthy */
+				/* flush the terminating dot */
+	if (s) fs_give ((void **) &s);
+      }
+      else i = stream->nmsgs;	/* OVER failed, punt cache load */
+    }
+
+				/* now scan sequence to return overviews */
+  if (ofn) for (i = 1; i <= stream->nmsgs; i++)
+    if ((elt = mail_elt (stream,i))->sequence) {
+      uid = mail_uid (stream,i);/* UID for this message */
+				/* parse cached overview */
+      if (nntp_parse_overview (&ov,s = (char *) elt->private.spare.ptr,elt))
+	(*ofn) (stream,uid,&ov,i);
+      else {			/* parse failed */
+	(*ofn) (stream,uid,NIL,i);
+	if (s && *s) {		/* unusable cached entry? */
+	  sprintf (tmp,"Unable to parse overview for UID %lu: %.500s",uid,s);
+	  mm_notify (stream,tmp,WARN);
+	  stream->unhealthy = T;
+				/* erase it from the cache */
+	  fs_give ((void **) &s);
+	}
+	stream->unhealthy = NIL;/* set healthy */
+				/* insert empty cached text as necessary */
+	if (!s) elt->private.spare.ptr = cpystr ("");
+      }
+				/* clean up overview data */
+      if (ov.from) mail_free_address (&ov.from);
+      if (ov.subject) fs_give ((void **) &ov.subject);
+    }
+  return T;
+}
+
+/* Send OVER to NNTP server
+ * Accepts: mail stream
+ *	    sequence to send
+ * Returns: T if success and overviews will follow, else NIL
+ */
+
+long nntp_over (MAILSTREAM *stream,char *sequence)
+{
+  unsigned char *s;
+				/* test for Netscape Collabra server */
+  if (EXTENSION.over && LOCAL->xover &&
+      nntp_send (LOCAL->nntpstream,"OVER","0") == NNTPOVER) {
+    /* "Netscape-Collabra/3.52 03615 NNTP" responds to the OVER command with
+     * a bogus "Subject:From:Date:Bytes:Lines" response followed by overviews
+     * which lack the Message-ID and References:.  This violates the draft
+     * NNTP specification (draft-ietf-nntpext-base-18.txt as of this writing).
+     * XOVER works fine.
+     */
+    while ((s = net_getline (LOCAL->nntpstream->netstream)) && strcmp (s,".")){
+      if (!isdigit (*s)) {	/* is it that fetid piece of reptile dung? */
+	EXTENSION.over = NIL;	/* sure smells like it */
+	mm_log ("Working around Netscape Collabra bug",WARN);
+      }
+      fs_give ((void **) &s);	/* flush the overview */
+    }
+    if (s) fs_give ((void **) &s);
+				/* don't do this test again */
+    if (EXTENSION.over) LOCAL->xover = NIL;
+  }
+  if (EXTENSION.over)		/* have OVER extension? */
+    return (nntp_send (LOCAL->nntpstream,"OVER",sequence) == NNTPOVER) ?
+      LONGT : NIL;
+  if (LOCAL->xover)		/* try the experiment extension then */
+    switch ((int) nntp_send (LOCAL->nntpstream,"XOVER",sequence)) {
+    case NNTPOVER:		/* got an overview? */
+      return LONGT;
+    case NNTPBADCMD:		/* unknown command? */
+      LOCAL->xover = NIL;	/* disable future XOVER attempts */
+    }
+  return NIL;
+}
+
+/* Parse OVERVIEW struct from cached NNTP OVER response
+ * Accepts: struct to load
+ *	    cached OVER response
+ *	    internaldate
+ * Returns: T if success, NIL if fail
+ */
+
+long nntp_parse_overview (OVERVIEW *ov,char *text,MESSAGECACHE *elt)
+{
+  char *t;
+				/* nothing in overview yet */
+  memset ((void *) ov,0,sizeof (OVERVIEW));
+				/* no cached data */
+  if (!(text && *text)) return NIL;
+  ov->subject = cpystr (text);	/* make hackable copy of overview */
+				/* find end of Subject */
+  if (t = strchr (ov->subject,'\t')) {
+    *t++ = '\0';		/* tie off Subject, point to From */
+				/* find end of From */
+    if (ov->date = strchr (t,'\t')) {
+      *ov->date++ = '\0';	/* tie off From, point to Date */
+				/* load internaldate too */
+      if (!elt->day) mail_parse_date (elt,ov->date);
+				/* parse From */
+      rfc822_parse_adrlist (&ov->from,t,BADHOST);
+				/* find end of Date */
+      if (ov->message_id = strchr (ov->date,'\t')) {
+				/* tie off Date, point to Message-ID */
+	*ov->message_id++ = '\0';
+				/* find end of Message-ID */
+	if (ov->references = strchr (ov->message_id,'\t')) {
+				/* tie off Message-ID, point to References */
+	  *ov->references++ = '\0';
+				/* fine end of References */
+	  if (t = strchr (ov->references,'\t')) {
+	    *t++ = '\0';	/* tie off References, point to octet size */
+				/* parse size of message in octets */
+	    ov->optional.octets = atol (t);
+				/* find end of size */
+	    if (t = strchr (t,'\t')) {
+				/* parse size of message in lines */
+	      ov->optional.lines = atol (++t);
+				/* find Xref */
+	      if (ov->optional.xref = strchr (t,'\t'))
+		*ov->optional.xref++ = '\0';
+	    }
+	  }
+	}
+      }
+    }
+  }
+  return ov->references ? T : NIL;
+}
+
+/* NNTP fetch header as text
+ * Accepts: mail stream
+ *	    message number
+ *	    pointer to return size
+ *	    flags
+ * Returns: header text
+ */
+
+char *nntp_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *size,
+		   long flags)
+{
+  char tmp[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  FILE *f;
+  *size = 0;
+  if ((flags & FT_UID) && !(msgno = mail_msgno (stream,msgno))) return "";
+				/* have header text? */
+  if (!(elt = mail_elt (stream,msgno))->private.msg.header.text.data) {
+    sprintf (tmp,"%lu",mail_uid (stream,msgno));
+				/* get header text */
+    switch (nntp_send (LOCAL->nntpstream,"HEAD",tmp)) {
+    case NNTPHEAD:
+      if (f = netmsg_slurp (LOCAL->nntpstream->netstream,size,NIL)) {
+	fread (elt->private.msg.header.text.data =
+	       (unsigned char *) fs_get ((size_t) *size + 3),
+	       (size_t) 1,(size_t) *size,f);
+	fclose (f);		/* flush temp file */
+				/* tie off header with extra CRLF and NUL */
+	elt->private.msg.header.text.data[*size] = '\015';
+	elt->private.msg.header.text.data[++*size] = '\012';
+	elt->private.msg.header.text.data[++*size] = '\0';
+	elt->private.msg.header.text.size = *size;
+	elt->valid = T;		/* make elt valid now */
+	break;
+      }
+				/* fall into default case */
+    default:			/* failed, mark as deleted and empty */
+      elt->valid = elt->deleted = T;
+    case NNTPSOFTFATAL:		/* don't mark deleted if stream dead */
+      *size = elt->private.msg.header.text.size = 0;
+      break;
+    }
+  }
+				/* just return size of text */
+  else *size = elt->private.msg.header.text.size;
+  return elt->private.msg.header.text.data ?
+    (char *) elt->private.msg.header.text.data : "";
+}
+
+/* NNTP fetch body
+ * Accepts: mail stream
+ *	    message number
+ *	    pointer to stringstruct to initialize
+ *	    flags
+ * Returns: T if successful, else NIL
+ */
+
+long nntp_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  char tmp[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  INIT (bs,mail_string,(void *) "",0);
+  if ((flags & FT_UID) && !(msgno = mail_msgno (stream,msgno))) return NIL;
+  elt = mail_elt (stream,msgno);
+				/* different message, flush cache */
+  if (LOCAL->txt && (LOCAL->msgno != msgno)) {
+    fclose (LOCAL->txt);
+    LOCAL->txt = NIL;
+  }
+  LOCAL->msgno = msgno;		/* note cached message */
+  if (!LOCAL->txt) {		/* have file for this message? */
+    sprintf (tmp,"%lu",elt->private.uid);
+    switch (nntp_send (LOCAL->nntpstream,"BODY",tmp)) {
+    case NNTPBODY:
+      if (LOCAL->txt = netmsg_slurp (LOCAL->nntpstream->netstream,
+				     &LOCAL->txtsize,NIL)) break;
+				/* fall into default case */
+    default:			/* failed, mark as deleted */
+      elt->deleted = T;
+    case NNTPSOFTFATAL:		/* don't mark deleted if stream dead */
+      return NIL;
+    }
+  }
+  if (!(flags & FT_PEEK)) {	/* mark seen if needed */
+    elt->seen = T;
+    mm_flags (stream,elt->msgno);
+  }
+  INIT (bs,file_string,(void *) LOCAL->txt,LOCAL->txtsize);
+  return T;
+}
+
+/* NNTP fetch article from message ID (for news: URL support)
+ * Accepts: mail stream
+ *	    message ID
+ *	    pointer to return total message size
+ *	    pointer to return file size
+ * Returns: FILE * to message if successful, else NIL
+ */
+
+FILE *nntp_article (MAILSTREAM *stream,char *msgid,unsigned long *size,
+		    unsigned long *hsiz)
+{
+  return (nntp_send (LOCAL->nntpstream,"ARTICLE",msgid) == NNTPARTICLE) ?
+    netmsg_slurp (LOCAL->nntpstream->netstream,size,hsiz) : NIL;
+}
+
+
+/* NNTP per-message modify flag
+ * Accepts: MAIL stream
+ *	    message cache element
+ */
+
+void nntp_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  if (!LOCAL->dirty) {		/* only bother checking if not dirty yet */
+    if (elt->valid) {		/* if done, see if deleted changed */
+      if (elt->sequence != elt->deleted) LOCAL->dirty = T;
+      elt->sequence = T;	/* leave the sequence set */
+    }
+				/* note current setting of deleted flag */
+    else elt->sequence = elt->deleted;
+  }
+}
+
+/* NNTP search messages
+ * Accepts: mail stream
+ *	    character set
+ *	    search program
+ *	    option flags
+ * Returns: T on success, NIL on failure
+ */
+
+long nntp_search (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm,long flags)
+{
+  unsigned long i;
+  MESSAGECACHE *elt;
+  OVERVIEW ov;
+  char *msg;
+				/* make sure that charset is good */
+  if (msg = utf8_badcharset (charset)) {
+    MM_LOG (msg,ERROR);		/* output error */
+    fs_give ((void **) &msg);
+    return NIL;
+  }
+  utf8_searchpgm (pgm,charset);
+  if (flags & SO_OVERVIEW) {	/* only if specified to use overview */
+				/* identify messages that will be searched */
+    for (i = 1; i <= stream->nmsgs; ++i)
+      mail_elt (stream,i)->sequence = nntp_search_msg (stream,i,pgm,NIL);
+    nntp_overview (stream,NIL);	/* load the overview cache */
+  }
+				/* init in case no overview at cleanup */
+  memset ((void *) &ov,0,sizeof (OVERVIEW));
+				/* otherwise do default search */
+  for (i = 1; i <= stream->nmsgs; ++i) {
+    if (((flags & SO_OVERVIEW) && ((elt = mail_elt (stream,i))->sequence) &&
+	 nntp_parse_overview (&ov,(char *) elt->private.spare.ptr,elt)) ?
+	nntp_search_msg (stream,i,pgm,&ov) :
+	mail_search_msg (stream,i,NIL,pgm)) {
+      if (flags & SE_UID) mm_searched (stream,mail_uid (stream,i));
+      else {			/* mark as searched, notify mail program */
+	mail_elt (stream,i)->searched = T;
+	if (!stream->silent) mm_searched (stream,i);
+      }
+    }
+				/* clean up overview data */
+    if (ov.from) mail_free_address (&ov.from);
+    if (ov.subject) fs_give ((void **) &ov.subject);
+  }
+  return LONGT;
+}
+
+/* NNTP search message
+ * Accepts: MAIL stream
+ *	    message number
+ *	    search program
+ *	    overview to search (NIL means preliminary pass)
+ * Returns: T if found, NIL otherwise
+ */
+
+long nntp_search_msg (MAILSTREAM *stream,unsigned long msgno,SEARCHPGM *pgm,
+		      OVERVIEW *ov)
+{
+  unsigned short d;
+  unsigned long now = (unsigned long) time (0);
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  SEARCHHEADER *hdr;
+  SEARCHOR *or;
+  SEARCHPGMLIST *not;
+  if (pgm->msgno || pgm->uid) {	/* message set searches */
+    SEARCHSET *set;
+				/* message sequences */
+    if (set = pgm->msgno) {	/* must be inside this sequence */
+      while (set) {		/* run down until find matching range */
+	if (set->last ? ((msgno < set->first) || (msgno > set->last)) :
+	    msgno != set->first) set = set->next;
+	else break;
+      }
+      if (!set) return NIL;	/* not found within sequence */
+    }
+    if (set = pgm->uid) {	/* must be inside this sequence */
+      unsigned long uid = mail_uid (stream,msgno);
+      while (set) {		/* run down until find matching range */
+	if (set->last ? ((uid < set->first) || (uid > set->last)) :
+	    uid != set->first) set = set->next;
+	else break;
+      }
+      if (!set) return NIL;	/* not found within sequence */
+    }
+  }
+
+  /* Fast data searches */
+				/* message flags */
+  if ((pgm->answered && !elt->answered) ||
+      (pgm->unanswered && elt->answered) ||
+      (pgm->deleted && !elt->deleted) ||
+      (pgm->undeleted && elt->deleted) ||
+      (pgm->draft && !elt->draft) ||
+      (pgm->undraft && elt->draft) ||
+      (pgm->flagged && !elt->flagged) ||
+      (pgm->unflagged && elt->flagged) ||
+      (pgm->recent && !elt->recent) ||
+      (pgm->old && elt->recent) ||
+      (pgm->seen && !elt->seen) ||
+      (pgm->unseen && elt->seen)) return NIL;
+				/* keywords */
+  if ((pgm->keyword && !mail_search_keyword (stream,elt,pgm->keyword,LONGT)) ||
+      (pgm->unkeyword && mail_search_keyword (stream,elt,pgm->unkeyword,NIL)))
+    return NIL;
+  if (ov) {			/* only do this if real searching */
+    MESSAGECACHE delt;
+				/* size ranges */
+    if ((pgm->larger && (ov->optional.octets <= pgm->larger)) ||
+	(pgm->smaller && (ov->optional.octets >= pgm->smaller))) return NIL;
+				/* date ranges */
+    if ((pgm->sentbefore || pgm->senton || pgm->sentsince ||
+	 pgm->before || pgm->on || pgm->since) &&
+	(!mail_parse_date (&delt,ov->date) ||
+	 !(d = mail_shortdate (delt.year,delt.month,delt.day)) ||
+	 (pgm->sentbefore && (d >= pgm->sentbefore)) ||
+	 (pgm->senton && (d != pgm->senton)) ||
+	 (pgm->sentsince && (d < pgm->sentsince)) ||
+	 (pgm->before && (d >= pgm->before)) ||
+	 (pgm->on && (d != pgm->on)) ||
+	 (pgm->since && (d < pgm->since)))) return NIL;
+    if (pgm->older || pgm->younger) {
+      unsigned long msgd = mail_longdate (elt);
+      if (pgm->older && msgd > (now - pgm->older)) return NIL;
+      if (pgm->younger && msgd < (now - pgm->younger)) return NIL;
+    }
+    if ((pgm->from && !mail_search_addr (ov->from,pgm->from)) ||
+	(pgm->subject && !mail_search_header_text (ov->subject,pgm->subject))||
+	(pgm->message_id &&
+	 !mail_search_header_text (ov->message_id,pgm->message_id)) ||
+	(pgm->references &&
+	 !mail_search_header_text (ov->references,pgm->references)))
+      return NIL;
+
+
+				/* envelope searches */
+    if (pgm->bcc || pgm->cc || pgm->to || pgm->return_path || pgm->sender ||
+	pgm->reply_to || pgm->in_reply_to || pgm->newsgroups ||
+	pgm->followup_to) {
+      ENVELOPE *env = mail_fetchenvelope (stream,msgno);
+      if (!env) return NIL;	/* no envelope obtained */
+				/* search headers */
+      if ((pgm->bcc && !mail_search_addr (env->bcc,pgm->bcc)) ||
+	  (pgm->cc && !mail_search_addr (env->cc,pgm->cc)) ||
+	  (pgm->to && !mail_search_addr (env->to,pgm->to)))
+	return NIL;
+      /* These criteria are not supported by IMAP and have to be emulated */
+      if ((pgm->return_path &&
+	   !mail_search_addr (env->return_path,pgm->return_path)) ||
+	  (pgm->sender && !mail_search_addr (env->sender,pgm->sender)) ||
+	  (pgm->reply_to && !mail_search_addr (env->reply_to,pgm->reply_to)) ||
+	  (pgm->in_reply_to &&
+	   !mail_search_header_text (env->in_reply_to,pgm->in_reply_to)) ||
+	  (pgm->newsgroups &&
+	   !mail_search_header_text (env->newsgroups,pgm->newsgroups)) ||
+	  (pgm->followup_to &&
+	   !mail_search_header_text (env->followup_to,pgm->followup_to)))
+	return NIL;
+    }
+
+				/* search header lines */
+    for (hdr = pgm->header; hdr; hdr = hdr->next) {
+      char *t,*e,*v;
+      SIZEDTEXT s;
+      STRINGLIST sth,stc;
+      sth.next = stc.next = NIL;/* only one at a time */
+      sth.text.data = hdr->line.data;
+      sth.text.size = hdr->line.size;
+				/* get the header text */
+      if ((t = mail_fetch_header (stream,msgno,NIL,&sth,&s.size,
+				  FT_INTERNAL | FT_PEEK)) && strchr (t,':')) {
+	if (hdr->text.size) {	/* anything matches empty search string */
+				/* non-empty, copy field data */
+	  s.data = (unsigned char *) fs_get (s.size + 1);
+				/* for each line */
+	  for (v = (char *) s.data, e = t + s.size; t < e;) switch (*t) {
+	  default:		/* non-continuation, skip leading field name */
+	    while ((t < e) && (*t++ != ':'));
+	    if ((t < e) && (*t == ':')) t++;
+	  case '\t': case ' ':	/* copy field data  */
+	    while ((t < e) && (*t != '\015') && (*t != '\012')) *v++ = *t++;
+	    *v++ = '\n';	/* tie off line */
+	    while (((*t == '\015') || (*t == '\012')) && (t < e)) t++;
+	  }
+				/* calculate true size */
+	  s.size = v - (char *) s.data;
+	  *v = '\0';		/* tie off results */
+	  stc.text.data = hdr->text.data;
+	  stc.text.size = hdr->text.size;
+				/* search header */
+	  if (mail_search_header (&s,&stc)) fs_give ((void **) &s.data);
+	  else {		/* search failed */
+	    fs_give ((void **) &s.data);
+	    return NIL;
+	  }
+	}
+      }
+      else return NIL;		/* no matching header text */
+    }
+				/* search strings */
+    if ((pgm->text &&
+	 !mail_search_text (stream,msgno,NIL,pgm->text,LONGT))||
+	(pgm->body && !mail_search_text (stream,msgno,NIL,pgm->body,NIL)))
+      return NIL;
+  }
+				/* logical conditions */
+  for (or = pgm->or; or; or = or->next)
+    if (!(nntp_search_msg (stream,msgno,or->first,ov) ||
+	  nntp_search_msg (stream,msgno,or->second,ov))) return NIL;
+  for (not = pgm->not; not; not = not->next)
+    if (nntp_search_msg (stream,msgno,not->pgm,ov)) return NIL;
+  return T;
+}
+
+/* NNTP sort messages
+ * Accepts: mail stream
+ *	    character set
+ *	    search program
+ *	    sort program
+ *	    option flags
+ * Returns: vector of sorted message sequences or NIL if error
+ */
+
+unsigned long *nntp_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
+			  SORTPGM *pgm,long flags)
+{
+  unsigned long i,start,last;
+  SORTCACHE **sc;
+  mailcache_t mailcache = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL);
+  unsigned long *ret = NIL;
+  sortresults_t sr = (sortresults_t) mail_parameters (NIL,GET_SORTRESULTS,NIL);
+  if (spg) {			/* only if a search needs to be done */
+    int silent = stream->silent;
+    stream->silent = T;		/* don't pass up mm_searched() events */
+				/* search for messages */
+    mail_search_full (stream,charset,spg,NIL);
+    stream->silent = silent;	/* restore silence state */
+  }
+				/* initialize progress counters */
+  pgm->nmsgs = pgm->progress.cached = 0;
+				/* pass 1: count messages to sort */
+  for (i = 1,start = last = 0; i <= stream->nmsgs; ++i)
+    if (mail_elt (stream,i)->searched) {
+      pgm->nmsgs++;
+				/* have this in the sortcache already? */
+      if (!((SORTCACHE *) (*mailcache) (stream,i,CH_SORTCACHE))->date) {
+				/* no, record as last message */
+	last = mail_uid (stream,i);
+				/* and as first too if needed */
+	if (!start) start = last;
+      }
+    }
+  if (pgm->nmsgs) {		/* pass 2: load sort cache */
+    sc = nntp_sort_loadcache (stream,pgm,start,last,flags);
+				/* pass 3: sort messages */
+    if (!pgm->abort) ret = mail_sort_cache (stream,pgm,sc,flags);
+    fs_give ((void **) &sc);	/* don't need sort vector any more */
+  }
+				/* empty sort results */
+  else ret = (unsigned long *) memset (fs_get (sizeof (unsigned long)),0,
+				       sizeof (unsigned long));
+				/* also return via callback if requested */
+  if (sr) (*sr) (stream,ret,pgm->nmsgs);
+  return ret;
+}
+
+/* Mail load sortcache
+ * Accepts: mail stream, already searched
+ *	    sort program
+ *	    first UID to OVER
+ *	    last UID to OVER
+ *	    option flags
+ * Returns: vector of sortcache pointers matching search
+ */
+
+SORTCACHE **nntp_sort_loadcache (MAILSTREAM *stream,SORTPGM *pgm,
+				 unsigned long start,unsigned long last,
+				 long flags)
+{
+  unsigned long i;
+  char c,*s,*t,*v,tmp[MAILTMPLEN];
+  SORTPGM *pg;
+  SORTCACHE **sc,*r;
+  MESSAGECACHE telt;
+  ADDRESS *adr = NIL;
+  mailcache_t mailcache = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL);
+				/* verify that the sortpgm is OK */
+  for (pg = pgm; pg; pg = pg->next) switch (pg->function) {
+  case SORTARRIVAL:		/* sort by arrival date */
+  case SORTSIZE:		/* sort by message size */
+  case SORTDATE:		/* sort by date */
+  case SORTFROM:		/* sort by first from */
+  case SORTSUBJECT:		/* sort by subject */
+    break;
+  case SORTTO:			/* sort by first to */
+    mm_notify (stream,"[NNTPSORT] Can't do To-field sorting in NNTP",WARN);
+    break;
+  case SORTCC:			/* sort by first cc */
+    mm_notify (stream,"[NNTPSORT] Can't do cc-field sorting in NNTP",WARN);
+    break;
+  default:
+    fatal ("Unknown sort function");
+  }
+
+  if (start) {			/* messages need to be loaded in sortcache? */
+				/* yes, build range */
+    if (start != last) sprintf (tmp,"%lu-%lu",start,last);
+    else sprintf (tmp,"%lu",start);
+				/* get it from the NNTP server */
+    if (!nntp_over (stream,tmp)) return mail_sort_loadcache (stream,pgm);
+    while ((s = net_getline (LOCAL->nntpstream->netstream)) && strcmp (s,".")){
+				/* death to embedded newlines */
+      for (t = v = s; c = *v++;) if ((c != '\012') && (c != '\015')) *t++ = c;
+      *t++ = '\0';		/* tie off resulting string */
+				/* parse OVER response */
+      if ((i = mail_msgno (stream,atol (s))) &&
+	  (t = strchr (s,'\t')) && (v = strchr (++t,'\t'))) {
+	*v++ = '\0';		/* tie off subject */
+				/* put stripped subject in sortcache */
+	r = (SORTCACHE *) (*mailcache) (stream,i,CH_SORTCACHE);
+	  r->refwd = mail_strip_subject (t,&r->subject);
+	if (t = strchr (v,'\t')) {
+	  *t++ = '\0';		/* tie off from */
+	  if (adr = rfc822_parse_address (&adr,adr,&v,BADHOST,0)) {
+	    r->from = adr->mailbox;
+	    adr->mailbox = NIL;
+	    mail_free_address (&adr);
+	  }
+	  if (v = strchr (t,'\t')) {
+	    *v++ = '\0';	/* tie off date */
+	    if (mail_parse_date (&telt,t)) r->date = mail_longdate (&telt);
+	    if ((v = strchr (v,'\t')) && (v = strchr (++v,'\t')))
+	      r->size = atol (++v);
+	  }
+	}
+      }
+      fs_give ((void **) &s);
+    }
+    if (s) fs_give ((void **) &s);
+  }
+
+				/* calculate size of sortcache index */
+  i = pgm->nmsgs * sizeof (SORTCACHE *);
+				/* instantiate the index */
+  sc = (SORTCACHE **) memset (fs_get ((size_t) i),0,(size_t) i);
+				/* see what needs to be loaded */
+  for (i = 1; !pgm->abort && (i <= stream->nmsgs); i++)
+    if ((mail_elt (stream,i))->searched) {
+      sc[pgm->progress.cached++] =
+	r = (SORTCACHE *) (*mailcache) (stream,i,CH_SORTCACHE);
+      r->pgm = pgm;	/* note sort program */
+      r->num = (flags & SE_UID) ? mail_uid (stream,i) : i;
+      if (!r->date) r->date = r->num;
+      if (!r->arrival) r->arrival = mail_uid (stream,i);
+      if (!r->size) r->size = 1;
+      if (!r->from) r->from = cpystr ("");
+      if (!r->to) r->to = cpystr ("");
+      if (!r->cc) r->cc = cpystr ("");
+      if (!r->subject) r->subject = cpystr ("");
+    }
+  return sc;
+}
+
+
+/* NNTP thread messages
+ * Accepts: mail stream
+ *	    thread type
+ *	    character set
+ *	    search program
+ *	    option flags
+ * Returns: thread node tree
+ */
+
+THREADNODE *nntp_thread (MAILSTREAM *stream,char *type,char *charset,
+			 SEARCHPGM *spg,long flags)
+{
+  return mail_thread_msgs (stream,type,charset,spg,flags,nntp_sort);
+}
+
+/* NNTP ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ */
+
+long nntp_ping (MAILSTREAM *stream)
+{
+  return (nntp_send (LOCAL->nntpstream,"STAT",NIL) != NNTPSOFTFATAL);
+}
+
+
+/* NNTP check mailbox
+ * Accepts: MAIL stream
+ */
+
+void nntp_check (MAILSTREAM *stream)
+{
+				/* never do if no updates */
+  if (LOCAL->dirty) newsrc_write (LOCAL->name,stream);
+  LOCAL->dirty = NIL;
+}
+
+
+/* NNTP expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T if success, NIL if failure
+ */
+
+long nntp_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  if (!stream->silent) mm_log ("Expunge ignored on readonly mailbox",NIL);
+  return LONGT;
+}
+
+/* NNTP copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    option flags
+ * Returns: T if copy successful, else NIL
+ */
+
+long nntp_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+  if (pc) return (*pc) (stream,sequence,mailbox,options);
+  mm_log ("Copy not valid for NNTP",ERROR);
+  return NIL;
+}
+
+
+/* NNTP append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long nntp_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  mm_log ("Append not valid for NNTP",ERROR);
+  return NIL;
+}
+
+/* NNTP open connection
+ * Accepts: network driver
+ *	    service host list
+ *	    port number
+ *	    service name
+ *	    NNTP open options
+ * Returns: SEND stream on success, NIL on failure
+ */
+
+SENDSTREAM *nntp_open_full (NETDRIVER *dv,char **hostlist,char *service,
+			    unsigned long port,long options)
+{
+  SENDSTREAM *stream = NIL;
+  NETSTREAM *netstream = NIL;
+  NETMBX mb;
+  char tmp[MAILTMPLEN];
+  long extok = LONGT;
+  NETDRIVER *ssld = (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL);
+  sslstart_t stls = (sslstart_t) mail_parameters (NIL,GET_SSLSTART,NIL);
+  if (!(hostlist && *hostlist)) mm_log ("Missing NNTP service host",ERROR);
+  else do {			/* try to open connection */
+    sprintf (tmp,"{%.200s/%.20s}",*hostlist,service ? service : "nntp");
+    if (!mail_valid_net_parse (tmp,&mb) || mb.anoflag) {
+      sprintf (tmp,"Invalid host specifier: %.80s",*hostlist);
+      mm_log (tmp,ERROR);
+    }
+    else {			/* light tryssl flag if requested */
+      mb.trysslflag = (options & NOP_TRYSSL) ? T : NIL;
+				/* default port */
+      if (mb.port) port = mb.port;
+      else if (!port) port = nntp_port ? nntp_port : NNTPTCPPORT;
+      if (netstream =		/* try to open ordinary connection */
+	  net_open (&mb,dv,port,
+		    (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL),
+		    "*nntps",nntp_sslport ? nntp_sslport : NNTPSSLPORT)) {
+	stream = (SENDSTREAM *) fs_get (sizeof (SENDSTREAM));
+				/* initialize stream */
+	memset ((void *) stream,0,sizeof (SENDSTREAM));
+	stream->netstream = netstream;
+	stream->host = cpystr ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ?
+			       net_host (netstream) : mb.host);
+	stream->debug = (mb.dbgflag || (options & NOP_DEBUG)) ? T : NIL;
+	if (mb.loser) stream->loser = T;
+				/* process greeting */
+	switch ((int) nntp_reply (stream)) {
+	case NNTPGREET:		/* allow posting */
+	  NNTP.post = T;
+	  mm_notify (NIL,stream->reply + 4,(long) NIL);
+	  break;
+	case NNTPGREETNOPOST:	/* posting not allowed, must be readonly */
+	  NNTP.post = NIL;
+	  break;
+	default:
+	  mm_log (stream->reply,ERROR);
+	  stream = nntp_close (stream);
+	  break;
+	}
+      }
+    }
+  } while (!stream && *++hostlist);
+
+				/* get extensions */
+  if (stream && extok)
+    extok = nntp_extensions (stream,(mb.secflag ? AU_SECURE : NIL) |
+			     (mb.authuser[0] ? AU_AUTHUSER : NIL));
+  if (stream && !dv && stls && NNTP.ext.starttls &&
+      !mb.sslflag && !mb.notlsflag &&
+      (nntp_send_work (stream,"STARTTLS",NNTP.ext.multidomain ? mb.host : NIL)
+       == NNTPTLSSTART)) {
+    mb.tlsflag = T;		/* TLS OK, get into TLS at this end */
+    stream->netstream->dtb = ssld;
+				/* negotiate TLS */
+    if (stream->netstream->stream =
+	(*stls) (stream->netstream->stream,mb.host,
+		 (mb.tlssslv23 ? NIL : NET_TLSCLIENT) |
+		 (mb.novalidate ? NET_NOVALIDATECERT:NIL)))
+      extok = nntp_extensions (stream,(mb.secflag ? AU_SECURE : NIL) |
+			       (mb.authuser[0] ? AU_AUTHUSER : NIL));
+    else {
+      sprintf (tmp,"Unable to negotiate TLS with this server: %.80s",mb.host);
+      mm_log (tmp,ERROR);
+				/* close without doing QUIT */
+      if (stream->netstream) net_close (stream->netstream);
+      stream->netstream = NIL;
+      stream = nntp_close (stream);
+    }
+  }
+  else if (mb.tlsflag) {	/* user specified /tls but can't do it */
+    mm_log ("Unable to negotiate TLS with this server",ERROR);
+    return NIL;
+  }
+  if (stream) {			/* have a session? */
+    if (mb.user[0]) {		/* yes, have user name? */
+      if ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL)) {
+				/* remote name for authentication */
+	strncpy (mb.host,(long) mail_parameters (NIL,GET_SASLUSESPTRNAME,NIL) ?
+		 net_remotehost (netstream) : net_host (netstream),
+		 NETMAXHOST-1);
+	mb.host[NETMAXHOST-1] = '\0';
+      }
+      if (!nntp_send_auth_work (stream,&mb,tmp,NIL))
+	stream = nntp_close (stream);
+    }
+				/* authenticate if no-post and not readonly */
+    else if (!(NNTP.post || (options & NOP_READONLY) ||
+	       nntp_send_auth (stream,NIL))) stream = nntp_close (stream);
+  }
+
+				/* in case server demands MODE READER */
+  if (stream) switch ((int) nntp_send_work (stream,"MODE","READER")) {
+  case NNTPGREET:
+    NNTP.post = T;
+    break;
+  case NNTPGREETNOPOST:
+    NNTP.post = NIL;
+    break;
+  case NNTPWANTAUTH:		/* server wants auth first, do so and retry */
+  case NNTPWANTAUTH2:		/* remote name for authentication */
+    if ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL)) {
+      strncpy (mb.host,(long) mail_parameters (NIL,GET_SASLUSESPTRNAME,NIL) ?
+	       net_remotehost (netstream) : net_host (netstream),NETMAXHOST-1);
+      mb.host[NETMAXHOST-1] = '\0';
+    }
+    if (nntp_send_auth_work (stream,&mb,tmp,NIL))
+      switch ((int) nntp_send (stream,"MODE","READER")) {
+      case NNTPGREET:
+	NNTP.post = T;
+	break;
+      case NNTPGREETNOPOST:
+	NNTP.post = NIL;
+	break;
+      }
+    else stream = nntp_close (stream);
+    break;
+  }
+  if (stream) {			/* looks like we have a stream? */
+				/* yes, make sure can post if not readonly */
+    if (!(NNTP.post || (options & NOP_READONLY))) stream = nntp_close (stream);
+    else if (extok) nntp_extensions (stream,(mb.secflag ? AU_SECURE : NIL) |
+				     (mb.authuser[0] ? AU_AUTHUSER : NIL));
+  }
+  return stream;
+}
+
+/* NNTP extensions
+ * Accepts: stream
+ *	    authenticator flags
+ * Returns: T on success, NIL on failure
+ */
+
+long nntp_extensions (SENDSTREAM *stream,long flags)
+{
+  unsigned long i;
+  char *t,*r,*args;
+				/* zap all old extensions */
+  memset (&NNTP.ext,0,sizeof (NNTP.ext));
+  if (stream->loser) return NIL;/* nothing at all for losers */
+				/* get server extensions */
+  switch ((int) nntp_send_work (stream,"LIST","EXTENSIONS")) {
+  case NNTPEXTOK:		/* what NNTP base spec says */
+  case NNTPGLIST:		/* some servers do this instead */
+    break;
+  default:			/* no LIST EXTENSIONS on this server */
+    return NIL;
+  }
+  NNTP.ext.ok = T;		/* server offers extensions */
+  while ((t = net_getline (stream->netstream)) && (t[1] || (*t != '.'))) {
+    if (stream->debug) mm_dlog (t);
+				/* get optional capability arguments */
+    if (args = strchr (t,' ')) *args++ = '\0';
+    if (!compare_cstring (t,"LISTGROUP")) NNTP.ext.listgroup = T;
+    else if (!compare_cstring (t,"OVER")) NNTP.ext.over = T;
+    else if (!compare_cstring (t,"HDR")) NNTP.ext.hdr = T;
+    else if (!compare_cstring (t,"PAT")) NNTP.ext.pat = T;
+    else if (!compare_cstring (t,"STARTTLS")) NNTP.ext.starttls = T;
+    else if (!compare_cstring (t,"MULTIDOMAIN")) NNTP.ext.multidomain = T;
+
+    else if (!compare_cstring (t,"AUTHINFO") && args) {
+      char *sasl = NIL;
+      for (args = strtok_r (args," ",&r); args; args = strtok_r (NIL," ",&r)) {
+	if (!compare_cstring (args,"USER")) NNTP.ext.authuser = T;
+	else if (((args[0] == 'S') || (args[0] == 's')) &&
+		 ((args[1] == 'A') || (args[1] == 'a')) &&
+		 ((args[2] == 'S') || (args[2] == 's')) &&
+		 ((args[3] == 'L') || (args[3] == 'l')) && (args[4] == ':'))
+	  sasl = args + 5;
+      }
+      if (sasl) {		/* if SASL, look up authenticators */
+	for (sasl = strtok_r (sasl,",",&r); sasl; sasl = strtok_r (NIL,",",&r))
+	  if ((i = mail_lookup_auth_name (sasl,flags)) &&
+	      (--i < MAXAUTHENTICATORS))
+	    NNTP.ext.sasl |= (1 << i);
+				/* disable LOGIN if PLAIN also advertised */
+	if ((i = mail_lookup_auth_name ("PLAIN",NIL)) &&
+	    (--i < MAXAUTHENTICATORS) && (NNTP.ext.sasl & (1 << i)) &&
+	    (i = mail_lookup_auth_name ("LOGIN",NIL)) &&
+	    (--i < MAXAUTHENTICATORS)) NNTP.ext.sasl &= ~(1 << i);
+      }
+    }
+    fs_give ((void **) &t);
+  }
+  if (t) {			/* flush end of text indicator */
+    if (stream->debug) mm_dlog (t);
+    fs_give ((void **) &t);
+  }
+  return LONGT;
+}
+
+/* NNTP close connection
+ * Accepts: SEND stream
+ * Returns: NIL always
+ */
+
+SENDSTREAM *nntp_close (SENDSTREAM *stream)
+{
+  if (stream) {			/* send "QUIT" */
+    if (stream->netstream) nntp_send (stream,"QUIT",NIL);
+				/* do close actions */
+    if (stream->netstream) net_close (stream->netstream);
+    if (stream->host) fs_give ((void **) &stream->host);
+    if (stream->reply) fs_give ((void **) &stream->reply);
+    fs_give ((void **) &stream);/* flush the stream */
+  }
+  return NIL;
+}
+
+/* NNTP deliver news
+ * Accepts: SEND stream
+ *	    message envelope
+ *	    message body
+ * Returns: T on success, NIL on failure
+ */
+
+long nntp_mail (SENDSTREAM *stream,ENVELOPE *env,BODY *body)
+{
+  long ret;
+  RFC822BUFFER buf;
+  char *s,path[MAILTMPLEN],tmp[SENDBUFLEN+1];
+  long error = NIL;
+  long retry = NIL;
+  buf.f = nntp_soutr;		/* initialize buffer */
+  buf.s = stream->netstream;
+  buf.end = (buf.beg = buf.cur = tmp) + SENDBUFLEN;
+  tmp[SENDBUFLEN] = '\0';	/* must have additional null guard byte */
+  /* Gabba gabba hey, we need some brain damage to send netnews!!!
+   *
+   * First, we give ourselves a frontal lobotomy, and put in some UUCP
+   *  syntax.  It doesn't matter that it's completely bogus UUCP, and
+   *  that UUCP has nothing to do with anything we're doing.  It's been
+   *  alleged that "Path: not-for-mail" is also acceptable, but we won't
+   *  make assumptions unless the user says so.
+   *
+   * Second, we bop ourselves on the head with a ball-peen hammer.  How
+   *  dare we be so presumptious as to insert a *comment* in a Date:
+   *  header line.  Why, we were actually trying to be nice to a human
+   *  by giving a symbolic timezone (such as PST) in addition to a
+   *  numeric timezone (such as -0800).  But the gods of news transport
+   *  will have none of this.  Unix weenies, tried and true, rule!!!
+   *
+   * Third, Netscape Collabra server doesn't give the NNTPWANTAUTH error
+   *  until after requesting and receiving the entire message.  So we can't
+   *  call rely upon nntp_send() to do the auth retry.
+   */
+				/* RFC-1036 requires this cretinism */
+  sprintf (path,"Path: %s!%s\015\012",net_localhost (stream->netstream),
+	   env->sender ? env->sender->mailbox :
+	   (env->from ? env->from->mailbox : "not-for-mail"));
+				/* here's another cretinism */
+  if (s = strstr (env->date," (")) *s = NIL;
+  do if ((ret = nntp_send_work (stream,"POST",NIL)) == NNTPREADY)
+				/* output data, return success status */
+    ret = (net_soutr (stream->netstream,
+		      nntp_hidepath ? "Path: not-for-mail\015\012" : path) &&
+	   rfc822_output_full (&buf,env,body,T)) ?
+      nntp_send_work (stream,".",NIL) :
+      nntp_fake (stream,"NNTP connection broken (message text)");
+  while (((ret == NNTPWANTAUTH) || (ret == NNTPWANTAUTH2)) &&
+	 nntp_send_auth (stream,LONGT));
+  if (s) *s = ' ';		/* put the comment in the date back */
+  if (ret == NNTPOK) return LONGT;
+  else if (ret < 400) {		/* if not an error reply */
+    sprintf (tmp,"Unexpected NNTP posting reply code %ld",ret);
+    mm_log (tmp,WARN);		/* so someone looks at this eventually */
+    if ((ret >= 200) && (ret < 300)) return LONGT;
+  }
+  return NIL;
+}
+
+/* NNTP send command
+ * Accepts: SEND stream
+ *	    text
+ * Returns: reply code
+ */
+
+long nntp_send (SENDSTREAM *stream,char *command,char *args)
+{
+  long ret;
+  switch ((int) (ret = nntp_send_work (stream,command,args))) {
+  case NNTPWANTAUTH:		/* authenticate and retry */
+  case NNTPWANTAUTH2:
+    if (nntp_send_auth (stream,LONGT))
+      ret = nntp_send_work (stream,command,args);
+    else {			/* we're probably hosed, nuke the session */
+      nntp_send (stream,"QUIT",NIL);
+				/* close net connection */
+      if (stream->netstream) net_close (stream->netstream);
+      stream->netstream = NIL;
+    }
+  default:			/* all others just return */
+    break;
+  }
+  return ret;
+}
+
+
+/* NNTP send command worker routine
+ * Accepts: SEND stream
+ *	    text
+ * Returns: reply code
+ */
+
+long nntp_send_work (SENDSTREAM *stream,char *command,char *args)
+{
+  long ret;
+  char *s = (char *) fs_get (strlen (command) + (args ? strlen (args) + 1 : 0)
+			     + 3);
+  if (!stream->netstream) ret = nntp_fake (stream,"NNTP connection lost");
+  else {			/* build the complete command */
+    if (args) sprintf (s,"%s %s",command,args);
+    else strcpy (s,command);
+    if (stream->debug) mail_dlog (s,stream->sensitive);
+    strcat (s,"\015\012");
+				/* send the command */
+    ret = net_soutr (stream->netstream,s) ? nntp_reply (stream) :
+      nntp_fake (stream,"NNTP connection broken (command)");
+  }
+  fs_give ((void **) &s);
+  return ret;
+}
+
+/* NNTP send authentication if needed
+ * Accepts: SEND stream
+ *	    flags (non-NIL to get new extensions)
+ * Returns: T if need to redo command, NIL otherwise
+ */
+
+long nntp_send_auth (SENDSTREAM *stream,long flags)
+{
+  NETMBX mb;
+  char tmp[MAILTMPLEN];
+				/* remote name for authentication */
+  sprintf (tmp,"{%.200s/nntp",(long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ?
+	   ((long) mail_parameters (NIL,GET_SASLUSESPTRNAME,NIL) ?
+	    net_remotehost (stream->netstream) : net_host (stream->netstream)):
+	   stream->host);
+  if (stream->netstream->dtb ==
+      (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL))
+    strcat (tmp,"/ssl");
+  strcat (tmp,"}<none>");
+  mail_valid_net_parse (tmp,&mb);
+  return nntp_send_auth_work (stream,&mb,tmp,flags);
+}
+
+/* NNTP send authentication worker routine
+ * Accepts: SEND stream
+ *	    NETMBX structure
+ *	    scratch buffer of length MAILTMPLEN
+ *	    flags (non-NIL to get new extensions)
+ * Returns: T if authenticated, NIL otherwise
+ */
+
+long nntp_send_auth_work (SENDSTREAM *stream,NETMBX *mb,char *pwd,long flags)
+{
+  unsigned long trial,auths;
+  char tmp[MAILTMPLEN],usr[MAILTMPLEN];
+  AUTHENTICATOR *at;
+  char *lsterr = NIL;
+  long ret = NIL;
+				/* try SASL first */
+  for (auths = NNTP.ext.sasl, stream->saslcancel = NIL;
+       !ret && stream->netstream && auths &&
+       (at = mail_lookup_auth (find_rightmost_bit (&auths) + 1)); ) {
+    if (lsterr) {		/* previous authenticator failed? */
+      sprintf (tmp,"Retrying using %s authentication after %.80s",
+	       at->name,lsterr);
+      mm_log (tmp,NIL);
+      fs_give ((void **) &lsterr);
+    }
+    trial = 0;			/* initial trial count */
+    tmp[0] = '\0';		/* empty buffer */
+    if (stream->netstream) do {
+      if (lsterr) {
+	sprintf (tmp,"Retrying %s authentication after %.80s",at->name,lsterr);
+	mm_log (tmp,WARN);
+	fs_give ((void **) &lsterr);
+      }
+      stream->saslcancel = NIL;
+      if (nntp_send (stream,"AUTHINFO SASL",at->name) == NNTPCHALLENGE) {
+				/* hide client authentication responses */
+	if (!(at->flags & AU_SECURE)) stream->sensitive = T;
+	if ((*at->client) (nntp_challenge,nntp_response,"nntp",mb,stream,
+			   &trial,usr)) {
+	  if (stream->replycode == NNTPAUTHED) ret = LONGT;
+				/* if main program requested cancellation */
+	  else if (!trial) mm_log ("NNTP Authentication cancelled",ERROR);
+	}
+	stream->sensitive = NIL;/* unhide */
+      }
+				/* remember response if error and no cancel */
+      if (!ret && trial) lsterr = cpystr (stream->reply);
+    } while (!ret && stream->netstream && trial &&
+	     (trial < nntp_maxlogintrials));
+  }
+
+  if (lsterr) {			/* SAIL failed? */
+    if (!stream->saslcancel) {	/* don't do this if a cancel */
+      sprintf (tmp,"Can not authenticate to NNTP server: %.80s",lsterr);
+      mm_log (tmp,ERROR);
+    }
+    fs_give ((void **) &lsterr);
+  }
+  else if (mb->secflag)		/* no SASL, can't do /secure */
+    mm_log ("Can't do secure authentication with this server",ERROR);
+  else if (mb->authuser[0])	/* or /authuser */
+    mm_log ("Can't do /authuser with this server",ERROR);
+  /* Always try AUTHINFO USER, even if NNTP.ext.authuser isn't set.  There
+   * are servers that require it but don't return it as an extension.
+   */
+  else for (trial = 0, pwd[0] = 'x';
+	    !ret && pwd[0] && (trial < nntp_maxlogintrials) &&
+	      stream->netstream; ) {
+    pwd[0] = NIL;		/* get user name and password */
+    mm_login (mb,usr,pwd,trial++);
+				/* do the authentication */
+    if (pwd[0]) switch ((int) nntp_send_work (stream,"AUTHINFO USER",usr)) {
+    case NNTPBADCMD:		/* give up if unrecognized command */
+      mm_log (NNTP.ext.authuser ? stream->reply :
+	      "Can't do AUTHINFO USER to this server",ERROR);
+      trial = nntp_maxlogintrials;
+      break;
+    case NNTPAUTHED:		/* successful authentication */
+      ret = LONGT;		/* guess no password was needed */
+      break;
+    case NNTPWANTPASS:		/* wants password */
+      stream->sensitive = T;	/* hide this command */
+      if (nntp_send_work (stream,"AUTHINFO PASS",pwd) == NNTPAUTHED)
+	ret = LONGT;		/* password OK */
+      stream->sensitive = NIL;	/* unhide */
+      if (ret) break;		/* OK if successful */
+    default:			/* authentication failed */
+      mm_log (stream->reply,WARN);
+      if (trial == nntp_maxlogintrials)
+	mm_log ("Too many NNTP authentication failures",ERROR);
+    }
+				/* user refused to give a password */
+    else mm_log ("Login aborted",ERROR);
+  }
+  memset (pwd,0,MAILTMPLEN);	/* erase password */
+				/* get new extensions if needed */
+  if (ret && flags) nntp_extensions (stream,(mb->secflag ? AU_SECURE : NIL) |
+				     (mb->authuser[0] ? AU_AUTHUSER : NIL));
+  return ret;
+}
+
+/* Get challenge to authenticator in binary
+ * Accepts: stream
+ *	    pointer to returned size
+ * Returns: challenge or NIL if not challenge
+ */
+
+void *nntp_challenge (void *s,unsigned long *len)
+{
+  char tmp[MAILTMPLEN];
+  void *ret = NIL;
+  SENDSTREAM *stream = (SENDSTREAM *) s;
+  if ((stream->replycode == NNTPCHALLENGE) &&
+      !(ret = rfc822_base64 ((unsigned char *) stream->reply + 4,
+			     strlen (stream->reply + 4),len))) {
+    sprintf (tmp,"NNTP SERVER BUG (invalid challenge): %.80s",stream->reply+4);
+    mm_log (tmp,ERROR);
+  }
+  return ret;
+}
+
+
+/* Send authenticator response in BASE64
+ * Accepts: MAIL stream
+ *	    string to send
+ *	    length of string
+ * Returns: T, always
+ */
+
+long nntp_response (void *s,char *response,unsigned long size)
+{
+  SENDSTREAM *stream = (SENDSTREAM *) s;
+  unsigned long i,j;
+  char *t,*u;
+  if (response) {		/* make CRLFless BASE64 string */
+    if (size) {
+      for (t = (char *) rfc822_binary ((void *) response,size,&i),u = t,j = 0;
+	   j < i; j++) if (t[j] > ' ') *u++ = t[j];
+      *u = '\0';		/* tie off string */
+      i = nntp_send_work (stream,t,NIL);
+      fs_give ((void **) &t);
+    }
+    else i = nntp_send_work (stream,"",NIL);
+  }
+  else {			/* abort requested */
+    i = nntp_send_work (stream,"*",NIL);
+    stream->saslcancel = T;	/* mark protocol-requested SASL cancel */
+  }
+  return LONGT;
+}
+
+/* NNTP get reply
+ * Accepts: SEND stream
+ * Returns: reply code
+ */
+
+long nntp_reply (SENDSTREAM *stream)
+{
+				/* flush old reply */
+  if (stream->reply) fs_give ((void **) &stream->reply);
+  				/* get reply */
+  if (!(stream->reply = net_getline (stream->netstream)))
+    return nntp_fake (stream,"NNTP connection broken (response)");
+  if (stream->debug) mm_dlog (stream->reply);
+				/* handle continuation by recursion */
+  if (stream->reply[3] == '-') return nntp_reply (stream);
+				/* return response code */
+  return stream->replycode = atol (stream->reply);
+}
+
+
+/* NNTP set fake error
+ * Accepts: SEND stream
+ *	    error text
+ * Returns: error code
+ */
+
+long nntp_fake (SENDSTREAM *stream,char *text)
+{
+  if (stream->netstream) {	/* close net connection if still open */
+    net_close (stream->netstream);
+    stream->netstream = NIL;
+  }
+				/* flush any old reply */
+  if (stream->reply) fs_give ((void **) &stream->reply);
+  				/* set up pseudo-reply string */
+  stream->reply = (char *) fs_get (20+strlen (text));
+  sprintf (stream->reply,"%ld %s",NNTPSOFTFATAL,text);
+  return NNTPSOFTFATAL;		/* return error code */
+}
+
+/* NNTP filter mail
+ * Accepts: stream
+ *	    string
+ * Returns: T on success, NIL on failure
+ */
+
+long nntp_soutr (void *stream,char *s)
+{
+  char c,*t;
+				/* "." on first line */
+  if (s[0] == '.') net_soutr (stream,".");
+				/* find lines beginning with a "." */
+  while (t = strstr (s,"\015\012.")) {
+    c = *(t += 3);		/* remember next character after "." */
+    *t = '\0';			/* tie off string */
+				/* output prefix */
+    if (!net_soutr (stream,s)) return NIL;
+    *t = c;			/* restore delimiter */
+    s = t - 1;			/* push pointer up to the "." */
+  }
+				/* output remainder of text */
+  return *s ? net_soutr (stream,s) : T;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/nntp.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,56 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Network News Transfer Protocol (NNTP) routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 February 1992
+ * Last Edited:	30 August 2006
+ */
+
+/* Constants (should be in nntp.c) */
+
+#define NNTPTCPPORT (long) 119	/* assigned TCP contact port */
+
+
+/* NNTP open options
+ * For compatibility with the past, NOP_DEBUG must always be 1.
+ */
+
+#define NOP_DEBUG (long) 0x1	/* debug protocol negotiations */
+#define NOP_READONLY (long) 0x2	/* read-only open */
+#define NOP_TRYSSL (long) 0x4	/* try SSL first */
+				/* reserved for application use */
+#define NOP_RESERVED (unsigned long) 0xff000000
+
+
+/* Compatibility support names */
+
+#define nntp_open(hostlist,options) \
+  nntp_open_full (NIL,hostlist,"nntp",NIL,options)
+
+
+/* Function prototypes */
+
+SENDSTREAM *nntp_open_full (NETDRIVER *dv,char **hostlist,char *service,
+			    unsigned long port,long options);
+SENDSTREAM *nntp_close (SENDSTREAM *stream);
+long nntp_mail (SENDSTREAM *stream,ENVELOPE *msg,BODY *body);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/pop3.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1091 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Post Office Protocol 3 (POP3) client routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	6 June 1994
+ * Last Edited:	4 April 2007
+ */
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <time.h>
+#include "c-client.h"
+#include "flstring.h"
+#include "netmsg.h"
+
+/* Parameters */
+
+#define POP3TCPPORT (long) 110	/* assigned TCP contact port */
+#define POP3SSLPORT (long) 995	/* assigned SSL TCP contact port */
+#define IDLETIMEOUT (long) 10	/* defined in RFC 1939 */
+
+
+/* POP3 I/O stream local data */
+	
+typedef struct pop3_local {
+  NETSTREAM *netstream;		/* TCP I/O stream */
+  char *response;		/* last server reply */
+  char *reply;			/* text of last server reply */
+  unsigned long cached;		/* current cached message uid */
+  unsigned long hdrsize;	/* current cached header size */
+  FILE *txt;			/* current cached file descriptor */
+  struct {
+    unsigned int capa : 1;	/* server has CAPA, definitely new */
+    unsigned int expire : 1;	/* server has EXPIRE */
+    unsigned int logindelay : 1;/* server has LOGIN-DELAY */
+    unsigned int stls : 1;	/* server has STLS */
+    unsigned int pipelining : 1;/* server has PIPELINING */
+    unsigned int respcodes : 1;	/* server has RESP-CODES */
+    unsigned int top : 1;	/* server has TOP */
+    unsigned int uidl : 1;	/* server has UIDL */
+    unsigned int user : 1;	/* server has USER */
+    char *implementation;	/* server implementation string */
+    long delaysecs;		/* minimum time between login (neg variable) */
+    long expiredays;		/* server-guaranteed minimum retention days */
+				/* supported authenticators */
+    unsigned int sasl : MAXAUTHENTICATORS;
+  } cap;
+  unsigned int sensitive : 1;	/* sensitive data in progress */
+  unsigned int loser : 1;	/* server is a loser */
+  unsigned int saslcancel : 1;	/* SASL cancelled by protocol */
+} POP3LOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((POP3LOCAL *) stream->local)
+
+/* Function prototypes */
+
+DRIVER *pop3_valid (char *name);
+void *pop3_parameters (long function,void *value);
+void pop3_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void pop3_list (MAILSTREAM *stream,char *ref,char *pat);
+void pop3_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long pop3_subscribe (MAILSTREAM *stream,char *mailbox);
+long pop3_unsubscribe (MAILSTREAM *stream,char *mailbox);
+long pop3_create (MAILSTREAM *stream,char *mailbox);
+long pop3_delete (MAILSTREAM *stream,char *mailbox);
+long pop3_rename (MAILSTREAM *stream,char *old,char *newname);
+long pop3_status (MAILSTREAM *stream,char *mbx,long flags);
+MAILSTREAM *pop3_open (MAILSTREAM *stream);
+long pop3_capa (MAILSTREAM *stream,long flags);
+long pop3_auth (MAILSTREAM *stream,NETMBX *mb,char *pwd,char *usr);
+void *pop3_challenge (void *stream,unsigned long *len);
+long pop3_response (void *stream,char *s,unsigned long size);
+void pop3_close (MAILSTREAM *stream,long options);
+void pop3_fetchfast (MAILSTREAM *stream,char *sequence,long flags);
+char *pop3_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *size,
+		   long flags);
+long pop3_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+unsigned long pop3_cache (MAILSTREAM *stream,MESSAGECACHE *elt);
+long pop3_ping (MAILSTREAM *stream);
+void pop3_check (MAILSTREAM *stream);
+long pop3_expunge (MAILSTREAM *stream,char *sequence,long options);
+long pop3_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long pop3_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+long pop3_send_num (MAILSTREAM *stream,char *command,unsigned long n);
+long pop3_send (MAILSTREAM *stream,char *command,char *args);
+long pop3_reply (MAILSTREAM *stream);
+long pop3_fake (MAILSTREAM *stream,char *text);
+
+/* POP3 mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER pop3driver = {
+  "pop3",			/* driver name */
+				/* driver flags */
+#ifdef INADEQUATE_MEMORY
+  DR_LOWMEM |
+#endif
+  DR_MAIL|DR_NOFAST|DR_CRLF|DR_NOSTICKY|DR_NOINTDATE|DR_NONEWMAIL,
+  (DRIVER *) NIL,		/* next driver */
+  pop3_valid,			/* mailbox is valid for us */
+  pop3_parameters,		/* manipulate parameters */
+  pop3_scan,			/* scan mailboxes */
+  pop3_list,			/* find mailboxes */
+  pop3_lsub,			/* find subscribed mailboxes */
+  pop3_subscribe,		/* subscribe to mailbox */
+  pop3_unsubscribe,		/* unsubscribe from mailbox */
+  pop3_create,			/* create mailbox */
+  pop3_delete,			/* delete mailbox */
+  pop3_rename,			/* rename mailbox */
+  pop3_status,			/* status of mailbox */
+  pop3_open,			/* open mailbox */
+  pop3_close,			/* close mailbox */
+  pop3_fetchfast,		/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message structure */
+  pop3_header,			/* fetch message header */
+  pop3_text,			/* fetch message text */
+  NIL,				/* fetch message */
+  NIL,				/* unique identifier */
+  NIL,				/* message number from UID */
+  NIL,				/* modify flags */
+  NIL,				/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  pop3_ping,			/* ping mailbox to see if still alive */
+  pop3_check,			/* check for new messages */
+  pop3_expunge,			/* expunge deleted messages */
+  pop3_copy,			/* copy messages to another mailbox */
+  pop3_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM pop3proto = {&pop3driver};
+
+				/* driver parameters */
+static unsigned long pop3_maxlogintrials = MAXLOGINTRIALS;
+static long pop3_port = 0;
+static long pop3_sslport = 0;
+
+/* POP3 mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *pop3_valid (char *name)
+{
+  NETMBX mb;
+  return (mail_valid_net_parse (name,&mb) &&
+	  !strcmp (mb.service,pop3driver.name) && !mb.authuser[0] &&
+	  !compare_cstring (mb.mailbox,"INBOX")) ? &pop3driver : NIL;
+}
+
+
+/* News manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *pop3_parameters (long function,void *value)
+{
+  switch ((int) function) {
+  case SET_MAXLOGINTRIALS:
+    pop3_maxlogintrials = (unsigned long) value;
+    break;
+  case GET_MAXLOGINTRIALS:
+    value = (void *) pop3_maxlogintrials;
+    break;
+  case SET_POP3PORT:
+    pop3_port = (long) value;
+    break;
+  case GET_POP3PORT:
+    value = (void *) pop3_port;
+    break;
+  case SET_SSLPOPPORT:
+    pop3_sslport = (long) value;
+    break;
+  case GET_SSLPOPPORT:
+    value = (void *) pop3_sslport;
+    break;
+  case GET_IDLETIMEOUT:
+    value = (void *) IDLETIMEOUT;
+    break;
+  default:
+    value = NIL;		/* error case */
+    break;
+  }
+  return value;
+}
+
+/* POP3 mail scan mailboxes for string
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void pop3_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  char tmp[MAILTMPLEN];
+  if ((ref && *ref) ?		/* have a reference */
+      (pop3_valid (ref) && pmatch ("INBOX",pat)) :
+      (mail_valid_net (pat,&pop3driver,NIL,tmp) && pmatch ("INBOX",tmp)))
+    mm_log ("Scan not valid for POP3 mailboxes",ERROR);
+}
+
+
+/* POP3 mail find list of all mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void pop3_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  char tmp[MAILTMPLEN];
+  if (ref && *ref) {		/* have a reference */
+    if (pop3_valid (ref) && pmatch ("INBOX",pat)) {
+      strcpy (strchr (strcpy (tmp,ref),'}')+1,"INBOX");
+      mm_list (stream,NIL,tmp,LATT_NOINFERIORS);
+    }
+  }
+  else if (mail_valid_net (pat,&pop3driver,NIL,tmp) && pmatch ("INBOX",tmp)) {
+    strcpy (strchr (strcpy (tmp,pat),'}')+1,"INBOX");
+    mm_list (stream,NIL,tmp,LATT_NOINFERIORS);
+  }
+}
+
+/* POP3 mail find list of subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void pop3_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  void *sdb = NIL;
+  char *s,mbx[MAILTMPLEN];
+  if (*pat == '{') {		/* if remote pattern, must be POP3 */
+    if (!pop3_valid (pat)) return;
+    ref = NIL;			/* good POP3 pattern, punt reference */
+  }
+				/* if remote reference, must be valid POP3 */
+  if (ref && (*ref == '{') && !pop3_valid (ref)) return;
+				/* kludgy application of reference */
+  if (ref && *ref) sprintf (mbx,"%s%s",ref,pat);
+  else strcpy (mbx,pat);
+
+  if (s = sm_read (&sdb)) do if (pop3_valid (s) && pmatch (s,mbx))
+    mm_lsub (stream,NIL,s,NIL);
+  while (s = sm_read (&sdb));	/* until no more subscriptions */
+}
+
+
+/* POP3 mail subscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to add to subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long pop3_subscribe (MAILSTREAM *stream,char *mailbox)
+{
+  return sm_subscribe (mailbox);
+}
+
+
+/* POP3 mail unsubscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to delete from subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long pop3_unsubscribe (MAILSTREAM *stream,char *mailbox)
+{
+  return sm_unsubscribe (mailbox);
+}
+
+/* POP3 mail create mailbox
+ * Accepts: mail stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long pop3_create (MAILSTREAM *stream,char *mailbox)
+{
+  return NIL;			/* never valid for POP3 */
+}
+
+
+/* POP3 mail delete mailbox
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long pop3_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return NIL;			/* never valid for POP3 */
+}
+
+
+/* POP3 mail rename mailbox
+ * Accepts: mail stream
+ *	    old mailbox name
+ *	    new mailbox name
+ * Returns: T on success, NIL on failure
+ */
+
+long pop3_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  return NIL;			/* never valid for POP3 */
+}
+
+/* POP3 status
+ * Accepts: mail stream
+ *	    mailbox name
+ *	    status flags
+ * Returns: T on success, NIL on failure
+ */
+
+long pop3_status (MAILSTREAM *stream,char *mbx,long flags)
+{
+  MAILSTATUS status;
+  unsigned long i;
+  long ret = NIL;
+  MAILSTREAM *tstream =
+    (stream && LOCAL->netstream && mail_usable_network_stream (stream,mbx)) ?
+      stream : mail_open (NIL,mbx,OP_SILENT);
+  if (tstream) {		/* have a usable stream? */
+    status.flags = flags;	/* return status values */
+    status.messages = tstream->nmsgs;
+    status.recent = tstream->recent;
+    if (flags & SA_UNSEEN)	/* must search to get unseen messages */
+      for (i = 1,status.unseen = 0; i <= tstream->nmsgs; i++)
+	if (!mail_elt (tstream,i)->seen) status.unseen++;
+    status.uidnext = tstream->uid_last + 1;
+    status.uidvalidity = tstream->uid_validity;
+				/* pass status to main program */
+    mm_status (tstream,mbx,&status);
+    if (stream != tstream) mail_close (tstream);
+    ret = LONGT;
+  }
+  return ret;			/* success */
+}
+
+/* POP3 mail open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *pop3_open (MAILSTREAM *stream)
+{
+  unsigned long i,j;
+  char *s,*t,tmp[MAILTMPLEN],usr[MAILTMPLEN];
+  NETMBX mb;
+  MESSAGECACHE *elt;
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return &pop3proto;
+  mail_valid_net_parse (stream->mailbox,&mb);
+  usr[0] = '\0';		/* initially no user name */
+  if (stream->local) fatal ("pop3 recycle stream");
+				/* /anonymous not supported */
+  if (mb.anoflag || stream->anonymous) {
+    mm_log ("Anonymous POP3 login not available",ERROR);
+    return NIL;
+  }
+				/* /readonly not supported either */
+  if (mb.readonlyflag || stream->rdonly) {
+    mm_log ("Read-only POP3 access not available",ERROR);
+    return NIL;
+  }
+				/* copy other switches */
+  if (mb.dbgflag) stream->debug = T;
+  if (mb.secflag) stream->secure = T;
+  mb.trysslflag = stream->tryssl = (mb.trysslflag || stream->tryssl) ? T : NIL;
+  stream->local =		/* instantiate localdata */
+    (void *) memset (fs_get (sizeof (POP3LOCAL)),0,sizeof (POP3LOCAL));
+  stream->sequence++;		/* bump sequence number */
+  stream->perm_deleted = T;	/* deleted is only valid flag */
+
+  if ((LOCAL->netstream =	/* try to open connection */
+       net_open (&mb,NIL,pop3_port ? pop3_port : POP3TCPPORT,
+		 (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL),
+		 "*pop3s",pop3_sslport ? pop3_sslport : POP3SSLPORT)) &&
+      pop3_reply (stream)) {
+    mm_log (LOCAL->reply,NIL);	/* give greeting */
+    if (!pop3_auth (stream,&mb,tmp,usr)) pop3_close (stream,NIL);
+    else if (pop3_send (stream,"STAT",NIL)) {
+      int silent = stream->silent;
+      stream->silent = T;
+      sprintf (tmp,"{%.200s:%lu/pop3",
+	       (long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ?
+	       net_host (LOCAL->netstream) : mb.host,
+	       net_port (LOCAL->netstream));
+      if (mb.tlsflag) strcat (tmp,"/tls");
+      if (mb.tlssslv23) strcat (tmp,"/tls-sslv23");
+      if (mb.notlsflag) strcat (tmp,"/notls");
+      if (mb.sslflag) strcat (tmp,"/ssl");
+      if (mb.novalidate) strcat (tmp,"/novalidate-cert");
+      if (LOCAL->loser = mb.loser) strcat (tmp,"/loser");
+      if (stream->secure) strcat (tmp,"/secure");
+      sprintf (tmp + strlen (tmp),"/user=\"%s\"}%s",usr,mb.mailbox);
+      stream->inbox = T;	/* always INBOX */
+      fs_give ((void **) &stream->mailbox);
+      stream->mailbox = cpystr (tmp);
+				/* notify upper level */
+      mail_exists (stream,stream->uid_last = strtoul (LOCAL->reply,NIL,10));
+      mail_recent (stream,stream->nmsgs);
+				/* instantiate elt */
+      for (i = 0; i < stream->nmsgs;) {
+	elt = mail_elt (stream,++i);
+	elt->valid = elt->recent = T;
+	elt->private.uid = i;
+      }
+
+				/* trust LIST output if new server */
+      if (!LOCAL->loser && LOCAL->cap.capa && pop3_send (stream,"LIST",NIL)) {
+	while ((s = net_getline (LOCAL->netstream)) && (*s != '.')) {
+	  if ((i = strtoul (s,&t,10)) && (i <= stream->nmsgs) &&
+	      (j = strtoul (t,NIL,10))) mail_elt (stream,i)->rfc822_size = j;
+	  fs_give ((void **) &s);
+	}
+				/* flush final dot */
+	if (s) fs_give ((void **) &s);
+	else {			/* lost connection */
+	  mm_log ("POP3 connection broken while itemizing messages",ERROR);
+	  pop3_close (stream,NIL);
+	  return NIL;
+	}
+      }
+      stream->silent = silent;	/* notify main program */
+      mail_exists (stream,stream->nmsgs);
+				/* notify if empty */
+      if (!(stream->nmsgs || stream->silent)) mm_log ("Mailbox is empty",WARN);
+    }
+    else {			/* error in STAT */
+      mm_log (LOCAL->reply,ERROR);
+      pop3_close (stream,NIL);	/* too bad */
+    }
+  }
+  else {			/* connection failed */
+    if (LOCAL->reply) mm_log (LOCAL->reply,ERROR);
+    pop3_close (stream,NIL);	/* failed, clean up */
+  }
+  return LOCAL ? stream : NIL;	/* if stream is alive, return to caller */
+}
+
+/* POP3 capabilities
+ * Accepts: stream
+ *	    authenticator flags
+ * Returns: T on success, NIL on failure
+ */
+
+long pop3_capa (MAILSTREAM *stream,long flags)
+{
+  unsigned long i;
+  char *s,*t,*r,*args;
+  if (LOCAL->cap.implementation)/* zap all old capabilities */
+    fs_give ((void **) &LOCAL->cap.implementation);
+  memset (&LOCAL->cap,0,sizeof (LOCAL->cap));
+				/* get server capabilities */
+  if (pop3_send (stream,"CAPA",NIL)) LOCAL->cap.capa = T;
+  else {
+    LOCAL->cap.user = T;	/* guess worst-case old server */
+    return NIL;			/* no CAPA on this server */
+  }
+  while ((t = net_getline (LOCAL->netstream)) && (t[1] || (*t != '.'))) {
+    if (stream->debug) mm_dlog (t);
+				/* get optional capability arguments */
+    if (args = strchr (t,' ')) *args++ = '\0';
+    if (!compare_cstring (t,"STLS")) LOCAL->cap.stls = T;
+    else if (!compare_cstring (t,"PIPELINING")) LOCAL->cap.pipelining = T;
+    else if (!compare_cstring (t,"RESP-CODES")) LOCAL->cap.respcodes = T;
+    else if (!compare_cstring (t,"TOP")) LOCAL->cap.top = T;
+    else if (!compare_cstring (t,"UIDL")) LOCAL->cap.uidl = T;
+    else if (!compare_cstring (t,"USER")) LOCAL->cap.user = T;
+    else if (!compare_cstring (t,"IMPLEMENTATION") && args)
+      LOCAL->cap.implementation = cpystr (args);
+    else if (!compare_cstring (t,"EXPIRE") && args) {
+      LOCAL->cap.expire = T;	/* note that it is present */
+      if (s = strchr(args,' ')){/* separate time from possible USER */
+	*s++ = '\0';
+				/* in case they add something after USER */
+	if ((strlen (s) > 4) && (s[4] == ' ')) s[4] = '\0';
+      }
+      LOCAL->cap.expire =	/* get expiration time */
+	(!compare_cstring (args,"NEVER")) ? 65535 :
+	  ((s && !compare_cstring (s,"USER")) ? -atoi (args) : atoi (args));
+    }
+    else if (!compare_cstring (t,"LOGIN-DELAY") && args) {
+      LOCAL->cap.logindelay = T;/* note that it is present */
+      if (s = strchr(args,' ')){/* separate time from possible USER */
+	*s++ = '\0';
+				/* in case they add something after USER */
+	if ((strlen (s) > 4) && (s[4] == ' ')) s[4] = '\0';
+      }
+				/* get delay time */
+      LOCAL->cap.delaysecs = (s && !compare_cstring (s,"USER")) ?
+	-atoi (args) : atoi (args);
+    }
+    else if (!compare_cstring (t,"SASL") && args)
+      for (args = strtok_r (args," ",&r); args; args = strtok_r (NIL," ",&r))
+	if ((i = mail_lookup_auth_name (args,flags)) &&
+	    (--i < MAXAUTHENTICATORS))
+	  LOCAL->cap.sasl |= (1 << i);
+    fs_give ((void **) &t);
+  }
+  if (t) {			/* flush end of text indicator */
+    if (stream->debug) mm_dlog (t);
+    fs_give ((void **) &t);
+  }
+  return LONGT;
+}
+
+/* POP3 authenticate
+ * Accepts: stream to login
+ *	    parsed network mailbox structure
+ *	    scratch buffer of length MAILTMPLEN
+ *	    place to return user name
+ * Returns: T on success, NIL on failure
+ */
+
+long pop3_auth (MAILSTREAM *stream,NETMBX *mb,char *pwd,char *usr)
+{
+  unsigned long i,trial,auths = 0;
+  char *t;
+  AUTHENTICATOR *at;
+  long ret = NIL;
+  long flags = (stream->secure ? AU_SECURE : NIL) |
+    (mb->authuser[0] ? AU_AUTHUSER : NIL);
+  long capaok = pop3_capa (stream,flags);
+  NETDRIVER *ssld = (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL);
+  sslstart_t stls = (sslstart_t) mail_parameters (NIL,GET_SSLSTART,NIL);
+				/* server has TLS? */
+  if (stls && LOCAL->cap.stls && !mb->sslflag && !mb->notlsflag &&
+      pop3_send (stream,"STLS",NIL)) {
+    mb->tlsflag = T;		/* TLS OK, get into TLS at this end */
+    LOCAL->netstream->dtb = ssld;
+    if (!(LOCAL->netstream->stream =
+	  (*stls) (LOCAL->netstream->stream,mb->host,
+		   (mb->tlssslv23 ? NIL : NET_TLSCLIENT) |
+		   (mb->novalidate ? NET_NOVALIDATECERT : NIL)))) {
+				/* drat, drop this connection */
+      if (LOCAL->netstream) net_close (LOCAL->netstream);
+      LOCAL->netstream= NIL;
+      return NIL;		/* TLS negotiation failed */
+    }
+    pop3_capa (stream,flags);	/* get capabilities now that TLS in effect */
+  }
+  else if (mb->tlsflag) {	/* user specified /tls but can't do it */
+    mm_log ("Unable to negotiate TLS with this server",ERROR);
+    return NIL;
+  }
+  				/* get authenticators from capabilities */
+  if (capaok) auths = LOCAL->cap.sasl;
+				/* get list of authenticators */
+  else if (pop3_send (stream,"AUTH",NIL)) {
+    while ((t = net_getline (LOCAL->netstream)) && (t[1] || (*t != '.'))) {
+      if (stream->debug) mm_dlog (t);
+      if ((i = mail_lookup_auth_name (t,flags)) && (--i < MAXAUTHENTICATORS))
+	auths |= (1 << i);
+      fs_give ((void **) &t);
+    }
+    if (t) {			/* flush end of text indicator */
+      if (stream->debug) mm_dlog (t);
+      fs_give ((void **) &t);
+    }
+  }
+				/* disable LOGIN if PLAIN also advertised */
+  if ((i = mail_lookup_auth_name ("PLAIN",NIL)) && (--i < MAXAUTHENTICATORS) &&
+      (auths & (1 << i)) &&
+      (i = mail_lookup_auth_name ("LOGIN",NIL)) && (--i < MAXAUTHENTICATORS))
+    auths &= ~(1 << i);
+
+  if (auths) {			/* got any authenticators? */
+    if ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL)) {
+				/* remote name for authentication */
+      strncpy (mb->host,(long) mail_parameters (NIL,GET_SASLUSESPTRNAME,NIL) ?
+	       net_remotehost (LOCAL->netstream) : net_host (LOCAL->netstream),
+	       NETMAXHOST-1);
+      mb->host[NETMAXHOST-1] = '\0';
+    }
+    for (t = NIL, LOCAL->saslcancel = NIL; !ret && LOCAL->netstream && auths &&
+	 (at = mail_lookup_auth (find_rightmost_bit (&auths)+1)); ) {
+      if (t) {			/* previous authenticator failed? */
+	sprintf (pwd,"Retrying using %.80s authentication after %.80s",
+		 at->name,t);
+	mm_log (pwd,NIL);
+	fs_give ((void **) &t);
+      }
+      trial = 0;		/* initial trial count */
+      do {
+	if (t) {
+	  sprintf (pwd,"Retrying %s authentication after %.80s",at->name,t);
+	  mm_log (pwd,WARN);
+	  fs_give ((void **) &t);
+	}
+	LOCAL->saslcancel = NIL;
+	if (pop3_send (stream,"AUTH",at->name)) {
+				/* hide client authentication responses */
+	  if (!(at->flags & AU_SECURE)) LOCAL->sensitive = T;
+	  if ((*at->client) (pop3_challenge,pop3_response,"pop",mb,stream,
+			     &trial,usr) && LOCAL->response) {
+	    if (*LOCAL->response == '+') ret = LONGT;
+				/* if main program requested cancellation */
+	    else if (!trial) mm_log ("POP3 Authentication cancelled",ERROR);
+	  }
+	  LOCAL->sensitive=NIL;	/* unhide */
+	}
+				/* remember response if error and no cancel */
+	if (!ret && trial) t = cpystr (LOCAL->reply);
+      } while (!ret && trial && (trial < pop3_maxlogintrials) &&
+	       LOCAL->netstream);
+    }
+    if (t) {			/* previous authenticator failed? */
+      if (!LOCAL->saslcancel) {	/* don't do this if a cancel */
+	sprintf (pwd,"Can not authenticate to POP3 server: %.80s",t);
+	mm_log (pwd,ERROR);
+      }
+      fs_give ((void **) &t);
+    }
+  }
+
+  else if (stream->secure)
+    mm_log ("Can't do secure authentication with this server",ERROR);
+  else if (mb->authuser[0])
+    mm_log ("Can't do /authuser with this server",ERROR);
+  else if (!LOCAL->cap.user) mm_log ("Can't login to this server",ERROR);
+  else {			/* traditional login */
+    trial = 0;			/* initial trial count */
+    do {
+      pwd[0] = 0;		/* prompt user for password */
+      mm_login (mb,usr,pwd,trial++);
+      if (pwd[0]) {		/* send login sequence if have password */
+	if (pop3_send (stream,"USER",usr)) {
+	  LOCAL->sensitive = T;	/* hide this command */
+	  if (pop3_send (stream,"PASS",pwd)) ret = LONGT;
+	  LOCAL->sensitive=NIL;	/* unhide */
+	}
+	if (!ret) {		/* failure */
+	  mm_log (LOCAL->reply,WARN);
+	  if (trial == pop3_maxlogintrials)
+	    mm_log ("Too many login failures",ERROR);
+	}
+      }
+				/* user refused to give password */
+      else mm_log ("Login aborted",ERROR);
+    } while (!ret && pwd[0] && (trial < pop3_maxlogintrials) &&
+	     LOCAL->netstream);
+  }
+  memset (pwd,0,MAILTMPLEN);	/* erase password */
+				/* get capabilities if logged in */
+  if (ret && capaok) pop3_capa (stream,flags);
+  return ret;
+}
+
+/* Get challenge to authenticator in binary
+ * Accepts: stream
+ *	    pointer to returned size
+ * Returns: challenge or NIL if not challenge
+ */
+
+void *pop3_challenge (void *s,unsigned long *len)
+{
+  char tmp[MAILTMPLEN];
+  void *ret = NIL;
+  MAILSTREAM *stream = (MAILSTREAM *) s;
+  if (stream && LOCAL->response &&
+      (*LOCAL->response == '+') && (LOCAL->response[1] == ' ') &&
+      !(ret = rfc822_base64 ((unsigned char *) LOCAL->reply,
+			     strlen (LOCAL->reply),len))) {
+    sprintf (tmp,"POP3 SERVER BUG (invalid challenge): %.80s",LOCAL->reply);
+    mm_log (tmp,ERROR);
+  }
+  return ret;
+}
+
+
+/* Send authenticator response in BASE64
+ * Accepts: MAIL stream
+ *	    string to send
+ *	    length of string
+ * Returns: T if successful, else NIL
+ */
+
+long pop3_response (void *s,char *response,unsigned long size)
+{
+  MAILSTREAM *stream = (MAILSTREAM *) s;
+  unsigned long i,j,ret;
+  char *t,*u;
+  if (response) {		/* make CRLFless BASE64 string */
+    if (size) {
+      for (t = (char *) rfc822_binary ((void *) response,size,&i),u = t,j = 0;
+	   j < i; j++) if (t[j] > ' ') *u++ = t[j];
+      *u = '\0';		/* tie off string for mm_dlog() */
+      if (stream->debug) mail_dlog (t,LOCAL->sensitive);
+				/* append CRLF */
+      *u++ = '\015'; *u++ = '\012'; *u = '\0';
+      ret = net_sout (LOCAL->netstream,t,u - t);
+      fs_give ((void **) &t);
+    }
+    else ret = net_sout (LOCAL->netstream,"\015\012",2);
+  }
+  else {			/* abort requested */
+    ret = net_sout (LOCAL->netstream,"*\015\012",3);
+    LOCAL->saslcancel = T;	/* mark protocol-requested SASL cancel */
+  }
+  pop3_reply (stream);		/* get response */
+  return ret;
+}
+
+/* POP3 mail close
+ * Accepts: MAIL stream
+ *	    option flags
+ */
+
+void pop3_close (MAILSTREAM *stream,long options)
+{
+  int silent = stream->silent;
+  if (LOCAL) {			/* only if a file is open */
+    if (LOCAL->netstream) {	/* close POP3 connection */
+      stream->silent = T;
+      if (options & CL_EXPUNGE) pop3_expunge (stream,NIL,NIL);
+      stream->silent = silent;
+      pop3_send (stream,"QUIT",NIL);
+      mm_notify (stream,LOCAL->reply,BYE);
+    }
+				/* close POP3 connection */
+    if (LOCAL->netstream) net_close (LOCAL->netstream);
+				/* clean up */
+    if (LOCAL->cap.implementation)
+      fs_give ((void **) &LOCAL->cap.implementation);
+    if (LOCAL->txt) fclose (LOCAL->txt);
+    LOCAL->txt = NIL;
+    if (LOCAL->response) fs_give ((void **) &LOCAL->response);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+/* POP3 mail fetch fast information
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ * This is ugly and slow
+ */
+
+void pop3_fetchfast (MAILSTREAM *stream,char *sequence,long flags)
+{
+  unsigned long i;
+  MESSAGECACHE *elt;
+				/* get sequence */
+  if (stream && LOCAL && ((flags & FT_UID) ?
+			  mail_uid_sequence (stream,sequence) :
+			  mail_sequence (stream,sequence)))
+    for (i = 1; i <= stream->nmsgs; i++)
+      if ((elt = mail_elt (stream,i))->sequence &&
+	  !(elt->day && elt->rfc822_size)) {
+	ENVELOPE **env = NIL;
+	ENVELOPE *e = NIL;
+	if (!stream->scache) env = &elt->private.msg.env;
+	else if (stream->msgno == i) env = &stream->env;
+	else env = &e;
+	if (!*env || !elt->rfc822_size) {
+	  STRING bs;
+	  unsigned long hs;
+	  char *ht = (*stream->dtb->header) (stream,i,&hs,NIL);
+				/* need to make an envelope? */
+	  if (!*env) rfc822_parse_msg (env,NIL,ht,hs,NIL,BADHOST,
+				       stream->dtb->flags);
+				/* need message size too, ugh */
+	  if (!elt->rfc822_size) {
+	    (*stream->dtb->text) (stream,i,&bs,FT_PEEK);
+	    elt->rfc822_size = hs + SIZE (&bs) - GETPOS (&bs);
+	  }
+	}
+				/* if need date, have date in envelope? */
+	if (!elt->day && *env && (*env)->date)
+	  mail_parse_date (elt,(*env)->date);
+				/* sigh, fill in bogus default */
+	if (!elt->day) elt->day = elt->month = 1;
+	mail_free_envelope (&e);
+      }
+}
+
+/* POP3 fetch header as text
+ * Accepts: mail stream
+ *	    message number
+ *	    pointer to return size
+ *	    flags
+ * Returns: header text
+ */
+
+char *pop3_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *size,
+		   long flags)
+{
+  unsigned long i;
+  char tmp[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  FILE *f = NIL;
+  *size = 0;			/* initially no header size */
+  if ((flags & FT_UID) && !(msgno = mail_msgno (stream,msgno))) return "";
+				/* have header text already? */
+  if (!(elt = mail_elt (stream,msgno))->private.msg.header.text.data) {
+				/* if have CAPA and TOP, assume good TOP */
+    if (!LOCAL->loser && LOCAL->cap.top) {
+      sprintf (tmp,"TOP %lu 0",mail_uid (stream,msgno));
+      if (pop3_send (stream,tmp,NIL))
+	f = netmsg_slurp (LOCAL->netstream,&i,
+			  &elt->private.msg.header.text.size);
+    }
+				/* otherwise load the cache with the message */
+    else if (elt->private.msg.header.text.size = pop3_cache (stream,elt))
+      f = LOCAL->txt;
+    if (f) {			/* got it, make sure at start of file */
+      fseek (f,(unsigned long) 0,SEEK_SET);
+				/* read header from the cache */
+      fread (elt->private.msg.header.text.data = (unsigned char *)
+	     fs_get ((size_t) elt->private.msg.header.text.size + 1),
+	     (size_t) 1,(size_t) elt->private.msg.header.text.size,f);
+				/* tie off header text */
+      elt->private.msg.header.text.data[elt->private.msg.header.text.size] =
+	'\0';
+				/* close if not the cache */
+      if (f != LOCAL->txt) fclose (f);
+    }
+  }
+				/* return size of text */
+  if (size) *size = elt->private.msg.header.text.size;
+  return elt->private.msg.header.text.data ?
+    (char *) elt->private.msg.header.text.data : "";
+}
+
+/* POP3 fetch body
+ * Accepts: mail stream
+ *	    message number
+ *	    pointer to stringstruct to initialize
+ *	    flags
+ * Returns: T if successful, else NIL
+ */
+
+long pop3_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  MESSAGECACHE *elt;
+  INIT (bs,mail_string,(void *) "",0);
+  if ((flags & FT_UID) && !(msgno = mail_msgno (stream,msgno))) return NIL;
+  elt = mail_elt (stream,msgno);
+  pop3_cache (stream,elt);	/* make sure cache loaded */
+  if (!LOCAL->txt) return NIL;	/* error if don't have a file */
+  if (!(flags & FT_PEEK)) {	/* mark seen if needed */
+    elt->seen = T;
+    mm_flags (stream,elt->msgno);
+  }
+  INIT (bs,file_string,(void *) LOCAL->txt,elt->rfc822_size);
+  SETPOS (bs,LOCAL->hdrsize);	/* skip past header */
+  return T;
+}
+
+/* POP3 cache message
+ * Accepts: mail stream
+ *	    message number
+ * Returns: header size
+ */
+
+unsigned long pop3_cache (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+				/* already cached? */
+  if (LOCAL->cached != mail_uid (stream,elt->msgno)) {
+				/* no, close current file */
+    if (LOCAL->txt) fclose (LOCAL->txt);
+    LOCAL->txt = NIL;
+    LOCAL->cached = LOCAL->hdrsize = 0;
+    if (pop3_send_num (stream,"RETR",elt->msgno) &&
+	(LOCAL->txt = netmsg_slurp (LOCAL->netstream,&elt->rfc822_size,
+				    &LOCAL->hdrsize)))
+				/* set as current message number */
+      LOCAL->cached = mail_uid (stream,elt->msgno);
+    else elt->deleted = T;
+  }
+  return LOCAL->hdrsize;
+}
+
+/* POP3 mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ */
+
+long pop3_ping (MAILSTREAM *stream)
+{
+  return pop3_send (stream,"NOOP",NIL);
+}
+
+
+/* POP3 mail check mailbox
+ * Accepts: MAIL stream
+ */
+
+void pop3_check (MAILSTREAM *stream)
+{
+  if (pop3_ping (stream)) mm_log ("Check completed",NIL);
+}
+
+
+/* POP3 mail expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T if success, NIL if failure
+ */
+
+long pop3_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  char tmp[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  unsigned long i = 1,n = 0;
+  long ret;
+  if (ret = sequence ? ((options & EX_UID) ?
+			mail_uid_sequence (stream,sequence) :
+			mail_sequence (stream,sequence)) :
+      LONGT) {			/* build selected sequence if needed */
+    while (i <= stream->nmsgs) {
+      elt = mail_elt (stream,i);
+      if (elt->deleted && (sequence ? elt->sequence : T) &&
+	  pop3_send_num (stream,"DELE",i)) {
+				/* expunging currently cached message? */
+	if (LOCAL->cached == mail_uid (stream,i)) {
+				/* yes, close current file */
+	  if (LOCAL->txt) fclose (LOCAL->txt);
+	  LOCAL->txt = NIL;
+	  LOCAL->cached = LOCAL->hdrsize = 0;
+	}
+	mail_expunged (stream,i);
+	n++;
+      }
+      else i++;			/* try next message */
+    }
+    if (!stream->silent) {	/* only if not silent */
+      if (n) {			/* did we expunge anything? */
+	sprintf (tmp,"Expunged %lu messages",n);
+	mm_log (tmp,(long) NIL);
+      }
+      else mm_log ("No messages deleted, so no update needed",(long) NIL);
+    }
+  }
+  return ret;
+}
+
+/* POP3 mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    option flags
+ * Returns: T if copy successful, else NIL
+ */
+
+long pop3_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+  if (pc) return (*pc) (stream,sequence,mailbox,options);
+  mm_log ("Copy not valid for POP3",ERROR);
+  return NIL;
+}
+
+
+/* POP3 mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long pop3_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  mm_log ("Append not valid for POP3",ERROR);
+  return NIL;
+}
+
+/* Internal routines */
+
+
+/* Post Office Protocol 3 send command with number argument
+ * Accepts: MAIL stream
+ *	    command
+ *	    number
+ * Returns: T if successful, NIL if failure
+ */
+
+long pop3_send_num (MAILSTREAM *stream,char *command,unsigned long n)
+{
+  char tmp[MAILTMPLEN];
+  sprintf (tmp,"%lu",mail_uid (stream,n));
+  return pop3_send (stream,command,tmp);
+}
+
+
+/* Post Office Protocol 3 send command
+ * Accepts: MAIL stream
+ *	    command
+ *	    command argument
+ * Returns: T if successful, NIL if failure
+ */
+
+long pop3_send (MAILSTREAM *stream,char *command,char *args)
+{
+  long ret;
+  char *s = (char *) fs_get (strlen (command) + (args ? strlen (args) + 1: 0)
+			     + 3);
+  mail_lock (stream);		/* lock up the stream */
+  if (!LOCAL->netstream) ret = pop3_fake (stream,"POP3 connection lost");
+  else {			/* build the complete command */
+    if (args) sprintf (s,"%s %s",command,args);
+    else strcpy (s,command);
+    if (stream->debug) mail_dlog (s,LOCAL->sensitive);
+    strcat (s,"\015\012");
+				/* send the command */
+    ret = net_soutr (LOCAL->netstream,s) ? pop3_reply (stream) :
+      pop3_fake (stream,"POP3 connection broken in command");
+  }
+  fs_give ((void **) &s);
+  mail_unlock (stream);		/* unlock stream */
+  return ret;
+}
+
+/* Post Office Protocol 3 get reply
+ * Accepts: MAIL stream
+ * Returns: T if success reply, NIL if error reply
+ */
+
+long pop3_reply (MAILSTREAM *stream)
+{
+  char *s;
+				/* flush old reply */
+  if (LOCAL->response) fs_give ((void **) &LOCAL->response);
+  				/* get reply */
+  if (!(LOCAL->response = net_getline (LOCAL->netstream)))
+    return pop3_fake (stream,"POP3 connection broken in response");
+  if (stream->debug) mm_dlog (LOCAL->response);
+  LOCAL->reply = (s = strchr (LOCAL->response,' ')) ? s + 1 : LOCAL->response;
+				/* return success or failure */
+  return (*LOCAL->response =='+') ? T : NIL;
+}
+
+
+/* Post Office Protocol 3 set fake error
+ * Accepts: MAIL stream
+ *	    error text
+ * Returns: NIL, always
+ */
+
+long pop3_fake (MAILSTREAM *stream,char *text)
+{
+  mm_notify (stream,text,BYE);	/* send bye alert */
+  if (LOCAL->netstream) net_close (LOCAL->netstream);
+  LOCAL->netstream = NIL;	/* farewell, dear TCP stream */
+				/* flush any old reply */
+  if (LOCAL->response) fs_give ((void **) &LOCAL->response);
+  LOCAL->reply = text;		/* set up pseudo-reply string */
+  return NIL;			/* return error code */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/rfc822.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,2369 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	RFC 2822 and MIME routines
+ *
+ * Author:	Mark Crispin
+ *		UW Technology
+ *		University of Washington
+ *		Seattle, WA  98195
+ *		Internet: MRC@Washington.EDU
+ *
+ * Date:	27 July 1988
+ * Last Edited:	14 May 2008
+ *
+ * This original version of this file is
+ * Copyright 1988 Stanford University
+ * and was developed in the Symbolic Systems Resources Group of the Knowledge
+ * Systems Laboratory at Stanford University in 1987-88, and was funded by the
+ * Biomedical Research Technology Program of the NationalInstitutes of Health
+ * under grant number RR-00785.
+ */
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <time.h>
+#include "c-client.h"
+
+
+/* Support for deprecated features in earlier specifications.  Note that this
+ * module follows RFC 2822, and all use of "rfc822" in function names is
+ * for compatibility.  Only the code identified by the conditionals below
+ * follows the earlier documents.
+ */
+
+#define RFC733 1		/* parse "at" */
+#define RFC822 0		/* generate A-D-L (MUST be 0 for 2822) */
+
+/* RFC-822 static data */
+
+#define RFC822CONT "    "	/* RFC 2822 continuation */
+
+				/* should have been "Remailed-" */
+#define RESENTPREFIX "ReSent-"
+static char *resentprefix = RESENTPREFIX;
+				/* syntax error host string */
+static const char *errhst = ERRHOST;
+
+
+/* Body formats constant strings, must match definitions in mail.h */
+
+char *body_types[TYPEMAX+1] = {
+  "TEXT", "MULTIPART", "MESSAGE", "APPLICATION", "AUDIO", "IMAGE", "VIDEO",
+  "MODEL", "X-UNKNOWN"
+};
+
+
+char *body_encodings[ENCMAX+1] = {
+  "7BIT", "8BIT", "BINARY", "BASE64", "QUOTED-PRINTABLE", "X-UNKNOWN"
+};
+
+
+/* Token delimiting special characters */
+
+				/* RFC 2822 specials */
+const char *specials = " ()<>@,;:\\\"[].\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\177";
+				/* RFC 2822 phrase specials (no space) */
+const char *rspecials = "()<>@,;:\\\"[].\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\177";
+				/* RFC 2822 dot-atom specials (no dot) */
+const char *wspecials = " ()<>@,;:\\\"[]\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\177";
+				/* RFC 2045 MIME body token specials */
+const char *tspecials = " ()<>@,;:\\\"[]/?=\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32\33\34\35\36\37\177";
+
+/* Subtype defaulting (a no-no, but regretably necessary...)
+ * Accepts: type code
+ * Returns: default subtype name
+ */
+
+char *rfc822_default_subtype (unsigned short type)
+{
+  switch (type) {
+  case TYPETEXT:		/* default is TEXT/PLAIN */
+    return "PLAIN";
+  case TYPEMULTIPART:		/* default is MULTIPART/MIXED */
+    return "MIXED";
+  case TYPEMESSAGE:		/* default is MESSAGE/RFC822 */
+    return "RFC822";
+  case TYPEAPPLICATION:		/* default is APPLICATION/OCTET-STREAM */
+    return "OCTET-STREAM";
+  case TYPEAUDIO:		/* default is AUDIO/BASIC */
+    return "BASIC";
+  default:			/* others have no default subtype */
+    return "UNKNOWN";
+  }
+}
+
+/* RFC 2822 parsing routines */
+
+
+/* Parse an RFC 2822 message
+ * Accepts: pointer to return envelope
+ *	    pointer to return body
+ *	    pointer to header
+ *	    header byte count
+ *	    pointer to body stringstruct
+ *	    pointer to local host name
+ *	    recursion depth
+ *	    source driver flags
+ */
+
+void rfc822_parse_msg_full (ENVELOPE **en,BODY **bdy,char *s,unsigned long i,
+			    STRING *bs,char *host,unsigned long depth,
+			    unsigned long flags)
+{
+  char c,*t,*d;
+  char *tmp = (char *) fs_get ((size_t) i + 100);
+  ENVELOPE *env = (*en = mail_newenvelope ());
+  BODY *body = bdy ? (*bdy = mail_newbody ()) : NIL;
+  long MIMEp = -1;		/* flag that MIME semantics are in effect */
+  parseline_t pl = (parseline_t) mail_parameters (NIL,GET_PARSELINE,NIL);
+  if (!host) host = BADHOST;	/* make sure that host is non-null */
+  while (i && *s != '\n') {	/* until end of header */
+    t = tmp;			/* initialize buffer pointer */
+    c = ' ';			/* and previous character */
+    while (i && c) {		/* collect text until logical end of line */
+      switch (c = *s++) {	/* slurp a character */
+      case '\015':		/* return, possible end of logical line */
+	if (*s == '\n') break;	/* ignore if LF follows */
+      case '\012':		/* LF, possible end of logical line */
+				/* tie off unless next line starts with WS */
+	if (*s != ' ' && *s != '\t') *t++ = c = '\0';
+	break;
+      case '\t':		/* tab */
+	*t++ = ' ';		/* coerce to space */
+	break;
+      default:			/* all other characters */
+	*t++ = c;		/* insert the character into the line */
+	break;
+      }
+      if (!--i) *t++ = '\0';	/* see if end of header */
+    }
+
+				/* find header item type */
+    if (t = d = strchr (tmp,':')) {
+      *d++ = '\0';		/* tie off header item, point at its data */
+      while (*d == ' ') d++;	/* flush whitespace */
+      while ((tmp < t--) && (*t == ' ')) *t = '\0';
+      ucase (tmp);		/* coerce to uppercase */
+				/* external callback */
+      if (pl) (*pl) (env,tmp,d,host);
+      switch (*tmp) {		/* dispatch based on first character */
+      case '>':			/* possible >From: */
+	if (!strcmp (tmp+1,"FROM")) rfc822_parse_adrlist (&env->from,d,host);
+	break;
+      case 'B':			/* possible bcc: */
+	if (!strcmp (tmp+1,"CC")) rfc822_parse_adrlist (&env->bcc,d,host);
+	break;
+      case 'C':			/* possible cc: or Content-<mumble>*/
+	if (!strcmp (tmp+1,"C")) rfc822_parse_adrlist (&env->cc,d,host);
+	else if ((tmp[1] == 'O') && (tmp[2] == 'N') && (tmp[3] == 'T') &&
+		 (tmp[4] == 'E') && (tmp[5] == 'N') && (tmp[6] == 'T') &&
+		 (tmp[7] == '-') && body)
+	  switch (MIMEp) {
+	  case -1:		/* unknown if MIME or not */
+	    if (!(MIMEp =	/* see if MIME-Version header exists */
+		  search ((unsigned char *) s-1,i,
+			  (unsigned char *)"\012MIME-Version",(long) 13))) {
+#if 1
+	      /* This is a disgusting kludge, and most of the messages which
+	       * benefit from it are spam.
+	       */
+	      if (!strcmp (tmp+8,"TRANSFER-ENCODING") ||
+		  (!strcmp (tmp+8,"TYPE") && strchr (d,'/'))) {
+		MM_LOG ("Warning: MIME header encountered in non-MIME message",
+			PARSE);
+		MIMEp = 1;	/* declare MIME now */
+	      }
+	      else
+#endif
+		break;		/* non-MIME message */
+	    }
+	  case T:		/* definitely MIME */
+	    rfc822_parse_content_header (body,tmp+8,d);
+	  }
+	break;
+      case 'D':			/* possible Date: */
+	if (!env->date && !strcmp (tmp+1,"ATE")) env->date = cpystr (d);
+	break;
+      case 'F':			/* possible From: */
+	if (!strcmp (tmp+1,"ROM")) rfc822_parse_adrlist (&env->from,d,host);
+	else if (!strcmp (tmp+1,"OLLOWUP-TO")) {
+	  t = env->followup_to = (char *) fs_get (1 + strlen (d));
+	  while (c = *d++) if (c != ' ') *t++ = c;
+	  *t++ = '\0';
+	}
+	break;
+      case 'I':			/* possible In-Reply-To: */
+	if (!env->in_reply_to && !strcmp (tmp+1,"N-REPLY-TO"))
+	  env->in_reply_to = cpystr (d);
+	break;
+
+      case 'M':			/* possible Message-ID: or MIME-Version: */
+	if (!env->message_id && !strcmp (tmp+1,"ESSAGE-ID"))
+	  env->message_id = cpystr (d);
+	else if (!strcmp (tmp+1,"IME-VERSION")) {
+				/* tie off at end of phrase */
+	  if (t = rfc822_parse_phrase (d)) *t = '\0';
+	  rfc822_skipws (&d);	/* skip whitespace */
+				/* known version? */
+	  if (strcmp (d,"1.0") && strcmp (d,"RFC-XXXX"))
+	    MM_LOG ("Warning: message has unknown MIME version",PARSE);
+	  MIMEp = T;		/* note that we are MIME */
+	}
+	break;
+      case 'N':			/* possible Newsgroups: */
+	if (!env->newsgroups && !strcmp (tmp+1,"EWSGROUPS")) {
+	  t = env->newsgroups = (char *) fs_get (1 + strlen (d));
+	  while (c = *d++) if (c != ' ') *t++ = c;
+	  *t++ = '\0';
+	}
+	break;
+      case 'R':			/* possible Reply-To: */
+	if (!strcmp (tmp+1,"EPLY-TO"))
+	  rfc822_parse_adrlist (&env->reply_to,d,host);
+	else if (!env->references && !strcmp (tmp+1,"EFERENCES"))
+	  env->references = cpystr (d);
+	break;
+      case 'S':			/* possible Subject: or Sender: */
+	if (!env->subject && !strcmp (tmp+1,"UBJECT"))
+	  env->subject = cpystr (d);
+	else if (!strcmp (tmp+1,"ENDER"))
+	  rfc822_parse_adrlist (&env->sender,d,host);
+	break;
+      case 'T':			/* possible To: */
+	if (!strcmp (tmp+1,"O")) rfc822_parse_adrlist (&env->to,d,host);
+	break;
+      default:
+	break;
+      }
+    }
+  }
+  fs_give ((void **) &tmp);	/* done with scratch buffer */
+				/* default Sender: and Reply-To: to From: */
+  if (!env->sender) env->sender = rfc822_cpy_adr (env->from);
+  if (!env->reply_to) env->reply_to = rfc822_cpy_adr (env->from);
+				/* now parse the body */
+  if (body) rfc822_parse_content (body,bs,host,depth,flags);
+}
+
+/* Parse a message body content
+ * Accepts: pointer to body structure
+ *	    body string
+ *	    pointer to local host name
+ *	    recursion depth
+ *	    source driver flags
+ */
+
+void rfc822_parse_content (BODY *body,STRING *bs,char *h,unsigned long depth,
+			   unsigned long flags)
+{
+  char c,c1,*s,*s1;
+  int f;
+  unsigned long i,j,k,m;
+  PARAMETER *param;
+  PART *part = NIL;
+  if (depth > MAXMIMEDEPTH) {	/* excessively deep recursion? */
+    body->type = TYPETEXT;	/* yes, probably a malicious MIMEgram */
+    MM_LOG ("Ignoring excessively deep MIME recursion",PARSE);
+  }
+  if (!body->subtype)		/* default subtype if still unknown */
+    body->subtype = cpystr (rfc822_default_subtype (body->type));
+				/* note offset and sizes */
+  body->contents.offset = GETPOS (bs);
+				/* note internal body size in all cases */
+  body->size.bytes = body->contents.text.size = i = SIZE (bs);
+  if (!(flags & DR_CRLF)) body->size.bytes = strcrlflen (bs);
+  switch (body->type) {		/* see if anything else special to do */
+  case TYPETEXT:		/* text content */
+    if (!body->parameter) {	/* no parameters set */
+      body->parameter = mail_newbody_parameter ();
+      body->parameter->attribute = cpystr ("CHARSET");
+      while (i--) {		/* count lines and guess charset */
+	c = SNX (bs);		/* get current character */
+				/* charset still unknown? */
+	if (!body->parameter->value) {
+	  if ((c == I2C_ESC) && (i && i--) && ((c = SNX (bs)) == I2C_MULTI) &&
+	      (i && i--) && (((c = SNX (bs)) == I2CS_94x94_JIS_NEW) ||
+			     (c == I2CS_94x94_JIS_OLD)))
+	    body->parameter->value = cpystr ("ISO-2022-JP");
+	  else if (c & 0x80) body->parameter->value = cpystr ("X-UNKNOWN");
+	}
+	if (c == '\n') body->size.lines++;
+      }
+				/* 7-bit content */
+      if (!body->parameter->value) switch (body->encoding) {
+      case ENC7BIT:		/* unadorned 7-bit */
+      case ENC8BIT:		/* unadorned 8-bit (but 7-bit content) */
+      case ENCBINARY:		/* binary (but 7-bit content( */
+	body->parameter->value = cpystr ("US-ASCII");
+	break;
+      default:			/* QUOTED-PRINTABLE, BASE64, etc. */
+	body->parameter->value = cpystr ("X-UNKNOWN");
+	break;
+      }
+    }
+				/* just count lines */
+    else while (i--) if ((SNX (bs)) == '\n') body->size.lines++;
+    break;
+
+  case TYPEMESSAGE:		/* encapsulated message */
+				/* encapsulated RFC-822 message? */
+    if (!strcmp (body->subtype,"RFC822")) {
+      body->nested.msg = mail_newmsg ();
+      switch (body->encoding) {	/* make sure valid encoding */
+      case ENC7BIT:		/* these are valid nested encodings */
+      case ENC8BIT:
+      case ENCBINARY:
+	break;
+      default:
+	MM_LOG ("Ignoring nested encoding of message contents",PARSE);
+      }
+				/* hunt for blank line */
+      for (c = '\012',j = 0; (i > j) && ((c != '\012') || (CHR(bs) != '\012'));
+	   j++) if ((c1 = SNX (bs)) != '\015') c = c1;
+      if (i > j) {		/* unless no more text */
+	c1 = SNX (bs);		/* body starts here */
+	j++;			/* advance count */
+      }
+				/* note body text offset and header size */
+      body->nested.msg->header.text.size = j;
+      body->nested.msg->text.text.size = body->contents.text.size - j;
+      body->nested.msg->text.offset = GETPOS (bs);
+      body->nested.msg->full.offset = body->nested.msg->header.offset =
+	body->contents.offset;
+      body->nested.msg->full.text.size = body->contents.text.size;
+				/* copy header string */
+      SETPOS (bs,body->contents.offset);
+      s = (char *) fs_get ((size_t) j + 1);
+      for (s1 = s,k = j; k--; *s1++ = SNX (bs));
+      s[j] = '\0';		/* tie off string (not really necessary) */
+				/* now parse the body */
+      rfc822_parse_msg_full (&body->nested.msg->env,&body->nested.msg->body,s,
+			     j,bs,h,depth+1,flags);
+      fs_give ((void **) &s);	/* free header string */
+				/* restore position */
+      SETPOS (bs,body->contents.offset);
+    }
+				/* count number of lines */
+    while (i--) if (SNX (bs) == '\n') body->size.lines++;
+    break;
+  case TYPEMULTIPART:		/* multiple parts */
+    switch (body->encoding) {	/* make sure valid encoding */
+    case ENC7BIT:		/* these are valid nested encodings */
+    case ENC8BIT:
+    case ENCBINARY:
+      break;
+    default:
+      MM_LOG ("Ignoring nested encoding of multipart contents",PARSE);
+    }
+				/* remember if digest */
+    f = !strcmp (body->subtype,"DIGEST");
+				/* find cookie */
+    for (s1 = NIL,param = body->parameter; param && !s1; param = param->next)
+      if (!strcmp (param->attribute,"BOUNDARY")) s1 = param->value;
+    if (!s1) s1 = "-";		/* yucky default */
+    j = strlen (s1) + 2;	/* length of cookie and header */
+    c = '\012';			/* initially at beginning of line */
+
+    while (i > j) {		/* examine data */
+      if (m = GETPOS (bs)) m--;	/* get position in front of character */
+      switch (c) {		/* examine each line */
+      case '\015':		/* handle CRLF form */
+	if (CHR (bs) == '\012'){/* following LF? */
+	  c = SNX (bs); i--;	/* yes, slurp it */
+	}
+      case '\012':		/* at start of a line, start with -- ? */
+	if (!(i && i-- && ((c = SNX (bs)) == '-') && i-- &&
+	      ((c = SNX (bs)) == '-'))) break;
+				/* see if cookie matches */
+	if (k = j - 2) for (s = s1; i-- && *s++ == (c = SNX (bs)) && --k;);
+	if (k) break;		/* strings didn't match if non-zero */
+				/* terminating delimiter? */
+	if ((c = ((i && i--) ? (SNX (bs)) : '\012')) == '-') {
+	  if ((i && i--) && ((c = SNX (bs)) == '-') &&
+	      ((i && i--) ? (((c = SNX (bs)) == '\015') || (c=='\012')):T)) {
+				/* if have a final part calculate its size */
+	    if (part) part->body.mime.text.size =
+	      (m > part->body.mime.offset) ? (m - part->body.mime.offset) :0;
+	    part = NIL; i = 1;	/* terminate scan */
+	  }
+	  break;
+	}
+				/* swallow trailing whitespace */
+	while ((c == ' ') || (c == '\t'))
+	  c = ((i && i--) ? (SNX (bs)) : '\012');
+	switch (c) {		/* need newline after all of it */
+	case '\015':		/* handle CRLF form */
+	  if (i && CHR (bs) == '\012') {
+	    c = SNX (bs); i--;/* yes, slurp it */
+	  }
+	case '\012':		/* new line */
+	  if (part) {		/* calculate size of previous */
+	    part->body.mime.text.size =
+	      (m > part->body.mime.offset) ? (m-part->body.mime.offset) : 0;
+	    /* instantiate next */
+	    part = part->next = mail_newbody_part ();
+	  }			/* otherwise start new list */
+	  else part = body->nested.part = mail_newbody_part ();
+				/* digest has a different default */
+	  if (f) part->body.type = TYPEMESSAGE;
+				/* note offset from main body */
+	  part->body.mime.offset = GETPOS (bs);
+	  break;
+	default:		/* whatever it was it wasn't valid */
+	  break;
+	}
+	break;
+      default:			/* not at a line */
+	c = SNX (bs); i--;	/* get next character */
+	break;
+      }
+    }
+
+				/* calculate size of any final part */
+    if (part) part->body.mime.text.size = i +
+      ((GETPOS(bs) > part->body.mime.offset) ?
+       (GETPOS(bs) - part->body.mime.offset) : 0);
+				/* make a scratch buffer */
+    s1 = (char *) fs_get ((size_t) (k = MAILTMPLEN));
+				/* in case empty multipart */
+    if (!body->nested.part) body->nested.part = mail_newbody_part ();
+				/* parse non-empty body parts */
+    for (part = body->nested.part; part; part = part->next) {
+				/* part non-empty (header and/or content)? */
+      if (i = part->body.mime.text.size) {
+				/* move to that part of the body */
+	SETPOS (bs,part->body.mime.offset);
+				/* until end of header */
+	while (i && ((c = CHR (bs)) != '\015') && (c != '\012')) {
+				/* collect text until logical end of line */
+	  for (j = 0,c = ' '; c; ) {
+				/* make sure buffer big enough */
+	    if (j > (k - 10)) fs_resize ((void **) &s1,k += MAILTMPLEN);
+	    switch (c1 = SNX (bs)) {
+	    case '\015':	/* return */
+	      if (i && (CHR (bs) == '\012')) {
+		c1 = SNX (bs);	/* eat any LF following */
+		i--;
+	      }
+	    case '\012':	/* newline, possible end of logical line */
+				/* tie off unless continuation */
+	      if (!i || ((CHR (bs) != ' ') && (CHR (bs) != '\t')))
+		s1[j] = c = '\0';
+	      break;
+	    case '\t':		/* tab */
+	    case ' ':		/* insert whitespace if not already there */
+	      if (c != ' ') s1[j++] = c = ' ';
+	      break;
+	    default:		/* all other characters */
+	      s1[j++] = c = c1;	/* insert the character into the line */
+	      break;
+	    }
+				/* end of data ties off the header */
+	    if (!i || !--i) s1[j++] = c = '\0';
+	  }
+
+				/* find header item type */
+	  if (((s1[0] == 'C') || (s1[0] == 'c')) &&
+	      ((s1[1] == 'O') || (s1[1] == 'o')) &&
+	      ((s1[2] == 'N') || (s1[2] == 'n')) &&
+	      ((s1[3] == 'T') || (s1[3] == 't')) &&
+	      ((s1[4] == 'E') || (s1[4] == 'e')) &&
+	      ((s1[5] == 'N') || (s1[5] == 'n')) &&
+	      ((s1[6] == 'T') || (s1[6] == 't')) &&
+	      (s1[7] == '-') && (s = strchr (s1+8,':'))) {
+				/* tie off and flush whitespace */
+	    for (*s++ = '\0'; *s == ' '; s++);
+				/* parse the header */
+	    rfc822_parse_content_header (&part->body,ucase (s1+8),s);
+	  }
+	}
+				/* skip header trailing (CR)LF */
+	if (i && (CHR (bs) =='\015')) {i--; c1 = SNX (bs);}
+	if (i && (CHR (bs) =='\012')) {i--; c1 = SNX (bs);}
+	j = bs->size;		/* save upper level size */
+				/* set offset for next level, fake size to i */
+	bs->size = GETPOS (bs) + i;
+	part->body.mime.text.size -= i;
+				/* now parse it */
+	rfc822_parse_content (&part->body,bs,h,depth+1,flags);
+	bs->size = j;		/* restore current level size */
+      }
+      else {			/* zero-length part, use default subtype */
+	part->body.subtype = cpystr (rfc822_default_subtype (part->body.type));
+				/* see if anything else special to do */
+	switch (part->body.type) {
+	case TYPETEXT:		/* text content */
+				/* default parameters */
+	  if (!part->body.parameter) {
+	    part->body.parameter = mail_newbody_parameter ();
+	    part->body.parameter->attribute = cpystr ("CHARSET");
+				/* only assume US-ASCII if 7BIT */
+	    part->body.parameter->value =
+	      cpystr ((part->body.encoding == ENC7BIT) ?
+		      "US-ASCII" : "X-UNKNOWN");
+	  }
+	  break;
+	case TYPEMESSAGE:	/* encapsulated message in digest */
+	  part->body.nested.msg = mail_newmsg ();
+	  break;
+	default:
+	  break;
+	}
+      }
+    }
+    fs_give ((void **) &s1);	/* finished with scratch buffer */
+    break;
+  default:			/* nothing special to do in any other case */
+    break;
+  }
+}
+
+/* Parse RFC 2822 body content header
+ * Accepts: body to write to
+ *	    possible content name
+ *	    remainder of header
+ */
+
+void rfc822_parse_content_header (BODY *body,char *name,char *s)
+{
+  char c,*t,tmp[MAILTMPLEN];
+  long i;
+  STRINGLIST *stl;
+  rfc822_skipws (&s);		/* skip leading comments */
+				/* flush whitespace */
+  if (t = strchr (name,' ')) *t = '\0';
+  switch (*name) {		/* see what kind of content */
+  case 'I':			/* possible Content-ID */
+    if (!(strcmp (name+1,"D") || body->id)) body->id = cpystr (s);
+    break;
+  case 'D':			/* possible Content-Description */
+    if (!(strcmp (name+1,"ESCRIPTION") || body->description))
+      body->description = cpystr (s);
+    if (!(strcmp (name+1,"ISPOSITION") || body->disposition.type)) {
+				/* get type word */
+      if (!(name = rfc822_parse_word (s,tspecials))) break;
+      c = *name;		/* remember delimiter */
+      *name = '\0';		/* tie off type */
+      body->disposition.type = ucase (cpystr (s));
+      *name = c;		/* restore delimiter */
+      rfc822_skipws (&name);	/* skip whitespace */
+      rfc822_parse_parameter (&body->disposition.parameter,name);
+    }
+    break;
+  case 'L':			/* possible Content-Language */
+    if (!(strcmp (name+1,"ANGUAGE") || body->language)) {
+      stl = NIL;		/* process languages */
+      while (s && (name = rfc822_parse_word (s,tspecials))) {
+	c = *name;		/* save delimiter */
+	*name = '\0';		/* tie off subtype */
+	if (stl) stl = stl->next = mail_newstringlist ();
+	else stl = body->language = mail_newstringlist ();
+	stl->text.data = (unsigned char *) ucase (cpystr (s));
+	stl->text.size = strlen ((char *) stl->text.data);
+	*name = c;		/* restore delimiter */
+	rfc822_skipws (&name);	/* skip whitespace */
+	if (*name == ',') {	/* any more languages? */
+	  s = ++name;		/* advance to it them */
+	  rfc822_skipws (&s);
+	}
+	else s = NIL;		/* bogus or end of list */
+      }
+    }
+    else if (!(strcmp (name+1,"OCATION") || body->location))
+      body->location = cpystr (s);
+    break;
+  case 'M':			/* possible Content-MD5 */
+    if (!(strcmp (name+1,"D5") || body->md5)) body->md5 = cpystr (s);
+    break;
+
+  case 'T':			/* possible Content-Type/Transfer-Encoding */
+    if (!(strcmp (name+1,"YPE") || body->subtype || body->parameter)) {
+				/* get type word */
+      if (!(name = rfc822_parse_word (s,tspecials))) break;
+      c = *name;		/* remember delimiter */
+      *name = '\0';		/* tie off type */
+				/* search for body type */
+      for (i = 0,s = rfc822_cpy (s);
+	   (i <= TYPEMAX) && body_types[i] &&
+	     compare_cstring (s,body_types[i]); i++);
+      if (i > TYPEMAX) {	/* fell off end of loop? */
+	body->type = TYPEOTHER;	/* coerce to X-UNKNOWN */
+	sprintf (tmp,"MIME type table overflow: %.100s",s);
+	MM_LOG (tmp,PARSE);
+      }
+      else {			/* record body type index */
+	body->type = (unsigned short) i;
+				/* and name if new type */
+	if (body_types[body->type]) fs_give ((void **) &s);
+	else {			/* major MIME body type unknown to us */
+	  body_types[body->type] = ucase (s);
+	  sprintf (tmp,"Unknown MIME type: %.100s",s);
+	  MM_LOG (tmp,PARSE);
+	}
+      }
+      *name = c;		/* restore delimiter */
+      rfc822_skipws (&name);	/* skip whitespace */
+      if ((*name == '/') &&	/* subtype? */
+	  (name = rfc822_parse_word ((s = ++name),tspecials))) {
+	c = *name;		/* save delimiter */
+	*name = '\0';		/* tie off subtype */
+	rfc822_skipws (&s);	/* copy subtype */
+	if (s) body->subtype = ucase (rfc822_cpy (s));
+	*name = c;		/* restore delimiter */
+	rfc822_skipws (&name);	/* skip whitespace */
+      }
+      else if (!name) {		/* no subtype, was a subtype delimiter? */
+	name = s;		/* barf, restore pointer */
+	rfc822_skipws (&name);	/* skip leading whitespace */
+      }
+      rfc822_parse_parameter (&body->parameter,name);
+    }
+
+    else if (!strcmp (name+1,"RANSFER-ENCODING")) {
+      if (!(name = rfc822_parse_word (s,tspecials))) break;
+      c = *name;		/* remember delimiter */
+      *name = '\0';		/* tie off encoding */
+				/* search for body encoding */      
+      for (i = 0,s = rfc822_cpy (s);
+	   (i <= ENCMAX) && body_encodings[i] &&
+	     compare_cstring (s,body_encodings[i]); i++);
+      if (i > ENCMAX) {		/* fell off end of loop? */
+	body->encoding = ENCOTHER;
+	sprintf (tmp,"MIME encoding table overflow: %.100s",s);
+	MM_LOG (tmp,PARSE);
+      }
+      else {			/* record body encoding index */
+	body->encoding = (unsigned short) i;
+				/* and name if new encoding */
+	if (body_encodings[body->encoding]) fs_give ((void **) &s);
+	else {
+	  body_encodings[body->encoding] = ucase (s);
+	  sprintf (tmp,"Unknown MIME transfer encoding: %.100s",s);
+	  MM_LOG (tmp,PARSE);
+	}
+      }
+      *name = c;		/* restore delimiter */
+      /* ??check for cruft here?? */
+    }
+    break;
+  default:			/* otherwise unknown */
+    break;
+  }
+}
+
+/* Parse RFC 2822 body parameter list
+ * Accepts: parameter list to write to
+ *	    text of list
+ */
+
+void rfc822_parse_parameter (PARAMETER **par,char *text)
+{
+  char c,*s,tmp[MAILTMPLEN];
+  PARAMETER *param = NIL;
+				/* parameter list? */
+  while (text && (*text == ';') &&
+	 (text = rfc822_parse_word ((s = ++text),tspecials))) {
+    c = *text;			/* remember delimiter */
+    *text = '\0';		/* tie off attribute name */
+    rfc822_skipws (&s);		/* skip leading attribute whitespace */
+    if (!*s) *text = c;		/* must have an attribute name */
+    else {			/* instantiate a new parameter */
+      if (*par) param = param->next = mail_newbody_parameter ();
+      else param = *par = mail_newbody_parameter ();
+      param->attribute = ucase (cpystr (s));
+      *text = c;		/* restore delimiter */
+      rfc822_skipws (&text);	/* skip whitespace before equal sign */
+      if ((*text == '=') &&	/* make sure have value */
+	  (text = rfc822_parse_word ((s = ++text),tspecials))) {
+	c = *text;		/* remember delimiter */
+	*text = '\0';		/* tie off value */
+	rfc822_skipws (&s);	/* skip leading value whitespace */
+	if (*s) param->value = rfc822_cpy (s);
+	*text = c;		/* restore delimiter */
+	rfc822_skipws (&text);
+      }
+      if (!param->value) {	/* value not found? */
+	param->value = cpystr ("MISSING_PARAMETER_VALUE");
+	sprintf (tmp,"Missing parameter value: %.80s",param->attribute);
+	MM_LOG (tmp,PARSE);
+      }
+    }
+  }
+				/* string not present */
+  if (!text) MM_LOG ("Missing parameter",PARSE);
+  else if (*text) {		/* must be end of poop */
+    sprintf (tmp,"Unexpected characters at end of parameters: %.80s",text);
+    MM_LOG (tmp,PARSE);
+  }
+}
+
+/* Parse RFC 2822 address list
+ * Accepts: address list to write to
+ *	    input string
+ *	    default host name
+ */
+
+void rfc822_parse_adrlist (ADDRESS **lst,char *string,char *host)
+{
+  int c;
+  char *s,tmp[MAILTMPLEN];
+  ADDRESS *last = *lst;
+  ADDRESS *adr;
+  if (!string) return;		/* no string */
+  rfc822_skipws (&string);	/* skip leading WS */
+  if (!*string) return;		/* empty string */
+				/* run to tail of list */
+  if (last) while (last->next) last = last->next;
+  while (string) {		/* loop until string exhausted */
+    while (*string == ',') {	/* RFC 822 allowed null addresses!! */
+      ++string;			/* skip the comma */
+      rfc822_skipws (&string);	/* and any leading WS */
+    }
+    if (!*string) string = NIL;	/* punt if ran out of string */
+				/* got an address? */
+    else if (adr = rfc822_parse_address (lst,last,&string,host,0)) {
+      last = adr;		/* new tail address */
+      if (string) {		/* analyze what follows */
+	rfc822_skipws (&string);
+	switch (c = *(unsigned char *) string) {
+	case ',':		/* comma? */
+	  ++string;		/* then another address follows */
+	  break;
+	default:
+	  s = isalnum (c) ? "Must use comma to separate addresses: %.80s" :
+	    "Unexpected characters at end of address: %.80s";
+	  sprintf (tmp,s,string);
+	  MM_LOG (tmp,PARSE);
+	  last = last->next = mail_newaddr ();
+	  last->mailbox = cpystr ("UNEXPECTED_DATA_AFTER_ADDRESS");
+	  last->host = cpystr (errhst);
+				/* falls through */
+	case '\0':		/* null-specified address? */
+	  string = NIL;		/* punt remainder of parse */
+	  break;
+	}
+      }
+    }
+    else if (string) {		/* bad mailbox */
+      rfc822_skipws (&string);	/* skip WS */
+      if (!*string) strcpy (tmp,"Missing address after comma");
+      else sprintf (tmp,"Invalid mailbox list: %.80s",string);
+      MM_LOG (tmp,PARSE);
+      string = NIL;
+      (adr = mail_newaddr ())->mailbox = cpystr ("INVALID_ADDRESS");
+      adr->host = cpystr (errhst);
+      if (last) last = last->next = adr;
+      else *lst = last = adr;
+      break;
+    }
+  }
+}
+
+/* Parse RFC 2822 address
+ * Accepts: address list to write to
+ *	    tail of address list
+ *	    pointer to input string
+ *	    default host name
+ *	    group nesting depth
+ * Returns: new list tail
+ */
+
+ADDRESS *rfc822_parse_address (ADDRESS **lst,ADDRESS *last,char **string,
+			       char *defaulthost,unsigned long depth)
+{
+  ADDRESS *adr;
+  if (!*string) return NIL;	/* no string */
+  rfc822_skipws (string);	/* skip leading WS */
+  if (!**string) return NIL;	/* empty string */
+  if (adr = rfc822_parse_group (lst,last,string,defaulthost,depth)) last = adr;
+				/* got an address? */
+  else if (adr = rfc822_parse_mailbox (string,defaulthost)) {
+    if (!*lst) *lst = adr;	/* yes, first time through? */
+    else last->next = adr;	/* no, append to the list */
+				/* set for subsequent linking */
+    for (last = adr; last->next; last = last->next);
+  }
+  else if (*string) return NIL;
+  return last;
+}
+
+/* Parse RFC 2822 group
+ * Accepts: address list to write to
+ *	    pointer to tail of address list
+ *	    pointer to input string
+ *	    default host name
+ *	    group nesting depth
+ */
+
+ADDRESS *rfc822_parse_group (ADDRESS **lst,ADDRESS *last,char **string,
+			     char *defaulthost,unsigned long depth)
+{
+  char tmp[MAILTMPLEN];
+  char *p,*s;
+  ADDRESS *adr;
+  if (depth > MAXGROUPDEPTH) {	/* excessively deep recursion? */
+    MM_LOG ("Ignoring excessively deep group recursion",PARSE);
+    return NIL;			/* probably abusive */
+  }
+  if (!*string) return NIL;	/* no string */
+  rfc822_skipws (string);	/* skip leading WS */
+  if (!**string ||		/* trailing whitespace or not group */
+      ((*(p = *string) != ':') && !(p = rfc822_parse_phrase (*string))))
+    return NIL;
+  s = p;			/* end of candidate phrase */
+  rfc822_skipws (&s);		/* find delimiter */
+  if (*s != ':') return NIL;	/* not really a group */
+  *p = '\0';			/* tie off group name */
+  p = ++s;			/* continue after the delimiter */
+  rfc822_skipws (&p);		/* skip subsequent whitespace */
+				/* write as address */
+  (adr = mail_newaddr ())->mailbox = rfc822_cpy (*string);
+  if (!*lst) *lst = adr;	/* first time through? */
+  else last->next = adr;	/* no, append to the list */
+  last = adr;			/* set for subsequent linking */
+  *string = p;			/* continue after this point */
+  while (*string && **string && (**string != ';')) {
+    if (adr = rfc822_parse_address (lst,last,string,defaulthost,depth+1)) {
+      last = adr;		/* new tail address */
+      if (*string) {		/* anything more? */
+	rfc822_skipws (string);	/* skip whitespace */
+	switch (**string) {	/* see what follows */
+	case ',':		/* another address? */
+	  ++*string;		/* yes, skip past the comma */
+	case ';':		/* end of group? */
+	case '\0':		/* end of string */
+	  break;
+	default:
+	  sprintf (tmp,"Unexpected characters after address in group: %.80s",
+		   *string);
+	  MM_LOG (tmp,PARSE);
+	  *string = NIL;	/* cancel remainder of parse */
+	  last = last->next = mail_newaddr ();
+	  last->mailbox = cpystr ("UNEXPECTED_DATA_AFTER_ADDRESS_IN_GROUP");
+	  last->host = cpystr (errhst);
+	}
+      }
+    }
+    else {			/* bogon */
+      sprintf (tmp,"Invalid group mailbox list: %.80s",*string);
+      MM_LOG (tmp,PARSE);
+      *string = NIL;		/* cancel remainder of parse */
+      (adr = mail_newaddr ())->mailbox = cpystr ("INVALID_ADDRESS_IN_GROUP");
+      adr->host = cpystr (errhst);
+      last = last->next = adr;
+    }
+  }
+  if (*string) {		/* skip close delimiter */
+    if (**string == ';') ++*string;
+    rfc822_skipws (string);
+  }
+				/* append end of address mark to the list */
+  last->next = (adr = mail_newaddr ());
+  last = adr;			/* set for subsequent linking */
+  return last;			/* return the tail */
+}
+
+/* Parse RFC 2822 mailbox
+ * Accepts: pointer to string pointer
+ *	    default host
+ * Returns: address list
+ *
+ * Updates string pointer
+ */
+
+ADDRESS *rfc822_parse_mailbox (char **string,char *defaulthost)
+{
+  ADDRESS *adr = NIL;
+  char *s,*end;
+  parsephrase_t pp = (parsephrase_t) mail_parameters (NIL,GET_PARSEPHRASE,NIL);
+  if (!*string) return NIL;	/* no string */
+  rfc822_skipws (string);	/* flush leading whitespace */
+  if (!**string) return NIL;	/* empty string */
+  if (*(s = *string) == '<') 	/* note start, handle case of phraseless RA */
+    adr = rfc822_parse_routeaddr (s,string,defaulthost);
+				/* otherwise, expect at least one word */
+  else if (end = rfc822_parse_phrase (s)) {
+    if ((adr = rfc822_parse_routeaddr (end,string,defaulthost))) {
+				/* phrase is a personal name */
+      if (adr->personal) fs_give ((void **) &adr->personal);
+      *end = '\0';		/* tie off phrase */
+      adr->personal = rfc822_cpy (s);
+    }
+				/* call external phraseparser if phrase only */
+    else if (pp && rfc822_phraseonly (end) &&
+	     (adr = (*pp) (s,end,defaulthost))) {
+      *string = end;		/* update parse pointer */
+      rfc822_skipws (string);	/* skip WS in the normal way */
+    }
+    else adr = rfc822_parse_addrspec (s,string,defaulthost);
+  }
+  return adr;			/* return the address */
+}
+
+
+/* Check if address is a phrase only
+ * Accepts: pointer to end of phrase
+ * Returns: T if phrase only, else NIL;
+ */
+
+long rfc822_phraseonly (char *end)
+{
+  while (*end == ' ') ++end;	/* call rfc822_skipws() instead?? */
+  switch (*end) {
+  case '\0': case ',': case ';':
+    return LONGT;		/* is a phrase only */
+  }
+  return NIL;			/* something other than phase is here */
+}
+
+/* Parse RFC 2822 route-address
+ * Accepts: string pointer
+ *	    pointer to string pointer to update
+ * Returns: address
+ *
+ * Updates string pointer
+ */
+
+ADDRESS *rfc822_parse_routeaddr (char *string,char **ret,char *defaulthost)
+{
+  char tmp[MAILTMPLEN];
+  ADDRESS *adr;
+  char *s,*t,*adl;
+  size_t adllen,i;
+  if (!string) return NIL;
+  rfc822_skipws (&string);	/* flush leading whitespace */
+				/* must start with open broket */
+  if (*string != '<') return NIL;
+  t = ++string;			/* see if A-D-L there */
+  rfc822_skipws (&t);		/* flush leading whitespace */
+  for (adl = NIL,adllen = 0;	/* parse possible A-D-L */
+       (*t == '@') && (s = rfc822_parse_domain (t+1,&t));) {
+    i = strlen (s) + 2;		/* @ plus domain plus delimiter or NUL */
+    if (adl) {			/* have existing A-D-L? */
+      fs_resize ((void **) &adl,adllen + i);
+      sprintf (adl + adllen - 1,",@%s",s);
+    }
+				/* write initial A-D-L */
+    else sprintf (adl = (char *) fs_get (i),"@%s",s);
+    adllen += i;		/* new A-D-L length */
+    fs_give ((void **) &s);	/* don't need domain any more */
+    rfc822_skipws (&t);		/* skip WS */
+    if (*t != ',') break;	/* put if not comma */
+    t++;			/* skip the comma */
+    rfc822_skipws (&t);		/* skip WS */
+  }
+  if (adl) {			/* got an A-D-L? */
+    if (*t != ':') {		/* make sure syntax good */
+      sprintf (tmp,"Unterminated at-domain-list: %.80s%.80s",adl,t);
+      MM_LOG (tmp,PARSE);
+    }
+    else string = ++t;		/* continue parse from this point */
+  }
+
+				/* parse address spec */
+  if (!(adr = rfc822_parse_addrspec (string,ret,defaulthost))) {
+    if (adl) fs_give ((void **) &adl);
+    return NIL;
+  }
+  if (adl) adr->adl = adl;	/* have an A-D-L? */
+  if (*ret) if (**ret == '>') {	/* make sure terminated OK */
+    ++*ret;			/* skip past the broket */
+    rfc822_skipws (ret);	/* flush trailing WS */
+    if (!**ret) *ret = NIL;	/* wipe pointer if at end of string */
+    return adr;			/* return the address */
+  }
+  sprintf (tmp,"Unterminated mailbox: %.80s@%.80s",adr->mailbox,
+	   *adr->host == '@' ? "<null>" : adr->host);
+  MM_LOG (tmp,PARSE);
+  adr->next = mail_newaddr ();
+  adr->next->mailbox = cpystr ("MISSING_MAILBOX_TERMINATOR");
+  adr->next->host = cpystr (errhst);
+  return adr;			/* return the address */
+}
+
+/* Parse RFC 2822 address-spec
+ * Accepts: string pointer
+ *	    pointer to string pointer to update
+ *	    default host
+ * Returns: address
+ *
+ * Updates string pointer
+ */
+
+ADDRESS *rfc822_parse_addrspec (char *string,char **ret,char *defaulthost)
+{
+  ADDRESS *adr;
+  char c,*s,*t,*v,*end;
+  if (!string) return NIL;	/* no string */
+  rfc822_skipws (&string);	/* flush leading whitespace */
+  if (!*string) return NIL;	/* empty string */
+				/* find end of mailbox */
+  if (!(t = rfc822_parse_word (string,wspecials))) return NIL;
+  adr = mail_newaddr ();	/* create address block */
+  c = *t;			/* remember delimiter */
+  *t = '\0';			/* tie off mailbox */
+				/* copy mailbox */
+  adr->mailbox = rfc822_cpy (string);
+  *t = c;			/* restore delimiter */
+  end = t;			/* remember end of mailbox */
+  rfc822_skipws (&t);		/* skip whitespace */
+  while (*t == '.') {		/* some cretin taking RFC 822 too seriously? */
+    string = ++t;		/* skip past the dot and any WS */
+    rfc822_skipws (&string);
+				/* get next word of mailbox */
+    if (t = rfc822_parse_word (string,wspecials)) {
+      end = t;			/* remember new end of mailbox */
+      c = *t;			/* remember delimiter */
+      *t = '\0';		/* tie off word */
+      s = rfc822_cpy (string);	/* copy successor part */
+      *t = c;			/* restore delimiter */
+				/* build new mailbox */
+      sprintf (v = (char *) fs_get (strlen (adr->mailbox) + strlen (s) + 2),
+	       "%s.%s",adr->mailbox,s);
+      fs_give ((void **) &adr->mailbox);
+      adr->mailbox = v;		/* new host name */
+      rfc822_skipws (&t);	/* skip WS after mailbox */
+    }
+    else {			/* barf */
+      MM_LOG ("Invalid mailbox part after .",PARSE);
+      break;
+    }
+  }
+  t = end;			/* remember delimiter in case no host */
+
+  rfc822_skipws (&end);		/* sniff ahead at what follows */
+#if RFC733			/* RFC 733 used "at" instead of "@" */
+  if (((*end == 'a') || (*end == 'A')) &&
+      ((end[1] == 't') || (end[1] == 'T')) &&
+      ((end[2] == ' ') || (end[2] == '\t') || (end[2] == '\015') ||
+       (end[2] == '\012') || (end[2] == '(')))
+    *++end = '@';
+#endif
+  if (*end != '@') end = t;	/* host name missing */
+				/* otherwise parse host name */
+  else if (!(adr->host = rfc822_parse_domain (++end,&end)))
+    adr->host = cpystr (errhst);
+				/* default host if missing */
+  if (!adr->host) adr->host = cpystr (defaulthost);
+				/* try person name in comments if missing */
+  if (end && !(adr->personal && *adr->personal)) {
+    while (*end == ' ') ++end;	/* see if we can find a person name here */
+    if ((*end == '(') && (s = rfc822_skip_comment (&end,LONGT)) && strlen (s))
+      adr->personal = rfc822_cpy (s);
+    rfc822_skipws (&end);	/* skip any other WS in the normal way */
+  }
+				/* set return to end pointer */
+  *ret = (end && *end) ? end : NIL;
+  return adr;			/* return the address we got */
+}
+
+/* Parse RFC 2822 domain
+ * Accepts: string pointer
+ *	    pointer to return end of domain
+ * Returns: domain name or NIL if failure
+ */
+
+char *rfc822_parse_domain (char *string,char **end)
+{
+  char *ret = NIL;
+  char c,*s,*t,*v;
+  rfc822_skipws (&string);	/* skip whitespace */
+  if (*string == '[') {		/* domain literal? */
+    if (!(*end = rfc822_parse_word (string + 1,"]\\")))
+      MM_LOG ("Empty domain literal",PARSE);
+    else if (**end != ']') MM_LOG ("Unterminated domain literal",PARSE);
+    else {
+      size_t len = ++*end - string;
+      strncpy (ret = (char *) fs_get (len + 1),string,len);
+      ret[len] = '\0';		/* tie off literal */
+    }
+  }
+				/* search for end of host */
+  else if (t = rfc822_parse_word (string,wspecials)) {
+    c = *t;			/* remember delimiter */
+    *t = '\0';			/* tie off host */
+    ret = rfc822_cpy (string);	/* copy host */
+    *t = c;			/* restore delimiter */
+    *end = t;			/* remember end of domain */
+    rfc822_skipws (&t);		/* skip WS after host */
+    while (*t == '.') {		/* some cretin taking RFC 822 too seriously? */
+      string = ++t;		/* skip past the dot and any WS */
+      rfc822_skipws (&string);
+      if (string = rfc822_parse_domain (string,&t)) {
+	*end = t;		/* remember new end of domain */
+	c = *t;			/* remember delimiter */
+	*t = '\0';		/* tie off host */
+	s = rfc822_cpy (string);/* copy successor part */
+	*t = c;			/* restore delimiter */
+				/* build new domain */
+	sprintf (v = (char *) fs_get (strlen (ret) + strlen (s) + 2),
+		 "%s.%s",ret,s);
+	fs_give ((void **) &ret);
+	ret = v;		/* new host name */
+	rfc822_skipws (&t);	/* skip WS after domain */
+      }
+      else {			/* barf */
+	MM_LOG ("Invalid domain part after .",PARSE);
+	break;
+      }
+    }
+  }
+  else MM_LOG ("Missing or invalid host name after @",PARSE);
+  return ret;
+}
+
+/* Parse RFC 2822 phrase
+ * Accepts: string pointer
+ * Returns: pointer to end of phrase
+ */
+
+char *rfc822_parse_phrase (char *s)
+{
+  char *curpos;
+  if (!s) return NIL;		/* no-op if no string */
+				/* find first word of phrase */
+  curpos = rfc822_parse_word (s,NIL);
+  if (!curpos) return NIL;	/* no words means no phrase */
+  if (!*curpos) return curpos;	/* check if string ends with word */
+  s = curpos;			/* sniff past the end of this word and WS */
+  rfc822_skipws (&s);		/* skip whitespace */
+				/* recurse to see if any more */
+  return (s = rfc822_parse_phrase (s)) ? s : curpos;
+}
+
+/* Parse RFC 2822 word
+ * Accepts: string pointer
+ *	    delimiter (or NIL for phrase word parsing)
+ * Returns: pointer to end of word
+ */
+
+char *rfc822_parse_word (char *s,const char *delimiters)
+{
+  char *st,*str;
+  if (!s) return NIL;		/* no string */
+  rfc822_skipws (&s);		/* flush leading whitespace */
+  if (!*s) return NIL;		/* empty string */
+  str = s;			/* hunt pointer for strpbrk */
+  while (T) {			/* look for delimiter, return if none */
+    if (!(st = strpbrk (str,delimiters ? delimiters : wspecials)))
+      return str + strlen (str);
+				/* ESC in phrase */
+    if (!delimiters && (*st == I2C_ESC)) {
+      str = ++st;		/* always skip past ESC */
+      switch (*st) {		/* special hack for RFC 1468 (ISO-2022-JP) */
+      case I2C_MULTI:		/* multi byte sequence */
+	switch (*++st) {
+	case I2CS_94x94_JIS_OLD:/* old JIS (1978) */
+	case I2CS_94x94_JIS_NEW:/* new JIS (1983) */
+	  str = ++st;		/* skip past the shift to JIS */
+	  while (st = strchr (st,I2C_ESC))
+	    if ((*++st == I2C_G0_94) && ((st[1] == I2CS_94_ASCII) ||
+					 (st[1] == I2CS_94_JIS_ROMAN) ||
+					 (st[1] == I2CS_94_JIS_BUGROM))) {
+	      str = st += 2;	/* skip past the shift back to ASCII */
+	      break;
+	    }
+				/* eats entire text if no shift back */
+	  if (!st || !*st) return str + strlen (str);
+	}
+	break;
+      case I2C_G0_94:		/* single byte sequence */
+	switch (st[1]) {
+	case I2CS_94_ASCII:	/* shift to ASCII */
+	case I2CS_94_JIS_ROMAN:	/* shift to JIS-Roman */
+	case I2CS_94_JIS_BUGROM:/* old buggy definition of JIS-Roman */
+	  str = st + 2;		/* skip past the shift */
+	  break;
+	}
+      }
+    }
+
+    else switch (*st) {		/* dispatch based on delimiter */
+    case '"':			/* quoted string */
+				/* look for close quote */
+      while (*++st != '"') switch (*st) {
+      case '\0':		/* unbalanced quoted string */
+	return NIL;		/* sick sick sick */
+      case '\\':		/* quoted character */
+	if (!*++st) return NIL;	/* skip the next character */
+      default:			/* ordinary character */
+	break;			/* no special action */
+      }
+      str = ++st;		/* continue parse */
+      break;
+    case '\\':			/* quoted character */
+      /* This is wrong; a quoted-pair can not be part of a word.  However,
+       * domain-literal is parsed as a word and quoted-pairs can be used
+       * *there*.  Either way, it's pretty pathological.
+       */
+      if (st[1]) {		/* not on NUL though... */
+	str = st + 2;		/* skip quoted character and go on */
+	break;
+      }
+    default:			/* found a word delimiter */
+      return (st == s) ? NIL : st;
+    }
+  }
+}
+
+/* Copy an RFC 2822 format string
+ * Accepts: string
+ * Returns: copy of string
+ */
+
+char *rfc822_cpy (char *src)
+{
+				/* copy and unquote */
+  return rfc822_quote (cpystr (src));
+}
+
+
+/* Unquote an RFC 2822 format string
+ * Accepts: string
+ * Returns: string
+ */
+
+char *rfc822_quote (char *src)
+{
+  char *ret = src;
+  if (strpbrk (src,"\\\"")) {	/* any quoting in string? */
+    char *dst = ret;
+    while (*src) {		/* copy string */
+      if (*src == '\"') src++;	/* skip double quote entirely */
+      else {
+	if (*src == '\\') src++;/* skip over single quote, copy next always */
+	*dst++ = *src++;	/* copy character */
+      }
+    }
+    *dst = '\0';		/* tie off string */
+  }
+  return ret;			/* return our string */
+}
+
+
+/* Copy address list
+ * Accepts: address list
+ * Returns: address list
+ */
+
+ADDRESS *rfc822_cpy_adr (ADDRESS *adr)
+{
+  ADDRESS *dadr;
+  ADDRESS *ret = NIL;
+  ADDRESS *prev = NIL;
+  while (adr) {			/* loop while there's still an MAP adr */
+    dadr = mail_newaddr ();	/* instantiate a new address */
+    if (!ret) ret = dadr;	/* note return */
+    if (prev) prev->next = dadr;/* tie on to the end of any previous */
+    dadr->personal = cpystr (adr->personal);
+    dadr->adl = cpystr (adr->adl);
+    dadr->mailbox = cpystr (adr->mailbox);
+    dadr->host = cpystr (adr->host);
+    prev = dadr;		/* this is now the previous */
+    adr = adr->next;		/* go to next address in list */
+  }
+  return (ret);			/* return the MTP address list */
+}
+
+/* Skips RFC 2822 whitespace
+ * Accepts: pointer to string pointer
+ */
+
+void rfc822_skipws (char **s)
+{
+  while (T) switch (**s) {
+  case ' ': case '\t': case '\015': case '\012':
+    ++*s;			/* skip all forms of LWSP */
+    break;
+  case '(':			/* start of comment */
+    if (rfc822_skip_comment (s,(long) NIL)) break;
+  default:
+    return;			/* end of whitespace */
+  }
+}
+
+
+/* Skips RFC 2822 comment
+ * Accepts: pointer to string pointer
+ *	    trim flag
+ * Returns: pointer to first non-blank character of comment
+ */
+
+char *rfc822_skip_comment (char **s,long trim)
+{
+  char *ret,tmp[MAILTMPLEN];
+  char *s1 = *s;
+  char *t = NIL;
+				/* skip past whitespace */
+  for (ret = ++s1; *ret == ' '; ret++);
+  do switch (*s1) {		/* get character of comment */
+  case '(':			/* nested comment? */
+    if (!rfc822_skip_comment (&s1,(long) NIL)) return NIL;
+    t = --s1;			/* last significant char at end of comment */
+    break;
+  case ')':			/* end of comment? */
+    *s = ++s1;			/* skip past end of comment */
+    if (trim) {			/* if level 0, must trim */
+      if (t) t[1] = '\0';	/* tie off comment string */
+      else *ret = '\0';		/* empty comment */
+    }
+    return ret;
+  case '\\':			/* quote next character? */
+    if (*++s1) {		/* next character non-null? */
+      t = s1;			/* update last significant character pointer */
+      break;			/* all OK */
+    }
+  case '\0':			/* end of string */
+    sprintf (tmp,"Unterminated comment: %.80s",*s);
+    MM_LOG (tmp,PARSE);
+    **s = '\0';			/* nuke duplicate messages in case reparse */
+    return NIL;			/* this is wierd if it happens */
+  case ' ':			/* whitespace isn't significant */
+    break;
+  default:			/* random character */
+    t = s1;			/* update last significant character pointer */
+    break;
+  } while (s1++);
+  return NIL;			/* impossible, but pacify lint et al */
+}
+
+/* Buffered output routines */
+
+
+/* Output character to buffer
+ * Accepts: buffer
+ *	    character to write
+ * Returns: T if success, NIL if error
+ */
+
+static long rfc822_output_char (RFC822BUFFER *buf,int c)
+{
+  if ((buf->cur == buf->end) && !rfc822_output_flush (buf)) return NIL;
+  *buf->cur++ = c;		/* add character, soutr buffer if full */
+  return (buf->cur == buf->end) ? rfc822_output_flush (buf) : LONGT;
+}
+
+
+/* Output data to buffer
+ * Accepts: buffer
+ *	    data to write
+ *	    size of data
+ * Returns: T if success, NIL if error
+ */
+
+static long rfc822_output_data (RFC822BUFFER *buf,char *string,long len)
+{
+  while (len) {			/* until request satified */
+    long i;
+    if (i = min (len,buf->end - buf->cur)) {
+      memcpy (buf->cur,string,i);
+      buf->cur += i;		/* blat data */
+      string += i;
+      len -= i;
+    }
+				/* soutr buffer now if full */
+    if ((len || (buf->cur == buf->end)) && !rfc822_output_flush (buf))
+      return NIL;
+  }
+  return LONGT;
+}
+
+/* Output string to buffer
+ * Accepts: buffer
+ *	    string to write
+ * Returns: T if success, NIL if error
+ */
+
+static long rfc822_output_string (RFC822BUFFER *buf,char *string)
+{
+  return rfc822_output_data (buf,string,strlen (string));
+}
+
+
+/* Flush buffer
+ * Accepts: buffer
+ *	    I/O routine
+ *	    stream for I/O routine
+ * Returns: T if success, NIL if error
+ */
+
+long rfc822_output_flush (RFC822BUFFER *buf)
+{
+  *buf->cur = '\0';		/* tie off buffer at this point */
+  return (*buf->f) (buf->s,buf->cur = buf->beg);
+}
+
+/* Message writing routines */
+
+
+/* Output RFC 822 message
+ * Accepts: temporary buffer as a SIZEDTEXT
+ *	    envelope
+ *	    body
+ *	    I/O routine
+ *	    stream for I/O routine
+ *	    non-zero if 8-bit output desired
+ * Returns: T if successful, NIL if failure
+ *
+ * This routine always uses standard specials for phrases and does not write
+ * bcc entries, since it is called from the SMTP and NNTP routines.  If you
+ * need to do something different you need to arm an rfc822outfull_t and/or
+ * rfc822out_t function.
+ */
+
+long rfc822_output_full (RFC822BUFFER *buf,ENVELOPE *env,BODY *body,long ok8)
+{
+  rfc822outfull_t r822of =
+    (rfc822outfull_t) mail_parameters (NIL,GET_RFC822OUTPUTFULL,NIL);
+  rfc822out_t r822o = (rfc822out_t) mail_parameters (NIL,GET_RFC822OUTPUT,NIL);
+				/* call external RFC 2822 output generator */
+  if (r822of) return (*r822of) (buf,env,body,ok8);
+  else if (r822o) return (*r822o) (buf->cur,env,body,buf->f,buf->s,ok8);
+				/* encode body as necessary */
+  if (ok8) rfc822_encode_body_8bit (env,body);
+  else rfc822_encode_body_7bit (env,body);
+				/* output header and body */
+  return rfc822_output_header (buf,env,body,NIL,NIL) &&
+    rfc822_output_text (buf,body) && rfc822_output_flush (buf);
+}
+
+/* Output RFC 822 header
+ * Accepts: buffer
+ *	    envelope
+ *	    body
+ *	    non-standard specials to be used for phrases if non-NIL
+ *	    flags (non-zero to include bcc
+ * Returns: T if success, NIL if failure
+ */
+
+long rfc822_output_header (RFC822BUFFER *buf,ENVELOPE *env,BODY *body,
+			   const char *specials,long flags)
+{
+  long i = env->remail ? strlen (env->remail) : 0;
+  return			/* write header */
+    (!i ||		      /* snip extra CRLF from remail header */
+     rfc822_output_data (buf,env->remail,
+			 ((i > 4) && (env->remail[i-4] == '\015')) ?
+			 i - 2 : i)) &&
+    rfc822_output_header_line (buf,"Newsgroups",i,env->newsgroups) &&
+    rfc822_output_header_line (buf,"Date",i,env->date) &&
+    rfc822_output_address_line (buf,"From",i,env->from,specials) &&
+    rfc822_output_address_line (buf,"Sender",i,env->sender,specials) &&
+    rfc822_output_address_line (buf,"Reply-To",i,env->reply_to,specials) &&
+    rfc822_output_header_line (buf,"Subject",i,env->subject) &&
+    ((env->bcc && !(env->to || env->cc)) ?
+     rfc822_output_string (buf,"To: undisclosed recipients: ;\015\012") :
+     LONGT) &&
+    rfc822_output_address_line (buf,"To",i,env->to,specials) &&
+    rfc822_output_address_line (buf,"cc",i,env->cc,specials) &&
+    (flags ? rfc822_output_address_line (buf,"bcc",i,env->bcc,specials) : T) &&
+    rfc822_output_header_line (buf,"In-Reply-To",i,env->in_reply_to) &&
+    rfc822_output_header_line (buf,"Message-ID",i,env->message_id) &&
+    rfc822_output_header_line (buf,"Followup-to",i,env->followup_to) &&
+    rfc822_output_header_line (buf,"References",i,env->references) &&
+    (env->remail || !body ||
+     (rfc822_output_string (buf,"MIME-Version: 1.0\015\012") &&
+      rfc822_output_body_header (buf,body))) &&
+				/* write terminating blank line */
+    rfc822_output_string (buf,"\015\012");
+}
+
+/* Output RFC 2822 header text line
+ * Accepts: buffer
+ *	    pointer to header type
+ *	    non-NIL if resending
+ *	    pointer to text
+ * Returns: T if success, NIL if failure
+ */
+
+long rfc822_output_header_line (RFC822BUFFER *buf,char *type,long resent,
+				char *text)
+{
+  return !text ||
+    ((resent ? rfc822_output_string (buf,resentprefix) : LONGT) &&
+     rfc822_output_string (buf,type) && rfc822_output_string (buf,": ") &&
+     rfc822_output_string (buf,text) && rfc822_output_string (buf,"\015\012"));
+}
+
+
+/* Output RFC 2822 header address line
+ * Accepts: buffer
+ *	    pointer to header type
+ *	    non-NIL if resending
+ *	    address(s) to interpret
+ *	    non-standard specials to be used for phrases if non-NIL
+ * Returns: T if success, NIL if failure
+ */
+
+long rfc822_output_address_line (RFC822BUFFER *buf,char *type,long resent,
+				 ADDRESS *adr,const char *specials)
+{
+  long pretty = strlen (type);
+  return !adr ||
+    ((resent ? rfc822_output_string (buf,resentprefix) : LONGT) &&
+     rfc822_output_data (buf,type,pretty) && rfc822_output_string (buf,": ") &&
+     rfc822_output_address_list (buf,adr,
+				 resent ? pretty + sizeof (RESENTPREFIX) - 1 :
+				 pretty,specials) &&
+     rfc822_output_string (buf,"\015\012"));
+}
+
+/* Output RFC 2822 address list
+ * Accepts: buffer
+ *	    pointer to address list
+ *	    non-zero if pretty-printing
+ *	    non-standard specials to be used for phrases if non-NIL
+ * Returns: T if success, NIL if failure
+ */
+
+long rfc822_output_address_list (RFC822BUFFER *buf,ADDRESS *adr,long pretty,
+				 const char *specials)
+{
+  long n;
+				/* default to rspecials */
+  if (!specials) specials = rspecials;
+  for (n = 0; adr; adr = adr->next) {
+    char *base = buf->cur;
+    if (adr->host) {		/* ordinary address? */
+      if (!(pretty && n)) {	/* suppress if pretty and in group */
+	if (			/* use phrase <route-addr> if phrase */
+#if RFC822
+	    adr->adl ||		/* or A-D-L */
+#endif
+	    (adr->personal && *adr->personal)) {
+	  if (!((adr->personal ? rfc822_output_cat (buf,adr->personal,
+						    rspecials) : LONGT) &&
+		rfc822_output_string (buf," <") &&
+		rfc822_output_address (buf,adr) &&
+		rfc822_output_string (buf,">"))) return NIL;
+	}
+	else if (!rfc822_output_address (buf,adr)) return NIL;
+	if (adr->next && adr->next->mailbox &&
+	    !rfc822_output_string (buf,", ")) return NIL;
+      }
+    }
+    else if (adr->mailbox) {	/* start of group? */
+				/* yes, write group */
+      if (!(rfc822_output_cat (buf,adr->mailbox,rspecials) &&
+	    rfc822_output_string (buf,": "))) return NIL;
+      ++n;			/* in a group now */
+    }
+    else if (n) {		/* must be end of group (but be paranoid) */
+      if (!rfc822_output_char (buf,';') ||
+	  ((!--n && adr->next && adr->next->mailbox) &&
+	   !rfc822_output_string (buf,", "))) return NIL;
+    }
+    if (pretty && adr->next &&	/* pretty printing? */
+	((pretty += ((buf->cur > base) ? buf->cur - base :
+		     (buf->end - base) + (buf->cur - buf->beg))) >= 78)) {
+      if (!(rfc822_output_string (buf,"\015\012") &&
+	    rfc822_output_string (buf,RFC822CONT))) return NIL;
+      base = buf->cur;	/* update base for pretty printing */
+      pretty = sizeof (RFC822CONT) - 1;
+    }
+  }
+  return LONGT;
+}
+
+/* Write RFC 2822 route-address to string
+ * Accepts: buffer
+ *	    pointer to single address
+ * Returns: T if success, NIL if failure
+ */
+
+long rfc822_output_address (RFC822BUFFER *buf,ADDRESS *adr)
+{
+  return !adr || !adr->host ||
+    (
+#if RFC822			/* old code with A-D-L support */
+     (!adr->adl || (rfc822_output_string (buf,adr->adl) &&
+		    rfc822_output_char (buf,':'))) &&
+#endif
+     rfc822_output_cat (buf,adr->mailbox,NIL) &&
+     ((*adr->host == '@') ||	/* unless null host (HIGHLY discouraged!) */
+      (rfc822_output_char (buf,'@') &&
+       rfc822_output_cat (buf,adr->host,NIL))));
+}
+
+
+/* Output RFC 2822 string with concatenation
+ * Accepts: buffer
+ *	    string to concatenate
+ *	    list of special characters or NIL for dot-atom format
+ * Returns: T if success, NIL if failure
+ */
+
+long rfc822_output_cat (RFC822BUFFER *buf,char *src,const char *specials)
+{
+  char *s;
+  if (!*src ||			/* empty string or any specials present? */
+      (specials ? (T && strpbrk (src,specials)) :
+       (strpbrk (src,wspecials) || (*src == '.') || strstr (src,"..") ||
+	(src[strlen (src) - 1] == '.')))) {
+				/* yes, write as quoted string*/
+    if (!rfc822_output_char (buf,'"')) return NIL;
+				/* embedded quote characters? */
+    for (; s = strpbrk (src,"\\\""); src = s + 1) {
+				/* yes, insert quoting */
+      if (!(rfc822_output_data (buf,src,s-src) &&
+	    rfc822_output_char (buf,'\\') &&
+	    rfc822_output_char (buf,*s))) return NIL;
+    }
+				/* return string and trailing quote*/
+    return rfc822_output_string (buf,src) && rfc822_output_char (buf,'"');
+  }
+				/* easy case */
+  return rfc822_output_string (buf,src);
+}
+
+/* Output MIME parameter list
+ * Accepts: buffer
+ *	    parameter list
+ * Returns: T if success, NIL if failure
+ */
+
+long rfc822_output_parameter (RFC822BUFFER *buf,PARAMETER *param)
+{
+  while (param) {
+    if (rfc822_output_string (buf,"; ") &&
+	rfc822_output_string (buf,param->attribute) &&
+	rfc822_output_char (buf,'=') &&
+	rfc822_output_cat (buf,param->value,tspecials)) param = param->next;
+    else return NIL;
+  }
+  return LONGT;
+}
+
+
+/* Output RFC 2822 stringlist
+ * Accepts: buffer
+ *	    stringlist
+ * Returns: T if success, NIL if failure
+ */
+
+long rfc822_output_stringlist (RFC822BUFFER *buf,STRINGLIST *stl)
+{
+  while (stl)
+    if (!rfc822_output_cat (buf,(char *) stl->text.data,tspecials) ||
+	((stl = stl->next) && !rfc822_output_string (buf,", ")))
+      return NIL;
+  return LONGT;
+}
+
+/* Output body content header
+ * Accepts: buffer
+ *	    body to interpret
+ * Returns: T if success, NIL if failure
+ */
+
+long rfc822_output_body_header (RFC822BUFFER *buf,BODY *body)
+{
+  return			/* type and subtype*/
+    rfc822_output_string (buf,"Content-Type: ") &&
+    rfc822_output_string (buf,body_types[body->type]) &&
+    rfc822_output_char (buf,'/') &&
+    rfc822_output_string (buf,body->subtype ? body->subtype :
+			  rfc822_default_subtype (body->type)) &&
+				/* parameters (w/ US-ASCII default */
+    (body->parameter ? rfc822_output_parameter (buf,body->parameter) :
+     ((body->type != TYPETEXT) ||
+      (rfc822_output_string (buf,"; CHARSET=") &&
+       rfc822_output_string (buf,(body->encoding == ENC7BIT) ?
+			     "US-ASCII" : "X-UNKNOWN")))) &&
+    (!body->encoding ||	    /* note: 7BIT never output as encoding! */
+     (rfc822_output_string (buf,"\015\012Content-Transfer-Encoding: ") &&
+      rfc822_output_string (buf,body_encodings[body->encoding]))) &&
+    (!body->id ||		/* identification */
+     (rfc822_output_string (buf,"\015\012Content-ID: ") &&
+      rfc822_output_string (buf,body->id))) &&
+    (!body->description ||	/* description */
+     (rfc822_output_string (buf,"\015\012Content-Description: ") &&
+      rfc822_output_string (buf,body->description))) &&
+    (!body->md5 ||		/* MD5 checksum */
+     (rfc822_output_string (buf,"\015\012Content-MD5: ") &&
+      rfc822_output_string (buf,body->md5))) &&
+    (!body->language ||		/* language */
+     (rfc822_output_string (buf,"\015\012Content-Language: ") &&
+      rfc822_output_stringlist (buf,body->language))) &&
+    (!body->location ||		/* location */
+     (rfc822_output_string (buf,"\015\012Content-Location: ") &&
+      rfc822_output_string (buf,body->location))) &&
+    (!body->disposition.type ||	/* disposition */
+     (rfc822_output_string (buf,"\015\012Content-Disposition: ") &&
+      rfc822_output_string (buf,body->disposition.type) &&
+      rfc822_output_parameter (buf,body->disposition.parameter))) &&
+    rfc822_output_string (buf,"\015\012");
+}
+
+/* Encode a body for 7BIT transmittal
+ * Accepts: envelope
+ *	    body
+ */
+
+void rfc822_encode_body_7bit (ENVELOPE *env,BODY *body)
+{
+  void *f;
+  PART *part;
+  PARAMETER **param;
+  if (body) switch (body->type) {
+  case TYPEMULTIPART:		/* multi-part */
+    for (param = &body->parameter;
+	 *param && strcmp ((*param)->attribute,"BOUNDARY");
+	 param = &(*param)->next);
+    if (!*param) {		/* cookie not set up yet? */
+      char tmp[MAILTMPLEN];	/* make cookie not in BASE64 or QUOTEPRINT*/
+      sprintf (tmp,"%lu-%lu-%lu=:%lu",(unsigned long) gethostid (),
+	       (unsigned long) random (),(unsigned long) time (0),
+	       (unsigned long) getpid ());
+      (*param) = mail_newbody_parameter ();
+      (*param)->attribute = cpystr ("BOUNDARY");
+      (*param)->value = cpystr (tmp);
+    }
+    part = body->nested.part;	/* encode body parts */
+    do rfc822_encode_body_7bit (env,&part->body);
+    while (part = part->next);	/* until done */
+    break;
+  case TYPEMESSAGE:		/* encapsulated message */
+    switch (body->encoding) {
+    case ENC7BIT:
+      break;
+    case ENC8BIT:
+      MM_LOG ("8-bit included message in 7-bit message body",PARSE);
+      break;
+    case ENCBINARY:
+      MM_LOG ("Binary included message in 7-bit message body",PARSE);
+      break;
+    default:
+      fatal ("Invalid rfc822_encode_body_7bit message encoding");
+    }
+    break;			/* can't change encoding */
+  default:			/* all else has some encoding */
+    switch (body->encoding) {
+    case ENC8BIT:		/* encode 8BIT into QUOTED-PRINTABLE */
+				/* remember old 8-bit contents */
+      f = (void *) body->contents.text.data;
+      body->contents.text.data =
+	rfc822_8bit (body->contents.text.data,
+		     body->contents.text.size,&body->contents.text.size);
+      body->encoding = ENCQUOTEDPRINTABLE;
+      fs_give (&f);		/* flush old binary contents */
+      break;
+    case ENCBINARY:		/* encode binary into BASE64 */
+				/* remember old binary contents */
+      f = (void *) body->contents.text.data;
+      body->contents.text.data =
+	rfc822_binary ((void *) body->contents.text.data,
+		       body->contents.text.size,&body->contents.text.size);
+      body->encoding = ENCBASE64;
+      fs_give (&f);		/* flush old binary contents */
+    default:			/* otherwise OK */
+      break;
+    }
+    break;
+  }
+}
+
+/* Encode a body for 8BIT transmittal
+ * Accepts: envelope
+ *	    body
+ */
+
+void rfc822_encode_body_8bit (ENVELOPE *env,BODY *body)
+{
+  void *f;
+  PART *part;
+  PARAMETER **param;
+  if (body) switch (body->type) {
+  case TYPEMULTIPART:		/* multi-part */
+    for (param = &body->parameter;
+	 *param && strcmp ((*param)->attribute,"BOUNDARY");
+	 param = &(*param)->next);
+    if (!*param) {		/* cookie not set up yet? */
+      char tmp[MAILTMPLEN];	/* make cookie not in BASE64 or QUOTEPRINT*/
+      sprintf (tmp,"%lu-%lu-%lu=:%lu",(unsigned long) gethostid (),
+	       (unsigned long) random (),(unsigned long) time (0),
+	       (unsigned long) getpid ());
+      (*param) = mail_newbody_parameter ();
+      (*param)->attribute = cpystr ("BOUNDARY");
+      (*param)->value = cpystr (tmp);
+    }
+    part = body->nested.part;	/* encode body parts */
+    do rfc822_encode_body_8bit (env,&part->body);
+    while (part = part->next);	/* until done */
+    break;
+  case TYPEMESSAGE:		/* encapsulated message */
+    switch (body->encoding) {
+    case ENC7BIT:
+    case ENC8BIT:
+      break;
+    case ENCBINARY:
+      MM_LOG ("Binary included message in 8-bit message body",PARSE);
+      break;
+    default:
+      fatal ("Invalid rfc822_encode_body_7bit message encoding");
+    }
+    break;			/* can't change encoding */
+  default:			/* other type, encode binary into BASE64 */
+    if (body->encoding == ENCBINARY) {
+				/* remember old binary contents */
+      f = (void *) body->contents.text.data;
+      body->contents.text.data =
+	rfc822_binary ((void *) body->contents.text.data,
+		       body->contents.text.size,&body->contents.text.size);
+      body->encoding = ENCBASE64;
+      fs_give (&f);		/* flush old binary contents */
+    }
+    break;
+  }
+}
+
+/* Output RFC 822 text
+ * Accepts: buffer
+ *	    body
+ * Returns: T if successful, NIL if failure
+ */
+
+long rfc822_output_text (RFC822BUFFER *buf,BODY *body)
+{
+				/* MULTIPART gets special handling */
+  if (body->type == TYPEMULTIPART) {
+    char *cookie,tmp[MAILTMPLEN];
+    PARAMETER *param;
+    PART *part;
+				/* find cookie */
+    for (param = body->parameter; param && strcmp (param->attribute,"BOUNDARY");
+	 param = param->next);
+    if (param) cookie = param->value;
+    else {		  /* make cookie not in BASE64 or QUOTEPRINT*/
+      sprintf (cookie = tmp,"%lu-%lu-%lu=:%lu",(unsigned long) gethostid (),
+	       (unsigned long) random (),(unsigned long) time (0),
+	       (unsigned long) getpid ());
+      (param = mail_newbody_parameter ())->attribute = cpystr ("BOUNDARY");
+      param->value = cpystr (tmp);
+      param->next = body->parameter;
+      body->parameter = param;
+    }
+				/* output each part */
+    for (part = body->nested.part; part; part = part->next)
+      if (!(rfc822_output_string (buf,"--") &&
+	    rfc822_output_string (buf,cookie) &&
+	    rfc822_output_string (buf,"\015\012") &&
+	    rfc822_output_body_header (buf,&part->body) &&
+	    rfc822_output_string (buf,"\015\012") &&
+	    rfc822_output_text (buf,&part->body))) return NIL;
+				/* output trailing cookie */
+    return rfc822_output_string (buf,"--") &&
+      rfc822_output_string (buf,cookie) &&
+      rfc822_output_string (buf,"--\015\012");
+  }
+				/* output segment and trailing CRLF */
+  return (!body->contents.text.data ||
+	  rfc822_output_string (buf,(char *) body->contents.text.data)) &&
+    rfc822_output_string (buf,"\015\012");
+}
+
+/* Body contents encoding/decoding routines */
+
+
+/* Convert BASE64 contents to binary
+ * Accepts: source
+ *	    length of source
+ *	    pointer to return destination length
+ * Returns: destination as binary or NIL if error
+ */
+
+#define WSP 0176		/* NUL, TAB, LF, FF, CR, SPC */
+#define JNK 0177
+#define PAD 0100
+
+void *rfc822_base64 (unsigned char *src,unsigned long srcl,unsigned long *len)
+{
+  char c,*s,tmp[MAILTMPLEN];
+  void *ret = fs_get ((size_t) ((*len = 4 + ((srcl * 3) / 4))) + 1);
+  char *d = (char *) ret;
+  int e;
+  static char decode[256] = {
+   WSP,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,WSP,WSP,JNK,WSP,WSP,JNK,JNK,
+   JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,
+   WSP,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,076,JNK,JNK,JNK,077,
+   064,065,066,067,070,071,072,073,074,075,JNK,JNK,JNK,PAD,JNK,JNK,
+   JNK,000,001,002,003,004,005,006,007,010,011,012,013,014,015,016,
+   017,020,021,022,023,024,025,026,027,030,031,JNK,JNK,JNK,JNK,JNK,
+   JNK,032,033,034,035,036,037,040,041,042,043,044,045,046,047,050,
+   051,052,053,054,055,056,057,060,061,062,063,JNK,JNK,JNK,JNK,JNK,
+   JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,
+   JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,
+   JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,
+   JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,
+   JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,
+   JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,
+   JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,
+   JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK,JNK
+  };
+				/* initialize block */
+  memset (ret,0,((size_t) *len) + 1);
+  *len = 0;			/* in case we return an error */
+
+				/* simple-minded decode */
+  for (e = 0; srcl--; ) switch (c = decode[*src++]) {
+  default:			/* valid BASE64 data character */
+    switch (e++) {		/* install based on quantum position */
+    case 0:
+      *d = c << 2;		/* byte 1: high 6 bits */
+      break;
+    case 1:
+      *d++ |= c >> 4;		/* byte 1: low 2 bits */
+      *d = c << 4;		/* byte 2: high 4 bits */
+      break;
+    case 2:
+      *d++ |= c >> 2;		/* byte 2: low 4 bits */
+      *d = c << 6;		/* byte 3: high 2 bits */
+      break;
+    case 3:
+      *d++ |= c;		/* byte 3: low 6 bits */
+      e = 0;			/* reinitialize mechanism */
+      break;
+    }
+    break;
+  case WSP:			/* whitespace */
+    break;
+  case PAD:			/* padding */
+    switch (e++) {		/* check quantum position */
+    case 3:			/* one = is good enough in quantum 3 */
+				/* make sure no data characters in remainder */
+      for (; srcl; --srcl) switch (decode[*src++]) {
+				/* ignore space, junk and extraneous padding */
+      case WSP: case JNK: case PAD:
+	break;
+      default:			/* valid BASE64 data character */
+	/* This indicates bad MIME.  One way that it can be caused is if
+	   a single-section message was BASE64 encoded and then something
+	   (e.g. a mailing list processor) appended text.  The problem is
+	   that in 1 out of 3 cases, there is no padding and hence no way
+	   to detect the end of the data.  Consequently, prudent software
+	   will always encapsulate a BASE64 segment inside a MULTIPART.
+	   */
+	sprintf (tmp,"Possible data truncation in rfc822_base64(): %.80s",
+		 (char *) src - 1);
+	if (s = strpbrk (tmp,"\015\012")) *s = NIL;
+	mm_log (tmp,PARSE);
+	srcl = 1;		/* don't issue any more messages */
+	break;
+      }
+      break;
+    case 2:			/* expect a second = in quantum 2 */
+      if (srcl && (*src == '=')) break;
+    default:			/* impossible quantum position */
+      fs_give (&ret);
+      return NIL;
+    }
+    break;
+  case JNK:			/* junk character */
+    fs_give (&ret);
+    return NIL;
+  }
+  *len = d - (char *) ret;	/* calculate data length */
+  *d = '\0';			/* NUL terminate just in case */
+  return ret;			/* return the string */
+}
+
+/* Convert binary contents to BASE64
+ * Accepts: source
+ *	    length of source
+ *	    pointer to return destination length
+ * Returns: destination as BASE64
+ */
+
+unsigned char *rfc822_binary (void *src,unsigned long srcl,unsigned long *len)
+{
+  unsigned char *ret,*d;
+  unsigned char *s = (unsigned char *) src;
+  char *v = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+  unsigned long i = ((srcl + 2) / 3) * 4;
+  *len = i += 2 * ((i / 60) + 1);
+  d = ret = (unsigned char *) fs_get ((size_t) ++i);
+				/* process tuplets */
+  for (i = 0; srcl >= 3; s += 3, srcl -= 3) {
+    *d++ = v[s[0] >> 2];	/* byte 1: high 6 bits (1) */
+				/* byte 2: low 2 bits (1), high 4 bits (2) */
+    *d++ = v[((s[0] << 4) + (s[1] >> 4)) & 0x3f];
+				/* byte 3: low 4 bits (2), high 2 bits (3) */
+    *d++ = v[((s[1] << 2) + (s[2] >> 6)) & 0x3f];
+    *d++ = v[s[2] & 0x3f];	/* byte 4: low 6 bits (3) */
+    if ((++i) == 15) {		/* output 60 characters? */
+      i = 0;			/* restart line break count, insert CRLF */
+      *d++ = '\015'; *d++ = '\012';
+    }
+  }
+  if (srcl) {
+    *d++ = v[s[0] >> 2];	/* byte 1: high 6 bits (1) */
+				/* byte 2: low 2 bits (1), high 4 bits (2) */
+    *d++ = v[((s[0] << 4) + (--srcl ? (s[1] >> 4) : 0)) & 0x3f];
+				/* byte 3: low 4 bits (2), high 2 bits (3) */
+    *d++ = srcl ? v[((s[1] << 2) + (--srcl ? (s[2] >> 6) : 0)) & 0x3f] : '=';
+				/* byte 4: low 6 bits (3) */
+    *d++ = srcl ? v[s[2] & 0x3f] : '=';
+    if (srcl) srcl--;		/* count third character if processed */
+    if ((++i) == 15) {		/* output 60 characters? */
+      i = 0;			/* restart line break count, insert CRLF */
+      *d++ = '\015'; *d++ = '\012';
+    }
+  }
+  *d++ = '\015'; *d++ = '\012';	/* insert final CRLF */
+  *d = '\0';			/* tie off string */
+  if (((unsigned long) (d - ret)) != *len) fatal ("rfc822_binary logic flaw");
+  return ret;			/* return the resulting string */
+}
+
+/* Convert QUOTED-PRINTABLE contents to 8BIT
+ * Accepts: source
+ *	    length of source
+ * 	    pointer to return destination length
+ * Returns: destination as 8-bit text or NIL if error
+ */
+
+unsigned char *rfc822_qprint (unsigned char *src,unsigned long srcl,
+			      unsigned long *len)
+{
+  char tmp[MAILTMPLEN];
+  unsigned int bogon = NIL;
+  unsigned char *ret = (unsigned char *) fs_get ((size_t) srcl + 1);
+  unsigned char *d = ret;
+  unsigned char *t = d;
+  unsigned char *s = src;
+  unsigned char c,e;
+  *len = 0;			/* in case we return an error */
+				/* until run out of characters */
+  while (((unsigned long) (s - src)) < srcl) {
+    switch (c = *s++) {		/* what type of character is it? */
+    case '=':			/* quoting character */
+      if (((unsigned long) (s - src)) < srcl) switch (c = *s++) {
+      case '\0':		/* end of data */
+	s--;			/* back up pointer */
+	break;
+      case '\015':		/* non-significant line break */
+	if ((((unsigned long) (s - src)) < srcl) && (*s == '\012')) s++;
+      case '\012':		/* bare LF */
+	t = d;			/* accept any leading spaces */
+	break;
+      default:			/* two hex digits then */
+	if (!(isxdigit (c) && (((unsigned long) (s - src)) < srcl) &&
+	      (e = *s++) && isxdigit (e))) {
+	  /* This indicates bad MIME.  One way that it can be caused is if
+	     a single-section message was QUOTED-PRINTABLE encoded and then
+	     something (e.g. a mailing list processor) appended text.  The
+	     problem is that there is no way to determine where the encoded
+	     data ended and the appended crud began.  Consequently, prudent
+	     software will always encapsulate a QUOTED-PRINTABLE segment
+	     inside a MULTIPART.
+	   */
+	  if (!bogon++) {	/* only do this once */
+	    sprintf (tmp,"Invalid quoted-printable sequence: =%.80s",
+		   (char *) s - 1);
+	    mm_log (tmp,PARSE);
+	  }
+	  *d++ = '=';		/* treat = as ordinary character */
+	  *d++ = c;		/* and the character following */
+	  t = d;		/* note point of non-space */
+	  break;
+	}
+	*d++ = hex2byte (c,e);	/* merge the two hex digits */
+	t = d;			/* note point of non-space */
+	break;
+      }
+      break;
+    case ' ':			/* space, possibly bogus */
+      *d++ = c;			/* stash the space but don't update s */
+      break;
+    case '\015':		/* end of line */
+    case '\012':		/* bare LF */
+      d = t;			/* slide back to last non-space, drop in */
+    default:
+      *d++ = c;			/* stash the character */
+      t = d;			/* note point of non-space */
+    }      
+  }
+  *d = '\0';			/* tie off results */
+  *len = d - ret;		/* calculate length */
+  return ret;			/* return the string */
+}
+
+/* Convert 8BIT contents to QUOTED-PRINTABLE
+ * Accepts: source
+ *	    length of source
+ * 	    pointer to return destination length
+ * Returns: destination as quoted-printable text
+ */
+
+#define MAXL (size_t) 75	/* 76th position only used by continuation = */
+
+unsigned char *rfc822_8bit (unsigned char *src,unsigned long srcl,
+			    unsigned long *len)
+{
+  unsigned long lp = 0;
+  unsigned char *ret = (unsigned char *)
+    fs_get ((size_t) (3*srcl + 3*(((3*srcl)/MAXL) + 1)));
+  unsigned char *d = ret;
+  char *hex = "0123456789ABCDEF";
+  unsigned char c;
+  while (srcl--) {		/* for each character */
+				/* true line break? */
+    if (((c = *src++) == '\015') && (*src == '\012') && srcl) {
+      *d++ = '\015'; *d++ = *src++; srcl--;
+      lp = 0;			/* reset line count */
+    }
+    else {			/* not a line break */
+				/* quoting required? */
+      if (iscntrl (c) || (c == 0x7f) || (c & 0x80) || (c == '=') ||
+	  ((c == ' ') && (*src == '\015'))) {
+	if ((lp += 3) > MAXL) {	/* yes, would line overflow? */
+	  *d++ = '='; *d++ = '\015'; *d++ = '\012';
+	  lp = 3;		/* set line count */
+	}
+	*d++ = '=';		/* quote character */
+	*d++ = hex[c >> 4];	/* high order 4 bits */
+	*d++ = hex[c & 0xf];	/* low order 4 bits */
+      }
+      else {			/* ordinary character */
+	if ((++lp) > MAXL) {	/* would line overflow? */
+	  *d++ = '='; *d++ = '\015'; *d++ = '\012';
+	  lp = 1;		/* set line count */
+	}
+	*d++ = c;		/* ordinary character */
+      }
+    }
+  }
+  *d = '\0';			/* tie off destination */
+  *len = d - ret;		/* calculate true size */
+				/* try to give some space back */
+  fs_resize ((void **) &ret,(size_t) *len + 1);
+  return ret;
+}
+
+/* Legacy Routines */
+
+/*
+ * WARNING: These routines are for compatibility with old software only.
+ *
+ * Their use in new software is to be avoided.
+ *
+ * These interfaces do not provide satisfactory buffer checking.  In
+ * versions of c-client prior to imap-2005, they did not provide any
+ * buffer checking at all.
+ *
+ * As a half-hearted attempt, these new compatability functions for the
+ * legacy interfaces limit what they write to size SENDBUFLEN and will
+ * fatal() if more than that is written.  However, that isn't good enough
+ * since several of these functions *append* to the buffer, and return an
+ * updated pointer.  Consequently, there is no way of knowing what the
+ * actual available space is in the buffer, yet the function will still
+ * write up to SENDBUFLEN bytes even if there is much less space actually
+ * available.  The result is a buffer overflow.
+ *
+ * You won't get a buffer overflow if you never attempt to append using
+ * these interfaces, but you can get the fatal() if it tries to write
+ * more than SENDBUFLEN bytes.
+ *
+ * To avoid this problem, use the corresponding rfc822_output_???()
+ * functions instead, e.g., rfc822_output_address() instead of
+ * rfc822_address().
+ *
+ */
+
+/* Flush routine, only called if overflow
+ * Accepts: stream
+ *	    string to output
+ * Returns: never
+ */
+
+static long rfc822_legacy_soutr (void *stream,char *string)
+{
+  fatal ("rfc822.c legacy routine buffer overflow");
+  return NIL;
+}
+
+/* Legacy write RFC 2822 header from message structure
+ * Accepts: scratch buffer to write into
+ *	    message envelope
+ *	    message body
+ */
+
+void rfc822_header (char *header,ENVELOPE *env,BODY *body)
+{
+  RFC822BUFFER buf;
+				/* write at start of buffer */
+  buf.end = (buf.beg = buf.cur = header) + SENDBUFLEN - 1;
+  buf.f = rfc822_legacy_soutr;
+  buf.s = NIL;
+  rfc822_output_header (&buf,env,body,NIL,NIL);
+  *buf.cur = '\0';		/* tie off buffer */
+}
+
+
+/* Legacy write RFC 2822 text from header line
+ * Accepts: pointer to destination string pointer
+ *	    pointer to header type
+ *	    message to interpret
+ *	    pointer to text
+ */
+
+void rfc822_header_line (char **header,char *type,ENVELOPE *env,char *text)
+{
+  RFC822BUFFER buf;
+				/* append to buffer */
+  buf.end = (buf.beg = buf.cur = *header + strlen (*header)) + SENDBUFLEN - 1;
+  buf.f = rfc822_legacy_soutr;
+  buf.s = NIL;
+  rfc822_output_header_line (&buf,type,env->remail ? LONGT : NIL,text);
+  *(*header = buf.cur) = '\0';	/* tie off buffer */
+}
+
+/* Legacy write RFC 2822 address from header line
+ * Accepts: pointer to destination string pointer
+ *	    pointer to header type
+ *	    message to interpret
+ *	    address to interpret
+ */
+
+void rfc822_address_line (char **header,char *type,ENVELOPE *env,ADDRESS *adr)
+{
+  RFC822BUFFER buf;
+				/* append to buffer */
+  buf.end = (buf.beg = buf.cur = *header + strlen (*header)) + SENDBUFLEN - 1;
+  buf.f = rfc822_legacy_soutr;
+  buf.s = NIL;
+  rfc822_output_address_line (&buf,type,env->remail ? LONGT : NIL,adr,NIL);
+  *(*header = buf.cur) = '\0';	/* tie off buffer */
+}
+
+
+/* Legacy write RFC 2822 address list
+ * Accepts: pointer to destination string
+ *	    address to interpret
+ *	    header base if pretty-printing
+ * Returns: end of destination string
+ */
+
+char *rfc822_write_address_full (char *dest,ADDRESS *adr,char *base)
+{
+  RFC822BUFFER buf;
+				/* append to buffer */
+  buf.end = (buf.beg = buf.cur = dest + strlen (dest)) + SENDBUFLEN - 1;
+  buf.f = rfc822_legacy_soutr;
+  buf.s = NIL;
+  rfc822_output_address_list (&buf,adr,base ? dest - base : 0,NIL);
+  *buf.cur = '\0';		/* tie off buffer */
+  return buf.cur;
+}
+
+
+/* Legacy write RFC 2822 route-address to string
+ * Accepts: pointer to destination string
+ *	    address to interpret
+ */
+
+void rfc822_address (char *dest,ADDRESS *adr)
+{
+  RFC822BUFFER buf;
+				/* append to buffer */
+  buf.end = (buf.beg = buf.cur = dest + strlen (dest)) + SENDBUFLEN - 1;
+  buf.f = rfc822_legacy_soutr;
+  buf.s = NIL;
+  rfc822_output_address (&buf,adr);
+  *buf.cur = '\0';		/* tie off buffer */
+}
+
+/* Concatenate RFC 2822 string
+ * Accepts: pointer to destination string
+ *	    pointer to string to concatenate
+ *	    list of special characters or NIL for dot-atom format
+ */
+
+void rfc822_cat (char *dest,char *src,const char *specials)
+{
+  RFC822BUFFER buf;
+				/* append to buffer */
+  buf.end = (buf.beg = buf.cur = dest + strlen (dest)) + SENDBUFLEN - 1;
+  buf.f = rfc822_legacy_soutr;
+  buf.s = NIL;
+  rfc822_output_cat (&buf,src,specials);
+  *buf.cur = '\0';		/* tie off buffer */
+}
+
+
+/* Legacy write body content header
+ * Accepts: pointer to destination string pointer
+ *	    pointer to body to interpret
+ */
+
+void rfc822_write_body_header (char **dst,BODY *body)
+{
+  RFC822BUFFER buf;
+				/* append to buffer */
+  buf.end = (buf.beg = buf.cur = *dst + strlen (*dst)) + SENDBUFLEN - 1;
+  buf.f = rfc822_legacy_soutr;
+  buf.s = NIL;
+  rfc822_output_body_header (&buf,body);
+  *(*dst = buf.cur) = '\0';	/* tie off buffer */
+}
+
+/* Legacy output RFC 822 message
+ * Accepts: temporary buffer
+ *	    envelope
+ *	    body
+ *	    I/O routine
+ *	    stream for I/O routine
+ *	    non-zero if 8-bit output desired
+ * Returns: T if successful, NIL if failure
+ */
+
+long rfc822_output (char *t,ENVELOPE *env,BODY *body,soutr_t f,void *s,
+		    long ok8bit)
+{
+  long ret;
+  rfc822out_t r822o = (rfc822out_t) mail_parameters (NIL,GET_RFC822OUTPUT,NIL);
+				/* call external RFC 2822 output generator */
+  if (r822o) ret = (*r822o) (t,env,body,f,s,ok8bit);
+  else {			/* output generator not armed */
+    RFC822BUFFER buf;		/* use our own buffer rather than trust */
+    char tmp[SENDBUFLEN+1];	/*  client to give us a big enough one */
+    buf.f = f;
+    buf.s = s;
+    buf.end = (buf.beg = buf.cur = t) + SENDBUFLEN - 1;
+    tmp[SENDBUFLEN] = '\0';	/* must have additional guard byte */
+    ret = rfc822_output_full (&buf,env,body,ok8bit);
+  }
+  return ret;
+}
+
+
+/* Legacy output RFC 822 body
+ * Accepts: body
+ *	    I/O routine
+ *	    stream for I/O routine
+ * Returns: T if successful, NIL if failure
+ */
+
+long rfc822_output_body (BODY *body,soutr_t f,void *s)
+{
+  RFC822BUFFER buf;
+  char tmp[SENDBUFLEN+1];
+  buf.f = f;
+  buf.s = s;
+  buf.end = (buf.beg = buf.cur = tmp) + SENDBUFLEN;
+  tmp[SENDBUFLEN] = '\0';	/* must have additional guard byte */
+  return rfc822_output_text (&buf,body) && rfc822_output_flush (&buf);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/rfc822.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,127 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	RFC 2822 and MIME routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	27 July 1988
+ * Last Edited:	30 August 2006
+ *
+ * This original version of this file is
+ * Copyright 1988 Stanford University
+ * and was developed in the Symbolic Systems Resources Group of the Knowledge
+ * Systems Laboratory at Stanford University in 1987-88, and was funded by the
+ * Biomedical Research Technology Program of the NationalInstitutes of Health
+ * under grant number RR-00785.
+ */
+
+#define MAXGROUPDEPTH 50	/* RFC [2]822 doesn't allow any group nesting */
+#define MAXMIMEDEPTH 50		/* more than any sane MIMEgram */
+
+/* Output buffering for RFC [2]822 */
+
+typedef long (*soutr_t) (void *stream,char *string);
+typedef long (*rfc822out_t) (char *tmp,ENVELOPE *env,BODY *body,soutr_t f,
+			     void *s,long ok8bit);
+
+typedef struct rfc822buffer {
+  soutr_t f;			/* I/O flush routine */
+  void *s;			/* stream for I/O routine */
+  char *beg;			/* start of buffer */
+  char *cur;			/* current buffer pointer */
+  char *end;			/* end of buffer */
+} RFC822BUFFER;
+
+typedef long (*rfc822outfull_t) (RFC822BUFFER *buf,ENVELOPE *env,BODY *body,
+				 long ok8bit);
+
+/* Function prototypes */
+
+char *rfc822_default_subtype (unsigned short type);
+void rfc822_parse_msg_full (ENVELOPE **en,BODY **bdy,char *s,unsigned long i,
+			    STRING *bs,char *host,unsigned long depth,
+			    unsigned long flags);
+void rfc822_parse_content (BODY *body,STRING *bs,char *h,unsigned long depth,
+			   unsigned long flags);
+void rfc822_parse_content_header (BODY *body,char *name,char *s);
+void rfc822_parse_parameter (PARAMETER **par,char *text);
+void rfc822_parse_adrlist (ADDRESS **lst,char *string,char *host);
+ADDRESS *rfc822_parse_address (ADDRESS **lst,ADDRESS *last,char **string,
+			       char *defaulthost,unsigned long depth);
+ADDRESS *rfc822_parse_group (ADDRESS **lst,ADDRESS *last,char **string,
+			     char *defaulthost,unsigned long depth);
+ADDRESS *rfc822_parse_mailbox (char **string,char *defaulthost);
+long rfc822_phraseonly (char *end);
+ADDRESS *rfc822_parse_routeaddr (char *string,char **ret,char *defaulthost);
+ADDRESS *rfc822_parse_addrspec (char *string,char **ret,char *defaulthost);
+char *rfc822_parse_domain (char *string,char **end);
+char *rfc822_parse_phrase (char *string);
+char *rfc822_parse_word (char *string,const char *delimiters);
+char *rfc822_cpy (char *src);
+char *rfc822_quote (char *src);
+ADDRESS *rfc822_cpy_adr (ADDRESS *adr);
+void rfc822_skipws (char **s);
+char *rfc822_skip_comment (char **s,long trim);
+
+long rfc822_output_full (RFC822BUFFER *buf,ENVELOPE *env,BODY *body,long ok8);
+long rfc822_output_flush (RFC822BUFFER *buf);
+long rfc822_output_header (RFC822BUFFER *buf,ENVELOPE *env,BODY *body,
+			   const char *specials,long flags);
+long rfc822_output_header_line (RFC822BUFFER *buf,char *type,long resent,
+				char *text);
+long rfc822_output_address_line (RFC822BUFFER *buf,char *type,long resent,
+				 ADDRESS *adr,const char *specials);
+long rfc822_output_address_list (RFC822BUFFER *buf,ADDRESS *adr,long pretty,
+				 const char *specials);
+long rfc822_output_address (RFC822BUFFER *buf,ADDRESS *adr);
+long rfc822_output_cat (RFC822BUFFER *buf,char *src,const char *specials);
+long rfc822_output_parameter (RFC822BUFFER *buf,PARAMETER *param);
+long rfc822_output_stringlist (RFC822BUFFER *buf,STRINGLIST *stl);
+long rfc822_output_body_header (RFC822BUFFER *buf,BODY *body);
+void rfc822_encode_body_7bit (ENVELOPE *env,BODY *body);
+void rfc822_encode_body_8bit (ENVELOPE *env,BODY *body);
+long rfc822_output_text (RFC822BUFFER *buf,BODY *body);
+void *rfc822_base64 (unsigned char *src,unsigned long srcl,unsigned long *len);
+unsigned char *rfc822_binary (void *src,unsigned long srcl,unsigned long *len);
+unsigned char *rfc822_qprint (unsigned char *src,unsigned long srcl,
+			      unsigned long *len);
+unsigned char *rfc822_8bit (unsigned char *src,unsigned long srcl,
+			    unsigned long *len);
+
+/* Legacy routines for compatibility with the past */
+
+void rfc822_header (char *header,ENVELOPE *env,BODY *body);
+void rfc822_header_line (char **header,char *type,ENVELOPE *env,char *text);
+void rfc822_address_line (char **header,char *type,ENVELOPE *env,ADDRESS *adr);
+char *rfc822_write_address_full (char *dest,ADDRESS *adr,char *base);
+void rfc822_address (char *dest,ADDRESS *adr);
+void rfc822_cat (char *dest,char *src,const char *specials);
+void rfc822_write_body_header (char **header,BODY *body);
+long rfc822_output (char *t,ENVELOPE *env,BODY *body,soutr_t f,void *s,
+		    long ok8bit);
+long rfc822_output_body (BODY *body,soutr_t f,void *s);
+
+
+#define rfc822_write_address(dest,adr) \
+  rfc822_write_address_full (dest,adr,NIL)
+
+#define rfc822_parse_msg(en,bdy,s,i,bs,host,flags) \
+  rfc822_parse_msg_full (en,bdy,s,i,bs,host,0,flags)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/smanager.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,129 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Subscription Manager
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	3 December 1992
+ * Last Edited:	6 December 2006
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include "c-client.h"
+
+/* Subscribe to mailbox
+ * Accepts: mailbox name
+ * Returns: T on success, NIL on failure
+ */
+
+long sm_subscribe (char *mailbox)
+{
+  FILE *f;
+  char *s,db[MAILTMPLEN],tmp[MAILTMPLEN];
+				/* canonicalize INBOX */
+  if (!compare_cstring (mailbox,"INBOX")) mailbox = "INBOX";
+  SUBSCRIPTIONFILE (db);	/* open subscription database */
+  if (f = fopen (db,"r")) {	/* make sure not already there */
+    while (fgets (tmp,MAILTMPLEN,f)) {
+      if (s = strchr (tmp,'\n')) *s = '\0';
+      if (!strcmp (tmp,mailbox)) {/* already subscribed? */
+	sprintf (tmp,"Already subscribed to mailbox %.80s",mailbox);
+	MM_LOG (tmp,ERROR);
+	fclose (f);
+	return NIL;
+      }
+    }
+    fclose (f);
+  }
+  if (!(f = fopen (db,"a"))) {	/* append new entry */
+    MM_LOG ("Can't append to subscription database",ERROR);
+    return NIL;
+  }
+  fprintf (f,"%s\n",mailbox);
+  return (fclose (f) == EOF) ? NIL : T;
+}
+
+/* Unsubscribe from mailbox
+ * Accepts: mailbox name
+ * Returns: T on success, NIL on failure
+ */
+
+long sm_unsubscribe (char *mailbox)
+{
+  FILE *f,*tf;
+  char *s,tmp[MAILTMPLEN],old[MAILTMPLEN],newname[MAILTMPLEN];
+  int found = NIL;
+				/* canonicalize INBOX */
+  if (!compare_cstring (mailbox,"INBOX")) mailbox = "INBOX";
+  SUBSCRIPTIONFILE (old);	/* make file names */
+  SUBSCRIPTIONTEMP (newname);
+  if (!(f = fopen (old,"r")))	/* open subscription database */
+    MM_LOG ("No subscriptions",ERROR);
+  else if (!(tf = fopen (newname,"w"))) {
+    MM_LOG ("Can't create subscription temporary file",ERROR);
+    fclose (f);
+  }
+  else {
+    while (fgets (tmp,MAILTMPLEN,f)) {
+      if (s = strchr (tmp,'\n')) *s = '\0';
+      if (strcmp (tmp,mailbox)) fprintf (tf,"%s\n",tmp);
+      else found = T;		/* found the name */
+    }
+    fclose (f);
+    if (fclose (tf) == EOF)
+      MM_LOG ("Can't write subscription temporary file",ERROR);
+    else if (!found) {
+      sprintf (tmp,"Not subscribed to mailbox %.80s",mailbox);
+      MM_LOG (tmp,ERROR);	/* error if at end */
+    }
+    else if (!unlink (old) && !rename (newname,old)) return LONGT;
+    else MM_LOG ("Can't update subscription database",ERROR);
+  }
+  return NIL;
+}
+
+/* Read subscription database
+ * Accepts: pointer to subscription database handle (handle NIL if first time)
+ * Returns: character string for subscription database or NIL if done
+ */
+
+static char sbname[MAILTMPLEN];
+
+char *sm_read (void **sdb)
+{
+  FILE *f = (FILE *) *sdb;
+  char *s;
+  if (!f) {			/* first time through? */
+    SUBSCRIPTIONFILE (sbname);	/* open subscription database */
+				/* make sure not already there */
+    if (f = fopen (sbname,"r")) *sdb = (void *) f;
+    else return NIL;
+  }
+  if (fgets (sbname,MAILTMPLEN,f)) {
+    if (s = strchr (sbname,'\n')) *s = '\0';
+    return sbname;
+  }
+  fclose (f);			/* all done */
+  *sdb = NIL;			/* zap sdb */
+  return NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/smtp.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,793 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Simple Mail Transfer Protocol (SMTP) routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	27 July 1988
+ * Last Edited:	28 January 2008
+ *
+ * This original version of this file is
+ * Copyright 1988 Stanford University
+ * and was developed in the Symbolic Systems Resources Group of the Knowledge
+ * Systems Laboratory at Stanford University in 1987-88, and was funded by the
+ * Biomedical Research Technology Program of the National Institutes of Health
+ * under grant number RR-00785.
+ */
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include "c-client.h"
+
+/* Constants */
+
+#define SMTPSSLPORT (long) 465	/* former assigned SSL TCP contact port */
+#define SMTPGREET (long) 220	/* SMTP successful greeting */
+#define SMTPAUTHED (long) 235	/* SMTP successful authentication */
+#define SMTPOK (long) 250	/* SMTP OK code */
+#define SMTPAUTHREADY (long) 334/* SMTP ready for authentication */
+#define SMTPREADY (long) 354	/* SMTP ready for data */
+#define SMTPSOFTFATAL (long) 421/* SMTP soft fatal code */
+#define SMTPWANTAUTH (long) 505	/* SMTP authentication needed */
+#define SMTPWANTAUTH2 (long) 530/* SMTP authentication needed */
+#define SMTPUNAVAIL (long) 550	/* SMTP mailbox unavailable */
+#define SMTPHARDERROR (long) 554/* SMTP miscellaneous hard failure */
+
+
+/* Convenient access to protocol-specific data */
+
+#define ESMTP stream->protocol.esmtp
+
+
+/* Function prototypes */
+
+void *smtp_challenge (void *s,unsigned long *len);
+long smtp_response (void *s,char *response,unsigned long size);
+long smtp_auth (SENDSTREAM *stream,NETMBX *mb,char *tmp);
+long smtp_rcpt (SENDSTREAM *stream,ADDRESS *adr,long *error);
+long smtp_send (SENDSTREAM *stream,char *command,char *args);
+long smtp_reply (SENDSTREAM *stream);
+long smtp_ehlo (SENDSTREAM *stream,char *host,NETMBX *mb);
+long smtp_fake (SENDSTREAM *stream,char *text);
+static long smtp_seterror (SENDSTREAM *stream,long code,char *text);
+long smtp_soutr (void *stream,char *s);
+
+/* Mailer parameters */
+
+static unsigned long smtp_maxlogintrials = MAXLOGINTRIALS;
+static long smtp_port = 0;	/* default port override */
+static long smtp_sslport = 0;
+
+
+#ifndef RFC2821
+#define RFC2821			/* RFC 2821 compliance */
+#endif
+
+/* SMTP limits, current as of RFC 2821 */
+
+#define SMTPMAXLOCALPART 64
+#define SMTPMAXDOMAIN 255
+#define SMTPMAXPATH 256
+
+
+/* I have seen local parts of more than 64 octets, in spite of the SMTP
+ * limits.  So, we'll have a more generous limit that's still guaranteed
+ * not to pop the buffer, and let the server worry about it.  As of this
+ * writing, it comes out to 240.  Anyone with a mailbox name larger than
+ * that is in serious need of a life or at least a new ISP!  23 June 1998
+ */
+
+#define MAXLOCALPART ((MAILTMPLEN - (SMTPMAXDOMAIN + SMTPMAXPATH + 32)) / 2)
+
+/* Mail Transfer Protocol manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *smtp_parameters (long function,void *value)
+{
+  switch ((int) function) {
+  case SET_MAXLOGINTRIALS:
+    smtp_maxlogintrials = (unsigned long) value;
+    break;
+  case GET_MAXLOGINTRIALS:
+    value = (void *) smtp_maxlogintrials;
+    break;
+  case SET_SMTPPORT:
+    smtp_port = (long) value;
+    break;
+  case GET_SMTPPORT:
+    value = (void *) smtp_port;
+    break;
+  case SET_SSLSMTPPORT:
+    smtp_sslport = (long) value;
+    break;
+  case GET_SSLSMTPPORT:
+    value = (void *) smtp_sslport;
+    break;
+  default:
+    value = NIL;		/* error case */
+    break;
+  }
+  return value;
+}
+
+/* Mail Transfer Protocol open connection
+ * Accepts: network driver
+ *	    service host list
+ *	    port number
+ *	    service name
+ *	    SMTP open options
+ * Returns: SEND stream on success, NIL on failure
+ */
+
+SENDSTREAM *smtp_open_full (NETDRIVER *dv,char **hostlist,char *service,
+			    unsigned long port,long options)
+{
+  SENDSTREAM *stream = NIL;
+  long reply;
+  char *s,tmp[MAILTMPLEN];
+  NETSTREAM *netstream;
+  NETMBX mb;
+  if (!(hostlist && *hostlist)) mm_log ("Missing SMTP service host",ERROR);
+				/* maximum domain name is 64 characters */
+  else do if (strlen (*hostlist) < SMTPMAXDOMAIN) {
+    sprintf (tmp,"{%.1000s}",*hostlist);
+    if (!mail_valid_net_parse_work (tmp,&mb,service ? service : "smtp") ||
+	mb.anoflag || mb.readonlyflag) {
+      sprintf (tmp,"Invalid host specifier: %.80s",*hostlist);
+      mm_log (tmp,ERROR);
+    }
+    else {			/* light tryssl flag if requested */
+      mb.trysslflag = (options & SOP_TRYSSL) ? T : NIL;
+				/* explicit port overrides all */
+      if (mb.port) port = mb.port;
+				/* else /submit overrides port argument */
+      else if (!compare_cstring (mb.service,"submit")) {
+	port = SUBMITTCPPORT;	/* override port, use IANA name */
+	strcpy (mb.service,"submission");
+      }
+				/* else port argument overrides SMTP port */
+      else if (!port) port = smtp_port ? smtp_port : SMTPTCPPORT;
+      if (netstream =		/* try to open ordinary connection */
+	  net_open (&mb,dv,port,
+		    (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL),
+		    "*smtps",smtp_sslport ? smtp_sslport : SMTPSSLPORT)) {
+	stream = (SENDSTREAM *) memset (fs_get (sizeof (SENDSTREAM)),0,
+					sizeof (SENDSTREAM));
+	stream->netstream = netstream;
+	stream->host = cpystr ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ?
+			       net_host (netstream) : mb.host);
+	stream->debug = (mb.dbgflag || (options & OP_DEBUG)) ? T : NIL;
+	if (options & SOP_SECURE) mb.secflag = T;
+				/* get name of local host to use */
+	s = compare_cstring ("localhost",mb.host) ?
+	  net_localhost (netstream) : "localhost";
+
+	do reply = smtp_reply (stream);
+	while ((reply < 100) || (stream->reply[3] == '-'));
+	if (reply != SMTPGREET){/* get SMTP greeting */
+	  sprintf (tmp,"SMTP greeting failure: %.80s",stream->reply);
+	  mm_log (tmp,ERROR);
+	  stream = smtp_close (stream);
+	}
+				/* try EHLO first, then HELO */
+	else if (((reply = smtp_ehlo (stream,s,&mb)) != SMTPOK) &&
+		 ((reply = smtp_send (stream,"HELO",s)) != SMTPOK)) {
+	  sprintf (tmp,"SMTP hello failure: %.80s",stream->reply);
+	  mm_log (tmp,ERROR);
+	  stream = smtp_close (stream);
+	}
+	else {
+	  NETDRIVER *ssld =(NETDRIVER *)mail_parameters(NIL,GET_SSLDRIVER,NIL);
+	  sslstart_t stls = (sslstart_t) mail_parameters(NIL,GET_SSLSTART,NIL);
+	  ESMTP.ok = T;		/* ESMTP server, start TLS if present */
+	  if (!dv && stls && ESMTP.service.starttls &&
+	      !mb.sslflag && !mb.notlsflag &&
+	      (smtp_send (stream,"STARTTLS",NIL) == SMTPGREET)) {
+	    mb.tlsflag = T;	/* TLS OK, get into TLS at this end */
+	    stream->netstream->dtb = ssld;
+				/* TLS started, negotiate it */
+	    if (!(stream->netstream->stream = (*stls)
+		  (stream->netstream->stream,mb.host,
+		   (mb.tlssslv23 ? NIL : NET_TLSCLIENT) |
+		   (mb.novalidate ? NET_NOVALIDATECERT:NIL)))){
+				/* TLS negotiation failed after STARTTLS */
+	      sprintf (tmp,"Unable to negotiate TLS with this server: %.80s",
+		       mb.host);
+	      mm_log (tmp,ERROR);
+				/* close without doing QUIT */
+	      if (stream->netstream) net_close (stream->netstream);
+	      stream->netstream = NIL;
+	      stream = smtp_close (stream);
+	    }
+				/* TLS OK, re-negotiate EHLO */
+	    else if ((reply = smtp_ehlo (stream,s,&mb)) != SMTPOK) {
+	      sprintf (tmp,"SMTP EHLO failure after STARTTLS: %.80s",
+		       stream->reply);
+	      mm_log (tmp,ERROR);
+	      stream = smtp_close (stream);
+	    }
+	    else ESMTP.ok = T;	/* TLS OK and EHLO successful */
+	  }
+	  else if (mb.tlsflag) {/* user specified /tls but can't do it */
+	    sprintf (tmp,"TLS unavailable with this server: %.80s",mb.host);
+	    mm_log (tmp,ERROR);
+	    stream = smtp_close (stream);
+	  }
+
+				/* remote name for authentication */
+	  if (stream && ((mb.secflag || mb.user[0]))) {
+	    if (ESMTP.auth) {	/* use authenticator? */
+	      if ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL)) {
+				/* remote name for authentication */
+		strncpy (mb.host,
+			 (long) mail_parameters (NIL,GET_SASLUSESPTRNAME,NIL) ?
+			 net_remotehost (netstream) : net_host (netstream),
+			 NETMAXHOST-1);
+		mb.host[NETMAXHOST-1] = '\0';
+	      }
+	      if (!smtp_auth (stream,&mb,tmp)) stream = smtp_close (stream);
+	    }
+	    else {		/* no available authenticators? */
+	      sprintf (tmp,"%sSMTP authentication not available: %.80s",
+		       mb.secflag ? "Secure " : "",mb.host);
+	      mm_log (tmp,ERROR);
+	      stream = smtp_close (stream);
+	    }
+	  }
+	}
+      }
+    }
+  } while (!stream && *++hostlist);
+  if (stream) {			/* set stream options if have a stream */
+    if (options &(SOP_DSN | SOP_DSN_NOTIFY_FAILURE | SOP_DSN_NOTIFY_DELAY |
+		  SOP_DSN_NOTIFY_SUCCESS | SOP_DSN_RETURN_FULL)) {
+      ESMTP.dsn.want = T;
+      if (options & SOP_DSN_NOTIFY_FAILURE) ESMTP.dsn.notify.failure = T;
+      if (options & SOP_DSN_NOTIFY_DELAY) ESMTP.dsn.notify.delay = T;
+      if (options & SOP_DSN_NOTIFY_SUCCESS) ESMTP.dsn.notify.success = T;
+      if (options & SOP_DSN_RETURN_FULL) ESMTP.dsn.full = T;
+    }
+    if (options & SOP_8BITMIME) ESMTP.eightbit.want = T;
+  }
+  return stream;
+}
+
+/* SMTP authenticate
+ * Accepts: stream to login
+ *	    parsed network mailbox structure
+ *	    scratch buffer
+ *	    place to return user name
+ * Returns: T on success, NIL on failure
+ */
+
+long smtp_auth (SENDSTREAM *stream,NETMBX *mb,char *tmp)
+{
+  unsigned long trial,auths;
+  char *lsterr = NIL;
+  char usr[MAILTMPLEN];
+  AUTHENTICATOR *at;
+  long ret = NIL;
+  for (auths = ESMTP.auth, stream->saslcancel = NIL;
+       !ret && stream->netstream && auths &&
+       (at = mail_lookup_auth (find_rightmost_bit (&auths) + 1)); ) {
+    if (lsterr) {		/* previous authenticator failed? */
+      sprintf (tmp,"Retrying using %s authentication after %.80s",
+	       at->name,lsterr);
+      mm_log (tmp,NIL);
+      fs_give ((void **) &lsterr);
+    }
+    trial = 0;			/* initial trial count */
+    tmp[0] = '\0';		/* empty buffer */
+    if (stream->netstream) do {
+      if (lsterr) {
+	sprintf (tmp,"Retrying %s authentication after %.80s",at->name,lsterr);
+	mm_log (tmp,WARN);
+	fs_give ((void **) &lsterr);
+      }
+      stream->saslcancel = NIL;
+      if (smtp_send (stream,"AUTH",at->name) == SMTPAUTHREADY) {
+				/* hide client authentication responses */
+	if (!(at->flags & AU_SECURE)) stream->sensitive = T;
+	if ((*at->client) (smtp_challenge,smtp_response,"smtp",mb,stream,
+			   &trial,usr)) {
+	  if (stream->replycode == SMTPAUTHED) {
+	    ESMTP.auth = NIL;	/* disable authenticators */
+	    ret = LONGT;
+	  }
+				/* if main program requested cancellation */
+	  else if (!trial) mm_log ("SMTP Authentication cancelled",ERROR);
+	}
+	stream->sensitive = NIL;/* unhide */
+      }
+				/* remember response if error and no cancel */
+      if (!ret && trial) lsterr = cpystr (stream->reply);
+    } while (!ret && stream->netstream && trial &&
+	     (trial < smtp_maxlogintrials));
+  }
+  if (lsterr) {			/* previous authenticator failed? */
+    if (!stream->saslcancel) {	/* don't do this if a cancel */
+      sprintf (tmp,"Can not authenticate to SMTP server: %.80s",lsterr);
+      mm_log (tmp,ERROR);
+    }
+    fs_give ((void **) &lsterr);
+  }
+  return ret;			/* authentication failed */
+}
+
+/* Get challenge to authenticator in binary
+ * Accepts: stream
+ *	    pointer to returned size
+ * Returns: challenge or NIL if not challenge
+ */
+
+void *smtp_challenge (void *s,unsigned long *len)
+{
+  char tmp[MAILTMPLEN];
+  void *ret = NIL;
+  SENDSTREAM *stream = (SENDSTREAM *) s;
+  if ((stream->replycode == SMTPAUTHREADY) &&
+      !(ret = rfc822_base64 ((unsigned char *) stream->reply + 4,
+			     strlen (stream->reply + 4),len))) {
+    sprintf (tmp,"SMTP SERVER BUG (invalid challenge): %.80s",stream->reply+4);
+    mm_log (tmp,ERROR);
+  }
+  return ret;
+}
+
+
+/* Send authenticator response in BASE64
+ * Accepts: MAIL stream
+ *	    string to send
+ *	    length of string
+ * Returns: T, always
+ */
+
+long smtp_response (void *s,char *response,unsigned long size)
+{
+  SENDSTREAM *stream = (SENDSTREAM *) s;
+  unsigned long i,j;
+  char *t,*u;
+  if (response) {		/* make CRLFless BASE64 string */
+    if (size) {
+      for (t = (char *) rfc822_binary ((void *) response,size,&i),u = t,j = 0;
+	   j < i; j++) if (t[j] > ' ') *u++ = t[j];
+      *u = '\0';		/* tie off string */
+      i = smtp_send (stream,t,NIL);
+      fs_give ((void **) &t);
+    }
+    else i = smtp_send (stream,"",NIL);
+  }
+  else {			/* abort requested */
+    i = smtp_send (stream,"*",NIL);
+    stream->saslcancel = T;	/* mark protocol-requested SASL cancel */
+  }
+  return LONGT;
+}
+
+/* Mail Transfer Protocol close connection
+ * Accepts: SEND stream
+ * Returns: NIL always
+ */
+
+SENDSTREAM *smtp_close (SENDSTREAM *stream)
+{
+  if (stream) {			/* send "QUIT" */
+    if (stream->netstream) {	/* do close actions if have netstream */
+      smtp_send (stream,"QUIT",NIL);
+      if (stream->netstream)	/* could have been closed during "QUIT" */
+        net_close (stream->netstream);
+    }
+				/* clean up */
+    if (stream->host) fs_give ((void **) &stream->host);
+    if (stream->reply) fs_give ((void **) &stream->reply);
+    if (ESMTP.dsn.envid) fs_give ((void **) &ESMTP.dsn.envid);
+    if (ESMTP.atrn.domains) fs_give ((void **) &ESMTP.atrn.domains);
+    fs_give ((void **) &stream);/* flush the stream */
+  }
+  return NIL;
+}
+
+/* Mail Transfer Protocol deliver mail
+ * Accepts: SEND stream
+ *	    delivery option (MAIL, SEND, SAML, SOML)
+ *	    message envelope
+ *	    message body
+ * Returns: T on success, NIL on failure
+ */
+
+long smtp_mail (SENDSTREAM *stream,char *type,ENVELOPE *env,BODY *body)
+{
+  RFC822BUFFER buf;
+  char tmp[SENDBUFLEN+1];
+  long error = NIL;
+  long retry = NIL;
+  buf.f = smtp_soutr;		/* initialize buffer */
+  buf.s = stream->netstream;
+  buf.end = (buf.beg = buf.cur = tmp) + SENDBUFLEN;
+  tmp[SENDBUFLEN] = '\0';	/* must have additional null guard byte */
+  if (!(env->to || env->cc || env->bcc)) {
+  				/* no recipients in request */
+    smtp_seterror (stream,SMTPHARDERROR,"No recipients specified");
+    return NIL;
+  }
+  do {				/* make sure stream is in good shape */
+    smtp_send (stream,"RSET",NIL);
+    if (retry) {		/* need to retry with authentication? */
+      NETMBX mb;
+				/* yes, build remote name for authentication */
+      sprintf (tmp,"{%.200s/smtp%s}<none>",
+	       (long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ?
+	       ((long) mail_parameters (NIL,GET_SASLUSESPTRNAME,NIL) ?
+		net_remotehost (stream->netstream) :
+		net_host (stream->netstream)) :
+	       stream->host,
+	       (stream->netstream->dtb ==
+		(NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL)) ?
+	       "/ssl" : "");
+      mail_valid_net_parse (tmp,&mb);
+      if (!smtp_auth (stream,&mb,tmp)) return NIL;
+      retry = NIL;		/* no retry at this point */
+    }
+
+    strcpy (tmp,"FROM:<");	/* compose "MAIL FROM:<return-path>" */
+#ifdef RFC2821
+    if (env->return_path && env->return_path->host &&
+	!((strlen (env->return_path->mailbox) > SMTPMAXLOCALPART) ||
+	  (strlen (env->return_path->host) > SMTPMAXDOMAIN))) {
+      rfc822_cat (tmp,env->return_path->mailbox,NIL);
+      sprintf (tmp + strlen (tmp),"@%s",env->return_path->host);
+    }
+#else				/* old code with A-D-L support */
+    if (env->return_path && env->return_path->host &&
+	!((env->return_path->adl &&
+	   (strlen (env->return_path->adl) > SMTPMAXPATH)) ||
+	  (strlen (env->return_path->mailbox) > SMTPMAXLOCALPART) ||
+	  (strlen (env->return_path->host) > SMTPMAXDOMAIN)))
+      rfc822_address (tmp,env->return_path);
+#endif
+    strcat (tmp,">");
+    if (ESMTP.ok) {
+      if (ESMTP.eightbit.ok && ESMTP.eightbit.want)
+	strcat (tmp," BODY=8BITMIME");
+      if (ESMTP.dsn.ok && ESMTP.dsn.want) {
+	strcat (tmp,ESMTP.dsn.full ? " RET=FULL" : " RET=HDRS");
+	if (ESMTP.dsn.envid)
+	  sprintf (tmp + strlen (tmp)," ENVID=%.100s",ESMTP.dsn.envid);
+      }
+    }
+				/* send "MAIL FROM" command */
+    switch (smtp_send (stream,type,tmp)) {
+    case SMTPUNAVAIL:		/* mailbox unavailable? */
+    case SMTPWANTAUTH:		/* wants authentication? */
+    case SMTPWANTAUTH2:
+      if (ESMTP.auth) retry = T;/* yes, retry with authentication */
+    case SMTPOK:		/* looks good */
+      break;
+    default:			/* other failure */
+      return NIL;
+    }
+				/* negotiate the recipients */
+    if (!retry && env->to) retry = smtp_rcpt (stream,env->to,&error);
+    if (!retry && env->cc) retry = smtp_rcpt (stream,env->cc,&error);
+    if (!retry && env->bcc) retry = smtp_rcpt (stream,env->bcc,&error);
+    if (!retry && error) {	/* any recipients failed? */
+      smtp_send (stream,"RSET",NIL);
+      smtp_seterror (stream,SMTPHARDERROR,"One or more recipients failed");
+      return NIL;
+    }
+  } while (retry);
+				/* negotiate data command */
+  if (!(smtp_send (stream,"DATA",NIL) == SMTPREADY)) return NIL;
+				/* send message data */
+  if (!rfc822_output_full (&buf,env,body,
+			   ESMTP.eightbit.ok && ESMTP.eightbit.want)) {
+    smtp_fake (stream,"SMTP connection broken (message data)");
+    return NIL;			/* can't do much else here */
+  }
+				/* send trailing dot */
+  return (smtp_send (stream,".",NIL) == SMTPOK) ? LONGT : NIL;
+}
+
+/* Simple Mail Transfer Protocol send VERBose
+ * Accepts: SMTP stream
+ * Returns: T if successful, else NIL
+ *
+ * Descriptive text formerly in [al]pine sources:
+ * At worst, this command may cause the SMTP connection to get nuked.  Modern
+ * sendmail's recognize it, and possibly other SMTP implementations (the "ON"
+ * arg is for PMDF).  What's more, if it works, the reply code and accompanying
+ * text may vary from server to server.
+ */
+
+long smtp_verbose (SENDSTREAM *stream)
+{
+				/* accept any 2xx reply code */
+  return ((smtp_send (stream,"VERB","ON") / (long) 100) == 2) ? LONGT : NIL;
+}
+
+/* Internal routines */
+
+
+/* Simple Mail Transfer Protocol send recipient
+ * Accepts: SMTP stream
+ *	    address list
+ *	    pointer to error flag
+ * Returns: T if should retry, else NIL
+ */
+
+long smtp_rcpt (SENDSTREAM *stream,ADDRESS *adr,long *error)
+{
+ char *s,tmp[2*MAILTMPLEN],orcpt[MAILTMPLEN];
+  while (adr) {			/* for each address on the list */
+				/* clear any former error */
+    if (adr->error) fs_give ((void **) &adr->error);
+    if (adr->host) {		/* ignore group syntax */
+				/* enforce SMTP limits to protect the buffer */
+      if (strlen (adr->mailbox) > MAXLOCALPART) {
+	adr->error = cpystr ("501 Recipient name too long");
+	*error = T;
+      }
+      else if ((strlen (adr->host) > SMTPMAXDOMAIN)) {
+	adr->error = cpystr ("501 Recipient domain too long");
+	*error = T;
+      }
+#ifndef RFC2821			/* old code with A-D-L support */
+      else if (adr->adl && (strlen (adr->adl) > SMTPMAXPATH)) {
+	adr->error = cpystr ("501 Path too long");
+	*error = T;
+      }
+#endif
+
+      else {
+	strcpy (tmp,"TO:<");	/* compose "RCPT TO:<return-path>" */
+#ifdef RFC2821
+	rfc822_cat (tmp,adr->mailbox,NIL);
+	sprintf (tmp + strlen (tmp),"@%s>",adr->host);
+#else				/* old code with A-D-L support */
+	rfc822_address (tmp,adr);
+	strcat (tmp,">");
+#endif
+				/* want notifications */
+	if (ESMTP.ok && ESMTP.dsn.ok && ESMTP.dsn.want) {
+				/* yes, start with prefix */
+	  strcat (tmp," NOTIFY=");
+	  s = tmp + strlen (tmp);
+	  if (ESMTP.dsn.notify.failure) strcat (s,"FAILURE,");
+	  if (ESMTP.dsn.notify.delay) strcat (s,"DELAY,");
+	  if (ESMTP.dsn.notify.success) strcat (s,"SUCCESS,");
+				/* tie off last comma */
+	  if (*s) s[strlen (s) - 1] = '\0';
+	  else strcat (tmp,"NEVER");
+	  if (adr->orcpt.addr) {
+	    sprintf (orcpt,"%.498s;%.498s",
+		     adr->orcpt.type ? adr->orcpt.type : "rfc822",
+		     adr->orcpt.addr);
+	    sprintf (tmp + strlen (tmp)," ORCPT=%.500s",orcpt);
+	  }
+	}
+	switch (smtp_send (stream,"RCPT",tmp)) {
+	case SMTPOK:		/* looks good */
+	  break;
+	case SMTPUNAVAIL:	/* mailbox unavailable? */
+	case SMTPWANTAUTH:	/* wants authentication? */
+	case SMTPWANTAUTH2:
+	  if (ESMTP.auth) return T;
+	default:		/* other failure */
+	  *error = T;		/* note that an error occurred */
+	  adr->error = cpystr (stream->reply);
+	}
+      }
+    }
+    adr = adr->next;		/* do any subsequent recipients */
+  }
+  return NIL;			/* no retry called for */
+}
+
+/* Simple Mail Transfer Protocol send command
+ * Accepts: SEND stream
+ *	    text
+ * Returns: reply code
+ */
+
+long smtp_send (SENDSTREAM *stream,char *command,char *args)
+{
+  long ret;
+  char *s = (char *) fs_get (strlen (command) + (args ? strlen (args) + 1 : 0)
+			     + 3);
+				/* build the complete command */
+  if (args) sprintf (s,"%s %s",command,args);
+  else strcpy (s,command);
+  if (stream->debug) mail_dlog (s,stream->sensitive);
+  strcat (s,"\015\012");
+				/* send the command */
+  if (stream->netstream && net_soutr (stream->netstream,s)) {
+    do stream->replycode = smtp_reply (stream);
+    while ((stream->replycode < 100) || (stream->reply[3] == '-'));
+    ret = stream->replycode;
+  }
+  else ret = smtp_fake (stream,"SMTP connection broken (command)");
+  fs_give ((void **) &s);
+  return ret;
+}
+
+
+/* Simple Mail Transfer Protocol get reply
+ * Accepts: SMTP stream
+ * Returns: reply code
+ */
+
+long smtp_reply (SENDSTREAM *stream)
+{
+  smtpverbose_t pv = (smtpverbose_t) mail_parameters (NIL,GET_SMTPVERBOSE,NIL);
+  long reply;
+				/* flush old reply */
+  if (stream->reply) fs_give ((void **) &stream->reply);
+  				/* get reply */
+  if (stream->netstream && (stream->reply = net_getline (stream->netstream))) {
+    if (stream->debug) mm_dlog (stream->reply);
+				/* return response code */
+    reply = atol (stream->reply);
+    if (pv && (reply < 100)) (*pv) (stream->reply);
+  }
+  else reply = smtp_fake (stream,"SMTP connection broken (reply)");
+  return reply;
+}
+
+/* Simple Mail Transfer Protocol send EHLO
+ * Accepts: SMTP stream
+ *	    host name to use in EHLO
+ *	    NETMBX structure
+ * Returns: reply code
+ */
+
+long smtp_ehlo (SENDSTREAM *stream,char *host,NETMBX *mb)
+{
+  unsigned long i,j;
+  long flags = (mb->secflag ? AU_SECURE : NIL) |
+    (mb->authuser[0] ? AU_AUTHUSER : NIL);
+  char *s,*t,*r,tmp[MAILTMPLEN];
+				/* clear ESMTP data */
+  memset (&ESMTP,0,sizeof (ESMTP));
+  if (mb->loser) return 500;	/* never do EHLO if a loser */
+  sprintf (tmp,"EHLO %s",host);	/* build the complete command */
+  if (stream->debug) mm_dlog (tmp);
+  strcat (tmp,"\015\012");
+				/* send the command */
+  if (!net_soutr (stream->netstream,tmp))
+    return smtp_fake (stream,"SMTP connection broken (EHLO)");
+				/* got an OK reply? */
+  do if ((i = smtp_reply (stream)) == SMTPOK) {
+				/* hack for AUTH= */
+    if (stream->reply[4] && stream->reply[5] && stream->reply[6] &&
+	stream->reply[7] && (stream->reply[8] == '=')) stream->reply[8] = ' ';
+				/* get option code */
+    if (!(s = strtok_r (stream->reply+4," ",&r)));
+				/* have option, does it have a value */
+    else if ((t = strtok_r (NIL," ",&r)) && *t) {
+				/* EHLO options which take arguments */
+      if (!compare_cstring (s,"SIZE")) {
+	if (isdigit (*t)) ESMTP.size.limit = strtoul (t,&t,10);
+	ESMTP.size.ok = T;
+      }
+      else if (!compare_cstring (s,"DELIVERBY")) {
+	if (isdigit (*t)) ESMTP.deliverby.minby = strtoul (t,&t,10);
+	ESMTP.deliverby.ok = T;
+      }
+      else if (!compare_cstring (s,"ATRN")) {
+	ESMTP.atrn.domains = cpystr (t);
+	ESMTP.atrn.ok = T;
+      }
+      else if (!compare_cstring (s,"AUTH"))
+	do if ((j = mail_lookup_auth_name (t,flags)) &&
+	       (--j < MAXAUTHENTICATORS)) ESMTP.auth |= (1 << j);
+	while ((t = strtok_r (NIL," ",&r)) && *t);
+    }
+				/* EHLO options which do not take arguments */
+    else if (!compare_cstring (s,"SIZE")) ESMTP.size.ok = T;
+    else if (!compare_cstring (s,"8BITMIME")) ESMTP.eightbit.ok = T;
+    else if (!compare_cstring (s,"DSN")) ESMTP.dsn.ok = T;
+    else if (!compare_cstring (s,"ATRN")) ESMTP.atrn.ok = T;
+    else if (!compare_cstring (s,"SEND")) ESMTP.service.send = T;
+    else if (!compare_cstring (s,"SOML")) ESMTP.service.soml = T;
+    else if (!compare_cstring (s,"SAML")) ESMTP.service.saml = T;
+    else if (!compare_cstring (s,"EXPN")) ESMTP.service.expn = T;
+    else if (!compare_cstring (s,"HELP")) ESMTP.service.help = T;
+    else if (!compare_cstring (s,"TURN")) ESMTP.service.turn = T;
+    else if (!compare_cstring (s,"ETRN")) ESMTP.service.etrn = T;
+    else if (!compare_cstring (s,"STARTTLS")) ESMTP.service.starttls = T;
+    else if (!compare_cstring (s,"RELAY")) ESMTP.service.relay = T;
+    else if (!compare_cstring (s,"PIPELINING")) ESMTP.service.pipe = T;
+    else if (!compare_cstring (s,"ENHANCEDSTATUSCODES"))
+      ESMTP.service.ensc = T;
+    else if (!compare_cstring (s,"BINARYMIME")) ESMTP.service.bmime = T;
+    else if (!compare_cstring (s,"CHUNKING")) ESMTP.service.chunk = T;
+  }
+  while ((i < 100) || (stream->reply[3] == '-'));
+				/* disable LOGIN if PLAIN also advertised */
+  if ((j = mail_lookup_auth_name ("PLAIN",NIL)) && (--j < MAXAUTHENTICATORS) &&
+      (ESMTP.auth & (1 << j)) &&
+      (j = mail_lookup_auth_name ("LOGIN",NIL)) && (--j < MAXAUTHENTICATORS))
+    ESMTP.auth &= ~(1 << j);
+  return i;			/* return the response code */
+}
+
+/* Simple Mail Transfer Protocol set fake error and abort
+ * Accepts: SMTP stream
+ *	    error text
+ * Returns: SMTPSOFTFATAL, always
+ */
+
+long smtp_fake (SENDSTREAM *stream,char *text)
+{
+  if (stream->netstream) {	/* close net connection if still open */
+    net_close (stream->netstream);
+    stream->netstream = NIL;
+  }
+				/* set last error */
+  return smtp_seterror (stream,SMTPSOFTFATAL,text);
+}
+
+
+/* Simple Mail Transfer Protocol set error
+ * Accepts: SMTP stream
+ *	    SMTP error code
+ *	    error text
+ * Returns: error code
+ */
+
+static long smtp_seterror (SENDSTREAM *stream,long code,char *text)
+{
+				/* flush any old reply */
+  if (stream->reply ) fs_give ((void **) &stream->reply);
+  				/* set up pseudo-reply string */
+  stream->reply = (char *) fs_get (20+strlen (text));
+  sprintf (stream->reply,"%ld %s",code,text);
+  return code;			/* return error code */
+}
+
+
+/* Simple Mail Transfer Protocol filter mail
+ * Accepts: stream
+ *	    string
+ * Returns: T on success, NIL on failure
+ */
+
+long smtp_soutr (void *stream,char *s)
+{
+  char c,*t;
+				/* "." on first line */
+  if (s[0] == '.') net_sout (stream,".",1);
+				/* find lines beginning with a "." */
+  while (t = strstr (s,"\015\012.")) {
+    c = *(t += 3);		/* remember next character after "." */
+    *t = '\0';			/* tie off string */
+				/* output prefix */
+    if (!net_sout (stream,s,t-s)) return NIL;
+    *t = c;			/* restore delimiter */
+    s = t - 1;			/* push pointer up to the "." */
+  }
+				/* output remainder of text */
+  return *s ? net_soutr (stream,s) : T;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/smtp.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,76 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Simple Mail Transfer Protocol (SMTP) routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	27 July 1988
+ * Last Edited:	15 August 2007
+ *
+ * This original version of this file is
+ * Copyright 1988 Stanford University
+ * and was developed in the Symbolic Systems Resources Group of the Knowledge
+ * Systems Laboratory at Stanford University in 1987-88, and was funded by the
+ * Biomedical Research Technology Program of the NationalInstitutes of Health
+ * under grant number RR-00785.
+ */
+
+/* Constants (should be in smtp.c) */
+
+#define SMTPTCPPORT (long) 25	/* assigned TCP contact port */
+#define SUBMITTCPPORT (long) 587/* assigned TCP contact port */
+
+
+/* SMTP open options
+ * For compatibility with the past, SOP_DEBUG must always be 1.
+ */
+
+#define SOP_DEBUG (long) 1	/* debug protocol negotiations */
+#define SOP_DSN (long) 2	/* DSN requested */
+				/* DSN notification, none set mean NEVER */
+#define SOP_DSN_NOTIFY_FAILURE (long) 4
+#define SOP_DSN_NOTIFY_DELAY (long) 8
+#define SOP_DSN_NOTIFY_SUCCESS (long) 16
+				/* DSN return full msg vs. header */
+
+#define SOP_DSN_RETURN_FULL (long) 32
+#define SOP_8BITMIME (long) 64	/* 8-bit MIME requested */
+#define SOP_SECURE (long) 256	/* don't do non-secure authentication */
+#define SOP_TRYSSL (long) 512	/* try SSL first */
+#define SOP_TRYALT SOP_TRYSSL	/* old name */
+				/* reserved for application use */
+#define SOP_RESERVED (unsigned long) 0xff000000
+
+
+/* Compatibility support names */
+
+#define smtp_open(hostlist,options) \
+  smtp_open_full (NIL,hostlist,"smtp",NIL,options)
+
+
+/* Function prototypes */
+
+void *smtp_parameters (long function,void *value);
+SENDSTREAM *smtp_open_full (NETDRIVER *dv,char **hostlist,char *service,
+			    unsigned long port,long options);
+SENDSTREAM *smtp_close (SENDSTREAM *stream);
+long smtp_mail (SENDSTREAM *stream,char *type,ENVELOPE *msg,BODY *body);
+long smtp_verbose (SENDSTREAM *stream);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/sslio.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,70 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	SSL routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	7 February 2001
+ * Last Edited:	30 August 2006
+ */
+
+/* SSL driver */
+
+struct ssl_driver {		/* must parallel NETDRIVER in mail.h */
+  SSLSTREAM *(*open) (char *host,char *service,unsigned long port);
+  SSLSTREAM *(*aopen) (NETMBX *mb,char *service,char *usrbuf);
+  char *(*getline) (SSLSTREAM *stream);
+  long (*getbuffer) (SSLSTREAM *stream,unsigned long size,char *buffer);
+  long (*soutr) (SSLSTREAM *stream,char *string);
+  long (*sout) (SSLSTREAM *stream,char *string,unsigned long size);
+  void (*close) (SSLSTREAM *stream);
+  char *(*host) (SSLSTREAM *stream);
+  char *(*remotehost) (SSLSTREAM *stream);
+  unsigned long (*port) (SSLSTREAM *stream);
+  char *(*localhost) (SSLSTREAM *stream);
+};
+
+
+/* SSL stdio stream */
+
+typedef struct ssl_stdiostream {
+  SSLSTREAM *sslstream;		/* SSL stream */
+  int octr;			/* output counter */
+  char *optr;			/* output pointer */
+  char obuf[SSLBUFLEN];		/* output buffer */
+} SSLSTDIOSTREAM;
+
+
+/* Function prototypes */
+
+SSLSTREAM *ssl_open (char *host,char *service,unsigned long port);
+SSLSTREAM *ssl_aopen (NETMBX *mb,char *service,char *usrbuf);
+char *ssl_getline (SSLSTREAM *stream);
+long ssl_getbuffer (SSLSTREAM *stream,unsigned long size,char *buffer);
+long ssl_getdata (SSLSTREAM *stream);
+long ssl_soutr (SSLSTREAM *stream,char *string);
+long ssl_sout (SSLSTREAM *stream,char *string,unsigned long size);
+void ssl_close (SSLSTREAM *stream);
+char *ssl_host (SSLSTREAM *stream);
+char *ssl_remotehost (SSLSTREAM *stream);
+unsigned long ssl_port (SSLSTREAM *stream);
+char *ssl_localhost (SSLSTREAM *stream);
+long ssl_server_input_wait (long seconds);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/tcp.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,59 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	TCP/IP routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	31 January 2007
+ */
+
+
+/* Dummy definition overridden by TCP routines */
+
+#ifndef TCPSTREAM
+#define TCPSTREAM void
+#endif
+
+
+/* Function prototypes */
+
+void *tcp_parameters (long function,void *value);
+TCPSTREAM *tcp_open (char *host,char *service,unsigned long port);
+TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf);
+char *tcp_getline (TCPSTREAM *stream);
+long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer);
+long tcp_getdata (TCPSTREAM *stream);
+long tcp_soutr (TCPSTREAM *stream,char *string);
+long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size);
+void tcp_close (TCPSTREAM *stream);
+char *tcp_host (TCPSTREAM *stream);
+char *tcp_remotehost (TCPSTREAM *stream);
+unsigned long tcp_port (TCPSTREAM *stream);
+char *tcp_localhost (TCPSTREAM *stream);
+char *tcp_clientaddr (void);
+char *tcp_clienthost (void);
+long tcp_clientport (void);
+char *tcp_serveraddr (void);
+char *tcp_serverhost (void);
+long tcp_serverport (void);
+char *tcp_canonical (char *name);
+long tcp_isclienthost (char *host);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/utf8.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,2554 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UTF-8 routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 June 1997
+ * Last Edited:	17 January 2008
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include "c-client.h"
+
+/*	*** IMPORTANT ***
+ *
+ *  There is a very important difference between "character set" and "charset",
+ * and the comments in this file reflect these differences.  A "character set"
+ * (also known as "coded character set") is a mapping between codepoints and
+ * characters.  A "charset" is as defined in MIME, and incorporates one or more
+ * coded character sets in a character encoding scheme.  See RFC 2130 for more
+ * details.
+ */
+
+
+/* Character set conversion tables */
+
+#include "iso_8859.c"		/* 8-bit single-byte coded graphic */
+#include "koi8_r.c"		/* Cyrillic - Russia */
+#include "koi8_u.c"		/* Cyrillic - Ukraine */
+#include "tis_620.c"		/* Thai */
+#include "viscii.c"		/* Vietnamese */
+#include "windows.c"		/* Windows */
+#include "ibm.c"		/* IBM */
+#include "gb_2312.c"		/* Chinese (PRC) - simplified */
+#include "gb_12345.c"		/* Chinese (PRC) - traditional */
+#include "jis_0208.c"		/* Japanese - basic */
+#include "jis_0212.c"		/* Japanese - supplementary */
+#include "ksc_5601.c"		/* Korean */
+#include "big5.c"		/* Taiwanese (ROC) - industrial standard */
+#include "cns11643.c"		/* Taiwanese (ROC) - national standard */
+
+
+#include "widths.c"		/* Unicode character widths */
+#include "tmap.c"		/* Unicode titlecase mapping */
+#include "decomtab.c"		/* Unicode decomposions */
+
+/* EUC parameters */
+
+#ifdef GBTOUNICODE		/* PRC simplified Chinese */
+static const struct utf8_eucparam gb_param = {
+  BASE_GB2312_KU,BASE_GB2312_TEN,MAX_GB2312_KU,MAX_GB2312_TEN,
+  (void *) gb2312tab};
+#endif
+
+
+#ifdef GB12345TOUNICODE		/* PRC traditional Chinese */
+static const struct utf8_eucparam gbt_param = {
+  BASE_GB12345_KU,BASE_GB12345_TEN,MAX_GB12345_KU,MAX_GB12345_TEN,
+  (void *) gb12345tab};
+#endif
+
+
+#ifdef BIG5TOUNICODE		/* ROC traditional Chinese */
+static const struct utf8_eucparam big5_param[] = {
+  {BASE_BIG5_KU,BASE_BIG5_TEN_0,MAX_BIG5_KU,MAX_BIG5_TEN_0,(void *) big5tab},
+  {BASE_BIG5_KU,BASE_BIG5_TEN_1,MAX_BIG5_KU,MAX_BIG5_TEN_1,NIL}
+};
+#endif
+
+
+#ifdef JISTOUNICODE		/* Japanese */
+static const struct utf8_eucparam jis_param[] = {
+  {BASE_JIS0208_KU,BASE_JIS0208_TEN,MAX_JIS0208_KU,MAX_JIS0208_TEN,
+     (void *) jis0208tab},
+  {MIN_KANA_8,0,MAX_KANA_8,0,(void *) KANA_8},
+#ifdef JIS0212TOUNICODE		/* Japanese extended */
+  {BASE_JIS0212_KU,BASE_JIS0212_TEN,MAX_JIS0212_KU,MAX_JIS0212_TEN,
+     (void *) jis0212tab}
+#else
+  {0,0,0,0,NIL}
+#endif
+};
+#endif
+
+
+#ifdef KSCTOUNICODE		/* Korean */
+static const struct utf8_eucparam ksc_param = {
+  BASE_KSC5601_KU,BASE_KSC5601_TEN,MAX_KSC5601_KU,MAX_KSC5601_TEN,
+  (void *) ksc5601tab};
+#endif
+
+/* List of supported charsets */
+
+static const CHARSET utf8_csvalid[] = {
+  {"US-ASCII",CT_ASCII,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+   NIL,NIL,NIL},
+  {"UTF-8",CT_UTF8,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+   NIL,SC_UNICODE,NIL},
+  {"UTF-7",CT_UTF7,CF_PRIMARY | CF_POSTING | CF_UNSUPRT,
+   NIL,SC_UNICODE,"UTF-8"},
+  {"ISO-8859-1",CT_1BYTE0,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+   NIL,SC_LATIN_1,NIL},
+  {"ISO-8859-2",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+   (void *) iso8859_2tab,SC_LATIN_2,NIL},
+  {"ISO-8859-3",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+   (void *) iso8859_3tab,SC_LATIN_3,NIL},
+  {"ISO-8859-4",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+   (void *) iso8859_4tab,SC_LATIN_4,NIL},
+  {"ISO-8859-5",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+   (void *) iso8859_5tab,SC_CYRILLIC,"KOI8-R"},
+  {"ISO-8859-6",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+   (void *) iso8859_6tab,SC_ARABIC,NIL},
+  {"ISO-8859-7",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+   (void *) iso8859_7tab,SC_GREEK,NIL},
+  {"ISO-8859-8",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+   (void *) iso8859_8tab,SC_HEBREW,NIL},
+  {"ISO-8859-9",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+   (void *) iso8859_9tab,SC_LATIN_5,NIL},
+  {"ISO-8859-10",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+   (void *) iso8859_10tab,SC_LATIN_6,NIL},
+  {"ISO-8859-11",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+   (void *) iso8859_11tab,SC_THAI,NIL},
+#if 0				/* ISO 8859-12 reserved for ISCII(?) */
+  {"ISO-8859-12",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+   (void *) iso8859_12tab,NIL,NIL},
+#endif
+  {"ISO-8859-13",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+   (void *) iso8859_13tab,SC_LATIN_7,NIL},
+  {"ISO-8859-14",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+   (void *) iso8859_14tab,SC_LATIN_8,NIL},
+  {"ISO-8859-15",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+   (void *) iso8859_15tab,SC_LATIN_9,NIL},
+  {"ISO-8859-16",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+   (void *) iso8859_16tab,SC_LATIN_10,NIL},
+  {"KOI8-R",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+   (void *) koi8rtab,SC_CYRILLIC,NIL},
+  {"KOI8-U",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+   (void *) koi8utab,SC_CYRILLIC | SC_UKRANIAN,NIL},
+  {"KOI8-RU",CT_1BYTE,CF_DISPLAY,
+   (void *) koi8utab,SC_CYRILLIC | SC_UKRANIAN,"KOI8-U"},
+  {"TIS-620",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+   (void *) tis620tab,SC_THAI,"ISO-8859-11"},
+  {"VISCII",CT_1BYTE8,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+   (void *) visciitab,SC_VIETNAMESE,NIL},
+
+#ifdef GBTOUNICODE
+  {"GBK",CT_DBYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+     (void *) &gb_param,SC_CHINESE_SIMPLIFIED,NIL},
+  {"GB2312",CT_DBYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+   (void *) &gb_param,SC_CHINESE_SIMPLIFIED,"GBK"},
+  {"CN-GB",CT_DBYTE,CF_DISPLAY,
+     (void *) &gb_param,SC_CHINESE_SIMPLIFIED,"GBK"},
+#ifdef CNS1TOUNICODE
+  {"ISO-2022-CN",CT_2022,CF_PRIMARY | CF_UNSUPRT,
+     NIL,SC_CHINESE_SIMPLIFIED | SC_CHINESE_TRADITIONAL,
+   NIL},
+#endif
+#endif
+#ifdef GB12345TOUNICODE
+  {"CN-GB-12345",CT_DBYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) &gbt_param,SC_CHINESE_TRADITIONAL,"BIG5"},
+#endif
+#ifdef BIG5TOUNICODE
+  {"BIG5",CT_DBYTE2,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+     (void *) big5_param,SC_CHINESE_TRADITIONAL,NIL},
+  {"CN-BIG5",CT_DBYTE2,CF_DISPLAY,
+     (void *) big5_param,SC_CHINESE_TRADITIONAL,"BIG5"},
+  {"BIG-5",CT_DBYTE2,CF_DISPLAY,
+     (void *) big5_param,SC_CHINESE_TRADITIONAL,"BIG5"},
+#endif
+#ifdef JISTOUNICODE
+  {"ISO-2022-JP",CT_2022,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+     NIL,SC_JAPANESE,NIL},
+  {"EUC-JP",CT_EUC,CF_PRIMARY | CF_DISPLAY,
+     (void *) jis_param,SC_JAPANESE,"ISO-2022-JP"},
+  {"SHIFT_JIS",CT_SJIS,CF_PRIMARY | CF_DISPLAY,
+     NIL,SC_JAPANESE,"ISO-2022-JP"},
+  {"SHIFT-JIS",CT_SJIS,CF_PRIMARY | CF_DISPLAY,
+     NIL,SC_JAPANESE,"ISO-2022-JP"},
+#ifdef JIS0212TOUNICODE
+  {"ISO-2022-JP-1",CT_2022,CF_UNSUPRT,
+     NIL,SC_JAPANESE,"ISO-2022-JP"},
+#ifdef GBTOUNICODE
+#ifdef KSCTOUNICODE
+  {"ISO-2022-JP-2",CT_2022,CF_UNSUPRT,
+     NIL,
+     SC_LATIN_1 | SC_LATIN_2 | SC_LATIN_3 | SC_LATIN_4 | SC_LATIN_5 |
+       SC_LATIN_6 | SC_LATIN_7 | SC_LATIN_8 | SC_LATIN_9 | SC_LATIN_10 |
+	 SC_ARABIC | SC_CYRILLIC | SC_GREEK | SC_HEBREW | SC_THAI |
+	   SC_VIETNAMESE | SC_CHINESE_SIMPLIFIED | SC_JAPANESE | SC_KOREAN
+#ifdef CNS1TOUNICODE
+	     | SC_CHINESE_TRADITIONAL
+#endif
+	       ,"UTF-8"},
+#endif
+#endif
+#endif
+#endif
+
+#ifdef KSCTOUNICODE
+  {"ISO-2022-KR",CT_2022,CF_PRIMARY | CF_DISPLAY | CF_UNSUPRT,
+     NIL,SC_KOREAN,"EUC-KR"},
+  {"EUC-KR",CT_DBYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+     (void *) &ksc_param,SC_KOREAN,NIL},
+  {"KSC5601",CT_DBYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) &ksc_param,SC_KOREAN,"EUC-KR"},
+  {"KSC_5601",CT_DBYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) &ksc_param,SC_KOREAN,"EUC-KR"},
+  {"KS_C_5601-1987",CT_DBYTE,CF_DISPLAY,
+     (void *) &ksc_param,SC_KOREAN,"EUC-KR"},
+  {"KS_C_5601-1989",CT_DBYTE,CF_DISPLAY,
+     (void *) &ksc_param,SC_KOREAN,"EUC-KR"},
+  {"KS_C_5601-1992",CT_DBYTE,CF_DISPLAY,
+     (void *) &ksc_param,SC_KOREAN,"EUC-KR"},
+  {"KS_C_5601-1997",CT_DBYTE,CF_DISPLAY,
+     (void *) &ksc_param,SC_KOREAN,"EUC-KR"},
+#endif
+
+				/* deep sigh */
+  {"WINDOWS-874",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) windows_874tab,SC_THAI,"ISO-8859-11"},
+  {"CP874",CT_1BYTE,CF_DISPLAY,
+     (void *) windows_874tab,SC_THAI,"ISO-8859-11"},
+#ifdef GBTOUNICODE
+  {"WINDOWS-936",CT_DBYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) &gb_param,SC_CHINESE_SIMPLIFIED,"GBK"},
+  {"CP936",CT_DBYTE,CF_DISPLAY,
+     (void *) &gb_param,SC_CHINESE_SIMPLIFIED,"GBK"},
+#endif
+#ifdef KSCTOUNICODE
+  {"WINDOWS-949",CT_DBYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) &ksc_param,SC_KOREAN,"EUC-KR"},
+  {"CP949",CT_DBYTE,CF_DISPLAY,
+     (void *) &ksc_param,SC_KOREAN,"EUC-KR"},
+  {"X-WINDOWS-949",CT_DBYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) &ksc_param,SC_KOREAN,"EUC-KR"},
+#endif
+  {"WINDOWS-1250",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) windows_1250tab,SC_LATIN_2,"ISO-8859-2"},
+  {"CP1250",CT_1BYTE,CF_DISPLAY,
+     (void *) windows_1250tab,SC_LATIN_2,"ISO-8859-2"},
+  {"WINDOWS-1251",CT_1BYTE,CF_PRIMARY | CF_DISPLAY | CF_POSTING,
+     (void *) windows_1251tab,SC_CYRILLIC,"KOI8-R"},
+  {"CP1251",CT_1BYTE,CF_DISPLAY,
+     (void *) windows_1251tab,SC_CYRILLIC,"KOI8-R"},
+  {"WINDOWS-1252",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) windows_1252tab,SC_LATIN_1,"ISO-8859-1"},
+  {"CP1252",CT_1BYTE,CF_DISPLAY,
+     (void *) windows_1252tab,SC_LATIN_1,"ISO-8859-1"},
+  {"WINDOWS-1253",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) windows_1253tab,SC_GREEK,"ISO-8859-7"},
+  {"CP1253",CT_1BYTE,CF_DISPLAY,
+     (void *) windows_1253tab,SC_GREEK,"ISO-8859-7"},
+  {"WINDOWS-1254",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) windows_1254tab,SC_LATIN_5,"ISO-8859-9"},
+  {"CP1254",CT_1BYTE,CF_DISPLAY,
+     (void *) windows_1254tab,SC_LATIN_5,"ISO-8859-9"},
+  {"WINDOWS-1255",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) windows_1255tab,SC_HEBREW,"ISO-8859-8"},
+  {"CP1255",CT_1BYTE,CF_DISPLAY,
+     (void *) windows_1255tab,SC_HEBREW,"ISO-8859-8"},
+  {"WINDOWS-1256",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) windows_1256tab,SC_ARABIC,"ISO-8859-6"},
+  {"CP1256",CT_1BYTE,CF_DISPLAY,
+     (void *) windows_1256tab,SC_ARABIC,"ISO-8859-6"},
+  {"WINDOWS-1257",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) windows_1257tab,SC_LATIN_7,"ISO-8859-13"},
+  {"CP1257",CT_1BYTE,CF_DISPLAY,
+     (void *) windows_1257tab,SC_LATIN_7,"ISO-8859-13"},
+  {"WINDOWS-1258",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) windows_1258tab,SC_VIETNAMESE,"VISCII"},
+  {"CP1258",CT_1BYTE,CF_DISPLAY,
+     (void *) windows_1258tab,SC_VIETNAMESE,"VISCII"},
+
+				/* deeper sigh */
+  {"IBM367",CT_ASCII,CF_PRIMARY | CF_DISPLAY,
+     NIL,NIL,"US-ASCII"},
+  {"IBM437",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) ibm_437tab,SC_LATIN_1,"ISO-8859-1"},
+  {"IBM737",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) ibm_737tab,SC_GREEK,"ISO-8859-7"},
+  {"IBM775",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) ibm_775tab,SC_LATIN_7,"ISO-8859-13"},
+  {"IBM850",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) ibm_850tab,SC_LATIN_1,"ISO-8859-1"},
+  {"IBM852",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) ibm_852tab,SC_LATIN_2,"ISO-8859-2"},
+  {"IBM855",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) ibm_855tab,SC_CYRILLIC,"ISO-8859-5"},
+  {"IBM857",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) ibm_857tab,SC_LATIN_5,"ISO-8859-9"},
+  {"IBM860",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) ibm_860tab,SC_LATIN_1,"ISO-8859-1"},
+  {"IBM861",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) ibm_861tab,SC_LATIN_6,"ISO-8859-10"},
+  {"IBM862",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) ibm_862tab,SC_HEBREW,"ISO-8859-8"},
+  {"IBM863",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) ibm_863tab,SC_LATIN_1,"ISO-8859-1"},
+  {"IBM864",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) ibm_864tab,SC_ARABIC,"ISO-8859-6"},
+  {"IBM865",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) ibm_865tab,SC_LATIN_6,"ISO-8859-10"},
+  {"IBM866",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) ibm_866tab,SC_CYRILLIC,"KOI8-R"},
+  {"IBM869",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) ibm_869tab,SC_GREEK,"ISO-8859-7"},
+  {"IBM874",CT_1BYTE,CF_PRIMARY | CF_DISPLAY,
+     (void *) ibm_874tab,SC_THAI,"ISO-8859-11"},
+				/* deepest sigh */
+  {"ANSI_X3.4-1968",CT_ASCII,CF_DISPLAY,
+     NIL,NIL,"US-ASCII"},
+  {"UNICODE-1-1-UTF-7",CT_UTF7,CF_UNSUPRT,
+     NIL,SC_UNICODE,"UTF-8"},
+				/* these should never appear in email */
+  {"UCS-2",CT_UCS2,CF_PRIMARY | CF_DISPLAY | CF_NOEMAIL,
+     NIL,SC_UNICODE,"UTF-8"},
+  {"UCS-4",CT_UCS4,CF_PRIMARY | CF_DISPLAY | CF_NOEMAIL,
+     NIL,SC_UNICODE,"UTF-8"},
+  {"UTF-16",CT_UTF16,CF_PRIMARY | CF_DISPLAY | CF_NOEMAIL,
+     NIL,SC_UNICODE,"UTF-8"},
+  NIL
+};
+
+/* Non-Unicode Script table */
+
+static const SCRIPT utf8_scvalid[] = {
+  {"Arabic",NIL,SC_ARABIC},
+  {"Chinese Simplified","China, Singapore",SC_CHINESE_SIMPLIFIED},
+  {"Chinese Traditional","Taiwan, Hong Kong, Macao",SC_CHINESE_TRADITIONAL},
+  {"Cyrillic",NIL,SC_CYRILLIC},
+  {"Cyrillic Ukranian",NIL,SC_UKRANIAN},
+  {"Greek",NIL,SC_GREEK},
+  {"Hebrew",NIL,SC_HEBREW},
+  {"Japanese",NIL,SC_JAPANESE},
+  {"Korean",NIL,SC_KOREAN},
+  {"Latin-1","Western Europe",SC_LATIN_1},
+  {"Latin-2","Eastern Europe",SC_LATIN_2},
+  {"Latin-3","Southern Europe",SC_LATIN_3},
+  {"Latin-4","Northern Europe",SC_LATIN_4},
+  {"Latin-5","Turkish",SC_LATIN_5},
+  {"Latin-6","Nordic",SC_LATIN_6},
+  {"Latin-7","Baltic",SC_LATIN_7},
+  {"Latin-8","Celtic",SC_LATIN_8},
+  {"Latin-9","Euro",SC_LATIN_9},
+  {"Latin-10","Balkan",SC_LATIN_10},
+  {"Thai",NIL,SC_THAI},
+  {"Vietnamese",NIL,SC_VIETNAMESE},
+  NIL
+};
+
+/* Look up script name or return entire table
+ * Accepts: script name or NIL
+ * Returns: pointer to script table entry or NIL if unknown
+ */
+
+SCRIPT *utf8_script (char *script)
+{
+  unsigned long i;
+  if (!script) return (SCRIPT *) &utf8_scvalid[0];
+  else if (*script && (strlen (script) < 128))
+    for (i = 0; utf8_scvalid[i].name; i++)
+      if (!compare_cstring (script,utf8_scvalid[i].name))
+	return (SCRIPT *) &utf8_scvalid[i];
+  return NIL;			/* failed */
+}
+
+
+/* Look up charset name or return entire table
+ * Accepts: charset name or NIL
+ * Returns: charset table entry or NIL if unknown
+ */
+
+const CHARSET *utf8_charset (char *charset)
+{
+  unsigned long i;
+  if (!charset) return (CHARSET *) &utf8_csvalid[0];
+  else if (*charset && (strlen (charset) < 128))
+    for (i = 0; utf8_csvalid[i].name; i++)
+      if (!compare_cstring (charset,utf8_csvalid[i].name))
+	return (CHARSET *) &utf8_csvalid[i];
+  return NIL;			/* failed */
+}
+
+/* Validate charset and generate error message if invalid
+ * Accepts: bad character set
+ * Returns: NIL if good charset, else error message string
+ */
+
+#define BADCSS "[BADCHARSET ("
+#define BADCSE ")] Unknown charset: "
+
+char *utf8_badcharset (char *charset)
+{
+  char *msg = NIL;
+  if (!utf8_charset (charset)) {
+    char *s,*t;
+    unsigned long i,j;
+				/* calculate size of header, trailer, and bad
+				 * charset plus charset names */
+    for (i = 0, j = sizeof (BADCSS) + sizeof (BADCSE) + strlen (charset) - 2;
+	 utf8_csvalid[i].name; i++)
+      j += strlen (utf8_csvalid[i].name) + 1;
+				/* not built right */
+    if (!i) fatal ("No valid charsets!");
+				/* header */
+    for (s = msg = (char *) fs_get (j), t = BADCSS; *t; *s++ = *t++);
+				/* each charset */
+    for (i = 0; utf8_csvalid[i].name; *s++ = ' ', i++)
+      for (t = utf8_csvalid[i].name; *t; *s++ = *t++);
+				/* back over last space, trailer */
+    for (t = BADCSE, --s; *t; *s++ = *t++);
+				/* finally bogus charset */
+    for (t = charset; *t; *s++ = *t++);
+    *s++ = '\0';		/* finally tie off string */
+    if (s != (msg + j)) fatal ("charset msg botch");
+  }
+  return msg;
+}
+
+/* Convert charset labelled sized text to UTF-8
+ * Accepts: source sized text
+ *	    charset
+ *	    pointer to returned sized text if non-NIL
+ *	    flags
+ * Returns: T if successful, NIL if failure
+ */
+
+long utf8_text (SIZEDTEXT *text,char *charset,SIZEDTEXT *ret,long flags)
+{
+  ucs4cn_t cv = (flags & U8T_CASECANON) ? ucs4_titlecase : NIL;
+  ucs4de_t de = (flags & U8T_DECOMPOSE) ? ucs4_decompose_recursive : NIL;
+  const CHARSET *cs = (charset && *charset) ?
+    utf8_charset (charset) : utf8_infercharset (text);
+  if (cs) return (text && ret) ? utf8_text_cs (text,cs,ret,cv,de) : LONGT;
+  if (ret) {			/* no conversion possible */
+    ret->data = text->data;	/* so return source */
+    ret->size = text->size;
+  }
+  return NIL;			/* failure */
+}
+
+
+/* Operations used in converting data */
+
+#define UTF8_COUNT_BMP(count,c,cv,de) {		\
+  void *more = NIL;				\
+  if (cv) c = (*cv) (c);			\
+  if (de) c = (*de) (c,&more);			\
+  do count += UTF8_SIZE_BMP(c);			\
+  while (more && (c = (*de) (U8G_ERROR,&more)));\
+}
+
+#define UTF8_WRITE_BMP(b,c,cv,de) {		\
+  void *more = NIL;				\
+  if (cv) c = (*cv) (c);			\
+  if (de) c = (*de) (c,&more);			\
+  do UTF8_PUT_BMP (b,c)				\
+  while (more && (c = (*de) (U8G_ERROR,&more)));\
+}
+
+#define UTF8_COUNT(count,c,cv,de) {		\
+  void *more = NIL;				\
+  if (cv) c = (*cv) (c);			\
+  if (de) c = (*de) (c,&more);			\
+  do count += utf8_size (c);			\
+  while (more && (c = (*de) (U8G_ERROR,&more)));\
+}
+
+#define UTF8_WRITE(b,c,cv,de) {			\
+  void *more = NIL;				\
+  if (cv) c = (*cv) (c);			\
+  if (de) c = (*de) (c,&more);			\
+  do b = utf8_put (b,c);			\
+  while (more && (c = (*de) (U8G_ERROR,&more)));\
+}
+
+/* Convert sized text to UTF-8 given CHARSET block
+ * Accepts: source sized text
+ *	    CHARSET block
+ *	    pointer to returned sized text 
+ *	    canonicalization function
+ *	    decomposition function
+ * Returns: T if successful, NIL if failure
+ */
+
+long utf8_text_cs (SIZEDTEXT *text,const CHARSET *cs,SIZEDTEXT *ret,
+		   ucs4cn_t cv,ucs4de_t de)
+{
+  ret->data = text->data;	/* default to source */
+  ret->size = text->size;
+  switch (cs->type) {		/* convert if type known */
+  case CT_ASCII:		/* 7-bit ASCII no table */
+  case CT_UTF8:			/* variable UTF-8 encoded Unicode no table */
+    if (cv || de) utf8_text_utf8 (text,ret,cv,de);
+    break;
+  case CT_1BYTE0:		/* 1 byte no table */
+    utf8_text_1byte0 (text,ret,cv,de);
+    break;
+  case CT_1BYTE:		/* 1 byte ASCII + table 0x80-0xff */
+    utf8_text_1byte (text,ret,cs->tab,cv,de);
+    break;
+  case CT_1BYTE8:		/* 1 byte table 0x00 - 0xff */
+    utf8_text_1byte8 (text,ret,cs->tab,cv,de);
+    break;
+  case CT_EUC:			/* 2 byte ASCII + utf8_eucparam base/CS2/CS3 */
+    utf8_text_euc (text,ret,cs->tab,cv,de);
+    break;
+  case CT_DBYTE:		/* 2 byte ASCII + utf8_eucparam */
+    utf8_text_dbyte (text,ret,cs->tab,cv,de);
+    break;
+  case CT_DBYTE2:		/* 2 byte ASCII + utf8_eucparam plane1/2 */
+    utf8_text_dbyte2 (text,ret,cs->tab,cv,de);
+    break;
+  case CT_UTF7:			/* variable UTF-7 encoded Unicode no table */
+    utf8_text_utf7 (text,ret,cv,de);
+    break;
+  case CT_UCS2:			/* 2 byte 16-bit Unicode no table */
+    utf8_text_ucs2 (text,ret,cv,de);
+    break;
+  case CT_UCS4:			/* 4 byte 32-bit Unicode no table */
+    utf8_text_ucs4 (text,ret,cv,de);
+    break;
+  case CT_UTF16:		/* variable UTF-16 encoded Unicode no table */
+    utf8_text_utf16 (text,ret,cv,de);
+    break;
+  case CT_2022:			/* variable ISO-2022 encoded no table*/
+    utf8_text_2022 (text,ret,cv,de);
+    break;
+  case CT_SJIS:			/* 2 byte Shift-JIS encoded JIS no table */
+    utf8_text_sjis (text,ret,cv,de);
+    break;
+  default:			/* unknown character set type */
+    return NIL;
+  }
+  return LONGT;			/* return success */
+}
+
+/* Reverse mapping routines
+ *
+ * These routines only support character sets, not all possible charsets.  In
+ * particular, they do not support any Unicode encodings or ISO 2022.
+ *
+ * As a special dispensation, utf8_cstext() and utf8_cstocstext() support
+ * support ISO-2022-JP if EUC-JP can be reverse mapped; and utf8_rmaptext()
+ * will generated ISO-2022-JP using an EUC-JP rmap if flagged to do so.
+ *
+ * No attempt is made to map "equivalent" Unicode characters or Unicode
+ * characters that have the same glyph; nor is there any attempt to handle
+ * combining characters or otherwise do any stringprep.  Maybe later.
+ */
+
+
+/* Convert UTF-8 sized text to charset
+ * Accepts: source sized text
+ *	    destination charset
+ *	    pointer to returned sized text
+ *	    substitute character if not in cs, else NIL to return failure
+ * Returns: T if successful, NIL if failure
+ */
+
+
+long utf8_cstext (SIZEDTEXT *text,char *charset,SIZEDTEXT *ret,
+		  unsigned long errch)
+{
+  short iso2022jp = !compare_cstring (charset,"ISO-2022-JP");
+  unsigned short *rmap = utf8_rmap (iso2022jp ? "EUC-JP" : charset);
+  return rmap ? utf8_rmaptext (text,rmap,ret,errch,iso2022jp) : NIL;
+}
+
+/* Convert charset labelled sized text to another charset
+ * Accepts: source sized text
+ *	    source charset
+ *	    pointer to returned sized text
+ *	    destination charset
+ *	    substitute character if not in dest cs, else NIL to return failure
+ * Returns: T if successful, NIL if failure
+ *
+ * This routine has the same restricts as utf8_cstext().
+ */
+
+long utf8_cstocstext (SIZEDTEXT *src,char *sc,SIZEDTEXT *dst,char *dc,
+		      unsigned long errch)
+{
+  SIZEDTEXT utf8;
+  const CHARSET *scs,*dcs;
+  unsigned short *rmap;
+  long ret = NIL;
+  long iso2022jp;
+				/* lookup charsets and reverse map */
+  if ((dc && (dcs = utf8_charset (dc))) &&
+      (rmap = (iso2022jp = ((dcs->type == CT_2022) &&
+			    !compare_cstring (dcs->name,"ISO-2022-JP"))) ?
+       utf8_rmap ("EUC-JP") : utf8_rmap_cs (dcs)) &&
+      (scs = (sc && *sc) ? utf8_charset (sc) : utf8_infercharset (src))) {
+				/* init temporary buffer */
+    memset (&utf8,NIL,sizeof (SIZEDTEXT));
+				/* source cs equivalent to dest cs? */
+    if ((scs->type == dcs->type) && (scs->tab == dcs->tab)) {
+      dst->data = src->data;	/* yes, just copy pointers */
+      dst->size = src->size;
+      ret = LONGT;
+    }
+				/* otherwise do the conversion */
+    else ret = (utf8_text_cs (src,scs,&utf8,NIL,NIL) &&
+		utf8_rmaptext (&utf8,rmap,dst,errch,iso2022jp));
+				/* flush temporary buffer */
+    if (utf8.data && (utf8.data != src->data) && (utf8.data != dst->data))
+      fs_give ((void **) &utf8.data);
+  }
+  return ret;
+}
+
+/* Cached rmap */
+
+static const CHARSET *currmapcs = NIL;
+static unsigned short *currmap = NIL;
+
+
+/* Cache and return map for UTF-8 -> character set
+ * Accepts: character set name
+ * Returns: cached map if character set found, else NIL
+ */
+
+unsigned short *utf8_rmap (char *charset)
+{
+  return (currmapcs && !compare_cstring (charset,currmapcs->name)) ? currmap :
+    utf8_rmap_cs (utf8_charset (charset));
+}
+
+
+/* Cache and return map for UTF-8 -> character set given CHARSET block
+ * Accepts: CHARSET block
+ * Returns: cached map if character set found, else NIL
+ */
+
+unsigned short *utf8_rmap_cs (const CHARSET *cs)
+{
+  unsigned short *ret = NIL;
+  if (!cs);			/* have charset? */
+  else if (cs == currmapcs) ret = currmap;
+  else if (ret = utf8_rmap_gen (cs,currmap)) {
+    currmapcs = cs;
+    currmap = ret;
+  }
+  return ret;
+}
+
+/* Return map for UTF-8 -> character set given CHARSET block
+ * Accepts: CHARSET block
+ *	    old map to recycle
+ * Returns: map if character set found, else NIL
+ */
+
+unsigned short *utf8_rmap_gen (const CHARSET *cs,unsigned short *oldmap)
+{
+  unsigned short u,*tab,*rmap;
+  unsigned int i,m,ku,ten;
+  struct utf8_eucparam *param,*p2;
+  switch (cs->type) {		/* is a character set? */
+  case CT_ASCII:		/* 7-bit ASCII no table */
+  case CT_1BYTE0:		/* 1 byte no table */
+  case CT_1BYTE:		/* 1 byte ASCII + table 0x80-0xff */
+  case CT_1BYTE8:		/* 1 byte table 0x00 - 0xff */
+  case CT_EUC:			/* 2 byte ASCII + utf8_eucparam base/CS2/CS3 */
+  case CT_DBYTE:		/* 2 byte ASCII + utf8_eucparam */
+  case CT_DBYTE2:		/* 2 byte ASCII + utf8_eucparam plane1/2 */
+  case CT_SJIS:			/* 2 byte Shift-JIS */
+    rmap = oldmap ? oldmap :	/* recycle old map if supplied else make new */
+      (unsigned short *) fs_get (65536 * sizeof (unsigned short));
+				/* initialize table for ASCII */
+    for (i = 0; i < 128; i++) rmap[i] = (unsigned short) i;
+				/* populate remainder of table with NOCHAR */
+#define NOCHARBYTE (NOCHAR & 0xff)
+#if NOCHAR - ((NOCHARBYTE << 8) | NOCHARBYTE)
+    while (i < 65536) rmap[i++] = NOCHAR;
+#else
+    memset (rmap + 128,NOCHARBYTE,(65536 - 128) * sizeof (unsigned short));
+#endif
+    break;
+  default:			/* unsupported charset type */
+    rmap = NIL;			/* no map possible */
+  }
+  if (rmap) {			/* have a map? */
+    switch (cs->type) {		/* additional reverse map actions */
+    case CT_1BYTE0:		/* 1 byte no table */
+      for (i = 128; i < 256; i++) rmap[i] = (unsigned short) i;
+      break;
+    case CT_1BYTE:		/* 1 byte ASCII + table 0x80-0xff */
+      for (tab = (unsigned short *) cs->tab,i = 128; i < 256; i++)
+	if (tab[i & BITS7] != UBOGON) rmap[tab[i & BITS7]] = (unsigned short)i;
+      break;
+    case CT_1BYTE8:		/* 1 byte table 0x00 - 0xff */
+      for (tab = (unsigned short *) cs->tab,i = 0; i < 256; i++)
+	if (tab[i] != UBOGON) rmap[tab[i]] = (unsigned short) i;
+      break;
+    case CT_EUC:		/* 2 byte ASCII + utf8_eucparam base/CS2/CS3 */
+      for (param = (struct utf8_eucparam *) cs->tab,
+	     tab = (unsigned short *) param->tab, ku = 0;
+	   ku < param->max_ku; ku++)
+	for (ten = 0; ten < param->max_ten; ten++)
+	  if ((u = tab[(ku * param->max_ten) + ten]) != UBOGON)
+	    rmap[u] = ((ku + param->base_ku) << 8) +
+	      (ten + param->base_ten) + 0x8080;
+      break;
+
+    case CT_DBYTE:		/* 2 byte ASCII + utf8_eucparam */
+      for (param = (struct utf8_eucparam *) cs->tab,
+	     tab = (unsigned short *) param->tab, ku = 0;
+	   ku < param->max_ku; ku++)
+	for (ten = 0; ten < param->max_ten; ten++)
+	  if ((u = tab[(ku * param->max_ten) + ten]) != UBOGON)
+	    rmap[u] = ((ku + param->base_ku) << 8) + (ten + param->base_ten);
+      break;
+    case CT_DBYTE2:		/* 2 byte ASCII + utf8_eucparam plane1/2 */
+      param = (struct utf8_eucparam *) cs->tab;
+      p2 = param + 1;		/* plane 2 parameters */
+				/* only ten parameters should differ */
+      if ((param->base_ku != p2->base_ku) || (param->max_ku != p2->max_ku))
+	fatal ("ku definition error for CT_DBYTE2 charset");
+				/* total codepoints in each ku */
+      m = param->max_ten + p2->max_ten;
+      tab = (unsigned short *) param->tab;
+      for (ku = 0; ku < param->max_ku; ku++) {
+	for (ten = 0; ten < param->max_ten; ten++)
+	  if ((u = tab[(ku * m) + ten]) != UBOGON)
+	    rmap[u] = ((ku + param->base_ku) << 8) + (ten + param->base_ten);
+	for (ten = 0; ten < p2->max_ten; ten++)
+	  if ((u = tab[(ku * m) + param->max_ten + ten]) != UBOGON)
+	    rmap[u] = ((ku + param->base_ku) << 8) + (ten + p2->base_ten);
+      }
+      break;
+    case CT_SJIS:		/* 2 byte Shift-JIS */
+      for (ku = 0; ku < MAX_JIS0208_KU; ku++)
+	for (ten = 0; ten < MAX_JIS0208_TEN; ten++)
+	  if ((u = jis0208tab[ku][ten]) != UBOGON) {
+	    int sku = ku + BASE_JIS0208_KU;
+	    int sten = ten + BASE_JIS0208_TEN;
+	    rmap[u] = ((((sku + 1) >> 1) + ((sku < 95) ? 112 : 176)) << 8) +
+	      sten + ((sku % 2) ? ((sten > 95) ? 32 : 31) : 126);
+	  }
+				/* JIS Roman */
+      rmap[UCS2_YEN] = JISROMAN_YEN;
+      rmap[UCS2_OVERLINE] = JISROMAN_OVERLINE;
+				/* JIS hankaku katakana */
+      for (u = 0; u < (MAX_KANA_8 - MIN_KANA_8); u++)
+	rmap[UCS2_KATAKANA + u] = MIN_KANA_8 + u;
+      break;
+    }
+				/* hack: map NBSP to SP if otherwise no map */
+    if (rmap[0x00a0] == NOCHAR) rmap[0x00a0] = rmap[0x0020];
+  }
+  return rmap;			/* return map */
+}
+
+/* Convert UTF-8 sized text to charset using rmap
+ * Accepts: source sized text
+ *	    conversion rmap
+ *	    pointer to returned sized text
+ *	    substitute character if not in rmap, else NIL to return failure
+ *	    ISO-2022-JP conversion flag
+ * Returns T if successful, NIL if failure
+ *
+ * This routine doesn't try to convert to all possible charsets; in particular
+ * it doesn't support other Unicode encodings or any ISO 2022 other than
+ * ISO-2022-JP.
+ */
+
+long utf8_rmaptext (SIZEDTEXT *text,unsigned short *rmap,SIZEDTEXT *ret,
+		    unsigned long errch,long iso2022jp)
+{
+  unsigned long i,u,c;
+				/* get size of buffer */
+  if (i = utf8_rmapsize (text,rmap,errch,iso2022jp)) {
+    unsigned char *s = text->data;
+    unsigned char *t = ret->data = (unsigned char *) fs_get (i);
+    ret->size = i - 1;		/* number of octets in destination buffer */
+				/* start non-zero ISO-2022-JP state at 1 */
+    if (iso2022jp) iso2022jp = 1;
+				/* convert string, ignore BOM */
+    for (i = text->size; i;) if ((u = utf8_get (&s,&i)) != UCS2_BOM) {
+				/* substitute error character for NOCHAR */
+      if ((u & U8GM_NONBMP) || ((c = rmap[u]) == NOCHAR)) c = errch;
+      switch (iso2022jp) {	/* depends upon ISO 2022 mode */
+      case 0:			/* ISO 2022 not in effect */
+				/* two-byte character */
+	if (c > 0xff) *t++ = (unsigned char) (c >> 8);
+				/* single-byte or low-byte of two-byte */
+	*t++ = (unsigned char) (c & 0xff);
+	break;
+      case 1:			/* ISO 2022 Roman */
+				/* <ch> */
+	if (c < 0x80) *t++ = (unsigned char) c;
+	else {			/* JIS character */
+	  *t++ = I2C_ESC;	/* ESC $ B <hi> <lo> */
+	  *t++ = I2C_MULTI;
+	  *t++ = I2CS_94x94_JIS_NEW;
+	  *t++ = (unsigned char) (c >> 8) & 0x7f;
+	  *t++ = (unsigned char) c & 0x7f;
+	  iso2022jp = 2;	/* shift to ISO 2022 JIS */
+	}
+	break;
+      case 2:			/* ISO 2022 JIS */
+	if (c > 0x7f) {		/* <hi> <lo> */
+	  *t++ = (unsigned char) (c >> 8) & 0x7f;
+	  *t++ = (unsigned char) c & 0x7f;
+	}
+	else {			/* ASCII character */
+	  *t++ = I2C_ESC;	/* ESC ( J <ch> */
+	  *t++ = I2C_G0_94;
+	  *t++ = I2CS_94_JIS_ROMAN;
+	  *t++ = (unsigned char) c;
+	  iso2022jp = 1;	/* shift to ISO 2022 Roman */
+	}
+	break;
+      }
+    }
+    if (iso2022jp == 2) {	/* ISO-2022-JP string must end in Roman */
+      *t++ = I2C_ESC;		/* ESC ( J */
+      *t++ = I2C_G0_94;
+      *t++ = I2CS_94_JIS_ROMAN;
+    }
+    *t++ = NIL;			/* tie off returned data */
+    return LONGT;		/* return success */
+  }
+  ret->data = NIL;
+  ret->size = 0;
+  return NIL;			/* failure */
+}
+
+/* Calculate size of convertsion of UTF-8 sized text to charset using rmap
+ * Accepts: source sized text
+ *	    conversion rmap
+ *	    pointer to returned sized text
+ *	    substitute character if not in rmap, else NIL to return failure
+ *	    ISO-2022-JP conversion flag
+ * Returns size+1 if successful, NIL if failure
+ *
+ * This routine doesn't try to handle to all possible charsets; in particular
+ * it doesn't support other Unicode encodings or any ISO 2022 other than
+ * ISO-2022-JP.
+ */
+
+unsigned long utf8_rmapsize (SIZEDTEXT *text,unsigned short *rmap,
+			     unsigned long errch,long iso2022jp)
+{
+  unsigned long i,u,c;
+  unsigned long ret = 1;	/* terminating NUL */
+  unsigned char *s = text->data;
+  if (iso2022jp) iso2022jp = 1;	/* start non-zero ISO-2022-JP state at 1 */
+  for (i = text->size; i;) if ((u = utf8_get (&s,&i)) != UCS2_BOM) {
+    if ((u & U8GM_NONBMP) || (((c = rmap[u]) == NOCHAR) && !(c = errch)))
+      return NIL;		/* not in BMP, or NOCHAR and no err char */
+    switch (iso2022jp) {	/* depends upon ISO 2022 mode */
+    case 0:			/* ISO 2022 not in effect */
+      ret += (c > 0xff) ? 2 : 1;
+      break;
+    case 1:			/* ISO 2022 Roman */
+      if (c < 0x80) ret += 1;	/* <ch> */
+      else {			/* JIS character */
+	ret += 5;		/* ESC $ B <hi> <lo> */
+	iso2022jp = 2;		/* shift to ISO 2022 JIS */
+      }
+      break;
+    case 2:			/* ISO 2022 JIS */
+      if (c > 0x7f) ret += 2;	/* <hi> <lo> */
+      else {			/* ASCII character */
+	ret += 4;		/* ESC ( J <ch> */
+	iso2022jp = 1;		/* shift to ISO 2022 Roman */
+      }
+      break;
+    }
+  }
+  if (iso2022jp == 2) {		/* ISO-2022-JP string must end in Roman */
+    ret += 3;			/* ESC ( J */
+    iso2022jp = 1;		/* reset state to Roman */
+  }
+  return ret;
+}
+
+/* Convert UCS-4 to charset using rmap
+ * Accepts: source UCS-4 character(s)
+ *	    numver of UCS-4 characters
+ *	    conversion rmap
+ *	    pointer to returned sized text
+ *	    substitute character if not in rmap, else NIL to return failure
+ * Returns T if successful, NIL if failure
+ *
+ * Currently only supports BMP characters, and does not support ISO-2022
+ */
+
+long ucs4_rmaptext (unsigned long *ucs4,unsigned long len,unsigned short *rmap,
+		    SIZEDTEXT *ret,unsigned long errch)
+{
+  long size = ucs4_rmaplen (ucs4,len,rmap,errch);
+  return (size >= 0) ?		/* build in newly-created buffer */
+    ucs4_rmapbuf (ret->data = (unsigned char *) fs_get ((ret->size = size) +1),
+		  ucs4,len,rmap,errch) : NIL;
+}
+
+/* Return size of UCS-4 string converted to other CS via rmap
+ * Accepts: source UCS-4 character(s)
+ *	    numver of UCS-4 characters
+ *	    conversion rmap
+ *	    substitute character if not in rmap, else NIL to return failure
+ * Returns: length if success, negative if failure (no-convert)
+ */
+
+long ucs4_rmaplen (unsigned long *ucs4,unsigned long len,unsigned short *rmap,
+		   unsigned long errch)
+{
+  long ret;
+  unsigned long i,u,c;
+				/* count non-BOM characters */
+  for (ret = 0,i = 0; i < len; ++i) if ((u = ucs4[i]) != UCS2_BOM) {
+    if ((u & U8GM_NONBMP) || (((c = rmap[u]) == NOCHAR) && !(c = errch)))
+      return -1;		/* not in BMP, or NOCHAR and no err char? */
+    ret += (c > 0xff) ? 2 : 1;
+  }
+  return ret;
+}
+
+
+/* Stuff buffer with UCS-4 string converted to other CS via rmap
+ * Accepts: destination buffer
+ *	    source UCS-4 character(s)
+ *	    number of UCS-4 characters
+ *	    conversion rmap
+ *	    substitute character if not in rmap, else NIL to return failure
+ * Returns: T, always
+ */
+
+long ucs4_rmapbuf (unsigned char *t,unsigned long *ucs4,unsigned long len,
+		   unsigned short *rmap,unsigned long errch)
+{
+  unsigned long i,u,c;
+				/* convert non-BOM characters */
+  for (i = 0; i < len; ++i) if ((u = ucs4[i]) != UCS2_BOM) {
+				/* substitute error character for NOCHAR */
+    if ((u & U8GM_NONBMP) || ((c = rmap[u]) == NOCHAR)) c = errch;
+				/* two-byte character? */
+    if (c > 0xff) *t++ = (unsigned char) (c >> 8);
+				/* single-byte or low-byte of two-byte */
+    *t++ = (unsigned char) (c & 0xff);
+  }
+  *t++ = NIL;			/* tie off returned data */
+  return LONGT;
+}
+
+/* Return UCS-4 Unicode character from UTF-8 string
+ * Accepts: pointer to string
+ *	    remaining octets in string
+ * Returns: UCS-4 character with pointer and count updated
+ *	    or error code with pointer and count unchanged
+ */
+
+unsigned long utf8_get (unsigned char **s,unsigned long *i)
+{
+  unsigned char *t = *s;
+  unsigned long j = *i;
+				/* decode raw UTF-8 string */
+  unsigned long ret = utf8_get_raw (&t,&j);
+  if (ret & U8G_ERROR);		/* invalid raw UTF-8 decoding? */
+				/* no, is it surrogate? */
+  else if ((ret >= UTF16_SURR) && (ret <= UTF16_MAXSURR)) ret = U8G_SURROGA;
+				/* or in non-Unicode ISO 10646 space? */
+  else if (ret > UCS4_MAXUNICODE) ret = U8G_NOTUNIC;
+  else {
+    *s = t;			/* all is well, update pointer */
+    *i = j;			/* and counter */
+  }
+  return ret;			/* return value */
+}
+
+/* Return raw (including non-Unicode) UCS-4 character from UTF-8 string
+ * Accepts: pointer to string
+ *	    remaining octets in string
+ * Returns: UCS-4 character with pointer and count updated
+ *	    or error code with pointer and count unchanged
+ */
+
+unsigned long utf8_get_raw (unsigned char **s,unsigned long *i)
+{
+  unsigned char c,c1;
+  unsigned char *t = *s;
+  unsigned long j = *i;
+  unsigned long ret = U8G_NOTUTF8;
+  int more = 0;
+  do {				/* make sure have source octets available */
+    if (!j--) return more ? U8G_ENDSTRI : U8G_ENDSTRG;
+				/* UTF-8 continuation? */
+    else if (((c = *t++) > 0x7f) && (c < 0xc0)) {
+				/* continuation when not in progress */
+      if (!more) return U8G_BADCONT;
+      --more;			/* found a continuation octet */
+      ret <<= 6;		/* shift current value by 6 bits */
+      ret |= c & 0x3f;		/* merge continuation octet */
+    }
+				/* incomplete UTF-8 character */
+    else if (more) return U8G_INCMPLT;
+    else {			/* start of sequence */
+      c1 = j ? *t : 0xbf;	/* assume valid continuation if incomplete */
+      if (c < 0x80) ret = c;	/* U+0000 - U+007f */
+      else if (c < 0xc2);	/* c0 and c1 never valid */
+      else if (c < 0xe0) {	/* U+0080 - U+07ff */
+	if (c &= 0x1f) more = 1;
+      }
+      else if (c < 0xf0) {	/* U+0800 - U+ffff */
+	if ((c &= 0x0f) || (c1 >= 0xa0)) more = 2;
+      }
+      else if (c < 0xf8) {	/* U+10000 - U+10ffff (and 110000 - 1fffff) */
+	if ((c &= 0x07) || (c1 >= 0x90)) more = 3;
+      }
+      else if (c < 0xfc) {	/* ISO 10646 200000 - 3ffffff */
+	if ((c &= 0x03) || (c1 >= 0x88)) more = 4;
+      }
+      else if (c < 0xfe) {	/* ISO 10646 4000000 - 7fffffff */
+	if ((c &= 0x01) || (c1 >= 0x84)) more = 5;
+      }
+				/* fe and ff never valid */
+      if (more) {		/* multi-octet, make sure more to come */
+	if (!j) return U8G_ENDSTRI;
+	ret = c;		/* continuation needed, save start bits */
+      }
+    }
+  } while (more);
+  if (!(ret & U8G_ERROR)) {	/* success return? */
+    *s = t;			/* yes, update pointer */
+    *i = j;			/* and counter */
+  }
+  return ret;			/* return value */
+}
+
+/* Return UCS-4 character from named charset string
+ * Accepts: charset
+ *	    pointer to string
+ *	    remaining octets in string
+ * Returns: UCS-4 character with pointer and count updated, negative if error
+ *
+ * Error codes are the same as utf8_get().
+ */
+
+unsigned long ucs4_cs_get (CHARSET *cs,unsigned char **s,unsigned long *i)
+{
+  unsigned char c,c1,ku,ten;
+  unsigned long ret,d;
+  unsigned char *t = *s;
+  unsigned long j = *i;
+  struct utf8_eucparam *p1,*p2,*p3;
+  if (j--) c = *t++;		/* get first octet */
+  else return U8G_ENDSTRG;	/* empty string */
+  switch (cs->type) {		/* convert if type known */
+  case CT_UTF8:			/* variable UTF-8 encoded Unicode no table */
+    return utf8_get (s,i);
+  case CT_ASCII:		/* 7-bit ASCII no table */
+    if (c >= 0x80) return U8G_NOTUTF8;
+  case CT_1BYTE0:		/* 1 byte no table */
+    ret = c;			/* identity */
+    break;
+  case CT_1BYTE:		/* 1 byte ASCII + table 0x80-0xff */
+    ret = (c > 0x80) ? ((unsigned short *) cs->tab)[c & BITS7] : c;
+    break;
+  case CT_1BYTE8:		/* 1 byte table 0x00 - 0xff */
+    ret = ((unsigned short *) cs->tab)[c];
+    break;
+
+  case CT_EUC:			/* 2 byte ASCII + utf8_eucparam base/CS2/CS3 */
+    if (c & BIT8) {
+      p1 = (struct utf8_eucparam *) cs->tab;
+      p2 = p1 + 1;
+      p3 = p1 + 2;
+      if (j--) c1 = *t++;	/* get second octet */
+      else return U8G_ENDSTRI;
+      if (!(c1 & BIT8)) return U8G_NOTUTF8;
+      switch (c) {		/* check 8bit code set */
+      case EUC_CS2:		/* CS2 */
+	if (p2->base_ku) {	/* CS2 set up? */
+	  if (p2->base_ten) {	/* yes, multibyte? */
+	    if (j--) c = *t++;	/* get second octet */
+	    else return U8G_ENDSTRI;
+	    if ((c & BIT8) &&
+		((ku = (c1 & BITS7) - p2->base_ku) < p2->max_ku) &&
+		((ten = (c & BITS7) - p2->base_ten) < p2->max_ten)) {
+	      ret = ((unsigned short *) p2->tab)[(ku*p2->max_ten) + ten];
+	      break;
+	    }
+	  }
+	  else if ((c1 >= p2->base_ku) && (c1 < p2->max_ku)) {
+	    ret = c1 + ((unsigned long) p2->tab);
+	    break;
+	  }
+	}
+	return U8G_NOTUTF8;	/* CS2 not set up or bogus */
+      case EUC_CS3:		/* CS3 */
+	if (p3->base_ku) {	/* CS3 set up? */
+	  if (p3->base_ten) {	/* yes, multibyte? */
+	    if (j--) c = *t++;	/* get second octet */
+	    else return U8G_ENDSTRI;
+	    if ((c & BIT8) &&
+		((ku = (c1 & BITS7) - p3->base_ku) < p3->max_ku) &&
+		((ten = (c & BITS7) - p3->base_ten) < p3->max_ten)) {
+	      ret = ((unsigned short *) p3->tab)[(ku*p3->max_ten) + ten];
+	      break;
+	    }
+	  }
+	  else if ((c1 >= p3->base_ku) && (c1 < p3->max_ku)) {
+	    ret = c1 + ((unsigned long) p3->tab);
+	    break;
+	  }
+	}
+	return U8G_NOTUTF8;	/* CS3 not set up or bogus */
+      default:
+	if (((ku = (c & BITS7) - p1->base_ku) >= p1->max_ku) ||
+	    ((ten = (c1 & BITS7) - p1->base_ten) >= p1->max_ten))
+	  return U8G_NOTUTF8;
+	ret = ((unsigned short *) p1->tab)[(ku*p1->max_ten) + ten];
+		/* special hack for JIS X 0212: merge rows less than 10 */
+	if ((ret == UBOGON) && ku && (ku < 10) && p3->tab && p3->base_ten)
+	  ret = ((unsigned short *) p3->tab)
+	    [((ku - (p3->base_ku - p1->base_ku))*p3->max_ten) + ten];
+	break;
+      }
+    }
+    else ret = c;		/* ASCII character */
+    break;
+
+  case CT_DBYTE:		/* 2 byte ASCII + utf8_eucparam */
+    if (c & BIT8) {		/* double-byte character? */
+      p1 = (struct utf8_eucparam *) cs->tab;
+      if (j--) c1 = *t++;	/* get second octet */
+      else return U8G_ENDSTRI;
+      if (((ku = c - p1->base_ku) < p1->max_ku) &&
+	  ((ten = c1 - p1->base_ten) < p1->max_ten))
+	ret = ((unsigned short *) p1->tab)[(ku*p1->max_ten) + ten];
+      else return U8G_NOTUTF8;
+    }
+    else ret = c;		/* ASCII character */
+    break;
+  case CT_DBYTE2:		/* 2 byte ASCII + utf8_eucparam plane1/2 */
+    if (c & BIT8) {		/* double-byte character? */
+      p1 = (struct utf8_eucparam *) cs->tab;
+      p2 = p1 + 1;
+      if (j--) c1 = *t++;	/* get second octet */
+      else return U8G_ENDSTRI;
+      if (c1 & BIT8) {		/* high vs. low plane */
+	if ((ku = c - p2->base_ku) < p2->max_ku &&
+	    ((ten = c1 - p2->base_ten) < p2->max_ten))
+	  ret = ((unsigned short *) p1->tab)
+	    [(ku*(p1->max_ten + p2->max_ten)) + p1->max_ten + ten];
+	else return U8G_NOTUTF8;
+      }
+      else if ((ku = c - p1->base_ku) < p1->max_ku &&
+	       ((ten = c1 - p1->base_ten) < p1->max_ten))
+	  ret = ((unsigned short *) p1->tab)
+	    [(ku*(p1->max_ten + p2->max_ten)) + ten];
+      else return U8G_NOTUTF8;
+    }
+    else ret = c;		/* ASCII character */
+    break;
+  case CT_SJIS:			/* 2 byte Shift-JIS encoded JIS no table */
+				/* compromise - do yen sign but not overline */
+    if (!(c & BIT8)) ret = (c == JISROMAN_YEN) ? UCS2_YEN : c;
+				/* half-width katakana? */
+    else if ((c >= MIN_KANA_8) && (c < MAX_KANA_8)) ret = c + KANA_8;
+    else {			/* Shift-JIS */
+      if (j--) c1 = *t++;	/* get second octet */
+      else return U8G_ENDSTRI;
+      SJISTOJIS (c,c1);
+      c = JISTOUNICODE (c,c1,ku,ten);
+    }
+    break;
+
+  case CT_UCS2:			/* 2 byte 16-bit Unicode no table */
+    ret = c << 8;
+    if (j--) c = *t++;		/* get second octet */
+    else return U8G_ENDSTRI;	/* empty string */
+    ret |= c;
+    break;
+  case CT_UCS4:			/* 4 byte 32-bit Unicode no table */
+    if (c & 0x80) return U8G_NOTUTF8;
+    if (j < 3) return U8G_ENDSTRI;
+    j -= 3;			/* count three octets */
+    ret = c << 24;
+    ret |= (*t++) << 16;
+    ret |= (*t++) << 8;
+    ret |= (*t++);
+    break;
+  case CT_UTF16:		/* variable UTF-16 encoded Unicode no table */
+    ret = c << 8;
+    if (j--) c = *t++;		/* get second octet */
+    else return U8G_ENDSTRI;	/* empty string */
+    ret |= c;
+				/* surrogate? */
+    if ((ret >= UTF16_SURR) && (ret <= UTF16_MAXSURR)) {
+				/* invalid first surrogate */
+      if ((ret > UTF16_SURRHEND) || (j < 2)) return U8G_NOTUTF8;
+      j -= 2;			/* count two octets */
+      d = (*t++) << 8;		/* first octet of second surrogate */
+      d |= *t++;		/* second octet of second surrogate */
+      if ((d < UTF16_SURRL) || (d > UTF16_SURRLEND)) return U8G_NOTUTF8;
+      ret = UTF16_BASE + ((ret & UTF16_MASK) << UTF16_SHIFT) +
+	(d & UTF16_MASK);
+    }
+    break;
+  default:			/* unknown/unsupported character set type */
+    return U8G_NOTUTF8;
+  }
+  *s = t;			/* update pointer and counter */
+  *i = j;
+  return ret;
+}
+
+/* Produce charset validity map for BMP
+ * Accepts: list of charsets to map
+ * Returns: validity map, indexed by BMP codepoint
+ *
+ * Bit 0x1 is the "not-CJK" character bit
+ */
+
+unsigned long *utf8_csvalidmap (char *charsets[])
+{
+  unsigned short u,*tab;
+  unsigned int m,ku,ten;
+  unsigned long i,csi,csb;
+  struct utf8_eucparam *param,*p2;
+  char *s;
+  const CHARSET *cs;
+  unsigned long *ret = (unsigned long *)
+    fs_get (i = 0x10000 * sizeof (unsigned long));
+  memset (ret,0,i);		/* zero the entire vector */
+				/* mark all the non-CJK codepoints */
+	/* U+0000 - U+2E7F non-CJK */
+  for (i = 0; i < 0x2E7F; ++i) ret[i] = 0x1;
+	/* U+2E80 - U+2EFF CJK Radicals Supplement
+	 * U+2F00 - U+2FDF Kangxi Radicals
+	 * U+2FE0 - U+2FEF unassigned
+	 * U+2FF0 - U+2FFF Ideographic Description Characters
+	 * U+3000 - U+303F CJK Symbols and Punctuation
+	 * U+3040 - U+309F Hiragana
+	 * U+30A0 - U+30FF Katakana
+	 * U+3100 - U+312F BoPoMoFo
+	 * U+3130 - U+318F Hangul Compatibility Jamo
+	 * U+3190 - U+319F Kanbun
+	 * U+31A0 - U+31BF BoPoMoFo Extended
+	 * U+31C0 - U+31EF CJK Strokes
+	 * U+31F0 - U+31FF Katakana Phonetic Extensions
+	 * U+3200 - U+32FF Enclosed CJK Letters and Months
+	 * U+3300 - U+33FF CJK Compatibility
+	 * U+3400 - U+4DBF CJK Unified Ideographs Extension A
+	 * U+4DC0 - U+4DFF Yijing Hexagram Symbols
+	 * U+4E00 - U+9FFF CJK Unified Ideographs
+	 * U+A000 - U+A48F Yi Syllables
+	 * U+A490 - U+A4CF Yi Radicals
+	 * U+A700 - U+A71F Modifier Tone Letters
+	 */
+  for (i = 0xa720; i < 0xabff; ++i) ret[i] = 0x1;
+	/* U+AC00 - U+D7FF Hangul Syllables */
+  for (i = 0xd800; i < 0xf8ff; ++i) ret[i] = 0x1;
+	/* U+F900 - U+FAFF CJK Compatibility Ideographs */
+  for (i = 0xfb00; i < 0xfe2f; ++i) ret[i] = 0x1;
+	/* U+FE30 - U+FE4F CJK Compatibility Forms
+	 * U+FE50 - U+FE6F Small Form Variants (for CNS 11643)
+	 */
+  for (i = 0xfe70; i < 0xfeff; ++i) ret[i] = 0x1;
+	/* U+FF00 - U+FFEF CJK Compatibility Ideographs */
+  for (i = 0xfff0; i < 0x10000; ++i) ret[i] = 0x1;
+
+				/* for each supplied charset */
+  for (csi = 1; ret && charsets && (s = charsets[csi - 1]); ++csi) {
+				/* substitute EUC-JP for ISO-2022-JP */
+    if (!compare_cstring (s,"ISO-2022-JP")) s = "EUC-JP";
+				/* look up charset */
+    if (cs = utf8_charset (s)) {
+      csb = 1 << csi;		/* charset bit */
+      switch (cs->type) {
+      case CT_ASCII:		/* 7-bit ASCII no table */
+      case CT_1BYTE0:		/* 1 byte no table */
+      case CT_1BYTE:		/* 1 byte ASCII + table 0x80-0xff */
+      case CT_1BYTE8:		/* 1 byte table 0x00 - 0xff */
+      case CT_EUC:		/* 2 byte ASCII + utf8_eucparam base/CS2/CS3 */
+      case CT_DBYTE:		/* 2 byte ASCII + utf8_eucparam */
+      case CT_DBYTE2:		/* 2 byte ASCII + utf8_eucparam plane1/2 */
+      case CT_SJIS:		/* 2 byte Shift-JIS */
+				/* supported charset type, all ASCII is OK */
+	for (i = 0; i < 128; ++i) ret[i] |= csb;
+	break;
+      default:			/* unsupported charset type */
+	fs_give ((void **) &ret);
+	break;
+      }
+				/* now do additional operations */
+      if (ret) switch (cs->type) {
+      case CT_1BYTE0:		/* 1 byte no table */
+	for (i = 128; i < 256; i++) ret[i] |= csb;
+	break;
+      case CT_1BYTE:		/* 1 byte ASCII + table 0x80-0xff */
+	for (tab = (unsigned short *) cs->tab,i = 128; i < 256; i++)
+	  if (tab[i & BITS7] != UBOGON) ret[tab[i & BITS7]] |= csb;
+	break;
+      case CT_1BYTE8:		/* 1 byte table 0x00 - 0xff */
+	for (tab = (unsigned short *) cs->tab,i = 0; i < 256; i++)
+	  if (tab[i] != UBOGON) ret[tab[i]] |= csb;
+      break;
+      case CT_EUC:		/* 2 byte ASCII + utf8_eucparam base/CS2/CS3 */
+	for (param = (struct utf8_eucparam *) cs->tab,
+	       tab = (unsigned short *) param->tab, ku = 0;
+	     ku < param->max_ku; ku++)
+	  for (ten = 0; ten < param->max_ten; ten++)
+	    if ((u = tab[(ku * param->max_ten) + ten]) != UBOGON)
+	      ret[u] |= csb;
+	break;
+
+      case CT_DBYTE:		/* 2 byte ASCII + utf8_eucparam */
+	for (param = (struct utf8_eucparam *) cs->tab,
+	       tab = (unsigned short *) param->tab, ku = 0;
+	     ku < param->max_ku; ku++)
+	  for (ten = 0; ten < param->max_ten; ten++)
+	    if ((u = tab[(ku * param->max_ten) + ten]) != UBOGON)
+	      ret[u] |= csb;
+      break;
+      case CT_DBYTE2:		/* 2 byte ASCII + utf8_eucparam plane1/2 */
+	param = (struct utf8_eucparam *) cs->tab;
+	p2 = param + 1;		/* plane 2 parameters */
+				/* only ten parameters should differ */
+	if ((param->base_ku != p2->base_ku) || (param->max_ku != p2->max_ku))
+	  fatal ("ku definition error for CT_DBYTE2 charset");
+				/* total codepoints in each ku */
+	m = param->max_ten + p2->max_ten;
+	tab = (unsigned short *) param->tab;
+	for (ku = 0; ku < param->max_ku; ku++) {
+	  for (ten = 0; ten < param->max_ten; ten++)
+	    if ((u = tab[(ku * m) + ten]) != UBOGON)
+	      ret[u] |= csb;
+	  for (ten = 0; ten < p2->max_ten; ten++)
+	    if ((u = tab[(ku * m) + param->max_ten + ten]) != UBOGON)
+	      ret[u] |= csb;
+	}
+	break;
+      case CT_SJIS:		/* 2 byte Shift-JIS */
+	for (ku = 0; ku < MAX_JIS0208_KU; ku++)
+	  for (ten = 0; ten < MAX_JIS0208_TEN; ten++)
+	    if ((u = jis0208tab[ku][ten]) != UBOGON) ret[u] |= csb;
+				/* JIS hankaku katakana */
+	for (u = 0; u < (MAX_KANA_8 - MIN_KANA_8); u++)
+	  ret[UCS2_KATAKANA + u] |= csb;
+	break;
+      }
+    }
+				/* invalid charset, punt */
+    else fs_give ((void **) &ret);
+  }
+  return ret;
+}
+
+/* Infer charset from unlabelled sized text
+ * Accepts: sized text
+ * Returns: charset if one inferred, or NIL if unknown
+ */
+
+const CHARSET *utf8_infercharset (SIZEDTEXT *src)
+{
+  long iso2022jp = NIL;
+  long eightbit = NIL;
+  unsigned long i;
+				/* look for ISO 2022 */
+  if (src) for (i = 0; i < src->size; i++) {
+				/* ESC sequence? */
+    if ((src->data[i] == I2C_ESC) && (++i < src->size)) switch (src->data[i]) {
+    case I2C_MULTI:		/* yes, multibyte? */
+      if (++i < src->size) switch (src->data[i]) {
+      case I2CS_94x94_JIS_OLD:	/* JIS X 0208-1978 */
+      case I2CS_94x94_JIS_NEW:	/* JIS X 0208-1983 */
+      case I2CS_94x94_JIS_EXT:	/* JIS X 0212-1990 (kludge...) */
+	iso2022jp = T;		/* found an ISO-2022-JP sequence */
+	break;
+      default:			/* other multibyte */
+	return NIL;		/* definitely invalid */
+      }
+      break;
+    case I2C_G0_94:		/* single byte */
+      if (++i < src->size) switch (src->data[i]) {
+      case I2CS_94_JIS_BUGROM:	/* in case old buggy software */
+      case I2CS_94_JIS_ROMAN:	/* JIS X 0201-1976 left half */
+      case I2CS_94_ASCII:	/* ASCII */
+      case I2CS_94_BRITISH:	/* good enough for gov't work */
+	break;
+      default:			/* other 94 single byte */
+	return NIL;		/* definitely invalid */
+      }
+    }
+				/* if possible UTF-8 and not ISO-2022-JP */
+    else if (!iso2022jp && (eightbit >= 0) && (src->data[i] & BIT8) &&
+	     (eightbit = utf8_validate (src->data + i,src->size - i)) > 0)
+      i += eightbit - 1;	/* skip past all but last of UTF-8 char */
+  }
+				/* ISO-2022-JP overrides other guesses */
+  if (iso2022jp) return utf8_charset ("ISO-2022-JP");
+  if (eightbit > 0) return utf8_charset ("UTF-8");
+  return eightbit ? NIL : utf8_charset ("US-ASCII");
+}
+
+
+/* Validate that character at this position is UTF-8
+ * Accepts: string pointer
+ *	    size of remaining string
+ * Returns: size of UTF-8 character in octets or -1 if not UTF-8
+ */
+
+long utf8_validate (unsigned char *s,unsigned long i)
+{
+  unsigned long j = i;
+  return (utf8_get (&s,&i) & U8G_ERROR) ? -1 : j - i;
+}
+
+/* Convert ISO 8859-1 to UTF-8
+ * Accepts: source sized text
+ *	    pointer to return sized text
+ *	    canonicalization function
+ */
+
+void utf8_text_1byte0 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de)
+{
+  unsigned long i;
+  unsigned char *s;
+  unsigned int c;
+  for (ret->size = i = 0; i < text->size;) {
+    c = text->data[i++];
+    UTF8_COUNT_BMP (ret->size,c,cv,de)
+  }
+  (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] =NIL;
+  for (i = 0; i < text->size;) {
+    c = text->data[i++];
+    UTF8_WRITE_BMP (s,c,cv,de)	/* convert UCS-2 to UTF-8 */
+  }
+}
+
+
+/* Convert single byte ASCII+8bit character set sized text to UTF-8
+ * Accepts: source sized text
+ *	    pointer to return sized text
+ *	    conversion table
+ *	    canonicalization function
+ */
+
+void utf8_text_1byte (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv,
+		      ucs4de_t de)
+{
+  unsigned long i;
+  unsigned char *s;
+  unsigned int c;
+  unsigned short *tbl = (unsigned short *) tab;
+  for (ret->size = i = 0; i < text->size;) {
+    if ((c = text->data[i++]) & BIT8) c = tbl[c & BITS7];
+    UTF8_COUNT_BMP (ret->size,c,cv,de)
+  }
+  (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] =NIL;
+  for (i = 0; i < text->size;) {
+    if ((c = text->data[i++]) & BIT8) c = tbl[c & BITS7];
+    UTF8_WRITE_BMP (s,c,cv,de)	/* convert UCS-2 to UTF-8 */
+  }
+}
+
+/* Convert single byte 8bit character set sized text to UTF-8
+ * Accepts: source sized text
+ *	    pointer to return sized text
+ *	    conversion table
+ *	    canonicalization function
+ */
+
+void utf8_text_1byte8 (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv,
+		       ucs4de_t de)
+{
+  unsigned long i;
+  unsigned char *s;
+  unsigned int c;
+  unsigned short *tbl = (unsigned short *) tab;
+  for (ret->size = i = 0; i < text->size;) {
+    c = tbl[text->data[i++]];
+    UTF8_COUNT_BMP (ret->size,c,cv,de)
+  }
+  (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] =NIL;
+  for (i = 0; i < text->size;) {
+    c = tbl[text->data[i++]];
+    UTF8_WRITE_BMP (s,c,cv,de)	/* convert UCS-2 to UTF-8 */
+  }
+}
+
+/* Convert EUC sized text to UTF-8
+ * Accepts: source sized text
+ *	    pointer to return sized text
+ *	    EUC parameter table
+ *	    canonicalization function
+ */
+
+void utf8_text_euc (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv,
+		    ucs4de_t de)
+{
+  unsigned long i;
+  unsigned char *s;
+  unsigned int pass,c,c1,ku,ten;
+  struct utf8_eucparam *p1 = (struct utf8_eucparam *) tab;
+  struct utf8_eucparam *p2 = p1 + 1;
+  struct utf8_eucparam *p3 = p1 + 2;
+  unsigned short *t1 = (unsigned short *) p1->tab;
+  unsigned short *t2 = (unsigned short *) p2->tab;
+  unsigned short *t3 = (unsigned short *) p3->tab;
+  for (pass = 0,s = NIL,ret->size = 0; pass <= 1; pass++) {
+    for (i = 0; i < text->size;) {
+				/* not CS0? */
+      if ((c = text->data[i++]) & BIT8) {
+				/* yes, must have another high byte */
+	if ((i >= text->size) || !((c1 = text->data[i++]) & BIT8))
+	  c = UBOGON;		/* out of space or bogon */
+	else switch (c) {	/* check 8bit code set */
+	case EUC_CS2:		/* CS2 */
+	  if (p2->base_ku) {	/* CS2 set up? */
+	    if (p2->base_ten)	/* yes, multibyte? */
+	      c = ((i < text->size) && ((c = text->data[i++]) & BIT8) &&
+		   ((ku = (c1 & BITS7) - p2->base_ku) < p2->max_ku) &&
+		   ((ten = (c & BITS7) - p2->base_ten) < p2->max_ten)) ?
+		     t2[(ku*p2->max_ten) + ten] : UBOGON;
+	    else c = ((c1 >= p2->base_ku) && (c1 < p2->max_ku)) ?
+	      c1 + ((unsigned long) p2->tab) : UBOGON;
+	  }	  
+	  else {		/* CS2 not set up */
+	    c = UBOGON;		/* swallow byte, say bogon */
+	    if (i < text->size) i++;
+	  }
+	  break;
+	case EUC_CS3:		/* CS3 */
+	  if (p3->base_ku) {	/* CS3 set up? */
+	    if (p3->base_ten)	/* yes, multibyte? */
+	      c = ((i < text->size) && ((c = text->data[i++]) & BIT8) &&
+		   ((ku = (c1 & BITS7) - p3->base_ku) < p3->max_ku) &&
+		   ((ten = (c & BITS7) - p3->base_ten) < p3->max_ten)) ?
+		     t3[(ku*p3->max_ten) + ten] : UBOGON;
+	    else c = ((c1 >= p3->base_ku) && (c1 < p3->max_ku)) ?
+	      c1 + ((unsigned long) p3->tab) : UBOGON;
+	  }	  
+	  else {		/* CS3 not set up */
+	    c = UBOGON;		/* swallow byte, say bogon */
+	    if (i < text->size) i++;
+	  }
+	  break;
+
+	default:
+	  if (((ku = (c & BITS7) - p1->base_ku) >= p1->max_ku) ||
+	      ((ten = (c1 & BITS7) - p1->base_ten) >= p1->max_ten)) c = UBOGON;
+	  else if (((c = t1[(ku*p1->max_ten) + ten]) == UBOGON) &&
+		   /* special hack for JIS X 0212: merge rows less than 10 */
+		   ku && (ku < 10) && t3 && p3->base_ten)
+	    c = t3[((ku - (p3->base_ku - p1->base_ku))*p3->max_ten) + ten];
+	}
+      }
+				/* convert if second pass */
+      if (pass) UTF8_WRITE_BMP (s,c,cv,de)
+      else UTF8_COUNT_BMP (ret->size,c,cv,de);
+    }
+    if (!pass) (s = ret->data = (unsigned char *)
+		fs_get (ret->size + 1))[ret->size] =NIL;
+  }
+}
+
+
+/* Convert ASCII + double-byte sized text to UTF-8
+ * Accepts: source sized text
+ *	    pointer to return sized text
+ *	    conversion table
+ *	    canonicalization function
+ */
+
+void utf8_text_dbyte (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv,
+		      ucs4de_t de)
+{
+  unsigned long i;
+  unsigned char *s;
+  unsigned int c,c1,ku,ten;
+  struct utf8_eucparam *p1 = (struct utf8_eucparam *) tab;
+  unsigned short *t1 = (unsigned short *) p1->tab;
+  for (ret->size = i = 0; i < text->size;) {
+    if ((c = text->data[i++]) & BIT8) {
+				/* special hack for GBK: 0x80 is Euro */
+      if ((c == 0x80) && (t1 == (unsigned short *) gb2312tab)) c = UCS2_EURO;
+      else c = ((i < text->size) && (c1 = text->data[i++]) &&
+		((ku = c - p1->base_ku) < p1->max_ku) &&
+		((ten = c1 - p1->base_ten) < p1->max_ten)) ?
+	     t1[(ku*p1->max_ten) + ten] : UBOGON;
+    }
+    UTF8_COUNT_BMP (ret->size,c,cv,de)
+  }
+  (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] = NIL;
+  for (i = 0; i < text->size;) {
+    if ((c = text->data[i++]) & BIT8) {
+				/* special hack for GBK: 0x80 is Euro */
+      if ((c == 0x80) && (t1 == (unsigned short *) gb2312tab)) c = UCS2_EURO;
+      else c = ((i < text->size) && (c1 = text->data[i++]) &&
+		((ku = c - p1->base_ku) < p1->max_ku) &&
+		((ten = c1 - p1->base_ten) < p1->max_ten)) ?
+	     t1[(ku*p1->max_ten) + ten] : UBOGON;
+    }
+    UTF8_WRITE_BMP (s,c,cv,de)	/* convert UCS-2 to UTF-8 */
+  }
+}
+
+/* Convert ASCII + double byte 2 plane sized text to UTF-8
+ * Accepts: source sized text
+ *	    pointer to return sized text
+ *	    conversion table
+ *	    canonicalization function
+ */
+
+void utf8_text_dbyte2 (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv,
+		       ucs4de_t de)
+{
+  unsigned long i;
+  unsigned char *s;
+  unsigned int c,c1,ku,ten;
+  struct utf8_eucparam *p1 = (struct utf8_eucparam *) tab;
+  struct utf8_eucparam *p2 = p1 + 1;
+  unsigned short *t = (unsigned short *) p1->tab;
+  for (ret->size = i = 0; i < text->size;) {
+    if ((c = text->data[i++]) & BIT8) {
+      if ((i >= text->size) || !(c1 = text->data[i++]))
+	c = UBOGON;		/* out of space or bogon */
+      else if (c1 & BIT8)	/* high vs. low plane */
+	c = ((ku = c - p2->base_ku) < p2->max_ku &&
+	     ((ten = c1 - p2->base_ten) < p2->max_ten)) ?
+	       t[(ku*(p1->max_ten + p2->max_ten)) + p1->max_ten + ten] :UBOGON;
+      else c = ((ku = c - p1->base_ku) < p1->max_ku &&
+		((ten = c1 - p1->base_ten) < p1->max_ten)) ?
+		  t[(ku*(p1->max_ten + p2->max_ten)) + ten] : UBOGON;
+    }
+    UTF8_COUNT_BMP (ret->size,c,cv,de)
+  }
+  (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] = NIL;
+  for (i = 0; i < text->size;) {
+    if ((c = text->data[i++]) & BIT8) {
+      if ((i >= text->size) || !(c1 = text->data[i++]))
+	c = UBOGON;		/* out of space or bogon */
+      else if (c1 & BIT8)	/* high vs. low plane */
+	c = ((ku = c - p2->base_ku) < p2->max_ku &&
+	     ((ten = c1 - p2->base_ten) < p2->max_ten)) ?
+	       t[(ku*(p1->max_ten + p2->max_ten)) + p1->max_ten + ten] :UBOGON;
+      else c = ((ku = c - p1->base_ku) < p1->max_ku &&
+		((ten = c1 - p1->base_ten) < p1->max_ten)) ?
+		  t[(ku*(p1->max_ten + p2->max_ten)) + ten] : UBOGON;
+    }
+    UTF8_WRITE_BMP (s,c,cv,de)	/* convert UCS-2 to UTF-8 */
+  }
+}
+
+#ifdef JISTOUNICODE		/* Japanese */
+/* Convert Shift JIS sized text to UTF-8
+ * Accepts: source sized text
+ *	    pointer to return sized text
+ *	    canonicalization function
+ */
+
+void utf8_text_sjis (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,
+		     ucs4de_t de)
+{
+  unsigned long i;
+  unsigned char *s;
+  unsigned int c,c1,ku,ten;
+  for (ret->size = i = 0; i < text->size;) {
+    if ((c = text->data[i++]) & BIT8) {
+				/* half-width katakana */
+      if ((c >= MIN_KANA_8) && (c < MAX_KANA_8)) c += KANA_8;
+      else if (i >= text->size) c = UBOGON;
+      else {			/* Shift-JIS */
+	c1 = text->data[i++];
+	SJISTOJIS (c,c1);
+	c = JISTOUNICODE (c,c1,ku,ten);
+      }
+    }
+				/* compromise - do yen sign but not overline */
+    else if (c == JISROMAN_YEN) c = UCS2_YEN;
+    UTF8_COUNT_BMP (ret->size,c,cv,de)
+  }
+  (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] = NIL;
+  for (i = 0; i < text->size;) {
+    if ((c = text->data[i++]) & BIT8) {
+				/* half-width katakana */
+      if ((c >= MIN_KANA_8) && (c < MAX_KANA_8)) c += KANA_8;
+      else {			/* Shift-JIS */
+	c1 = text->data[i++];
+	SJISTOJIS (c,c1);
+	c = JISTOUNICODE (c,c1,ku,ten);
+      }
+    }
+				/* compromise - do yen sign but not overline */
+    else if (c == JISROMAN_YEN) c = UCS2_YEN;
+    UTF8_WRITE_BMP (s,c,cv,de)	/* convert UCS-2 to UTF-8 */
+  }
+}
+#endif
+
+/* Convert ISO-2022 sized text to UTF-8
+ * Accepts: source sized text
+ *	    pointer to returned sized text
+ *	    canonicalization function
+ */
+
+void utf8_text_2022 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de)
+{
+  unsigned long i;
+  unsigned char *s;
+  unsigned int pass,state,c,co,gi,gl,gr,g[4],ku,ten;
+  for (pass = 0,s = NIL,ret->size = 0; pass <= 1; pass++) {
+    gi = 0;			/* quell compiler warnings */
+    state = I2S_CHAR;		/* initialize engine */
+    g[0]= g[2] = I2CS_ASCII;	/* G0 and G2 are ASCII */
+    g[1]= g[3] = I2CS_ISO8859_1;/* G1 and G3 are ISO-8850-1 */
+    gl = I2C_G0; gr = I2C_G1;	/* left is G0, right is G1 */
+    for (i = 0; i < text->size;) {
+      c = text->data[i++];
+      switch (state) {		/* dispatch based upon engine state */
+      case I2S_ESC:		/* ESC seen */
+	switch (c) {		/* process intermediate character */
+	case I2C_MULTI:		/* multibyte character? */
+	  state = I2S_MUL;	/* mark multibyte flag seen */
+	  break;
+        case I2C_SS2:		/* single shift GL to G2 */
+	case I2C_SS2_ALT:	/* Taiwan SeedNet */
+	  gl |= I2C_SG2;
+	  break;
+        case I2C_SS3:		/* single shift GL to G3 */
+	case I2C_SS3_ALT:	/* Taiwan SeedNet */
+	  gl |= I2C_SG3;
+	  break;
+        case I2C_LS2:		/* shift GL to G2 */
+	  gl = I2C_G2;
+	  break;
+        case I2C_LS3:		/* shift GL to G3 */
+	  gl = I2C_G3;
+	  break;
+        case I2C_LS1R:		/* shift GR to G1 */
+	  gr = I2C_G1;
+	  break;
+        case I2C_LS2R:		/* shift GR to G2 */
+	  gr = I2C_G2;
+	  break;
+        case I2C_LS3R:		/* shift GR to G3 */
+	  gr = I2C_G3;
+	  break;
+	case I2C_G0_94: case I2C_G1_94: case I2C_G2_94:	case I2C_G3_94:
+	  g[gi = c - I2C_G0_94] = (state == I2S_MUL) ? I2CS_94x94 : I2CS_94;
+	  state = I2S_INT;	/* ready for character set */
+	  break;
+	case I2C_G0_96:	case I2C_G1_96: case I2C_G2_96:	case I2C_G3_96:
+	  g[gi = c - I2C_G0_96] = (state == I2S_MUL) ? I2CS_96x96 : I2CS_96;
+	  state = I2S_INT;	/* ready for character set */
+	  break;
+	default:		/* bogon */
+	  if (pass) *s++ = I2C_ESC,*s++ = c;
+	  else ret->size += 2;
+	  state = I2S_CHAR;	/* return to previous state */
+	}
+	break;
+
+      case I2S_MUL:		/* ESC $ */
+	switch (c) {		/* process multibyte intermediate character */
+	case I2C_G0_94: case I2C_G1_94: case I2C_G2_94:	case I2C_G3_94:
+	  g[gi = c - I2C_G0_94] = I2CS_94x94;
+	  state = I2S_INT;	/* ready for character set */
+	  break;
+	case I2C_G0_96:	case I2C_G1_96: case I2C_G2_96:	case I2C_G3_96:
+	  g[gi = c - I2C_G0_96] = I2CS_96x96;
+	  state = I2S_INT;	/* ready for character set */
+	  break;
+	default:		/* probably omitted I2CS_94x94 */
+	  g[gi = I2C_G0] = I2CS_94x94 | c;
+	  state = I2S_CHAR;	/* return to character state */
+	}
+	break;
+      case I2S_INT:
+	state = I2S_CHAR;	/* return to character state */
+	g[gi] |= c;		/* set character set */
+	break;
+
+      case I2S_CHAR:		/* character data */
+	switch (c) {
+	case I2C_ESC:		/* ESC character */
+	  state = I2S_ESC;	/* see if ISO-2022 prefix */
+	  break;
+	case I2C_SI:		/* shift GL to G0 */
+	  gl = I2C_G0;
+	  break;
+	case I2C_SO:		/* shift GL to G1 */
+	  gl = I2C_G1;
+	  break;
+        case I2C_SS2_ALT:	/* single shift GL to G2 */
+	case I2C_SS2_ALT_7:
+	  gl |= I2C_SG2;
+	  break;
+        case I2C_SS3_ALT:	/* single shift GL to G3 */
+	case I2C_SS3_ALT_7:
+	  gl |= I2C_SG3;
+	  break;
+
+	default:		/* ordinary character */
+	  co = c;		/* note original character */
+	  if (gl & (3 << 2)) {	/* single shifted? */
+	    gi = g[gl >> 2];	/* get shifted character set */
+	    gl &= 0x3;		/* cancel shift */
+	  }
+				/* select left or right half */
+	  else gi = (c & BIT8) ? g[gr] : g[gl];
+	  c &= BITS7;		/* make 7-bit */
+	  switch (gi) {		/* interpret in character set */
+	  case I2CS_ASCII:	/* ASCII */
+	    break;		/* easy! */
+	  case I2CS_BRITISH:	/* British ASCII */
+				/* Pound sterling sign */
+	    if (c == BRITISH_POUNDSTERLING) c = UCS2_POUNDSTERLING;
+	    break;
+	  case I2CS_JIS_ROMAN:	/* JIS Roman */
+	  case I2CS_JIS_BUGROM:	/* old bugs */
+	    switch (c) {	/* two exceptions to ASCII */
+	    case JISROMAN_YEN:	/* Yen sign */
+	      c = UCS2_YEN;
+	      break;
+				/* overline */
+	    case JISROMAN_OVERLINE:
+	      c = UCS2_OVERLINE;
+	      break;
+	    }
+	    break;
+	  case I2CS_JIS_KANA:	/* JIS hankaku katakana */
+	    if ((c >= MIN_KANA_7) && (c < MAX_KANA_7)) c += KANA_7;
+	    break;
+
+	  case I2CS_ISO8859_1:	/* Latin-1 (West European) */
+	    c |= BIT8;		/* just turn on high bit */
+	    break;
+	  case I2CS_ISO8859_2:	/* Latin-2 (Czech, Slovak) */
+	    c = iso8859_2tab[c];
+	    break;
+	  case I2CS_ISO8859_3:	/* Latin-3 (Dutch, Turkish) */
+	    c = iso8859_3tab[c];
+	    break;
+	  case I2CS_ISO8859_4:	/* Latin-4 (Scandinavian) */
+	    c = iso8859_4tab[c];
+	    break;
+	  case I2CS_ISO8859_5:	/* Cyrillic */
+	    c = iso8859_5tab[c];
+	    break;
+	  case I2CS_ISO8859_6:	/* Arabic */
+	    c = iso8859_6tab[c];
+	    break;
+	  case I2CS_ISO8859_7:	/* Greek */
+	    c = iso8859_7tab[c];
+	    break;
+	  case I2CS_ISO8859_8:	/* Hebrew */
+	    c = iso8859_8tab[c];
+	    break;
+	  case I2CS_ISO8859_9:	/* Latin-5 (Finnish, Portuguese) */
+	    c = iso8859_9tab[c];
+	    break;
+	  case I2CS_TIS620:	/* Thai */
+	    c = tis620tab[c];
+	    break;
+	  case I2CS_ISO8859_10:	/* Latin-6 (Northern Europe) */
+	    c = iso8859_10tab[c];
+	    break;
+	  case I2CS_ISO8859_13:	/* Latin-7 (Baltic) */
+	    c = iso8859_13tab[c];
+	    break;
+	  case I2CS_VSCII:	/* Vietnamese */
+	    c = visciitab[c];
+	    break;
+	  case I2CS_ISO8859_14:	/* Latin-8 (Celtic) */
+	    c = iso8859_14tab[c];
+	    break;
+	  case I2CS_ISO8859_15:	/* Latin-9 (Euro) */
+	    c = iso8859_15tab[c];
+	    break;
+	  case I2CS_ISO8859_16:	/* Latin-10 (Baltic) */
+	    c = iso8859_16tab[c];
+	    break;
+
+	  default:		/* all other character sets */
+				/* multibyte character set */
+	    if ((gi & I2CS_MUL) && !(c & BIT8) && isgraph (c)) {
+	      c = (i < text->size) ? text->data[i++] : 0;
+	      switch (gi) {
+#ifdef GBTOUNICODE
+	      case I2CS_GB:	/* GB 2312 */
+		co |= BIT8;	/* make into EUC */
+		c |= BIT8;
+		c = GBTOUNICODE (co,c,ku,ten);
+		break;
+#endif
+#ifdef JISTOUNICODE
+	      case I2CS_JIS_OLD:/* JIS X 0208-1978 */
+	      case I2CS_JIS_NEW:/* JIS X 0208-1983 */
+		c = JISTOUNICODE (co,c,ku,ten);
+		break;
+#endif
+#ifdef JIS0212TOUNICODE
+	      case I2CS_JIS_EXT:/* JIS X 0212-1990 */
+		c = JIS0212TOUNICODE (co,c,ku,ten);
+		break;
+#endif
+#ifdef KSCTOUNICODE
+	      case I2CS_KSC:	/* KSC 5601 */
+		co |= BIT8;	/* make into EUC */
+		c |= BIT8;
+		c = KSCTOUNICODE (co,c,ku,ten);
+		break;
+#endif
+#ifdef CNS1TOUNICODE
+	      case I2CS_CNS1:	/* CNS 11643 plane 1 */
+		c = CNS1TOUNICODE (co,c,ku,ten);
+		break;
+#endif
+#ifdef CNS2TOUNICODE
+	      case I2CS_CNS2:	/* CNS 11643 plane 2 */
+		c = CNS2TOUNICODE (co,c,ku,ten);
+		break;
+#endif
+#ifdef CNS3TOUNICODE
+	      case I2CS_CNS3:	/* CNS 11643 plane 3 */
+		c = CNS3TOUNICODE (co,c,ku,ten);
+		break;
+#endif
+#ifdef CNS4TOUNICODE
+	      case I2CS_CNS4:	/* CNS 11643 plane 4 */
+		c = CNS4TOUNICODE (co,c,ku,ten);
+		break;
+#endif
+#ifdef CNS5TOUNICODE
+	      case I2CS_CNS5:	/* CNS 11643 plane 5 */
+		c = CNS5TOUNICODE (co,c,ku,ten);
+		break;
+#endif
+#ifdef CNS6TOUNICODE
+	      case I2CS_CNS6:	/* CNS 11643 plane 6 */
+		c = CNS6TOUNICODE (co,c,ku,ten);
+		break;
+#endif
+#ifdef CNS7TOUNICODE
+	      case I2CS_CNS7:	/* CNS 11643 plane 7 */
+		c = CNS7TOUNICODE (co,c,ku,ten);
+		break;
+#endif
+	      default:		/* unknown multibyte, treat as UCS-2 */
+		c |= (co << 8);	/* wrong, but nothing else to do */
+		break;
+	      }
+	    }
+	    else c = co;	/* unknown single byte, treat as 8859-1 */
+	  }
+				/* convert if second pass */
+	  if (pass) UTF8_WRITE_BMP (s,c,cv,de)
+	  else UTF8_COUNT_BMP (ret->size,c,cv,de);
+	}
+      }
+    }
+    if (!pass) (s = ret->data = (unsigned char *)
+		fs_get (ret->size + 1))[ret->size] = NIL;
+    else if (((unsigned long) (s - ret->data)) != ret->size)
+      fatal ("ISO-2022 to UTF-8 botch");
+  }
+}
+
+/* Convert UTF-7 sized text to UTF-8
+ * Accepts: source sized text
+ *	    pointer to returned sized text
+ *	    canonicalization function
+ */
+
+void utf8_text_utf7 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de)
+{
+  unsigned long i;
+  unsigned char *s;
+  unsigned int c,c1,d,uc,pass,e,e1,state,surrh;
+  for (pass = 0,s = NIL,ret->size = 0; pass <= 1; pass++) {
+    c1 = d = uc = e = e1 = 0;
+    for (i = 0,state = NIL; i < text->size;) {
+      c = text->data[i++];	/* get next byte */
+      switch (state) {
+      case U7_PLUS:		/* previous character was + */
+	if (c == '-') {		/* +- means textual + */
+	  c = '+';
+	  state = U7_ASCII;	/* revert to ASCII */
+	  break;
+	}
+	state = U7_UNICODE;	/* enter Unicode state */
+	e = e1 = 0;		/* initialize Unicode quantum position */
+      case U7_UNICODE:		/* Unicode state */
+	if (c == '-') state = U7_MINUS;
+	else {			/* decode Unicode */
+	  /* don't use isupper/islower since this is ASCII only */
+	  if ((c >= 'A') && (c <= 'Z')) c -= 'A';
+	  else if ((c >= 'a') && (c <= 'z')) c -= 'a' - 26;
+	  else if (isdigit (c)) c -= '0' - 52;
+	  else if (c == '+') c = 62;
+	  else if (c == '/') c = 63;
+	  else state = U7_ASCII;/* end of modified BASE64 */
+	}
+	break;
+      case U7_MINUS:		/* previous character was absorbed - */
+	state = U7_ASCII;	/* revert to ASCII */
+      case U7_ASCII:		/* ASCII state */
+	if (c == '+') state = U7_PLUS;
+	break;
+      }
+
+      switch (state) {		/* store character if in character mode */
+      case U7_UNICODE:		/* Unicode */
+	switch (e++) {		/* install based on BASE64 state */
+	case 0:
+	  c1 = c << 2;		/* byte 1: high 6 bits */
+	  break;
+	case 1:
+	  d = c1 | (c >> 4);	/* byte 1: low 2 bits */
+	  c1 = c << 4;		/* byte 2: high 4 bits */
+	  break;
+	case 2:
+	  d = c1 | (c >> 2);	/* byte 2: low 4 bits */
+	  c1 = c << 6;		/* byte 3: high 2 bits */
+	  break;
+	case 3:
+	  d = c | c1;		/* byte 3: low 6 bits */
+	  e = 0;		/* reinitialize mechanism */
+	  break;
+	}
+	if (e == 1) break;	/* done if first BASE64 state */
+	if (!e1) {		/* first byte of UCS-2 character */
+	  uc = (d & 0xff) << 8;	/* note first byte */
+	  e1 = T;		/* enter second UCS-2 state */
+	  break;		/* done */
+	}
+	c = uc | (d & 0xff);	/* build UCS-2 character */
+	e1 = NIL;		/* back to first UCS-2 state, drop in */
+				/* surrogate pair?  */
+	if ((c >= UTF16_SURR) && (c <= UTF16_MAXSURR)) {
+				/* save high surrogate for later */
+	  if (c < UTF16_SURRL) surrh = c;
+	  else c = UTF16_BASE + ((surrh & UTF16_MASK) << UTF16_SHIFT) +
+		 (c & UTF16_MASK);
+	  break;		/* either way with surrogates, we're done */
+	}
+      case U7_ASCII:		/* just install if ASCII */
+				/* convert if second pass */
+	if (pass) UTF8_WRITE_BMP (s,c,cv,de)
+	else UTF8_COUNT_BMP (ret->size,c,cv,de);
+      }
+    }
+    if (!pass) (s = ret->data = (unsigned char *)
+		fs_get (ret->size + 1))[ret->size] = NIL;
+    else if (((unsigned long) (s - ret->data)) != ret->size)
+      fatal ("UTF-7 to UTF-8 botch");
+  }
+}
+
+
+/* Convert UTF-8 sized text to UTF-8
+ * Accepts: source sized text
+ *	    pointer to returned sized text
+ *	    canonicalization function
+ */
+
+void utf8_text_utf8 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de)
+{
+  unsigned long i,c;
+  unsigned char *s,*t;
+  for (ret->size = 0, t = text->data, i = text->size; i;) {
+    if ((c = utf8_get (&t,&i)) & U8G_ERROR) {
+      ret->data = text->data;	/* conversion failed */
+      ret->size = text->size;
+      return;
+    }
+    UTF8_COUNT (ret->size,c,cv,de)
+  }
+  (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] =NIL;
+  for (t = text->data, i = text->size; i;) {
+    c = utf8_get (&t,&i);
+    UTF8_WRITE (s,c,cv,de)	/* convert UCS-4 to UTF-8 */
+  }
+  if (((unsigned long) (s - ret->data)) != ret->size)
+    fatal ("UTF-8 to UTF-8 botch");
+}
+
+/* Convert UCS-2 sized text to UTF-8
+ * Accepts: source sized text
+ *	    pointer to returned sized text
+ *	    canonicalization function
+ */
+
+void utf8_text_ucs2 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de)
+{
+  unsigned long i;
+  unsigned char *s,*t;
+  unsigned int c;
+  for (ret->size = 0, t = text->data, i = text->size / 2; i; --i) {
+    c = *t++ << 8;
+    c |= *t++;
+    UTF8_COUNT_BMP (ret->size,c,cv,de);
+  }
+  (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] = NIL;
+  for (t = text->data, i = text->size / 2; i; --i) {
+    c = *t++ << 8;
+    c |= *t++;
+    UTF8_WRITE_BMP (s,c,cv,de)	/* convert UCS-2 to UTF-8 */
+  }
+  if (((unsigned long) (s - ret->data)) != ret->size)
+    fatal ("UCS-2 to UTF-8 botch");
+}
+
+
+/* Convert UCS-4 sized text to UTF-8
+ * Accepts: source sized text
+ *	    pointer to returned sized text
+ *	    canonicalization function
+ */
+
+void utf8_text_ucs4 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de)
+{
+  unsigned long i;
+  unsigned char *s,*t;
+  unsigned long c;
+  for (ret->size = 0, t = text->data, i = text->size / 4; i; --i) {
+    c = *t++ << 24; c |= *t++ << 16; c |= *t++ << 8; c |= *t++;
+    UTF8_COUNT (ret->size,c,cv,de);
+  }
+  (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] = NIL;
+  for (t = text->data, i = text->size / 2; i; --i) {
+    c = *t++ << 24; c |= *t++ << 16; c |= *t++ << 8; c |= *t++;
+    UTF8_WRITE (s,c,cv,de)	/* convert UCS-4 to UTF-8 */
+  }
+  if (((unsigned long) (s - ret->data)) != ret->size)
+    fatal ("UCS-4 to UTF-8 botch");
+}
+
+/* Convert UTF-16 sized text to UTF-8
+ * Accepts: source sized text
+ *	    pointer to returned sized text
+ *	    canonicalization function
+ */
+
+void utf8_text_utf16 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de)
+{
+  unsigned long i;
+  unsigned char *s,*t;
+  unsigned long c,d;
+  for (ret->size = 0, t = text->data, i = text->size / 2; i; --i) {
+    c = *t++ << 8;
+    c |= *t++;
+				/* possible surrogate? */
+    if ((c >= UTF16_SURR) && (c <= UTF16_MAXSURR)) {
+				/* invalid first surrogate */
+      if ((c > UTF16_SURRHEND) || !i) c = UBOGON;
+      else {			/* get second surrogate */
+	d = *t++ << 8;
+	d |= *t++;
+	--i;			/* swallowed another 16-bits */
+				/* invalid second surrogate */
+	if ((d < UTF16_SURRL) || (d > UTF16_SURRLEND)) c = UBOGON;
+	else c = UTF16_BASE + ((c & UTF16_MASK) << UTF16_SHIFT) +
+	       (d & UTF16_MASK);
+      }
+    }
+    UTF8_COUNT (ret->size,c,cv,de);
+  }
+  (s = ret->data = (unsigned char *) fs_get (ret->size + 1))[ret->size] = NIL;
+  for (t = text->data, i = text->size / 2; i; --i) {
+    c = *t++ << 8;
+    c |= *t++;
+				/* possible surrogate? */
+    if ((c >= UTF16_SURR) && (c <= UTF16_MAXSURR)) {
+				/* invalid first surrogate */
+      if ((c > UTF16_SURRHEND) || !i) c = UBOGON;
+      else {			/* get second surrogate */
+	d = *t++ << 8;
+	d |= *t++;
+	--i;			/* swallowed another 16-bits */
+				/* invalid second surrogate */
+	if ((d < UTF16_SURRL) || (d > UTF16_SURRLEND)) c = UBOGON;
+	else c = UTF16_BASE + ((c & UTF16_MASK) << UTF16_SHIFT) +
+	       (d & UTF16_MASK);
+      }
+    }
+    UTF8_WRITE (s,c,cv,de)	/* convert UCS-4 to UTF-8 */
+  }
+  if (((unsigned long) (s - ret->data)) != ret->size)
+    fatal ("UTF-16 to UTF-8 botch");
+}
+
+/* Size of UCS-4 character, possibly not in BMP, as UTF-8 octets
+ * Accepts: character
+ * Returns: size (0 means bogon)
+ *
+ * Use UTF8_SIZE macro if known to be in the BMP
+ */
+
+unsigned long utf8_size (unsigned long c)
+{
+  if (c < 0x80) return 1;
+  else if (c < 0x800) return 2;
+  else if (c < 0x10000) return 3;
+  else if (c < 0x200000) return 4;
+  else if (c < 0x4000000) return 5;
+  else if (c < 0x80000000) return 6;
+  return 0;
+}
+
+
+/* Put UCS-4 character, possibly not in BMP, as UTF-8 octets
+ * Accepts: destination string pointer
+ *	    character
+ * Returns: updated destination pointer
+ *
+ * Use UTF8_PUT_BMP macro if known to be in the BMP
+ */
+
+unsigned char *utf8_put (unsigned char *s,unsigned long c)
+{
+  unsigned char mark[6] = {0x00,0xc0,0xe0,0xf0,0xf8,0xfc};
+  unsigned long size = utf8_size (c);
+  switch (size) {
+  case 6:
+    s[5] = 0x80 | (unsigned char) (c & 0x3f);
+    c >>= 6;
+  case 5:
+    s[4] = 0x80 | (unsigned char) (c & 0x3f);
+    c >>= 6;
+  case 4:
+    s[3] = 0x80 | (unsigned char) (c & 0x3f);
+    c >>= 6;
+  case 3:
+    s[2] = 0x80 | (unsigned char) (c & 0x3f);
+    c >>= 6;
+  case 2:
+    s[1] = 0x80 | (unsigned char) (c & 0x3f);
+    c >>= 6;
+  case 1:
+    *s = mark[size-1] | (unsigned char) (c & 0x7f);
+    break;
+  }
+  return s + size;
+}
+
+/* Return title case of a fixed-width UCS-4 character
+ * Accepts: character
+ * Returns: title case of character
+ */
+
+unsigned long ucs4_titlecase (unsigned long c)
+{
+  if (c <= UCS4_TMAPMAX) return ucs4_tmaptab[c];
+  if (c < UCS4_TMAPHIMIN) return c;
+  if (c <= UCS4_TMAPHIMAX) return c - UCS4_TMAPHIMAP;
+  if (c < UCS4_TMAPDESERETMIN) return c;
+  if (c <= UCS4_TMAPDESERETMAX) return c - UCS4_TMAPDESERETMAP;
+  return c;
+}
+
+
+/* Return width of a fixed-width UCS-4 character in planes 0-2
+ * Accepts: character
+ * Returns: width (0, 1, 2) or negative error condition if not valid
+ */
+
+long ucs4_width (unsigned long c)
+{
+  long ret;
+				/* out of range, not-a-char, or surrogates */
+  if ((c > UCS4_MAXUNICODE) || ((c & 0xfffe) == 0xfffe) ||
+      ((c >= UTF16_SURR) && (c <= UTF16_MAXSURR))) ret = U4W_NOTUNCD;
+				/* private-use */
+  else if (c >= UCS4_PVTBASE) ret = U4W_PRIVATE;
+				/* SSP are not printing characters */
+  else if (c >= UCS4_SSPBASE) ret = U4W_SSPCHAR;
+				/* unassigned planes */
+  else if (c >= UCS4_UNABASE) ret = U4W_UNASSGN;
+				/* SIP and reserved plane 3 are wide */
+  else if (c >= UCS4_SIPBASE) ret = 2;
+#if (UCS4_WIDLEN != UCS4_SIPBASE)
+#error "UCS4_WIDLEN != UCS4_SIPBASE"
+#endif
+				/* C0/C1 controls */
+  else if ((c <= UCS2_C0CONTROLEND) ||
+	   ((c >= UCS2_C1CONTROL) && (c <= UCS2_C1CONTROLEND)))
+    ret = U4W_CONTROL;
+				/* BMP and SMP get value from table */
+  else switch (ret = (ucs4_widthtab[(c >> 2)] >> ((3 - (c & 0x3)) << 1)) &0x3){
+  case 0:			/* zero-width */
+    if (c == 0x00ad) ret = 1;	/* force U+00ad (SOFT HYPHEN) to width 1 */
+  case 1:			/* single-width */
+  case 2:			/* double-width */
+    break;
+  case 3:			/* ambiguous width */
+    ret = (c >= 0x2100) ? 2 : 1;/* need to do something better than this */
+    break;
+  }
+  return ret;
+}
+
+/* Return screen width of UTF-8 string
+ * Accepts: string
+ * Returns: width or negative if not valid UTF-8
+ */
+
+long utf8_strwidth (unsigned char *s)
+{
+  unsigned long c,i,ret;
+				/* go through string */
+  for (ret = 0; *s; ret += ucs4_width (c)) {
+    /* It's alright to give a fake value for the byte count to utf8_get()
+     * since the null of a null-terminated string will stop processing anyway.
+     */
+    i = 6;			/* fake value */
+    if ((c = utf8_get (&s,&i)) & U8G_ERROR) return -1;
+  }
+  return ret;
+}
+
+
+/* Return screen width of UTF-8 text
+ * Accepts: SIZEDTEXT to string
+ * Returns: width or negative if not valid UTF-8
+ */
+
+long utf8_textwidth (SIZEDTEXT *utf8)
+{
+  unsigned long c;
+  unsigned char *s = utf8->data;
+  unsigned long i = utf8->size;
+  unsigned long ret = 0;
+  while (i) {			/* while there's a string to process */
+    if ((c = utf8_get (&s,&i)) & U8G_ERROR) return -1;
+    ret += ucs4_width (c);
+  }
+  return ret;
+}
+
+/* Decomposition (phew!) */
+
+#define MORESINGLE 1		/* single UCS-4 tail value */
+#define MOREMULTIPLE 2		/* multiple UCS-2 tail values */
+
+struct decomposemore {
+  short type;			/* type of more */
+  union {
+    unsigned long single;	/* single decomposed value */
+    struct {			/* multiple BMP values */
+      unsigned short *next;
+      unsigned long count;
+    } multiple;
+  } data;
+};
+
+#define RECURSIVEMORE struct recursivemore
+
+RECURSIVEMORE {
+  struct decomposemore *more;
+  RECURSIVEMORE *next;
+};
+
+
+/* Return decomposition of a UCS-4 character
+ * Accepts: character or U8G_ERROR to return next from "more"
+ *	    pointer to returned more
+ * Returns: [next] decomposed value, more set if still more decomposition
+ */
+
+unsigned long ucs4_decompose (unsigned long c,void **more)
+{
+  unsigned long i,ix,ret;
+  struct decomposemore *m;
+  if (c & U8G_ERROR) {		/* want to chase more? */
+				/* do sanity check */
+    if (m = (struct decomposemore *) *more) switch (m->type) {
+    case MORESINGLE:		/* single value */
+      ret = m->data.single;
+      fs_give (more);		/* no more decomposition */
+      break;
+    case MOREMULTIPLE:		/* multiple value */
+      ret = *m->data.multiple.next++;
+      if (!--m->data.multiple.count) fs_give (more);
+      break;
+    default:			/* uh-oh */
+      fatal ("invalid more block argument to ucs4_decompose!");
+    }
+    else fatal ("no more block provided to ucs4_decompose!");
+  }
+
+  else {			/* start decomposition */
+    *more = NIL;		/* initially set no more */
+				/* BMP low decompositions */
+    if (c < UCS4_BMPLOMIN) ret = c;
+				/* fix this someday */
+    else if (c == UCS4_BMPLOMIN) ret = ucs4_dbmplotab[0];
+    else if (c <= UCS4_BMPLOMAX) {
+				/* within range - have a decomposition? */
+      if (i = ucs4_dbmploixtab[c - UCS4_BMPLOMIN]) {
+				/* get first value of decomposition */
+	ret = ucs4_dbmplotab[ix = i & UCS4_BMPLOIXMASK];
+				/* has continuation? */
+	if (i & UCS4_BMPLOSIZEMASK) {
+	  m = (struct decomposemore *)
+	    (*more = memset (fs_get (sizeof (struct decomposemore)),0,
+			    sizeof (struct decomposemore)));
+	  m->type = MOREMULTIPLE;
+	  m->data.multiple.next = &ucs4_dbmplotab[++ix];
+	  m->data.multiple.count = i >> UCS4_BMPLOSIZESHIFT;
+	}
+      }
+      else ret = c;		/* in range but doesn't decompose */
+    }
+				/* BMP CJK compatibility */
+    else if (c < UCS4_BMPCJKMIN) ret = c;
+    else if (c <= UCS4_BMPCJKMAX) {
+      if (!(ret = ucs4_bmpcjk1decomptab[c - UCS4_BMPCJKMIN])) ret = c;
+    }
+				/* BMP CJK compatibility - some not in BMP */
+#if UCS4_BMPCJK2MIN - (UCS4_BMPCJKMAX + 1)
+    else if (c < UCS4_BMPCJK2MIN) ret = c;
+#endif
+    else if (c <= UCS4_BMPCJK2MAX)
+      ret = ucs4_bmpcjk2decomptab[c - UCS4_BMPCJK2MIN];
+				/* BMP high decompositions */
+    else if (c < UCS4_BMPHIMIN) ret = c;
+    else if (c <= UCS4_BMPHIMAX) {
+				/* within range - have a decomposition? */
+      if (i = ucs4_dbmphiixtab[c - UCS4_BMPHIMIN]) {
+				/* get first value of decomposition */
+	ret = ucs4_dbmphitab[ix = i & UCS4_BMPHIIXMASK];
+				/* has continuation? */
+	if (i & UCS4_BMPHISIZEMASK) {
+	  m = (struct decomposemore *)
+	    (*more = memset (fs_get (sizeof (struct decomposemore)),0,
+			    sizeof (struct decomposemore)));
+	  m->type = MOREMULTIPLE;
+	  m->data.multiple.next = &ucs4_dbmphitab[++ix];
+	  m->data.multiple.count = i >> UCS4_BMPHISIZESHIFT;
+	}
+      }
+      else ret = c;		/* in range but doesn't decompose */
+    }
+
+				/* BMP half and full width forms */
+    else if (c < UCS4_BMPHALFFULLMIN) ret = c;
+    else if (c <= UCS4_BMPHALFFULLMAX) {
+      if (!(ret = ucs4_bmphalffulldecomptab[c - UCS4_BMPHALFFULLMIN])) ret = c;
+    }
+				/* SMP music */
+    else if (c < UCS4_SMPMUSIC1MIN) ret = c;
+    else if (c <= UCS4_SMPMUSIC1MAX) {
+      ret = ucs4_smpmusic1decomptab[c -= UCS4_SMPMUSIC1MIN][0];
+      m = (struct decomposemore *)
+	(*more = memset (fs_get (sizeof (struct decomposemore)),0,
+			 sizeof (struct decomposemore)));
+      m->type = MORESINGLE;
+      m->data.single = ucs4_smpmusic1decomptab[c][1];
+    }
+    else if (c < UCS4_SMPMUSIC2MIN) ret = c;
+    else if (c <= UCS4_SMPMUSIC2MAX) {
+      ret = ucs4_smpmusic2decomptab[c -= UCS4_SMPMUSIC2MIN][0];
+      m = (struct decomposemore *)
+	(*more = memset (fs_get (sizeof (struct decomposemore)),0,
+			 sizeof (struct decomposemore)));
+      m->type = MORESINGLE;
+      m->data.single = ucs4_smpmusic2decomptab[c][1];
+    }
+				/* SMP mathematical forms */
+    else if (c < UCS4_SMPMATHMIN) ret = c;
+    else if (c <= UCS4_SMPMATHMAX) {
+      if (!(ret = ucs4_smpmathdecomptab[c - UCS4_SMPMATHMIN])) ret = c;
+    }
+				/* CJK compatibility ideographs in SIP */
+    else if (!(ret = ((c >= UCS4_SIPMIN) && (c <= UCS4_SIPMAX)) ?
+	       ucs4_sipdecomptab[c - UCS4_SIPMIN] : c)) ret = c;
+  }
+  return ret;
+}
+
+/* Return recursive decomposition of a UCS-4 character
+ * Accepts: character or U8G_ERROR to return next from "more"
+ *	    pointer to returned more
+ * Returns: [next] decomposed value, more set if still more decomposition
+ */
+
+unsigned long ucs4_decompose_recursive (unsigned long c,void **more)
+{
+  unsigned long c1;
+  void *m,*mn;
+  RECURSIVEMORE *mr;
+  if (c & U8G_ERROR) {		/* want to chase more? */
+    mn = NIL;
+    if (mr = (RECURSIVEMORE *) *more) switch (mr->more->type) {
+    case MORESINGLE:		/* decompose single value */
+      c = ucs4_decompose_recursive (mr->more->data.single,&mn);
+      *more = mr->next;		/* done with this more, remove it */
+      fs_give ((void **) &mr->more);
+      fs_give ((void **) &mr);
+      break;
+    case MOREMULTIPLE:		/* decompose current value in multiple */
+      c = ucs4_decompose_recursive (*mr->more->data.multiple.next++,&mn);
+				/* if done with this multiple decomposition */
+      if (!--mr->more->data.multiple.count) {
+	*more = mr->next;	/* done with this more, remove it */
+	fs_give ((void **) &mr->more);
+	fs_give ((void **) &mr);
+      }
+      break;
+    default:			/* uh-oh */
+      fatal ("invalid more block argument to ucs4_decompose_recursive!");
+    }
+    else fatal ("no more block provided to ucs4_decompose_recursive!");
+    if (mr = mn) {		/* did this value recurse on us? */
+      mr->next = *more;		/* yes, insert new more at head */
+      *more = mr;
+    }
+  }
+  else {			/* start decomposition */
+    *more = NIL;		/* initially set no more */
+    mr = NIL;
+    do {			/* repeatedly decompose this codepoint */
+      c = ucs4_decompose (c1 = c,&m);
+      if (m) {			/* multi-byte decomposition */
+	if (c1 == c) fatal ("endless multiple decomposition!");
+				/* create a block to stash this more */
+	mr = memset (fs_get (sizeof (RECURSIVEMORE)),0,sizeof (RECURSIVEMORE));
+	mr->more = m;		/* note the expansion */
+	mr->next = *more;	/* old list is the tail */
+	*more = mr;		/* and this is the new head */
+      }
+    } while (c1 != c);		/* until nothing more to decompose */
+  }
+  return c;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/utf8.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,584 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UTF-8 routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 June 1997
+ * Last Edited:	17 January 2008
+ */
+
+/* UTF-8 size and conversion routines from UCS-2 values (thus in the BMP).
+ * Don't use these if UTF-16 data (surrogate pairs) are an issue.
+ * For UCS-4 values, use the utf8_size() and utf8_put() functions.
+ */
+
+#define UTF8_SIZE_BMP(c) ((c & 0xff80) ? ((c & 0xf800) ? 3 : 2) : 1)
+
+#define UTF8_PUT_BMP(b,c) {				\
+  if (c & 0xff80) {		/* non-ASCII? */	\
+    if (c & 0xf800) {		/* three byte code */	\
+      *b++ = 0xe0 | (c >> 12);				\
+      *b++ = 0x80 | ((c >> 6) & 0x3f);			\
+    }							\
+    else *b++ = 0xc0 | ((c >> 6) & 0x3f);		\
+    *b++ = 0x80 | (c & 0x3f); 				\
+  }							\
+  else *b++ = c;					\
+}
+
+/* utf8_text() flag values */
+
+#define U8T_CASECANON 2		/* canonicalize case */
+#define U8T_DECOMPOSE 4		/* decompose */
+				/* full canonicalization */
+#define U8T_CANONICAL (U8T_CASECANON | U8T_DECOMPOSE)
+
+
+/* utf8_get() return values */
+
+				/* 0x0000 - 0xffff BMP plane */
+#define U8GM_NONBMP 0xffff0000	/* mask for non-BMP values */
+				/* 0x10000 - 0x10ffff extended planes */
+				/* 0x110000 - 0x7ffffff non-Unicode */
+#define U8G_ERROR 0x80000000	/* error flag */
+#define U8G_BADCONT U8G_ERROR+1	/* continuation when not in progress */
+#define U8G_INCMPLT U8G_ERROR+2	/* incomplete UTF-8 character */
+#define U8G_NOTUTF8 U8G_ERROR+3	/* not a valid UTF-8 octet */
+#define U8G_ENDSTRG U8G_ERROR+4	/* end of string */
+#define U8G_ENDSTRI U8G_ERROR+5	/* end of string w/ incomplete UTF-8 char */
+#define U8G_SURROGA U8G_ERROR+6	/* surrogate codepoint */
+#define U8G_NOTUNIC U8G_ERROR+7	/* non-Unicode codepoint */
+
+
+/* ucs4_width() return values */
+
+#define U4W_ERROR 0x80000000	/* error flags */
+#define U4W_NOTUNCD U4W_ERROR+1	/* not a Unicode char */
+#define U4W_PRIVATE U4W_ERROR+2	/* private-space plane */
+#define U4W_SSPCHAR U4W_ERROR+3	/* Supplementary Special-purpose Plane */
+#define U4W_UNASSGN U4W_ERROR+4	/* unassigned space plane */
+#define U4W_CONTROL U4W_ERROR+5	/* C0/C1 control */
+#define U4W_CTLSRGT U4W_CONTROL	/* in case legacy code references this */
+
+/* ISO-2022 engine states */
+
+#define I2S_CHAR 0		/* character */
+#define I2S_ESC 1		/* previous character was ESC */
+#define I2S_MUL 2		/* previous character was multi-byte code */
+#define I2S_INT 3		/* previous character was intermediate */
+
+
+/* ISO-2022 Gn selections */
+
+#define I2C_G0 0		/* G0 */
+#define I2C_G1 1		/* G1 */
+#define I2C_G2 2		/* G2 */
+#define I2C_G3 3		/* G3 */
+#define I2C_SG2 (2 << 2)	/* single shift G2 */
+#define I2C_SG3 (3 << 2)	/* single shift G2 */
+
+
+/* ISO-2022 octet definitions */
+
+#define I2C_ESC 0x1b		/* ESCape */
+
+	/* Intermediate character */
+#define I2C_STRUCTURE 0x20	/* announce code structure */
+#define I2C_C0 0x21		/* C0 */
+#define I2C_C1 0x22		/* C1 */
+#define I2C_CONTROL 0x23	/* single control function */
+#define I2C_MULTI 0x24		/* multi-byte character set */
+#define I2C_OTHER 0x25		/* other coding system */
+#define I2C_REVISED 0x26	/* revised registration */
+#define I2C_G0_94 0x28		/* G0 94-character set */
+#define I2C_G1_94 0x29		/* G1 94-character set */
+#define I2C_G2_94 0x2A		/* G2 94-character set */
+#define I2C_G3_94 0x2B		/* G3 94-character set */
+#define I2C_G0_96 0x2C		/* (not in ISO-2022) G0 96-character set */
+#define I2C_G1_96 0x2D		/* G1 96-character set */
+#define I2C_G2_96 0x2E		/* G2 96-character set */
+#define I2C_G3_96 0x2F		/* G3 96-character set */
+
+	/* Locking shifts */
+#define I2C_SI 0x0f		/* lock shift to G0 (Shift In) */
+#define I2C_SO 0x0e		/* lock shift to G1 (Shift Out) */
+	/* prefixed by ESC */
+#define I2C_LS2 0x6e		/* lock shift to G2 */
+#define I2C_LS3 0x6f		/* lock shift to G3 */
+#define I2C_LS1R 0x7e		/* lock shift GR to G1 */
+#define I2C_LS2R 0x7d		/* lock shift GR to G2 */
+#define I2C_LS3R 0x7c		/* lock shift GR to G3 */
+
+	/* Single shifts */
+#define I2C_SS2_ALT 0x8e	/* single shift to G2 (SS2) */
+#define I2C_SS3_ALT 0x8f	/* single shift to G3 (SS3) */
+#define I2C_SS2_ALT_7 0x19	/* single shift to G2 (SS2) */
+#define I2C_SS3_ALT_7 0x1d	/* single shift to G3 (SS3) */
+	/* prefixed by ESC */
+#define I2C_SS2 0x4e		/* single shift to G2 (SS2) */
+#define I2C_SS3 0x4f		/* single shift to G3 (SS3) */
+
+/* 94 character sets */
+
+				/* 4/0 ISO 646 IRV */
+#define I2CS_94_BRITISH 0x41	/* 4/1 ISO 646 British */
+#define I2CS_94_ASCII 0x42	/* 4/2 ISO 646 USA (ASCII) */
+				/* 4/3 NATS Finland/Sweden (primary) */
+				/* 4/4 NATS Finland/Sweden (secondary) */
+				/* 4/5 NATS Denmark/Norway (primary) */
+				/* 4/6 NATS Denmark/Norway (secondary) */
+				/* 4/7 ISO 646 Swedish SEN 850200 */
+				/* 4/8 ISO 646 Swedish names */
+#define I2CS_94_JIS_BUGROM 0x48	/* 4/8 some buggy software does this */
+#define I2CS_94_JIS_KANA 0x49	/* 4/9 JIS X 0201-1976 right half */
+#define I2CS_94_JIS_ROMAN 0x4a	/* 4/a JIS X 0201-1976 left half */
+				/* 4/b ISO 646 German */
+				/* 4/c ISO 646 Portuguese (Olivetti) */
+				/* 4/d ISO 6438 African */
+				/* 4/e ISO 5427 Cyrillic (Honeywell-Bull) */
+				/* 4/f DIN 31624 extended bibliography  */
+				/* 5/0 ISO 5426-1980 Bibliography */
+				/* 5/1 ISO 5427-1981 Cyrillic*/
+				/* 5/2 ISO 646 French (withdrawn) */
+				/* 5/3 ISO 5428-1980 Greek bibliography */
+				/* 5/4 GB 1988-80 Chinese */
+				/* 5/5 Latin-Greek (Honeywell-Bull) */
+				/* 5/6 UK Viewdata/Teletext */
+				/* 5/7 INIS (IRV subset) */
+				/* 5/8 ISO 5428 Greek Bibliography */
+				/* 5/9 ISO 646 Italian (Olivetti) */
+				/* 5/a ISO 646 Spanish (Olivetti) */
+				/* 5/b Greek (Olivetti) */
+				/* 5/c Latin-Greek (Olivetti) */
+				/* 5/d INIS non-standard extension */
+				/* 5/e INIS Cyrillic extension */
+				/* 5/f Arabic CODAR-U IERA */
+				/* 6/0 ISO 646 Norwegian */
+				/* 6/1 Norwegian version 2 (withdrawn) */
+				/* 6/2 Videotex supplementary */
+				/* 6/3 Videotex supplementary #2 */
+				/* 6/4 Videotex supplementary #3 */
+				/* 6/5 APL */
+				/* 6/6 ISO 646 French */
+				/* 6/7 ISO 646 Portuguese (IBM) */
+				/* 6/8 ISO 646 Spanish (IBM) */
+				/* 6/9 ISO 646 Hungarian */
+				/* 6/a Greek ELOT (withdrawn) */
+				/* 6/b ISO 9036 Arabic 7-bit */
+				/* 6/c ISO 646 IRV supplementary set */
+				/* 6/d JIS C6229-1984 OCR-A */
+				/* 6/e JIS C6229-1984 OCR-B */
+				/* 6/f JIS C6229-1984 OCR-B additional */
+				/* 7/0 JIS C6229-1984 hand-printed */
+				/* 7/1 JIS C6229-1984 additional hand-printd */
+				/* 7/2 JIS C6229-1984 katakana hand-printed */
+				/* 7/3 E13B Japanese graphic */
+				/* 7/4 Supplementary Videotex (withdrawn) */
+				/* 7/5 Teletex primary CCITT T.61 */
+				/* 7/6 Teletex secondary CCITT T.61 */
+				/* 7/7 CSA Z 243.4-1985 Alternate primary #1 */
+				/* 7/8 CSA Z 243.4-1985 Alternate primary #2 */
+				/* 7/9 Mosaic CCITT T.101 */
+				/* 7/a Serbocroatian/Slovenian Latin */
+				/* 7/b Serbocroatian Cyrillic */
+				/* 7/c Supplementary CCITT T.101 */
+				/* 7/d Macedonian Cyrillic */
+
+/* 94 character sets - second intermediate byte */
+
+				/* 4/0 Greek primary CCITT */
+				/* 4/1 Cuba */
+				/* 4/2 ISO/IEC 646 invariant */
+				/* 4/3 Irish Gaelic 7-bit */
+				/* 4/4 Turkmen */
+
+
+/* 94x94 character sets */
+
+#define I2CS_94x94_JIS_OLD 0x40	/* 4/0 JIS X 0208-1978 */
+#define I2CS_94x94_GB 0x41	/* 4/1 GB 2312 */
+#define I2CS_94x94_JIS_NEW 0x42	/* 4/2 JIS X 0208-1983 */
+#define I2CS_94x94_KSC 0x43	/* 4/3 KSC 5601 */
+#define I2CS_94x94_JIS_EXT 0x44	/* 4/4 JIS X 0212-1990 */
+				/* 4/5 CCITT Chinese */
+				/* 4/6 Blisssymbol Graphic */
+#define I2CS_94x94_CNS1 0x47	/* 4/7 CNS 11643 plane 1 */
+#define I2CS_94x94_CNS2 0x48	/* 4/8 CNS 11643 plane 2 */
+#define I2CS_94x94_CNS3 0x49	/* 4/9 CNS 11643 plane 3 */
+#define I2CS_94x94_CNS4 0x4a	/* 4/a CNS 11643 plane 4 */
+#define I2CS_94x94_CNS5 0x4b	/* 4/b CNS 11643 plane 5 */
+#define I2CS_94x94_CNS6 0x4c	/* 4/c CNS 11643 plane 6 */
+#define I2CS_94x94_CNS7 0x4d	/* 4/d CNS 11643 plane 7 */
+				/* 4/e DPRK (North Korea) KGCII */
+				/* 4/f JGCII plane 1 */
+				/* 5/0 JGCII plane 2 */
+
+/* 96 character sets */
+
+#define I2CS_96_ISO8859_1 0x41	/* 4/1 Latin-1 (Western Europe) */
+#define I2CS_96_ISO8859_2 0x42	/* 4/2 Latin-2 (Czech, Slovak) */
+#define I2CS_96_ISO8859_3 0x43	/* 4/3 Latin-3 (Dutch, Turkish) */
+#define I2CS_96_ISO8859_4 0x44	/* 4/4 Latin-4 (Scandinavian) */
+				/* 4/5 CSA Z 243.4-1985 */
+#define I2CS_96_ISO8859_7 0x46	/* 4/6 Greek */
+#define I2CS_96_ISO8859_6 0x47	/* 4/7 Arabic */
+#define I2CS_96_ISO8859_8 0x48	/* 4/8 Hebrew */
+				/* 4/9 Czechoslovak CSN 369103 */
+				/* 4/a Supplementary Latin and non-alpha */
+				/* 4/b Technical */
+#define I2CS_96_ISO8859_5 0x4c	/* 4/c Cyrillic */
+#define I2CS_96_ISO8859_9 0x4d	/* 4/d Latin-5 (Finnish, Portuguese) */
+				/* 4/e ISO 6937-2 residual */
+				/* 4/f Basic Cyrillic */
+				/* 5/0 Supplementary Latin 1, 2 and 5 */
+				/* 5/1 Basic Box */
+				/* 5/2 Supplementary ISO/IEC 6937 : 1992 */
+				/* 5/3 CCITT Hebrew supplementary */
+#define I2CS_96_TIS620 0x54	/* 5/4 TIS 620 */
+				/* 5/5 Arabic/French/German */
+#define I2CS_96_ISO8859_10 0x56	/* 5/6 Latin-6 (Northern Europe) */
+				/* 5/7 ??? */
+				/* 5/8 Sami (Lappish) supplementary */
+#define I2CS_96_ISO8859_13 0x59	/* 5/9 Latin-7 (Baltic) */
+#define I2CS_96_VSCII 0x5a	/* 5/a Vietnamese */
+				/* 5/b Technical #1 IEC 1289 */
+#define I2CS_96_ISO8859_14 0x5c	/* 5/c Latin-8 (Celtic) */
+				/* 5/d Sami supplementary Latin */
+				/* 5/e Latin/Hebrew */
+				/* 5/f Celtic supplementary Latin */
+				/* 6/0 Uralic supplementary Cyrillic */
+				/* 6/1 Volgaic supplementary Cyrillic */
+#define I2CS_96_ISO8859_15 0x62	/* 6/2 Latin-9 (Euro) */
+				/* 6/3 Latin-1 with Euro */
+				/* 6/4 Latin-4 with Euro */
+				/* 6/5 Latin-7 with Euro */
+#define I2CS_96_ISO8859_16 0x66	/* 6/6 Latin-10 (Balkan) */
+				/* 6/7 Ogham */
+				/* 6/8 Sami supplementary Latin #2 */
+				/* 7/d Supplementary Mosaic for CCITT 101 */
+
+/* 96x96 character sets */
+
+/* Types of character sets */
+
+#define I2CS_94 0x000		/* 94 character set */
+#define I2CS_96 0x100		/* 96 character set */
+#define I2CS_MUL 0x200		/* multi-byte */
+#define I2CS_94x94 (I2CS_MUL | I2CS_94)
+#define I2CS_96x96 (I2CS_MUL | I2CS_96)
+
+
+/* Character set identifiers stored in Gn */
+
+#define I2CS_BRITISH (I2CS_94 | I2CS_94_BRITISH)
+#define I2CS_ASCII (I2CS_94 | I2CS_94_ASCII)
+#define I2CS_JIS_BUGROM (I2CS_94 | I2CS_94_JIS_BUGROM)
+#define I2CS_JIS_KANA (I2CS_94 | I2CS_94_JIS_KANA)
+#define I2CS_JIS_ROMAN (I2CS_94 | I2CS_94_JIS_ROMAN)
+#define I2CS_JIS_OLD (I2CS_94x94 | I2CS_94x94_JIS_OLD)
+#define I2CS_GB (I2CS_94x94 | I2CS_94x94_GB)
+#define I2CS_JIS_NEW (I2CS_94x94 | I2CS_94x94_JIS_NEW)
+#define I2CS_KSC (I2CS_94x94 | I2CS_94x94_KSC)
+#define I2CS_JIS_EXT (I2CS_94x94 | I2CS_94x94_JIS_EXT)
+#define I2CS_CNS1 (I2CS_94x94 | I2CS_94x94_CNS1)
+#define I2CS_CNS2 (I2CS_94x94 | I2CS_94x94_CNS2)
+#define I2CS_CNS3 (I2CS_94x94 | I2CS_94x94_CNS3)
+#define I2CS_CNS4 (I2CS_94x94 | I2CS_94x94_CNS4)
+#define I2CS_CNS5 (I2CS_94x94 | I2CS_94x94_CNS5)
+#define I2CS_CNS6 (I2CS_94x94 | I2CS_94x94_CNS6)
+#define I2CS_CNS7 (I2CS_94x94 | I2CS_94x94_CNS7)
+#define I2CS_ISO8859_1 (I2CS_96 | I2CS_96_ISO8859_1)
+#define I2CS_ISO8859_2 (I2CS_96 | I2CS_96_ISO8859_2)
+#define I2CS_ISO8859_3 (I2CS_96 | I2CS_96_ISO8859_3)
+#define I2CS_ISO8859_4 (I2CS_96 | I2CS_96_ISO8859_4)
+#define I2CS_ISO8859_7 (I2CS_96 | I2CS_96_ISO8859_7)
+#define I2CS_ISO8859_6 (I2CS_96 | I2CS_96_ISO8859_6)
+#define I2CS_ISO8859_8 (I2CS_96 | I2CS_96_ISO8859_8)
+#define I2CS_ISO8859_5 (I2CS_96 | I2CS_96_ISO8859_5)
+#define I2CS_ISO8859_9 (I2CS_96 | I2CS_96_ISO8859_9)
+#define I2CS_TIS620 (I2CS_96 | I2CS_96_TIS620)
+#define I2CS_ISO8859_10 (I2CS_96 | I2CS_96_ISO8859_10)
+#define I2CS_ISO8859_13 (I2CS_96 | I2CS_96_ISO8859_13)
+#define I2CS_VSCII (I2CS_96 | I2CS_96_VSCII)
+#define I2CS_ISO8859_14 (I2CS_96 | I2CS_96_ISO8859_14)
+#define I2CS_ISO8859_15 (I2CS_96 | I2CS_96_ISO8859_15)
+#define I2CS_ISO8859_16 (I2CS_96 | I2CS_96_ISO8859_16)
+
+
+/* Miscellaneous ISO 2022 definitions */
+
+#define EUC_CS2 0x8e		/* single shift CS2 */
+#define EUC_CS3 0x8f		/* single shift CS3 */
+
+#define BITS7 0x7f		/* 7-bit value mask */
+#define BIT8 0x80		/* 8th bit mask */
+
+/* The following saves us from having to have yet more charset tables */
+
+/* Unicode codepoints */
+
+#define UCS2_C0CONTROL 0x00	/* first C0 control */
+#define UCS2_C0CONTROLEND 0x1F	/* last C0 control */
+#define UCS2_C1CONTROL 0x80	/* first C1 control */
+#define UCS2_C1CONTROLEND 0x9F	/* last C1 control */
+
+				/* ISO 646 substituted Unicode codepoints */
+#define UCS2_POUNDSTERLING 0x00a3
+#define UCS2_YEN 0x00a5
+#define UCS2_OVERLINE 0x203e
+#define UCS2_EURO 0x20ac
+#define UCS2_KATAKANA 0xff61	/* first katakana codepoint */
+#define UCS2_BOM 0xfeff		/* byte order mark */
+#define UCS2_BOGON 0xfffd	/* replacement character */
+				/* next two codepoints are not Unicode chars */
+#define UCS2_BOMCHECK 0xfffe	/* used to check byte order with UCS2_BOM */
+#define UCS2_NOTCHAR 0xffff	/* not a character */
+
+#define UCS4_BMPBASE 0x0000	/* Basic Multilingual Plane */
+#define UCS4_SMPBASE 0x10000	/* Supplementary Multilinugual Plane */
+#define UCS4_SIPBASE 0x20000	/* Supplementary Ideographic Plane */
+				/* EastAsianWidth says plane 3 is wide */
+#define UCS4_UNABASE 0x40000	/* unassigned space */
+#define UCS4_SSPBASE 0xe0000	/* Supplementary Special-purpose Plane */
+#define UCS4_PVTBASE 0xf0000	/* private-space (two planes) */
+#define UCS4_MAXUNICODE 0x10ffff/* highest Unicode codepoint */
+
+#define UTF16_BASE 0x10000	/* base of codepoints needing surrogates */
+#define UTF16_SHIFT 10		/* surrogate shift */
+#define UTF16_MASK 0x3ff	/* surrogate mask */
+#define UTF16_SURR 0xd800	/* UTF-16 surrogate area */
+#define UTF16_SURRH 0xd800	/* UTF-16 first high surrogate */
+#define UTF16_SURRHEND 0xdbff	/* UTF-16 last high surrogate */
+#define UTF16_SURRL 0xdc00	/* UTF-16 first low surrogate */
+#define UTF16_SURRLEND 0xdfff	/* UTF-16 last low surrogate */
+#define UTF16_MAXSURR 0xdfff	/* end of UTF-16 surrogates */
+
+
+/* UBOGON is used to represent a codepoint in a character set which does not
+ * map to Unicode.  It is also used for mapping failures, e.g. incomplete
+ * shift sequences.  This name has the same text width as 0x????, for
+ * convenience in the mapping tables.
+ *
+ * NOCHAR is used to represent a codepoint in Unicode which does not map to
+ * the target character set in a reverse mapping table.  This name has the
+ * same text width as 0x???? in case we ever add static reverse mapping tables.
+ */
+
+#define UBOGON UCS2_BOGON
+#define NOCHAR UCS2_NOTCHAR
+
+/* Codepoints in non-Unicode character sets */
+
+/* Codepoints in ISO 646 character sets */
+
+/* British ASCII codepoints */
+
+#define BRITISH_POUNDSTERLING 0x23
+
+/* JIS Roman codepoints */
+
+#define JISROMAN_YEN 0x5c
+#define JISROMAN_OVERLINE 0x7e
+
+
+/* Hankaku katakana codepoints & parameters
+ *
+ * In earlier versions, MAX_KANA_7 and MAX_KANA_8 were the maximum codepoint
+ * values.  Although this made sense, it was confusing with the "max ku" and
+ * "max ten" values used in the double-byte tables; there are 1-origin, but
+ * the calculated values used for "ku" and "ten" are 0-origin (derived by
+ * substracting the "base").  What this all meant is that for double byte
+ * characters the limit test is of the form (value < max_ku), but for single
+ * byte characters (which used the same cell to hold the max ku) the limit
+ * test was (value <= max_ku).
+ *
+ * By making MAX_KANA_[78] be maximum+1, the same (value < max_ku) limit test
+ * is used throughout.  - 6/15/2006
+ */
+
+#define MIN_KANA_7 0x21
+#define MAX_KANA_7 0x60		/* maximum value + 1 */
+#define KANA_7 (UCS2_KATAKANA - MIN_KANA_7)
+#define MIN_KANA_8 (MIN_KANA_7 | BIT8)
+#define MAX_KANA_8 (MAX_KANA_7 | BIT8)
+#define KANA_8 (UCS2_KATAKANA - MIN_KANA_8)
+
+/* Charset scripts */
+
+/*  The term "script" is used here in a very loose sense, enough to make
+ * purists cringe.  Basically, the idea is to give the main program some
+ * idea of how it should treat the characters of text in a charset with
+ * respect to font, drawing routines, etc.
+ *
+ *  In some cases, "script" is associated with a charset; in other cases,
+ * it's more closely tied to a language.
+ */
+
+#define SC_UNICODE 0x1		/* Unicode */
+#define SC_LATIN_1 0x10		/* Western Europe */
+#define SC_LATIN_2 0x20		/* Eastern Europe */
+#define SC_LATIN_3 0x40		/* Southern Europe */
+#define SC_LATIN_4 0x80		/* Northern Europe */
+#define SC_LATIN_5 0x100	/* Turkish */
+#define SC_LATIN_6 0x200	/* Nordic */
+#define SC_LATIN_7 0x400	/* Baltic */
+#define SC_LATIN_8 0x800	/* Celtic */
+#define SC_LATIN_9 0x1000	/* Euro */
+#define SC_LATIN_0 SC_LATIN_9	/* colloquial name for Latin-9 */
+#define SC_ARABIC 0x2000
+#define SC_CYRILLIC 0x4000
+#define SC_GREEK 0x8000
+#define SC_HEBREW 0x10000
+#define SC_THAI 0x20000
+#define SC_UKRANIAN 0x40000
+#define SC_LATIN_10 0x80000	/* Balkan */
+#define SC_VIETNAMESE 0x100000
+#define SC_CHINESE_SIMPLIFIED 0x1000000
+#define SC_CHINESE_TRADITIONAL 0x2000000
+#define SC_JAPANESE 0x4000000
+#define SC_KOREAN 0x8000000
+
+
+/* Script table */
+
+typedef struct utf8_scent {
+  char *name;			/* script name */
+  char *description;		/* script description */
+  unsigned long script;		/* script bitmask */
+} SCRIPT;
+
+/* Character set table support */
+
+typedef struct utf8_csent {
+  char *name;			/* charset name */
+  unsigned short type;		/* type of charset */
+  unsigned short flags;		/* charset flags */
+  void *tab;			/* additional data */
+  unsigned long script;		/* script(s) implemented by this charset */
+  char *preferred;		/* preferred charset over this one */
+} CHARSET;
+
+
+struct utf8_eucparam {
+  unsigned int base_ku : 8;	/* base row */
+  unsigned int base_ten : 8;	/* base column */
+  unsigned int max_ku : 8;	/* maximum row */
+  unsigned int max_ten : 8;	/* maximum column */
+  void *tab;			/* conversion table */
+};
+
+
+/* Charset types */
+
+#define CT_UNKNOWN 0		/* unknown 8-bit */
+#define CT_ASCII 1		/* 7-bit ASCII no table */
+#define CT_UCS2 2		/* 2 byte 16-bit Unicode no table */
+#define CT_UCS4 3		/* 4 byte 32-bit Unicode no table */
+#define CT_1BYTE0 10		/* 1 byte ISO 8859-1 no table */
+#define CT_1BYTE 11		/* 1 byte ASCII + table 0x80-0xff */
+#define CT_1BYTE8 12		/* 1 byte table 0x00 - 0xff */
+#define CT_EUC 100		/* 2 byte ASCII + utf8_eucparam base/CS2/CS3 */
+#define CT_DBYTE 101		/* 2 byte ASCII + utf8_eucparam */
+#define CT_DBYTE2 102		/* 2 byte ASCII + utf8_eucparam plane1/2 */
+#define CT_UTF16 1000		/* variable UTF-16 encoded Unicode no table */
+#define CT_UTF8 1001		/* variable UTF-8 encoded Unicode no table */
+#define CT_UTF7 1002		/* variable UTF-7 encoded Unicode no table */
+#define CT_2022 10000		/* variable ISO-2022 encoded no table */
+#define CT_SJIS 10001		/* 2 byte Shift-JIS encoded JIS no table */
+
+
+/* Character set flags */
+
+#define CF_PRIMARY 0x1		/* primary name for this charset */
+#define CF_DISPLAY 0x2		/* charset used in displays */
+#define CF_POSTING 0x4		/* charset used in email posting */
+#define CF_UNSUPRT 0x8		/* charset unsupported (can't convert to it) */
+#define CF_NOEMAIL 0x10		/* charset not used in email */
+
+
+/* UTF-7 engine states */
+
+#define U7_ASCII 0		/* ASCII character */
+#define U7_PLUS 1		/* plus seen */
+#define U7_UNICODE 2		/* Unicode characters */
+#define U7_MINUS 3		/* absorbed minus seen */
+
+/* Function prototypes */
+
+typedef unsigned long (*ucs4cn_t) (unsigned long c);
+typedef unsigned long (*ucs4de_t) (unsigned long c,void **more);
+
+SCRIPT *utf8_script (char *script);
+const CHARSET *utf8_charset (char *charset);
+char *utf8_badcharset (char *charset);
+long utf8_text (SIZEDTEXT *text,char *charset,SIZEDTEXT *ret,long flags);
+long utf8_text_cs (SIZEDTEXT *text,const CHARSET *cs,SIZEDTEXT *ret,
+		   ucs4cn_t cv,ucs4de_t de);
+long utf8_cstext (SIZEDTEXT *text,char *charset,SIZEDTEXT *ret,
+		  unsigned long errch);
+long utf8_cstocstext (SIZEDTEXT *text,char *sc,SIZEDTEXT *ret,char *dc,
+		      unsigned long errch);
+unsigned short *utf8_rmap (char *charset);
+unsigned short *utf8_rmap_cs (const CHARSET *cs);
+unsigned short *utf8_rmap_gen (const CHARSET *cs,unsigned short *oldmap);
+long utf8_rmaptext (SIZEDTEXT *text,unsigned short *rmap,SIZEDTEXT *ret,
+		    unsigned long errch,long iso2022jp);
+unsigned long utf8_rmapsize (SIZEDTEXT *text,unsigned short *rmap,
+			     unsigned long errch,long iso2022jp);
+long ucs4_rmaptext (unsigned long *ucs4,unsigned long len,unsigned short *rmap,
+		    SIZEDTEXT *ret,unsigned long errch);
+long ucs4_rmaplen (unsigned long *ucs4,unsigned long len,unsigned short *rmap,
+		   unsigned long errch);
+long ucs4_rmapbuf (unsigned char *t,unsigned long *ucs4,unsigned long len,
+		   unsigned short *rmap,unsigned long errch);
+unsigned long utf8_get (unsigned char **s,unsigned long *i);
+unsigned long utf8_get_raw (unsigned char **s,unsigned long *i);
+unsigned long ucs4_cs_get (CHARSET *cs,unsigned char **s,unsigned long *i);
+unsigned long *utf8_csvalidmap (char *charsets[]);
+const CHARSET *utf8_infercharset (SIZEDTEXT *src);
+long utf8_validate (unsigned char *s,unsigned long i);
+void utf8_text_1byte0 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de);
+void utf8_text_1byte (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv,
+		      ucs4de_t de);
+void utf8_text_1byte8 (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv,
+		       ucs4de_t de);
+void utf8_text_euc (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv,
+		    ucs4de_t de);
+void utf8_text_dbyte (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv,
+		      ucs4de_t de);
+void utf8_text_dbyte2 (SIZEDTEXT *text,SIZEDTEXT *ret,void *tab,ucs4cn_t cv,
+		       ucs4de_t de);
+void utf8_text_sjis (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de);
+void utf8_text_2022 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de);
+void utf8_text_utf7 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de);
+void utf8_text_utf8 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de);
+void utf8_text_ucs2 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de);
+void utf8_text_ucs4 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de);
+void utf8_text_utf16 (SIZEDTEXT *text,SIZEDTEXT *ret,ucs4cn_t cv,ucs4de_t de);
+unsigned long utf8_size (unsigned long c);
+unsigned char *utf8_put (unsigned char *s,unsigned long c);
+unsigned long ucs4_titlecase (unsigned long c);
+long ucs4_width (unsigned long c);
+long utf8_strwidth (unsigned char *s);
+long utf8_textwidth (SIZEDTEXT *utf8);
+unsigned long ucs4_decompose (unsigned long c,void **more);
+unsigned long ucs4_decompose_recursive (unsigned long c,void **more);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/utf8aux.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,449 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UTF-8 auxillary routines (c-client and MIME2 support)
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 June 1997
+ * Last Edited:	12 October 2007
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include "c-client.h"
+
+/* Convert charset labelled stringlist to UTF-8 in place
+ * Accepts: string list
+ *	    charset
+ */
+
+static void utf8_stringlist (STRINGLIST *st,char *charset)
+{
+  SIZEDTEXT txt;
+				/* convert entire stringstruct */
+  if (st) do if (utf8_text (&st->text,charset,&txt,U8T_CANONICAL)) {
+    fs_give ((void **) &st->text.data);
+    st->text.data = txt.data; /* transfer this text */
+    st->text.size = txt.size;
+  } while (st = st->next);
+}
+
+
+/* Convert charset labelled searchpgm to UTF-8 in place
+ * Accepts: search program
+ *	    charset
+ */
+
+void utf8_searchpgm (SEARCHPGM *pgm,char *charset)
+{
+  SIZEDTEXT txt;
+  SEARCHHEADER *hl;
+  SEARCHOR *ol;
+  SEARCHPGMLIST *pl;
+  if (pgm) {			/* must have a search program */
+    utf8_stringlist (pgm->bcc,charset);
+    utf8_stringlist (pgm->cc,charset);
+    utf8_stringlist (pgm->from,charset);
+    utf8_stringlist (pgm->to,charset);
+    utf8_stringlist (pgm->subject,charset);
+    for (hl = pgm->header; hl; hl = hl->next) {
+      if (utf8_text (&hl->line,charset,&txt,U8T_CANONICAL)) {
+	fs_give ((void **) &hl->line.data);
+	hl->line.data = txt.data;
+	hl->line.size = txt.size;
+      }
+      if (utf8_text (&hl->text,charset,&txt,U8T_CANONICAL)) {
+	fs_give ((void **) &hl->text.data);
+	hl->text.data = txt.data;
+	hl->text.size = txt.size;
+      }
+    }
+    utf8_stringlist (pgm->body,charset);
+    utf8_stringlist (pgm->text,charset);
+    for (ol = pgm->or; ol; ol = ol->next) {
+      utf8_searchpgm (ol->first,charset);
+      utf8_searchpgm (ol->second,charset);
+    }
+    for (pl = pgm->not; pl; pl = pl->next) utf8_searchpgm (pl->pgm,charset);
+    utf8_stringlist (pgm->return_path,charset);
+    utf8_stringlist (pgm->sender,charset);
+    utf8_stringlist (pgm->reply_to,charset);
+    utf8_stringlist (pgm->in_reply_to,charset);
+    utf8_stringlist (pgm->message_id,charset);
+    utf8_stringlist (pgm->newsgroups,charset);
+    utf8_stringlist (pgm->followup_to,charset);
+    utf8_stringlist (pgm->references,charset);
+  }
+}
+
+/* Convert MIME-2 sized text to UTF-8
+ * Accepts: source sized text
+ *	    charset
+ *	    flags (same as utf8_text())
+ * Returns: T if successful, NIL if failure
+ */
+
+#define MINENCWORD 9
+#define MAXENCWORD 75
+
+/* This resizing algorithm is stupid, but hopefully it should never be triggered
+ * except for a pathological header.  The main concern is that we don't get a
+ * buffer overflow.
+ */
+
+#define DSIZE 65536		/* real headers should never be this big */
+#define FUZZ 10			/* paranoia fuzz */
+
+long utf8_mime2text (SIZEDTEXT *src,SIZEDTEXT *dst,long flags)
+{
+  unsigned char *s,*se,*e,*ee,*t,*te;
+  char *cs,*ce,*ls;
+  SIZEDTEXT txt,rtxt;
+  unsigned long i;
+  size_t dsize = min (DSIZE,((src->size / 4) + 1) * 9);
+				/* always create buffer if canonicalizing */
+  dst->data = (flags & U8T_CANONICAL) ?
+    (unsigned char *) fs_get ((size_t) dsize) : NIL;
+  dst->size = 0;		/* nothing written yet */
+				/* look for encoded words */
+  for (s = src->data, se = src->data + src->size; s < se; s++) {
+    if (((se - s) > MINENCWORD) && (*s == '=') && (s[1] == '?') &&
+      (cs = (char *) mime2_token (s+2,se,(unsigned char **) &ce)) &&
+	(e = mime2_token ((unsigned char *) ce+1,se,&ee)) &&
+	(te = mime2_text (t = e+2,se)) && (ee == e + 1) &&
+	((te - s) < MAXENCWORD)) {
+      if (mime2_decode (e,t,te,&txt)) {
+	*ce = '\0';		/* temporarily tie off charset */
+	if (ls = strchr (cs,'*')) *ls = '\0';
+				/* convert to UTF-8 as best we can */
+	if (!utf8_text (&txt,cs,&rtxt,flags)) utf8_text (&txt,NIL,&rtxt,flags);
+	if (dst->data) {	/* make sure existing buffer fits */
+	  while (dsize <= (dst->size + rtxt.size + FUZZ)) {
+	    dsize += DSIZE;	/* kick it up */
+	    fs_resize ((void **) &dst->data,dsize);
+	  }
+	}
+	else {			/* make a new buffer */
+	  while (dsize <= (dst->size + rtxt.size)) dsize += DSIZE;
+	  memcpy (dst->data = (unsigned char *) fs_get (dsize),src->data,
+		  dst->size = s - src->data);
+	}
+	for (i = 0; i < rtxt.size; i++) dst->data[dst->size++] = rtxt.data[i];
+
+				/* all done with converted text */
+	if (rtxt.data != txt.data) fs_give ((void **) &rtxt.data);
+	if (ls) *ls = '*';	/* restore language tag delimiter */
+	*ce = '?';		/* restore charset delimiter */
+				/* all done with decoded text */
+	fs_give ((void **) &txt.data);
+	s = te+1;		/* continue scan after encoded word */
+				/* skip leading whitespace */
+	for (t = s + 1; (t < se) && ((*t == ' ') || (*t == '\t')); t++);
+				/* see if likely continuation encoded word */
+	if (t < (se - MINENCWORD)) switch (*t) {
+	case '=':		/* possible encoded word? */
+	  if (t[1] == '?') s = t - 1;
+	  break;
+	case '\015':		/* CR, eat a following LF */
+	  if (t[1] == '\012') t++;
+	case '\012':		/* possible end of logical line */
+	  if ((t[1] == ' ') || (t[1] == '\t')) {
+	    do t++;
+	    while ((t < (se - MINENCWORD)) && ((t[1] == ' ')||(t[1] == '\t')));
+	    if ((t < (se - MINENCWORD)) && (t[1] == '=') && (t[2] == '?'))
+	      s = t;		/* definitely looks like continuation */
+	  }
+	}
+      }
+      else {			/* restore original text */
+	if (dst->data) fs_give ((void **) &dst->data);
+	dst->data = src->data;
+	dst->size = src->size;
+	return NIL;		/* syntax error: MIME-2 decoding failure */
+      }
+    }
+    else do if (dst->data) {	/* stash ASCII characters until LWSP */
+      if (dsize < (dst->size + FUZZ)) {
+	dsize += DSIZE;		/* kick it up */
+	fs_resize ((void **) &dst->data,dsize);
+      }
+      /* kludge: assumes ASCII doesn't decompose and titlecases to one byte */
+      dst->data[dst->size++] = (flags & U8T_CASECANON) ?
+	(unsigned char) ucs4_titlecase (*s) : *s;
+    }
+    while ((*s != ' ') && (*s != '\t') && (*s != '\015') && (*s != '\012') &&
+	   (++s < se));
+  }
+  if (dst->data) dst->data[dst->size] = '\0';
+  else {			/* nothing converted, return identity */
+    dst->data = src->data;
+    dst->size = src->size;
+  }
+  return T;			/* success */
+}
+
+/* Decode MIME-2 text
+ * Accepts: Encoding
+ *	    text
+ *	    text end
+ *	    destination sized text
+ * Returns: T if successful, else NIL
+ */
+
+long mime2_decode (unsigned char *e,unsigned char *t,unsigned char *te,
+		   SIZEDTEXT *txt)
+{
+  unsigned char *q;
+  txt->data = NIL;		/* initially no returned data */
+  switch (*e) {			/* dispatch based upon encoding */
+  case 'Q': case 'q':		/* sort-of QUOTED-PRINTABLE */
+    txt->data = (unsigned char *) fs_get ((size_t) (te - t) + 1);
+    for (q = t,txt->size = 0; q < te; q++) switch (*q) {
+    case '=':			/* quoted character */
+				/* both must be hex */
+      if (!isxdigit (q[1]) || !isxdigit (q[2])) {
+	fs_give ((void **) &txt->data);
+	return NIL;		/* syntax error: bad quoted character */
+      }
+				/* assemble character */
+      txt->data[txt->size++] = hex2byte (q[1],q[2]);
+      q += 2;			/* advance past quoted character */
+      break;
+    case '_':			/* convert to space */
+      txt->data[txt->size++] = ' ';
+      break;
+    default:			/* ordinary character */
+      txt->data[txt->size++] = *q;
+      break;
+    }
+    txt->data[txt->size] = '\0';
+    break;
+  case 'B': case 'b':		/* BASE64 */
+    if (txt->data = (unsigned char *) rfc822_base64 (t,te - t,&txt->size))
+      break;
+  default:			/* any other encoding is unknown */
+    return NIL;			/* syntax error: unknown encoding */
+  }
+  return T;
+}
+
+/* Get MIME-2 token from encoded word
+ * Accepts: current text pointer
+ *	    text limit pointer
+ *	    pointer to returned end pointer
+ * Returns: current text pointer & end pointer if success, else NIL
+ */
+
+unsigned char *mime2_token (unsigned char *s,unsigned char *se,
+			    unsigned char **t)
+{
+  for (*t = s; **t != '?'; ++*t) {
+    if ((*t < se) && isgraph (**t)) switch (**t) {
+    case '(': case ')': case '<': case '>': case '@': case ',': case ';':
+    case ':': case '\\': case '"': case '/': case '[': case ']': case '.':
+    case '=':
+      return NIL;		/* none of these are valid in tokens */
+    }
+    else return NIL;		/* out of text or CTL or space */
+  }
+  return s;
+}
+
+
+/* Get MIME-2 text from encoded word
+ * Accepts: current text pointer
+ *	    text limit pointer
+ *	    pointer to returned end pointer
+ * Returns: end pointer if success, else NIL
+ */
+
+unsigned char *mime2_text (unsigned char *s,unsigned char *se)
+{
+  unsigned char *t = se - 1;
+				/* search for closing ?, make sure valid */
+  while ((s < t) && (*s != '?') && isgraph (*s++));
+  return ((s < t) && (*s == '?') && (s[1] == '=') &&
+	  ((se == (s + 2)) || (s[2] == ' ') || (s[2] == '\t') ||
+	   (s[2] == '\015') || (s[2] == '\012'))) ? s : NIL;
+}
+
+/* Convert UTF-16 string to Modified Base64
+ * Accepts: destination pointer
+ *	    source string
+ *	    source length in octets
+ * Returns: updated destination pointer
+ */
+
+static unsigned char *utf16_to_mbase64 (unsigned char *t,unsigned char *s,
+					size_t i)
+{
+  char *v = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
+  *t++ = '&';			/* write shift-in */
+  while (i >= 3) {		/* process tuplets */
+    *t++ = v[s[0] >> 2];	/* byte 1: high 6 bits (1) */
+				/* byte 2: low 2 bits (1), high 4 bits (2) */
+    *t++ = v[((s[0] << 4) + (s[1] >> 4)) & 0x3f];
+				/* byte 3: low 4 bits (2), high 2 bits (3) */
+    *t++ = v[((s[1] << 2) + (s[2] >> 6)) & 0x3f];
+    *t++ = v[s[2] & 0x3f];	/* byte 4: low 6 bits (3) */
+    s += 3;
+    i -= 3;
+  }
+  if (i) {
+    *t++ = v[s[0] >> 2];	/* byte 1: high 6 bits (1) */
+				/* byte 2: low 2 bits (1), high 4 bits (2) */
+    *t++ = v[((s[0] << 4) + (--i ? (s[1] >> 4) : 0)) & 0x3f];
+				/* byte 3: low 4 bits (2) */
+    if (i) *t++ = v[(s[1] << 2) & 0x3f];
+  }
+  *t++ = '-';			/* write shift-out */
+  return t;
+}
+
+
+/* Poot a UTF-16 value to a buffer
+ * Accepts: buffer pointer
+ *	    value
+ * Returns: updated pointer
+ */
+
+static unsigned char *utf16_poot (unsigned char *s,unsigned long c)
+{
+  *s++ = (unsigned char) (c >> 8);
+  *s++ = (unsigned char) (c & 0xff);
+  return s;
+}
+
+/* Convert UTF-8 to Modified UTF-7
+ * Accepts: UTF-8 string
+ * Returns: Modified UTF-7 string on success, NIL if invalid UTF-8
+ */
+
+#define MAXUNIUTF8 4		/* maximum length of Unicode UTF-8 sequence */
+
+unsigned char *utf8_to_mutf7 (unsigned char *src)
+{
+  unsigned char *u16buf,*utf16;
+  unsigned char *ret,*t;
+  unsigned long j,c;
+  unsigned char *s = src;
+  unsigned long i = 0;
+  int nonascii = 0;
+  while (*s) {			/* pass one: count destination octets */
+    if (*s & 0x80) {		/* non-ASCII character? */
+      j = MAXUNIUTF8;		/* get single UCS-4 codepoint */
+      if ((c = utf8_get (&s,&j)) & U8G_ERROR) return NIL;
+				/* tally number of UTF-16 octets */
+      nonascii += (c & U8GM_NONBMP) ? 4 : 2;
+    }
+    else {			/* ASCII character */
+      if (nonascii) {		/* add pending Modified BASE64 size + shifts */
+	i += ((nonascii / 3) * 4) + ((j = nonascii % 3) ? j + 1 : 0) + 2;
+	nonascii = 0;		/* back to ASCII */
+      }
+      if (*s == '&') i += 2;	/* two octets if the escape */
+      else ++i;			/* otherwise just count another octet */
+      ++s;			/* advance to next source octet */
+    }
+  }
+  if (nonascii)			/* add pending Modified BASE64 size + shifts */
+    i += ((nonascii / 3) * 4) + ((j = nonascii % 3) ? j + 1 : 0) + 2;
+
+				/* create return buffer */
+  t = ret = (unsigned char *) fs_get (i + 1);
+				/* and scratch buffer */
+  utf16 = u16buf = (unsigned char *) fs_get (i + 1);
+  for (s = src; *s;) {		/* pass two: copy destination octets */
+    if (*s & 0x80) {		/* non-ASCII character? */
+      j = MAXUNIUTF8;		/* get single UCS-4 codepoint */
+      if ((c = utf8_get (&s,&j)) & U8G_ERROR) return NIL;
+      if (c & U8GM_NONBMP) {	/* non-BMP? */
+	c -= UTF16_BASE;	/* yes, convert to surrogate */
+	utf16 = utf16_poot (utf16_poot (utf16,(c >> UTF16_SHIFT)+UTF16_SURRH),
+			    (c & UTF16_MASK) + UTF16_SURRL);
+      }
+      else utf16 = utf16_poot (utf16,c);
+    }
+    else {			/* ASCII character */
+      if (utf16 != u16buf) {	/* add pending Modified BASE64 size + shifts */
+	t = utf16_to_mbase64 (t,u16buf,utf16 - u16buf);
+	utf16 = u16buf;		/* reset buffer */
+      }
+      *t++ = *s;		/* copy the character */
+      if (*s == '&') *t++ = '-';/* special sequence if the escape */
+      ++s;			/* advance to next source octet */
+    }
+  }
+				/* add pending Modified BASE64 size + shifts */
+  if (utf16 != u16buf) t = utf16_to_mbase64 (t,u16buf,utf16 - u16buf);
+  *t = '\0';			/* tie off destination */
+  if (i != (t - ret)) fatal ("utf8_to_mutf7 botch");
+  fs_give ((void **) &u16buf);
+  return ret;
+}
+
+/* Convert Modified UTF-7 to UTF-8
+ * Accepts: Modified UTF-7 string
+ * Returns: UTF-8 string on success, NIL if invalid Modified UTF-7
+ */
+
+unsigned char *utf8_from_mutf7 (unsigned char *src)
+{
+  SIZEDTEXT utf8,utf7;
+  unsigned char *s;
+  int mbase64 = 0;
+				/* disallow bogus strings */
+  if (mail_utf7_valid (src)) return NIL;
+				/* initialize SIZEDTEXTs */
+  memset (&utf7,0,sizeof (SIZEDTEXT));
+  memset (&utf8,0,sizeof (SIZEDTEXT));
+				/* make copy of source */
+  for (s = cpytxt (&utf7,src,strlen (src)); *s; ++s) switch (*s) {
+  case '&':			/* Modified UTF-7 uses & instead of + */
+    *s = '+';
+    mbase64 = T;		/* note that we are in Modified BASE64 */
+    break;
+  case '+':			/* temporarily swap text + to & */
+    if (!mbase64) *s = '&';
+    break;
+  case '-':			/* shift back to ASCII */
+    mbase64 = NIL;
+    break;
+  case ',':			/* Modified UTF-7 uses , instead of / ... */
+    if (mbase64) *s = '/';	/* ...in Modified BASE64 */
+    break;
+  }
+				/* do the conversion */
+  utf8_text_utf7 (&utf7,&utf8,NIL,NIL);
+				/* no longer need copy of source */
+  fs_give ((void **) &utf7.data);
+				/* post-process: switch & and + */
+  for (s = utf8.data; *s; ++s) switch (*s) {
+  case '&':
+    *s = '+';
+    break;
+  case '+':
+    *s = '&';
+    break;
+  }
+  return utf8.data;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/c-client/utf8aux.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,44 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UTF-8 auxillary routines (c-client and MIME2 support)
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 June 1997
+ * Last Edited:	9 October 2007
+ */
+
+
+/* Following routines are in utf8aux.c as these depend upon c-client.
+ * Splitting these routines out makes it possible for pico to link with utf8.o
+ * and a few rump routines (e.g., fs_get()) but not all the rest of c-client
+ * (which pico does not need).
+ */
+
+void utf8_searchpgm (SEARCHPGM *pgm,char *charset);
+long utf8_mime2text (SIZEDTEXT *src,SIZEDTEXT *dst,long flags);
+unsigned char *mime2_token (unsigned char *s,unsigned char *se,
+			    unsigned char **t);
+unsigned char *mime2_text (unsigned char *s,unsigned char *se);
+long mime2_decode (unsigned char *e,unsigned char *t,unsigned char *te,
+		   SIZEDTEXT *txt);
+unsigned char *utf8_to_mutf7 (unsigned char *src);
+unsigned char *utf8_from_mutf7 (unsigned char *src);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/charset/big5.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,2016 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	BIG-5 conversion table
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	3 July 1997
+ * Last Edited:	30 August 2006
+ */
+
+/* Big-5 is the de-facto industrial standard of the Republic of China
+ * (Taiwan), and is commonly used in the Hong Kong Special Administrative
+ * Region of the People's Republic of China (mainland China).
+ */
+
+#define BASE_BIG5_KU 0xa1
+#define BASE_BIG5_TEN_0 0x40
+#define BASE_BIG5_TEN_1 0xa1
+#define MAX_BIG5_KU 89
+#define MAX_BIG5_TEN_0 63
+#define MAX_BIG5_TEN_1 94
+
+
+#define BIG5TOUNICODE(c,c1,ku,ten)			\
+  (((ku = c - BASE_BIG5_KU) < MAX_BIG5_KU) ?		\
+   ((c1 & 0x80) ?					\
+    (((ten = c1 - BASE_BIG5_TEN_1) < MAX_BIG5_TEN_1) ?	\
+     big5tab[ku].plane1[ten] : UBOGON) :		\
+    (((ten = c1 - BASE_BIG5_TEN_0) < MAX_BIG5_TEN_0) ?	\
+     big5tab[ku].plane0[ten] : UBOGON)) : UBOGON)
+
+
+typedef struct big5_ku {
+  unsigned short plane0[MAX_BIG5_TEN_0];
+  unsigned short plane1[MAX_BIG5_TEN_1];
+} BIG5;
+
+
+static const BIG5 big5tab[MAX_BIG5_KU] = {
+  {				/* ku 01 */
+    {
+      0x3000,0xff0c,0x3001,0x3002,0xff0e,0x2022,0xff1b,0xff1a,0xff1f,0xff01,
+      0xfe30,0x2026,0x2025,0xfe50,0xff64,0xfe52,0x00b7,0xfe54,0xfe55,0xfe56,
+      0xfe57,0xff5c,0x2013,0xfe31,0x2014,0xfe33,0xfffd,0xfe34,0xfe4f,0xff08,
+      0xff09,0xfe35,0xfe36,0xff5b,0xff5d,0xfe37,0xfe38,0x3014,0x3015,0xfe39,
+      0xfe3a,0x3010,0x3011,0xfe3b,0xfe3c,0x300a,0x300b,0xfe3d,0xfe3e,0x3008,
+      0x3009,0xfe3f,0xfe40,0x300c,0x300d,0xfe41,0xfe42,0x300e,0x300f,0xfe43,
+      0xfe44,0xfe59,0xfe5a
+    },{
+      0xfe5b,0xfe5c,0xfe5d,0xfe5e,0x2018,0x2019,0x201c,0x201d,0x301d,0x301e,
+      0x2035,0x2032,0xff03,0xff06,0xff0a,0x203b,0x00a7,0x3003,0x25cb,0x25cf,
+      0x25b3,0x25b2,0x25ce,0x2606,0x2605,0x25c7,0x25c6,0x25a1,0x25a0,0x25bd,
+      0x25bc,0x32a3,0x2105,0x203e,0xfffd,0xff3f,0xfffd,0xfe49,0xfe4a,0xfe4d,
+      0xfe4e,0xfe4b,0xfe4c,0xfe5f,0xfe60,0xfe61,0xff0b,0xff0d,0x00d7,0x00f7,
+      0x00b1,0x221a,0xff1c,0xff1e,0xff1d,0x2266,0x2267,0x2260,0x221e,0x2252,
+      0x2261,0xfe62,0xfe63,0xfe64,0xfe65,0xfe66,0x223c,0x2229,0x222a,0x22a5,
+      0x2220,0x221f,0x22bf,0x33d2,0x33d1,0x222b,0x222e,0x2235,0x2234,0x2640,
+      0x2642,0x2641,0x2609,0x2191,0x2193,0x2190,0x2192,0x2196,0x2197,0x2199,
+      0x2198,0x2225,0x2223,0xfffd
+    }
+  },
+  {				/* ku 02 */
+    {
+      0xfffd,0xff0f,0xff3c,0xff04,0x00a5,0x3012,0x00a2,0x00a3,0xff05,0xff20,
+      0x2103,0x2109,0xfe69,0xfe6a,0xfe6b,0x33d5,0x339c,0x339d,0x339e,0x33ce,
+      0x33a1,0x338e,0x338f,0x33c4,0x00b0,0x5159,0x515b,0x515e,0x515d,0x5161,
+      0x5163,0x55e7,0x74e9,0x7cce,0x2581,0x2582,0x2583,0x2584,0x2585,0x2586,
+      0x2587,0x2588,0x258f,0x258e,0x258d,0x258c,0x258b,0x258a,0x2589,0x253c,
+      0x2534,0x252c,0x2524,0x251c,0x2594,0x2500,0x2502,0x2595,0x250c,0x2510,
+      0x2514,0x2518,0x256d
+    },{
+      0x256e,0x2570,0x256f,0x2550,0x255e,0x256a,0x2561,0x25e2,0x25e3,0x25e5,
+      0x25e4,0x2571,0x2572,0x2573,0xff10,0xff11,0xff12,0xff13,0xff14,0xff15,
+      0xff16,0xff17,0xff18,0xff19,0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,
+      0x2166,0x2167,0x2168,0x2169,0x3021,0x3022,0x3023,0x3024,0x3025,0x3026,
+      0x3027,0x3028,0x3029,0xfffd,0x5344,0xfffd,0xff21,0xff22,0xff23,0xff24,
+      0xff25,0xff26,0xff27,0xff28,0xff29,0xff2a,0xff2b,0xff2c,0xff2d,0xff2e,
+      0xff2f,0xff30,0xff31,0xff32,0xff33,0xff34,0xff35,0xff36,0xff37,0xff38,
+      0xff39,0xff3a,0xff41,0xff42,0xff43,0xff44,0xff45,0xff46,0xff47,0xff48,
+      0xff49,0xff4a,0xff4b,0xff4c,0xff4d,0xff4e,0xff4f,0xff50,0xff51,0xff52,
+      0xff53,0xff54,0xff55,0xff56
+    }
+  },
+  {				/* ku 03 */
+    {
+      0xff57,0xff58,0xff59,0xff5a,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,
+      0x0397,0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0,
+      0x03a1,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,0x03a8,0x03a9,0x03b1,0x03b2,
+      0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,
+      0x03bd,0x03be,0x03bf,0x03c0,0x03c1,0x03c3,0x03c4,0x03c5,0x03c6,0x03c7,
+      0x03c8,0x03c9,0x3105,0x3106,0x3107,0x3108,0x3109,0x310a,0x310b,0x310c,
+      0x310d,0x310e,0x310f
+    },{
+      0x3110,0x3111,0x3112,0x3113,0x3114,0x3115,0x3116,0x3117,0x3118,0x3119,
+      0x311a,0x311b,0x311c,0x311d,0x311e,0x311f,0x3120,0x3121,0x3122,0x3123,
+      0x3124,0x3125,0x3126,0x3127,0x3128,0x3129,0x02d9,0x02c9,0x02ca,0x02c7,
+      0x02cb,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+      UBOGON,UBOGON,UBOGON,UBOGON
+    }
+  },
+  {				/* ku 04 */
+    {
+      0x4e00,0x4e59,0x4e01,0x4e03,0x4e43,0x4e5d,0x4e86,0x4e8c,0x4eba,0x513f,
+      0x5165,0x516b,0x51e0,0x5200,0x5201,0x529b,0x5315,0x5341,0x535c,0x53c8,
+      0x4e09,0x4e0b,0x4e08,0x4e0a,0x4e2b,0x4e38,0x51e1,0x4e45,0x4e48,0x4e5f,
+      0x4e5e,0x4e8e,0x4ea1,0x5140,0x5203,0x52fa,0x5343,0x53c9,0x53e3,0x571f,
+      0x58eb,0x5915,0x5927,0x5973,0x5b50,0x5b51,0x5b53,0x5bf8,0x5c0f,0x5c22,
+      0x5c38,0x5c71,0x5ddd,0x5de5,0x5df1,0x5df2,0x5df3,0x5dfe,0x5e72,0x5efe,
+      0x5f0b,0x5f13,0x624d
+    },{
+      0x4e11,0x4e10,0x4e0d,0x4e2d,0x4e30,0x4e39,0x4e4b,0x5c39,0x4e88,0x4e91,
+      0x4e95,0x4e92,0x4e94,0x4ea2,0x4ec1,0x4ec0,0x4ec3,0x4ec6,0x4ec7,0x4ecd,
+      0x4eca,0x4ecb,0x4ec4,0x5143,0x5141,0x5167,0x516d,0x516e,0x516c,0x5197,
+      0x51f6,0x5206,0x5207,0x5208,0x52fb,0x52fe,0x52ff,0x5316,0x5339,0x5348,
+      0x5347,0x5345,0x535e,0x5384,0x53cb,0x53ca,0x53cd,0x58ec,0x5929,0x592b,
+      0x592a,0x592d,0x5b54,0x5c11,0x5c24,0x5c3a,0x5c6f,0x5df4,0x5e7b,0x5eff,
+      0x5f14,0x5f15,0x5fc3,0x6208,0x6236,0x624b,0x624e,0x652f,0x6587,0x6597,
+      0x65a4,0x65b9,0x65e5,0x66f0,0x6708,0x6728,0x6b20,0x6b62,0x6b79,0x6bcb,
+      0x6bd4,0x6bdb,0x6c0f,0x6c34,0x706b,0x722a,0x7236,0x723b,0x7247,0x7259,
+      0x725b,0x72ac,0x738b,0x4e19
+    }
+  },
+  {				/* ku 05 */
+    {
+      0x4e16,0x4e15,0x4e14,0x4e18,0x4e3b,0x4e4d,0x4e4f,0x4e4e,0x4ee5,0x4ed8,
+      0x4ed4,0x4ed5,0x4ed6,0x4ed7,0x4ee3,0x4ee4,0x4ed9,0x4ede,0x5145,0x5144,
+      0x5189,0x518a,0x51ac,0x51f9,0x51fa,0x51f8,0x520a,0x52a0,0x529f,0x5305,
+      0x5306,0x5317,0x531d,0x4edf,0x534a,0x5349,0x5361,0x5360,0x536f,0x536e,
+      0x53bb,0x53ef,0x53e4,0x53f3,0x53ec,0x53ee,0x53e9,0x53e8,0x53fc,0x53f8,
+      0x53f5,0x53eb,0x53e6,0x53ea,0x53f2,0x53f1,0x53f0,0x53e5,0x53ed,0x53fb,
+      0x56db,0x56da,0x5916
+    },{
+      0x592e,0x5931,0x5974,0x5976,0x5b55,0x5b83,0x5c3c,0x5de8,0x5de7,0x5de6,
+      0x5e02,0x5e03,0x5e73,0x5e7c,0x5f01,0x5f18,0x5f17,0x5fc5,0x620a,0x6253,
+      0x6254,0x6252,0x6251,0x65a5,0x65e6,0x672e,0x672c,0x672a,0x672b,0x672d,
+      0x6b63,0x6bcd,0x6c11,0x6c10,0x6c38,0x6c41,0x6c40,0x6c3e,0x72af,0x7384,
+      0x7389,0x74dc,0x74e6,0x7518,0x751f,0x7528,0x7529,0x7530,0x7531,0x7532,
+      0x7533,0x758b,0x767d,0x76ae,0x76bf,0x76ee,0x77db,0x77e2,0x77f3,0x793a,
+      0x79be,0x7a74,0x7acb,0x4e1e,0x4e1f,0x4e52,0x4e53,0x4e69,0x4e99,0x4ea4,
+      0x4ea6,0x4ea5,0x4eff,0x4f09,0x4f19,0x4f0a,0x4f15,0x4f0d,0x4f10,0x4f11,
+      0x4f0f,0x4ef2,0x4ef6,0x4efb,0x4ef0,0x4ef3,0x4efd,0x4f01,0x4f0b,0x5149,
+      0x5147,0x5146,0x5148,0x5168
+    }
+  },
+  {				/* ku 06 */
+    {
+      0x5171,0x518d,0x51b0,0x5217,0x5211,0x5212,0x520e,0x5216,0x52a3,0x5308,
+      0x5321,0x5320,0x5370,0x5371,0x5409,0x540f,0x540c,0x540a,0x5410,0x5401,
+      0x540b,0x5404,0x5411,0x540d,0x5408,0x5403,0x540e,0x5406,0x5412,0x56e0,
+      0x56de,0x56dd,0x5733,0x5730,0x5728,0x572d,0x572c,0x572f,0x5729,0x5919,
+      0x591a,0x5937,0x5938,0x5984,0x5978,0x5983,0x597d,0x5979,0x5982,0x5981,
+      0x5b57,0x5b58,0x5b87,0x5b88,0x5b85,0x5b89,0x5bfa,0x5c16,0x5c79,0x5dde,
+      0x5e06,0x5e76,0x5e74
+    },{
+      0x5f0f,0x5f1b,0x5fd9,0x5fd6,0x620e,0x620c,0x620d,0x6210,0x6263,0x625b,
+      0x6258,0x6536,0x65e9,0x65e8,0x65ec,0x65ed,0x66f2,0x66f3,0x6709,0x673d,
+      0x6734,0x6731,0x6735,0x6b21,0x6b64,0x6b7b,0x6c16,0x6c5d,0x6c57,0x6c59,
+      0x6c5f,0x6c60,0x6c50,0x6c55,0x6c61,0x6c5b,0x6c4d,0x6c4e,0x7070,0x725f,
+      0x725d,0x767e,0x7af9,0x7c73,0x7cf8,0x7f36,0x7f8a,0x7fbd,0x8001,0x8003,
+      0x800c,0x8012,0x8033,0x807f,0x8089,0x808b,0x808c,0x81e3,0x81ea,0x81f3,
+      0x81fc,0x820c,0x821b,0x821f,0x826e,0x8272,0x827e,0x866b,0x8840,0x884c,
+      0x8863,0x897f,0x9621,0x4e32,0x4ea8,0x4f4d,0x4f4f,0x4f47,0x4f57,0x4f5e,
+      0x4f34,0x4f5b,0x4f55,0x4f30,0x4f50,0x4f51,0x4f3d,0x4f3a,0x4f38,0x4f43,
+      0x4f54,0x4f3c,0x4f46,0x4f63
+    }
+  },
+  {				/* ku 07 */
+    {
+      0x4f5c,0x4f60,0x4f2f,0x4f4e,0x4f36,0x4f59,0x4f5d,0x4f48,0x4f5a,0x514c,
+      0x514b,0x514d,0x5175,0x51b6,0x51b7,0x5225,0x5224,0x5229,0x522a,0x5228,
+      0x52ab,0x52a9,0x52aa,0x52ac,0x5323,0x5373,0x5375,0x541d,0x542d,0x541e,
+      0x543e,0x5426,0x544e,0x5427,0x5446,0x5443,0x5433,0x5448,0x5442,0x541b,
+      0x5429,0x544a,0x5439,0x543b,0x5438,0x542e,0x5435,0x5436,0x5420,0x543c,
+      0x5440,0x5431,0x542b,0x541f,0x542c,0x56ea,0x56f0,0x56e4,0x56eb,0x574a,
+      0x5751,0x5740,0x574d
+    },{
+      0x5747,0x574e,0x573e,0x5750,0x574f,0x573b,0x58ef,0x593e,0x599d,0x5992,
+      0x59a8,0x599e,0x59a3,0x5999,0x5996,0x598d,0x59a4,0x5993,0x598a,0x59a5,
+      0x5b5d,0x5b5c,0x5b5a,0x5b5b,0x5b8c,0x5b8b,0x5b8f,0x5c2c,0x5c40,0x5c41,
+      0x5c3f,0x5c3e,0x5c90,0x5c91,0x5c94,0x5c8c,0x5deb,0x5e0c,0x5e8f,0x5e87,
+      0x5e8a,0x5ef7,0x5f04,0x5f1f,0x5f64,0x5f62,0x5f77,0x5f79,0x5fd8,0x5fcc,
+      0x5fd7,0x5fcd,0x5ff1,0x5feb,0x5ff8,0x5fea,0x6212,0x6211,0x6284,0x6297,
+      0x6296,0x6280,0x6276,0x6289,0x626d,0x628a,0x627c,0x627e,0x6279,0x6273,
+      0x6292,0x626f,0x6298,0x626e,0x6295,0x6293,0x6291,0x6286,0x6539,0x653b,
+      0x6538,0x65f1,0x66f4,0x675f,0x674e,0x674f,0x6750,0x6751,0x675c,0x6756,
+      0x675e,0x6749,0x6746,0x6760
+    }
+  },
+  {				/* ku 08 */
+    {
+      0x6753,0x6757,0x6b65,0x6bcf,0x6c42,0x6c5e,0x6c99,0x6c81,0x6c88,0x6c89,
+      0x6c85,0x6c9b,0x6c6a,0x6c7a,0x6c90,0x6c70,0x6c8c,0x6c68,0x6c96,0x6c92,
+      0x6c7d,0x6c83,0x6c72,0x6c7e,0x6c74,0x6c86,0x6c76,0x6c8d,0x6c94,0x6c98,
+      0x6c82,0x7076,0x707c,0x707d,0x7078,0x7262,0x7261,0x7260,0x72c4,0x72c2,
+      0x7396,0x752c,0x752b,0x7537,0x7538,0x7682,0x76ef,0x77e3,0x79c1,0x79c0,
+      0x79bf,0x7a76,0x7cfb,0x7f55,0x8096,0x8093,0x809d,0x8098,0x809b,0x809a,
+      0x80b2,0x826f,0x8292
+    },{
+      0x828b,0x828d,0x898b,0x89d2,0x8a00,0x8c37,0x8c46,0x8c55,0x8c9d,0x8d64,
+      0x8d70,0x8db3,0x8eab,0x8eca,0x8f9b,0x8fb0,0x8fc2,0x8fc6,0x8fc5,0x8fc4,
+      0x5de1,0x9091,0x90a2,0x90aa,0x90a6,0x90a3,0x9149,0x91c6,0x91cc,0x9632,
+      0x962e,0x9631,0x962a,0x962c,0x4e26,0x4e56,0x4e73,0x4e8b,0x4e9b,0x4e9e,
+      0x4eab,0x4eac,0x4f6f,0x4f9d,0x4f8d,0x4f73,0x4f7f,0x4f6c,0x4f9b,0x4f8b,
+      0x4f86,0x4f83,0x4f70,0x4f75,0x4f88,0x4f69,0x4f7b,0x4f96,0x4f7e,0x4f8f,
+      0x4f91,0x4f7a,0x5154,0x5152,0x5155,0x5169,0x5177,0x5176,0x5178,0x51bd,
+      0x51fd,0x523b,0x5238,0x5237,0x523a,0x5230,0x522e,0x5236,0x5241,0x52be,
+      0x52bb,0x5352,0x5354,0x5353,0x5351,0x5366,0x5377,0x5378,0x5379,0x53d6,
+      0x53d4,0x53d7,0x5473,0x5475
+    }
+  },
+  {				/* ku 09 */
+    {
+      0x5496,0x5478,0x5495,0x5480,0x547b,0x5477,0x5484,0x5492,0x5486,0x547c,
+      0x5490,0x5471,0x5476,0x548c,0x549a,0x5462,0x5468,0x548b,0x547d,0x548e,
+      0x56fa,0x5783,0x5777,0x576a,0x5769,0x5761,0x5766,0x5764,0x577c,0x591c,
+      0x5949,0x5947,0x5948,0x5944,0x5954,0x59be,0x59bb,0x59d4,0x59b9,0x59ae,
+      0x59d1,0x59c6,0x59d0,0x59cd,0x59cb,0x59d3,0x59ca,0x59af,0x59b3,0x59d2,
+      0x59c5,0x5b5f,0x5b64,0x5b63,0x5b97,0x5b9a,0x5b98,0x5b9c,0x5b99,0x5b9b,
+      0x5c1a,0x5c48,0x5c45
+    },{
+      0x5c46,0x5cb7,0x5ca1,0x5cb8,0x5ca9,0x5cab,0x5cb1,0x5cb3,0x5e18,0x5e1a,
+      0x5e16,0x5e15,0x5e1b,0x5e11,0x5e78,0x5e9a,0x5e97,0x5e9c,0x5e95,0x5e96,
+      0x5ef6,0x5f26,0x5f27,0x5f29,0x5f80,0x5f81,0x5f7f,0x5f7c,0x5fdd,0x5fe0,
+      0x5ffd,0x5ff5,0x5fff,0x600f,0x6014,0x602f,0x6035,0x6016,0x602a,0x6015,
+      0x6021,0x6027,0x6029,0x602b,0x601b,0x6216,0x6215,0x623f,0x623e,0x6240,
+      0x627f,0x62c9,0x62cc,0x62c4,0x62bf,0x62c2,0x62b9,0x62d2,0x62db,0x62ab,
+      0x62d3,0x62d4,0x62cb,0x62c8,0x62a8,0x62bd,0x62bc,0x62d0,0x62d9,0x62c7,
+      0x62cd,0x62b5,0x62da,0x62b1,0x62d8,0x62d6,0x62d7,0x62c6,0x62ac,0x62ce,
+      0x653e,0x65a7,0x65bc,0x65fa,0x6614,0x6613,0x660c,0x6606,0x6602,0x660e,
+      0x6600,0x660f,0x6615,0x660a
+    }
+  },
+  {				/* ku 0a */
+    {
+      0x6607,0x670d,0x670b,0x676d,0x678b,0x6795,0x6771,0x679c,0x6773,0x6777,
+      0x6787,0x679d,0x6797,0x676f,0x6770,0x677f,0x6789,0x677e,0x6790,0x6775,
+      0x679a,0x6793,0x677c,0x676a,0x6772,0x6b23,0x6b66,0x6b67,0x6b7f,0x6c13,
+      0x6c1b,0x6ce3,0x6ce8,0x6cf3,0x6cb1,0x6ccc,0x6ce5,0x6cb3,0x6cbd,0x6cbe,
+      0x6cbc,0x6ce2,0x6cab,0x6cd5,0x6cd3,0x6cb8,0x6cc4,0x6cb9,0x6cc1,0x6cae,
+      0x6cd7,0x6cc5,0x6cf1,0x6cbf,0x6cbb,0x6ce1,0x6cdb,0x6cca,0x6cac,0x6cef,
+      0x6cdc,0x6cd6,0x6ce0
+    },{
+      0x7095,0x708e,0x7092,0x708a,0x7099,0x722c,0x722d,0x7238,0x7248,0x7267,
+      0x7269,0x72c0,0x72ce,0x72d9,0x72d7,0x72d0,0x73a9,0x73a8,0x739f,0x73ab,
+      0x73a5,0x753d,0x759d,0x7599,0x759a,0x7684,0x76c2,0x76f2,0x76f4,0x77e5,
+      0x77fd,0x793e,0x7940,0x7941,0x79c9,0x79c8,0x7a7a,0x7a79,0x7afa,0x7cfe,
+      0x7f54,0x7f8c,0x7f8b,0x8005,0x80ba,0x80a5,0x80a2,0x80b1,0x80a1,0x80ab,
+      0x80a9,0x80b4,0x80aa,0x80af,0x81e5,0x81fe,0x820d,0x82b3,0x829d,0x8299,
+      0x82ad,0x82bd,0x829f,0x82b9,0x82b1,0x82ac,0x82a5,0x82af,0x82b8,0x82a3,
+      0x82b0,0x82be,0x82b7,0x864e,0x8671,0x521d,0x8868,0x8ecb,0x8fce,0x8fd4,
+      0x8fd1,0x90b5,0x90b8,0x90b1,0x90b6,0x91c7,0x91d1,0x9577,0x9580,0x961c,
+      0x9640,0x963f,0x963b,0x9644
+    }
+  },
+  {				/* ku 0b */
+    {
+      0x9642,0x96b9,0x96e8,0x9752,0x975e,0x4e9f,0x4ead,0x4eae,0x4fe1,0x4fb5,
+      0x4faf,0x4fbf,0x4fe0,0x4fd1,0x4fcf,0x4fdd,0x4fc3,0x4fb6,0x4fd8,0x4fdf,
+      0x4fca,0x4fd7,0x4fae,0x4fd0,0x4fc4,0x4fc2,0x4fda,0x4fce,0x4fde,0x4fb7,
+      0x5157,0x5192,0x5191,0x51a0,0x524e,0x5243,0x524a,0x524d,0x524c,0x524b,
+      0x5247,0x52c7,0x52c9,0x52c3,0x52c1,0x530d,0x5357,0x537b,0x539a,0x53db,
+      0x54ac,0x54c0,0x54a8,0x54ce,0x54c9,0x54b8,0x54a6,0x54b3,0x54c7,0x54c2,
+      0x54bd,0x54aa,0x54c1
+    },{
+      0x54c4,0x54c8,0x54af,0x54ab,0x54b1,0x54bb,0x54a9,0x54a7,0x54bf,0x56ff,
+      0x5782,0x578b,0x57a0,0x57a3,0x57a2,0x57ce,0x57ae,0x5793,0x5955,0x5951,
+      0x594f,0x594e,0x5950,0x59dc,0x59d8,0x59ff,0x59e3,0x59e8,0x5a03,0x59e5,
+      0x59ea,0x59da,0x59e6,0x5a01,0x59fb,0x5b69,0x5ba3,0x5ba6,0x5ba4,0x5ba2,
+      0x5ba5,0x5c01,0x5c4e,0x5c4f,0x5c4d,0x5c4b,0x5cd9,0x5cd2,0x5df7,0x5e1d,
+      0x5e25,0x5e1f,0x5e7d,0x5ea0,0x5ea6,0x5efa,0x5f08,0x5f2d,0x5f65,0x5f88,
+      0x5f85,0x5f8a,0x5f8b,0x5f87,0x5f8c,0x5f89,0x6012,0x601d,0x6020,0x6025,
+      0x600e,0x6028,0x604d,0x6070,0x6068,0x6062,0x6046,0x6043,0x606c,0x606b,
+      0x606a,0x6064,0x6241,0x62dc,0x6316,0x6309,0x62fc,0x62ed,0x6301,0x62ee,
+      0x62fd,0x6307,0x62f1,0x62f7
+    }
+  },
+  {				/* ku 0c */
+    {
+      0x62ef,0x62ec,0x62fe,0x62f4,0x6311,0x6302,0x653f,0x6545,0x65ab,0x65bd,
+      0x65e2,0x6625,0x662d,0x6620,0x6627,0x662f,0x661f,0x6628,0x6631,0x6624,
+      0x66f7,0x67ff,0x67d3,0x67f1,0x67d4,0x67d0,0x67ec,0x67b6,0x67af,0x67f5,
+      0x67e9,0x67ef,0x67c4,0x67d1,0x67b4,0x67da,0x67e5,0x67b8,0x67cf,0x67de,
+      0x67f3,0x67b0,0x67d9,0x67e2,0x67dd,0x67d2,0x6b6a,0x6b83,0x6b86,0x6bb5,
+      0x6bd2,0x6bd7,0x6c1f,0x6cc9,0x6d0b,0x6d32,0x6d2a,0x6d41,0x6d25,0x6d0c,
+      0x6d31,0x6d1e,0x6d17
+    },{
+      0x6d3b,0x6d3d,0x6d3e,0x6d36,0x6d1b,0x6cf5,0x6d39,0x6d27,0x6d38,0x6d29,
+      0x6d2e,0x6d35,0x6d0e,0x6d2b,0x70ab,0x70ba,0x70b3,0x70ac,0x70af,0x70ad,
+      0x70b8,0x70ae,0x70a4,0x7230,0x7272,0x726f,0x7274,0x72e9,0x72e0,0x72e1,
+      0x73b7,0x73ca,0x73bb,0x73b2,0x73cd,0x73c0,0x73b3,0x751a,0x752d,0x754f,
+      0x754c,0x754e,0x754b,0x75ab,0x75a4,0x75a5,0x75a2,0x75a3,0x7678,0x7686,
+      0x7687,0x7688,0x76c8,0x76c6,0x76c3,0x76c5,0x7701,0x76f9,0x76f8,0x7709,
+      0x770b,0x76fe,0x76fc,0x7707,0x77dc,0x7802,0x7814,0x780c,0x780d,0x7946,
+      0x7949,0x7948,0x7947,0x79b9,0x79ba,0x79d1,0x79d2,0x79cb,0x7a7f,0x7a81,
+      0x7aff,0x7afd,0x7c7d,0x7d02,0x7d05,0x7d00,0x7d09,0x7d07,0x7d04,0x7d06,
+      0x7f38,0x7f8e,0x7fbf,0x8004
+    }
+  },
+  {				/* ku 0d */
+    {
+      0x8010,0x800d,0x8011,0x8036,0x80d6,0x80e5,0x80da,0x80c3,0x80c4,0x80cc,
+      0x80e1,0x80db,0x80ce,0x80de,0x80e4,0x80dd,0x81f4,0x8222,0x82e7,0x8303,
+      0x8305,0x82e3,0x82db,0x82e6,0x8304,0x82e5,0x8302,0x8309,0x82d2,0x82d7,
+      0x82f1,0x8301,0x82dc,0x82d4,0x82d1,0x82de,0x82d3,0x82df,0x82ef,0x8306,
+      0x8650,0x8679,0x867b,0x867a,0x884d,0x886b,0x8981,0x89d4,0x8a08,0x8a02,
+      0x8a03,0x8c9e,0x8ca0,0x8d74,0x8d73,0x8db4,0x8ecd,0x8ecc,0x8ff0,0x8fe6,
+      0x8fe2,0x8fea,0x8fe5
+    },{
+      0x8fed,0x8feb,0x8fe4,0x8fe8,0x90ca,0x90ce,0x90c1,0x90c3,0x914b,0x914a,
+      0x91cd,0x9582,0x9650,0x964b,0x964c,0x964d,0x9762,0x9769,0x97cb,0x97ed,
+      0x97f3,0x9801,0x98a8,0x98db,0x98df,0x9996,0x9999,0x4e58,0x4eb3,0x500c,
+      0x500d,0x5023,0x4fef,0x5026,0x5025,0x4ff8,0x5029,0x5016,0x5006,0x503c,
+      0x501f,0x501a,0x5012,0x5011,0x4ffa,0x5000,0x5014,0x5028,0x4ff1,0x5021,
+      0x500b,0x5019,0x5018,0x4ff3,0x4fee,0x502d,0x502a,0x4ffe,0x502b,0x5009,
+      0x517c,0x51a4,0x51a5,0x51a2,0x51cd,0x51cc,0x51c6,0x51cb,0x5256,0x525c,
+      0x5254,0x525b,0x525d,0x532a,0x537f,0x539f,0x539d,0x53df,0x54e8,0x5510,
+      0x5501,0x5537,0x54fc,0x54e5,0x54f2,0x5506,0x54fa,0x5514,0x54e9,0x54ed,
+      0x54e1,0x5509,0x54ee,0x54ea
+    }
+  },
+  {				/* ku 0e */
+    {
+      0x54e6,0x5527,0x5507,0x54fd,0x550f,0x5703,0x5704,0x57c2,0x57d4,0x57cb,
+      0x57c3,0x5809,0x590f,0x5957,0x5958,0x595a,0x5a11,0x5a18,0x5a1c,0x5a1f,
+      0x5a1b,0x5a13,0x59ec,0x5a20,0x5a23,0x5a29,0x5a25,0x5a0c,0x5a09,0x5b6b,
+      0x5c58,0x5bb0,0x5bb3,0x5bb6,0x5bb4,0x5bae,0x5bb5,0x5bb9,0x5bb8,0x5c04,
+      0x5c51,0x5c55,0x5c50,0x5ced,0x5cfd,0x5cfb,0x5cea,0x5ce8,0x5cf0,0x5cf6,
+      0x5d01,0x5cf4,0x5dee,0x5e2d,0x5e2b,0x5eab,0x5ead,0x5ea7,0x5f31,0x5f92,
+      0x5f91,0x5f90,0x6059
+    },{
+      0x6063,0x6065,0x6050,0x6055,0x606d,0x6069,0x606f,0x6084,0x609f,0x609a,
+      0x608d,0x6094,0x608c,0x6085,0x6096,0x6247,0x62f3,0x6308,0x62ff,0x634e,
+      0x633e,0x632f,0x6355,0x6342,0x6346,0x634f,0x6349,0x633a,0x6350,0x633d,
+      0x632a,0x632b,0x6328,0x634d,0x634c,0x6548,0x6549,0x6599,0x65c1,0x65c5,
+      0x6642,0x6649,0x664f,0x6643,0x6652,0x664c,0x6645,0x6641,0x66f8,0x6714,
+      0x6715,0x6717,0x6821,0x6838,0x6848,0x6846,0x6853,0x6839,0x6842,0x6854,
+      0x6829,0x68b3,0x6817,0x684c,0x6851,0x683d,0x67f4,0x6850,0x6840,0x683c,
+      0x6843,0x682a,0x6845,0x6813,0x6818,0x6841,0x6b8a,0x6b89,0x6bb7,0x6c23,
+      0x6c27,0x6c28,0x6c26,0x6c24,0x6cf0,0x6d6a,0x6d95,0x6d88,0x6d87,0x6d66,
+      0x6d78,0x6d77,0x6d59,0x6d93
+    }
+  },
+  {				/* ku 0f */
+    {
+      0x6d6c,0x6d89,0x6d6e,0x6d5a,0x6d74,0x6d69,0x6d8c,0x6d8a,0x6d79,0x6d85,
+      0x6d65,0x6d94,0x70ca,0x70d8,0x70e4,0x70d9,0x70c8,0x70cf,0x7239,0x7279,
+      0x72fc,0x72f9,0x72fd,0x72f8,0x72f7,0x7386,0x73ed,0x7409,0x73ee,0x73e0,
+      0x73ea,0x73de,0x7554,0x755d,0x755c,0x755a,0x7559,0x75be,0x75c5,0x75c7,
+      0x75b2,0x75b3,0x75bd,0x75bc,0x75b9,0x75c2,0x75b8,0x768b,0x76b0,0x76ca,
+      0x76cd,0x76ce,0x7729,0x771f,0x7720,0x7728,0x77e9,0x7830,0x7827,0x7838,
+      0x781d,0x7834,0x7837
+    },{
+      0x7825,0x782d,0x7820,0x781f,0x7832,0x7955,0x7950,0x7960,0x795f,0x7956,
+      0x795e,0x795d,0x7957,0x795a,0x79e4,0x79e3,0x79e7,0x79df,0x79e6,0x79e9,
+      0x79d8,0x7a84,0x7a88,0x7ad9,0x7b06,0x7b11,0x7c89,0x7d21,0x7d17,0x7d0b,
+      0x7d0a,0x7d20,0x7d22,0x7d14,0x7d10,0x7d15,0x7d1a,0x7d1c,0x7d0d,0x7d19,
+      0x7d1b,0x7f3a,0x7f5f,0x7f94,0x7fc5,0x7fc1,0x8006,0x8018,0x8015,0x8019,
+      0x8017,0x803d,0x803f,0x80f1,0x8102,0x80f0,0x8105,0x80ed,0x80f4,0x8106,
+      0x80f8,0x80f3,0x8108,0x80fd,0x810a,0x80fc,0x80ef,0x81ed,0x81ec,0x8200,
+      0x8210,0x822a,0x822b,0x8228,0x822c,0x82bb,0x832b,0x8352,0x8354,0x834a,
+      0x8338,0x8350,0x8349,0x8335,0x8334,0x834f,0x8332,0x8339,0x8336,0x8317,
+      0x8340,0x8331,0x8328,0x8343
+    }
+  },
+  {				/* ku 10 */
+    {
+      0x8654,0x868a,0x86aa,0x8693,0x86a4,0x86a9,0x868c,0x86a3,0x869c,0x8870,
+      0x8877,0x8881,0x8882,0x887d,0x8879,0x8a18,0x8a10,0x8a0e,0x8a0c,0x8a15,
+      0x8a0a,0x8a17,0x8a13,0x8a16,0x8a0f,0x8a11,0x8c48,0x8c7a,0x8c79,0x8ca1,
+      0x8ca2,0x8d77,0x8eac,0x8ed2,0x8ed4,0x8ecf,0x8fb1,0x9001,0x9006,0x8ff7,
+      0x9000,0x8ffa,0x8ff4,0x9003,0x8ffd,0x9005,0x8ff8,0x9095,0x90e1,0x90dd,
+      0x90e2,0x9152,0x914d,0x914c,0x91d8,0x91dd,0x91d7,0x91dc,0x91d9,0x9583,
+      0x9662,0x9663,0x9661
+    },{
+      0x965b,0x965d,0x9664,0x9658,0x965e,0x96bb,0x98e2,0x99ac,0x9aa8,0x9ad8,
+      0x9b25,0x9b32,0x9b3c,0x4e7e,0x507a,0x507d,0x505c,0x5047,0x5043,0x504c,
+      0x505a,0x5049,0x5065,0x5076,0x504e,0x5055,0x5075,0x5074,0x5077,0x504f,
+      0x500f,0x506f,0x506d,0x515c,0x5195,0x51f0,0x526a,0x526f,0x52d2,0x52d9,
+      0x52d8,0x52d5,0x5310,0x530f,0x5319,0x533f,0x5340,0x533e,0x53c3,0x66fc,
+      0x5546,0x556a,0x5566,0x5544,0x555e,0x5561,0x5543,0x554a,0x5531,0x5556,
+      0x554f,0x5555,0x552f,0x5564,0x5538,0x552e,0x555c,0x552c,0x5563,0x5533,
+      0x5541,0x5557,0x5708,0x570b,0x5709,0x57df,0x5805,0x580a,0x5806,0x57e0,
+      0x57e4,0x57fa,0x5802,0x5835,0x57f7,0x57f9,0x5920,0x5962,0x5a36,0x5a41,
+      0x5a49,0x5a66,0x5a6a,0x5a40
+    }
+  },
+  {				/* ku 11 */
+    {
+      0x5a3c,0x5a62,0x5a5a,0x5a46,0x5a4a,0x5b70,0x5bc7,0x5bc5,0x5bc4,0x5bc2,
+      0x5bbf,0x5bc6,0x5c09,0x5c08,0x5c07,0x5c60,0x5c5c,0x5c5d,0x5d07,0x5d06,
+      0x5d0e,0x5d1b,0x5d16,0x5d22,0x5d11,0x5d29,0x5d14,0x5d19,0x5d24,0x5d27,
+      0x5d17,0x5de2,0x5e38,0x5e36,0x5e33,0x5e37,0x5eb7,0x5eb8,0x5eb6,0x5eb5,
+      0x5ebe,0x5f35,0x5f37,0x5f57,0x5f6c,0x5f69,0x5f6b,0x5f97,0x5f99,0x5f9e,
+      0x5f98,0x5fa1,0x5fa0,0x5f9c,0x607f,0x60a3,0x6089,0x60a0,0x60a8,0x60cb,
+      0x60b4,0x60e6,0x60bd
+    },{
+      0x60c5,0x60bb,0x60b5,0x60dc,0x60bc,0x60d8,0x60d5,0x60c6,0x60df,0x60b8,
+      0x60da,0x60c7,0x621a,0x621b,0x6248,0x63a0,0x63a7,0x6372,0x6396,0x63a2,
+      0x63a5,0x6377,0x6367,0x6398,0x63aa,0x6371,0x63a9,0x6389,0x6383,0x639b,
+      0x636b,0x63a8,0x6384,0x6388,0x6399,0x63a1,0x63ac,0x6392,0x638f,0x6380,
+      0x637b,0x6369,0x6368,0x637a,0x655d,0x6556,0x6551,0x6559,0x6557,0x555f,
+      0x654f,0x6558,0x6555,0x6554,0x659c,0x659b,0x65ac,0x65cf,0x65cb,0x65cc,
+      0x65ce,0x665d,0x665a,0x6664,0x6668,0x6666,0x665e,0x66f9,0x52d7,0x671b,
+      0x6881,0x68af,0x68a2,0x6893,0x68b5,0x687f,0x6876,0x68b1,0x68a7,0x6897,
+      0x68b0,0x6883,0x68c4,0x68ad,0x6886,0x6885,0x6894,0x689d,0x68a8,0x689f,
+      0x68a1,0x6882,0x6b32,0x6bba
+    }
+  },
+  {				/* ku 12 */
+    {
+      0x6beb,0x6bec,0x6c2b,0x6d8e,0x6dbc,0x6df3,0x6dd9,0x6db2,0x6de1,0x6dcc,
+      0x6de4,0x6dfb,0x6dfa,0x6e05,0x6dc7,0x6dcb,0x6daf,0x6dd1,0x6dae,0x6dde,
+      0x6df9,0x6db8,0x6df7,0x6df5,0x6dc5,0x6dd2,0x6e1a,0x6db5,0x6dda,0x6deb,
+      0x6dd8,0x6dea,0x6df1,0x6dee,0x6de8,0x6dc6,0x6dc4,0x6daa,0x6dec,0x6dbf,
+      0x6de6,0x70f9,0x7109,0x710a,0x70fd,0x70ef,0x723d,0x727d,0x7281,0x731c,
+      0x731b,0x7316,0x7313,0x7319,0x7387,0x7405,0x740a,0x7403,0x7406,0x73fe,
+      0x740d,0x74e0,0x74f6
+    },{
+      0x74f7,0x751c,0x7522,0x7565,0x7566,0x7562,0x7570,0x758f,0x75d4,0x75d5,
+      0x75b5,0x75ca,0x75cd,0x768e,0x76d4,0x76d2,0x76db,0x7737,0x773e,0x773c,
+      0x7736,0x7738,0x773a,0x786b,0x7843,0x784e,0x7965,0x7968,0x796d,0x79fb,
+      0x7a92,0x7a95,0x7b20,0x7b28,0x7b1b,0x7b2c,0x7b26,0x7b19,0x7b1e,0x7b2e,
+      0x7c92,0x7c97,0x7c95,0x7d46,0x7d43,0x7d71,0x7d2e,0x7d39,0x7d3c,0x7d40,
+      0x7d30,0x7d33,0x7d44,0x7d2f,0x7d42,0x7d32,0x7d31,0x7f3d,0x7f9e,0x7f9a,
+      0x7fcc,0x7fce,0x7fd2,0x801c,0x804a,0x8046,0x812f,0x8116,0x8123,0x812b,
+      0x8129,0x8130,0x8124,0x8202,0x8235,0x8237,0x8236,0x8239,0x838e,0x839e,
+      0x8398,0x8378,0x83a2,0x8396,0x83bd,0x83ab,0x8392,0x838a,0x8393,0x8389,
+      0x83a0,0x8377,0x837b,0x837c
+    }
+  },
+  {				/* ku 13 */
+    {
+      0x8386,0x83a7,0x8655,0x5f6a,0x86c7,0x86c0,0x86b6,0x86c4,0x86b5,0x86c6,
+      0x86cb,0x86b1,0x86af,0x86c9,0x8853,0x889e,0x8888,0x88ab,0x8892,0x8896,
+      0x888d,0x888b,0x8993,0x898f,0x8a2a,0x8a1d,0x8a23,0x8a25,0x8a31,0x8a2d,
+      0x8a1f,0x8a1b,0x8a22,0x8c49,0x8c5a,0x8ca9,0x8cac,0x8cab,0x8ca8,0x8caa,
+      0x8ca7,0x8d67,0x8d66,0x8dbe,0x8dba,0x8edb,0x8edf,0x9019,0x900d,0x901a,
+      0x9017,0x9023,0x901f,0x901d,0x9010,0x9015,0x901e,0x9020,0x900f,0x9022,
+      0x9016,0x901b,0x9014
+    },{
+      0x90e8,0x90ed,0x90fd,0x9157,0x91ce,0x91f5,0x91e6,0x91e3,0x91e7,0x91ed,
+      0x91e9,0x9589,0x966a,0x9675,0x9673,0x9678,0x9670,0x9674,0x9676,0x9677,
+      0x966c,0x96c0,0x96ea,0x96e9,0x7ae0,0x7adf,0x9802,0x9803,0x9b5a,0x9ce5,
+      0x9e75,0x9e7f,0x9ea5,0x9ebb,0x50a2,0x508d,0x5085,0x5099,0x5091,0x5080,
+      0x5096,0x5098,0x509a,0x6700,0x51f1,0x5272,0x5274,0x5275,0x5269,0x52de,
+      0x52dd,0x52db,0x535a,0x53a5,0x557b,0x5580,0x55a7,0x557c,0x558a,0x559d,
+      0x5598,0x5582,0x559c,0x55aa,0x5594,0x5587,0x558b,0x5583,0x55b3,0x55ae,
+      0x559f,0x553e,0x55b2,0x559a,0x55bb,0x55ac,0x55b1,0x557e,0x5589,0x55ab,
+      0x5599,0x570d,0x582f,0x582a,0x5834,0x5824,0x5830,0x5831,0x5821,0x581d,
+      0x5820,0x58f9,0x58fa,0x5960
+    }
+  },
+  {				/* ku 14 */
+    {
+      0x5a77,0x5a9a,0x5a7f,0x5a92,0x5a9b,0x5aa7,0x5b73,0x5b71,0x5bd2,0x5bcc,
+      0x5bd3,0x5bd0,0x5c0a,0x5c0b,0x5c31,0x5d4c,0x5d50,0x5d34,0x5d47,0x5dfd,
+      0x5e45,0x5e3d,0x5e40,0x5e43,0x5e7e,0x5eca,0x5ec1,0x5ec2,0x5ec4,0x5f3c,
+      0x5f6d,0x5fa9,0x5faa,0x5fa8,0x60d1,0x60e1,0x60b2,0x60b6,0x60e0,0x611c,
+      0x6123,0x60fa,0x6115,0x60f0,0x60fb,0x60f4,0x6168,0x60f1,0x610e,0x60f6,
+      0x6109,0x6100,0x6112,0x621f,0x6249,0x63a3,0x638c,0x63cf,0x63c0,0x63e9,
+      0x63c9,0x63c6,0x63cd
+    },{
+      0x63d2,0x63e3,0x63d0,0x63e1,0x63d6,0x63ed,0x63ee,0x6376,0x63f4,0x63ea,
+      0x63db,0x6452,0x63da,0x63f9,0x655e,0x6566,0x6562,0x6563,0x6591,0x6590,
+      0x65af,0x666e,0x6670,0x6674,0x6676,0x666f,0x6691,0x667a,0x667e,0x6677,
+      0x66fe,0x66ff,0x671f,0x671d,0x68fa,0x68d5,0x68e0,0x68d8,0x68d7,0x6905,
+      0x68df,0x68f5,0x68ee,0x68e7,0x68f9,0x68d2,0x68f2,0x68e3,0x68cb,0x68cd,
+      0x690d,0x6912,0x690e,0x68c9,0x68da,0x696e,0x68fb,0x6b3e,0x6b3a,0x6b3d,
+      0x6b98,0x6b96,0x6bbc,0x6bef,0x6c2e,0x6c2f,0x6c2c,0x6e2f,0x6e38,0x6e54,
+      0x6e21,0x6e32,0x6e67,0x6e4a,0x6e20,0x6e25,0x6e23,0x6e1b,0x6e5b,0x6e58,
+      0x6e24,0x6e56,0x6e6e,0x6e2d,0x6e26,0x6e6f,0x6e34,0x6e4d,0x6e3a,0x6e2c,
+      0x6e43,0x6e1d,0x6e3e,0x6ecb
+    }
+  },
+  {				/* ku 15 */
+    {
+      0x6e89,0x6e19,0x6e4e,0x6e63,0x6e44,0x6e72,0x6e69,0x6e5f,0x7119,0x711a,
+      0x7126,0x7130,0x7121,0x7136,0x716e,0x711c,0x724c,0x7284,0x7280,0x7336,
+      0x7325,0x7334,0x7329,0x743a,0x742a,0x7433,0x7422,0x7425,0x7435,0x7436,
+      0x7434,0x742f,0x741b,0x7426,0x7428,0x7525,0x7526,0x756b,0x756a,0x75e2,
+      0x75db,0x75e3,0x75d9,0x75d8,0x75de,0x75e0,0x767b,0x767c,0x7696,0x7693,
+      0x76b4,0x76dc,0x774f,0x77ed,0x785d,0x786c,0x786f,0x7a0d,0x7a08,0x7a0b,
+      0x7a05,0x7a00,0x7a98
+    },{
+      0x7a97,0x7a96,0x7ae5,0x7ae3,0x7b49,0x7b56,0x7b46,0x7b50,0x7b52,0x7b54,
+      0x7b4d,0x7b4b,0x7b4f,0x7b51,0x7c9f,0x7ca5,0x7d5e,0x7d50,0x7d68,0x7d55,
+      0x7d2b,0x7d6e,0x7d72,0x7d61,0x7d66,0x7d62,0x7d70,0x7d73,0x5584,0x7fd4,
+      0x7fd5,0x800b,0x8052,0x8085,0x8155,0x8154,0x814b,0x8151,0x814e,0x8139,
+      0x8146,0x813e,0x814c,0x8153,0x8174,0x8212,0x821c,0x83e9,0x8403,0x83f8,
+      0x840d,0x83e0,0x83c5,0x840b,0x83c1,0x83ef,0x83f1,0x83f4,0x8457,0x840a,
+      0x83f0,0x840c,0x83cc,0x83fd,0x83f2,0x83ca,0x8438,0x840e,0x8404,0x83dc,
+      0x8407,0x83d4,0x83df,0x865b,0x86df,0x86d9,0x86ed,0x86d4,0x86db,0x86e4,
+      0x86d0,0x86de,0x8857,0x88c1,0x88c2,0x88b1,0x8983,0x8996,0x8a3b,0x8a60,
+      0x8a55,0x8a5e,0x8a3c,0x8a41
+    }
+  },
+  {				/* ku 16 */
+    {
+      0x8a54,0x8a5b,0x8a50,0x8a46,0x8a34,0x8a3a,0x8a36,0x8a56,0x8c61,0x8c82,
+      0x8caf,0x8cbc,0x8cb3,0x8cbd,0x8cc1,0x8cbb,0x8cc0,0x8cb4,0x8cb7,0x8cb6,
+      0x8cbf,0x8cb8,0x8d8a,0x8d85,0x8d81,0x8dce,0x8ddd,0x8dcb,0x8dda,0x8dd1,
+      0x8dcc,0x8ddb,0x8dc6,0x8efb,0x8ef8,0x8efc,0x8f9c,0x902e,0x9035,0x9031,
+      0x9038,0x9032,0x9036,0x9102,0x90f5,0x9109,0x90fe,0x9163,0x9165,0x91cf,
+      0x9214,0x9215,0x9223,0x9209,0x921e,0x920d,0x9210,0x9207,0x9211,0x9594,
+      0x958f,0x958b,0x9591
+    },{
+      0x9593,0x9592,0x958e,0x968a,0x968e,0x968b,0x967d,0x9685,0x9686,0x968d,
+      0x9672,0x9684,0x96c1,0x96c5,0x96c4,0x96c6,0x96c7,0x96ef,0x96f2,0x97cc,
+      0x9805,0x9806,0x9808,0x98e7,0x98ea,0x98ef,0x98e9,0x98f2,0x98ed,0x99ae,
+      0x99ad,0x9ec3,0x9ecd,0x9ed1,0x4e82,0x50ad,0x50b5,0x50b2,0x50b3,0x50c5,
+      0x50be,0x50ac,0x50b7,0x50bb,0x50af,0x50c7,0x527f,0x5277,0x527d,0x52df,
+      0x52e6,0x52e4,0x52e2,0x52e3,0x532f,0x55df,0x55e8,0x55d3,0x55e6,0x55ce,
+      0x55dc,0x55c7,0x55d1,0x55e3,0x55e4,0x55ef,0x55da,0x55e1,0x55c5,0x55c6,
+      0x55e5,0x55c9,0x5712,0x5713,0x585e,0x5851,0x5858,0x5857,0x585a,0x5854,
+      0x586b,0x584c,0x586d,0x584a,0x5862,0x5852,0x584b,0x5967,0x5ac1,0x5ac9,
+      0x5acc,0x5abe,0x5abd,0x5abc
+    }
+  },
+  {				/* ku 17 */
+    {
+      0x5ab3,0x5ac2,0x5ab2,0x5d69,0x5d6f,0x5e4c,0x5e79,0x5ec9,0x5ec8,0x5f12,
+      0x5f59,0x5fac,0x5fae,0x611a,0x610f,0x6148,0x611f,0x60f3,0x611b,0x60f9,
+      0x6101,0x6108,0x614e,0x614c,0x6144,0x614d,0x613e,0x6134,0x6127,0x610d,
+      0x6106,0x6137,0x6221,0x6222,0x6413,0x643e,0x641e,0x642a,0x642d,0x643d,
+      0x642c,0x640f,0x641c,0x6414,0x640d,0x6436,0x6416,0x6417,0x6406,0x656c,
+      0x659f,0x65b0,0x6697,0x6689,0x6687,0x6688,0x6696,0x6684,0x6698,0x668d,
+      0x6703,0x6994,0x696d
+    },{
+      0x695a,0x6977,0x6960,0x6954,0x6975,0x6930,0x6982,0x694a,0x6968,0x696b,
+      0x695e,0x6953,0x6979,0x6986,0x695d,0x6963,0x695b,0x6b47,0x6b72,0x6bc0,
+      0x6bbf,0x6bd3,0x6bfd,0x6ea2,0x6eaf,0x6ed3,0x6eb6,0x6ec2,0x6e90,0x6e9d,
+      0x6ec7,0x6ec5,0x6ea5,0x6e98,0x6ebc,0x6eba,0x6eab,0x6ed1,0x6e96,0x6e9c,
+      0x6ec4,0x6ed4,0x6eaa,0x6ea7,0x6eb4,0x714e,0x7159,0x7169,0x7164,0x7149,
+      0x7167,0x715c,0x716c,0x7166,0x714c,0x7165,0x715e,0x7146,0x7168,0x7156,
+      0x723a,0x7252,0x7337,0x7345,0x733f,0x733e,0x746f,0x745a,0x7455,0x745f,
+      0x745e,0x7441,0x743f,0x7459,0x745b,0x745c,0x7576,0x7578,0x7600,0x75f0,
+      0x7601,0x75f2,0x75f1,0x75fa,0x75ff,0x75f4,0x75f3,0x76de,0x76df,0x775b,
+      0x776b,0x7766,0x775e,0x7763
+    }
+  },
+  {				/* ku 18 */
+    {
+      0x7779,0x776a,0x776c,0x775c,0x7765,0x7768,0x7762,0x77ee,0x788e,0x78b0,
+      0x7897,0x7898,0x788c,0x7889,0x787c,0x7891,0x7893,0x787f,0x797a,0x797f,
+      0x7981,0x842c,0x79bd,0x7a1c,0x7a1a,0x7a20,0x7a14,0x7a1f,0x7a1e,0x7a9f,
+      0x7aa0,0x7b77,0x7bc0,0x7b60,0x7b6e,0x7b67,0x7cb1,0x7cb3,0x7cb5,0x7d93,
+      0x7d79,0x7d91,0x7d81,0x7d8f,0x7d5b,0x7f6e,0x7f69,0x7f6a,0x7f72,0x7fa9,
+      0x7fa8,0x7fa4,0x8056,0x8058,0x8086,0x8084,0x8171,0x8170,0x8178,0x8165,
+      0x816e,0x8173,0x816b
+    },{
+      0x8179,0x817a,0x8166,0x8205,0x8247,0x8482,0x8477,0x843d,0x8431,0x8475,
+      0x8466,0x846b,0x8449,0x846c,0x845b,0x843c,0x8435,0x8461,0x8463,0x8469,
+      0x846d,0x8446,0x865e,0x865c,0x865f,0x86f9,0x8713,0x8708,0x8707,0x8700,
+      0x86fe,0x86fb,0x8702,0x8703,0x8706,0x870a,0x8859,0x88df,0x88d4,0x88d9,
+      0x88dc,0x88d8,0x88dd,0x88e1,0x88ca,0x88d5,0x88d2,0x899c,0x89e3,0x8a6b,
+      0x8a72,0x8a73,0x8a66,0x8a69,0x8a70,0x8a87,0x8a7c,0x8a63,0x8aa0,0x8a71,
+      0x8a85,0x8a6d,0x8a62,0x8a6e,0x8a6c,0x8a79,0x8a7b,0x8a3e,0x8a68,0x8c62,
+      0x8c8a,0x8c89,0x8cca,0x8cc7,0x8cc8,0x8cc4,0x8cb2,0x8cc3,0x8cc2,0x8cc5,
+      0x8de1,0x8ddf,0x8de8,0x8def,0x8df3,0x8dfa,0x8dea,0x8de4,0x8de6,0x8eb2,
+      0x8f03,0x8f09,0x8efe,0x8f0a
+    }
+  },
+  {				/* ku 19 */
+    {
+      0x8f9f,0x8fb2,0x904b,0x904a,0x9053,0x9042,0x9054,0x903c,0x9055,0x9050,
+      0x9047,0x904f,0x904e,0x904d,0x9051,0x903e,0x9041,0x9112,0x9117,0x916c,
+      0x916a,0x9169,0x91c9,0x9237,0x9257,0x9238,0x923d,0x9240,0x923e,0x925b,
+      0x924b,0x9264,0x9251,0x9234,0x9249,0x924d,0x9245,0x9239,0x923f,0x925a,
+      0x9598,0x9698,0x9694,0x9695,0x96cd,0x96cb,0x96c9,0x96ca,0x96f7,0x96fb,
+      0x96f9,0x96f6,0x9756,0x9774,0x9776,0x9810,0x9811,0x9813,0x980a,0x9812,
+      0x980c,0x98fc,0x98f4
+    },{
+      0x98fd,0x98fe,0x99b3,0x99b1,0x99b4,0x9ae1,0x9ce9,0x9e82,0x9f0e,0x9f13,
+      0x9f20,0x50e7,0x50ee,0x50e5,0x50d6,0x50ed,0x50da,0x50d5,0x50cf,0x50d1,
+      0x50f1,0x50ce,0x50e9,0x5162,0x51f3,0x5283,0x5282,0x5331,0x53ad,0x55fe,
+      0x5600,0x561b,0x5617,0x55fd,0x5614,0x5606,0x5609,0x560d,0x560e,0x55f7,
+      0x5616,0x561f,0x5608,0x5610,0x55f6,0x5718,0x5716,0x5875,0x587e,0x5883,
+      0x5893,0x588a,0x5879,0x5885,0x587d,0x58fd,0x5925,0x5922,0x5924,0x596a,
+      0x5969,0x5ae1,0x5ae6,0x5ae9,0x5ad7,0x5ad6,0x5ad8,0x5ae3,0x5b75,0x5bde,
+      0x5be7,0x5be1,0x5be5,0x5be6,0x5be8,0x5be2,0x5be4,0x5bdf,0x5c0d,0x5c62,
+      0x5d84,0x5d87,0x5e5b,0x5e63,0x5e55,0x5e57,0x5e54,0x5ed3,0x5ed6,0x5f0a,
+      0x5f46,0x5f70,0x5fb9,0x6147
+    }
+  },
+  {				/* ku 1a */
+    {
+      0x613f,0x614b,0x6177,0x6162,0x6163,0x615f,0x615a,0x6158,0x6175,0x622a,
+      0x6487,0x6458,0x6454,0x64a4,0x6478,0x645f,0x647a,0x6451,0x6467,0x6434,
+      0x646d,0x647b,0x6572,0x65a1,0x65d7,0x65d6,0x66a2,0x66a8,0x669d,0x699c,
+      0x69a8,0x6995,0x69c1,0x69ae,0x69d3,0x69cb,0x699b,0x69b7,0x69bb,0x69ab,
+      0x69b4,0x69d0,0x69cd,0x69ad,0x69cc,0x69a6,0x69c3,0x69a3,0x6b49,0x6b4c,
+      0x6c33,0x6f33,0x6f14,0x6efe,0x6f13,0x6ef4,0x6f29,0x6f3e,0x6f20,0x6f2c,
+      0x6f0f,0x6f02,0x6f22
+    },{
+      0x6eff,0x6eef,0x6f06,0x6f31,0x6f38,0x6f32,0x6f23,0x6f15,0x6f2b,0x6f2f,
+      0x6f88,0x6f2a,0x6eec,0x6f01,0x6ef2,0x6ecc,0x6ef7,0x7194,0x7199,0x717d,
+      0x718a,0x7184,0x7192,0x723e,0x7292,0x7296,0x7344,0x7350,0x7464,0x7463,
+      0x746a,0x7470,0x746d,0x7504,0x7591,0x7627,0x760d,0x760b,0x7609,0x7613,
+      0x76e1,0x76e3,0x7784,0x777d,0x777f,0x7761,0x78c1,0x789f,0x78a7,0x78b3,
+      0x78a9,0x78a3,0x798e,0x798f,0x798d,0x7a2e,0x7a31,0x7aaa,0x7aa9,0x7aed,
+      0x7aef,0x7ba1,0x7b95,0x7b8b,0x7b75,0x7b97,0x7b9d,0x7b94,0x7b8f,0x7bb8,
+      0x7b87,0x7b84,0x7cb9,0x7cbd,0x7cbe,0x7dbb,0x7db0,0x7d9c,0x7dbd,0x7dbe,
+      0x7da0,0x7dca,0x7db4,0x7db2,0x7db1,0x7dba,0x7da2,0x7dbf,0x7db5,0x7db8,
+      0x7dad,0x7dd2,0x7dc7,0x7dac
+    }
+  },
+  {				/* ku 1b */
+    {
+      0x7f70,0x7fe0,0x7fe1,0x7fdf,0x805e,0x805a,0x8087,0x8150,0x8180,0x818f,
+      0x8188,0x818a,0x817f,0x8182,0x81e7,0x81fa,0x8207,0x8214,0x821e,0x824b,
+      0x84c9,0x84bf,0x84c6,0x84c4,0x8499,0x849e,0x84b2,0x849c,0x84cb,0x84b8,
+      0x84c0,0x84d3,0x8490,0x84bc,0x84d1,0x84ca,0x873f,0x871c,0x873b,0x8722,
+      0x8725,0x8734,0x8718,0x8755,0x8737,0x8729,0x88f3,0x8902,0x88f4,0x88f9,
+      0x88f8,0x88fd,0x88e8,0x891a,0x88ef,0x8aa6,0x8a8c,0x8a9e,0x8aa3,0x8a8d,
+      0x8aa1,0x8a93,0x8aa4
+    },{
+      0x8aaa,0x8aa5,0x8aa8,0x8a98,0x8a91,0x8a9a,0x8aa7,0x8c6a,0x8c8d,0x8c8c,
+      0x8cd3,0x8cd1,0x8cd2,0x8d6b,0x8d99,0x8d95,0x8dfc,0x8f14,0x8f12,0x8f15,
+      0x8f13,0x8fa3,0x9060,0x9058,0x905c,0x9063,0x9059,0x905e,0x9062,0x905d,
+      0x905b,0x9119,0x9118,0x911e,0x9175,0x9178,0x9177,0x9174,0x9278,0x9280,
+      0x9285,0x9298,0x9296,0x927b,0x9293,0x929c,0x92a8,0x927c,0x9291,0x95a1,
+      0x95a8,0x95a9,0x95a3,0x95a5,0x95a4,0x9699,0x969c,0x969b,0x96cc,0x96d2,
+      0x9700,0x977c,0x9785,0x97f6,0x9817,0x9818,0x98af,0x98b1,0x9903,0x9905,
+      0x990c,0x9909,0x99c1,0x9aaf,0x9ab0,0x9ae6,0x9b41,0x9b42,0x9cf4,0x9cf6,
+      0x9cf3,0x9ebc,0x9f3b,0x9f4a,0x5104,0x5100,0x50fb,0x50f5,0x50f9,0x5102,
+      0x5108,0x5109,0x5105,0x51dc
+    }
+  },
+  {				/* ku 1c */
+    {
+      0x5287,0x5288,0x5289,0x528d,0x528a,0x52f0,0x53b2,0x562e,0x563b,0x5639,
+      0x5632,0x563f,0x5634,0x5629,0x5653,0x564e,0x5657,0x5674,0x5636,0x562f,
+      0x5630,0x5880,0x589f,0x589e,0x58b3,0x589c,0x58ae,0x58a9,0x58a6,0x596d,
+      0x5b09,0x5afb,0x5b0b,0x5af5,0x5b0c,0x5b08,0x5bee,0x5bec,0x5be9,0x5beb,
+      0x5c64,0x5c65,0x5d9d,0x5d94,0x5e62,0x5e5f,0x5e61,0x5ee2,0x5eda,0x5edf,
+      0x5edd,0x5ee3,0x5ee0,0x5f48,0x5f71,0x5fb7,0x5fb5,0x6176,0x6167,0x616e,
+      0x615d,0x6155,0x6182
+    },{
+      0x617c,0x6170,0x616b,0x617e,0x61a7,0x6190,0x61ab,0x618e,0x61ac,0x619a,
+      0x61a4,0x6194,0x61ae,0x622e,0x6469,0x646f,0x6479,0x649e,0x64b2,0x6488,
+      0x6490,0x64b0,0x64a5,0x6493,0x6495,0x64a9,0x6492,0x64ae,0x64ad,0x64ab,
+      0x649a,0x64ac,0x6499,0x64a2,0x64b3,0x6575,0x6577,0x6578,0x66ae,0x66ab,
+      0x66b4,0x66b1,0x6a23,0x6a1f,0x69e8,0x6a01,0x6a1e,0x6a19,0x69fd,0x6a21,
+      0x6a13,0x6a0a,0x69f3,0x6a02,0x6a05,0x69ed,0x6a11,0x6b50,0x6b4e,0x6ba4,
+      0x6bc5,0x6bc6,0x6f3f,0x6f7c,0x6f84,0x6f51,0x6f66,0x6f54,0x6f86,0x6f6d,
+      0x6f5b,0x6f78,0x6f6e,0x6f8e,0x6f7a,0x6f70,0x6f64,0x6f97,0x6f58,0x6ed5,
+      0x6f6f,0x6f60,0x6f5f,0x719f,0x71ac,0x71b1,0x71a8,0x7256,0x729b,0x734e,
+      0x7357,0x7469,0x748b,0x7483
+    }
+  },
+  {				/* ku 1d */
+    {
+      0x747e,0x7480,0x757f,0x7620,0x7629,0x761f,0x7624,0x7626,0x7621,0x7622,
+      0x769a,0x76ba,0x76e4,0x778e,0x7787,0x778c,0x7791,0x778b,0x78cb,0x78c5,
+      0x78ba,0x78ca,0x78be,0x78d5,0x78bc,0x78d0,0x7a3f,0x7a3c,0x7a40,0x7a3d,
+      0x7a37,0x7a3b,0x7aaf,0x7aae,0x7bad,0x7bb1,0x7bc4,0x7bb4,0x7bc6,0x7bc7,
+      0x7bc1,0x7ba0,0x7bcc,0x7cca,0x7de0,0x7df4,0x7def,0x7dfb,0x7dd8,0x7dec,
+      0x7ddd,0x7de8,0x7de3,0x7dda,0x7dde,0x7de9,0x7d9e,0x7dd9,0x7df2,0x7df9,
+      0x7f75,0x7f77,0x7faf
+    },{
+      0x7fe9,0x8026,0x819b,0x819c,0x819d,0x81a0,0x819a,0x8198,0x8517,0x853d,
+      0x851a,0x84ee,0x852c,0x852d,0x8513,0x8511,0x8523,0x8521,0x8514,0x84ec,
+      0x8525,0x84ff,0x8506,0x8782,0x8774,0x8776,0x8760,0x8766,0x8778,0x8768,
+      0x8759,0x8757,0x874c,0x8753,0x885b,0x885d,0x8910,0x8907,0x8912,0x8913,
+      0x8915,0x890a,0x8abc,0x8ad2,0x8ac7,0x8ac4,0x8a95,0x8acb,0x8af8,0x8ab2,
+      0x8ac9,0x8ac2,0x8abf,0x8ab0,0x8ad6,0x8acd,0x8ab6,0x8ab9,0x8adb,0x8c4c,
+      0x8c4e,0x8c6c,0x8ce0,0x8cde,0x8ce6,0x8ce4,0x8cec,0x8ced,0x8ce2,0x8ce3,
+      0x8cdc,0x8cea,0x8ce1,0x8d6d,0x8d9f,0x8da3,0x8e2b,0x8e10,0x8e1d,0x8e22,
+      0x8e0f,0x8e29,0x8e1f,0x8e21,0x8e1e,0x8eba,0x8f1d,0x8f1b,0x8f1f,0x8f29,
+      0x8f26,0x8f2a,0x8f1c,0x8f1e
+    }
+  },
+  {				/* ku 1e */
+    {
+      0x8f25,0x9069,0x906e,0x9068,0x906d,0x9077,0x9130,0x912d,0x9127,0x9131,
+      0x9187,0x9189,0x918b,0x9183,0x92c5,0x92bb,0x92b7,0x92ea,0x92ac,0x92e4,
+      0x92c1,0x92b3,0x92bc,0x92d2,0x92c7,0x92f0,0x92b2,0x95ad,0x95b1,0x9704,
+      0x9706,0x9707,0x9709,0x9760,0x978d,0x978b,0x978f,0x9821,0x982b,0x981c,
+      0x98b3,0x990a,0x9913,0x9912,0x9918,0x99dd,0x99d0,0x99df,0x99db,0x99d1,
+      0x99d5,0x99d2,0x99d9,0x9ab7,0x9aee,0x9aef,0x9b27,0x9b45,0x9b44,0x9b77,
+      0x9b6f,0x9d06,0x9d09
+    },{
+      0x9d03,0x9ea9,0x9ebe,0x9ece,0x58a8,0x9f52,0x5112,0x5118,0x5114,0x5110,
+      0x5115,0x5180,0x51aa,0x51dd,0x5291,0x5293,0x52f3,0x5659,0x566b,0x5679,
+      0x5669,0x5664,0x5678,0x566a,0x5668,0x5665,0x5671,0x566f,0x566c,0x5662,
+      0x5676,0x58c1,0x58be,0x58c7,0x58c5,0x596e,0x5b1d,0x5b34,0x5b78,0x5bf0,
+      0x5c0e,0x5f4a,0x61b2,0x6191,0x61a9,0x618a,0x61cd,0x61b6,0x61be,0x61ca,
+      0x61c8,0x6230,0x64c5,0x64c1,0x64cb,0x64bb,0x64bc,0x64da,0x64c4,0x64c7,
+      0x64c2,0x64cd,0x64bf,0x64d2,0x64d4,0x64be,0x6574,0x66c6,0x66c9,0x66b9,
+      0x66c4,0x66c7,0x66b8,0x6a3d,0x6a38,0x6a3a,0x6a59,0x6a6b,0x6a58,0x6a39,
+      0x6a44,0x6a62,0x6a61,0x6a4b,0x6a47,0x6a35,0x6a5f,0x6a48,0x6b59,0x6b77,
+      0x6c05,0x6fc2,0x6fb1,0x6fa1
+    }
+  },
+  {				/* ku 1f */
+    {
+      0x6fc3,0x6fa4,0x6fc1,0x6fa7,0x6fb3,0x6fc0,0x6fb9,0x6fb6,0x6fa6,0x6fa0,
+      0x6fb4,0x71be,0x71c9,0x71d0,0x71d2,0x71c8,0x71d5,0x71b9,0x71ce,0x71d9,
+      0x71dc,0x71c3,0x71c4,0x7368,0x749c,0x74a3,0x7498,0x749f,0x749e,0x74e2,
+      0x750c,0x750d,0x7634,0x7638,0x763a,0x76e7,0x76e5,0x77a0,0x779e,0x779f,
+      0x77a5,0x78e8,0x78da,0x78ec,0x78e7,0x79a6,0x7a4d,0x7a4e,0x7a46,0x7a4c,
+      0x7a4b,0x7aba,0x7bd9,0x7c11,0x7bc9,0x7be4,0x7bdb,0x7be1,0x7be9,0x7be6,
+      0x7cd5,0x7cd6,0x7e0a
+    },{
+      0x7e11,0x7e08,0x7e1b,0x7e23,0x7e1e,0x7e1d,0x7e09,0x7e10,0x7f79,0x7fb2,
+      0x7ff0,0x7ff1,0x7fee,0x8028,0x81b3,0x81a9,0x81a8,0x81fb,0x8208,0x8258,
+      0x8259,0x854a,0x8559,0x8548,0x8568,0x8569,0x8543,0x8549,0x856d,0x856a,
+      0x855e,0x8783,0x879f,0x879e,0x87a2,0x878d,0x8861,0x892a,0x8932,0x8925,
+      0x892b,0x8921,0x89aa,0x89a6,0x8ae6,0x8afa,0x8aeb,0x8af1,0x8b00,0x8adc,
+      0x8ae7,0x8aee,0x8afe,0x8b01,0x8b02,0x8af7,0x8aed,0x8af3,0x8af6,0x8afc,
+      0x8c6b,0x8c6d,0x8c93,0x8cf4,0x8e44,0x8e31,0x8e34,0x8e42,0x8e39,0x8e35,
+      0x8f3b,0x8f2f,0x8f38,0x8f33,0x8fa8,0x8fa6,0x9075,0x9074,0x9078,0x9072,
+      0x907c,0x907a,0x9134,0x9192,0x9320,0x9336,0x92f8,0x9333,0x932f,0x9322,
+      0x92fc,0x932b,0x9304,0x931a
+    }
+  },
+  {				/* ku 20 */
+    {
+      0x9310,0x9326,0x9321,0x9315,0x932e,0x9319,0x95bb,0x96a7,0x96a8,0x96aa,
+      0x96d5,0x970e,0x9711,0x9716,0x970d,0x9713,0x970f,0x975b,0x975c,0x9766,
+      0x9798,0x9830,0x9838,0x983b,0x9837,0x982d,0x9839,0x9824,0x9910,0x9928,
+      0x991e,0x991b,0x9921,0x991a,0x99ed,0x99e2,0x99f1,0x9ab8,0x9abc,0x9afb,
+      0x9aed,0x9b28,0x9b91,0x9d15,0x9d23,0x9d26,0x9d28,0x9d12,0x9d1b,0x9ed8,
+      0x9ed4,0x9f8d,0x9f9c,0x512a,0x511f,0x5121,0x5132,0x52f5,0x568e,0x5680,
+      0x5690,0x5685,0x5687
+    },{
+      0x568f,0x58d5,0x58d3,0x58d1,0x58ce,0x5b30,0x5b2a,0x5b24,0x5b7a,0x5c37,
+      0x5c68,0x5dbc,0x5dba,0x5dbd,0x5db8,0x5e6b,0x5f4c,0x5fbd,0x61c9,0x61c2,
+      0x61c7,0x61e6,0x61cb,0x6232,0x6234,0x64ce,0x64ca,0x64d8,0x64e0,0x64f0,
+      0x64e6,0x64ec,0x64f1,0x64e2,0x64ed,0x6582,0x6583,0x66d9,0x66d6,0x6a80,
+      0x6a94,0x6a84,0x6aa2,0x6a9c,0x6adb,0x6aa3,0x6a7e,0x6a97,0x6a90,0x6aa0,
+      0x6b5c,0x6bae,0x6bda,0x6c08,0x6fd8,0x6ff1,0x6fdf,0x6fe0,0x6fdb,0x6fe4,
+      0x6feb,0x6fef,0x6f80,0x6fec,0x6fe1,0x6fe9,0x6fd5,0x6fee,0x6ff0,0x71e7,
+      0x71df,0x71ee,0x71e6,0x71e5,0x71ed,0x71ec,0x71f4,0x71e0,0x7235,0x7246,
+      0x7370,0x7372,0x74a9,0x74b0,0x74a6,0x74a8,0x7646,0x7642,0x764c,0x76ea,
+      0x77b3,0x77aa,0x77b0,0x77ac
+    }
+  },
+  {				/* ku 21 */
+    {
+      0x77a7,0x77ad,0x77ef,0x78f7,0x78fa,0x78f4,0x78ef,0x7901,0x79a7,0x79aa,
+      0x7a57,0x7abf,0x7c07,0x7c0d,0x7bfe,0x7bf7,0x7c0c,0x7be0,0x7ce0,0x7cdc,
+      0x7cde,0x7ce2,0x7cdf,0x7cd9,0x7cdd,0x7e2e,0x7e3e,0x7e46,0x7e37,0x7e32,
+      0x7e43,0x7e2b,0x7e3d,0x7e31,0x7e45,0x7e41,0x7e34,0x7e39,0x7e48,0x7e35,
+      0x7e3f,0x7e2f,0x7f44,0x7ff3,0x7ffc,0x8071,0x8072,0x8070,0x806f,0x8073,
+      0x81c6,0x81c3,0x81ba,0x81c2,0x81c0,0x81bf,0x81bd,0x81c9,0x81be,0x81e8,
+      0x8209,0x8271,0x85aa
+    },{
+      0x8584,0x857e,0x859c,0x8591,0x8594,0x85af,0x859b,0x8587,0x85a8,0x858a,
+      0x8667,0x87c0,0x87d1,0x87b3,0x87d2,0x87c6,0x87ab,0x87bb,0x87ba,0x87c8,
+      0x87cb,0x893b,0x8936,0x8944,0x8938,0x893d,0x89ac,0x8b0e,0x8b17,0x8b19,
+      0x8b1b,0x8b0a,0x8b20,0x8b1d,0x8b04,0x8b10,0x8c41,0x8c3f,0x8c73,0x8cfa,
+      0x8cfd,0x8cfc,0x8cf8,0x8cfb,0x8da8,0x8e49,0x8e4b,0x8e48,0x8e4a,0x8f44,
+      0x8f3e,0x8f42,0x8f45,0x8f3f,0x907f,0x907d,0x9084,0x9081,0x9082,0x9080,
+      0x9139,0x91a3,0x919e,0x919c,0x934d,0x9382,0x9328,0x9375,0x934a,0x9365,
+      0x934b,0x9318,0x937e,0x936c,0x935b,0x9370,0x935a,0x9354,0x95ca,0x95cb,
+      0x95cc,0x95c8,0x95c6,0x96b1,0x96b8,0x96d6,0x971c,0x971e,0x97a0,0x97d3,
+      0x9846,0x98b6,0x9935,0x9a01
+    }
+  },
+  {				/* ku 22 */
+    {
+      0x99ff,0x9bae,0x9bab,0x9baa,0x9bad,0x9d3b,0x9d3f,0x9e8b,0x9ecf,0x9ede,
+      0x9edc,0x9edd,0x9edb,0x9f3e,0x9f4b,0x53e2,0x5695,0x56ae,0x58d9,0x58d8,
+      0x5b38,0x5f5d,0x61e3,0x6233,0x64f4,0x64f2,0x64fe,0x6506,0x64fa,0x64fb,
+      0x64f7,0x65b7,0x66dc,0x6726,0x6ab3,0x6aac,0x6ac3,0x6abb,0x6ab8,0x6ac2,
+      0x6aae,0x6aaf,0x6b5f,0x6b78,0x6baf,0x7009,0x700b,0x6ffe,0x7006,0x6ffa,
+      0x7011,0x700f,0x71fb,0x71fc,0x71fe,0x71f8,0x7377,0x7375,0x74a7,0x74bf,
+      0x7515,0x7656,0x7658
+    },{
+      0x7652,0x77bd,0x77bf,0x77bb,0x77bc,0x790e,0x79ae,0x7a61,0x7a62,0x7a60,
+      0x7ac4,0x7ac5,0x7c2b,0x7c27,0x7c2a,0x7c1e,0x7c23,0x7c21,0x7ce7,0x7e54,
+      0x7e55,0x7e5e,0x7e5a,0x7e61,0x7e52,0x7e59,0x7f48,0x7ff9,0x7ffb,0x8077,
+      0x8076,0x81cd,0x81cf,0x820a,0x85cf,0x85a9,0x85cd,0x85d0,0x85c9,0x85b0,
+      0x85ba,0x85b9,0x85a6,0x87ef,0x87ec,0x87f2,0x87e0,0x8986,0x89b2,0x89f4,
+      0x8b28,0x8b39,0x8b2c,0x8b2b,0x8c50,0x8d05,0x8e59,0x8e63,0x8e66,0x8e64,
+      0x8e5f,0x8e55,0x8ec0,0x8f49,0x8f4d,0x9087,0x9083,0x9088,0x91ab,0x91ac,
+      0x91d0,0x9394,0x938a,0x9396,0x93a2,0x93b3,0x93ae,0x93ac,0x93b0,0x9398,
+      0x939a,0x9397,0x95d4,0x95d6,0x95d0,0x95d5,0x96e2,0x96dc,0x96d9,0x96db,
+      0x96de,0x9724,0x97a3,0x97a6
+    }
+  },
+  {				/* ku 23 */
+    {
+      0x97ad,0x97f9,0x984d,0x984f,0x984c,0x984e,0x9853,0x98ba,0x993e,0x993f,
+      0x993d,0x992e,0x99a5,0x9a0e,0x9ac1,0x9b03,0x9b06,0x9b4f,0x9b4e,0x9b4d,
+      0x9bca,0x9bc9,0x9bfd,0x9bc8,0x9bc0,0x9d51,0x9d5d,0x9d60,0x9ee0,0x9f15,
+      0x9f2c,0x5133,0x56a5,0x58de,0x58df,0x58e2,0x5bf5,0x9f90,0x5eec,0x61f2,
+      0x61f7,0x61f6,0x61f5,0x6500,0x650f,0x66e0,0x66dd,0x6ae5,0x6add,0x6ada,
+      0x6ad3,0x701b,0x701f,0x7028,0x701a,0x701d,0x7015,0x7018,0x7206,0x720d,
+      0x7258,0x72a2,0x7378
+    },{
+      0x737a,0x74bd,0x74ca,0x74e3,0x7587,0x7586,0x765f,0x7661,0x77c7,0x7919,
+      0x79b1,0x7a6b,0x7a69,0x7c3e,0x7c3f,0x7c38,0x7c3d,0x7c37,0x7c40,0x7e6b,
+      0x7e6d,0x7e79,0x7e69,0x7e6a,0x7f85,0x7e73,0x7fb6,0x7fb9,0x7fb8,0x81d8,
+      0x85e9,0x85dd,0x85ea,0x85d5,0x85e4,0x85e5,0x85f7,0x87fb,0x8805,0x880d,
+      0x87f9,0x87fe,0x8960,0x895f,0x8956,0x895e,0x8b41,0x8b5c,0x8b58,0x8b49,
+      0x8b5a,0x8b4e,0x8b4f,0x8b46,0x8b59,0x8d08,0x8d0a,0x8e7c,0x8e72,0x8e87,
+      0x8e76,0x8e6c,0x8e7a,0x8e74,0x8f54,0x8f4e,0x8fad,0x908a,0x908b,0x91b1,
+      0x91ae,0x93e1,0x93d1,0x93df,0x93c3,0x93c8,0x93dc,0x93dd,0x93d6,0x93e2,
+      0x93cd,0x93d8,0x93e4,0x93d7,0x93e8,0x95dc,0x96b4,0x96e3,0x972a,0x9727,
+      0x9761,0x97dc,0x97fb,0x985e
+    }
+  },
+  {				/* ku 24 */
+    {
+      0x9858,0x985b,0x98bc,0x9945,0x9949,0x9a16,0x9a19,0x9b0d,0x9be8,0x9be7,
+      0x9bd6,0x9bdb,0x9d89,0x9d61,0x9d72,0x9d6a,0x9d6c,0x9e92,0x9e97,0x9e93,
+      0x9eb4,0x52f8,0x56a8,0x56b7,0x56b6,0x56b4,0x56bc,0x58e4,0x5b40,0x5b43,
+      0x5b7d,0x5bf6,0x5dc9,0x61f8,0x61fa,0x6518,0x6514,0x6519,0x66e6,0x6727,
+      0x6aec,0x703e,0x7030,0x7032,0x7210,0x737b,0x74cf,0x7662,0x7665,0x7926,
+      0x792a,0x792c,0x792b,0x7ac7,0x7af6,0x7c4c,0x7c43,0x7c4d,0x7cef,0x7cf0,
+      0x8fae,0x7e7d,0x7e7c
+    },{
+      0x7e82,0x7f4c,0x8000,0x81da,0x8266,0x85fb,0x85f9,0x8611,0x85fa,0x8606,
+      0x860b,0x8607,0x860a,0x8814,0x8815,0x8964,0x89ba,0x89f8,0x8b70,0x8b6c,
+      0x8b66,0x8b6f,0x8b5f,0x8b6b,0x8d0f,0x8d0d,0x8e89,0x8e81,0x8e85,0x8e82,
+      0x91b4,0x91cb,0x9418,0x9403,0x93fd,0x95e1,0x9730,0x98c4,0x9952,0x9951,
+      0x99a8,0x9a2b,0x9a30,0x9a37,0x9a35,0x9c13,0x9c0d,0x9e79,0x9eb5,0x9ee8,
+      0x9f2f,0x9f5f,0x9f63,0x9f61,0x5137,0x5138,0x56c1,0x56c0,0x56c2,0x5914,
+      0x5c6c,0x5dcd,0x61fc,0x61fe,0x651d,0x651c,0x6595,0x66e9,0x6afb,0x6b04,
+      0x6afa,0x6bb2,0x704c,0x721b,0x72a7,0x74d6,0x74d4,0x7669,0x77d3,0x7c50,
+      0x7e8f,0x7e8c,0x7fbc,0x8617,0x862d,0x861a,0x8823,0x8822,0x8821,0x881f,
+      0x896a,0x896c,0x89bd,0x8b74
+    }
+  },
+  {				/* ku 25 */
+    {
+      0x8b77,0x8b7d,0x8d13,0x8e8a,0x8e8d,0x8e8b,0x8f5f,0x8faf,0x91ba,0x942e,
+      0x9433,0x9435,0x943a,0x9438,0x9432,0x942b,0x95e2,0x9738,0x9739,0x9732,
+      0x97ff,0x9867,0x9865,0x9957,0x9a45,0x9a43,0x9a40,0x9a3e,0x9acf,0x9b54,
+      0x9b51,0x9c2d,0x9c25,0x9daf,0x9db4,0x9dc2,0x9db8,0x9e9d,0x9eef,0x9f19,
+      0x9f5c,0x9f66,0x9f67,0x513c,0x513b,0x56c8,0x56ca,0x56c9,0x5b7f,0x5dd4,
+      0x5dd2,0x5f4e,0x61ff,0x6524,0x6b0a,0x6b61,0x7051,0x7058,0x7380,0x74e4,
+      0x758a,0x766e,0x766c
+    },{
+      0x79b3,0x7c60,0x7c5f,0x807e,0x807d,0x81df,0x8972,0x896f,0x89fc,0x8b80,
+      0x8d16,0x8d17,0x8e91,0x8e93,0x8f61,0x9148,0x9444,0x9451,0x9452,0x973d,
+      0x973e,0x97c3,0x97c1,0x986b,0x9955,0x9a55,0x9a4d,0x9ad2,0x9b1a,0x9c49,
+      0x9c31,0x9c3e,0x9c3b,0x9dd3,0x9dd7,0x9f34,0x9f6c,0x9f6a,0x9f94,0x56cc,
+      0x5dd6,0x6200,0x6523,0x652b,0x652a,0x66ec,0x6b10,0x74da,0x7aca,0x7c64,
+      0x7c63,0x7c65,0x7e93,0x7e96,0x7e94,0x81e2,0x8638,0x863f,0x8831,0x8b8a,
+      0x9090,0x908f,0x9463,0x9460,0x9464,0x9768,0x986f,0x995c,0x9a5a,0x9a5b,
+      0x9a57,0x9ad3,0x9ad4,0x9ad1,0x9c54,0x9c57,0x9c56,0x9de5,0x9e9f,0x9ef4,
+      0x56d1,0x58e9,0x652c,0x705e,0x7671,0x7672,0x77d7,0x7f50,0x7f88,0x8836,
+      0x8839,0x8862,0x8b93,0x8b92
+    }
+  },
+  {				/* ku 26 */
+    {
+      0x8b96,0x8277,0x8d1b,0x91c0,0x946a,0x9742,0x9748,0x9744,0x97c6,0x9870,
+      0x9a5f,0x9b22,0x9b58,0x9c5f,0x9df9,0x9dfa,0x9e7c,0x9e7d,0x9f07,0x9f77,
+      0x9f72,0x5ef3,0x6b16,0x7063,0x7c6c,0x7c6e,0x883b,0x89c0,0x8ea1,0x91c1,
+      0x9472,0x9470,0x9871,0x995e,0x9ad6,0x9b23,0x9ecc,0x7064,0x77da,0x8b9a,
+      0x9477,0x97c9,0x9a62,0x9a65,0x7e9c,0x8b9c,0x8eaa,0x91c5,0x947d,0x947e,
+      0x947c,0x9c77,0x9c78,0x9ef7,0x8c54,0x947f,0x9e1a,0x7228,0x9a6a,0x9b31,
+      0x9e1b,0x9e1e,0x7c72
+    },{
+      0x30fe,0x309d,0x309e,0x3005,0x3041,0x3042,0x3043,0x3044,0x3045,0x3046,
+      0x3047,0x3048,0x3049,0x304a,0x304b,0x304c,0x304d,0x304e,0x304f,0x3050,
+      0x3051,0x3052,0x3053,0x3054,0x3055,0x3056,0x3057,0x3058,0x3059,0x305a,
+      0x305b,0x305c,0x305d,0x305e,0x305f,0x3060,0x3061,0x3062,0x3063,0x3064,
+      0x3065,0x3066,0x3067,0x3068,0x3069,0x306a,0x306b,0x306c,0x306d,0x306e,
+      0x306f,0x3070,0x3071,0x3072,0x3073,0x3074,0x3075,0x3076,0x3077,0x3078,
+      0x3079,0x307a,0x307b,0x307c,0x307d,0x307e,0x307f,0x3080,0x3081,0x3082,
+      0x3083,0x3084,0x3085,0x3086,0x3087,0x3088,0x3089,0x308a,0x308b,0x308c,
+      0x308d,0x308e,0x308f,0x3090,0x3091,0x3092,0x3093,0x30a1,0x30a2,0x30a3,
+      0x30a4,0x30a5,0x30a6,0x30a7
+    }
+  },
+  {				/* ku 27 */
+    {
+      0x30a8,0x30a9,0x30aa,0x30ab,0x30ac,0x30ad,0x30ae,0x30af,0x30b0,0x30b1,
+      0x30b2,0x30b3,0x30b4,0x30b5,0x30b6,0x30b7,0x30b8,0x30b9,0x30ba,0x30bb,
+      0x30bc,0x30bd,0x30be,0x30bf,0x30c0,0x30c1,0x30c2,0x30c3,0x30c4,0x30c5,
+      0x30c6,0x30c7,0x30c8,0x30c9,0x30ca,0x30cb,0x30cc,0x30cd,0x30ce,0x30cf,
+      0x30d0,0x30d1,0x30d2,0x30d3,0x30d4,0x30d5,0x30d6,0x30d7,0x30d8,0x30d9,
+      0x30da,0x30db,0x30dc,0x30dd,0x30de,0x30df,0x30e0,0x30e1,0x30e2,0x30e3,
+      0x30e4,0x30e5,0x30e6
+    },{
+      0x30e7,0x30e8,0x30e9,0x30ea,0x30eb,0x30ec,0x30ed,0x30ee,0x30ef,0x30f0,
+      0x30f1,0x30f2,0x30f3,0x30f4,0x30f5,0x30f6,0x0414,0x0415,0x0401,0x0416,
+      0x0417,0x0418,0x0419,0x041a,0x041b,0x041c,0x0423,0x0424,0x0425,0x0426,
+      0x0427,0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f,0x0430,
+      0x0431,0x0432,0x0433,0x0434,0x0435,0x0451,0x0436,0x0437,0x0438,0x0439,
+      0x043a,0x043b,0x043c,0x043d,0x043e,0x043f,0x0440,0x0441,0x0442,0x0443,
+      0x0444,0x0445,0x0446,0x0447,0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,
+      0x044e,0x044f,0x2460,0x2461,0x2462,0x2463,0x2464,0x2465,0x2466,0x2467,
+      0x2468,0x2469,0x2474,0x2475,0x2476,0x2477,0x2478,0x2479,0x247a,0x247b,
+      0x247c,0x247d,UBOGON,UBOGON
+    }
+  },
+  {				/* ku 28 */
+    {
+      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+      UBOGON,UBOGON,UBOGON
+    },{
+      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+      UBOGON,UBOGON,UBOGON,UBOGON
+    }
+  },
+  {				/* ku 29 */
+    {
+      0x4e42,0x4e5c,0x51f5,0x531a,0x5382,0x4e07,0x4e0c,0x4e47,0x4e8d,0x56d7,
+      0xfa0c,0x5c6e,0x5f73,0x4e0f,0x5187,0x4e0e,0x4e2e,0x4e93,0x4ec2,0x4ec9,
+      0x4ec8,0x5198,0x52fc,0x536c,0x53b9,0x5720,0x5903,0x592c,0x5c10,0x5dff,
+      0x65e1,0x6bb3,0x6bcc,0x6c14,0x723f,0x4e31,0x4e3c,0x4ee8,0x4edc,0x4ee9,
+      0x4ee1,0x4edd,0x4eda,0x520c,0x531c,0x534c,0x5722,0x5723,0x5917,0x592f,
+      0x5b81,0x5b84,0x5c12,0x5c3b,0x5c74,0x5c73,0x5e04,0x5e80,0x5e82,0x5fc9,
+      0x6209,0x6250,0x6c15
+    },{
+      0x6c36,0x6c43,0x6c3f,0x6c3b,0x72ae,0x72b0,0x738a,0x79b8,0x808a,0x961e,
+      0x4f0e,0x4f18,0x4f2c,0x4ef5,0x4f14,0x4ef1,0x4f00,0x4ef7,0x4f08,0x4f1d,
+      0x4f02,0x4f05,0x4f22,0x4f13,0x4f04,0x4ef4,0x4f12,0x51b1,0x5213,0x5209,
+      0x5210,0x52a6,0x5322,0x531f,0x534d,0x538a,0x5407,0x56e1,0x56df,0x572e,
+      0x572a,0x5734,0x593c,0x5980,0x597c,0x5985,0x597b,0x597e,0x5977,0x597f,
+      0x5b56,0x5c15,0x5c25,0x5c7c,0x5c7a,0x5c7b,0x5c7e,0x5ddf,0x5e75,0x5e84,
+      0x5f02,0x5f1a,0x5f74,0x5fd5,0x5fd4,0x5fcf,0x625c,0x625e,0x6264,0x6261,
+      0x6266,0x6262,0x6259,0x6260,0x625a,0x6265,0x65ef,0x65ee,0x673e,0x6739,
+      0x6738,0x673b,0x673a,0x673f,0x673c,0x6733,0x6c18,0x6c46,0x6c52,0x6c5c,
+      0x6c4f,0x6c4a,0x6c54,0x6c4b
+    }
+  },
+  {				/* ku 2a */
+    {
+      0x6c4c,0x7071,0x725e,0x72b4,0x72b5,0x738e,0x752a,0x767f,0x7a75,0x7f51,
+      0x8278,0x827c,0x8280,0x827d,0x827f,0x864d,0x897e,0x9099,0x9097,0x9098,
+      0x909b,0x9094,0x9622,0x9624,0x9620,0x9623,0x4f56,0x4f3b,0x4f62,0x4f49,
+      0x4f53,0x4f64,0x4f3e,0x4f67,0x4f52,0x4f5f,0x4f41,0x4f58,0x4f2d,0x4f33,
+      0x4f3f,0x4f61,0x518f,0x51b9,0x521c,0x521e,0x5221,0x52ad,0x52ae,0x5309,
+      0x5363,0x5372,0x538e,0x538f,0x5430,0x5437,0x542a,0x5454,0x5445,0x5419,
+      0x541c,0x5425,0x5418
+    },{
+      0x543d,0x544f,0x5441,0x5428,0x5424,0x5447,0x56ee,0x56e7,0x56e5,0x5741,
+      0x5745,0x574c,0x5749,0x574b,0x5752,0x5906,0x5940,0x59a6,0x5998,0x59a0,
+      0x5997,0x598e,0x59a2,0x5990,0x598f,0x59a7,0x59a1,0x5b8e,0x5b92,0x5c28,
+      0x5c2a,0x5c8d,0x5c8f,0x5c88,0x5c8b,0x5c89,0x5c92,0x5c8a,0x5c86,0x5c93,
+      0x5c95,0x5de0,0x5e0a,0x5e0e,0x5e8b,0x5e89,0x5e8c,0x5e88,0x5e8d,0x5f05,
+      0x5f1d,0x5f78,0x5f76,0x5fd2,0x5fd1,0x5fd0,0x5fed,0x5fe8,0x5fee,0x5ff3,
+      0x5fe1,0x5fe4,0x5fe3,0x5ffa,0x5fef,0x5ff7,0x5ffb,0x6000,0x5ff4,0x623a,
+      0x6283,0x628c,0x628e,0x628f,0x6294,0x6287,0x6271,0x627b,0x627a,0x6270,
+      0x6281,0x6288,0x6277,0x627d,0x6272,0x6274,0x6537,0x65f0,0x65f4,0x65f3,
+      0x65f2,0x65f5,0x6745,0x6747
+    }
+  },
+  {				/* ku 2b */
+    {
+      0x6759,0x6755,0x674c,0x6748,0x675d,0x674d,0x675a,0x674b,0x6bd0,0x6c19,
+      0x6c1a,0x6c78,0x6c67,0x6c6b,0x6c84,0x6c8b,0x6c8f,0x6c71,0x6c6f,0x6c69,
+      0x6c9a,0x6c6d,0x6c87,0x6c95,0x6c9c,0x6c66,0x6c73,0x6c65,0x6c7b,0x6c8e,
+      0x7074,0x707a,0x7263,0x72bf,0x72bd,0x72c3,0x72c6,0x72c1,0x72ba,0x72c5,
+      0x7395,0x7397,0x7393,0x7394,0x7392,0x753a,0x7539,0x7594,0x7595,0x7681,
+      0x793d,0x8034,0x8095,0x8099,0x8090,0x8092,0x809c,0x8290,0x828f,0x8285,
+      0x828e,0x8291,0x8293
+    },{
+      0x828a,0x8283,0x8284,0x8c78,0x8fc9,0x8fbf,0x909f,0x90a1,0x90a5,0x909e,
+      0x90a7,0x90a0,0x9630,0x9628,0x962f,0x962d,0x4e33,0x4f98,0x4f7c,0x4f85,
+      0x4f7d,0x4f80,0x4f87,0x4f76,0x4f74,0x4f89,0x4f84,0x4f77,0x4f4c,0x4f97,
+      0x4f6a,0x4f9a,0x4f79,0x4f81,0x4f78,0x4f90,0x4f9c,0x4f94,0x4f9e,0x4f92,
+      0x4f82,0x4f95,0x4f6b,0x4f6e,0x519e,0x51bc,0x51be,0x5235,0x5232,0x5233,
+      0x5246,0x5231,0x52bc,0x530a,0x530b,0x533c,0x5392,0x5394,0x5487,0x547f,
+      0x5481,0x5491,0x5482,0x5488,0x546b,0x547a,0x547e,0x5465,0x546c,0x5474,
+      0x5466,0x548d,0x546f,0x5461,0x5460,0x5498,0x5463,0x5467,0x5464,0x56f7,
+      0x56f9,0x576f,0x5772,0x576d,0x576b,0x5771,0x5770,0x5776,0x5780,0x5775,
+      0x577b,0x5773,0x5774,0x5762
+    }
+  },
+  {				/* ku 2c */
+    {
+      0x5768,0x577d,0x590c,0x5945,0x59b5,0x59ba,0x59cf,0x59ce,0x59b2,0x59cc,
+      0x59c1,0x59b6,0x59bc,0x59c3,0x59d6,0x59b1,0x59bd,0x59c0,0x59c8,0x59b4,
+      0x59c7,0x5b62,0x5b65,0x5b93,0x5b95,0x5c44,0x5c47,0x5cae,0x5ca4,0x5ca0,
+      0x5cb5,0x5caf,0x5ca8,0x5cac,0x5c9f,0x5ca3,0x5cad,0x5ca2,0x5caa,0x5ca7,
+      0x5c9d,0x5ca5,0x5cb6,0x5cb0,0x5ca6,0x5e17,0x5e14,0x5e19,0x5f28,0x5f22,
+      0x5f23,0x5f24,0x5f54,0x5f82,0x5f7e,0x5f7d,0x5fde,0x5fe5,0x602d,0x6026,
+      0x6019,0x6032,0x600b
+    },{
+      0x6034,0x600a,0x6017,0x6033,0x601a,0x601e,0x602c,0x6022,0x600d,0x6010,
+      0x602e,0x6013,0x6011,0x600c,0x6009,0x601c,0x6214,0x623d,0x62ad,0x62b4,
+      0x62d1,0x62be,0x62aa,0x62b6,0x62ca,0x62ae,0x62b3,0x62af,0x62bb,0x62a9,
+      0x62b0,0x62b8,0x653d,0x65a8,0x65bb,0x6609,0x65fc,0x6604,0x6612,0x6608,
+      0x65fb,0x6603,0x660b,0x660d,0x6605,0x65fd,0x6611,0x6610,0x66f6,0x670a,
+      0x6785,0x676c,0x678e,0x6792,0x6776,0x677b,0x6798,0x6786,0x6784,0x6774,
+      0x678d,0x678c,0x677a,0x679f,0x6791,0x6799,0x6783,0x677d,0x6781,0x6778,
+      0x6779,0x6794,0x6b25,0x6b80,0x6b7e,0x6bde,0x6c1d,0x6c93,0x6cec,0x6ceb,
+      0x6cee,0x6cd9,0x6cb6,0x6cd4,0x6cad,0x6ce7,0x6cb7,0x6cd0,0x6cc2,0x6cba,
+      0x6cc3,0x6cc6,0x6ced,0x6cf2
+    }
+  },
+  {				/* ku 2d */
+    {
+      0x6cd2,0x6cdd,0x6cb4,0x6c8a,0x6c9d,0x6c80,0x6cde,0x6cc0,0x6d30,0x6ccd,
+      0x6cc7,0x6cb0,0x6cf9,0x6ccf,0x6ce9,0x6cd1,0x7094,0x7098,0x7085,0x7093,
+      0x7086,0x7084,0x7091,0x7096,0x7082,0x709a,0x7083,0x726a,0x72d6,0x72cb,
+      0x72d8,0x72c9,0x72dc,0x72d2,0x72d4,0x72da,0x72cc,0x72d1,0x73a4,0x73a1,
+      0x73ad,0x73a6,0x73a2,0x73a0,0x73ac,0x739d,0x74dd,0x74e8,0x753f,0x7540,
+      0x753e,0x758c,0x7598,0x76af,0x76f3,0x76f1,0x76f0,0x76f5,0x77f8,0x77fc,
+      0x77f9,0x77fb,0x77fa
+    },{
+      0x77f7,0x7942,0x793f,0x79c5,0x7a78,0x7a7b,0x7afb,0x7c75,0x7cfd,0x8035,
+      0x808f,0x80ae,0x80a3,0x80b8,0x80b5,0x80ad,0x8220,0x82a0,0x82c0,0x82ab,
+      0x829a,0x8298,0x829b,0x82b5,0x82a7,0x82ae,0x82bc,0x829e,0x82ba,0x82b4,
+      0x82a8,0x82a1,0x82a9,0x82c2,0x82a4,0x82c3,0x82b6,0x82a2,0x8670,0x866f,
+      0x866d,0x866e,0x8c56,0x8fd2,0x8fcb,0x8fd3,0x8fcd,0x8fd6,0x8fd5,0x8fd7,
+      0x90b2,0x90b4,0x90af,0x90b3,0x90b0,0x9639,0x963d,0x963c,0x963a,0x9643,
+      0x4fcd,0x4fc5,0x4fd3,0x4fb2,0x4fc9,0x4fcb,0x4fc1,0x4fd4,0x4fdc,0x4fd9,
+      0x4fbb,0x4fb3,0x4fdb,0x4fc7,0x4fd6,0x4fba,0x4fc0,0x4fb9,0x4fec,0x5244,
+      0x5249,0x52c0,0x52c2,0x533d,0x537c,0x5397,0x5396,0x5399,0x5398,0x54ba,
+      0x54a1,0x54ad,0x54a5,0x54cf
+    }
+  },
+  {				/* ku 2e */
+    {
+      0x54c3,0x830d,0x54b7,0x54ae,0x54d6,0x54b6,0x54c5,0x54c6,0x54a0,0x5470,
+      0x54bc,0x54a2,0x54be,0x5472,0x54de,0x54b0,0x57b5,0x579e,0x579f,0x57a4,
+      0x578c,0x5797,0x579d,0x579b,0x5794,0x5798,0x578f,0x5799,0x57a5,0x579a,
+      0x5795,0x58f4,0x590d,0x5953,0x59e1,0x59de,0x59ee,0x5a00,0x59f1,0x59dd,
+      0x59fa,0x59fd,0x59fc,0x59f6,0x59e4,0x59f2,0x59f7,0x59db,0x59e9,0x59f3,
+      0x59f5,0x59e0,0x59fe,0x59f4,0x59ed,0x5ba8,0x5c4c,0x5cd0,0x5cd8,0x5ccc,
+      0x5cd7,0x5ccb,0x5cdb
+    },{
+      0x5cde,0x5cda,0x5cc9,0x5cc7,0x5cca,0x5cd6,0x5cd3,0x5cd4,0x5ccf,0x5cc8,
+      0x5cc6,0x5cce,0x5cdf,0x5cf8,0x5df9,0x5e21,0x5e22,0x5e23,0x5e20,0x5e24,
+      0x5eb0,0x5ea4,0x5ea2,0x5e9b,0x5ea3,0x5ea5,0x5f07,0x5f2e,0x5f56,0x5f86,
+      0x6037,0x6039,0x6054,0x6072,0x605e,0x6045,0x6053,0x6047,0x6049,0x605b,
+      0x604c,0x6040,0x6042,0x605f,0x6024,0x6044,0x6058,0x6066,0x606e,0x6242,
+      0x6243,0x62cf,0x630d,0x630b,0x62f5,0x630e,0x6303,0x62eb,0x62f9,0x630f,
+      0x630c,0x62f8,0x62f6,0x6300,0x6313,0x6314,0x62fa,0x6315,0x62fb,0x62f0,
+      0x6541,0x6543,0x65aa,0x65bf,0x6636,0x6621,0x6632,0x6635,0x661c,0x6626,
+      0x6622,0x6633,0x662b,0x663a,0x661d,0x6634,0x6639,0x662e,0x670f,0x6710,
+      0x67c1,0x67f2,0x67c8,0x67ba
+    }
+  },
+  {				/* ku 2f */
+    {
+      0x67dc,0x67bb,0x67f8,0x67d8,0x67c0,0x67b7,0x67c5,0x67eb,0x67e4,0x67df,
+      0x67b5,0x67cd,0x67b3,0x67f7,0x67f6,0x67ee,0x67e3,0x67c2,0x67b9,0x67ce,
+      0x67e7,0x67f0,0x67b2,0x67fc,0x67c6,0x67ed,0x67cc,0x67ae,0x67e6,0x67db,
+      0x67fa,0x67c9,0x67ca,0x67c3,0x67ea,0x67cb,0x6b28,0x6b82,0x6b84,0x6bb6,
+      0x6bd6,0x6bd8,0x6be0,0x6c20,0x6c21,0x6d28,0x6d34,0x6d2d,0x6d1f,0x6d3c,
+      0x6d3f,0x6d12,0x6d0a,0x6cda,0x6d33,0x6d04,0x6d19,0x6d3a,0x6d1a,0x6d11,
+      0x6d00,0x6d1d,0x6d42
+    },{
+      0x6d01,0x6d18,0x6d37,0x6d03,0x6d0f,0x6d40,0x6d07,0x6d20,0x6d2c,0x6d08,
+      0x6d22,0x6d09,0x6d10,0x70b7,0x709f,0x70be,0x70b1,0x70b0,0x70a1,0x70b4,
+      0x70b5,0x70a9,0x7241,0x7249,0x724a,0x726c,0x7270,0x7273,0x726e,0x72ca,
+      0x72e4,0x72e8,0x72eb,0x72df,0x72ea,0x72e6,0x72e3,0x7385,0x73cc,0x73c2,
+      0x73c8,0x73c5,0x73b9,0x73b6,0x73b5,0x73b4,0x73eb,0x73bf,0x73c7,0x73be,
+      0x73c3,0x73c6,0x73b8,0x73cb,0x74ec,0x74ee,0x752e,0x7547,0x7548,0x75a7,
+      0x75aa,0x7679,0x76c4,0x7708,0x7703,0x7704,0x7705,0x770a,0x76f7,0x76fb,
+      0x76fa,0x77e7,0x77e8,0x7806,0x7811,0x7812,0x7805,0x7810,0x780f,0x780e,
+      0x7809,0x7803,0x7813,0x794a,0x794c,0x794b,0x7945,0x7944,0x79d5,0x79cd,
+      0x79cf,0x79d6,0x79ce,0x7a80
+    }
+  },
+  {				/* ku 30 */
+    {
+      0x7a7e,0x7ad1,0x7b00,0x7b01,0x7c7a,0x7c78,0x7c79,0x7c7f,0x7c80,0x7c81,
+      0x7d03,0x7d08,0x7d01,0x7f58,0x7f91,0x7f8d,0x7fbe,0x8007,0x800e,0x800f,
+      0x8014,0x8037,0x80d8,0x80c7,0x80e0,0x80d1,0x80c8,0x80c2,0x80d0,0x80c5,
+      0x80e3,0x80d9,0x80dc,0x80ca,0x80d5,0x80c9,0x80cf,0x80d7,0x80e6,0x80cd,
+      0x81ff,0x8221,0x8294,0x82d9,0x82fe,0x82f9,0x8307,0x82e8,0x8300,0x82d5,
+      0x833a,0x82eb,0x82d6,0x82f4,0x82ec,0x82e1,0x82f2,0x82f5,0x830c,0x82fb,
+      0x82f6,0x82f0,0x82ea
+    },{
+      0x82e4,0x82e0,0x82fa,0x82f3,0x82ed,0x8677,0x8674,0x867c,0x8673,0x8841,
+      0x884e,0x8867,0x886a,0x8869,0x89d3,0x8a04,0x8a07,0x8d72,0x8fe3,0x8fe1,
+      0x8fee,0x8fe0,0x90f1,0x90bd,0x90bf,0x90d5,0x90c5,0x90be,0x90c7,0x90cb,
+      0x90c8,0x91d4,0x91d3,0x9654,0x964f,0x9651,0x9653,0x964a,0x964e,0x501e,
+      0x5005,0x5007,0x5013,0x5022,0x5030,0x501b,0x4ff5,0x4ff4,0x5033,0x5037,
+      0x502c,0x4ff6,0x4ff7,0x5017,0x501c,0x5020,0x5027,0x5035,0x502f,0x5031,
+      0x500e,0x515a,0x5194,0x5193,0x51ca,0x51c4,0x51c5,0x51c8,0x51ce,0x5261,
+      0x525a,0x5252,0x525e,0x525f,0x5255,0x5262,0x52cd,0x530e,0x539e,0x5526,
+      0x54e2,0x5517,0x5512,0x54e7,0x54f3,0x54e4,0x551a,0x54ff,0x5504,0x5508,
+      0x54eb,0x5511,0x5505,0x54f1
+    }
+  },
+  {				/* ku 31 */
+    {
+      0x550a,0x54fb,0x54f7,0x54f8,0x54e0,0x550e,0x5503,0x550b,0x5701,0x5702,
+      0x57cc,0x5832,0x57d5,0x57d2,0x57ba,0x57c6,0x57bd,0x57bc,0x57b8,0x57b6,
+      0x57bf,0x57c7,0x57d0,0x57b9,0x57c1,0x590e,0x594a,0x5a19,0x5a16,0x5a2d,
+      0x5a2e,0x5a15,0x5a0f,0x5a17,0x5a0a,0x5a1e,0x5a33,0x5b6c,0x5ba7,0x5bad,
+      0x5bac,0x5c03,0x5c56,0x5c54,0x5cec,0x5cff,0x5cee,0x5cf1,0x5cf7,0x5d00,
+      0x5cf9,0x5e29,0x5e28,0x5ea8,0x5eae,0x5eaa,0x5eac,0x5f33,0x5f30,0x5f67,
+      0x605d,0x605a,0x6067
+    },{
+      0x6041,0x60a2,0x6088,0x6080,0x6092,0x6081,0x609d,0x6083,0x6095,0x609b,
+      0x6097,0x6087,0x609c,0x608e,0x6219,0x6246,0x62f2,0x6310,0x6356,0x632c,
+      0x6344,0x6345,0x6336,0x6343,0x63e4,0x6339,0x634b,0x634a,0x633c,0x6329,
+      0x6341,0x6334,0x6358,0x6354,0x6359,0x632d,0x6347,0x6333,0x635a,0x6351,
+      0x6338,0x6357,0x6340,0x6348,0x654a,0x6546,0x65c6,0x65c3,0x65c4,0x65c2,
+      0x664a,0x665f,0x6647,0x6651,0x6712,0x6713,0x681f,0x681a,0x6849,0x6832,
+      0x6833,0x683b,0x684b,0x684f,0x6816,0x6831,0x681c,0x6835,0x682b,0x682d,
+      0x682f,0x684e,0x6844,0x6834,0x681d,0x6812,0x6814,0x6826,0x6828,0x682e,
+      0x684d,0x683a,0x6825,0x6820,0x6b2c,0x6b2f,0x6b2d,0x6b31,0x6b34,0x6b6d,
+      0x8082,0x6b88,0x6be6,0x6be4
+    }
+  },
+  {				/* ku 32 */
+    {
+      0x6be8,0x6be3,0x6be2,0x6be7,0x6c25,0x6d7a,0x6d63,0x6d64,0x6d76,0x6d0d,
+      0x6d61,0x6d92,0x6d58,0x6d62,0x6d6d,0x6d6f,0x6d91,0x6d8d,0x6def,0x6d7f,
+      0x6d86,0x6d5e,0x6d67,0x6d60,0x6d97,0x6d70,0x6d7c,0x6d5f,0x6d82,0x6d98,
+      0x6d2f,0x6d68,0x6d8b,0x6d7e,0x6d80,0x6d84,0x6d16,0x6d83,0x6d7b,0x6d7d,
+      0x6d75,0x6d90,0x70dc,0x70d3,0x70d1,0x70dd,0x70cb,0x7f39,0x70e2,0x70d7,
+      0x70d2,0x70de,0x70e0,0x70d4,0x70cd,0x70c5,0x70c6,0x70c7,0x70da,0x70ce,
+      0x70e1,0x7242,0x7278
+    },{
+      0x7277,0x7276,0x7300,0x72fa,0x72f4,0x72fe,0x72f6,0x72f3,0x72fb,0x7301,
+      0x73d3,0x73d9,0x73e5,0x73d6,0x73bc,0x73e7,0x73e3,0x73e9,0x73dc,0x73d2,
+      0x73db,0x73d4,0x73dd,0x73da,0x73d7,0x73d8,0x73e8,0x74de,0x74df,0x74f4,
+      0x74f5,0x7521,0x755b,0x755f,0x75b0,0x75c1,0x75bb,0x75c4,0x75c0,0x75bf,
+      0x75b6,0x75ba,0x768a,0x76c9,0x771d,0x771b,0x7710,0x7713,0x7712,0x7723,
+      0x7711,0x7715,0x7719,0x771a,0x7722,0x7727,0x7823,0x782c,0x7822,0x7835,
+      0x782f,0x7828,0x782e,0x782b,0x7821,0x7829,0x7833,0x782a,0x7831,0x7954,
+      0x795b,0x794f,0x795c,0x7953,0x7952,0x7951,0x79eb,0x79ec,0x79e0,0x79ee,
+      0x79ed,0x79ea,0x79dc,0x79de,0x79dd,0x7a86,0x7a89,0x7a85,0x7a8b,0x7a8c,
+      0x7a8a,0x7a87,0x7ad8,0x7b10
+    }
+  },
+  {				/* ku 33 */
+    {
+      0x7b04,0x7b13,0x7b05,0x7b0f,0x7b08,0x7b0a,0x7b0e,0x7b09,0x7b12,0x7c84,
+      0x7c91,0x7c8a,0x7c8c,0x7c88,0x7c8d,0x7c85,0x7d1e,0x7d1d,0x7d11,0x7d0e,
+      0x7d18,0x7d16,0x7d13,0x7d1f,0x7d12,0x7d0f,0x7d0c,0x7f5c,0x7f61,0x7f5e,
+      0x7f60,0x7f5d,0x7f5b,0x7f96,0x7f92,0x7fc3,0x7fc2,0x7fc0,0x8016,0x803e,
+      0x8039,0x80fa,0x80f2,0x80f9,0x80f5,0x8101,0x80fb,0x8100,0x8201,0x822f,
+      0x8225,0x8333,0x832d,0x8344,0x8319,0x8351,0x8325,0x8356,0x833f,0x8341,
+      0x8326,0x831c,0x8322
+    },{
+      0x8342,0x834e,0x831b,0x832a,0x8308,0x833c,0x834d,0x8316,0x8324,0x8320,
+      0x8337,0x832f,0x8329,0x8347,0x8345,0x834c,0x8353,0x831e,0x832c,0x834b,
+      0x8327,0x8348,0x8653,0x8652,0x86a2,0x86a8,0x8696,0x868d,0x8691,0x869e,
+      0x8687,0x8697,0x8686,0x868b,0x869a,0x8685,0x86a5,0x8699,0x86a1,0x86a7,
+      0x8695,0x8698,0x868e,0x869d,0x8690,0x8694,0x8843,0x8844,0x886d,0x8875,
+      0x8876,0x8872,0x8880,0x8871,0x887f,0x886f,0x8883,0x887e,0x8874,0x887c,
+      0x8a12,0x8c47,0x8c57,0x8c7b,0x8ca4,0x8ca3,0x8d76,0x8d78,0x8db5,0x8db7,
+      0x8db6,0x8ed1,0x8ed3,0x8ffe,0x8ff5,0x9002,0x8fff,0x8ffb,0x9004,0x8ffc,
+      0x8ff6,0x90d6,0x90e0,0x90d9,0x90da,0x90e3,0x90df,0x90e5,0x90d8,0x90db,
+      0x90d7,0x90dc,0x90e4,0x9150
+    }
+  },
+  {				/* ku 34 */
+    {
+      0x914e,0x914f,0x91d5,0x91e2,0x91da,0x965c,0x965f,0x96bc,0x98e3,0x9adf,
+      0x9b2f,0x4e7f,0x5070,0x506a,0x5061,0x505e,0x5060,0x5053,0x504b,0x505d,
+      0x5072,0x5048,0x504d,0x5041,0x505b,0x504a,0x5062,0x5015,0x5045,0x505f,
+      0x5069,0x506b,0x5063,0x5064,0x5046,0x5040,0x506e,0x5073,0x5057,0x5051,
+      0x51d0,0x526b,0x526d,0x526c,0x526e,0x52d6,0x52d3,0x532d,0x539c,0x5575,
+      0x5576,0x553c,0x554d,0x5550,0x5534,0x552a,0x5551,0x5562,0x5536,0x5535,
+      0x5530,0x5552,0x5545
+    },{
+      0x550c,0x5532,0x5565,0x554e,0x5539,0x5548,0x552d,0x553b,0x5540,0x554b,
+      0x570a,0x5707,0x57fb,0x5814,0x57e2,0x57f6,0x57dc,0x57f4,0x5800,0x57ed,
+      0x57fd,0x5808,0x57f8,0x580b,0x57f3,0x57cf,0x5807,0x57ee,0x57e3,0x57f2,
+      0x57e5,0x57ec,0x57e1,0x580e,0x57fc,0x5810,0x57e7,0x5801,0x580c,0x57f1,
+      0x57e9,0x57f0,0x580d,0x5804,0x595c,0x5a60,0x5a58,0x5a55,0x5a67,0x5a5e,
+      0x5a38,0x5a35,0x5a6d,0x5a50,0x5a5f,0x5a65,0x5a6c,0x5a53,0x5a64,0x5a57,
+      0x5a43,0x5a5d,0x5a52,0x5a44,0x5a5b,0x5a48,0x5a8e,0x5a3e,0x5a4d,0x5a39,
+      0x5a4c,0x5a70,0x5a69,0x5a47,0x5a51,0x5a56,0x5a42,0x5a5c,0x5b72,0x5b6e,
+      0x5bc1,0x5bc0,0x5c59,0x5d1e,0x5d0b,0x5d1d,0x5d1a,0x5d20,0x5d0c,0x5d28,
+      0x5d0d,0x5d26,0x5d25,0x5d0f
+    }
+  },
+  {				/* ku 35 */
+    {
+      0x5d30,0x5d12,0x5d23,0x5d1f,0x5d2e,0x5e3e,0x5e34,0x5eb1,0x5eb4,0x5eb9,
+      0x5eb2,0x5eb3,0x5f36,0x5f38,0x5f9b,0x5f96,0x5f9f,0x608a,0x6090,0x6086,
+      0x60be,0x60b0,0x60ba,0x60d3,0x60d4,0x60cf,0x60e4,0x60d9,0x60dd,0x60c8,
+      0x60b1,0x60db,0x60b7,0x60ca,0x60bf,0x60c3,0x60cd,0x60c0,0x6332,0x6365,
+      0x638a,0x6382,0x637d,0x63bd,0x639e,0x63ad,0x639d,0x6397,0x63ab,0x638e,
+      0x636f,0x6387,0x6390,0x636e,0x63af,0x6375,0x639c,0x636d,0x63ae,0x637c,
+      0x63a4,0x633b,0x639f
+    },{
+      0x6378,0x6385,0x6381,0x6391,0x638d,0x6370,0x6553,0x65cd,0x6665,0x6661,
+      0x665b,0x6659,0x665c,0x6662,0x6718,0x6879,0x6887,0x6890,0x689c,0x686d,
+      0x686e,0x68ae,0x68ab,0x6956,0x686f,0x68a3,0x68ac,0x68a9,0x6875,0x6874,
+      0x68b2,0x688f,0x6877,0x6892,0x687c,0x686b,0x6872,0x68aa,0x6880,0x6871,
+      0x687e,0x689b,0x6896,0x688b,0x68a0,0x6889,0x68a4,0x6878,0x687b,0x6891,
+      0x688c,0x688a,0x687d,0x6b36,0x6b33,0x6b37,0x6b38,0x6b91,0x6b8f,0x6b8d,
+      0x6b8e,0x6b8c,0x6c2a,0x6dc0,0x6dab,0x6db4,0x6db3,0x6e74,0x6dac,0x6de9,
+      0x6de2,0x6db7,0x6df6,0x6dd4,0x6e00,0x6dc8,0x6de0,0x6ddf,0x6dd6,0x6dbe,
+      0x6de5,0x6ddc,0x6ddd,0x6ddb,0x6df4,0x6dca,0x6dbd,0x6ded,0x6df0,0x6dba,
+      0x6dd5,0x6dc2,0x6dcf,0x6dc9
+    }
+  },
+  {				/* ku 36 */
+    {
+      0x6dd0,0x6df2,0x6dd3,0x6dfd,0x6dd7,0x6dcd,0x6de3,0x6dbb,0x70fa,0x710d,
+      0x70f7,0x7117,0x70f4,0x710c,0x70f0,0x7104,0x70f3,0x7110,0x70fc,0x70ff,
+      0x7106,0x7113,0x7100,0x70f8,0x70f6,0x710b,0x7102,0x710e,0x727e,0x727b,
+      0x727c,0x727f,0x731d,0x7317,0x7307,0x7311,0x7318,0x730a,0x7308,0x72ff,
+      0x730f,0x731e,0x7388,0x73f6,0x73f8,0x73f5,0x7404,0x7401,0x73fd,0x7407,
+      0x7400,0x73fa,0x73fc,0x73ff,0x740c,0x740b,0x73f4,0x7408,0x7564,0x7563,
+      0x75ce,0x75d2,0x75cf
+    },{
+      0x75cb,0x75cc,0x75d1,0x75d0,0x768f,0x7689,0x76d3,0x7739,0x772f,0x772d,
+      0x7731,0x7732,0x7734,0x7733,0x773d,0x7725,0x773b,0x7735,0x7848,0x7852,
+      0x7849,0x784d,0x784a,0x784c,0x7826,0x7845,0x7850,0x7964,0x7967,0x7969,
+      0x796a,0x7963,0x796b,0x7961,0x79bb,0x79fa,0x79f8,0x79f6,0x79f7,0x7a8f,
+      0x7a94,0x7a90,0x7b35,0x7b47,0x7b34,0x7b25,0x7b30,0x7b22,0x7b24,0x7b33,
+      0x7b18,0x7b2a,0x7b1d,0x7b31,0x7b2b,0x7b2d,0x7b2f,0x7b32,0x7b38,0x7b1a,
+      0x7b23,0x7c94,0x7c98,0x7c96,0x7ca3,0x7d35,0x7d3d,0x7d38,0x7d36,0x7d3a,
+      0x7d45,0x7d2c,0x7d29,0x7d41,0x7d47,0x7d3e,0x7d3f,0x7d4a,0x7d3b,0x7d28,
+      0x7f63,0x7f95,0x7f9c,0x7f9d,0x7f9b,0x7fca,0x7fcb,0x7fcd,0x7fd0,0x7fd1,
+      0x7fc7,0x7fcf,0x7fc9,0x801f
+    }
+  },
+  {				/* ku 37 */
+    {
+      0x801e,0x801b,0x8047,0x8043,0x8048,0x8118,0x8125,0x8119,0x811b,0x812d,
+      0x811f,0x812c,0x811e,0x8121,0x8115,0x8127,0x811d,0x8122,0x8211,0x8238,
+      0x8233,0x823a,0x8234,0x8232,0x8274,0x8390,0x83a3,0x83a8,0x838d,0x837a,
+      0x8373,0x83a4,0x8374,0x838f,0x8381,0x8395,0x8399,0x8375,0x8394,0x83a9,
+      0x837d,0x8383,0x838c,0x839d,0x839b,0x83aa,0x838b,0x837e,0x83a5,0x83af,
+      0x8388,0x8397,0x83b0,0x837f,0x83a6,0x8387,0x83ae,0x8376,0x839a,0x8659,
+      0x8656,0x86bf,0x86b7
+    },{
+      0x86c2,0x86c1,0x86c5,0x86ba,0x86b0,0x86c8,0x86b9,0x86b3,0x86b8,0x86cc,
+      0x86b4,0x86bb,0x86bc,0x86c3,0x86bd,0x86be,0x8852,0x8889,0x8895,0x88a8,
+      0x88a2,0x88aa,0x889a,0x8891,0x88a1,0x889f,0x8898,0x88a7,0x8899,0x889b,
+      0x8897,0x88a4,0x88ac,0x888c,0x8893,0x888e,0x8982,0x89d6,0x89d9,0x89d5,
+      0x8a30,0x8a27,0x8a2c,0x8a1e,0x8c39,0x8c3b,0x8c5c,0x8c5d,0x8c7d,0x8ca5,
+      0x8d7d,0x8d7b,0x8d79,0x8dbc,0x8dc2,0x8db9,0x8dbf,0x8dc1,0x8ed8,0x8ede,
+      0x8edd,0x8edc,0x8ed7,0x8ee0,0x8ee1,0x9024,0x900b,0x9011,0x901c,0x900c,
+      0x9021,0x90ef,0x90ea,0x90f0,0x90f4,0x90f2,0x90f3,0x90d4,0x90eb,0x90ec,
+      0x90e9,0x9156,0x9158,0x915a,0x9153,0x9155,0x91ec,0x91f4,0x91f1,0x91f3,
+      0x91f8,0x91e4,0x91f9,0x91ea
+    }
+  },
+  {				/* ku 38 */
+    {
+      0x91eb,0x91f7,0x91e8,0x91ee,0x957a,0x9586,0x9588,0x967c,0x966d,0x966b,
+      0x9671,0x966f,0x96bf,0x976a,0x9804,0x98e5,0x9997,0x509b,0x5095,0x5094,
+      0x509e,0x508b,0x50a3,0x5083,0x508c,0x508e,0x509d,0x5068,0x509c,0x5092,
+      0x5082,0x5087,0x515f,0x51d4,0x5312,0x5311,0x53a4,0x53a7,0x5591,0x55a8,
+      0x55a5,0x55ad,0x5577,0x5645,0x55a2,0x5593,0x5588,0x558f,0x55b5,0x5581,
+      0x55a3,0x5592,0x55a4,0x557d,0x558c,0x55a6,0x557f,0x5595,0x55a1,0x558e,
+      0x570c,0x5829,0x5837
+    },{
+      0x5819,0x581e,0x5827,0x5823,0x5828,0x57f5,0x5848,0x5825,0x581c,0x581b,
+      0x5833,0x583f,0x5836,0x582e,0x5839,0x5838,0x582d,0x582c,0x583b,0x5961,
+      0x5aaf,0x5a94,0x5a9f,0x5a7a,0x5aa2,0x5a9e,0x5a78,0x5aa6,0x5a7c,0x5aa5,
+      0x5aac,0x5a95,0x5aae,0x5a37,0x5a84,0x5a8a,0x5a97,0x5a83,0x5a8b,0x5aa9,
+      0x5a7b,0x5a7d,0x5a8c,0x5a9c,0x5a8f,0x5a93,0x5a9d,0x5bea,0x5bcd,0x5bcb,
+      0x5bd4,0x5bd1,0x5bca,0x5bce,0x5c0c,0x5c30,0x5d37,0x5d43,0x5d6b,0x5d41,
+      0x5d4b,0x5d3f,0x5d35,0x5d51,0x5d4e,0x5d55,0x5d33,0x5d3a,0x5d52,0x5d3d,
+      0x5d31,0x5d59,0x5d42,0x5d39,0x5d49,0x5d38,0x5d3c,0x5d32,0x5d36,0x5d40,
+      0x5d45,0x5e44,0x5e41,0x5f58,0x5fa6,0x5fa5,0x5fab,0x60c9,0x60b9,0x60cc,
+      0x60e2,0x60ce,0x60c4,0x6114
+    }
+  },
+  {				/* ku 39 */
+    {
+      0x60f2,0x610a,0x6116,0x6105,0x60f5,0x6113,0x60f8,0x60fc,0x60fe,0x60c1,
+      0x6103,0x6118,0x611d,0x6110,0x60ff,0x6104,0x610b,0x624a,0x6394,0x63b1,
+      0x63b0,0x63ce,0x63e5,0x63e8,0x63ef,0x63c3,0x649d,0x63f3,0x63ca,0x63e0,
+      0x63f6,0x63d5,0x63f2,0x63f5,0x6461,0x63df,0x63be,0x63dd,0x63dc,0x63c4,
+      0x63d8,0x63d3,0x63c2,0x63c7,0x63cc,0x63cb,0x63c8,0x63f0,0x63d7,0x63d9,
+      0x6532,0x6567,0x656a,0x6564,0x655c,0x6568,0x6565,0x658c,0x659d,0x659e,
+      0x65ae,0x65d0,0x65d2
+    },{
+      0x667c,0x666c,0x667b,0x6680,0x6671,0x6679,0x666a,0x6672,0x6701,0x690c,
+      0x68d3,0x6904,0x68dc,0x692a,0x68ec,0x68ea,0x68f1,0x690f,0x68d6,0x68f7,
+      0x68eb,0x68e4,0x68f6,0x6913,0x6910,0x68f3,0x68e1,0x6907,0x68cc,0x6908,
+      0x6970,0x68b4,0x6911,0x68ef,0x68c6,0x6914,0x68f8,0x68d0,0x68fd,0x68fc,
+      0x68e8,0x690b,0x690a,0x6917,0x68ce,0x68c8,0x68dd,0x68de,0x68e6,0x68f4,
+      0x68d1,0x6906,0x68d4,0x68e9,0x6915,0x6925,0x68c7,0x6b39,0x6b3b,0x6b3f,
+      0x6b3c,0x6b94,0x6b97,0x6b99,0x6b95,0x6bbd,0x6bf0,0x6bf2,0x6bf3,0x6c30,
+      0x6dfc,0x6e46,0x6e47,0x6e1f,0x6e49,0x6e88,0x6e3c,0x6e3d,0x6e45,0x6e62,
+      0x6e2b,0x6e3f,0x6e41,0x6e5d,0x6e73,0x6e1c,0x6e33,0x6e4b,0x6e40,0x6e51,
+      0x6e3b,0x6e03,0x6e2e,0x6e5e
+    }
+  },
+  {				/* ku 3a */
+    {
+      0x6e68,0x6e5c,0x6e61,0x6e31,0x6e28,0x6e60,0x6e71,0x6e6b,0x6e39,0x6e22,
+      0x6e30,0x6e53,0x6e65,0x6e27,0x6e78,0x6e64,0x6e77,0x6e55,0x6e79,0x6e52,
+      0x6e66,0x6e35,0x6e36,0x6e5a,0x7120,0x711e,0x712f,0x70fb,0x712e,0x7131,
+      0x7123,0x7125,0x7122,0x7132,0x711f,0x7128,0x713a,0x711b,0x724b,0x725a,
+      0x7288,0x7289,0x7286,0x7285,0x728b,0x7312,0x730b,0x7330,0x7322,0x7331,
+      0x7333,0x7327,0x7332,0x732d,0x7326,0x7323,0x7335,0x730c,0x742e,0x742c,
+      0x7430,0x742b,0x7416
+    },{
+      0x741a,0x7421,0x742d,0x7431,0x7424,0x7423,0x741d,0x7429,0x7420,0x7432,
+      0x74fb,0x752f,0x756f,0x756c,0x75e7,0x75da,0x75e1,0x75e6,0x75dd,0x75df,
+      0x75e4,0x75d7,0x7695,0x7692,0x76da,0x7746,0x7747,0x7744,0x774d,0x7745,
+      0x774a,0x774e,0x774b,0x774c,0x77de,0x77ec,0x7860,0x7864,0x7865,0x785c,
+      0x786d,0x7871,0x786a,0x786e,0x7870,0x7869,0x7868,0x785e,0x7862,0x7974,
+      0x7973,0x7972,0x7970,0x7a02,0x7a0a,0x7a03,0x7a0c,0x7a04,0x7a99,0x7ae6,
+      0x7ae4,0x7b4a,0x7b3b,0x7b44,0x7b48,0x7b4c,0x7b4e,0x7b40,0x7b58,0x7b45,
+      0x7ca2,0x7c9e,0x7ca8,0x7ca1,0x7d58,0x7d6f,0x7d63,0x7d53,0x7d56,0x7d67,
+      0x7d6a,0x7d4f,0x7d6d,0x7d5c,0x7d6b,0x7d52,0x7d54,0x7d69,0x7d51,0x7d5f,
+      0x7d4e,0x7f3e,0x7f3f,0x7f65
+    }
+  },
+  {				/* ku 3b */
+    {
+      0x7f66,0x7fa2,0x7fa0,0x7fa1,0x7fd7,0x8051,0x804f,0x8050,0x80fe,0x80d4,
+      0x8143,0x814a,0x8152,0x814f,0x8147,0x813d,0x814d,0x813a,0x81e6,0x81ee,
+      0x81f7,0x81f8,0x81f9,0x8204,0x823c,0x823d,0x823f,0x8275,0x833b,0x83cf,
+      0x83f9,0x8423,0x83c0,0x83e8,0x8412,0x83e7,0x83e4,0x83fc,0x83f6,0x8410,
+      0x83c6,0x83c8,0x83eb,0x83e3,0x83bf,0x8401,0x83dd,0x83e5,0x83d8,0x83ff,
+      0x83e1,0x83cb,0x83ce,0x83d6,0x83f5,0x83c9,0x8409,0x840f,0x83de,0x8411,
+      0x8406,0x83c2,0x83f3
+    },{
+      0x83d5,0x83fa,0x83c7,0x83d1,0x83ea,0x8413,0x83c3,0x83ec,0x83ee,0x83c4,
+      0x83fb,0x83d7,0x83e2,0x841b,0x83db,0x83fe,0x86d8,0x86e2,0x86e6,0x86d3,
+      0x86e3,0x86da,0x86ea,0x86dd,0x86eb,0x86dc,0x86ec,0x86e9,0x86d7,0x86e8,
+      0x86d1,0x8848,0x8856,0x8855,0x88ba,0x88d7,0x88b9,0x88b8,0x88c0,0x88be,
+      0x88b6,0x88bc,0x88b7,0x88bd,0x88b2,0x8901,0x88c9,0x8995,0x8998,0x8997,
+      0x89dd,0x89da,0x89db,0x8a4e,0x8a4d,0x8a39,0x8a59,0x8a40,0x8a57,0x8a58,
+      0x8a44,0x8a45,0x8a52,0x8a48,0x8a51,0x8a4a,0x8a4c,0x8a4f,0x8c5f,0x8c81,
+      0x8c80,0x8cba,0x8cbe,0x8cb0,0x8cb9,0x8cb5,0x8d84,0x8d80,0x8d89,0x8dd8,
+      0x8dd3,0x8dcd,0x8dc7,0x8dd6,0x8ddc,0x8dcf,0x8dd5,0x8dd9,0x8dc8,0x8dd7,
+      0x8dc5,0x8eef,0x8ef7,0x8efa
+    }
+  },
+  {				/* ku 3c */
+    {
+      0x8ef9,0x8ee6,0x8eee,0x8ee5,0x8ef5,0x8ee7,0x8ee8,0x8ef6,0x8eeb,0x8ef1,
+      0x8eec,0x8ef4,0x8ee9,0x902d,0x9034,0x902f,0x9106,0x912c,0x9104,0x90ff,
+      0x90fc,0x9108,0x90f9,0x90fb,0x9101,0x9100,0x9107,0x9105,0x9103,0x9161,
+      0x9164,0x915f,0x9162,0x9160,0x9201,0x920a,0x9225,0x9203,0x921a,0x9226,
+      0x920f,0x920c,0x9200,0x9212,0x91ff,0x91fd,0x9206,0x9204,0x9227,0x9202,
+      0x921c,0x9224,0x9219,0x9217,0x9205,0x9216,0x957b,0x958d,0x958c,0x9590,
+      0x9687,0x967e,0x9688
+    },{
+      0x9689,0x9683,0x9680,0x96c2,0x96c8,0x96c3,0x96f1,0x96f0,0x976c,0x9770,
+      0x976e,0x9807,0x98a9,0x98eb,0x9ce6,0x9ef9,0x4e83,0x4e84,0x4eb6,0x50bd,
+      0x50bf,0x50c6,0x50ae,0x50c4,0x50ca,0x50b4,0x50c8,0x50c2,0x50b0,0x50c1,
+      0x50ba,0x50b1,0x50cb,0x50c9,0x50b6,0x50b8,0x51d7,0x527a,0x5278,0x527b,
+      0x527c,0x55c3,0x55db,0x55cc,0x55d0,0x55cb,0x55ca,0x55dd,0x55c0,0x55d4,
+      0x55c4,0x55e9,0x55bf,0x55d2,0x558d,0x55cf,0x55d5,0x55e2,0x55d6,0x55c8,
+      0x55f2,0x55cd,0x55d9,0x55c2,0x5714,0x5853,0x5868,0x5864,0x584f,0x584d,
+      0x5849,0x586f,0x5855,0x584e,0x585d,0x5859,0x5865,0x585b,0x583d,0x5863,
+      0x5871,0x58fc,0x5ac7,0x5ac4,0x5acb,0x5aba,0x5ab8,0x5ab1,0x5ab5,0x5ab0,
+      0x5abf,0x5ac8,0x5abb,0x5ac6
+    }
+  },
+  {				/* ku 3d */
+    {
+      0x5ab7,0x5ac0,0x5aca,0x5ab4,0x5ab6,0x5acd,0x5ab9,0x5a90,0x5bd6,0x5bd8,
+      0x5bd9,0x5c1f,0x5c33,0x5d71,0x5d63,0x5d4a,0x5d65,0x5d72,0x5d6c,0x5d5e,
+      0x5d68,0x5d67,0x5d62,0x5df0,0x5e4f,0x5e4e,0x5e4a,0x5e4d,0x5e4b,0x5ec5,
+      0x5ecc,0x5ec6,0x5ecb,0x5ec7,0x5f40,0x5faf,0x5fad,0x60f7,0x6149,0x614a,
+      0x612b,0x6145,0x6136,0x6132,0x612e,0x6146,0x612f,0x614f,0x6129,0x6140,
+      0x6220,0x9168,0x6223,0x6225,0x6224,0x63c5,0x63f1,0x63eb,0x6410,0x6412,
+      0x6409,0x6420,0x6424
+    },{
+      0x6433,0x6443,0x641f,0x6415,0x6418,0x6439,0x6437,0x6422,0x6423,0x640c,
+      0x6426,0x6430,0x6428,0x6441,0x6435,0x642f,0x640a,0x641a,0x6440,0x6425,
+      0x6427,0x640b,0x63e7,0x641b,0x642e,0x6421,0x640e,0x656f,0x6592,0x65d3,
+      0x6686,0x668c,0x6695,0x6690,0x668b,0x668a,0x6699,0x6694,0x6678,0x6720,
+      0x6966,0x695f,0x6938,0x694e,0x6962,0x6971,0x693f,0x6945,0x696a,0x6939,
+      0x6942,0x6957,0x6959,0x697a,0x6948,0x6949,0x6935,0x696c,0x6933,0x693d,
+      0x6965,0x68f0,0x6978,0x6934,0x6969,0x6940,0x696f,0x6944,0x6976,0x6958,
+      0x6941,0x6974,0x694c,0x693b,0x694b,0x6937,0x695c,0x694f,0x6951,0x6932,
+      0x6952,0x692f,0x697b,0x693c,0x6b46,0x6b45,0x6b43,0x6b42,0x6b48,0x6b41,
+      0x6b9b,0xfa0d,0x6bfb,0x6bfc
+    }
+  },
+  {				/* ku 3e */
+    {
+      0x6bf9,0x6bf7,0x6bf8,0x6e9b,0x6ed6,0x6ec8,0x6e8f,0x6ec0,0x6e9f,0x6e93,
+      0x6e94,0x6ea0,0x6eb1,0x6eb9,0x6ec6,0x6ed2,0x6ebd,0x6ec1,0x6e9e,0x6ec9,
+      0x6eb7,0x6eb0,0x6ecd,0x6ea6,0x6ecf,0x6eb2,0x6ebe,0x6ec3,0x6edc,0x6ed8,
+      0x6e99,0x6e92,0x6e8e,0x6e8d,0x6ea4,0x6ea1,0x6ebf,0x6eb3,0x6ed0,0x6eca,
+      0x6e97,0x6eae,0x6ea3,0x7147,0x7154,0x7152,0x7163,0x7160,0x7141,0x715d,
+      0x7162,0x7172,0x7178,0x716a,0x7161,0x7142,0x7158,0x7143,0x714b,0x7170,
+      0x715f,0x7150,0x7153
+    },{
+      0x7144,0x714d,0x715a,0x724f,0x728d,0x728c,0x7291,0x7290,0x728e,0x733c,
+      0x7342,0x733b,0x733a,0x7340,0x734a,0x7349,0x7444,0x744a,0x744b,0x7452,
+      0x7451,0x7457,0x7440,0x744f,0x7450,0x744e,0x7442,0x7446,0x744d,0x7454,
+      0x74e1,0x74ff,0x74fe,0x74fd,0x751d,0x7579,0x7577,0x6983,0x75ef,0x760f,
+      0x7603,0x75f7,0x75fe,0x75fc,0x75f9,0x75f8,0x7610,0x75fb,0x75f6,0x75ed,
+      0x75f5,0x75fd,0x7699,0x76b5,0x76dd,0x7755,0x775f,0x7760,0x7752,0x7756,
+      0x775a,0x7769,0x7767,0x7754,0x7759,0x776d,0x77e0,0x7887,0x789a,0x7894,
+      0x788f,0x7884,0x7895,0x7885,0x7886,0x78a1,0x7883,0x7879,0x7899,0x7880,
+      0x7896,0x787b,0x797c,0x7982,0x797d,0x7979,0x7a11,0x7a18,0x7a19,0x7a12,
+      0x7a17,0x7a15,0x7a22,0x7a13
+    }
+  },
+  {				/* ku 3f */
+    {
+      0x7a1b,0x7a10,0x7aa3,0x7aa2,0x7a9e,0x7aeb,0x7b66,0x7b64,0x7b6d,0x7b74,
+      0x7b69,0x7b72,0x7b65,0x7b73,0x7b71,0x7b70,0x7b61,0x7b78,0x7b76,0x7b63,
+      0x7cb2,0x7cb4,0x7caf,0x7d88,0x7d86,0x7d80,0x7d8d,0x7d7f,0x7d85,0x7d7a,
+      0x7d8e,0x7d7b,0x7d83,0x7d7c,0x7d8c,0x7d94,0x7d84,0x7d7d,0x7d92,0x7f6d,
+      0x7f6b,0x7f67,0x7f68,0x7f6c,0x7fa6,0x7fa5,0x7fa7,0x7fdb,0x7fdc,0x8021,
+      0x8164,0x8160,0x8177,0x815c,0x8169,0x815b,0x8162,0x8172,0x6721,0x815e,
+      0x8176,0x8167,0x816f
+    },{
+      0x8144,0x8161,0x821d,0x8249,0x8244,0x8240,0x8242,0x8245,0x84f1,0x843f,
+      0x8456,0x8476,0x8479,0x848f,0x848d,0x8465,0x8451,0x8440,0x8486,0x8467,
+      0x8430,0x844d,0x847d,0x845a,0x8459,0x8474,0x8473,0x845d,0x8507,0x845e,
+      0x8437,0x843a,0x8434,0x847a,0x8443,0x8478,0x8432,0x8445,0x8429,0x83d9,
+      0x844b,0x842f,0x8442,0x842d,0x845f,0x8470,0x8439,0x844e,0x844c,0x8452,
+      0x846f,0x84c5,0x848e,0x843b,0x8447,0x8436,0x8433,0x8468,0x847e,0x8444,
+      0x842b,0x8460,0x8454,0x846e,0x8450,0x870b,0x8704,0x86f7,0x870c,0x86fa,
+      0x86d6,0x86f5,0x874d,0x86f8,0x870e,0x8709,0x8701,0x86f6,0x870d,0x8705,
+      0x88d6,0x88cb,0x88cd,0x88ce,0x88de,0x88db,0x88da,0x88cc,0x88d0,0x8985,
+      0x899b,0x89df,0x89e5,0x89e4
+    }
+  },
+  {				/* ku 40 */
+    {
+      0x89e1,0x89e0,0x89e2,0x89dc,0x89e6,0x8a76,0x8a86,0x8a7f,0x8a61,0x8a3f,
+      0x8a77,0x8a82,0x8a84,0x8a75,0x8a83,0x8a81,0x8a74,0x8a7a,0x8c3c,0x8c4b,
+      0x8c4a,0x8c65,0x8c64,0x8c66,0x8c86,0x8c84,0x8c85,0x8ccc,0x8d68,0x8d69,
+      0x8d91,0x8d8c,0x8d8e,0x8d8f,0x8d8d,0x8d93,0x8d94,0x8d90,0x8d92,0x8df0,
+      0x8de0,0x8dec,0x8df1,0x8dee,0x8dd0,0x8de9,0x8de3,0x8de2,0x8de7,0x8df2,
+      0x8deb,0x8df4,0x8f06,0x8eff,0x8f01,0x8f00,0x8f05,0x8f07,0x8f08,0x8f02,
+      0x8f0b,0x9052,0x903f
+    },{
+      0x9044,0x9049,0x903d,0x9110,0x910d,0x910f,0x9111,0x9116,0x9114,0x910b,
+      0x910e,0x916e,0x916f,0x9248,0x9252,0x9230,0x923a,0x9266,0x9233,0x9265,
+      0x925e,0x9283,0x922e,0x924a,0x9246,0x926d,0x926c,0x924f,0x9260,0x9267,
+      0x926f,0x9236,0x9261,0x9270,0x9231,0x9254,0x9263,0x9250,0x9272,0x924e,
+      0x9253,0x924c,0x9256,0x9232,0x959f,0x959c,0x959e,0x959b,0x9692,0x9693,
+      0x9691,0x9697,0x96ce,0x96fa,0x96fd,0x96f8,0x96f5,0x9773,0x9777,0x9778,
+      0x9772,0x980f,0x980d,0x980e,0x98ac,0x98f6,0x98f9,0x99af,0x99b2,0x99b0,
+      0x99b5,0x9aad,0x9aab,0x9b5b,0x9cea,0x9ced,0x9ce7,0x9e80,0x9efd,0x50e6,
+      0x50d4,0x50d7,0x50e8,0x50f3,0x50db,0x50ea,0x50dd,0x50e4,0x50d3,0x50ec,
+      0x50f0,0x50ef,0x50e3,0x50e0
+    }
+  },
+  {				/* ku 41 */
+    {
+      0x51d8,0x5280,0x5281,0x52e9,0x52eb,0x5330,0x53ac,0x5627,0x5615,0x560c,
+      0x5612,0x55fc,0x560f,0x561c,0x5601,0x5613,0x5602,0x55fa,0x561d,0x5604,
+      0x55ff,0x55f9,0x5889,0x587c,0x5890,0x5898,0x5886,0x5881,0x587f,0x5874,
+      0x588b,0x587a,0x5887,0x5891,0x588e,0x5876,0x5882,0x5888,0x587b,0x5894,
+      0x588f,0x58fe,0x596b,0x5adc,0x5aee,0x5ae5,0x5ad5,0x5aea,0x5ada,0x5aed,
+      0x5aeb,0x5af3,0x5ae2,0x5ae0,0x5adb,0x5aec,0x5ade,0x5add,0x5ad9,0x5ae8,
+      0x5adf,0x5b77,0x5be0
+    },{
+      0x5be3,0x5c63,0x5d82,0x5d80,0x5d7d,0x5d86,0x5d7a,0x5d81,0x5d77,0x5d8a,
+      0x5d89,0x5d88,0x5d7e,0x5d7c,0x5d8d,0x5d79,0x5d7f,0x5e58,0x5e59,0x5e53,
+      0x5ed8,0x5ed1,0x5ed7,0x5ece,0x5edc,0x5ed5,0x5ed9,0x5ed2,0x5ed4,0x5f44,
+      0x5f43,0x5f6f,0x5fb6,0x612c,0x6128,0x6141,0x615e,0x6171,0x6173,0x6152,
+      0x6153,0x6172,0x616c,0x6180,0x6174,0x6154,0x617a,0x615b,0x6165,0x613b,
+      0x616a,0x6161,0x6156,0x6229,0x6227,0x622b,0x642b,0x644d,0x645b,0x645d,
+      0x6474,0x6476,0x6472,0x6473,0x647d,0x6475,0x6466,0x64a6,0x644e,0x6482,
+      0x645e,0x645c,0x644b,0x6453,0x6460,0x6450,0x647f,0x643f,0x646c,0x646b,
+      0x6459,0x6465,0x6477,0x6573,0x65a0,0x66a1,0x66a0,0x669f,0x6705,0x6704,
+      0x6722,0x69b1,0x69b6,0x69c9
+    }
+  },
+  {				/* ku 42 */
+    {
+      0x69a0,0x69ce,0x6996,0x69b0,0x69ac,0x69bc,0x6991,0x6999,0x698e,0x69a7,
+      0x698d,0x69a9,0x69be,0x69af,0x69bf,0x69c4,0x69bd,0x69a4,0x69d4,0x69b9,
+      0x69ca,0x699a,0x69cf,0x69b3,0x6993,0x69aa,0x69a1,0x699e,0x69d9,0x6997,
+      0x6990,0x69c2,0x69b5,0x69a5,0x69c6,0x6b4a,0x6b4d,0x6b4b,0x6b9e,0x6b9f,
+      0x6ba0,0x6bc3,0x6bc4,0x6bfe,0x6ece,0x6ef5,0x6ef1,0x6f03,0x6f25,0x6ef8,
+      0x6f37,0x6efb,0x6f2e,0x6f09,0x6f4e,0x6f19,0x6f1a,0x6f27,0x6f18,0x6f3b,
+      0x6f12,0x6eed,0x6f0a
+    },{
+      0x6f36,0x6f73,0x6ef9,0x6eee,0x6f2d,0x6f40,0x6f30,0x6f3c,0x6f35,0x6eeb,
+      0x6f07,0x6f0e,0x6f43,0x6f05,0x6efd,0x6ef6,0x6f39,0x6f1c,0x6efc,0x6f3a,
+      0x6f1f,0x6f0d,0x6f1e,0x6f08,0x6f21,0x7187,0x7190,0x7189,0x7180,0x7185,
+      0x7182,0x718f,0x717b,0x7186,0x7181,0x7197,0x7244,0x7253,0x7297,0x7295,
+      0x7293,0x7343,0x734d,0x7351,0x734c,0x7462,0x7473,0x7471,0x7475,0x7472,
+      0x7467,0x746e,0x7500,0x7502,0x7503,0x757d,0x7590,0x7616,0x7608,0x760c,
+      0x7615,0x7611,0x760a,0x7614,0x76b8,0x7781,0x777c,0x7785,0x7782,0x776e,
+      0x7780,0x776f,0x777e,0x7783,0x78b2,0x78aa,0x78b4,0x78ad,0x78a8,0x787e,
+      0x78ab,0x789e,0x78a5,0x78a0,0x78ac,0x78a2,0x78a4,0x7998,0x798a,0x798b,
+      0x7996,0x7995,0x7994,0x7993
+    }
+  },
+  {				/* ku 43 */
+    {
+      0x7997,0x7988,0x7992,0x7990,0x7a2b,0x7a4a,0x7a30,0x7a2f,0x7a28,0x7a26,
+      0x7aa8,0x7aab,0x7aac,0x7aee,0x7b88,0x7b9c,0x7b8a,0x7b91,0x7b90,0x7b96,
+      0x7b8d,0x7b8c,0x7b9b,0x7b8e,0x7b85,0x7b98,0x5284,0x7b99,0x7ba4,0x7b82,
+      0x7cbb,0x7cbf,0x7cbc,0x7cba,0x7da7,0x7db7,0x7dc2,0x7da3,0x7daa,0x7dc1,
+      0x7dc0,0x7dc5,0x7d9d,0x7dce,0x7dc4,0x7dc6,0x7dcb,0x7dcc,0x7daf,0x7db9,
+      0x7d96,0x7dbc,0x7d9f,0x7da6,0x7dae,0x7da9,0x7da1,0x7dc9,0x7f73,0x7fe2,
+      0x7fe3,0x7fe5,0x7fde
+    },{
+      0x8024,0x805d,0x805c,0x8189,0x8186,0x8183,0x8187,0x818d,0x818c,0x818b,
+      0x8215,0x8497,0x84a4,0x84a1,0x849f,0x84ba,0x84ce,0x84c2,0x84ac,0x84ae,
+      0x84ab,0x84b9,0x84b4,0x84c1,0x84cd,0x84aa,0x849a,0x84b1,0x84d0,0x849d,
+      0x84a7,0x84bb,0x84a2,0x8494,0x84c7,0x84cc,0x849b,0x84a9,0x84af,0x84a8,
+      0x84d6,0x8498,0x84b6,0x84cf,0x84a0,0x84d7,0x84d4,0x84d2,0x84db,0x84b0,
+      0x8491,0x8661,0x8733,0x8723,0x8728,0x876b,0x8740,0x872e,0x871e,0x8721,
+      0x8719,0x871b,0x8743,0x872c,0x8741,0x873e,0x8746,0x8720,0x8732,0x872a,
+      0x872d,0x873c,0x8712,0x873a,0x8731,0x8735,0x8742,0x8726,0x8727,0x8738,
+      0x8724,0x871a,0x8730,0x8711,0x88f7,0x88e7,0x88f1,0x88f2,0x88fa,0x88fe,
+      0x88ee,0x88fc,0x88f6,0x88fb
+    }
+  },
+  {				/* ku 44 */
+    {
+      0x88f0,0x88ec,0x88eb,0x899d,0x89a1,0x899f,0x899e,0x89e9,0x89eb,0x89e8,
+      0x8aab,0x8a99,0x8a8b,0x8a92,0x8a8f,0x8a96,0x8c3d,0x8c68,0x8c69,0x8cd5,
+      0x8ccf,0x8cd7,0x8d96,0x8e09,0x8e02,0x8dff,0x8e0d,0x8dfd,0x8e0a,0x8e03,
+      0x8e07,0x8e06,0x8e05,0x8dfe,0x8e00,0x8e04,0x8f10,0x8f11,0x8f0e,0x8f0d,
+      0x9123,0x911c,0x9120,0x9122,0x911f,0x911d,0x911a,0x9124,0x9121,0x911b,
+      0x917a,0x9172,0x9179,0x9173,0x92a5,0x92a4,0x9276,0x929b,0x927a,0x92a0,
+      0x9294,0x92aa,0x928d
+    },{
+      0x92a6,0x929a,0x92ab,0x9279,0x9297,0x927f,0x92a3,0x92ee,0x928e,0x9282,
+      0x9295,0x92a2,0x927d,0x9288,0x92a1,0x928a,0x9286,0x928c,0x9299,0x92a7,
+      0x927e,0x9287,0x92a9,0x929d,0x928b,0x922d,0x969e,0x96a1,0x96ff,0x9758,
+      0x977d,0x977a,0x977e,0x9783,0x9780,0x9782,0x977b,0x9784,0x9781,0x977f,
+      0x97ce,0x97cd,0x9816,0x98ad,0x98ae,0x9902,0x9900,0x9907,0x999d,0x999c,
+      0x99c3,0x99b9,0x99bb,0x99ba,0x99c2,0x99bd,0x99c7,0x9ab1,0x9ae3,0x9ae7,
+      0x9b3e,0x9b3f,0x9b60,0x9b61,0x9b5f,0x9cf1,0x9cf2,0x9cf5,0x9ea7,0x50ff,
+      0x5103,0x5130,0x50f8,0x5106,0x5107,0x50f6,0x50fe,0x510b,0x510c,0x50fd,
+      0x510a,0x528b,0x528c,0x52f1,0x52ef,0x5648,0x5642,0x564c,0x5635,0x5641,
+      0x564a,0x5649,0x5646,0x5658
+    }
+  },
+  {				/* ku 45 */
+    {
+      0x565a,0x5640,0x5633,0x563d,0x562c,0x563e,0x5638,0x562a,0x563a,0x571a,
+      0x58ab,0x589d,0x58b1,0x58a0,0x58a3,0x58af,0x58ac,0x58a5,0x58a1,0x58ff,
+      0x5aff,0x5af4,0x5afd,0x5af7,0x5af6,0x5b03,0x5af8,0x5b02,0x5af9,0x5b01,
+      0x5b07,0x5b05,0x5b0f,0x5c67,0x5d99,0x5d97,0x5d9f,0x5d92,0x5da2,0x5d93,
+      0x5d95,0x5da0,0x5d9c,0x5da1,0x5d9a,0x5d9e,0x5e69,0x5e5d,0x5e60,0x5e5c,
+      0x7df3,0x5edb,0x5ede,0x5ee1,0x5f49,0x5fb2,0x618b,0x6183,0x6179,0x61b1,
+      0x61b0,0x61a2,0x6189
+    },{
+      0x619b,0x6193,0x61af,0x61ad,0x619f,0x6192,0x61aa,0x61a1,0x618d,0x6166,
+      0x61b3,0x622d,0x646e,0x6470,0x6496,0x64a0,0x6485,0x6497,0x649c,0x648f,
+      0x648b,0x648a,0x648c,0x64a3,0x649f,0x6468,0x64b1,0x6498,0x6576,0x657a,
+      0x6579,0x657b,0x65b2,0x65b3,0x66b5,0x66b0,0x66a9,0x66b2,0x66b7,0x66aa,
+      0x66af,0x6a00,0x6a06,0x6a17,0x69e5,0x69f8,0x6a15,0x69f1,0x69e4,0x6a20,
+      0x69ff,0x69ec,0x69e2,0x6a1b,0x6a1d,0x69fe,0x6a27,0x69f2,0x69ee,0x6a14,
+      0x69f7,0x69e7,0x6a40,0x6a08,0x69e6,0x69fb,0x6a0d,0x69fc,0x69eb,0x6a09,
+      0x6a04,0x6a18,0x6a25,0x6a0f,0x69f6,0x6a26,0x6a07,0x69f4,0x6a16,0x6b51,
+      0x6ba5,0x6ba3,0x6ba2,0x6ba6,0x6c01,0x6c00,0x6bff,0x6c02,0x6f41,0x6f26,
+      0x6f7e,0x6f87,0x6fc6,0x6f92
+    }
+  },
+  {				/* ku 46 */
+    {
+      0x6f8d,0x6f89,0x6f8c,0x6f62,0x6f4f,0x6f85,0x6f5a,0x6f96,0x6f76,0x6f6c,
+      0x6f82,0x6f55,0x6f72,0x6f52,0x6f50,0x6f57,0x6f94,0x6f93,0x6f5d,0x6f00,
+      0x6f61,0x6f6b,0x6f7d,0x6f67,0x6f90,0x6f53,0x6f8b,0x6f69,0x6f7f,0x6f95,
+      0x6f63,0x6f77,0x6f6a,0x6f7b,0x71b2,0x71af,0x719b,0x71b0,0x71a0,0x719a,
+      0x71a9,0x71b5,0x719d,0x71a5,0x719e,0x71a4,0x71a1,0x71aa,0x719c,0x71a7,
+      0x71b3,0x7298,0x729a,0x7358,0x7352,0x735e,0x735f,0x7360,0x735d,0x735b,
+      0x7361,0x735a,0x7359
+    },{
+      0x7362,0x7487,0x7489,0x748a,0x7486,0x7481,0x747d,0x7485,0x7488,0x747c,
+      0x7479,0x7508,0x7507,0x757e,0x7625,0x761e,0x7619,0x761d,0x761c,0x7623,
+      0x761a,0x7628,0x761b,0x769c,0x769d,0x769e,0x769b,0x778d,0x778f,0x7789,
+      0x7788,0x78cd,0x78bb,0x78cf,0x78cc,0x78d1,0x78ce,0x78d4,0x78c8,0x78c3,
+      0x78c4,0x78c9,0x799a,0x79a1,0x79a0,0x799c,0x79a2,0x799b,0x6b76,0x7a39,
+      0x7ab2,0x7ab4,0x7ab3,0x7bb7,0x7bcb,0x7bbe,0x7bac,0x7bce,0x7baf,0x7bb9,
+      0x7bca,0x7bb5,0x7cc5,0x7cc8,0x7ccc,0x7ccb,0x7df7,0x7ddb,0x7dea,0x7de7,
+      0x7dd7,0x7de1,0x7e03,0x7dfa,0x7de6,0x7df6,0x7df1,0x7df0,0x7dee,0x7ddf,
+      0x7f76,0x7fac,0x7fb0,0x7fad,0x7fed,0x7feb,0x7fea,0x7fec,0x7fe6,0x7fe8,
+      0x8064,0x8067,0x81a3,0x819f
+    }
+  },
+  {				/* ku 47 */
+    {
+      0x819e,0x8195,0x81a2,0x8199,0x8197,0x8216,0x824f,0x8253,0x8252,0x8250,
+      0x824e,0x8251,0x8524,0x853b,0x850f,0x8500,0x8529,0x850e,0x8509,0x850d,
+      0x851f,0x850a,0x8527,0x851c,0x84fb,0x852b,0x84fa,0x8508,0x850c,0x84f4,
+      0x852a,0x84f2,0x8515,0x84f7,0x84eb,0x84f3,0x84fc,0x8512,0x84ea,0x84e9,
+      0x8516,0x84fe,0x8528,0x851d,0x852e,0x8502,0x84fd,0x851e,0x84f6,0x8531,
+      0x8526,0x84e7,0x84e8,0x84f0,0x84ef,0x84f9,0x8518,0x8520,0x8530,0x850b,
+      0x8519,0x852f,0x8662
+    },{
+      0x8756,0x8763,0x8764,0x8777,0x87e1,0x8773,0x8758,0x8754,0x875b,0x8752,
+      0x8761,0x875a,0x8751,0x875e,0x876d,0x876a,0x8750,0x874e,0x875f,0x875d,
+      0x876f,0x876c,0x877a,0x876e,0x875c,0x8765,0x874f,0x877b,0x8775,0x8762,
+      0x8767,0x8769,0x885a,0x8905,0x890c,0x8914,0x890b,0x8917,0x8918,0x8919,
+      0x8906,0x8916,0x8911,0x890e,0x8909,0x89a2,0x89a4,0x89a3,0x89ed,0x89f0,
+      0x89ec,0x8acf,0x8ac6,0x8ab8,0x8ad3,0x8ad1,0x8ad4,0x8ad5,0x8abb,0x8ad7,
+      0x8abe,0x8ac0,0x8ac5,0x8ad8,0x8ac3,0x8aba,0x8abd,0x8ad9,0x8c3e,0x8c4d,
+      0x8c8f,0x8ce5,0x8cdf,0x8cd9,0x8ce8,0x8cda,0x8cdd,0x8ce7,0x8da0,0x8d9c,
+      0x8da1,0x8d9b,0x8e20,0x8e23,0x8e25,0x8e24,0x8e2e,0x8e15,0x8e1b,0x8e16,
+      0x8e11,0x8e19,0x8e26,0x8e27
+    }
+  },
+  {				/* ku 48 */
+    {
+      0x8e14,0x8e12,0x8e18,0x8e13,0x8e1c,0x8e17,0x8e1a,0x8f2c,0x8f24,0x8f18,
+      0x8f1a,0x8f20,0x8f23,0x8f16,0x8f17,0x9073,0x9070,0x906f,0x9067,0x906b,
+      0x912f,0x912b,0x9129,0x912a,0x9132,0x9126,0x912e,0x9185,0x9186,0x918a,
+      0x9181,0x9182,0x9184,0x9180,0x92d0,0x92c3,0x92c4,0x92c0,0x92d9,0x92b6,
+      0x92cf,0x92f1,0x92df,0x92d8,0x92e9,0x92d7,0x92dd,0x92cc,0x92ef,0x92c2,
+      0x92e8,0x92ca,0x92c8,0x92ce,0x92e6,0x92cd,0x92d5,0x92c9,0x92e0,0x92de,
+      0x92e7,0x92d1,0x92d3
+    },{
+      0x92b5,0x92e1,0x92c6,0x92b4,0x957c,0x95ac,0x95ab,0x95ae,0x95b0,0x96a4,
+      0x96a2,0x96d3,0x9705,0x9708,0x9702,0x975a,0x978a,0x978e,0x9788,0x97d0,
+      0x97cf,0x981e,0x981d,0x9826,0x9829,0x9828,0x9820,0x981b,0x9827,0x98b2,
+      0x9908,0x98fa,0x9911,0x9914,0x9916,0x9917,0x9915,0x99dc,0x99cd,0x99cf,
+      0x99d3,0x99d4,0x99ce,0x99c9,0x99d6,0x99d8,0x99cb,0x99d7,0x99cc,0x9ab3,
+      0x9aec,0x9aeb,0x9af3,0x9af2,0x9af1,0x9b46,0x9b43,0x9b67,0x9b74,0x9b71,
+      0x9b66,0x9b76,0x9b75,0x9b70,0x9b68,0x9b64,0x9b6c,0x9cfc,0x9cfa,0x9cfd,
+      0x9cff,0x9cf7,0x9d07,0x9d00,0x9cf9,0x9cfb,0x9d08,0x9d05,0x9d04,0x9e83,
+      0x9ed3,0x9f0f,0x9f10,0x511c,0x5113,0x5117,0x511a,0x5111,0x51de,0x5334,
+      0x53e1,0x5670,0x5660,0x566e
+    }
+  },
+  {				/* ku 49 */
+    {
+      0x5673,0x5666,0x5663,0x566d,0x5672,0x565e,0x5677,0x571c,0x571b,0x58c8,
+      0x58bd,0x58c9,0x58bf,0x58ba,0x58c2,0x58bc,0x58c6,0x5b17,0x5b19,0x5b1b,
+      0x5b21,0x5b14,0x5b13,0x5b10,0x5b16,0x5b28,0x5b1a,0x5b20,0x5b1e,0x5bef,
+      0x5dac,0x5db1,0x5da9,0x5da7,0x5db5,0x5db0,0x5dae,0x5daa,0x5da8,0x5db2,
+      0x5dad,0x5daf,0x5db4,0x5e67,0x5e68,0x5e66,0x5e6f,0x5ee9,0x5ee7,0x5ee6,
+      0x5ee8,0x5ee5,0x5f4b,0x5fbc,0x619d,0x61a8,0x6196,0x61c5,0x61b4,0x61c6,
+      0x61c1,0x61cc,0x61ba
+    },{
+      0x61bf,0x61b8,0x618c,0x64d7,0x64d6,0x64d0,0x64cf,0x64c9,0x64bd,0x6489,
+      0x64c3,0x64db,0x64f3,0x64d9,0x6533,0x657f,0x657c,0x65a2,0x66c8,0x66be,
+      0x66c0,0x66ca,0x66cb,0x66cf,0x66bd,0x66bb,0x66ba,0x66cc,0x6723,0x6a34,
+      0x6a66,0x6a49,0x6a67,0x6a32,0x6a68,0x6a3e,0x6a5d,0x6a6d,0x6a76,0x6a5b,
+      0x6a51,0x6a28,0x6a5a,0x6a3b,0x6a3f,0x6a41,0x6a6a,0x6a64,0x6a50,0x6a4f,
+      0x6a54,0x6a6f,0x6a69,0x6a60,0x6a3c,0x6a5e,0x6a56,0x6a55,0x6a4d,0x6a4e,
+      0x6a46,0x6b55,0x6b54,0x6b56,0x6ba7,0x6baa,0x6bab,0x6bc8,0x6bc7,0x6c04,
+      0x6c03,0x6c06,0x6fad,0x6fcb,0x6fa3,0x6fc7,0x6fbc,0x6fce,0x6fc8,0x6f5e,
+      0x6fc4,0x6fbd,0x6f9e,0x6fca,0x6fa8,0x7004,0x6fa5,0x6fae,0x6fba,0x6fac,
+      0x6faa,0x6fcf,0x6fbf,0x6fb8
+    }
+  },
+  {				/* ku 4a */
+    {
+      0x6fa2,0x6fc9,0x6fab,0x6fcd,0x6faf,0x6fb2,0x6fb0,0x71c5,0x71c2,0x71bf,
+      0x71b8,0x71d6,0x71c0,0x71c1,0x71cb,0x71d4,0x71ca,0x71c7,0x71cf,0x71bd,
+      0x71d8,0x71bc,0x71c6,0x71da,0x71db,0x729d,0x729e,0x7369,0x7366,0x7367,
+      0x736c,0x7365,0x736b,0x736a,0x747f,0x749a,0x74a0,0x7494,0x7492,0x7495,
+      0x74a1,0x750b,0x7580,0x762f,0x762d,0x7631,0x763d,0x7633,0x763c,0x7635,
+      0x7632,0x7630,0x76bb,0x76e6,0x779a,0x779d,0x77a1,0x779c,0x779b,0x77a2,
+      0x77a3,0x7795,0x7799
+    },{
+      0x7797,0x78dd,0x78e9,0x78e5,0x78ea,0x78de,0x78e3,0x78db,0x78e1,0x78e2,
+      0x78ed,0x78df,0x78e0,0x79a4,0x7a44,0x7a48,0x7a47,0x7ab6,0x7ab8,0x7ab5,
+      0x7ab1,0x7ab7,0x7bde,0x7be3,0x7be7,0x7bdd,0x7bd5,0x7be5,0x7bda,0x7be8,
+      0x7bf9,0x7bd4,0x7bea,0x7be2,0x7bdc,0x7beb,0x7bd8,0x7bdf,0x7cd2,0x7cd4,
+      0x7cd7,0x7cd0,0x7cd1,0x7e12,0x7e21,0x7e17,0x7e0c,0x7e1f,0x7e20,0x7e13,
+      0x7e0e,0x7e1c,0x7e15,0x7e1a,0x7e22,0x7e0b,0x7e0f,0x7e16,0x7e0d,0x7e14,
+      0x7e25,0x7e24,0x7f43,0x7f7b,0x7f7c,0x7f7a,0x7fb1,0x7fef,0x802a,0x8029,
+      0x806c,0x81b1,0x81a6,0x81ae,0x81b9,0x81b5,0x81ab,0x81b0,0x81ac,0x81b4,
+      0x81b2,0x81b7,0x81a7,0x81f2,0x8255,0x8256,0x8257,0x8556,0x8545,0x856b,
+      0x854d,0x8553,0x8561,0x8558
+    }
+  },
+  {				/* ku 4b */
+    {
+      0x8540,0x8546,0x8564,0x8541,0x8562,0x8544,0x8551,0x8547,0x8563,0x853e,
+      0x855b,0x8571,0x854e,0x856e,0x8575,0x8555,0x8567,0x8560,0x858c,0x8566,
+      0x855d,0x8554,0x8565,0x856c,0x8663,0x8665,0x8664,0x879b,0x878f,0x8797,
+      0x8793,0x8792,0x8788,0x8781,0x8796,0x8798,0x8779,0x8787,0x87a3,0x8785,
+      0x8790,0x8791,0x879d,0x8784,0x8794,0x879c,0x879a,0x8789,0x891e,0x8926,
+      0x8930,0x892d,0x892e,0x8927,0x8931,0x8922,0x8929,0x8923,0x892f,0x892c,
+      0x891f,0x89f1,0x8ae0
+    },{
+      0x8ae2,0x8af2,0x8af4,0x8af5,0x8add,0x8b14,0x8ae4,0x8adf,0x8af0,0x8ac8,
+      0x8ade,0x8ae1,0x8ae8,0x8aff,0x8aef,0x8afb,0x8c91,0x8c92,0x8c90,0x8cf5,
+      0x8cee,0x8cf1,0x8cf0,0x8cf3,0x8d6c,0x8d6e,0x8da5,0x8da7,0x8e33,0x8e3e,
+      0x8e38,0x8e40,0x8e45,0x8e36,0x8e3c,0x8e3d,0x8e41,0x8e30,0x8e3f,0x8ebd,
+      0x8f36,0x8f2e,0x8f35,0x8f32,0x8f39,0x8f37,0x8f34,0x9076,0x9079,0x907b,
+      0x9086,0x90fa,0x9133,0x9135,0x9136,0x9193,0x9190,0x9191,0x918d,0x918f,
+      0x9327,0x931e,0x9308,0x931f,0x9306,0x930f,0x937a,0x9338,0x933c,0x931b,
+      0x9323,0x9312,0x9301,0x9346,0x932d,0x930e,0x930d,0x92cb,0x931d,0x92fa,
+      0x9325,0x9313,0x92f9,0x92f7,0x9334,0x9302,0x9324,0x92ff,0x9329,0x9339,
+      0x9335,0x932a,0x9314,0x930c
+    }
+  },
+  {				/* ku 4c */
+    {
+      0x930b,0x92fe,0x9309,0x9300,0x92fb,0x9316,0x95bc,0x95cd,0x95be,0x95b9,
+      0x95ba,0x95b6,0x95bf,0x95b5,0x95bd,0x96a9,0x96d4,0x970b,0x9712,0x9710,
+      0x9799,0x9797,0x9794,0x97f0,0x97f8,0x9835,0x982f,0x9832,0x9924,0x991f,
+      0x9927,0x9929,0x999e,0x99ee,0x99ec,0x99e5,0x99e4,0x99f0,0x99e3,0x99ea,
+      0x99e9,0x99e7,0x9ab9,0x9abf,0x9ab4,0x9abb,0x9af6,0x9afa,0x9af9,0x9af7,
+      0x9b33,0x9b80,0x9b85,0x9b87,0x9b7c,0x9b7e,0x9b7b,0x9b82,0x9b93,0x9b92,
+      0x9b90,0x9b7a,0x9b95
+    },{
+      0x9b7d,0x9b88,0x9d25,0x9d17,0x9d20,0x9d1e,0x9d14,0x9d29,0x9d1d,0x9d18,
+      0x9d22,0x9d10,0x9d19,0x9d1f,0x9e88,0x9e86,0x9e87,0x9eae,0x9ead,0x9ed5,
+      0x9ed6,0x9efa,0x9f12,0x9f3d,0x5126,0x5125,0x5122,0x5124,0x5120,0x5129,
+      0x52f4,0x5693,0x568c,0x568d,0x5686,0x5684,0x5683,0x567e,0x5682,0x567f,
+      0x5681,0x58d6,0x58d4,0x58cf,0x58d2,0x5b2d,0x5b25,0x5b32,0x5b23,0x5b2c,
+      0x5b27,0x5b26,0x5b2f,0x5b2e,0x5b7b,0x5bf1,0x5bf2,0x5db7,0x5e6c,0x5e6a,
+      0x5fbe,0x5fbb,0x61c3,0x61b5,0x61bc,0x61e7,0x61e0,0x61e5,0x61e4,0x61e8,
+      0x61de,0x64ef,0x64e9,0x64e3,0x64eb,0x64e4,0x64e8,0x6581,0x6580,0x65b6,
+      0x65da,0x66d2,0x6a8d,0x6a96,0x6a81,0x6aa5,0x6a89,0x6a9f,0x6a9b,0x6aa1,
+      0x6a9e,0x6a87,0x6a93,0x6a8e
+    }
+  },
+  {				/* ku 4d */
+    {
+      0x6a95,0x6a83,0x6aa8,0x6aa4,0x6a91,0x6a7f,0x6aa6,0x6a9a,0x6a85,0x6a8c,
+      0x6a92,0x6b5b,0x6bad,0x6c09,0x6fcc,0x6fa9,0x6ff4,0x6fd4,0x6fe3,0x6fdc,
+      0x6fed,0x6fe7,0x6fe6,0x6fde,0x6ff2,0x6fdd,0x6fe2,0x6fe8,0x71e1,0x71f1,
+      0x71e8,0x71f2,0x71e4,0x71f0,0x71e2,0x7373,0x736e,0x736f,0x7497,0x74b2,
+      0x74ab,0x7490,0x74aa,0x74ad,0x74b1,0x74a5,0x74af,0x7510,0x7511,0x7512,
+      0x750f,0x7584,0x7643,0x7648,0x7649,0x7647,0x76a4,0x76e9,0x77b5,0x77ab,
+      0x77b2,0x77b7,0x77b6
+    },{
+      0x77b4,0x77b1,0x77a8,0x77f0,0x78f3,0x78fd,0x7902,0x78fb,0x78fc,0x78f2,
+      0x7905,0x78f9,0x78fe,0x7904,0x79ab,0x79a8,0x7a5c,0x7a5b,0x7a56,0x7a58,
+      0x7a54,0x7a5a,0x7abe,0x7ac0,0x7ac1,0x7c05,0x7c0f,0x7bf2,0x7c00,0x7bff,
+      0x7bfb,0x7c0e,0x7bf4,0x7c0b,0x7bf3,0x7c02,0x7c09,0x7c03,0x7c01,0x7bf8,
+      0x7bfd,0x7c06,0x7bf0,0x7bf1,0x7c10,0x7c0a,0x7ce8,0x7e2d,0x7e3c,0x7e42,
+      0x7e33,0x9848,0x7e38,0x7e2a,0x7e49,0x7e40,0x7e47,0x7e29,0x7e4c,0x7e30,
+      0x7e3b,0x7e36,0x7e44,0x7e3a,0x7f45,0x7f7f,0x7f7e,0x7f7d,0x7ff4,0x7ff2,
+      0x802c,0x81bb,0x81c4,0x81cc,0x81ca,0x81c5,0x81c7,0x81bc,0x81e9,0x825b,
+      0x825a,0x825c,0x8583,0x8580,0x858f,0x85a7,0x8595,0x85a0,0x858b,0x85a3,
+      0x857b,0x85a4,0x859a,0x859e
+    }
+  },
+  {				/* ku 4e */
+    {
+      0x8577,0x857c,0x8589,0x85a1,0x857a,0x8578,0x8557,0x858e,0x8596,0x8586,
+      0x858d,0x8599,0x859d,0x8581,0x85a2,0x8582,0x8588,0x8585,0x8579,0x8576,
+      0x8598,0x8590,0x859f,0x8668,0x87be,0x87aa,0x87ad,0x87c5,0x87b0,0x87ac,
+      0x87b9,0x87b5,0x87bc,0x87ae,0x87c9,0x87c3,0x87c2,0x87cc,0x87b7,0x87af,
+      0x87c4,0x87ca,0x87b4,0x87b6,0x87bf,0x87b8,0x87bd,0x87de,0x87b2,0x8935,
+      0x8933,0x893c,0x893e,0x8941,0x8952,0x8937,0x8942,0x89ad,0x89af,0x89ae,
+      0x89f2,0x89f3,0x8b1e
+    },{
+      0x8b18,0x8b16,0x8b11,0x8b05,0x8b0b,0x8b22,0x8b0f,0x8b12,0x8b15,0x8b07,
+      0x8b0d,0x8b08,0x8b06,0x8b1c,0x8b13,0x8b1a,0x8c4f,0x8c70,0x8c72,0x8c71,
+      0x8c6f,0x8c95,0x8c94,0x8cf9,0x8d6f,0x8e4e,0x8e4d,0x8e53,0x8e50,0x8e4c,
+      0x8e47,0x8f43,0x8f40,0x9085,0x907e,0x9138,0x919a,0x91a2,0x919b,0x9199,
+      0x919f,0x91a1,0x919d,0x91a0,0x93a1,0x9383,0x93af,0x9364,0x9356,0x9347,
+      0x937c,0x9358,0x935c,0x9376,0x9349,0x9350,0x9351,0x9360,0x936d,0x938f,
+      0x934c,0x936a,0x9379,0x9357,0x9355,0x9352,0x934f,0x9371,0x9377,0x937b,
+      0x9361,0x935e,0x9363,0x9367,0x9380,0x934e,0x9359,0x95c7,0x95c0,0x95c9,
+      0x95c3,0x95c5,0x95b7,0x96ae,0x96b0,0x96ac,0x9720,0x971f,0x9718,0x971d,
+      0x9719,0x979a,0x97a1,0x979c
+    }
+  },
+  {				/* ku 4f */
+    {
+      0x979e,0x979d,0x97d5,0x97d4,0x97f1,0x9841,0x9844,0x984a,0x9849,0x9845,
+      0x9843,0x9925,0x992b,0x992c,0x992a,0x9933,0x9932,0x992f,0x992d,0x9931,
+      0x9930,0x9998,0x99a3,0x99a1,0x9a02,0x99fa,0x99f4,0x99f7,0x99f9,0x99f8,
+      0x99f6,0x99fb,0x99fd,0x99fe,0x99fc,0x9a03,0x9abe,0x9afe,0x9afd,0x9b01,
+      0x9afc,0x9b48,0x9b9a,0x9ba8,0x9b9e,0x9b9b,0x9ba6,0x9ba1,0x9ba5,0x9ba4,
+      0x9b86,0x9ba2,0x9ba0,0x9baf,0x9d33,0x9d41,0x9d67,0x9d36,0x9d2e,0x9d2f,
+      0x9d31,0x9d38,0x9d30
+    },{
+      0x9d45,0x9d42,0x9d43,0x9d3e,0x9d37,0x9d40,0x9d3d,0x7ff5,0x9d2d,0x9e8a,
+      0x9e89,0x9e8d,0x9eb0,0x9ec8,0x9eda,0x9efb,0x9eff,0x9f24,0x9f23,0x9f22,
+      0x9f54,0x9fa0,0x5131,0x512d,0x512e,0x5698,0x569c,0x5697,0x569a,0x569d,
+      0x5699,0x5970,0x5b3c,0x5c69,0x5c6a,0x5dc0,0x5e6d,0x5e6e,0x61d8,0x61df,
+      0x61ed,0x61ee,0x61f1,0x61ea,0x61f0,0x61eb,0x61d6,0x61e9,0x64ff,0x6504,
+      0x64fd,0x64f8,0x6501,0x6503,0x64fc,0x6594,0x65db,0x66da,0x66db,0x66d8,
+      0x6ac5,0x6ab9,0x6abd,0x6ae1,0x6ac6,0x6aba,0x6ab6,0x6ab7,0x6ac7,0x6ab4,
+      0x6aad,0x6b5e,0x6bc9,0x6c0b,0x7007,0x700c,0x700d,0x7001,0x7005,0x7014,
+      0x700e,0x6fff,0x7000,0x6ffb,0x7026,0x6ffc,0x6ff7,0x700a,0x7201,0x71ff,
+      0x71f9,0x7203,0x71fd,0x7376
+    }
+  },
+  {				/* ku 50 */
+    {
+      0x74b8,0x74c0,0x74b5,0x74c1,0x74be,0x74b6,0x74bb,0x74c2,0x7514,0x7513,
+      0x765c,0x7664,0x7659,0x7650,0x7653,0x7657,0x765a,0x76a6,0x76bd,0x76ec,
+      0x77c2,0x77ba,0x78ff,0x790c,0x7913,0x7914,0x7909,0x7910,0x7912,0x7911,
+      0x79ad,0x79ac,0x7a5f,0x7c1c,0x7c29,0x7c19,0x7c20,0x7c1f,0x7c2d,0x7c1d,
+      0x7c26,0x7c28,0x7c22,0x7c25,0x7c30,0x7e5c,0x7e50,0x7e56,0x7e63,0x7e58,
+      0x7e62,0x7e5f,0x7e51,0x7e60,0x7e57,0x7e53,0x7fb5,0x7fb3,0x7ff7,0x7ff8,
+      0x8075,0x81d1,0x81d2
+    },{
+      0x81d0,0x825f,0x825e,0x85b4,0x85c6,0x85c0,0x85c3,0x85c2,0x85b3,0x85b5,
+      0x85bd,0x85c7,0x85c4,0x85bf,0x85cb,0x85ce,0x85c8,0x85c5,0x85b1,0x85b6,
+      0x85d2,0x8624,0x85b8,0x85b7,0x85be,0x8669,0x87e7,0x87e6,0x87e2,0x87db,
+      0x87eb,0x87ea,0x87e5,0x87df,0x87f3,0x87e4,0x87d4,0x87dc,0x87d3,0x87ed,
+      0x87d8,0x87e3,0x87a4,0x87d7,0x87d9,0x8801,0x87f4,0x87e8,0x87dd,0x8953,
+      0x894b,0x894f,0x894c,0x8946,0x8950,0x8951,0x8949,0x8b2a,0x8b27,0x8b23,
+      0x8b33,0x8b30,0x8b35,0x8b47,0x8b2f,0x8b3c,0x8b3e,0x8b31,0x8b25,0x8b37,
+      0x8b26,0x8b36,0x8b2e,0x8b24,0x8b3b,0x8b3d,0x8b3a,0x8c42,0x8c75,0x8c99,
+      0x8c98,0x8c97,0x8cfe,0x8d04,0x8d02,0x8d00,0x8e5c,0x8e62,0x8e60,0x8e57,
+      0x8e56,0x8e5e,0x8e65,0x8e67
+    }
+  },
+  {				/* ku 51 */
+    {
+      0x8e5b,0x8e5a,0x8e61,0x8e5d,0x8e69,0x8e54,0x8f46,0x8f47,0x8f48,0x8f4b,
+      0x9128,0x913a,0x913b,0x913e,0x91a8,0x91a5,0x91a7,0x91af,0x91aa,0x93b5,
+      0x938c,0x9392,0x93b7,0x939b,0x939d,0x9389,0x93a7,0x938e,0x93aa,0x939e,
+      0x93a6,0x9395,0x9388,0x9399,0x939f,0x938d,0x93b1,0x9391,0x93b2,0x93a4,
+      0x93a8,0x93b4,0x93a3,0x93a5,0x95d2,0x95d3,0x95d1,0x96b3,0x96d7,0x96da,
+      0x5dc2,0x96df,0x96d8,0x96dd,0x9723,0x9722,0x9725,0x97ac,0x97ae,0x97a8,
+      0x97ab,0x97a4,0x97aa
+    },{
+      0x97a2,0x97a5,0x97d7,0x97d9,0x97d6,0x97d8,0x97fa,0x9850,0x9851,0x9852,
+      0x98b8,0x9941,0x993c,0x993a,0x9a0f,0x9a0b,0x9a09,0x9a0d,0x9a04,0x9a11,
+      0x9a0a,0x9a05,0x9a07,0x9a06,0x9ac0,0x9adc,0x9b08,0x9b04,0x9b05,0x9b29,
+      0x9b35,0x9b4a,0x9b4c,0x9b4b,0x9bc7,0x9bc6,0x9bc3,0x9bbf,0x9bc1,0x9bb5,
+      0x9bb8,0x9bd3,0x9bb6,0x9bc4,0x9bb9,0x9bbd,0x9d5c,0x9d53,0x9d4f,0x9d4a,
+      0x9d5b,0x9d4b,0x9d59,0x9d56,0x9d4c,0x9d57,0x9d52,0x9d54,0x9d5f,0x9d58,
+      0x9d5a,0x9e8e,0x9e8c,0x9edf,0x9f01,0x9f00,0x9f16,0x9f25,0x9f2b,0x9f2a,
+      0x9f29,0x9f28,0x9f4c,0x9f55,0x5134,0x5135,0x5296,0x52f7,0x53b4,0x56ab,
+      0x56ad,0x56a6,0x56a7,0x56aa,0x56ac,0x58da,0x58dd,0x58db,0x5912,0x5b3d,
+      0x5b3e,0x5b3f,0x5dc3,0x5e70
+    }
+  },
+  {				/* ku 52 */
+    {
+      0x5fbf,0x61fb,0x6507,0x6510,0x650d,0x6509,0x650c,0x650e,0x6584,0x65de,
+      0x65dd,0x66de,0x6ae7,0x6ae0,0x6acc,0x6ad1,0x6ad9,0x6acb,0x6adf,0x6adc,
+      0x6ad0,0x6aeb,0x6acf,0x6acd,0x6ade,0x6b60,0x6bb0,0x6c0c,0x7019,0x7027,
+      0x7020,0x7016,0x702b,0x7021,0x7022,0x7023,0x7029,0x7017,0x7024,0x701c,
+      0x702a,0x720c,0x720a,0x7207,0x7202,0x7205,0x72a5,0x72a6,0x72a4,0x72a3,
+      0x72a1,0x74cb,0x74c5,0x74b7,0x74c3,0x7516,0x7660,0x77c9,0x77ca,0x77c4,
+      0x77f1,0x791d,0x791b
+    },{
+      0x7921,0x791c,0x7917,0x791e,0x79b0,0x7a67,0x7a68,0x7c33,0x7c3c,0x7c39,
+      0x7c2c,0x7c3b,0x7cec,0x7cea,0x7e76,0x7e75,0x7e78,0x7e70,0x7e77,0x7e6f,
+      0x7e7a,0x7e72,0x7e74,0x7e68,0x7f4b,0x7f4a,0x7f83,0x7f86,0x7fb7,0x7ffd,
+      0x7ffe,0x8078,0x81d7,0x81d5,0x8264,0x8261,0x8263,0x85eb,0x85f1,0x85ed,
+      0x85d9,0x85e1,0x85e8,0x85da,0x85d7,0x85ec,0x85f2,0x85f8,0x85d8,0x85df,
+      0x85e3,0x85dc,0x85d1,0x85f0,0x85e6,0x85ef,0x85de,0x85e2,0x8800,0x87fa,
+      0x8803,0x87f6,0x87f7,0x8809,0x880c,0x880b,0x8806,0x87fc,0x8808,0x87ff,
+      0x880a,0x8802,0x8962,0x895a,0x895b,0x8957,0x8961,0x895c,0x8958,0x895d,
+      0x8959,0x8988,0x89b7,0x89b6,0x89f6,0x8b50,0x8b48,0x8b4a,0x8b40,0x8b53,
+      0x8b56,0x8b54,0x8b4b,0x8b55
+    }
+  },
+  {				/* ku 53 */
+    {
+      0x8b51,0x8b42,0x8b52,0x8b57,0x8c43,0x8c77,0x8c76,0x8c9a,0x8d06,0x8d07,
+      0x8d09,0x8dac,0x8daa,0x8dad,0x8dab,0x8e6d,0x8e78,0x8e73,0x8e6a,0x8e6f,
+      0x8e7b,0x8ec2,0x8f52,0x8f51,0x8f4f,0x8f50,0x8f53,0x8fb4,0x9140,0x913f,
+      0x91b0,0x91ad,0x93de,0x93c7,0x93cf,0x93c2,0x93da,0x93d0,0x93f9,0x93ec,
+      0x93cc,0x93d9,0x93a9,0x93e6,0x93ca,0x93d4,0x93ee,0x93e3,0x93d5,0x93c4,
+      0x93ce,0x93c0,0x93d2,0x93e7,0x957d,0x95da,0x95db,0x96e1,0x9729,0x972b,
+      0x972c,0x9728,0x9726
+    },{
+      0x97b3,0x97b7,0x97b6,0x97dd,0x97de,0x97df,0x985c,0x9859,0x985d,0x9857,
+      0x98bf,0x98bd,0x98bb,0x98be,0x9948,0x9947,0x9943,0x99a6,0x99a7,0x9a1a,
+      0x9a15,0x9a25,0x9a1d,0x9a24,0x9a1b,0x9a22,0x9a20,0x9a27,0x9a23,0x9a1e,
+      0x9a1c,0x9a14,0x9ac2,0x9b0b,0x9b0a,0x9b0e,0x9b0c,0x9b37,0x9bea,0x9beb,
+      0x9be0,0x9bde,0x9be4,0x9be6,0x9be2,0x9bf0,0x9bd4,0x9bd7,0x9bec,0x9bdc,
+      0x9bd9,0x9be5,0x9bd5,0x9be1,0x9bda,0x9d77,0x9d81,0x9d8a,0x9d84,0x9d88,
+      0x9d71,0x9d80,0x9d78,0x9d86,0x9d8b,0x9d8c,0x9d7d,0x9d6b,0x9d74,0x9d75,
+      0x9d70,0x9d69,0x9d85,0x9d73,0x9d7b,0x9d82,0x9d6f,0x9d79,0x9d7f,0x9d87,
+      0x9d68,0x9e94,0x9e91,0x9ec0,0x9efc,0x9f2d,0x9f40,0x9f41,0x9f4d,0x9f56,
+      0x9f57,0x9f58,0x5337,0x56b2
+    }
+  },
+  {				/* ku 54 */
+    {
+      0x56b5,0x56b3,0x58e3,0x5b45,0x5dc6,0x5dc7,0x5eee,0x5eef,0x5fc0,0x5fc1,
+      0x61f9,0x6517,0x6516,0x6515,0x6513,0x65df,0x66e8,0x66e3,0x66e4,0x6af3,
+      0x6af0,0x6aea,0x6ae8,0x6af9,0x6af1,0x6aee,0x6aef,0x703c,0x7035,0x702f,
+      0x7037,0x7034,0x7031,0x7042,0x7038,0x703f,0x703a,0x7039,0x7040,0x703b,
+      0x7033,0x7041,0x7213,0x7214,0x72a8,0x737d,0x737c,0x74ba,0x76ab,0x76aa,
+      0x76be,0x76ed,0x77cc,0x77ce,0x77cf,0x77cd,0x77f2,0x7925,0x7923,0x7927,
+      0x7928,0x7924,0x7929
+    },{
+      0x79b2,0x7a6e,0x7a6c,0x7a6d,0x7af7,0x7c49,0x7c48,0x7c4a,0x7c47,0x7c45,
+      0x7cee,0x7e7b,0x7e7e,0x7e81,0x7e80,0x7fba,0x7fff,0x8079,0x81db,0x81d9,
+      0x820b,0x8268,0x8269,0x8622,0x85ff,0x8601,0x85fe,0x861b,0x8600,0x85f6,
+      0x8604,0x8609,0x8605,0x860c,0x85fd,0x8819,0x8810,0x8811,0x8817,0x8813,
+      0x8816,0x8963,0x8966,0x89b9,0x89f7,0x8b60,0x8b6a,0x8b5d,0x8b68,0x8b63,
+      0x8b65,0x8b67,0x8b6d,0x8dae,0x8e86,0x8e88,0x8e84,0x8f59,0x8f56,0x8f57,
+      0x8f55,0x8f58,0x8f5a,0x908d,0x9143,0x9141,0x91b7,0x91b5,0x91b2,0x91b3,
+      0x940b,0x9413,0x93fb,0x9420,0x940f,0x9414,0x93fe,0x9415,0x9410,0x9428,
+      0x9419,0x940d,0x93f5,0x9400,0x93f7,0x9407,0x940e,0x9416,0x9412,0x93fa,
+      0x9409,0x93f8,0x940a,0x93ff
+    }
+  },
+  {				/* ku 55 */
+    {
+      0x93fc,0x940c,0x93f6,0x9411,0x9406,0x95de,0x95e0,0x95df,0x972e,0x972f,
+      0x97b9,0x97bb,0x97fd,0x97fe,0x9860,0x9862,0x9863,0x985f,0x98c1,0x98c2,
+      0x9950,0x994e,0x9959,0x994c,0x994b,0x9953,0x9a32,0x9a34,0x9a31,0x9a2c,
+      0x9a2a,0x9a36,0x9a29,0x9a2e,0x9a38,0x9a2d,0x9ac7,0x9aca,0x9ac6,0x9b10,
+      0x9b12,0x9b11,0x9c0b,0x9c08,0x9bf7,0x9c05,0x9c12,0x9bf8,0x9c40,0x9c07,
+      0x9c0e,0x9c06,0x9c17,0x9c14,0x9c09,0x9d9f,0x9d99,0x9da4,0x9d9d,0x9d92,
+      0x9d98,0x9d90,0x9d9b
+    },{
+      0x9da0,0x9d94,0x9d9c,0x9daa,0x9d97,0x9da1,0x9d9a,0x9da2,0x9da8,0x9d9e,
+      0x9da3,0x9dbf,0x9da9,0x9d96,0x9da6,0x9da7,0x9e99,0x9e9b,0x9e9a,0x9ee5,
+      0x9ee4,0x9ee7,0x9ee6,0x9f30,0x9f2e,0x9f5b,0x9f60,0x9f5e,0x9f5d,0x9f59,
+      0x9f91,0x513a,0x5139,0x5298,0x5297,0x56c3,0x56bd,0x56be,0x5b48,0x5b47,
+      0x5dcb,0x5dcf,0x5ef1,0x61fd,0x651b,0x6b02,0x6afc,0x6b03,0x6af8,0x6b00,
+      0x7043,0x7044,0x704a,0x7048,0x7049,0x7045,0x7046,0x721d,0x721a,0x7219,
+      0x737e,0x7517,0x766a,0x77d0,0x792d,0x7931,0x792f,0x7c54,0x7c53,0x7cf2,
+      0x7e8a,0x7e87,0x7e88,0x7e8b,0x7e86,0x7e8d,0x7f4d,0x7fbb,0x8030,0x81dd,
+      0x8618,0x862a,0x8626,0x861f,0x8623,0x861c,0x8619,0x8627,0x862e,0x8621,
+      0x8620,0x8629,0x861e,0x8625
+    }
+  },
+  {				/* ku 56 */
+    {
+      0x8829,0x881d,0x881b,0x8820,0x8824,0x881c,0x882b,0x884a,0x896d,0x8969,
+      0x896e,0x896b,0x89fa,0x8b79,0x8b78,0x8b45,0x8b7a,0x8b7b,0x8d10,0x8d14,
+      0x8daf,0x8e8e,0x8e8c,0x8f5e,0x8f5b,0x8f5d,0x9146,0x9144,0x9145,0x91b9,
+      0x943f,0x943b,0x9436,0x9429,0x943d,0x943c,0x9430,0x9439,0x942a,0x9437,
+      0x942c,0x9440,0x9431,0x95e5,0x95e4,0x95e3,0x9735,0x973a,0x97bf,0x97e1,
+      0x9864,0x98c9,0x98c6,0x98c0,0x9958,0x9956,0x9a39,0x9a3d,0x9a46,0x9a44,
+      0x9a42,0x9a41,0x9a3a
+    },{
+      0x9a3f,0x9acd,0x9b15,0x9b17,0x9b18,0x9b16,0x9b3a,0x9b52,0x9c2b,0x9c1d,
+      0x9c1c,0x9c2c,0x9c23,0x9c28,0x9c29,0x9c24,0x9c21,0x9db7,0x9db6,0x9dbc,
+      0x9dc1,0x9dc7,0x9dca,0x9dcf,0x9dbe,0x9dc5,0x9dc3,0x9dbb,0x9db5,0x9dce,
+      0x9db9,0x9dba,0x9dac,0x9dc8,0x9db1,0x9dad,0x9dcc,0x9db3,0x9dcd,0x9db2,
+      0x9e7a,0x9e9c,0x9eeb,0x9eee,0x9eed,0x9f1b,0x9f18,0x9f1a,0x9f31,0x9f4e,
+      0x9f65,0x9f64,0x9f92,0x4eb9,0x56c6,0x56c5,0x56cb,0x5971,0x5b4b,0x5b4c,
+      0x5dd5,0x5dd1,0x5ef2,0x6521,0x6520,0x6526,0x6522,0x6b0b,0x6b08,0x6b09,
+      0x6c0d,0x7055,0x7056,0x7057,0x7052,0x721e,0x721f,0x72a9,0x737f,0x74d8,
+      0x74d5,0x74d9,0x74d7,0x766d,0x76ad,0x7935,0x79b4,0x7a70,0x7a71,0x7c57,
+      0x7c5c,0x7c59,0x7c5b,0x7c5a
+    }
+  },
+  {				/* ku 57 */
+    {
+      0x7cf4,0x7cf1,0x7e91,0x7f4f,0x7f87,0x81de,0x826b,0x8634,0x8635,0x8633,
+      0x862c,0x8632,0x8636,0x882c,0x8828,0x8826,0x882a,0x8825,0x8971,0x89bf,
+      0x89be,0x89fb,0x8b7e,0x8b84,0x8b82,0x8b86,0x8b85,0x8b7f,0x8d15,0x8e95,
+      0x8e94,0x8e9a,0x8e92,0x8e90,0x8e96,0x8e97,0x8f60,0x8f62,0x9147,0x944c,
+      0x9450,0x944a,0x944b,0x944f,0x9447,0x9445,0x9448,0x9449,0x9446,0x973f,
+      0x97e3,0x986a,0x9869,0x98cb,0x9954,0x995b,0x9a4e,0x9a53,0x9a54,0x9a4c,
+      0x9a4f,0x9a48,0x9a4a
+    },{
+      0x9a49,0x9a52,0x9a50,0x9ad0,0x9b19,0x9b2b,0x9b3b,0x9b56,0x9b55,0x9c46,
+      0x9c48,0x9c3f,0x9c44,0x9c39,0x9c33,0x9c41,0x9c3c,0x9c37,0x9c34,0x9c32,
+      0x9c3d,0x9c36,0x9ddb,0x9dd2,0x9dde,0x9dda,0x9dcb,0x9dd0,0x9ddc,0x9dd1,
+      0x9ddf,0x9de9,0x9dd9,0x9dd8,0x9dd6,0x9df5,0x9dd5,0x9ddd,0x9eb6,0x9ef0,
+      0x9f35,0x9f33,0x9f32,0x9f42,0x9f6b,0x9f95,0x9fa2,0x513d,0x5299,0x58e8,
+      0x58e7,0x5972,0x5b4d,0x5dd8,0x882f,0x5f4f,0x6201,0x6203,0x6204,0x6529,
+      0x6525,0x6596,0x66eb,0x6b11,0x6b12,0x6b0f,0x6bca,0x705b,0x705a,0x7222,
+      0x7382,0x7381,0x7383,0x7670,0x77d4,0x7c67,0x7c66,0x7e95,0x826c,0x863a,
+      0x8640,0x8639,0x863c,0x8631,0x863b,0x863e,0x8830,0x8832,0x882e,0x8833,
+      0x8976,0x8974,0x8973,0x89fe
+    }
+  },
+  {				/* ku 58 */
+    {
+      0x8b8c,0x8b8e,0x8b8b,0x8b88,0x8c45,0x8d19,0x8e98,0x8f64,0x8f63,0x91bc,
+      0x9462,0x9455,0x945d,0x9457,0x945e,0x97c4,0x97c5,0x9800,0x9a56,0x9a59,
+      0x9b1e,0x9b1f,0x9b20,0x9c52,0x9c58,0x9c50,0x9c4a,0x9c4d,0x9c4b,0x9c55,
+      0x9c59,0x9c4c,0x9c4e,0x9dfb,0x9df7,0x9def,0x9de3,0x9deb,0x9df8,0x9de4,
+      0x9df6,0x9de1,0x9dee,0x9de6,0x9df2,0x9df0,0x9de2,0x9dec,0x9df4,0x9df3,
+      0x9de8,0x9ded,0x9ec2,0x9ed0,0x9ef2,0x9ef3,0x9f06,0x9f1c,0x9f38,0x9f37,
+      0x9f36,0x9f43,0x9f4f
+    },{
+      0x9f71,0x9f70,0x9f6e,0x9f6f,0x56d3,0x56cd,0x5b4e,0x5c6d,0x652d,0x66ed,
+      0x66ee,0x6b13,0x705f,0x7061,0x705d,0x7060,0x7223,0x74db,0x74e5,0x77d5,
+      0x7938,0x79b7,0x79b6,0x7c6a,0x7e97,0x7f89,0x826d,0x8643,0x8838,0x8837,
+      0x8835,0x884b,0x8b94,0x8b95,0x8e9e,0x8e9f,0x8ea0,0x8e9d,0x91be,0x91bd,
+      0x91c2,0x946b,0x9468,0x9469,0x96e5,0x9746,0x9743,0x9747,0x97c7,0x97e5,
+      0x9a5e,0x9ad5,0x9b59,0x9c63,0x9c67,0x9c66,0x9c62,0x9c5e,0x9c60,0x9e02,
+      0x9dfe,0x9e07,0x9e03,0x9e06,0x9e05,0x9e00,0x9e01,0x9e09,0x9dff,0x9dfd,
+      0x9e04,0x9ea0,0x9f1e,0x9f46,0x9f74,0x9f75,0x9f76,0x56d4,0x652e,0x65b8,
+      0x6b18,0x6b19,0x6b17,0x6b1a,0x7062,0x7226,0x72aa,0x77d8,0x77d9,0x7939,
+      0x7c69,0x7c6b,0x7cf6,0x7e9a
+    }
+  },
+  {				/* ku 59 */
+    {
+      0x7e98,0x7e9b,0x7e99,0x81e0,0x81e1,0x8646,0x8647,0x8648,0x8979,0x897a,
+      0x897c,0x897b,0x89ff,0x8b98,0x8b99,0x8ea5,0x8ea4,0x8ea3,0x946e,0x946d,
+      0x946f,0x9471,0x9473,0x9749,0x9872,0x995f,0x9c68,0x9c6e,0x9c6d,0x9e0b,
+      0x9e0d,0x9e10,0x9e0f,0x9e12,0x9e11,0x9ea1,0x9ef5,0x9f09,0x9f47,0x9f78,
+      0x9f7b,0x9f7a,0x9f79,0x571e,0x7066,0x7c6f,0x883c,0x8db2,0x8ea6,0x91c3,
+      0x9474,0x9478,0x9476,0x9475,0x9a60,0x9c74,0x9c73,0x9c71,0x9c75,0x9e14,
+      0x9e13,0x9ef6,0x9f0a
+    },{
+      0x9fa4,0x7068,0x7065,0x7cf7,0x866a,0x883e,0x883d,0x883f,0x8b9e,0x8c9c,
+      0x8ea9,0x8ec9,0x974b,0x9873,0x9874,0x98cc,0x9961,0x99ab,0x9a64,0x9a66,
+      0x9a67,0x9b24,0x9e15,0x9e17,0x9f48,0x6207,0x6b1e,0x7227,0x864c,0x8ea8,
+      0x9482,0x9480,0x9481,0x9a69,0x9a68,0x9b2e,0x9e19,0x7229,0x864b,0x8b9f,
+      0x9483,0x9c79,0x9eb7,0x7675,0x9a6b,0x9c7a,0x9e1d,0x7069,0x706a,0x9ea4,
+      0x9f7e,0x9f49,0x9f98,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+      UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+      UBOGON,UBOGON,UBOGON,UBOGON
+    }
+  }
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/charset/cns11643.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,8590 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	CSN 11643 conversion table
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	3 July 1997
+ * Last Edited:	30 August 2006
+ */
+
+/* CNS 11643 is the national standard of the Republic of China (Taiwan).
+ * Thanks to Emily Hsu of the ROC's Institute for Information Industry for
+ * this data.
+ *
+ * Note: It is assumed that CJK Unified Ideographs Extension A are encoded
+ * in the BMP at U+3400 to U+4DB5.
+ */
+
+#define CNS_EXTENDED 1		/* include extended planes 3-15 */
+#define CNS_OBSOLETE 0		/* include obsolete plane 14 */
+#define CNS_EXTENSION 0		/* include extension plane 15 */
+
+#define BASE_CNS11643_KU 0x21
+#define BASE_CNS11643_TEN 0x21
+#define MAX_CNS11643_KU_1 93
+#define MAX_CNS11643_KU_2 82
+#if CNS_EXTENDED
+#define MAX_CNS11643_KU_3 71
+#define MAX_CNS11643_KU_4 78
+#define MAX_CNS11643_KU_5 92
+#define MAX_CNS11643_KU_6 68
+#define MAX_CNS11643_KU_7 69
+#if CNS_OBSOLETE
+#define MAX_CNS11643_KU_14 71
+#endif
+#if CNS_EXTENSION
+#define MAX_CNS11643_KU_15 77
+#endif
+#endif
+#define MAX_CNS11643_TEN 94
+
+
+#define CNS1TOUNICODE(c,c1,ku,ten)					\
+  ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_1) &&	\
+    ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ?	\
+   cns11643_1tab[ku][ten] : UBOGON)
+
+
+#define CNS2TOUNICODE(c,c1,ku,ten)					\
+  ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_2) &&	\
+    ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ?	\
+   cns11643_2tab[ku][ten] : UBOGON)
+
+
+#if CNS_EXTENDED
+#define CNS3TOUNICODE(c,c1,ku,ten)					\
+  ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_3) &&	\
+    ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ?	\
+   cns11643_3tab[ku][ten] : UBOGON)
+
+
+#define CNS4TOUNICODE(c,c1,ku,ten)					\
+  ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_4) &&	\
+    ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ?	\
+   cns11643_4tab[ku][ten] : UBOGON)
+
+
+#define CNS5TOUNICODE(c,c1,ku,ten)					\
+  ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_5) &&	\
+    ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ?	\
+   cns11643_5tab[ku][ten] : UBOGON)
+
+
+#define CNS6TOUNICODE(c,c1,ku,ten)					\
+  ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_6) &&	\
+    ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ?	\
+   cns11643_6tab[ku][ten] : UBOGON)
+
+
+#define CNS7TOUNICODE(c,c1,ku,ten)					\
+  ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_7) &&	\
+    ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ?	\
+   cns11643_7tab[ku][ten] : UBOGON)
+
+
+#if CNS_OBSOLETE
+#define CNS14TOUNICODE(c,c1,ku,ten)					\
+  ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_14) &&	\
+    ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ?	\
+   cns11643_14tab[ku][ten] : UBOGON)
+#endif
+
+
+#if CNS_EXTENSION
+#define CNS15TOUNICODE(c,c1,ku,ten)					\
+  ((((ku = (c & 0x7f) - BASE_CNS11643_KU) < MAX_CNS11643_KU_15) &&	\
+    ((ten = (c1 & 0x7f) - BASE_CNS11643_TEN) < MAX_CNS11643_TEN)) ?	\
+   cns11643_15tab[ku][ten] : UBOGON)
+#endif
+#endif
+
+/* CNS 11643 plane 1 conversion table */
+
+static const unsigned short
+  cns11643_1tab[MAX_CNS11643_KU_1][MAX_CNS11643_TEN] = {
+  {				/* ku 01 */
+    0x3000,0xff0c,0x3001,0x3002,0xff0e,0x30fb,0xff1b,0xff1a,0xff1f,0xff01,
+    0xfe30,0x2026,0x2025,0xfe50,0xfe51,0xfe52,0x00b7,0xfe54,0xfe55,0xfe56,
+    0xfe57,0xfe31,0x2014,0xfe32,0x2013,UBOGON,UBOGON,UBOGON,UBOGON,0xff08,
+    0xff09,0xfe35,0xfe36,0xff5b,0xff5d,0xfe37,0xfe38,0x3014,0x3015,0xfe39,
+    0xfe3a,0x3010,0x3011,0xfe3b,0xfe3c,0x300a,0x300b,0xfe3d,0xfe3e,0x3008,
+    0x3009,0xfe3f,0xfe40,0x300c,0x300d,0xfe41,0xfe42,0x300e,0x300f,0xfe43,
+    0xfe44,0xfe59,0xfe5a,0xfe5b,0xfe5c,0xfe5d,0xfe5e,0x2018,0x2019,0x201c,
+    0x201d,0x301d,0x301e,0x2032,0x2035,0xff03,0xff06,0xff0a,0x203b,0x00a7,
+    0x3003,0x25cb,0x25cf,0x25b3,0x25b2,0x25ce,0x2606,0x2605,0x25c7,0x25c6,
+    0x25a1,0x25a0,0x25bd,0x25bc
+  },
+  {				/* ku 02 */
+    0x32a3,0x2105,0x203e,UBOGON,0xff3f,UBOGON,0xfe49,0xfe4a,0xfe4d,0xfe4e,
+    0xfe4b,0xfe4c,0xfe5f,0xfe60,0xfe61,0xff0b,0xff0d,0x00d7,0x00f7,0x00b1,
+    0x221a,0xff1c,0xff1e,0xff1d,0x2266,0x2267,0x2260,0x221e,0x2252,0x2261,
+    0xfe62,0xfe63,0xfe64,0xfe66,0xfe65,0x223c,0x2229,0x222a,0x22a5,0x2220,
+    0x221f,0x22bf,0x33d2,0x33d1,0x222b,0x222e,0x2235,0x2234,0x2640,0x2642,
+    0x2641,0x2609,0x2191,0x2193,0x2192,0x2190,0x2196,0x2197,0x2199,0x2198,
+    0x2016,0xff5c,0xff0f,0xff3c,0x2215,0xfe68,0xff04,0xffe5,0x3012,0xffe0,
+    0xffe1,0xff05,0xff20,0x2103,0x2109,0xfe69,0xfe6a,0xfe6b,0x33d5,0x339c,
+    0x339d,0x339e,0x33ce,0x33a1,0x338e,0x338f,0x33c4,0x00b0,0x5159,0x515b,
+    0x515e,0x515d,0x5161,0x5163
+  },
+  {				/* ku 03 */
+    0x55e7,0x74e9,0x7cce,0x2581,0x2582,0x2583,0x2584,0x2585,0x2586,0x2587,
+    0x2588,0x258f,0x258e,0x258d,0x258c,0x258b,0x258a,0x2589,0x253c,0x2534,
+    0x252c,0x2524,0x251c,0x2594,0x2500,0x2502,0x2595,0x250c,0x2510,0x2514,
+    0x2518,0x256d,0x256e,0x2570,0x256f,0x2550,0x255e,0x256a,0x2561,0x25e2,
+    0x25e3,0x25e5,0x25e4,0x2571,0x2572,0x2573,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 04 */
+    0xff10,0xff11,0xff12,0xff13,0xff14,0xff15,0xff16,0xff17,0xff18,0xff19,
+    0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,0x2169,
+    0x3021,0x3022,0x3023,0x3024,0x3025,0x3026,0x3027,0x3028,0x3029,UBOGON,
+    0x5344,UBOGON,0xff21,0xff22,0xff23,0xff24,0xff25,0xff26,0xff27,0xff28,
+    0xff29,0xff2a,0xff2b,0xff2c,0xff2d,0xff2e,0xff2f,0xff30,0xff31,0xff32,
+    0xff33,0xff34,0xff35,0xff36,0xff37,0xff38,0xff39,0xff3a,0xff41,0xff42,
+    0xff43,0xff44,0xff45,0xff46,0xff47,0xff48,0xff49,0xff4a,0xff4b,0xff4c,
+    0xff4d,0xff4e,0xff4f,0xff50,0xff51,0xff52,0xff53,0xff54,0xff55,0xff56,
+    0xff57,0xff58,0xff59,0xff5a,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,
+    0x0397,0x0398,0x0399,0x039a
+  },
+  {				/* ku 05 */
+    0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0,0x03a1,0x03a3,0x03a4,0x03a5,
+    0x03a6,0x03a7,0x03a8,0x03a9,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,
+    0x03b7,0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,0x03c0,
+    0x03c1,0x03c3,0x03c4,0x03c5,0x03c6,0x03c7,0x03c8,0x03c9,0x3105,0x3106,
+    0x3107,0x3108,0x3109,0x310a,0x310b,0x310c,0x310d,0x310e,0x310f,0x3110,
+    0x3111,0x3112,0x3113,0x3114,0x3115,0x3116,0x3117,0x3118,0x3119,0x311a,
+    0x311b,0x311c,0x311d,0x311e,0x311f,0x3120,0x3121,0x3122,0x3123,0x3124,
+    0x3125,0x3126,0x3127,0x3128,0x3129,0x02d9,0x02c9,0x02ca,0x02c7,0x02cb,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 06 */
+    0x2460,0x2461,0x2462,0x2463,0x2464,0x2465,0x2466,0x2467,0x2468,0x2469,
+    0x2474,0x2475,0x2476,0x2477,0x2478,0x2479,0x247a,0x247b,0x247c,0x247d,
+    0x2170,0x2171,0x2172,0x2173,0x2174,0x2175,0x2176,0x2177,0x2178,0x2179,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 07 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4ea0,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x51ab,UBOGON,UBOGON,UBOGON,UBOGON,0x52f9,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 08 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 09 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0a */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0b */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0d */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0e */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0f */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 10 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 11 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 12 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 13 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 14 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 15 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 16 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 17 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 18 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 19 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1a */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1b */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1d */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1e */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1f */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 20 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 21 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 22 */
+    0x2400,0x2401,0x2402,0x2403,0x2404,0x2405,0x2406,0x2407,0x2408,0x2409,
+    0x240a,0x240b,0x240c,0x240d,0x240e,0x240f,0x2410,0x2411,0x2412,0x2413,
+    0x2414,0x2415,0x2416,0x2417,0x2418,0x2419,0x241a,0x241b,0x241c,0x241d,
+    0x241e,0x241f,0x2421,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 23 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 24 */
+    0x4e00,0x4e59,0x4e01,0x4e03,0x4e43,0x4e5d,0x4e86,0x4e8c,0x4eba,0x513f,
+    0x5165,0x516b,0x51e0,0x5200,0x5201,0x529b,0x5315,0x5341,0x535c,0x53c8,
+    0x4e09,0x4e0b,0x4e08,0x4e0a,0x4e2b,0x4e38,0x51e1,0x4e45,0x4e48,0x4e5f,
+    0x4e5e,0x4e8e,0x4ea1,0x5140,0x5203,0x52fa,0x5343,0x53c9,0x53e3,0x571f,
+    0x58eb,0x5915,0x5927,0x5973,0x5b50,0x5b51,0x5b53,0x5bf8,0x5c0f,0x5c22,
+    0x5c38,0x5c71,0x5ddd,0x5de5,0x5df1,0x5df2,0x5df3,0x5dfe,0x5e72,0x5efe,
+    0x5f0b,0x5f13,0x624d,0x4e11,0x4e10,0x4e0d,0x4e2d,0x4e30,0x4e39,0x4e4b,
+    0x5c39,0x4e88,0x4e91,0x4e95,0x4e92,0x4e94,0x4ea2,0x4ec1,0x4ec0,0x4ec3,
+    0x4ec6,0x4ec7,0x4ecd,0x4eca,0x4ecb,0x4ec4,0x5143,0x5141,0x5167,0x516d,
+    0x516e,0x516c,0x5197,0x51f6
+  },
+  {				/* ku 25 */
+    0x5206,0x5207,0x5208,0x52fb,0x52fe,0x52ff,0x5316,0x5339,0x5348,0x5347,
+    0x5345,0x535e,0x5384,0x53cb,0x53ca,0x53cd,0x58ec,0x5929,0x592b,0x592a,
+    0x592d,0x5b54,0x5c11,0x5c24,0x5c3a,0x5c6f,0x5df4,0x5e7b,0x5eff,0x5f14,
+    0x5f15,0x5fc3,0x6208,0x6236,0x624b,0x624e,0x652f,0x6587,0x6597,0x65a4,
+    0x65b9,0x65e5,0x66f0,0x6708,0x6728,0x6b20,0x6b62,0x6b79,0x6bcb,0x6bd4,
+    0x6bdb,0x6c0f,0x6c34,0x706b,0x722a,0x7236,0x723b,0x7247,0x7259,0x725b,
+    0x72ac,0x738b,0x4e19,0x4e16,0x4e15,0x4e14,0x4e18,0x4e3b,0x4e4d,0x4e4f,
+    0x4e4e,0x4ee5,0x4ed8,0x4ed4,0x4ed5,0x4ed6,0x4ed7,0x4ee3,0x4ee4,0x4ed9,
+    0x4ede,0x5145,0x5144,0x5189,0x518a,0x51ac,0x51f9,0x51fa,0x51f8,0x520a,
+    0x52a0,0x529f,0x5305,0x5306
+  },
+  {				/* ku 26 */
+    0x5317,0x531d,0x4edf,0x534a,0x5349,0x5361,0x5360,0x536f,0x536e,0x53bb,
+    0x53ef,0x53e4,0x53f3,0x53ec,0x53ee,0x53e9,0x53e8,0x53fc,0x53f8,0x53f5,
+    0x53eb,0x53e6,0x53ea,0x53f2,0x53f1,0x53f0,0x53e5,0x53ed,0x53fb,0x56db,
+    0x56da,0x5916,0x592e,0x5931,0x5974,0x5976,0x5b55,0x5b83,0x5c3c,0x5de8,
+    0x5de7,0x5de6,0x5e02,0x5e03,0x5e73,0x5e7c,0x5f01,0x5f18,0x5f17,0x5fc5,
+    0x620a,0x6253,0x6254,0x6252,0x6251,0x65a5,0x65e6,0x672e,0x672c,0x672a,
+    0x672b,0x672d,0x6b63,0x6bcd,0x6c11,0x6c10,0x6c38,0x6c41,0x6c40,0x6c3e,
+    0x72af,0x7384,0x7389,0x74dc,0x74e6,0x7518,0x751f,0x7528,0x7529,0x7530,
+    0x7531,0x7532,0x7533,0x758b,0x767d,0x76ae,0x76bf,0x76ee,0x77db,0x77e2,
+    0x77f3,0x793a,0x79be,0x7a74
+  },
+  {				/* ku 27 */
+    0x7acb,0x4e1e,0x4e1f,0x4e52,0x4e53,0x4e69,0x4e99,0x4ea4,0x4ea6,0x4ea5,
+    0x4eff,0x4f09,0x4f19,0x4f0a,0x4f15,0x4f0d,0x4f10,0x4f11,0x4f0f,0x4ef2,
+    0x4ef6,0x4efb,0x4ef0,0x4ef3,0x4efd,0x4f01,0x4f0b,0x5149,0x5147,0x5146,
+    0x5148,0x5168,0x5171,0x518d,0x51b0,0x5217,0x5211,0x5212,0x520e,0x5216,
+    0x52a3,0x5308,0x5321,0x5320,0x5370,0x5371,0x5409,0x540f,0x540c,0x540a,
+    0x5410,0x5401,0x540b,0x5404,0x5411,0x540d,0x5408,0x5403,0x540e,0x5406,
+    0x5412,0x56e0,0x56de,0x56dd,0x5733,0x5730,0x5728,0x572d,0x572c,0x572f,
+    0x5729,0x5919,0x591a,0x5937,0x5938,0x5984,0x5978,0x5983,0x597d,0x5979,
+    0x5982,0x5981,0x5b57,0x5b58,0x5b87,0x5b88,0x5b85,0x5b89,0x5bfa,0x5c16,
+    0x5c79,0x5dde,0x5e06,0x5e76
+  },
+  {				/* ku 28 */
+    0x5e74,0x5f0f,0x5f1b,0x5fd9,0x5fd6,0x620e,0x620c,0x620d,0x6210,0x6263,
+    0x625b,0x6258,0x6536,0x65e9,0x65e8,0x65ec,0x65ed,0x66f2,0x66f3,0x6709,
+    0x673d,0x6734,0x6731,0x6735,0x6b21,0x6b64,0x6b7b,0x6c16,0x6c5d,0x6c57,
+    0x6c59,0x6c5f,0x6c60,0x6c50,0x6c55,0x6c61,0x6c5b,0x6c4d,0x6c4e,0x7070,
+    0x725f,0x725d,0x767e,0x7af9,0x7c73,0x7cf8,0x7f36,0x7f8a,0x7fbd,0x8001,
+    0x8003,0x800c,0x8012,0x8033,0x807f,0x8089,0x808b,0x808c,0x81e3,0x81ea,
+    0x81f3,0x81fc,0x820c,0x821b,0x821f,0x826e,0x8272,0x827e,0x866b,0x8840,
+    0x884c,0x8863,0x897f,0x9621,0x4e32,0x4ea8,0x4f4d,0x4f4f,0x4f47,0x4f57,
+    0x4f5e,0x4f34,0x4f5b,0x4f55,0x4f30,0x4f50,0x4f51,0x4f3d,0x4f3a,0x4f38,
+    0x4f43,0x4f54,0x4f3c,0x4f46
+  },
+  {				/* ku 29 */
+    0x4f63,0x4f5c,0x4f60,0x4f2f,0x4f4e,0x4f36,0x4f59,0x4f5d,0x4f48,0x4f5a,
+    0x514c,0x514b,0x514d,0x5175,0x51b6,0x51b7,0x5225,0x5224,0x5229,0x522a,
+    0x5228,0x52ab,0x52a9,0x52aa,0x52ac,0x5323,0x5373,0x5375,0x541d,0x542d,
+    0x541e,0x543e,0x5426,0x544e,0x5427,0x5446,0x5443,0x5433,0x5448,0x5442,
+    0x541b,0x5429,0x544a,0x5439,0x543b,0x5438,0x542e,0x5435,0x5436,0x5420,
+    0x543c,0x5440,0x5431,0x542b,0x541f,0x542c,0x56ea,0x56f0,0x56e4,0x56eb,
+    0x574a,0x5751,0x5740,0x574d,0x5747,0x574e,0x573e,0x5750,0x574f,0x573b,
+    0x58ef,0x593e,0x599d,0x5992,0x59a8,0x599e,0x59a3,0x5999,0x5996,0x598d,
+    0x59a4,0x5993,0x598a,0x59a5,0x5b5d,0x5b5c,0x5b5a,0x5b5b,0x5b8c,0x5b8b,
+    0x5b8f,0x5c2c,0x5c40,0x5c41
+  },
+  {				/* ku 2a */
+    0x5c3f,0x5c3e,0x5c90,0x5c91,0x5c94,0x5c8c,0x5deb,0x5e0c,0x5e8f,0x5e87,
+    0x5e8a,0x5ef7,0x5f04,0x5f1f,0x5f64,0x5f62,0x5f77,0x5f79,0x5fd8,0x5fcc,
+    0x5fd7,0x5fcd,0x5ff1,0x5feb,0x5ff8,0x5fea,0x6212,0x6211,0x6284,0x6297,
+    0x6296,0x6280,0x6276,0x6289,0x626d,0x628a,0x627c,0x627e,0x6279,0x6273,
+    0x6292,0x626f,0x6298,0x626e,0x6295,0x6293,0x6291,0x6286,0x6539,0x653b,
+    0x6538,0x65f1,0x66f4,0x675f,0x674e,0x674f,0x6750,0x6751,0x675c,0x6756,
+    0x675e,0x6749,0x6746,0x6760,0x6753,0x6757,0x6b65,0x6bcf,0x6c42,0x6c5e,
+    0x6c99,0x6c81,0x6c88,0x6c89,0x6c85,0x6c9b,0x6c6a,0x6c7a,0x6c90,0x6c70,
+    0x6c8c,0x6c68,0x6c96,0x6c92,0x6c7d,0x6c83,0x6c72,0x6c7e,0x6c74,0x6c86,
+    0x6c76,0x6c8d,0x6c94,0x6c98
+  },
+  {				/* ku 2b */
+    0x6c82,0x7076,0x707c,0x707d,0x7078,0x7262,0x7261,0x7260,0x72c4,0x72c2,
+    0x7396,0x752c,0x752b,0x7537,0x7538,0x7682,0x76ef,0x77e3,0x79c1,0x79c0,
+    0x79bf,0x7a76,0x7cfb,0x7f55,0x8096,0x8093,0x809d,0x8098,0x809b,0x809a,
+    0x80b2,0x826f,0x8292,0x828b,0x828d,0x898b,0x89d2,0x8a00,0x8c37,0x8c46,
+    0x8c55,0x8c9d,0x8d64,0x8d70,0x8db3,0x8eab,0x8eca,0x8f9b,0x8fb0,0x8fc2,
+    0x8fc6,0x8fc5,0x8fc4,0x5de1,0x9091,0x90a2,0x90aa,0x90a6,0x90a3,0x9149,
+    0x91c6,0x91cc,0x9632,0x962e,0x9631,0x962a,0x962c,0x4e26,0x4e56,0x4e73,
+    0x4e8b,0x4e9b,0x4e9e,0x4eab,0x4eac,0x4f6f,0x4f9d,0x4f8d,0x4f73,0x4f7f,
+    0x4f6c,0x4f9b,0x4f8b,0x4f86,0x4f83,0x4f70,0x4f75,0x4f88,0x4f69,0x4f7b,
+    0x4f96,0x4f7e,0x4f8f,0x4f91
+  },
+  {				/* ku 2c */
+    0x4f7a,0x5154,0x5152,0x5155,0x5169,0x5177,0x5176,0x5178,0x51bd,0x51fd,
+    0x523b,0x5238,0x5237,0x523a,0x5230,0x522e,0x5236,0x5241,0x52be,0x52bb,
+    0x5352,0x5354,0x5353,0x5351,0x5366,0x5377,0x5378,0x5379,0x53d6,0x53d4,
+    0x53d7,0x5473,0x5475,0x5496,0x5478,0x5495,0x5480,0x547b,0x5477,0x5484,
+    0x5492,0x5486,0x547c,0x5490,0x5471,0x5476,0x548c,0x549a,0x5462,0x5468,
+    0x548b,0x547d,0x548e,0x56fa,0x5783,0x5777,0x576a,0x5769,0x5761,0x5766,
+    0x5764,0x577c,0x591c,0x5949,0x5947,0x5948,0x5944,0x5954,0x59be,0x59bb,
+    0x59d4,0x59b9,0x59ae,0x59d1,0x59c6,0x59d0,0x59cd,0x59cb,0x59d3,0x59ca,
+    0x59af,0x59b3,0x59d2,0x59c5,0x5b5f,0x5b64,0x5b63,0x5b97,0x5b9a,0x5b98,
+    0x5b9c,0x5b99,0x5b9b,0x5c1a
+  },
+  {				/* ku 2d */
+    0x5c48,0x5c45,0x5c46,0x5cb7,0x5ca1,0x5cb8,0x5ca9,0x5cab,0x5cb1,0x5cb3,
+    0x5e18,0x5e1a,0x5e16,0x5e15,0x5e1b,0x5e11,0x5e78,0x5e9a,0x5e97,0x5e9c,
+    0x5e95,0x5e96,0x5ef6,0x5f26,0x5f27,0x5f29,0x5f80,0x5f81,0x5f7f,0x5f7c,
+    0x5fdd,0x5fe0,0x5ffd,0x5ff5,0x5fff,0x600f,0x6014,0x602f,0x6035,0x6016,
+    0x602a,0x6015,0x6021,0x6027,0x6029,0x602b,0x601b,0x6216,0x6215,0x623f,
+    0x623e,0x6240,0x627f,0x62c9,0x62cc,0x62c4,0x62bf,0x62c2,0x62b9,0x62d2,
+    0x62db,0x62ab,0x62d3,0x62d4,0x62cb,0x62c8,0x62a8,0x62bd,0x62bc,0x62d0,
+    0x62d9,0x62c7,0x62cd,0x62b5,0x62da,0x62b1,0x62d8,0x62d6,0x62d7,0x62c6,
+    0x62ac,0x62ce,0x653e,0x65a7,0x65bc,0x65fa,0x6614,0x6613,0x660c,0x6606,
+    0x6602,0x660e,0x6600,0x660f
+  },
+  {				/* ku 2e */
+    0x6615,0x660a,0x6607,0x670d,0x670b,0x676d,0x678b,0x6795,0x6771,0x679c,
+    0x6773,0x6777,0x6787,0x679d,0x6797,0x676f,0x6770,0x677f,0x6789,0x677e,
+    0x6790,0x6775,0x679a,0x6793,0x677c,0x676a,0x6772,0x6b23,0x6b66,0x6b67,
+    0x6b7f,0x6c13,0x6c1b,0x6ce3,0x6ce8,0x6cf3,0x6cb1,0x6ccc,0x6ce5,0x6cb3,
+    0x6cbd,0x6cbe,0x6cbc,0x6ce2,0x6cab,0x6cd5,0x6cd3,0x6cb8,0x6cc4,0x6cb9,
+    0x6cc1,0x6cae,0x6cd7,0x6cc5,0x6cf1,0x6cbf,0x6cbb,0x6ce1,0x6cdb,0x6cca,
+    0x6cac,0x6cef,0x6cdc,0x6cd6,0x6ce0,0x7095,0x708e,0x7092,0x708a,0x7099,
+    0x722c,0x722d,0x7238,0x7248,0x7267,0x7269,0x72c0,0x72ce,0x72d9,0x72d7,
+    0x72d0,0x73a9,0x73a8,0x739f,0x73ab,0x73a5,0x753d,0x759d,0x7599,0x759a,
+    0x7684,0x76c2,0x76f2,0x76f4
+  },
+  {				/* ku 2f */
+    0x77e5,0x77fd,0x793e,0x7940,0x7941,0x79c9,0x79c8,0x7a7a,0x7a79,0x7afa,
+    0x7cfe,0x7f54,0x7f8c,0x7f8b,0x8005,0x80ba,0x80a5,0x80a2,0x80b1,0x80a1,
+    0x80ab,0x80a9,0x80b4,0x80aa,0x80af,0x81e5,0x81fe,0x820d,0x82b3,0x829d,
+    0x8299,0x82ad,0x82bd,0x829f,0x82b9,0x82b1,0x82ac,0x82a5,0x82af,0x82b8,
+    0x82a3,0x82b0,0x82be,0x82b7,0x864e,0x8671,0x521d,0x8868,0x8ecb,0x8fce,
+    0x8fd4,0x8fd1,0x90b5,0x90b8,0x90b1,0x90b6,0x91c7,0x91d1,0x9577,0x9580,
+    0x961c,0x9640,0x963f,0x963b,0x9644,0x9642,0x96b9,0x96e8,0x9752,0x975e,
+    0x4e9f,0x4ead,0x4eae,0x4fe1,0x4fb5,0x4faf,0x4fbf,0x4fe0,0x4fd1,0x4fcf,
+    0x4fdd,0x4fc3,0x4fb6,0x4fd8,0x4fdf,0x4fca,0x4fd7,0x4fae,0x4fd0,0x4fc4,
+    0x4fc2,0x4fda,0x4fce,0x4fde
+  },
+  {				/* ku 30 */
+    0x4fb7,0x5157,0x5192,0x5191,0x51a0,0x524e,0x5243,0x524a,0x524d,0x524c,
+    0x524b,0x5247,0x52c7,0x52c9,0x52c3,0x52c1,0x530d,0x5357,0x537b,0x539a,
+    0x53db,0x54ac,0x54c0,0x54a8,0x54ce,0x54c9,0x54b8,0x54a6,0x54b3,0x54c7,
+    0x54c2,0x54bd,0x54aa,0x54c1,0x54c4,0x54c8,0x54af,0x54ab,0x54b1,0x54bb,
+    0x54a9,0x54a7,0x54bf,0x56ff,0x5782,0x578b,0x57a0,0x57a3,0x57a2,0x57ce,
+    0x57ae,0x5793,0x5955,0x5951,0x594f,0x594e,0x5950,0x59dc,0x59d8,0x59ff,
+    0x59e3,0x59e8,0x5a03,0x59e5,0x59ea,0x59da,0x59e6,0x5a01,0x59fb,0x5b69,
+    0x5ba3,0x5ba6,0x5ba4,0x5ba2,0x5ba5,0x5c01,0x5c4e,0x5c4f,0x5c4d,0x5c4b,
+    0x5cd9,0x5cd2,0x5df7,0x5e1d,0x5e25,0x5e1f,0x5e7d,0x5ea0,0x5ea6,0x5efa,
+    0x5f08,0x5f2d,0x5f65,0x5f88
+  },
+  {				/* ku 31 */
+    0x5f85,0x5f8a,0x5f8b,0x5f87,0x5f8c,0x5f89,0x6012,0x601d,0x6020,0x6025,
+    0x600e,0x6028,0x604d,0x6070,0x6068,0x6062,0x6046,0x6043,0x606c,0x606b,
+    0x606a,0x6064,0x6241,0x62dc,0x6316,0x6309,0x62fc,0x62ed,0x6301,0x62ee,
+    0x62fd,0x6307,0x62f1,0x62f7,0x62ef,0x62ec,0x62fe,0x62f4,0x6311,0x6302,
+    0x653f,0x6545,0x65ab,0x65bd,0x65e2,0x6625,0x662d,0x6620,0x6627,0x662f,
+    0x661f,0x6628,0x6631,0x6624,0x66f7,0x67ff,0x67d3,0x67f1,0x67d4,0x67d0,
+    0x67ec,0x67b6,0x67af,0x67f5,0x67e9,0x67ef,0x67c4,0x67d1,0x67b4,0x67da,
+    0x67e5,0x67b8,0x67cf,0x67de,0x67f3,0x67b0,0x67d9,0x67e2,0x67dd,0x67d2,
+    0x6b6a,0x6b83,0x6b86,0x6bb5,0x6bd2,0x6bd7,0x6c1f,0x6cc9,0x6d0b,0x6d32,
+    0x6d2a,0x6d41,0x6d25,0x6d0c
+  },
+  {				/* ku 32 */
+    0x6d31,0x6d1e,0x6d17,0x6d3b,0x6d3d,0x6d3e,0x6d36,0x6d1b,0x6cf5,0x6d39,
+    0x6d27,0x6d38,0x6d29,0x6d2e,0x6d35,0x6d0e,0x6d2b,0x70ab,0x70ba,0x70b3,
+    0x70ac,0x70af,0x70ad,0x70b8,0x70ae,0x70a4,0x7230,0x7272,0x726f,0x7274,
+    0x72e9,0x72e0,0x72e1,0x73b7,0x73ca,0x73bb,0x73b2,0x73cd,0x73c0,0x73b3,
+    0x751a,0x752d,0x754f,0x754c,0x754e,0x754b,0x75ab,0x75a4,0x75a5,0x75a2,
+    0x75a3,0x7678,0x7686,0x7687,0x7688,0x76c8,0x76c6,0x76c3,0x76c5,0x7701,
+    0x76f9,0x76f8,0x7709,0x770b,0x76fe,0x76fc,0x7707,0x77dc,0x7802,0x7814,
+    0x780c,0x780d,0x7946,0x7949,0x7948,0x7947,0x79b9,0x79ba,0x79d1,0x79d2,
+    0x79cb,0x7a7f,0x7a81,0x7aff,0x7afd,0x7c7d,0x7d02,0x7d05,0x7d00,0x7d09,
+    0x7d07,0x7d04,0x7d06,0x7f38
+  },
+  {				/* ku 33 */
+    0x7f8e,0x7fbf,0x8010,0x800d,0x8011,0x8036,0x80d6,0x80e5,0x80da,0x80c3,
+    0x80c4,0x80cc,0x80e1,0x80db,0x80ce,0x80de,0x80e4,0x80dd,0x81f4,0x8222,
+    0x82e7,0x8303,0x8305,0x82e3,0x82db,0x82e6,0x8304,0x82e5,0x8302,0x8309,
+    0x82d2,0x82d7,0x82f1,0x8301,0x82dc,0x82d4,0x82d1,0x82de,0x82d3,0x82df,
+    0x82ef,0x8306,0x8650,0x8679,0x867b,0x867a,0x884d,0x886b,0x8981,0x89d4,
+    0x8a08,0x8a02,0x8a03,0x8c9e,0x8ca0,0x8d74,0x8d73,0x8db4,0x8ecd,0x8ecc,
+    0x8ff0,0x8fe6,0x8fe2,0x8fea,0x8fe5,0x8fed,0x8feb,0x8fe4,0x8fe8,0x90ca,
+    0x90ce,0x90c1,0x90c3,0x914b,0x914a,0x91cd,0x9582,0x9650,0x964b,0x964c,
+    0x964d,0x9762,0x9769,0x97cb,0x97ed,0x97f3,0x9801,0x98a8,0x98db,0x98df,
+    0x9996,0x9999,0x4e58,0x4eb3
+  },
+  {				/* ku 34 */
+    0x500c,0x500d,0x5023,0x4fef,0x5026,0x5025,0x4ff8,0x5029,0x5016,0x5006,
+    0x503c,0x501f,0x501a,0x5012,0x5011,0x4ffa,0x5000,0x5014,0x5028,0x4ff1,
+    0x5021,0x500b,0x5019,0x5018,0x4ff3,0x4fee,0x502d,0x502a,0x4ffe,0x502b,
+    0x5009,0x517c,0x51a4,0x51a5,0x51a2,0x51cd,0x51cc,0x51c6,0x51cb,0x5256,
+    0x525c,0x5254,0x525b,0x525d,0x532a,0x537f,0x539f,0x539d,0x53df,0x54e8,
+    0x5510,0x5501,0x5537,0x54fc,0x54e5,0x54f2,0x5506,0x54fa,0x5514,0x54e9,
+    0x54ed,0x54e1,0x5509,0x54ee,0x54ea,0x54e6,0x5527,0x5507,0x54fd,0x550f,
+    0x5703,0x5704,0x57c2,0x57d4,0x57cb,0x57c3,0x5809,0x590f,0x5957,0x5958,
+    0x595a,0x5a11,0x5a18,0x5a1c,0x5a1f,0x5a1b,0x5a13,0x59ec,0x5a20,0x5a23,
+    0x5a29,0x5a25,0x5a0c,0x5a09
+  },
+  {				/* ku 35 */
+    0x5b6b,0x5c58,0x5bb0,0x5bb3,0x5bb6,0x5bb4,0x5bae,0x5bb5,0x5bb9,0x5bb8,
+    0x5c04,0x5c51,0x5c55,0x5c50,0x5ced,0x5cfd,0x5cfb,0x5cea,0x5ce8,0x5cf0,
+    0x5cf6,0x5d01,0x5cf4,0x5dee,0x5e2d,0x5e2b,0x5eab,0x5ead,0x5ea7,0x5f31,
+    0x5f92,0x5f91,0x5f90,0x6059,0x6063,0x6065,0x6050,0x6055,0x606d,0x6069,
+    0x606f,0x6084,0x609f,0x609a,0x608d,0x6094,0x608c,0x6085,0x6096,0x6247,
+    0x62f3,0x6308,0x62ff,0x634e,0x633e,0x632f,0x6355,0x6342,0x6346,0x634f,
+    0x6349,0x633a,0x6350,0x633d,0x632a,0x632b,0x6328,0x634d,0x634c,0x6548,
+    0x6549,0x6599,0x65c1,0x65c5,0x6642,0x6649,0x664f,0x6643,0x6652,0x664c,
+    0x6645,0x6641,0x66f8,0x6714,0x6715,0x6717,0x6821,0x6838,0x6848,0x6846,
+    0x6853,0x6839,0x6842,0x6854
+  },
+  {				/* ku 36 */
+    0x6829,0x68b3,0x6817,0x684c,0x6851,0x683d,0x67f4,0x6850,0x6840,0x683c,
+    0x6843,0x682a,0x6845,0x6813,0x6818,0x6841,0x6b8a,0x6b89,0x6bb7,0x6c23,
+    0x6c27,0x6c28,0x6c26,0x6c24,0x6cf0,0x6d6a,0x6d95,0x6d88,0x6d87,0x6d66,
+    0x6d78,0x6d77,0x6d59,0x6d93,0x6d6c,0x6d89,0x6d6e,0x6d5a,0x6d74,0x6d69,
+    0x6d8c,0x6d8a,0x6d79,0x6d85,0x6d65,0x6d94,0x70ca,0x70d8,0x70e4,0x70d9,
+    0x70c8,0x70cf,0x7239,0x7279,0x72fc,0x72f9,0x72fd,0x72f8,0x72f7,0x7386,
+    0x73ed,0x7409,0x73ee,0x73e0,0x73ea,0x73de,0x7554,0x755d,0x755c,0x755a,
+    0x7559,0x75be,0x75c5,0x75c7,0x75b2,0x75b3,0x75bd,0x75bc,0x75b9,0x75c2,
+    0x75b8,0x768b,0x76b0,0x76ca,0x76cd,0x76ce,0x7729,0x771f,0x7720,0x7728,
+    0x77e9,0x7830,0x7827,0x7838
+  },
+  {				/* ku 37 */
+    0x781d,0x7834,0x7837,0x7825,0x782d,0x7820,0x781f,0x7832,0x7955,0x7950,
+    0x7960,0x795f,0x7956,0x795e,0x795d,0x7957,0x795a,0x79e4,0x79e3,0x79e7,
+    0x79df,0x79e6,0x79e9,0x79d8,0x7a84,0x7a88,0x7ad9,0x7b06,0x7b11,0x7c89,
+    0x7d21,0x7d17,0x7d0b,0x7d0a,0x7d20,0x7d22,0x7d14,0x7d10,0x7d15,0x7d1a,
+    0x7d1c,0x7d0d,0x7d19,0x7d1b,0x7f3a,0x7f5f,0x7f94,0x7fc5,0x7fc1,0x8006,
+    0x8004,0x8018,0x8015,0x8019,0x8017,0x803d,0x803f,0x80f1,0x8102,0x80f0,
+    0x8105,0x80ed,0x80f4,0x8106,0x80f8,0x80f3,0x8108,0x80fd,0x810a,0x80fc,
+    0x80ef,0x81ed,0x81ec,0x8200,0x8210,0x822a,0x822b,0x8228,0x822c,0x82bb,
+    0x832b,0x8352,0x8354,0x834a,0x8338,0x8350,0x8349,0x8335,0x8334,0x834f,
+    0x8332,0x8339,0x8336,0x8317
+  },
+  {				/* ku 38 */
+    0x8340,0x8331,0x8328,0x8343,0x8654,0x868a,0x86aa,0x8693,0x86a4,0x86a9,
+    0x868c,0x86a3,0x869c,0x8870,0x8877,0x8881,0x8882,0x887d,0x8879,0x8a18,
+    0x8a10,0x8a0e,0x8a0c,0x8a15,0x8a0a,0x8a17,0x8a13,0x8a16,0x8a0f,0x8a11,
+    0x8c48,0x8c7a,0x8c79,0x8ca1,0x8ca2,0x8d77,0x8eac,0x8ed2,0x8ed4,0x8ecf,
+    0x8fb1,0x9001,0x9006,0x8ff7,0x9000,0x8ffa,0x8ff4,0x9003,0x8ffd,0x9005,
+    0x8ff8,0x9095,0x90e1,0x90dd,0x90e2,0x9152,0x914d,0x914c,0x91d8,0x91dd,
+    0x91d7,0x91dc,0x91d9,0x9583,0x9662,0x9663,0x9661,0x965b,0x965d,0x9664,
+    0x9658,0x965e,0x96bb,0x98e2,0x99ac,0x9aa8,0x9ad8,0x9b25,0x9b32,0x9b3c,
+    0x4e7e,0x507a,0x507d,0x505c,0x5047,0x5043,0x504c,0x505a,0x5049,0x5065,
+    0x5076,0x504e,0x5055,0x5075
+  },
+  {				/* ku 39 */
+    0x5074,0x5077,0x504f,0x500f,0x506f,0x506d,0x515c,0x5195,0x51f0,0x526a,
+    0x526f,0x52d2,0x52d9,0x52d8,0x52d5,0x5310,0x530f,0x5319,0x533f,0x5340,
+    0x533e,0x53c3,0x66fc,0x5546,0x556a,0x5566,0x5544,0x555e,0x5561,0x5543,
+    0x554a,0x5531,0x5556,0x554f,0x5555,0x552f,0x5564,0x5538,0x552e,0x555c,
+    0x552c,0x5563,0x5533,0x5541,0x5557,0x5708,0x570b,0x5709,0x57df,0x5805,
+    0x580a,0x5806,0x57e0,0x57e4,0x57fa,0x5802,0x5835,0x57f7,0x57f9,0x5920,
+    0x5962,0x5a36,0x5a41,0x5a49,0x5a66,0x5a6a,0x5a40,0x5a3c,0x5a62,0x5a5a,
+    0x5a46,0x5a4a,0x5b70,0x5bc7,0x5bc5,0x5bc4,0x5bc2,0x5bbf,0x5bc6,0x5c09,
+    0x5c08,0x5c07,0x5c60,0x5c5c,0x5c5d,0x5d07,0x5d06,0x5d0e,0x5d1b,0x5d16,
+    0x5d22,0x5d11,0x5d29,0x5d14
+  },
+  {				/* ku 3a */
+    0x5d19,0x5d24,0x5d27,0x5d17,0x5de2,0x5e38,0x5e36,0x5e33,0x5e37,0x5eb7,
+    0x5eb8,0x5eb6,0x5eb5,0x5ebe,0x5f35,0x5f37,0x5f57,0x5f6c,0x5f69,0x5f6b,
+    0x5f97,0x5f99,0x5f9e,0x5f98,0x5fa1,0x5fa0,0x5f9c,0x607f,0x60a3,0x6089,
+    0x60a0,0x60a8,0x60cb,0x60b4,0x60e6,0x60bd,0x60c5,0x60bb,0x60b5,0x60dc,
+    0x60bc,0x60d8,0x60d5,0x60c6,0x60df,0x60b8,0x60da,0x60c7,0x621a,0x621b,
+    0x6248,0x63a0,0x63a7,0x6372,0x6396,0x63a2,0x63a5,0x6377,0x6367,0x6398,
+    0x63aa,0x6371,0x63a9,0x6389,0x6383,0x639b,0x636b,0x63a8,0x6384,0x6388,
+    0x6399,0x63a1,0x63ac,0x6392,0x638f,0x6380,0x637b,0x6369,0x6368,0x637a,
+    0x655d,0x6556,0x6551,0x6559,0x6557,0x555f,0x654f,0x6558,0x6555,0x6554,
+    0x659c,0x659b,0x65ac,0x65cf
+  },
+  {				/* ku 3b */
+    0x65cb,0x65cc,0x65ce,0x665d,0x665a,0x6664,0x6668,0x6666,0x665e,0x66f9,
+    0x52d7,0x671b,0x6881,0x68af,0x68a2,0x6893,0x68b5,0x687f,0x6876,0x68b1,
+    0x68a7,0x6897,0x68b0,0x6883,0x68c4,0x68ad,0x6886,0x6885,0x6894,0x689d,
+    0x68a8,0x689f,0x68a1,0x6882,0x6b32,0x6bba,0x6beb,0x6bec,0x6c2b,0x6d8e,
+    0x6dbc,0x6df3,0x6dd9,0x6db2,0x6de1,0x6dcc,0x6de4,0x6dfb,0x6dfa,0x6e05,
+    0x6dc7,0x6dcb,0x6daf,0x6dd1,0x6dae,0x6dde,0x6df9,0x6db8,0x6df7,0x6df5,
+    0x6dc5,0x6dd2,0x6e1a,0x6db5,0x6dda,0x6deb,0x6dd8,0x6dea,0x6df1,0x6dee,
+    0x6de8,0x6dc6,0x6dc4,0x6daa,0x6dec,0x6dbf,0x6de6,0x70f9,0x7109,0x710a,
+    0x70fd,0x70ef,0x723d,0x727d,0x7281,0x731c,0x731b,0x7316,0x7313,0x7319,
+    0x7387,0x7405,0x740a,0x7403
+  },
+  {				/* ku 3c */
+    0x7406,0x73fe,0x740d,0x74e0,0x74f6,0x74f7,0x751c,0x7522,0x7565,0x7566,
+    0x7562,0x7570,0x758f,0x75d4,0x75d5,0x75b5,0x75ca,0x75cd,0x768e,0x76d4,
+    0x76d2,0x76db,0x7737,0x773e,0x773c,0x7736,0x7738,0x773a,0x786b,0x7843,
+    0x784e,0x7965,0x7968,0x796d,0x79fb,0x7a92,0x7a95,0x7b20,0x7b28,0x7b1b,
+    0x7b2c,0x7b26,0x7b19,0x7b1e,0x7b2e,0x7c92,0x7c97,0x7c95,0x7d46,0x7d43,
+    0x7d71,0x7d2e,0x7d39,0x7d3c,0x7d40,0x7d30,0x7d33,0x7d44,0x7d2f,0x7d42,
+    0x7d32,0x7d31,0x7f3d,0x7f9e,0x7f9a,0x7fcc,0x7fce,0x7fd2,0x801c,0x804a,
+    0x8046,0x812f,0x8116,0x8123,0x812b,0x8129,0x8130,0x8124,0x8202,0x8235,
+    0x8237,0x8236,0x8239,0x838e,0x839e,0x8398,0x8378,0x83a2,0x8396,0x83bd,
+    0x83ab,0x8392,0x838a,0x8393
+  },
+  {				/* ku 3d */
+    0x8389,0x83a0,0x8377,0x837b,0x837c,0x8386,0x83a7,0x8655,0x5f6a,0x86c7,
+    0x86c0,0x86b6,0x86c4,0x86b5,0x86c6,0x86cb,0x86b1,0x86af,0x86c9,0x8853,
+    0x889e,0x8888,0x88ab,0x8892,0x8896,0x888d,0x888b,0x8993,0x898f,0x8a2a,
+    0x8a1d,0x8a23,0x8a25,0x8a31,0x8a2d,0x8a1f,0x8a1b,0x8a22,0x8c49,0x8c5a,
+    0x8ca9,0x8cac,0x8cab,0x8ca8,0x8caa,0x8ca7,0x8d67,0x8d66,0x8dbe,0x8dba,
+    0x8edb,0x8edf,0x9019,0x900d,0x901a,0x9017,0x9023,0x901f,0x901d,0x9010,
+    0x9015,0x901e,0x9020,0x900f,0x9022,0x9016,0x901b,0x9014,0x90e8,0x90ed,
+    0x90fd,0x9157,0x91ce,0x91f5,0x91e6,0x91e3,0x91e7,0x91ed,0x91e9,0x9589,
+    0x966a,0x9675,0x9673,0x9678,0x9670,0x9674,0x9676,0x9677,0x966c,0x96c0,
+    0x96ea,0x96e9,0x7ae0,0x7adf
+  },
+  {				/* ku 3e */
+    0x9802,0x9803,0x9b5a,0x9ce5,0x9e75,0x9e7f,0x9ea5,0x9ebb,0x50a2,0x508d,
+    0x5085,0x5099,0x5091,0x5080,0x5096,0x5098,0x509a,0x6700,0x51f1,0x5272,
+    0x5274,0x5275,0x5269,0x52de,0x52dd,0x52db,0x535a,0x53a5,0x557b,0x5580,
+    0x55a7,0x557c,0x558a,0x559d,0x5598,0x5582,0x559c,0x55aa,0x5594,0x5587,
+    0x558b,0x5583,0x55b3,0x55ae,0x559f,0x553e,0x55b2,0x559a,0x55bb,0x55ac,
+    0x55b1,0x557e,0x5589,0x55ab,0x5599,0x570d,0x582f,0x582a,0x5834,0x5824,
+    0x5830,0x5831,0x5821,0x581d,0x5820,0x58f9,0x58fa,0x5960,0x5a77,0x5a9a,
+    0x5a7f,0x5a92,0x5a9b,0x5aa7,0x5b73,0x5b71,0x5bd2,0x5bcc,0x5bd3,0x5bd0,
+    0x5c0a,0x5c0b,0x5c31,0x5d4c,0x5d50,0x5d34,0x5d47,0x5dfd,0x5e45,0x5e3d,
+    0x5e40,0x5e43,0x5e7e,0x5eca
+  },
+  {				/* ku 3f */
+    0x5ec1,0x5ec2,0x5ec4,0x5f3c,0x5f6d,0x5fa9,0x5faa,0x5fa8,0x60d1,0x60e1,
+    0x60b2,0x60b6,0x60e0,0x611c,0x6123,0x60fa,0x6115,0x60f0,0x60fb,0x60f4,
+    0x6168,0x60f1,0x610e,0x60f6,0x6109,0x6100,0x6112,0x621f,0x6249,0x63a3,
+    0x638c,0x63cf,0x63c0,0x63e9,0x63c9,0x63c6,0x63cd,0x63d2,0x63e3,0x63d0,
+    0x63e1,0x63d6,0x63ed,0x63ee,0x6376,0x63f4,0x63ea,0x63db,0x6452,0x63da,
+    0x63f9,0x655e,0x6566,0x6562,0x6563,0x6591,0x6590,0x65af,0x666e,0x6670,
+    0x6674,0x6676,0x666f,0x6691,0x667a,0x667e,0x6677,0x66fe,0x66ff,0x671f,
+    0x671d,0x68fa,0x68d5,0x68e0,0x68d8,0x68d7,0x6905,0x68df,0x68f5,0x68ee,
+    0x68e7,0x68f9,0x68d2,0x68f2,0x68e3,0x68cb,0x68cd,0x690d,0x6912,0x690e,
+    0x68c9,0x68da,0x696e,0x68fb
+  },
+  {				/* ku 40 */
+    0x6b3e,0x6b3a,0x6b3d,0x6b98,0x6b96,0x6bbc,0x6bef,0x6c2e,0x6c2f,0x6c2c,
+    0x6e2f,0x6e38,0x6e54,0x6e21,0x6e32,0x6e67,0x6e4a,0x6e20,0x6e25,0x6e23,
+    0x6e1b,0x6e5b,0x6e58,0x6e24,0x6e56,0x6e6e,0x6e2d,0x6e26,0x6e6f,0x6e34,
+    0x6e4d,0x6e3a,0x6e2c,0x6e43,0x6e1d,0x6e3e,0x6ecb,0x6e89,0x6e19,0x6e4e,
+    0x6e63,0x6e44,0x6e72,0x6e69,0x6e5f,0x7119,0x711a,0x7126,0x7130,0x7121,
+    0x7136,0x716e,0x711c,0x724c,0x7284,0x7280,0x7336,0x7325,0x7334,0x7329,
+    0x743a,0x742a,0x7433,0x7422,0x7425,0x7435,0x7436,0x7434,0x742f,0x741b,
+    0x7426,0x7428,0x7525,0x7526,0x756b,0x756a,0x75e2,0x75db,0x75e3,0x75d9,
+    0x75d8,0x75de,0x75e0,0x767b,0x767c,0x7696,0x7693,0x76b4,0x76dc,0x774f,
+    0x77ed,0x785d,0x786c,0x786f
+  },
+  {				/* ku 41 */
+    0x7a0d,0x7a08,0x7a0b,0x7a05,0x7a00,0x7a98,0x7a97,0x7a96,0x7ae5,0x7ae3,
+    0x7b49,0x7b56,0x7b46,0x7b50,0x7b52,0x7b54,0x7b4d,0x7b4b,0x7b4f,0x7b51,
+    0x7c9f,0x7ca5,0x7d5e,0x7d50,0x7d68,0x7d55,0x7d2b,0x7d6e,0x7d72,0x7d61,
+    0x7d66,0x7d62,0x7d70,0x7d73,0x5584,0x7fd4,0x7fd5,0x800b,0x8052,0x8085,
+    0x8155,0x8154,0x814b,0x8151,0x814e,0x8139,0x8146,0x813e,0x814c,0x8153,
+    0x8174,0x8212,0x821c,0x83e9,0x8403,0x83f8,0x840d,0x83e0,0x83c5,0x840b,
+    0x83c1,0x83ef,0x83f1,0x83f4,0x8457,0x840a,0x83f0,0x840c,0x83cc,0x83fd,
+    0x83f2,0x83ca,0x8438,0x840e,0x8404,0x83dc,0x8407,0x83d4,0x83df,0x865b,
+    0x86df,0x86d9,0x86ed,0x86d4,0x86db,0x86e4,0x86d0,0x86de,0x8857,0x88c1,
+    0x88c2,0x88b1,0x8983,0x8996
+  },
+  {				/* ku 42 */
+    0x8a3b,0x8a60,0x8a55,0x8a5e,0x8a3c,0x8a41,0x8a54,0x8a5b,0x8a50,0x8a46,
+    0x8a34,0x8a3a,0x8a36,0x8a56,0x8c61,0x8c82,0x8caf,0x8cbc,0x8cb3,0x8cbd,
+    0x8cc1,0x8cbb,0x8cc0,0x8cb4,0x8cb7,0x8cb6,0x8cbf,0x8cb8,0x8d8a,0x8d85,
+    0x8d81,0x8dce,0x8ddd,0x8dcb,0x8dda,0x8dd1,0x8dcc,0x8ddb,0x8dc6,0x8efb,
+    0x8ef8,0x8efc,0x8f9c,0x902e,0x9035,0x9031,0x9038,0x9032,0x9036,0x9102,
+    0x90f5,0x9109,0x90fe,0x9163,0x9165,0x91cf,0x9214,0x9215,0x9223,0x9209,
+    0x921e,0x920d,0x9210,0x9207,0x9211,0x9594,0x958f,0x958b,0x9591,0x9593,
+    0x9592,0x958e,0x968a,0x968e,0x968b,0x967d,0x9685,0x9686,0x968d,0x9672,
+    0x9684,0x96c1,0x96c5,0x96c4,0x96c6,0x96c7,0x96ef,0x96f2,0x97cc,0x9805,
+    0x9806,0x9808,0x98e7,0x98ea
+  },
+  {				/* ku 43 */
+    0x98ef,0x98e9,0x98f2,0x98ed,0x99ae,0x99ad,0x9ec3,0x9ecd,0x9ed1,0x4e82,
+    0x50ad,0x50b5,0x50b2,0x50b3,0x50c5,0x50be,0x50ac,0x50b7,0x50bb,0x50af,
+    0x50c7,0x527f,0x5277,0x527d,0x52df,0x52e6,0x52e4,0x52e2,0x52e3,0x532f,
+    0x55df,0x55e8,0x55d3,0x55e6,0x55ce,0x55dc,0x55c7,0x55d1,0x55e3,0x55e4,
+    0x55ef,0x55da,0x55e1,0x55c5,0x55c6,0x55e5,0x55c9,0x5712,0x5713,0x585e,
+    0x5851,0x5858,0x5857,0x585a,0x5854,0x586b,0x584c,0x586d,0x584a,0x5862,
+    0x5852,0x584b,0x5967,0x5ac1,0x5ac9,0x5acc,0x5abe,0x5abd,0x5abc,0x5ab3,
+    0x5ac2,0x5ab2,0x5d69,0x5d6f,0x5e4c,0x5e79,0x5ec9,0x5ec8,0x5f12,0x5f59,
+    0x5fac,0x5fae,0x611a,0x610f,0x6148,0x611f,0x60f3,0x611b,0x60f9,0x6101,
+    0x6108,0x614e,0x614c,0x6144
+  },
+  {				/* ku 44 */
+    0x614d,0x613e,0x6134,0x6127,0x610d,0x6106,0x6137,0x6221,0x6222,0x6413,
+    0x643e,0x641e,0x642a,0x642d,0x643d,0x642c,0x640f,0x641c,0x6414,0x640d,
+    0x6436,0x6416,0x6417,0x6406,0x656c,0x659f,0x65b0,0x6697,0x6689,0x6687,
+    0x6688,0x6696,0x6684,0x6698,0x668d,0x6703,0x6994,0x696d,0x695a,0x6977,
+    0x6960,0x6954,0x6975,0x6930,0x6982,0x694a,0x6968,0x696b,0x695e,0x6953,
+    0x6979,0x6986,0x695d,0x6963,0x695b,0x6b47,0x6b72,0x6bc0,0x6bbf,0x6bd3,
+    0x6bfd,0x6ea2,0x6eaf,0x6ed3,0x6eb6,0x6ec2,0x6e90,0x6e9d,0x6ec7,0x6ec5,
+    0x6ea5,0x6e98,0x6ebc,0x6eba,0x6eab,0x6ed1,0x6e96,0x6e9c,0x6ec4,0x6ed4,
+    0x6eaa,0x6ea7,0x6eb4,0x714e,0x7159,0x7169,0x7164,0x7149,0x7167,0x715c,
+    0x716c,0x7166,0x714c,0x7165
+  },
+  {				/* ku 45 */
+    0x715e,0x7146,0x7168,0x7156,0x723a,0x7252,0x7337,0x7345,0x733f,0x733e,
+    0x746f,0x745a,0x7455,0x745f,0x745e,0x7441,0x743f,0x7459,0x745b,0x745c,
+    0x7576,0x7578,0x7600,0x75f0,0x7601,0x75f2,0x75f1,0x75fa,0x75ff,0x75f4,
+    0x75f3,0x76de,0x76df,0x775b,0x776b,0x7766,0x775e,0x7763,0x7779,0x776a,
+    0x776c,0x775c,0x7765,0x7768,0x7762,0x77ee,0x788e,0x78b0,0x7897,0x7898,
+    0x788c,0x7889,0x787c,0x7891,0x7893,0x787f,0x797a,0x797f,0x7981,0x842c,
+    0x79bd,0x7a1c,0x7a1a,0x7a20,0x7a14,0x7a1f,0x7a1e,0x7a9f,0x7aa0,0x7b77,
+    0x7bc0,0x7b60,0x7b6e,0x7b67,0x7cb1,0x7cb3,0x7cb5,0x7d93,0x7d79,0x7d91,
+    0x7d81,0x7d8f,0x7d5b,0x7f6e,0x7f69,0x7f6a,0x7f72,0x7fa9,0x7fa8,0x7fa4,
+    0x8056,0x8058,0x8086,0x8084
+  },
+  {				/* ku 46 */
+    0x8171,0x8170,0x8178,0x8165,0x816e,0x8173,0x816b,0x8179,0x817a,0x8166,
+    0x8205,0x8247,0x8482,0x8477,0x843d,0x8431,0x8475,0x8466,0x846b,0x8449,
+    0x846c,0x845b,0x843c,0x8435,0x8461,0x8463,0x8469,0x846d,0x8446,0x865e,
+    0x865c,0x865f,0x86f9,0x8713,0x8708,0x8707,0x8700,0x86fe,0x86fb,0x8702,
+    0x8703,0x8706,0x870a,0x8859,0x88df,0x88d4,0x88d9,0x88dc,0x88d8,0x88dd,
+    0x88e1,0x88ca,0x88d5,0x88d2,0x899c,0x89e3,0x8a6b,0x8a72,0x8a73,0x8a66,
+    0x8a69,0x8a70,0x8a87,0x8a7c,0x8a63,0x8aa0,0x8a71,0x8a85,0x8a6d,0x8a62,
+    0x8a6e,0x8a6c,0x8a79,0x8a7b,0x8a3e,0x8a68,0x8c62,0x8c8a,0x8c89,0x8cca,
+    0x8cc7,0x8cc8,0x8cc4,0x8cb2,0x8cc3,0x8cc2,0x8cc5,0x8de1,0x8ddf,0x8de8,
+    0x8def,0x8df3,0x8dfa,0x8dea
+  },
+  {				/* ku 47 */
+    0x8de4,0x8de6,0x8eb2,0x8f03,0x8f09,0x8efe,0x8f0a,0x8f9f,0x8fb2,0x904b,
+    0x904a,0x9053,0x9042,0x9054,0x903c,0x9055,0x9050,0x9047,0x904f,0x904e,
+    0x904d,0x9051,0x903e,0x9041,0x9112,0x9117,0x916c,0x916a,0x9169,0x91c9,
+    0x9237,0x9257,0x9238,0x923d,0x9240,0x923e,0x925b,0x924b,0x9264,0x9251,
+    0x9234,0x9249,0x924d,0x9245,0x9239,0x923f,0x925a,0x9598,0x9698,0x9694,
+    0x9695,0x96cd,0x96cb,0x96c9,0x96ca,0x96f7,0x96fb,0x96f9,0x96f6,0x9756,
+    0x9774,0x9776,0x9810,0x9811,0x9813,0x980a,0x9812,0x980c,0x98fc,0x98f4,
+    0x98fd,0x98fe,0x99b3,0x99b1,0x99b4,0x9ae1,0x9ce9,0x9e82,0x9f0e,0x9f13,
+    0x9f20,0x50e7,0x50ee,0x50e5,0x50d6,0x50ed,0x50da,0x50d5,0x50cf,0x50d1,
+    0x50f1,0x50ce,0x50e9,0x5162
+  },
+  {				/* ku 48 */
+    0x51f3,0x5283,0x5282,0x5331,0x53ad,0x55fe,0x5600,0x561b,0x5617,0x55fd,
+    0x5614,0x5606,0x5609,0x560d,0x560e,0x55f7,0x5616,0x561f,0x5608,0x5610,
+    0x55f6,0x5718,0x5716,0x5875,0x587e,0x5883,0x5893,0x588a,0x5879,0x5885,
+    0x587d,0x58fd,0x5925,0x5922,0x5924,0x596a,0x5969,0x5ae1,0x5ae6,0x5ae9,
+    0x5ad7,0x5ad6,0x5ad8,0x5ae3,0x5b75,0x5bde,0x5be7,0x5be1,0x5be5,0x5be6,
+    0x5be8,0x5be2,0x5be4,0x5bdf,0x5c0d,0x5c62,0x5d84,0x5d87,0x5e5b,0x5e63,
+    0x5e55,0x5e57,0x5e54,0x5ed3,0x5ed6,0x5f0a,0x5f46,0x5f70,0x5fb9,0x6147,
+    0x613f,0x614b,0x6177,0x6162,0x6163,0x615f,0x615a,0x6158,0x6175,0x622a,
+    0x6487,0x6458,0x6454,0x64a4,0x6478,0x645f,0x647a,0x6451,0x6467,0x6434,
+    0x646d,0x647b,0x6572,0x65a1
+  },
+  {				/* ku 49 */
+    0x65d7,0x65d6,0x66a2,0x66a8,0x669d,0x699c,0x69a8,0x6995,0x69c1,0x69ae,
+    0x69d3,0x69cb,0x699b,0x69b7,0x69bb,0x69ab,0x69b4,0x69d0,0x69cd,0x69ad,
+    0x69cc,0x69a6,0x69c3,0x69a3,0x6b49,0x6b4c,0x6c33,0x6f33,0x6f14,0x6efe,
+    0x6f13,0x6ef4,0x6f29,0x6f3e,0x6f20,0x6f2c,0x6f0f,0x6f02,0x6f22,0x6eff,
+    0x6eef,0x6f06,0x6f31,0x6f38,0x6f32,0x6f23,0x6f15,0x6f2b,0x6f2f,0x6f88,
+    0x6f2a,0x6eec,0x6f01,0x6ef2,0x6ecc,0x6ef7,0x7194,0x7199,0x717d,0x718a,
+    0x7184,0x7192,0x723e,0x7292,0x7296,0x7344,0x7350,0x7464,0x7463,0x746a,
+    0x7470,0x746d,0x7504,0x7591,0x7627,0x760d,0x760b,0x7609,0x7613,0x76e1,
+    0x76e3,0x7784,0x777d,0x777f,0x7761,0x78c1,0x789f,0x78a7,0x78b3,0x78a9,
+    0x78a3,0x798e,0x798f,0x798d
+  },
+  {				/* ku 4a */
+    0x7a2e,0x7a31,0x7aaa,0x7aa9,0x7aed,0x7aef,0x7ba1,0x7b95,0x7b8b,0x7b75,
+    0x7b97,0x7b9d,0x7b94,0x7b8f,0x7bb8,0x7b87,0x7b84,0x7cb9,0x7cbd,0x7cbe,
+    0x7dbb,0x7db0,0x7d9c,0x7dbd,0x7dbe,0x7da0,0x7dca,0x7db4,0x7db2,0x7db1,
+    0x7dba,0x7da2,0x7dbf,0x7db5,0x7db8,0x7dad,0x7dd2,0x7dc7,0x7dac,0x7f70,
+    0x7fe0,0x7fe1,0x7fdf,0x805e,0x805a,0x8087,0x8150,0x8180,0x818f,0x8188,
+    0x818a,0x817f,0x8182,0x81e7,0x81fa,0x8207,0x8214,0x821e,0x824b,0x84c9,
+    0x84bf,0x84c6,0x84c4,0x8499,0x849e,0x84b2,0x849c,0x84cb,0x84b8,0x84c0,
+    0x84d3,0x8490,0x84bc,0x84d1,0x84ca,0x873f,0x871c,0x873b,0x8722,0x8725,
+    0x8734,0x8718,0x8755,0x8737,0x8729,0x88f3,0x8902,0x88f4,0x88f9,0x88f8,
+    0x88fd,0x88e8,0x891a,0x88ef
+  },
+  {				/* ku 4b */
+    0x8aa6,0x8a8c,0x8a9e,0x8aa3,0x8a8d,0x8aa1,0x8a93,0x8aa4,0x8aaa,0x8aa5,
+    0x8aa8,0x8a98,0x8a91,0x8a9a,0x8aa7,0x8c6a,0x8c8d,0x8c8c,0x8cd3,0x8cd1,
+    0x8cd2,0x8d6b,0x8d99,0x8d95,0x8dfc,0x8f14,0x8f12,0x8f15,0x8f13,0x8fa3,
+    0x9060,0x9058,0x905c,0x9063,0x9059,0x905e,0x9062,0x905d,0x905b,0x9119,
+    0x9118,0x911e,0x9175,0x9178,0x9177,0x9174,0x9278,0x92ac,0x9280,0x9285,
+    0x9298,0x9296,0x927b,0x9293,0x929c,0x92a8,0x927c,0x9291,0x95a1,0x95a8,
+    0x95a9,0x95a3,0x95a5,0x95a4,0x9699,0x969c,0x969b,0x96cc,0x96d2,0x9700,
+    0x977c,0x9785,0x97f6,0x9817,0x9818,0x98af,0x98b1,0x9903,0x9905,0x990c,
+    0x9909,0x99c1,0x9aaf,0x9ab0,0x9ae6,0x9b41,0x9b42,0x9cf4,0x9cf6,0x9cf3,
+    0x9ebc,0x9f3b,0x9f4a,0x5104
+  },
+  {				/* ku 4c */
+    0x5100,0x50fb,0x50f5,0x50f9,0x5102,0x5108,0x5109,0x5105,0x51dc,0x5287,
+    0x5288,0x5289,0x528d,0x528a,0x52f0,0x53b2,0x562e,0x563b,0x5639,0x5632,
+    0x563f,0x5634,0x5629,0x5653,0x564e,0x5657,0x5674,0x5636,0x562f,0x5630,
+    0x5880,0x589f,0x589e,0x58b3,0x589c,0x58ae,0x58a9,0x58a6,0x596d,0x5b09,
+    0x5afb,0x5b0b,0x5af5,0x5b0c,0x5b08,0x5bee,0x5bec,0x5be9,0x5beb,0x5c64,
+    0x5c65,0x5d9d,0x5d94,0x5e62,0x5e5f,0x5e61,0x5ee2,0x5eda,0x5edf,0x5edd,
+    0x5ee3,0x5ee0,0x5f48,0x5f71,0x5fb7,0x5fb5,0x6176,0x6167,0x616e,0x615d,
+    0x6155,0x6182,0x617c,0x6170,0x616b,0x617e,0x61a7,0x6190,0x61ab,0x618e,
+    0x61ac,0x619a,0x61a4,0x6194,0x61ae,0x622e,0x6469,0x646f,0x6479,0x649e,
+    0x64b2,0x6488,0x6490,0x64b0
+  },
+  {				/* ku 4d */
+    0x64a5,0x6493,0x6495,0x64a9,0x6492,0x64ae,0x64ad,0x64ab,0x649a,0x64ac,
+    0x6499,0x64a2,0x64b3,0x6575,0x6577,0x6578,0x66ae,0x66ab,0x66b4,0x66b1,
+    0x6a23,0x6a1f,0x69e8,0x6a01,0x6a1e,0x6a19,0x69fd,0x6a21,0x6a13,0x6a0a,
+    0x69f3,0x6a02,0x6a05,0x69ed,0x6a11,0x6b50,0x6b4e,0x6ba4,0x6bc5,0x6bc6,
+    0x6f3f,0x6f7c,0x6f84,0x6f51,0x6f66,0x6f54,0x6f86,0x6f6d,0x6f5b,0x6f78,
+    0x6f6e,0x6f8e,0x6f7a,0x6f70,0x6f64,0x6f97,0x6f58,0x6ed5,0x6f6f,0x6f60,
+    0x6f5f,0x719f,0x71ac,0x71b1,0x71a8,0x7256,0x729b,0x734e,0x7357,0x7469,
+    0x748b,0x7483,0x747e,0x7480,0x757f,0x7620,0x7629,0x761f,0x7624,0x7626,
+    0x7621,0x7622,0x769a,0x76ba,0x76e4,0x778e,0x7787,0x778c,0x7791,0x778b,
+    0x78cb,0x78c5,0x78ba,0x78ca
+  },
+  {				/* ku 4e */
+    0x78be,0x78d5,0x78bc,0x78d0,0x7a3f,0x7a3c,0x7a40,0x7a3d,0x7a37,0x7a3b,
+    0x7aaf,0x7aae,0x7bad,0x7bb1,0x7bc4,0x7bb4,0x7bc6,0x7bc7,0x7bc1,0x7ba0,
+    0x7bcc,0x7cca,0x7de0,0x7df4,0x7def,0x7dfb,0x7dd8,0x7dec,0x7ddd,0x7de8,
+    0x7de3,0x7dda,0x7dde,0x7de9,0x7d9e,0x7dd9,0x7df2,0x7df9,0x7f75,0x7f77,
+    0x7faf,0x7fe9,0x8026,0x819b,0x819c,0x819d,0x81a0,0x819a,0x8198,0x8517,
+    0x853d,0x851a,0x84ee,0x852c,0x852d,0x8513,0x8511,0x8523,0x8521,0x8514,
+    0x84ec,0x8525,0x84ff,0x8506,0x8782,0x8774,0x8776,0x8760,0x8766,0x8778,
+    0x8768,0x8759,0x8757,0x874c,0x8753,0x885b,0x885d,0x8910,0x8907,0x8912,
+    0x8913,0x8915,0x890a,0x8abc,0x8ad2,0x8ac7,0x8ac4,0x8a95,0x8acb,0x8af8,
+    0x8ab2,0x8ac9,0x8ac2,0x8abf
+  },
+  {				/* ku 4f */
+    0x8ab0,0x8ad6,0x8acd,0x8ab6,0x8ab9,0x8adb,0x8c4c,0x8c4e,0x8c6c,0x8ce0,
+    0x8cde,0x8ce6,0x8ce4,0x8cec,0x8ced,0x8ce2,0x8ce3,0x8cdc,0x8cea,0x8ce1,
+    0x8d6d,0x8d9f,0x8da3,0x8e2b,0x8e10,0x8e1d,0x8e22,0x8e0f,0x8e29,0x8e1f,
+    0x8e21,0x8e1e,0x8eba,0x8f1d,0x8f1b,0x8f1f,0x8f29,0x8f26,0x8f2a,0x8f1c,
+    0x8f1e,0x8f25,0x9069,0x906e,0x9068,0x906d,0x9077,0x9130,0x912d,0x9127,
+    0x9131,0x9187,0x9189,0x918b,0x9183,0x92c5,0x92bb,0x92b7,0x92ea,0x92e4,
+    0x92c1,0x92b3,0x92bc,0x92d2,0x92c7,0x92f0,0x92b2,0x95ad,0x95b1,0x9704,
+    0x9706,0x9707,0x9709,0x9760,0x978d,0x978b,0x978f,0x9821,0x982b,0x981c,
+    0x98b3,0x990a,0x9913,0x9912,0x9918,0x99dd,0x99d0,0x99df,0x99db,0x99d1,
+    0x99d5,0x99d2,0x99d9,0x9ab7
+  },
+  {				/* ku 50 */
+    0x9aee,0x9aef,0x9b27,0x9b45,0x9b44,0x9b77,0x9b6f,0x9d06,0x9d09,0x9d03,
+    0x9ea9,0x9ebe,0x9ece,0x58a8,0x9f52,0x5112,0x5118,0x5114,0x5110,0x5115,
+    0x5180,0x51aa,0x51dd,0x5291,0x5293,0x52f3,0x5659,0x566b,0x5679,0x5669,
+    0x5664,0x5678,0x566a,0x5668,0x5665,0x5671,0x566f,0x566c,0x5662,0x5676,
+    0x58c1,0x58be,0x58c7,0x58c5,0x596e,0x5b1d,0x5b34,0x5b78,0x5bf0,0x5c0e,
+    0x5f4a,0x61b2,0x6191,0x61a9,0x618a,0x61cd,0x61b6,0x61be,0x61ca,0x61c8,
+    0x6230,0x64c5,0x64c1,0x64cb,0x64bb,0x64bc,0x64da,0x64c4,0x64c7,0x64c2,
+    0x64cd,0x64bf,0x64d2,0x64d4,0x64be,0x6574,0x66c6,0x66c9,0x66b9,0x66c4,
+    0x66c7,0x66b8,0x6a3d,0x6a38,0x6a3a,0x6a59,0x6a6b,0x6a58,0x6a39,0x6a44,
+    0x6a62,0x6a61,0x6a4b,0x6a47
+  },
+  {				/* ku 51 */
+    0x6a35,0x6a5f,0x6a48,0x6b59,0x6b77,0x6c05,0x6fc2,0x6fb1,0x6fa1,0x6fc3,
+    0x6fa4,0x6fc1,0x6fa7,0x6fb3,0x6fc0,0x6fb9,0x6fb6,0x6fa6,0x6fa0,0x6fb4,
+    0x71be,0x71c9,0x71d0,0x71d2,0x71c8,0x71d5,0x71b9,0x71ce,0x71d9,0x71dc,
+    0x71c3,0x71c4,0x7368,0x749c,0x74a3,0x7498,0x749f,0x749e,0x74e2,0x750c,
+    0x750d,0x7634,0x7638,0x763a,0x76e7,0x76e5,0x77a0,0x779e,0x779f,0x77a5,
+    0x78e8,0x78da,0x78ec,0x78e7,0x79a6,0x7a4d,0x7a4e,0x7a46,0x7a4c,0x7a4b,
+    0x7aba,0x7bd9,0x7c11,0x7bc9,0x7be4,0x7bdb,0x7be1,0x7be9,0x7be6,0x7cd5,
+    0x7cd6,0x7e0a,0x7e11,0x7e08,0x7e1b,0x7e23,0x7e1e,0x7e1d,0x7e09,0x7e10,
+    0x7f79,0x7fb2,0x7ff0,0x7ff1,0x7fee,0x8028,0x81b3,0x81a9,0x81a8,0x81fb,
+    0x8208,0x8258,0x8259,0x854a
+  },
+  {				/* ku 52 */
+    0x8559,0x8548,0x8568,0x8569,0x8543,0x8549,0x856d,0x856a,0x855e,0x8783,
+    0x879f,0x879e,0x87a2,0x878d,0x8861,0x892a,0x8932,0x8925,0x892b,0x8921,
+    0x89aa,0x89a6,0x8ae6,0x8afa,0x8aeb,0x8af1,0x8b00,0x8adc,0x8ae7,0x8aee,
+    0x8afe,0x8b01,0x8b02,0x8af7,0x8aed,0x8af3,0x8af6,0x8afc,0x8c6b,0x8c6d,
+    0x8c93,0x8cf4,0x8e44,0x8e31,0x8e34,0x8e42,0x8e39,0x8e35,0x8f3b,0x8f2f,
+    0x8f38,0x8f33,0x8fa8,0x8fa6,0x9075,0x9074,0x9078,0x9072,0x907c,0x907a,
+    0x9134,0x9192,0x9320,0x9336,0x92f8,0x9333,0x932f,0x9322,0x92fc,0x932b,
+    0x9304,0x931a,0x9310,0x9326,0x9321,0x9315,0x932e,0x9319,0x95bb,0x96a7,
+    0x96a8,0x96aa,0x96d5,0x970e,0x9711,0x9716,0x970d,0x9713,0x970f,0x975b,
+    0x975c,0x9766,0x9798,0x9830
+  },
+  {				/* ku 53 */
+    0x9838,0x983b,0x9837,0x982d,0x9839,0x9824,0x9910,0x9928,0x991e,0x991b,
+    0x9921,0x991a,0x99ed,0x99e2,0x99f1,0x9ab8,0x9abc,0x9afb,0x9aed,0x9b28,
+    0x9b91,0x9d15,0x9d23,0x9d26,0x9d28,0x9d12,0x9d1b,0x9ed8,0x9ed4,0x9f8d,
+    0x9f9c,0x512a,0x511f,0x5121,0x5132,0x52f5,0x568e,0x5680,0x5690,0x5685,
+    0x5687,0x568f,0x58d5,0x58d3,0x58d1,0x58ce,0x5b30,0x5b2a,0x5b24,0x5b7a,
+    0x5c37,0x5c68,0x5dbc,0x5dba,0x5dbd,0x5db8,0x5e6b,0x5f4c,0x5fbd,0x61c9,
+    0x61c2,0x61c7,0x61e6,0x61cb,0x6232,0x6234,0x64ce,0x64ca,0x64d8,0x64e0,
+    0x64f0,0x64e6,0x64ec,0x64f1,0x64e2,0x64ed,0x6582,0x6583,0x66d9,0x66d6,
+    0x6a80,0x6a94,0x6a84,0x6aa2,0x6a9c,0x6adb,0x6aa3,0x6a7e,0x6a97,0x6a90,
+    0x6aa0,0x6b5c,0x6bae,0x6bda
+  },
+  {				/* ku 54 */
+    0x6c08,0x6fd8,0x6ff1,0x6fdf,0x6fe0,0x6fdb,0x6fe4,0x6feb,0x6fef,0x6f80,
+    0x6fec,0x6fe1,0x6fe9,0x6fd5,0x6fee,0x6ff0,0x71e7,0x71df,0x71ee,0x71e6,
+    0x71e5,0x71ed,0x71ec,0x71f4,0x71e0,0x7235,0x7246,0x7370,0x7372,0x74a9,
+    0x74b0,0x74a6,0x74a8,0x7646,0x7642,0x764c,0x76ea,0x77b3,0x77aa,0x77b0,
+    0x77ac,0x77a7,0x77ad,0x77ef,0x78f7,0x78fa,0x78f4,0x78ef,0x7901,0x79a7,
+    0x79aa,0x7a57,0x7abf,0x7c07,0x7c0d,0x7bfe,0x7bf7,0x7c0c,0x7be0,0x7ce0,
+    0x7cdc,0x7cde,0x7ce2,0x7cdf,0x7cd9,0x7cdd,0x7e2e,0x7e3e,0x7e46,0x7e37,
+    0x7e32,0x7e43,0x7e2b,0x7e3d,0x7e31,0x7e45,0x7e41,0x7e34,0x7e39,0x7e48,
+    0x7e35,0x7e3f,0x7e2f,0x7f44,0x7ff3,0x7ffc,0x8071,0x8072,0x8070,0x806f,
+    0x8073,0x81c6,0x81c3,0x81ba
+  },
+  {				/* ku 55 */
+    0x81c2,0x81c0,0x81bf,0x81bd,0x81c9,0x81be,0x81e8,0x8209,0x8271,0x85aa,
+    0x8584,0x857e,0x859c,0x8591,0x8594,0x85af,0x859b,0x8587,0x85a8,0x858a,
+    0x85a6,0x8667,0x87c0,0x87d1,0x87b3,0x87d2,0x87c6,0x87ab,0x87bb,0x87ba,
+    0x87c8,0x87cb,0x893b,0x8936,0x8944,0x8938,0x893d,0x89ac,0x8b0e,0x8b17,
+    0x8b19,0x8b1b,0x8b0a,0x8b20,0x8b1d,0x8b04,0x8b10,0x8c41,0x8c3f,0x8c73,
+    0x8cfa,0x8cfd,0x8cfc,0x8cf8,0x8cfb,0x8da8,0x8e49,0x8e4b,0x8e48,0x8e4a,
+    0x8f44,0x8f3e,0x8f42,0x8f45,0x8f3f,0x907f,0x907d,0x9084,0x9081,0x9082,
+    0x9080,0x9139,0x91a3,0x919e,0x919c,0x934d,0x9382,0x9328,0x9375,0x934a,
+    0x9365,0x934b,0x9318,0x937e,0x936c,0x935b,0x9370,0x935a,0x9354,0x95ca,
+    0x95cb,0x95cc,0x95c8,0x95c6
+  },
+  {				/* ku 56 */
+    0x96b1,0x96b8,0x96d6,0x971c,0x971e,0x97a0,0x97d3,0x9846,0x98b6,0x9935,
+    0x9a01,0x99ff,0x9bae,0x9bab,0x9baa,0x9bad,0x9d3b,0x9d3f,0x9e8b,0x9ecf,
+    0x9ede,0x9edc,0x9edd,0x9edb,0x9f3e,0x9f4b,0x53e2,0x5695,0x56ae,0x58d9,
+    0x58d8,0x5b38,0x5f5e,0x61e3,0x6233,0x64f4,0x64f2,0x64fe,0x6506,0x64fa,
+    0x64fb,0x64f7,0x65b7,0x66dc,0x6726,0x6ab3,0x6aac,0x6ac3,0x6abb,0x6ab8,
+    0x6ac2,0x6aae,0x6aaf,0x6b5f,0x6b78,0x6baf,0x7009,0x700b,0x6ffe,0x7006,
+    0x6ffa,0x7011,0x700f,0x71fb,0x71fc,0x71fe,0x71f8,0x7377,0x7375,0x74a7,
+    0x74bf,0x7515,0x7656,0x7658,0x7652,0x77bd,0x77bf,0x77bb,0x77bc,0x790e,
+    0x79ae,0x7a61,0x7a62,0x7a60,0x7ac4,0x7ac5,0x7c2b,0x7c27,0x7c2a,0x7c1e,
+    0x7c23,0x7c21,0x7ce7,0x7e54
+  },
+  {				/* ku 57 */
+    0x7e55,0x7e5e,0x7e5a,0x7e61,0x7e52,0x7e59,0x7f48,0x7ff9,0x7ffb,0x8077,
+    0x8076,0x81cd,0x81cf,0x820a,0x85cf,0x85a9,0x85cd,0x85d0,0x85c9,0x85b0,
+    0x85ba,0x85b9,0x87ef,0x87ec,0x87f2,0x87e0,0x8986,0x89b2,0x89f4,0x8b28,
+    0x8b39,0x8b2c,0x8b2b,0x8c50,0x8d05,0x8e59,0x8e63,0x8e66,0x8e64,0x8e5f,
+    0x8e55,0x8ec0,0x8f49,0x8f4d,0x9087,0x9083,0x9088,0x91ab,0x91ac,0x91d0,
+    0x9394,0x938a,0x9396,0x93a2,0x93b3,0x93ae,0x93ac,0x93b0,0x9398,0x939a,
+    0x9397,0x95d4,0x95d6,0x95d0,0x95d5,0x96e2,0x96dc,0x96d9,0x96db,0x96de,
+    0x9724,0x97a3,0x97a6,0x97ad,0x97f9,0x984d,0x984f,0x984c,0x984e,0x9853,
+    0x98ba,0x993e,0x993f,0x993d,0x992e,0x99a5,0x9a0e,0x9ac1,0x9b03,0x9b06,
+    0x9b4f,0x9b4e,0x9b4d,0x9bca
+  },
+  {				/* ku 58 */
+    0x9bc9,0x9bfd,0x9bc8,0x9bc0,0x9d51,0x9d5d,0x9d60,0x9ee0,0x9f15,0x9f2c,
+    0x5133,0x56a5,0x56a8,0x58de,0x58df,0x58e2,0x5bf5,0x9f90,0x5eec,0x61f2,
+    0x61f7,0x61f6,0x61f5,0x6500,0x650f,0x66e0,0x66dd,0x6ae5,0x6add,0x6ada,
+    0x6ad3,0x701b,0x701f,0x7028,0x701a,0x701d,0x7015,0x7018,0x7206,0x720d,
+    0x7258,0x72a2,0x7378,0x737a,0x74bd,0x74ca,0x74e3,0x7587,0x7586,0x765f,
+    0x7661,0x77c7,0x7919,0x79b1,0x7a6b,0x7a69,0x7c3e,0x7c3f,0x7c38,0x7c3d,
+    0x7c37,0x7c40,0x7e6b,0x7e6d,0x7e79,0x7e69,0x7e6a,0x7e73,0x7f85,0x7fb6,
+    0x7fb9,0x7fb8,0x81d8,0x85e9,0x85dd,0x85ea,0x85d5,0x85e4,0x85e5,0x85f7,
+    0x87fb,0x8805,0x880d,0x87f9,0x87fe,0x8960,0x895f,0x8956,0x895e,0x8b41,
+    0x8b5c,0x8b58,0x8b49,0x8b5a
+  },
+  {				/* ku 59 */
+    0x8b4e,0x8b4f,0x8b46,0x8b59,0x8d08,0x8d0a,0x8e7c,0x8e72,0x8e87,0x8e76,
+    0x8e6c,0x8e7a,0x8e74,0x8f54,0x8f4e,0x8fad,0x908a,0x908b,0x91b1,0x91ae,
+    0x93e1,0x93d1,0x93df,0x93c3,0x93c8,0x93dc,0x93dd,0x93d6,0x93e2,0x93cd,
+    0x93d8,0x93e4,0x93d7,0x93e8,0x95dc,0x96b4,0x96e3,0x972a,0x9727,0x9761,
+    0x97dc,0x97fb,0x985e,0x9858,0x985b,0x98bc,0x9945,0x9949,0x9a16,0x9a19,
+    0x9b0d,0x9be8,0x9be7,0x9bd6,0x9bdb,0x9d89,0x9d61,0x9d72,0x9d6a,0x9d6c,
+    0x9e92,0x9e97,0x9e93,0x9eb4,0x52f8,0x56b7,0x56b6,0x56b4,0x56bc,0x58e4,
+    0x5b40,0x5b43,0x5b7d,0x5bf6,0x5dc9,0x61f8,0x61fa,0x6518,0x6514,0x6519,
+    0x66e6,0x6727,0x6aec,0x703e,0x7030,0x7032,0x7210,0x737b,0x74cf,0x7662,
+    0x7665,0x7926,0x792a,0x792c
+  },
+  {				/* ku 5a */
+    0x792b,0x7ac7,0x7af6,0x7c4c,0x7c43,0x7c4d,0x7cef,0x7cf0,0x8fae,0x7e7d,
+    0x7e7c,0x7e82,0x7f4c,0x8000,0x81da,0x8266,0x85fb,0x85f9,0x8611,0x85fa,
+    0x8606,0x860b,0x8607,0x860a,0x8814,0x8815,0x8964,0x89ba,0x89f8,0x8b70,
+    0x8b6c,0x8b66,0x8b6f,0x8b5f,0x8b6b,0x8d0f,0x8d0d,0x8e89,0x8e81,0x8e85,
+    0x8e82,0x91b4,0x91cb,0x9418,0x9403,0x93fd,0x95e1,0x9730,0x98c4,0x9952,
+    0x9951,0x99a8,0x9a2b,0x9a30,0x9a37,0x9a35,0x9c13,0x9c0d,0x9e79,0x9eb5,
+    0x9ee8,0x9f2f,0x9f5f,0x9f63,0x9f61,0x5137,0x5138,0x56c1,0x56c0,0x56c2,
+    0x5914,0x5c6c,0x5dcd,0x61fc,0x61fe,0x651d,0x651c,0x6595,0x66e9,0x6afb,
+    0x6b04,0x6afa,0x6bb2,0x704c,0x721b,0x72a7,0x74d6,0x74d4,0x7669,0x77d3,
+    0x7c50,0x7e8f,0x7e8c,0x7fbc
+  },
+  {				/* ku 5b */
+    0x8617,0x862d,0x861a,0x8823,0x8822,0x8821,0x881f,0x896a,0x896c,0x89bd,
+    0x8b74,0x8b77,0x8b7d,0x8d13,0x8e8a,0x8e8d,0x8e8b,0x8f5f,0x8faf,0x91ba,
+    0x942e,0x9433,0x9435,0x943a,0x9438,0x9432,0x942b,0x95e2,0x9738,0x9739,
+    0x9732,0x97ff,0x9867,0x9865,0x9957,0x9a45,0x9a43,0x9a40,0x9a3e,0x9acf,
+    0x9b54,0x9b51,0x9c2d,0x9c25,0x9daf,0x9db4,0x9dc2,0x9db8,0x9e9d,0x9eef,
+    0x9f19,0x9f5c,0x9f66,0x9f67,0x513c,0x513b,0x56c8,0x56ca,0x56c9,0x5b7f,
+    0x5dd4,0x5dd2,0x5f4e,0x61ff,0x6524,0x6b0a,0x6b61,0x7051,0x7058,0x7380,
+    0x74e4,0x758a,0x766e,0x766c,0x79b3,0x7c60,0x7c5f,0x807e,0x807d,0x81df,
+    0x8972,0x896f,0x89fc,0x8b80,0x8d16,0x8d17,0x8e91,0x8e93,0x8f61,0x9148,
+    0x9444,0x9451,0x9452,0x973d
+  },
+  {				/* ku 5c */
+    0x973e,0x97c3,0x97c1,0x986b,0x9955,0x9a55,0x9a4d,0x9ad2,0x9b1a,0x9c49,
+    0x9c31,0x9c3e,0x9c3b,0x9dd3,0x9dd7,0x9f34,0x9f6c,0x9f6a,0x9f94,0x56cc,
+    0x5dd6,0x6200,0x6523,0x652b,0x652a,0x66ec,0x6b10,0x74da,0x7aca,0x7c64,
+    0x7c63,0x7c65,0x7e93,0x7e96,0x7e94,0x81e2,0x8638,0x863f,0x8831,0x8b8a,
+    0x9090,0x908f,0x9463,0x9460,0x9464,0x9768,0x986f,0x995c,0x9a5a,0x9a5b,
+    0x9a57,0x9ad3,0x9ad4,0x9ad1,0x9c54,0x9c57,0x9c56,0x9de5,0x9e9f,0x9ef4,
+    0x56d1,0x58e9,0x652c,0x705e,0x7671,0x7672,0x77d7,0x7f50,0x7f88,0x8836,
+    0x8839,0x8862,0x8b93,0x8b92,0x8b96,0x8277,0x8d1b,0x91c0,0x946a,0x9742,
+    0x9748,0x9744,0x97c6,0x9870,0x9a5f,0x9b22,0x9b58,0x9c5f,0x9df9,0x9dfa,
+    0x9e7c,0x9e7d,0x9f07,0x9f77
+  },
+  {				/* ku 5d */
+    0x9f72,0x5ef3,0x6b16,0x7063,0x7c6c,0x7c6e,0x883b,0x89c0,0x8ea1,0x91c1,
+    0x9472,0x9470,0x9871,0x995e,0x9ad6,0x9b23,0x9ecc,0x7064,0x77da,0x8b9a,
+    0x9477,0x97c9,0x9a62,0x9a65,0x7e9c,0x8b9c,0x8eaa,0x91c5,0x947d,0x947e,
+    0x947c,0x9c77,0x9c78,0x9ef7,0x8c54,0x947f,0x9e1a,0x7228,0x9a6a,0x9b31,
+    0x9e1b,0x9e1e,0x7c72,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  }
+};
+
+/* CNS 11643 plane 2 conversion table */
+
+static const unsigned short
+ cns11643_2tab[MAX_CNS11643_KU_2][MAX_CNS11643_TEN] = {
+  {				/* ku 01 */
+    0x4e42,0x4e5c,0x51f5,0x531a,0x5382,0x4e07,0x4e0c,0x4e47,0x4e8d,0x56d7,
+    0x5c6e,0x5f73,0x4e0f,0x5187,0x4e0e,0x4e2e,0x4e93,0x4ec2,0x4ec9,0x4ec8,
+    0x5198,0x52fc,0x536c,0x53b9,0x5720,0x5903,0x592c,0x5c10,0x5dff,0x65e1,
+    0x6bb3,0x6bcc,0x6c14,0x723f,0x4e31,0x4e3c,0x4ee8,0x4edc,0x4ee9,0x4ee1,
+    0x4edd,0x4eda,0x520c,0x5209,0x531c,0x534c,0x5722,0x5723,0x5917,0x592f,
+    0x5b81,0x5b84,0x5c12,0x5c3b,0x5c74,0x5c73,0x5e04,0x5e80,0x5e82,0x5fc9,
+    0x6209,0x6250,0x6c15,0x6c36,0x6c43,0x6c3f,0x6c3b,0x72ae,0x72b0,0x738a,
+    0x79b8,0x808a,0x961e,0x4f0e,0x4f18,0x4f2c,0x4ef5,0x4f14,0x4ef1,0x4f00,
+    0x4ef7,0x4f08,0x4f1d,0x4f02,0x4f05,0x4f22,0x4f13,0x4f04,0x4ef4,0x4f12,
+    0x51b1,0x5213,0x5210,0x52a6
+  },
+  {				/* ku 02 */
+    0x5322,0x531f,0x534d,0x538a,0x5407,0x56e1,0x56df,0x572e,0x572a,0x5734,
+    0x593c,0x5980,0x597c,0x5985,0x597b,0x597e,0x5977,0x597f,0x5b56,0x5c15,
+    0x5c25,0x5c7c,0x5c7a,0x5c7b,0x5c7e,0x5ddf,0x5e75,0x5e84,0x5f02,0x5f1a,
+    0x5f74,0x5fd5,0x5fd4,0x5fcf,0x625c,0x625e,0x6264,0x6261,0x6266,0x6262,
+    0x6259,0x6260,0x625a,0x6265,0x6537,0x65ef,0x65ee,0x673e,0x6739,0x6738,
+    0x673b,0x673a,0x673f,0x673c,0x6733,0x6c18,0x6c46,0x6c52,0x6c5c,0x6c4f,
+    0x6c4a,0x6c54,0x6c4b,0x6c4c,0x7071,0x725e,0x72b4,0x72b5,0x738e,0x752a,
+    0x767f,0x7a75,0x7f51,0x8278,0x827c,0x8280,0x827d,0x827f,0x864d,0x897e,
+    0x9099,0x9097,0x9098,0x909b,0x9094,0x9622,0x9624,0x9620,0x9623,0x4f56,
+    0x4f3b,0x4f62,0x4f49,0x4f53
+  },
+  {				/* ku 03 */
+    0x4f64,0x4f3e,0x4f67,0x4f52,0x4f5f,0x4f41,0x4f58,0x4f2d,0x4f33,0x4f3f,
+    0x4f61,0x518f,0x51b9,0x521c,0x521e,0x5221,0x52ad,0x52ae,0x5309,0x5363,
+    0x5372,0x538e,0x538f,0x5430,0x5437,0x542a,0x5454,0x5445,0x5419,0x541c,
+    0x5425,0x5418,0x543d,0x544f,0x5441,0x5428,0x5424,0x5447,0x56ee,0x56e7,
+    0x56e5,0x5741,0x5745,0x574c,0x5749,0x574b,0x5752,0x5906,0x5940,0x59a6,
+    0x5998,0x59a0,0x5997,0x598e,0x59a2,0x5990,0x598f,0x59a7,0x59a1,0x5b8e,
+    0x5b92,0x5c28,0x5c2a,0x5c8d,0x5c8f,0x5c88,0x5c8b,0x5c89,0x5c92,0x5c8a,
+    0x5c86,0x5c93,0x5c95,0x5de0,0x5e0a,0x5e0e,0x5e8b,0x5e89,0x5e8c,0x5e88,
+    0x5e8d,0x5f05,0x5f1d,0x5f78,0x5f76,0x5fd2,0x5fd1,0x5fd0,0x5fed,0x5fe8,
+    0x5fee,0x5ff3,0x5fe1,0x5fe4
+  },
+  {				/* ku 04 */
+    0x5fe3,0x5ffa,0x5fef,0x5ff7,0x5ffb,0x6000,0x5ff4,0x623a,0x6283,0x628c,
+    0x628e,0x628f,0x6294,0x6287,0x6271,0x627b,0x627a,0x6270,0x6281,0x6288,
+    0x6277,0x627d,0x6272,0x6274,0x65f0,0x65f4,0x65f3,0x65f2,0x65f5,0x6745,
+    0x6747,0x6759,0x6755,0x674c,0x6748,0x675d,0x674d,0x675a,0x674b,0x6bd0,
+    0x6c19,0x6c1a,0x6c78,0x6c67,0x6c6b,0x6c84,0x6c8b,0x6c8f,0x6c71,0x6c6f,
+    0x6c69,0x6c9a,0x6c6d,0x6c87,0x6c95,0x6c9c,0x6c66,0x6c73,0x6c65,0x6c7b,
+    0x6c8e,0x7074,0x707a,0x7263,0x72bf,0x72bd,0x72c3,0x72c6,0x72c1,0x72ba,
+    0x72c5,0x7395,0x7397,0x7393,0x7394,0x7392,0x753a,0x7539,0x7594,0x7595,
+    0x7681,0x793d,0x8034,0x8095,0x8099,0x8090,0x8092,0x809c,0x8290,0x828f,
+    0x8285,0x828e,0x8291,0x8293
+  },
+  {				/* ku 05 */
+    0x828a,0x8283,0x8284,0x8c78,0x8fc9,0x8fbf,0x909f,0x90a1,0x90a5,0x909e,
+    0x90a7,0x90a0,0x9630,0x9628,0x962f,0x962d,0x4e33,0x4f98,0x4f7c,0x4f85,
+    0x4f7d,0x4f80,0x4f87,0x4f76,0x4f74,0x4f89,0x4f84,0x4f77,0x4f4c,0x4f97,
+    0x4f6a,0x4f9a,0x4f79,0x4f81,0x4f78,0x4f90,0x4f9c,0x4f94,0x4f9e,0x4f92,
+    0x4f82,0x4f95,0x4f6b,0x4f6e,0x519e,0x51bc,0x51be,0x5235,0x5232,0x5233,
+    0x5246,0x5231,0x52bc,0x530a,0x530b,0x533c,0x5392,0x5394,0x5487,0x547f,
+    0x5481,0x5491,0x5482,0x5488,0x546b,0x547a,0x547e,0x5465,0x546c,0x5474,
+    0x5466,0x548d,0x546f,0x5461,0x5460,0x5498,0x5463,0x5467,0x5464,0x56f7,
+    0x56f9,0x576f,0x5772,0x576d,0x576b,0x5771,0x5770,0x5776,0x5780,0x5775,
+    0x577b,0x5773,0x5774,0x5762
+  },
+  {				/* ku 06 */
+    0x5768,0x577d,0x590c,0x5945,0x59b5,0x59ba,0x59cf,0x59ce,0x59b2,0x59cc,
+    0x59c1,0x59b6,0x59bc,0x59c3,0x59d6,0x59b1,0x59bd,0x59c0,0x59c8,0x59b4,
+    0x59c7,0x5b62,0x5b65,0x5b93,0x5b95,0x5c44,0x5c47,0x5cae,0x5ca4,0x5ca0,
+    0x5cb5,0x5caf,0x5ca8,0x5cac,0x5c9f,0x5ca3,0x5cad,0x5ca2,0x5caa,0x5ca7,
+    0x5c9d,0x5ca5,0x5cb6,0x5cb0,0x5ca6,0x5e17,0x5e14,0x5e19,0x5f28,0x5f22,
+    0x5f23,0x5f24,0x5f54,0x5f82,0x5f7e,0x5f7d,0x5fde,0x5fe5,0x602d,0x6026,
+    0x6019,0x6032,0x600b,0x6034,0x600a,0x6017,0x6033,0x601a,0x601e,0x602c,
+    0x6022,0x600d,0x6010,0x602e,0x6013,0x6011,0x600c,0x6009,0x601c,0x6214,
+    0x623d,0x62ad,0x62b4,0x62d1,0x62be,0x62aa,0x62b6,0x62ca,0x62ae,0x62b3,
+    0x62af,0x62bb,0x62a9,0x62b0
+  },
+  {				/* ku 07 */
+    0x62b8,0x653d,0x65a8,0x65bb,0x6609,0x65fc,0x6604,0x6612,0x6608,0x65fb,
+    0x6603,0x660b,0x660d,0x6605,0x65fd,0x6611,0x6610,0x66f6,0x670a,0x6785,
+    0x676c,0x678e,0x6792,0x6776,0x677b,0x6798,0x6786,0x6784,0x6774,0x678d,
+    0x678c,0x677a,0x679f,0x6791,0x6799,0x6783,0x677d,0x6781,0x6778,0x6779,
+    0x6794,0x6b25,0x6b80,0x6b7e,0x6bde,0x6c1d,0x6c93,0x6cec,0x6ceb,0x6cee,
+    0x6cd9,0x6cb6,0x6cd4,0x6cad,0x6ce7,0x6cb7,0x6cd0,0x6cc2,0x6cba,0x6cc3,
+    0x6cc6,0x6ced,0x6cf2,0x6cd2,0x6cdd,0x6cb4,0x6c8a,0x6c9d,0x6c80,0x6cde,
+    0x6cc0,0x6d30,0x6ccd,0x6cc7,0x6cb0,0x6cf9,0x6ccf,0x6ce9,0x6cd1,0x7094,
+    0x7098,0x7085,0x7093,0x7086,0x7084,0x7091,0x7096,0x7082,0x709a,0x7083,
+    0x726a,0x72d6,0x72cb,0x72d8
+  },
+  {				/* ku 08 */
+    0x72c9,0x72dc,0x72d2,0x72d4,0x72da,0x72cc,0x72d1,0x73a4,0x73a1,0x73ad,
+    0x73a6,0x73a2,0x73a0,0x73ac,0x739d,0x74dd,0x74e8,0x753f,0x7540,0x753e,
+    0x758c,0x7598,0x76af,0x76f3,0x76f1,0x76f0,0x76f5,0x77f8,0x77fc,0x77f9,
+    0x77fb,0x77fa,0x77f7,0x7942,0x793f,0x79c5,0x7a78,0x7a7b,0x7afb,0x7c75,
+    0x7cfd,0x8035,0x808f,0x80ae,0x80a3,0x80b8,0x80b5,0x80ad,0x8220,0x82a0,
+    0x82c0,0x82ab,0x829a,0x8298,0x829b,0x82b5,0x82a7,0x82ae,0x82bc,0x829e,
+    0x82ba,0x82b4,0x82a8,0x82a1,0x82a9,0x82c2,0x82a4,0x82c3,0x82b6,0x82a2,
+    0x8670,0x866f,0x866d,0x866e,0x8c56,0x8fd2,0x8fcb,0x8fd3,0x8fcd,0x8fd6,
+    0x8fd5,0x8fd7,0x90b2,0x90b4,0x90af,0x90b3,0x90b0,0x9639,0x963d,0x963c,
+    0x963a,0x9643,0x4fcd,0x4fc5
+  },
+  {				/* ku 09 */
+    0x4fd3,0x4fb2,0x4fc9,0x4fcb,0x4fc1,0x4fd4,0x4fdc,0x4fd9,0x4fbb,0x4fb3,
+    0x4fdb,0x4fc7,0x4fd6,0x4fba,0x4fc0,0x4fb9,0x4fec,0x5244,0x5249,0x52c0,
+    0x52c2,0x533d,0x537c,0x5397,0x5396,0x5399,0x5398,0x54ba,0x54a1,0x54ad,
+    0x54a5,0x54cf,0x54c3,0x830d,0x54b7,0x54ae,0x54d6,0x54b6,0x54c5,0x54c6,
+    0x54a0,0x5470,0x54bc,0x54a2,0x54be,0x5472,0x54de,0x54b0,0x57b5,0x579e,
+    0x579f,0x57a4,0x578c,0x5797,0x579d,0x579b,0x5794,0x5798,0x578f,0x5799,
+    0x57a5,0x579a,0x5795,0x58f4,0x590d,0x5953,0x59e1,0x59de,0x59ee,0x5a00,
+    0x59f1,0x59dd,0x59fa,0x59fd,0x59fc,0x59f6,0x59e4,0x59f2,0x59f7,0x59db,
+    0x59e9,0x59f3,0x59f5,0x59e0,0x59fe,0x59f4,0x59ed,0x5ba8,0x5c4c,0x5cd0,
+    0x5cd8,0x5ccc,0x5cd7,0x5ccb
+  },
+  {				/* ku 0a */
+    0x5cdb,0x5cde,0x5cda,0x5cc9,0x5cc7,0x5cca,0x5cd6,0x5cd3,0x5cd4,0x5ccf,
+    0x5cc8,0x5cc6,0x5cce,0x5cdf,0x5cf8,0x5df9,0x5e21,0x5e22,0x5e23,0x5e20,
+    0x5e24,0x5eb0,0x5ea4,0x5ea2,0x5e9b,0x5ea3,0x5ea5,0x5f07,0x5f2e,0x5f56,
+    0x5f86,0x6037,0x6039,0x6054,0x6072,0x605e,0x6045,0x6053,0x6047,0x6049,
+    0x605b,0x604c,0x6040,0x6042,0x605f,0x6024,0x6044,0x6058,0x6066,0x606e,
+    0x6242,0x6243,0x62cf,0x630d,0x630b,0x62f5,0x630e,0x6303,0x62eb,0x62f9,
+    0x630f,0x630c,0x62f8,0x62f6,0x6300,0x6313,0x6314,0x62fa,0x6315,0x62fb,
+    0x62f0,0x6541,0x6543,0x65aa,0x65bf,0x6636,0x6621,0x6632,0x6635,0x661c,
+    0x6626,0x6622,0x6633,0x662b,0x663a,0x661d,0x6634,0x6639,0x662e,0x670f,
+    0x6710,0x67c1,0x67f2,0x67c8
+  },
+  {				/* ku 0b */
+    0x67ba,0x67dc,0x67bb,0x67f8,0x67d8,0x67c0,0x67b7,0x67c5,0x67eb,0x67e4,
+    0x67df,0x67b5,0x67cd,0x67b3,0x67f7,0x67f6,0x67ee,0x67e3,0x67c2,0x67b9,
+    0x67ce,0x67e7,0x67f0,0x67b2,0x67fc,0x67c6,0x67ed,0x67cc,0x67ae,0x67e6,
+    0x67db,0x67fa,0x67c9,0x67ca,0x67c3,0x67ea,0x67cb,0x6b28,0x6b82,0x6b84,
+    0x6bb6,0x6bd6,0x6bd8,0x6be0,0x6c20,0x6c21,0x6d28,0x6d34,0x6d2d,0x6d1f,
+    0x6d3c,0x6d3f,0x6d12,0x6d0a,0x6cda,0x6d33,0x6d04,0x6d19,0x6d3a,0x6d1a,
+    0x6d11,0x6d00,0x6d1d,0x6d42,0x6d01,0x6d18,0x6d37,0x6d03,0x6d0f,0x6d40,
+    0x6d07,0x6d20,0x6d2c,0x6d08,0x6d22,0x6d09,0x6d10,0x70b7,0x709f,0x70be,
+    0x70b1,0x70b0,0x70a1,0x70b4,0x70b5,0x70a9,0x7241,0x7249,0x724a,0x726c,
+    0x7270,0x7273,0x726e,0x72ca
+  },
+  {				/* ku 0c */
+    0x72e4,0x72e8,0x72eb,0x72df,0x72ea,0x72e6,0x72e3,0x7385,0x73cc,0x73c2,
+    0x73c8,0x73c5,0x73b9,0x73b6,0x73b5,0x73b4,0x73eb,0x73bf,0x73c7,0x73be,
+    0x73c3,0x73c6,0x73b8,0x73cb,0x74ec,0x74ee,0x752e,0x7547,0x7548,0x75a7,
+    0x75aa,0x7679,0x76c4,0x7708,0x7703,0x7704,0x7705,0x770a,0x76f7,0x76fb,
+    0x76fa,0x77e7,0x77e8,0x7806,0x7811,0x7812,0x7805,0x7810,0x780f,0x780e,
+    0x7809,0x7803,0x7813,0x794a,0x794c,0x794b,0x7945,0x7944,0x79d5,0x79cd,
+    0x79cf,0x79d6,0x79ce,0x7a80,0x7a7e,0x7ad1,0x7b00,0x7b01,0x7c7a,0x7c78,
+    0x7c79,0x7c7f,0x7c80,0x7c81,0x7d03,0x7d08,0x7d01,0x7f58,0x7f91,0x7f8d,
+    0x7fbe,0x8007,0x800e,0x800f,0x8014,0x8037,0x80d8,0x80c7,0x80e0,0x80d1,
+    0x80c8,0x80c2,0x80d0,0x80c5
+  },
+  {				/* ku 0d */
+    0x80e3,0x80d9,0x80dc,0x80ca,0x80d5,0x80c9,0x80cf,0x80d7,0x80e6,0x80cd,
+    0x81ff,0x8221,0x8294,0x82d9,0x82fe,0x82f9,0x8307,0x82e8,0x8300,0x82d5,
+    0x833a,0x82eb,0x82d6,0x82f4,0x82ec,0x82e1,0x82f2,0x82f5,0x830c,0x82fb,
+    0x82f6,0x82f0,0x82ea,0x82e4,0x82e0,0x82fa,0x82f3,0x82ed,0x8677,0x8674,
+    0x867c,0x8673,0x8841,0x884e,0x8867,0x886a,0x8869,0x89d3,0x8a04,0x8a07,
+    0x8d72,0x8fe3,0x8fe1,0x8fee,0x8fe0,0x90f1,0x90bd,0x90bf,0x90d5,0x90c5,
+    0x90be,0x90c7,0x90cb,0x90c8,0x91d4,0x91d3,0x9654,0x964f,0x9651,0x9653,
+    0x964a,0x964e,0x501e,0x5005,0x5007,0x5013,0x5022,0x5030,0x501b,0x4ff5,
+    0x4ff4,0x5033,0x5037,0x502c,0x4ff6,0x4ff7,0x5017,0x501c,0x5020,0x5027,
+    0x5035,0x502f,0x5031,0x500e
+  },
+  {				/* ku 0e */
+    0x515a,0x5194,0x5193,0x51ca,0x51c4,0x51c5,0x51c8,0x51ce,0x5261,0x525a,
+    0x5252,0x525e,0x525f,0x5255,0x5262,0x52cd,0x530e,0x539e,0x5526,0x54e2,
+    0x5517,0x5512,0x54e7,0x54f3,0x54e4,0x551a,0x54ff,0x5504,0x5508,0x54eb,
+    0x5511,0x5505,0x54f1,0x550a,0x54fb,0x54f7,0x54f8,0x54e0,0x550e,0x5503,
+    0x550b,0x5701,0x5702,0x57cc,0x5832,0x57d5,0x57d2,0x57ba,0x57c6,0x57bd,
+    0x57bc,0x57b8,0x57b6,0x57bf,0x57c7,0x57d0,0x57b9,0x57c1,0x590e,0x594a,
+    0x5a19,0x5a16,0x5a2d,0x5a2e,0x5a15,0x5a0f,0x5a17,0x5a0a,0x5a1e,0x5a33,
+    0x5b6c,0x5ba7,0x5bad,0x5bac,0x5c03,0x5c56,0x5c54,0x5cec,0x5cff,0x5cee,
+    0x5cf1,0x5cf7,0x5d00,0x5cf9,0x5e29,0x5e28,0x5ea8,0x5eae,0x5eaa,0x5eac,
+    0x5f33,0x5f30,0x5f67,0x605d
+  },
+  {				/* ku 0f */
+    0x605a,0x6067,0x6041,0x60a2,0x6088,0x6080,0x6092,0x6081,0x609d,0x6083,
+    0x6095,0x609b,0x6097,0x6087,0x609c,0x608e,0x6219,0x6246,0x62f2,0x6310,
+    0x6356,0x632c,0x6344,0x6345,0x6336,0x6343,0x63e4,0x6339,0x634b,0x634a,
+    0x633c,0x6329,0x6341,0x6334,0x6358,0x6354,0x6359,0x632d,0x6347,0x6333,
+    0x635a,0x6351,0x6338,0x6357,0x6340,0x6348,0x654a,0x6546,0x65c6,0x65c3,
+    0x65c4,0x65c2,0x664a,0x665f,0x6647,0x6651,0x6712,0x6713,0x681f,0x681a,
+    0x6849,0x6832,0x6833,0x683b,0x684b,0x684f,0x6816,0x6831,0x681c,0x6835,
+    0x682b,0x682d,0x682f,0x684e,0x6844,0x6834,0x681d,0x6812,0x6814,0x6826,
+    0x6828,0x682e,0x684d,0x683a,0x6825,0x6820,0x6b2c,0x6b2f,0x6b2d,0x6b31,
+    0x6b34,0x6b6d,0x8082,0x6b88
+  },
+  {				/* ku 10 */
+    0x6be6,0x6be4,0x6be8,0x6be3,0x6be2,0x6be7,0x6c25,0x6d7a,0x6d63,0x6d64,
+    0x6d76,0x6d0d,0x6d61,0x6d92,0x6d58,0x6d62,0x6d6d,0x6d6f,0x6d91,0x6d8d,
+    0x6def,0x6d7f,0x6d86,0x6d5e,0x6d67,0x6d60,0x6d97,0x6d70,0x6d7c,0x6d5f,
+    0x6d82,0x6d98,0x6d2f,0x6d68,0x6d8b,0x6d7e,0x6d80,0x6d84,0x6d16,0x6d83,
+    0x6d7b,0x6d7d,0x6d75,0x6d90,0x70dc,0x70d3,0x70d1,0x70dd,0x70cb,0x7f39,
+    0x70e2,0x70d7,0x70d2,0x70de,0x70e0,0x70d4,0x70cd,0x70c5,0x70c6,0x70c7,
+    0x70da,0x70ce,0x70e1,0x7242,0x7278,0x7277,0x7276,0x7300,0x72fa,0x72f4,
+    0x72fe,0x72f6,0x72f3,0x72fb,0x7301,0x73d3,0x73d9,0x73e5,0x73d6,0x73bc,
+    0x73e7,0x73e3,0x73e9,0x73dc,0x73d2,0x73db,0x73d4,0x73dd,0x73da,0x73d7,
+    0x73d8,0x73e8,0x74de,0x74df
+  },
+  {				/* ku 11 */
+    0x74f4,0x74f5,0x7521,0x755b,0x755f,0x75b0,0x75c1,0x75bb,0x75c4,0x75c0,
+    0x75bf,0x75b6,0x75ba,0x768a,0x76c9,0x771d,0x771b,0x7710,0x7713,0x7712,
+    0x7723,0x7711,0x7715,0x7719,0x771a,0x7722,0x7727,0x7823,0x782c,0x7822,
+    0x7835,0x782f,0x7828,0x782e,0x782b,0x7821,0x7829,0x7833,0x782a,0x7831,
+    0x7954,0x795b,0x794f,0x795c,0x7953,0x7952,0x7951,0x79eb,0x79ec,0x79e0,
+    0x79ee,0x79ed,0x79ea,0x79dc,0x79de,0x79dd,0x7a86,0x7a89,0x7a85,0x7a8b,
+    0x7a8c,0x7a8a,0x7a87,0x7ad8,0x7b10,0x7b04,0x7b13,0x7b05,0x7b0f,0x7b08,
+    0x7b0a,0x7b0e,0x7b09,0x7b12,0x7c84,0x7c91,0x7c8a,0x7c8c,0x7c88,0x7c8d,
+    0x7c85,0x7d1e,0x7d1d,0x7d11,0x7d0e,0x7d18,0x7d16,0x7d13,0x7d1f,0x7d12,
+    0x7d0f,0x7d0c,0x7f5c,0x7f61
+  },
+  {				/* ku 12 */
+    0x7f5e,0x7f60,0x7f5d,0x7f5b,0x7f96,0x7f92,0x7fc3,0x7fc2,0x7fc0,0x8016,
+    0x803e,0x8039,0x80fa,0x80f2,0x80f9,0x80f5,0x8101,0x80fb,0x8100,0x8201,
+    0x822f,0x8225,0x8333,0x832d,0x8344,0x8319,0x8351,0x8325,0x8356,0x833f,
+    0x8341,0x8326,0x831c,0x8322,0x8342,0x834e,0x831b,0x832a,0x8308,0x833c,
+    0x834d,0x8316,0x8324,0x8320,0x8337,0x832f,0x8329,0x8347,0x8345,0x834c,
+    0x8353,0x831e,0x832c,0x834b,0x8327,0x8348,0x8653,0x8652,0x86a2,0x86a8,
+    0x8696,0x868d,0x8691,0x869e,0x8687,0x8697,0x8686,0x868b,0x869a,0x8685,
+    0x86a5,0x8699,0x86a1,0x86a7,0x8695,0x8698,0x868e,0x869d,0x8690,0x8694,
+    0x8843,0x8844,0x886d,0x8875,0x8876,0x8872,0x8880,0x8871,0x887f,0x886f,
+    0x8883,0x887e,0x8874,0x887c
+  },
+  {				/* ku 13 */
+    0x8a12,0x8c47,0x8c57,0x8c7b,0x8ca4,0x8ca3,0x8d76,0x8d78,0x8db5,0x8db7,
+    0x8db6,0x8ed1,0x8ed3,0x8ffe,0x8ff5,0x9002,0x8fff,0x8ffb,0x9004,0x8ffc,
+    0x8ff6,0x90d6,0x90e0,0x90d9,0x90da,0x90e3,0x90df,0x90e5,0x90d8,0x90db,
+    0x90d7,0x90dc,0x90e4,0x9150,0x914e,0x914f,0x91d5,0x91e2,0x91da,0x965c,
+    0x965f,0x96bc,0x98e3,0x9adf,0x9b2f,0x4e7f,0x5070,0x506a,0x5061,0x505e,
+    0x5060,0x5053,0x504b,0x505d,0x5072,0x5048,0x504d,0x5041,0x505b,0x504a,
+    0x5062,0x5015,0x5045,0x505f,0x5069,0x506b,0x5063,0x5064,0x5046,0x5040,
+    0x506e,0x5073,0x5057,0x5051,0x51d0,0x526b,0x526d,0x526c,0x526e,0x52d6,
+    0x52d3,0x532d,0x539c,0x5575,0x5576,0x553c,0x554d,0x5550,0x5534,0x552a,
+    0x5551,0x5562,0x5536,0x5535
+  },
+  {				/* ku 14 */
+    0x5530,0x5552,0x5545,0x550c,0x5532,0x5565,0x554e,0x5539,0x5548,0x552d,
+    0x553b,0x5540,0x554b,0x570a,0x5707,0x57fb,0x5814,0x57e2,0x57f6,0x57dc,
+    0x57f4,0x5800,0x57ed,0x57fd,0x5808,0x57f8,0x580b,0x57f3,0x57cf,0x5807,
+    0x57ee,0x57e3,0x57f2,0x57e5,0x57ec,0x57e1,0x580e,0x57fc,0x5810,0x57e7,
+    0x5801,0x580c,0x57f1,0x57e9,0x57f0,0x580d,0x5804,0x595c,0x5a60,0x5a58,
+    0x5a55,0x5a67,0x5a5e,0x5a38,0x5a35,0x5a6d,0x5a50,0x5a5f,0x5a65,0x5a6c,
+    0x5a53,0x5a64,0x5a57,0x5a43,0x5a5d,0x5a52,0x5a44,0x5a5b,0x5a48,0x5a8e,
+    0x5a3e,0x5a4d,0x5a39,0x5a4c,0x5a70,0x5a69,0x5a47,0x5a51,0x5a56,0x5a42,
+    0x5a5c,0x5b72,0x5b6e,0x5bc1,0x5bc0,0x5c59,0x5d1e,0x5d0b,0x5d1d,0x5d1a,
+    0x5d20,0x5d0c,0x5d28,0x5d0d
+  },
+  {				/* ku 15 */
+    0x5d26,0x5d25,0x5d0f,0x5d30,0x5d12,0x5d23,0x5d1f,0x5d2e,0x5e3e,0x5e34,
+    0x5eb1,0x5eb4,0x5eb9,0x5eb2,0x5eb3,0x5f36,0x5f38,0x5f9b,0x5f96,0x5f9f,
+    0x608a,0x6090,0x6086,0x60be,0x60b0,0x60ba,0x60d3,0x60d4,0x60cf,0x60e4,
+    0x60d9,0x60dd,0x60c8,0x60b1,0x60db,0x60b7,0x60ca,0x60bf,0x60c3,0x60cd,
+    0x60c0,0x6332,0x6365,0x638a,0x6382,0x637d,0x63bd,0x639e,0x63ad,0x639d,
+    0x6397,0x63ab,0x638e,0x636f,0x6387,0x6390,0x636e,0x63af,0x6375,0x639c,
+    0x636d,0x63ae,0x637c,0x63a4,0x633b,0x639f,0x6378,0x6385,0x6381,0x6391,
+    0x638d,0x6370,0x6553,0x65cd,0x6665,0x6661,0x665b,0x6659,0x665c,0x6662,
+    0x6718,0x6879,0x6887,0x6890,0x689c,0x686d,0x686e,0x68ae,0x68ab,0x6956,
+    0x686f,0x68a3,0x68ac,0x68a9
+  },
+  {				/* ku 16 */
+    0x6875,0x6874,0x68b2,0x688f,0x6877,0x6892,0x687c,0x686b,0x6872,0x68aa,
+    0x6880,0x6871,0x687e,0x689b,0x6896,0x688b,0x68a0,0x6889,0x68a4,0x6878,
+    0x687b,0x6891,0x688c,0x688a,0x687d,0x6b36,0x6b33,0x6b37,0x6b38,0x6b91,
+    0x6b8f,0x6b8d,0x6b8e,0x6b8c,0x6c2a,0x6dc0,0x6dab,0x6db4,0x6db3,0x6e74,
+    0x6dac,0x6de9,0x6de2,0x6db7,0x6df6,0x6dd4,0x6e00,0x6dc8,0x6de0,0x6ddf,
+    0x6dd6,0x6dbe,0x6de5,0x6ddc,0x6ddd,0x6ddb,0x6df4,0x6dca,0x6dbd,0x6ded,
+    0x6df0,0x6dba,0x6dd5,0x6dc2,0x6dcf,0x6dc9,0x6dd0,0x6df2,0x6dd3,0x6dfd,
+    0x6dd7,0x6dcd,0x6de3,0x6dbb,0x70fa,0x710d,0x70f7,0x7117,0x70f4,0x710c,
+    0x70f0,0x7104,0x70f3,0x7110,0x70fc,0x70ff,0x7106,0x7113,0x7100,0x70f8,
+    0x70f6,0x710b,0x7102,0x710e
+  },
+  {				/* ku 17 */
+    0x727e,0x727b,0x727c,0x727f,0x731d,0x7317,0x7307,0x7311,0x7318,0x730a,
+    0x7308,0x72ff,0x730f,0x731e,0x7388,0x73f6,0x73f8,0x73f5,0x7404,0x7401,
+    0x73fd,0x7407,0x7400,0x73fa,0x73fc,0x73ff,0x740c,0x740b,0x73f4,0x7408,
+    0x7564,0x7563,0x75ce,0x75d2,0x75cf,0x75cb,0x75cc,0x75d1,0x75d0,0x768f,
+    0x7689,0x76d3,0x7739,0x772f,0x772d,0x7731,0x7732,0x7734,0x7733,0x773d,
+    0x7725,0x773b,0x7735,0x7848,0x7852,0x7849,0x784d,0x784a,0x784c,0x7826,
+    0x7845,0x7850,0x7964,0x7967,0x7969,0x796a,0x7963,0x796b,0x7961,0x79bb,
+    0x79fa,0x79f8,0x79f6,0x79f7,0x7a8f,0x7a94,0x7a90,0x7b35,0x7b3b,0x7b34,
+    0x7b25,0x7b30,0x7b22,0x7b24,0x7b33,0x7b18,0x7b2a,0x7b1d,0x7b31,0x7b2b,
+    0x7b2d,0x7b2f,0x7b32,0x7b38
+  },
+  {				/* ku 18 */
+    0x7b1a,0x7b23,0x7c94,0x7c98,0x7c96,0x7ca3,0x7d35,0x7d3d,0x7d38,0x7d36,
+    0x7d3a,0x7d45,0x7d2c,0x7d29,0x7d41,0x7d47,0x7d3e,0x7d3f,0x7d4a,0x7d3b,
+    0x7d28,0x7f63,0x7f95,0x7f9c,0x7f9d,0x7f9b,0x7fca,0x7fcb,0x7fcd,0x7fd0,
+    0x7fd1,0x7fc7,0x7fcf,0x7fc9,0x801f,0x801e,0x801b,0x8047,0x8043,0x8048,
+    0x8118,0x8125,0x8119,0x811b,0x812d,0x811f,0x812c,0x811e,0x8121,0x8115,
+    0x8127,0x811d,0x8122,0x8211,0x8238,0x8233,0x823a,0x8234,0x8232,0x8274,
+    0x8390,0x83a3,0x83a8,0x838d,0x837a,0x8373,0x83a4,0x8374,0x838f,0x8381,
+    0x8395,0x8399,0x8375,0x8394,0x83a9,0x837d,0x8383,0x838c,0x839d,0x839b,
+    0x83aa,0x838b,0x837e,0x83a5,0x83af,0x8388,0x8397,0x83b0,0x837f,0x83a6,
+    0x8387,0x83ae,0x8376,0x8659
+  },
+  {				/* ku 19 */
+    0x8656,0x86bf,0x86b7,0x86c2,0x86c1,0x86c5,0x86ba,0x86b0,0x86c8,0x86b9,
+    0x86b3,0x86b8,0x86cc,0x86b4,0x86bb,0x86bc,0x86c3,0x86bd,0x86be,0x8852,
+    0x8889,0x8895,0x88a8,0x88a2,0x88aa,0x889a,0x8891,0x88a1,0x889f,0x8898,
+    0x88a7,0x8899,0x889b,0x8897,0x88a4,0x88ac,0x888c,0x8893,0x888e,0x8982,
+    0x89d6,0x89d9,0x89d5,0x8a30,0x8a27,0x8a2c,0x8a1e,0x8c39,0x8c3b,0x8c5c,
+    0x8c5d,0x8c7d,0x8ca5,0x8d7d,0x8d7b,0x8d79,0x8dbc,0x8dc2,0x8db9,0x8dbf,
+    0x8dc1,0x8ed8,0x8ede,0x8edd,0x8edc,0x8ed7,0x8ee0,0x8ee1,0x9024,0x900b,
+    0x9011,0x901c,0x900c,0x9021,0x90ef,0x90ea,0x90f0,0x90f4,0x90f2,0x90f3,
+    0x90d4,0x90eb,0x90ec,0x90e9,0x9156,0x9158,0x915a,0x9153,0x9155,0x91ec,
+    0x91f4,0x91f1,0x91f3,0x91f8
+  },
+  {				/* ku 1a */
+    0x91e4,0x91f9,0x91ea,0x91eb,0x91f7,0x91e8,0x91ee,0x957a,0x9586,0x9588,
+    0x967c,0x966d,0x966b,0x9671,0x966f,0x96bf,0x976a,0x9804,0x98e5,0x9997,
+    0x509b,0x5095,0x5094,0x509e,0x508b,0x50a3,0x5083,0x508c,0x508e,0x509d,
+    0x5068,0x509c,0x5092,0x5082,0x5087,0x515f,0x51d4,0x5312,0x5311,0x53a4,
+    0x53a7,0x5591,0x55a8,0x55a5,0x55ad,0x5577,0x5645,0x55a2,0x5593,0x5588,
+    0x558f,0x55b5,0x5581,0x55a3,0x5592,0x55a4,0x557d,0x558c,0x55a6,0x557f,
+    0x5595,0x55a1,0x558e,0x570c,0x5829,0x5837,0x5819,0x581e,0x5827,0x5823,
+    0x5828,0x57f5,0x5848,0x5825,0x581c,0x581b,0x5833,0x583f,0x5836,0x582e,
+    0x5839,0x5838,0x582d,0x582c,0x583b,0x5961,0x5aaf,0x5a94,0x5a9f,0x5a7a,
+    0x5aa2,0x5a9e,0x5a78,0x5aa6
+  },
+  {				/* ku 1b */
+    0x5a7c,0x5aa5,0x5aac,0x5a95,0x5aae,0x5a37,0x5a84,0x5a8a,0x5a97,0x5a83,
+    0x5a8b,0x5aa9,0x5a7b,0x5a7d,0x5a8c,0x5a9c,0x5a8f,0x5a93,0x5a9d,0x5bea,
+    0x5bcd,0x5bcb,0x5bd4,0x5bd1,0x5bca,0x5bce,0x5c0c,0x5c30,0x5d37,0x5d43,
+    0x5d6b,0x5d41,0x5d4b,0x5d3f,0x5d35,0x5d51,0x5d4e,0x5d55,0x5d33,0x5d3a,
+    0x5d52,0x5d3d,0x5d31,0x5d59,0x5d42,0x5d39,0x5d49,0x5d38,0x5d3c,0x5d32,
+    0x5d36,0x5d40,0x5d45,0x5e44,0x5e41,0x5f58,0x5fa6,0x5fa5,0x5fab,0x60c9,
+    0x60b9,0x60cc,0x60e2,0x60ce,0x60c4,0x6114,0x60f2,0x610a,0x6116,0x6105,
+    0x60f5,0x6113,0x60f8,0x60fc,0x60fe,0x60c1,0x6103,0x6118,0x611d,0x6110,
+    0x60ff,0x6104,0x610b,0x624a,0x6394,0x63b1,0x63b0,0x63ce,0x63e5,0x63e8,
+    0x63ef,0x63c3,0x649d,0x63f3
+  },
+  {				/* ku 1c */
+    0x63ca,0x63e0,0x63f6,0x63d5,0x63f2,0x63f5,0x6461,0x63df,0x63be,0x63dd,
+    0x63dc,0x63c4,0x63d8,0x63d3,0x63c2,0x63c7,0x63cc,0x63cb,0x63c8,0x63f0,
+    0x63d7,0x63d9,0x6532,0x6567,0x656a,0x6564,0x655c,0x6568,0x6565,0x658c,
+    0x659d,0x659e,0x65ae,0x65d0,0x65d2,0x667c,0x666c,0x667b,0x6680,0x6671,
+    0x6679,0x666a,0x6672,0x6701,0x690c,0x68d3,0x6904,0x68dc,0x692a,0x68ec,
+    0x68ea,0x68f1,0x690f,0x68d6,0x68f7,0x68eb,0x68e4,0x68f6,0x6913,0x6910,
+    0x68f3,0x68e1,0x6907,0x68cc,0x6908,0x6970,0x68b4,0x6911,0x68ef,0x68c6,
+    0x6914,0x68f8,0x68d0,0x68fd,0x68fc,0x68e8,0x690b,0x690a,0x6917,0x68ce,
+    0x68c8,0x68dd,0x68de,0x68e6,0x68f4,0x68d1,0x6906,0x68d4,0x68e9,0x6915,
+    0x6925,0x68c7,0x6b39,0x6b3b
+  },
+  {				/* ku 1d */
+    0x6b3f,0x6b3c,0x6b94,0x6b97,0x6b99,0x6b95,0x6bbd,0x6bf0,0x6bf2,0x6bf3,
+    0x6c30,0x6dfc,0x6e46,0x6e47,0x6e1f,0x6e49,0x6e88,0x6e3c,0x6e3d,0x6e45,
+    0x6e62,0x6e2b,0x6e3f,0x6e41,0x6e5d,0x6e73,0x6e1c,0x6e33,0x6e4b,0x6e40,
+    0x6e51,0x6e3b,0x6e03,0x6e2e,0x6e5e,0x6e68,0x6e5c,0x6e61,0x6e31,0x6e28,
+    0x6e60,0x6e71,0x6e6b,0x6e39,0x6e22,0x6e30,0x6e53,0x6e65,0x6e27,0x6e78,
+    0x6e64,0x6e77,0x6e55,0x6e79,0x6e52,0x6e66,0x6e35,0x6e36,0x6e5a,0x7120,
+    0x711e,0x712f,0x70fb,0x712e,0x7131,0x7123,0x7125,0x7122,0x7132,0x711f,
+    0x7128,0x713a,0x711b,0x724b,0x725a,0x7288,0x7289,0x7286,0x7285,0x728b,
+    0x7312,0x730b,0x7330,0x7322,0x7331,0x7333,0x7327,0x7332,0x732d,0x7326,
+    0x7323,0x7335,0x730c,0x742e
+  },
+  {				/* ku 1e */
+    0x742c,0x7430,0x742b,0x7416,0x741a,0x7421,0x742d,0x7431,0x7424,0x7423,
+    0x741d,0x7429,0x7420,0x7432,0x74fb,0x752f,0x756f,0x756c,0x75e7,0x75da,
+    0x75e1,0x75e6,0x75dd,0x75df,0x75e4,0x75d7,0x7695,0x7692,0x76da,0x7746,
+    0x7747,0x7744,0x774d,0x7745,0x774a,0x774e,0x774b,0x774c,0x77de,0x77ec,
+    0x7860,0x7864,0x7865,0x785c,0x786d,0x7871,0x786a,0x786e,0x7870,0x7869,
+    0x7868,0x785e,0x7862,0x7974,0x7973,0x7972,0x7970,0x7a02,0x7a0a,0x7a03,
+    0x7a0c,0x7a04,0x7a99,0x7ae6,0x7ae4,0x7b4a,0x7b47,0x7b44,0x7b48,0x7b4c,
+    0x7b4e,0x7b40,0x7b58,0x7b45,0x7ca2,0x7c9e,0x7ca8,0x7ca1,0x7d58,0x7d6f,
+    0x7d63,0x7d53,0x7d56,0x7d67,0x7d6a,0x7d4f,0x7d6d,0x7d5c,0x7d6b,0x7d52,
+    0x7d54,0x7d69,0x7d51,0x7d5f
+  },
+  {				/* ku 1f */
+    0x7d4e,0x7f3e,0x7f3f,0x7f65,0x7f66,0x7fa2,0x7fa0,0x7fa1,0x7fd7,0x8051,
+    0x804f,0x8050,0x80fe,0x80d4,0x8143,0x814a,0x8152,0x814f,0x8147,0x813d,
+    0x814d,0x813a,0x81e6,0x81ee,0x81f7,0x81f8,0x81f9,0x8204,0x823c,0x823d,
+    0x823f,0x8275,0x833b,0x83cf,0x83f9,0x8423,0x83c0,0x83e8,0x8412,0x83e7,
+    0x83e4,0x83fc,0x83f6,0x8410,0x83c6,0x83c8,0x83eb,0x83e3,0x83bf,0x8401,
+    0x83dd,0x83e5,0x83d8,0x83ff,0x83e1,0x83cb,0x83ce,0x83d6,0x83f5,0x83c9,
+    0x8409,0x840f,0x83de,0x8411,0x8406,0x83c2,0x83f3,0x83d5,0x83fa,0x83c7,
+    0x83d1,0x83ea,0x8413,0x839a,0x83c3,0x83ec,0x83ee,0x83c4,0x83fb,0x83d7,
+    0x83e2,0x841b,0x83db,0x83fe,0x86d8,0x86e2,0x86e6,0x86d3,0x86e3,0x86da,
+    0x86ea,0x86dd,0x86eb,0x86dc
+  },
+  {				/* ku 20 */
+    0x86ec,0x86e9,0x86d7,0x86e8,0x86d1,0x8848,0x8856,0x8855,0x88ba,0x88d7,
+    0x88b9,0x88b8,0x88c0,0x88be,0x88b6,0x88bc,0x88b7,0x88bd,0x88b2,0x8901,
+    0x88c9,0x8995,0x8998,0x8997,0x89dd,0x89da,0x89db,0x8a4e,0x8a4d,0x8a39,
+    0x8a59,0x8a40,0x8a57,0x8a58,0x8a44,0x8a45,0x8a52,0x8a48,0x8a51,0x8a4a,
+    0x8a4c,0x8a4f,0x8c5f,0x8c81,0x8c80,0x8cba,0x8cbe,0x8cb0,0x8cb9,0x8cb5,
+    0x8d84,0x8d80,0x8d89,0x8dd8,0x8dd3,0x8dcd,0x8dc7,0x8dd6,0x8ddc,0x8dcf,
+    0x8dd5,0x8dd9,0x8dc8,0x8dd7,0x8dc5,0x8eef,0x8ef7,0x8efa,0x8ef9,0x8ee6,
+    0x8eee,0x8ee5,0x8ef5,0x8ee7,0x8ee8,0x8ef6,0x8eeb,0x8ef1,0x8eec,0x8ef4,
+    0x8ee9,0x902d,0x9034,0x902f,0x9106,0x912c,0x9104,0x90ff,0x90fc,0x9108,
+    0x90f9,0x90fb,0x9101,0x9100
+  },
+  {				/* ku 21 */
+    0x9107,0x9105,0x9103,0x9161,0x9164,0x915f,0x9162,0x9160,0x9201,0x920a,
+    0x9225,0x9203,0x921a,0x9226,0x920f,0x920c,0x9200,0x9212,0x91ff,0x91fd,
+    0x9206,0x9204,0x9227,0x9202,0x921c,0x9224,0x9219,0x9217,0x9205,0x9216,
+    0x957b,0x958d,0x958c,0x9590,0x9687,0x967e,0x9688,0x9689,0x9683,0x9680,
+    0x96c2,0x96c8,0x96c3,0x96f1,0x96f0,0x976c,0x9770,0x976e,0x9807,0x98a9,
+    0x98eb,0x9ce6,0x9ef9,0x4e83,0x4e84,0x4eb6,0x50bd,0x50bf,0x50c6,0x50ae,
+    0x50c4,0x50ca,0x50b4,0x50c8,0x50c2,0x50b0,0x50c1,0x50ba,0x50b1,0x50cb,
+    0x50c9,0x50b6,0x50b8,0x51d7,0x527a,0x5278,0x527b,0x527c,0x55c3,0x55db,
+    0x55cc,0x55d0,0x55cb,0x55ca,0x55dd,0x55c0,0x55d4,0x55c4,0x55e9,0x55bf,
+    0x55d2,0x558d,0x55cf,0x55d5
+  },
+  {				/* ku 22 */
+    0x55e2,0x55d6,0x55c8,0x55f2,0x55cd,0x55d9,0x55c2,0x5714,0x5853,0x5868,
+    0x5864,0x584f,0x584d,0x5849,0x586f,0x5855,0x584e,0x585d,0x5859,0x5865,
+    0x585b,0x583d,0x5863,0x5871,0x58fc,0x5ac7,0x5ac4,0x5acb,0x5aba,0x5ab8,
+    0x5ab1,0x5ab5,0x5ab0,0x5abf,0x5ac8,0x5abb,0x5ac6,0x5ab7,0x5ac0,0x5aca,
+    0x5ab4,0x5ab6,0x5acd,0x5ab9,0x5a90,0x5bd6,0x5bd8,0x5bd9,0x5c1f,0x5c33,
+    0x5d71,0x5d63,0x5d4a,0x5d65,0x5d72,0x5d6c,0x5d5e,0x5d68,0x5d67,0x5d62,
+    0x5df0,0x5e4f,0x5e4e,0x5e4a,0x5e4d,0x5e4b,0x5ec5,0x5ecc,0x5ec6,0x5ecb,
+    0x5ec7,0x5f40,0x5faf,0x5fad,0x60f7,0x6149,0x614a,0x612b,0x6145,0x6136,
+    0x6132,0x612e,0x6146,0x612f,0x614f,0x6129,0x6140,0x6220,0x9168,0x6223,
+    0x6225,0x6224,0x63c5,0x63f1
+  },
+  {				/* ku 23 */
+    0x63eb,0x6410,0x6412,0x6409,0x6420,0x6424,0x6433,0x6443,0x641f,0x6415,
+    0x6418,0x6439,0x6437,0x6422,0x6423,0x640c,0x6426,0x6430,0x6428,0x6441,
+    0x6435,0x642f,0x640a,0x641a,0x6440,0x6425,0x6427,0x640b,0x63e7,0x641b,
+    0x642e,0x6421,0x640e,0x656f,0x6592,0x65d3,0x6686,0x668c,0x6695,0x6690,
+    0x668b,0x668a,0x6699,0x6694,0x6678,0x6720,0x6966,0x695f,0x6938,0x694e,
+    0x6962,0x6971,0x693f,0x6945,0x696a,0x6939,0x6942,0x6957,0x6959,0x697a,
+    0x6948,0x6949,0x6935,0x696c,0x6933,0x693d,0x6965,0x68f0,0x6978,0x6934,
+    0x6969,0x6940,0x696f,0x6944,0x6976,0x6958,0x6941,0x6974,0x694c,0x693b,
+    0x694b,0x6937,0x695c,0x694f,0x6951,0x6932,0x6952,0x692f,0x697b,0x693c,
+    0x6b46,0x6b45,0x6b43,0x6b42
+  },
+  {				/* ku 24 */
+    0x6b48,0x6b41,0x6b9b,0x6bfb,0x6bfc,0x6bf9,0x6bf7,0x6bf8,0x6e9b,0x6ed6,
+    0x6ec8,0x6e8f,0x6ec0,0x6e9f,0x6e93,0x6e94,0x6ea0,0x6eb1,0x6eb9,0x6ec6,
+    0x6ed2,0x6ebd,0x6ec1,0x6e9e,0x6ec9,0x6eb7,0x6eb0,0x6ecd,0x6ea6,0x6ecf,
+    0x6eb2,0x6ebe,0x6ec3,0x6edc,0x6ed8,0x6e99,0x6e92,0x6e8e,0x6e8d,0x6ea4,
+    0x6ea1,0x6ebf,0x6eb3,0x6ed0,0x6eca,0x6e97,0x6eae,0x6ea3,0x7147,0x7154,
+    0x7152,0x7163,0x7160,0x7141,0x715d,0x7162,0x7172,0x7178,0x716a,0x7161,
+    0x7142,0x7158,0x7143,0x714b,0x7170,0x715f,0x7150,0x7153,0x7144,0x714d,
+    0x715a,0x724f,0x728d,0x728c,0x7291,0x7290,0x728e,0x733c,0x7342,0x733b,
+    0x733a,0x7340,0x734a,0x7349,0x7444,0x744a,0x744b,0x7452,0x7451,0x7457,
+    0x7440,0x744f,0x7450,0x744e
+  },
+  {				/* ku 25 */
+    0x7442,0x7446,0x744d,0x7454,0x74e1,0x74ff,0x74fe,0x74fd,0x751d,0x7579,
+    0x7577,0x6983,0x75ef,0x760f,0x7603,0x75f7,0x75fe,0x75fc,0x75f9,0x75f8,
+    0x7610,0x75fb,0x75f6,0x75ed,0x75f5,0x75fd,0x7699,0x76b5,0x76dd,0x7755,
+    0x775f,0x7760,0x7752,0x7756,0x775a,0x7769,0x7767,0x7754,0x7759,0x776d,
+    0x77e0,0x7887,0x789a,0x7894,0x788f,0x7884,0x7895,0x7885,0x7886,0x78a1,
+    0x7883,0x7879,0x7899,0x7880,0x7896,0x787b,0x797c,0x7982,0x797d,0x7979,
+    0x7a11,0x7a18,0x7a19,0x7a12,0x7a17,0x7a15,0x7a22,0x7a13,0x7a1b,0x7a10,
+    0x7aa3,0x7aa2,0x7a9e,0x7aeb,0x7b66,0x7b64,0x7b6d,0x7b74,0x7b69,0x7b72,
+    0x7b65,0x7b73,0x7b71,0x7b70,0x7b61,0x7b78,0x7b76,0x7b63,0x7cb2,0x7cb4,
+    0x7caf,0x7d88,0x7d86,0x7d80
+  },
+  {				/* ku 26 */
+    0x7d8d,0x7d7f,0x7d85,0x7d7a,0x7d8e,0x7d7b,0x7d83,0x7d7c,0x7d8c,0x7d94,
+    0x7d84,0x7d7d,0x7d92,0x7f6d,0x7f6b,0x7f67,0x7f68,0x7f6c,0x7fa6,0x7fa5,
+    0x7fa7,0x7fdb,0x7fdc,0x8021,0x8164,0x8160,0x8177,0x815c,0x8169,0x815b,
+    0x8162,0x8172,0x6721,0x815e,0x8176,0x8167,0x816f,0x8144,0x8161,0x821d,
+    0x8249,0x8244,0x8240,0x8242,0x8245,0x84f1,0x843f,0x8456,0x8476,0x8479,
+    0x848f,0x848d,0x8465,0x8451,0x8440,0x8486,0x8467,0x8430,0x844d,0x847d,
+    0x845a,0x8459,0x8474,0x8473,0x845d,0x8507,0x845e,0x8437,0x843a,0x8434,
+    0x847a,0x8443,0x8478,0x8432,0x8445,0x8429,0x83d9,0x844b,0x842f,0x8442,
+    0x842d,0x845f,0x8470,0x8439,0x844e,0x844c,0x8452,0x846f,0x84c5,0x848e,
+    0x843b,0x8447,0x8436,0x8433
+  },
+  {				/* ku 27 */
+    0x8468,0x847e,0x8444,0x842b,0x8460,0x8454,0x846e,0x8450,0x870b,0x8704,
+    0x86f7,0x870c,0x86fa,0x86d6,0x86f5,0x874d,0x86f8,0x870e,0x8709,0x8701,
+    0x86f6,0x870d,0x8705,0x88d6,0x88cb,0x88cd,0x88ce,0x88de,0x88db,0x88da,
+    0x88cc,0x88d0,0x8985,0x899b,0x89df,0x89e5,0x89e4,0x89e1,0x89e0,0x89e2,
+    0x89dc,0x89e6,0x8a76,0x8a86,0x8a7f,0x8a61,0x8a3f,0x8a77,0x8a82,0x8a84,
+    0x8a75,0x8a83,0x8a81,0x8a74,0x8a7a,0x8c3c,0x8c4b,0x8c4a,0x8c65,0x8c64,
+    0x8c66,0x8c86,0x8c84,0x8c85,0x8ccc,0x8d68,0x8d69,0x8d91,0x8d8c,0x8d8e,
+    0x8d8f,0x8d8d,0x8d93,0x8d94,0x8d90,0x8d92,0x8df0,0x8de0,0x8dec,0x8df1,
+    0x8dee,0x8dd0,0x8de9,0x8de3,0x8de2,0x8de7,0x8df2,0x8deb,0x8df4,0x8f06,
+    0x8eff,0x8f01,0x8f00,0x8f05
+  },
+  {				/* ku 28 */
+    0x8f07,0x8f08,0x8f02,0x8f0b,0x9052,0x903f,0x9044,0x9049,0x903d,0x9110,
+    0x910d,0x910f,0x9111,0x9116,0x9114,0x910b,0x910e,0x916e,0x916f,0x9248,
+    0x9252,0x9230,0x923a,0x9266,0x9233,0x9265,0x925e,0x9283,0x922e,0x924a,
+    0x9246,0x926d,0x926c,0x924f,0x9260,0x9267,0x926f,0x9236,0x9261,0x9270,
+    0x9231,0x9254,0x9263,0x9250,0x9272,0x924e,0x9253,0x924c,0x9256,0x9232,
+    0x959f,0x959c,0x959e,0x959b,0x9692,0x9693,0x9691,0x9697,0x96ce,0x96fa,
+    0x96fd,0x96f8,0x96f5,0x9773,0x9777,0x9778,0x9772,0x980f,0x980d,0x980e,
+    0x98ac,0x98f6,0x98f9,0x99af,0x99b2,0x99b0,0x99b5,0x9aad,0x9aab,0x9b5b,
+    0x9cea,0x9ced,0x9ce7,0x9e80,0x9efd,0x50e6,0x50d4,0x50d7,0x50e8,0x50f3,
+    0x50db,0x50ea,0x50dd,0x50e4
+  },
+  {				/* ku 29 */
+    0x50d3,0x50ec,0x50f0,0x50ef,0x50e3,0x50e0,0x51d8,0x5280,0x5281,0x52e9,
+    0x52eb,0x5330,0x53ac,0x5627,0x5615,0x560c,0x5612,0x55fc,0x560f,0x561c,
+    0x5601,0x5613,0x5602,0x55fa,0x561d,0x5604,0x55ff,0x55f9,0x5889,0x587c,
+    0x5890,0x5898,0x5886,0x5881,0x587f,0x5874,0x588b,0x587a,0x5887,0x5891,
+    0x588e,0x5876,0x5882,0x5888,0x587b,0x5894,0x588f,0x58fe,0x596b,0x5adc,
+    0x5aee,0x5ae5,0x5ad5,0x5aea,0x5ada,0x5aed,0x5aeb,0x5af3,0x5ae2,0x5ae0,
+    0x5adb,0x5aec,0x5ade,0x5add,0x5ad9,0x5ae8,0x5adf,0x5b77,0x5be0,0x5be3,
+    0x5c63,0x5d82,0x5d80,0x5d7d,0x5d86,0x5d7a,0x5d81,0x5d77,0x5d8a,0x5d89,
+    0x5d88,0x5d7e,0x5d7c,0x5d8d,0x5d79,0x5d7f,0x5e58,0x5e59,0x5e53,0x5ed8,
+    0x5ed1,0x5ed7,0x5ece,0x5edc
+  },
+  {				/* ku 2a */
+    0x5ed5,0x5ed9,0x5ed2,0x5ed4,0x5f44,0x5f43,0x5f6f,0x5fb6,0x612c,0x6128,
+    0x6141,0x615e,0x6171,0x6173,0x6152,0x6153,0x6172,0x616c,0x6180,0x6174,
+    0x6154,0x617a,0x615b,0x6165,0x613b,0x616a,0x6161,0x6156,0x6229,0x6227,
+    0x622b,0x642b,0x644d,0x645b,0x645d,0x6474,0x6476,0x6472,0x6473,0x647d,
+    0x6475,0x6466,0x64a6,0x644e,0x6482,0x645e,0x645c,0x644b,0x6453,0x6460,
+    0x6450,0x647f,0x643f,0x646c,0x646b,0x6459,0x6465,0x6477,0x6573,0x65a0,
+    0x66a1,0x66a0,0x669f,0x6705,0x6704,0x6722,0x69b1,0x69b6,0x69c9,0x69a0,
+    0x69ce,0x6996,0x69b0,0x69ac,0x69bc,0x6991,0x6999,0x698e,0x69a7,0x698d,
+    0x69a9,0x69be,0x69af,0x69bf,0x69c4,0x69bd,0x69a4,0x69d4,0x69b9,0x69ca,
+    0x699a,0x69cf,0x69b3,0x6993
+  },
+  {				/* ku 2b */
+    0x69aa,0x69a1,0x699e,0x69d9,0x6997,0x6990,0x69c2,0x69b5,0x69a5,0x69c6,
+    0x6b4a,0x6b4d,0x6b4b,0x6b9e,0x6b9f,0x6ba0,0x6bc3,0x6bc4,0x6bfe,0x6ece,
+    0x6ef5,0x6ef1,0x6f03,0x6f25,0x6ef8,0x6f37,0x6efb,0x6f2e,0x6f09,0x6f4e,
+    0x6f19,0x6f1a,0x6f27,0x6f18,0x6f3b,0x6f12,0x6eed,0x6f0a,0x6f36,0x6f73,
+    0x6ef9,0x6eee,0x6f2d,0x6f40,0x6f30,0x6f3c,0x6f35,0x6eeb,0x6f07,0x6f0e,
+    0x6f43,0x6f05,0x6efd,0x6ef6,0x6f39,0x6f1c,0x6efc,0x6f3a,0x6f1f,0x6f0d,
+    0x6f1e,0x6f08,0x6f21,0x7187,0x7190,0x7189,0x7180,0x7185,0x7182,0x718f,
+    0x717b,0x7186,0x7181,0x7197,0x7244,0x7253,0x7297,0x7295,0x7293,0x7343,
+    0x734d,0x7351,0x734c,0x7462,0x7473,0x7471,0x7475,0x7472,0x7467,0x746e,
+    0x7500,0x7502,0x7503,0x757d
+  },
+  {				/* ku 2c */
+    0x7590,0x7616,0x7608,0x760c,0x7615,0x7611,0x760a,0x7614,0x76b8,0x7781,
+    0x777c,0x7785,0x7782,0x776e,0x7780,0x776f,0x777e,0x7783,0x78b2,0x78aa,
+    0x78b4,0x78ad,0x78a8,0x787e,0x78ab,0x789e,0x78a5,0x78a0,0x78ac,0x78a2,
+    0x78a4,0x7998,0x798a,0x798b,0x7996,0x7995,0x7994,0x7993,0x7997,0x7988,
+    0x7992,0x7990,0x7a2b,0x7a4a,0x7a30,0x7a2f,0x7a28,0x7a26,0x7aa8,0x7aab,
+    0x7aac,0x7aee,0x7b88,0x7b9c,0x7b8a,0x7b91,0x7b90,0x7b96,0x7b8d,0x7b8c,
+    0x7b9b,0x7b8e,0x7b85,0x7b98,0x5284,0x7b99,0x7ba4,0x7b82,0x7cbb,0x7cbf,
+    0x7cbc,0x7cba,0x7da7,0x7db7,0x7dc2,0x7da3,0x7daa,0x7dc1,0x7dc0,0x7dc5,
+    0x7d9d,0x7dce,0x7dc4,0x7dc6,0x7dcb,0x7dcc,0x7daf,0x7db9,0x7d96,0x7dbc,
+    0x7d9f,0x7da6,0x7dae,0x7da9
+  },
+  {				/* ku 2d */
+    0x7da1,0x7dc9,0x7f73,0x7fe2,0x7fe3,0x7fe5,0x7fde,0x8024,0x805d,0x805c,
+    0x8189,0x8186,0x8183,0x8187,0x818d,0x818c,0x818b,0x8215,0x8497,0x84a4,
+    0x84a1,0x849f,0x84ba,0x84ce,0x84c2,0x84ac,0x84ae,0x84ab,0x84b9,0x84b4,
+    0x84c1,0x84cd,0x84aa,0x849a,0x84b1,0x84d0,0x849d,0x84a7,0x84bb,0x84a2,
+    0x8494,0x84c7,0x84cc,0x849b,0x84a9,0x84af,0x84a8,0x84d6,0x8498,0x84b6,
+    0x84cf,0x84a0,0x84d7,0x84d4,0x84d2,0x84db,0x84b0,0x8491,0x8661,0x8733,
+    0x8723,0x8728,0x876b,0x8740,0x872e,0x871e,0x8721,0x8719,0x871b,0x8743,
+    0x872c,0x8741,0x873e,0x8746,0x8720,0x8732,0x872a,0x872d,0x873c,0x8712,
+    0x873a,0x8731,0x8735,0x8742,0x8726,0x8727,0x8738,0x8724,0x871a,0x8730,
+    0x8711,0x88f7,0x88e7,0x88f1
+  },
+  {				/* ku 2e */
+    0x88f2,0x88fa,0x88fe,0x88ee,0x88fc,0x88f6,0x88fb,0x88f0,0x88ec,0x88eb,
+    0x899d,0x89a1,0x899f,0x899e,0x89e9,0x89eb,0x89e8,0x8aab,0x8a99,0x8a8b,
+    0x8a92,0x8a8f,0x8a96,0x8c3d,0x8c68,0x8c69,0x8cd5,0x8ccf,0x8cd7,0x8d96,
+    0x8e09,0x8e02,0x8dff,0x8e0d,0x8dfd,0x8e0a,0x8e03,0x8e07,0x8e06,0x8e05,
+    0x8dfe,0x8e00,0x8e04,0x8f10,0x8f11,0x8f0e,0x8f0d,0x9123,0x911c,0x9120,
+    0x9122,0x911f,0x911d,0x911a,0x9124,0x9121,0x911b,0x917a,0x9172,0x9179,
+    0x9173,0x92a5,0x92a4,0x9276,0x929b,0x927a,0x92a0,0x9294,0x92aa,0x928d,
+    0x92a6,0x929a,0x92ab,0x9279,0x9297,0x927f,0x92a3,0x92ee,0x928e,0x9282,
+    0x9295,0x92a2,0x927d,0x9288,0x92a1,0x928a,0x9286,0x928c,0x9299,0x92a7,
+    0x927e,0x9287,0x92a9,0x929d
+  },
+  {				/* ku 2f */
+    0x928b,0x922d,0x969e,0x96a1,0x96ff,0x9758,0x977d,0x977a,0x977e,0x9783,
+    0x9780,0x9782,0x977b,0x9784,0x9781,0x977f,0x97ce,0x97cd,0x9816,0x98ad,
+    0x98ae,0x9902,0x9900,0x9907,0x999d,0x999c,0x99c3,0x99b9,0x99bb,0x99ba,
+    0x99c2,0x99bd,0x99c7,0x9ab1,0x9ae3,0x9ae7,0x9b3e,0x9b3f,0x9b60,0x9b61,
+    0x9b5f,0x9cf1,0x9cf2,0x9cf5,0x9ea7,0x50ff,0x5103,0x5130,0x50f8,0x5106,
+    0x5107,0x50f6,0x50fe,0x510b,0x510c,0x50fd,0x510a,0x528b,0x528c,0x52f1,
+    0x52ef,0x5648,0x5642,0x564c,0x5635,0x5641,0x564a,0x5649,0x5646,0x5658,
+    0x565a,0x5640,0x5633,0x563d,0x562c,0x563e,0x5638,0x562a,0x563a,0x571a,
+    0x58ab,0x589d,0x58b1,0x58a0,0x58a3,0x58af,0x58ac,0x58a5,0x58a1,0x58ff,
+    0x5aff,0x5af4,0x5afd,0x5af7
+  },
+  {				/* ku 30 */
+    0x5af6,0x5b03,0x5af8,0x5b02,0x5af9,0x5b01,0x5b07,0x5b05,0x5b0f,0x5c67,
+    0x5d99,0x5d97,0x5d9f,0x5d92,0x5da2,0x5d93,0x5d95,0x5da0,0x5d9c,0x5da1,
+    0x5d9a,0x5d9e,0x5e69,0x5e5d,0x5e60,0x5e5c,0x7df3,0x5edb,0x5ede,0x5ee1,
+    0x5f49,0x5fb2,0x618b,0x6183,0x6179,0x61b1,0x61b0,0x61a2,0x6189,0x619b,
+    0x6193,0x61af,0x61ad,0x619f,0x6192,0x61aa,0x61a1,0x618d,0x6166,0x61b3,
+    0x622d,0x646e,0x6470,0x6496,0x64a0,0x6485,0x6497,0x649c,0x648f,0x648b,
+    0x648a,0x648c,0x64a3,0x649f,0x6468,0x64b1,0x6498,0x6576,0x657a,0x6579,
+    0x657b,0x65b2,0x65b3,0x66b5,0x66b0,0x66a9,0x66b2,0x66b7,0x66aa,0x66af,
+    0x6a00,0x6a06,0x6a17,0x69e5,0x69f8,0x6a15,0x69f1,0x69e4,0x6a20,0x69ff,
+    0x69ec,0x69e2,0x6a1b,0x6a1d
+  },
+  {				/* ku 31 */
+    0x69fe,0x6a27,0x69f2,0x69ee,0x6a14,0x69f7,0x69e7,0x6a40,0x6a08,0x69e6,
+    0x69fb,0x6a0d,0x69fc,0x69eb,0x6a09,0x6a04,0x6a18,0x6a25,0x6a0f,0x69f6,
+    0x6a26,0x6a07,0x69f4,0x6a16,0x6b51,0x6ba5,0x6ba3,0x6ba2,0x6ba6,0x6c01,
+    0x6c00,0x6bff,0x6c02,0x6f41,0x6f26,0x6f7e,0x6f87,0x6fc6,0x6f92,0x6f8d,
+    0x6f89,0x6f8c,0x6f62,0x6f4f,0x6f85,0x6f5a,0x6f96,0x6f76,0x6f6c,0x6f82,
+    0x6f55,0x6f72,0x6f52,0x6f50,0x6f57,0x6f94,0x6f93,0x6f5d,0x6f00,0x6f61,
+    0x6f6b,0x6f7d,0x6f67,0x6f90,0x6f53,0x6f8b,0x6f69,0x6f7f,0x6f95,0x6f63,
+    0x6f77,0x6f6a,0x6f7b,0x71b2,0x71af,0x719b,0x71b0,0x71a0,0x719a,0x71a9,
+    0x71b5,0x719d,0x71a5,0x719e,0x71a4,0x71a1,0x71aa,0x719c,0x71a7,0x71b3,
+    0x7298,0x729a,0x7358,0x7352
+  },
+  {				/* ku 32 */
+    0x735e,0x735f,0x7360,0x735d,0x735b,0x7361,0x735a,0x7359,0x7362,0x7487,
+    0x7489,0x748a,0x7486,0x7481,0x747d,0x7485,0x7488,0x747c,0x7479,0x7508,
+    0x7507,0x757e,0x7625,0x761e,0x7619,0x761d,0x761c,0x7623,0x761a,0x7628,
+    0x761b,0x769c,0x769d,0x769e,0x769b,0x778d,0x778f,0x7789,0x7788,0x78cd,
+    0x78bb,0x78cf,0x78cc,0x78d1,0x78ce,0x78d4,0x78c8,0x78c3,0x78c4,0x78c9,
+    0x799a,0x79a1,0x79a0,0x799c,0x79a2,0x799b,0x6b76,0x7a39,0x7ab2,0x7ab4,
+    0x7ab3,0x7bb7,0x7bcb,0x7bbe,0x7bac,0x7bce,0x7baf,0x7bb9,0x7bca,0x7bb5,
+    0x7cc5,0x7cc8,0x7ccc,0x7ccb,0x7df7,0x7ddb,0x7dea,0x7de7,0x7dd7,0x7de1,
+    0x7e03,0x7dfa,0x7de6,0x7df6,0x7df1,0x7df0,0x7dee,0x7ddf,0x7f76,0x7fac,
+    0x7fb0,0x7fad,0x7fed,0x7feb
+  },
+  {				/* ku 33 */
+    0x7fea,0x7fec,0x7fe6,0x7fe8,0x8064,0x8067,0x81a3,0x819f,0x819e,0x8195,
+    0x81a2,0x8199,0x8197,0x8216,0x824f,0x8253,0x8252,0x8250,0x824e,0x8251,
+    0x8524,0x853b,0x850f,0x8500,0x8529,0x850e,0x8509,0x850d,0x851f,0x850a,
+    0x8527,0x851c,0x84fb,0x852b,0x84fa,0x8508,0x850c,0x84f4,0x852a,0x84f2,
+    0x8515,0x84f7,0x84eb,0x84f3,0x84fc,0x8512,0x84ea,0x84e9,0x8516,0x84fe,
+    0x8528,0x851d,0x852e,0x8502,0x84fd,0x851e,0x84f6,0x8531,0x8526,0x84e7,
+    0x84e8,0x84f0,0x84ef,0x84f9,0x8518,0x8520,0x8530,0x850b,0x8519,0x852f,
+    0x8662,0x8756,0x8763,0x8764,0x8777,0x87e1,0x8773,0x8758,0x8754,0x875b,
+    0x8752,0x8761,0x875a,0x8751,0x875e,0x876d,0x876a,0x8750,0x874e,0x875f,
+    0x875d,0x876f,0x876c,0x877a
+  },
+  {				/* ku 34 */
+    0x876e,0x875c,0x8765,0x874f,0x877b,0x8775,0x8762,0x8767,0x8769,0x885a,
+    0x8905,0x890c,0x8914,0x890b,0x8917,0x8918,0x8919,0x8906,0x8916,0x8911,
+    0x890e,0x8909,0x89a2,0x89a4,0x89a3,0x89ed,0x89f0,0x89ec,0x8acf,0x8ac6,
+    0x8ab8,0x8ad3,0x8ad1,0x8ad4,0x8ad5,0x8abb,0x8ad7,0x8abe,0x8ac0,0x8ac5,
+    0x8ad8,0x8ac3,0x8aba,0x8abd,0x8ad9,0x8c3e,0x8c4d,0x8c8f,0x8ce5,0x8cdf,
+    0x8cd9,0x8ce8,0x8cda,0x8cdd,0x8ce7,0x8da0,0x8d9c,0x8da1,0x8d9b,0x8e20,
+    0x8e23,0x8e25,0x8e24,0x8e2e,0x8e15,0x8e1b,0x8e16,0x8e11,0x8e19,0x8e26,
+    0x8e27,0x8e14,0x8e12,0x8e18,0x8e13,0x8e1c,0x8e17,0x8e1a,0x8f2c,0x8f24,
+    0x8f18,0x8f1a,0x8f20,0x8f23,0x8f16,0x8f17,0x9073,0x9070,0x906f,0x9067,
+    0x906b,0x912f,0x912b,0x9129
+  },
+  {				/* ku 35 */
+    0x912a,0x9132,0x9126,0x912e,0x9185,0x9186,0x918a,0x9181,0x9182,0x9184,
+    0x9180,0x92d0,0x92c3,0x92c4,0x92c0,0x92d9,0x92b6,0x92cf,0x92f1,0x92df,
+    0x92d8,0x92e9,0x92d7,0x92dd,0x92cc,0x92ef,0x92c2,0x92e8,0x92ca,0x92c8,
+    0x92ce,0x92e6,0x92cd,0x92d5,0x92c9,0x92e0,0x92de,0x92e7,0x92d1,0x92d3,
+    0x92b5,0x92e1,0x9325,0x92c6,0x92b4,0x957c,0x95ac,0x95ab,0x95ae,0x95b0,
+    0x96a4,0x96a2,0x96d3,0x9705,0x9708,0x9702,0x975a,0x978a,0x978e,0x9788,
+    0x97d0,0x97cf,0x981e,0x981d,0x9826,0x9829,0x9828,0x9820,0x981b,0x9827,
+    0x98b2,0x9908,0x98fa,0x9911,0x9914,0x9916,0x9917,0x9915,0x99dc,0x99cd,
+    0x99cf,0x99d3,0x99d4,0x99ce,0x99c9,0x99d6,0x99d8,0x99cb,0x99d7,0x99cc,
+    0x9ab3,0x9aec,0x9aeb,0x9af3
+  },
+  {				/* ku 36 */
+    0x9af2,0x9af1,0x9b46,0x9b43,0x9b67,0x9b74,0x9b71,0x9b66,0x9b76,0x9b75,
+    0x9b70,0x9b68,0x9b64,0x9b6c,0x9cfc,0x9cfa,0x9cfd,0x9cff,0x9cf7,0x9d07,
+    0x9d00,0x9cf9,0x9cfb,0x9d08,0x9d05,0x9d04,0x9e83,0x9ed3,0x9f0f,0x9f10,
+    0x511c,0x5113,0x5117,0x511a,0x5111,0x51de,0x5334,0x53e1,0x5670,0x5660,
+    0x566e,0x5673,0x5666,0x5663,0x566d,0x5672,0x565e,0x5677,0x571c,0x571b,
+    0x58c8,0x58bd,0x58c9,0x58bf,0x58ba,0x58c2,0x58bc,0x58c6,0x5b17,0x5b19,
+    0x5b1b,0x5b21,0x5b14,0x5b13,0x5b10,0x5b16,0x5b28,0x5b1a,0x5b20,0x5b1e,
+    0x5bef,0x5dac,0x5db1,0x5da9,0x5da7,0x5db5,0x5db0,0x5dae,0x5daa,0x5da8,
+    0x5db2,0x5dad,0x5daf,0x5db4,0x5e67,0x5e68,0x5e66,0x5e6f,0x5ee9,0x5ee7,
+    0x5ee6,0x5ee8,0x5ee5,0x5f4b
+  },
+  {				/* ku 37 */
+    0x5fbc,0x5fbb,0x619d,0x61a8,0x6196,0x61c5,0x61b4,0x61c6,0x61c1,0x61cc,
+    0x61ba,0x61bf,0x61b8,0x618c,0x64d7,0x64d6,0x64d0,0x64cf,0x64c9,0x64bd,
+    0x6489,0x64c3,0x64db,0x64f3,0x64d9,0x6533,0x657f,0x657c,0x65a2,0x66c8,
+    0x66be,0x66c0,0x66ca,0x66cb,0x66cf,0x66bd,0x66bb,0x66ba,0x66cc,0x6723,
+    0x6a34,0x6a66,0x6a49,0x6a67,0x6a32,0x6a68,0x6a3e,0x6a5d,0x6a6d,0x6a76,
+    0x6a5b,0x6a51,0x6a28,0x6a5a,0x6a3b,0x6a3f,0x6a41,0x6a6a,0x6a64,0x6a50,
+    0x6a4f,0x6a54,0x6a6f,0x6a69,0x6a60,0x6a3c,0x6a5e,0x6a56,0x6a55,0x6a4d,
+    0x6a4e,0x6a46,0x6b55,0x6b54,0x6b56,0x6ba7,0x6baa,0x6bab,0x6bc8,0x6bc7,
+    0x6c04,0x6c03,0x6c06,0x6fad,0x6fcb,0x6fa3,0x6fc7,0x6fbc,0x6fce,0x6fc8,
+    0x6f5e,0x6fc4,0x6fbd,0x6f9e
+  },
+  {				/* ku 38 */
+    0x6fca,0x6fa8,0x7004,0x6fa5,0x6fae,0x6fba,0x6fac,0x6faa,0x6fcf,0x6fbf,
+    0x6fb8,0x6fa2,0x6fc9,0x6fab,0x6fcd,0x6faf,0x6fb2,0x6fb0,0x71c5,0x71c2,
+    0x71bf,0x71b8,0x71d6,0x71c0,0x71c1,0x71cb,0x71d4,0x71ca,0x71c7,0x71cf,
+    0x71bd,0x71d8,0x71bc,0x71c6,0x71da,0x71db,0x729d,0x729e,0x7369,0x7366,
+    0x7367,0x736c,0x7365,0x736b,0x736a,0x747f,0x749a,0x74a0,0x7494,0x7492,
+    0x7495,0x74a1,0x750b,0x7580,0x762f,0x762d,0x7631,0x763d,0x7633,0x763c,
+    0x7635,0x7632,0x7630,0x76bb,0x76e6,0x779a,0x779d,0x77a1,0x779c,0x779b,
+    0x77a2,0x77a3,0x7795,0x7799,0x7797,0x78dd,0x78e9,0x78e5,0x78ea,0x78de,
+    0x78e3,0x78db,0x78e1,0x78e2,0x78ed,0x78df,0x78e0,0x79a4,0x7a44,0x7a48,
+    0x7a47,0x7ab6,0x7ab8,0x7ab5
+  },
+  {				/* ku 39 */
+    0x7ab1,0x7ab7,0x7bde,0x7be3,0x7be7,0x7bdd,0x7bd5,0x7be5,0x7bda,0x7be8,
+    0x7bf9,0x7bd4,0x7bea,0x7be2,0x7bdc,0x7beb,0x7bd8,0x7bdf,0x7cd2,0x7cd4,
+    0x7cd7,0x7cd0,0x7cd1,0x7e12,0x7e21,0x7e17,0x7e0c,0x7e1f,0x7e20,0x7e13,
+    0x7e0e,0x7e1c,0x7e15,0x7e1a,0x7e22,0x7e0b,0x7e0f,0x7e16,0x7e0d,0x7e14,
+    0x7e25,0x7e24,0x7f43,0x7f7b,0x7f7c,0x7f7a,0x7fb1,0x7fef,0x802a,0x8029,
+    0x806c,0x81b1,0x81a6,0x81ae,0x81b9,0x81b5,0x81ab,0x81b0,0x81ac,0x81b4,
+    0x81b2,0x81b7,0x81a7,0x81f2,0x8255,0x8256,0x8257,0x8556,0x8545,0x856b,
+    0x854d,0x8553,0x8561,0x8558,0x8540,0x8546,0x8564,0x8541,0x8562,0x8544,
+    0x8551,0x8547,0x8563,0x853e,0x855b,0x8571,0x854e,0x856e,0x8575,0x8555,
+    0x8567,0x8560,0x858c,0x8566
+  },
+  {				/* ku 3a */
+    0x855d,0x8554,0x8565,0x856c,0x8663,0x8665,0x8664,0x87a4,0x879b,0x878f,
+    0x8797,0x8793,0x8792,0x8788,0x8781,0x8796,0x8798,0x8779,0x8787,0x87a3,
+    0x8785,0x8790,0x8791,0x879d,0x8784,0x8794,0x879c,0x879a,0x8789,0x891e,
+    0x8926,0x8930,0x892d,0x892e,0x8927,0x8931,0x8922,0x8929,0x8923,0x892f,
+    0x892c,0x891f,0x89f1,0x8ae0,0x8ae2,0x8af2,0x8af4,0x8af5,0x8add,0x8b14,
+    0x8ae4,0x8adf,0x8af0,0x8ac8,0x8ade,0x8ae1,0x8ae8,0x8aff,0x8aef,0x8afb,
+    0x8c91,0x8c92,0x8c90,0x8cf5,0x8cee,0x8cf1,0x8cf0,0x8cf3,0x8d6c,0x8d6e,
+    0x8da5,0x8da7,0x8e33,0x8e3e,0x8e38,0x8e40,0x8e45,0x8e36,0x8e3c,0x8e3d,
+    0x8e41,0x8e30,0x8e3f,0x8ebd,0x8f36,0x8f2e,0x8f35,0x8f32,0x8f39,0x8f37,
+    0x8f34,0x9076,0x9079,0x907b
+  },
+  {				/* ku 3b */
+    0x9086,0x90fa,0x9133,0x9135,0x9136,0x9193,0x9190,0x9191,0x918d,0x918f,
+    0x9327,0x931e,0x9308,0x931f,0x9306,0x930f,0x937a,0x9338,0x933c,0x931b,
+    0x9323,0x9312,0x9301,0x9346,0x932d,0x930e,0x930d,0x92cb,0x931d,0x92fa,
+    0x9313,0x92f9,0x92f7,0x9334,0x9302,0x9324,0x92ff,0x9329,0x9339,0x9335,
+    0x932a,0x9314,0x930c,0x930b,0x92fe,0x9309,0x9300,0x92fb,0x9316,0x95bc,
+    0x95cd,0x95be,0x95b9,0x95ba,0x95b6,0x95bf,0x95b5,0x95bd,0x96a9,0x96d4,
+    0x970b,0x9712,0x9710,0x9799,0x9797,0x9794,0x97f0,0x97f8,0x9835,0x982f,
+    0x9832,0x9924,0x991f,0x9927,0x9929,0x999e,0x99ee,0x99ec,0x99e5,0x99e4,
+    0x99f0,0x99e3,0x99ea,0x99e9,0x99e7,0x9ab9,0x9abf,0x9ab4,0x9abb,0x9af6,
+    0x9afa,0x9af9,0x9af7,0x9b33
+  },
+  {				/* ku 3c */
+    0x9b80,0x9b85,0x9b87,0x9b7c,0x9b7e,0x9b7b,0x9b82,0x9b93,0x9b92,0x9b90,
+    0x9b7a,0x9b95,0x9b7d,0x9b88,0x9d25,0x9d17,0x9d20,0x9d1e,0x9d14,0x9d29,
+    0x9d1d,0x9d18,0x9d22,0x9d10,0x9d19,0x9d1f,0x9e88,0x9e86,0x9e87,0x9eae,
+    0x9ead,0x9ed5,0x9ed6,0x9efa,0x9f12,0x9f3d,0x5126,0x5125,0x5122,0x5124,
+    0x5120,0x5129,0x52f4,0x5693,0x568c,0x568d,0x5686,0x5684,0x5683,0x567e,
+    0x5682,0x567f,0x5681,0x58d6,0x58d4,0x58cf,0x58d2,0x5b2d,0x5b25,0x5b32,
+    0x5b23,0x5b2c,0x5b27,0x5b26,0x5b2f,0x5b2e,0x5b7b,0x5bf1,0x5bf2,0x5db7,
+    0x5e6c,0x5e6a,0x5fbe,0x61c3,0x61b5,0x61bc,0x61e7,0x61e0,0x61e5,0x61e4,
+    0x61e8,0x61de,0x64ef,0x64e9,0x64e3,0x64eb,0x64e4,0x64e8,0x6581,0x6580,
+    0x65b6,0x65da,0x66d2,0x6a8d
+  },
+  {				/* ku 3d */
+    0x6a96,0x6a81,0x6aa5,0x6a89,0x6a9f,0x6a9b,0x6aa1,0x6a9e,0x6a87,0x6a93,
+    0x6a8e,0x6a95,0x6a83,0x6aa8,0x6aa4,0x6a91,0x6a7f,0x6aa6,0x6a9a,0x6a85,
+    0x6a8c,0x6a92,0x6b5b,0x6bad,0x6c09,0x6fcc,0x6fa9,0x6ff4,0x6fd4,0x6fe3,
+    0x6fdc,0x6fed,0x6fe7,0x6fe6,0x6fde,0x6ff2,0x6fdd,0x6fe2,0x6fe8,0x71e1,
+    0x71f1,0x71e8,0x71f2,0x71e4,0x71f0,0x71e2,0x7373,0x736e,0x736f,0x7497,
+    0x74b2,0x74ab,0x7490,0x74aa,0x74ad,0x74b1,0x74a5,0x74af,0x7510,0x7511,
+    0x7512,0x750f,0x7584,0x7643,0x7648,0x7649,0x7647,0x76a4,0x76e9,0x77b5,
+    0x77ab,0x77b2,0x77b7,0x77b6,0x77b4,0x77b1,0x77a8,0x77f0,0x78f3,0x78fd,
+    0x7902,0x78fb,0x78fc,0x78ff,0x78f2,0x7905,0x78f9,0x78fe,0x7904,0x79ab,
+    0x79a8,0x7a5c,0x7a5b,0x7a56
+  },
+  {				/* ku 3e */
+    0x7a58,0x7a54,0x7a5a,0x7abe,0x7ac0,0x7ac1,0x7c05,0x7c0f,0x7bf2,0x7c00,
+    0x7bff,0x7bfb,0x7c0e,0x7bf4,0x7c0b,0x7bf3,0x7c02,0x7c09,0x7c03,0x7c01,
+    0x7bf8,0x7bfd,0x7c06,0x7bf0,0x7bf1,0x7c10,0x7c0a,0x7ce8,0x7e2d,0x7e3c,
+    0x7e42,0x7e33,0x9848,0x7e38,0x7e2a,0x7e49,0x7e40,0x7e47,0x7e29,0x7e4c,
+    0x7e30,0x7e3b,0x7e36,0x7e44,0x7e3a,0x7f45,0x7f7f,0x7f7e,0x7f7d,0x7ff4,
+    0x7ff2,0x802c,0x81bb,0x81c4,0x81cc,0x81ca,0x81c5,0x81c7,0x81bc,0x81e9,
+    0x825b,0x825a,0x825c,0x8583,0x8580,0x858f,0x85a7,0x8595,0x85a0,0x858b,
+    0x85a3,0x857b,0x85a4,0x859a,0x859e,0x8577,0x857c,0x8589,0x85a1,0x857a,
+    0x8578,0x8557,0x858e,0x8596,0x8586,0x858d,0x8599,0x859d,0x8581,0x85a2,
+    0x8582,0x8588,0x8585,0x8579
+  },
+  {				/* ku 3f */
+    0x8576,0x8598,0x8590,0x859f,0x8668,0x87be,0x87aa,0x87ad,0x87c5,0x87b0,
+    0x87ac,0x87b9,0x87b5,0x87bc,0x87ae,0x87c9,0x87c3,0x87c2,0x87cc,0x87b7,
+    0x87af,0x87c4,0x87ca,0x87b4,0x87b6,0x87bf,0x87b8,0x87bd,0x87de,0x87b2,
+    0x8935,0x8933,0x893c,0x893e,0x8941,0x8952,0x8937,0x8942,0x89ad,0x89af,
+    0x89ae,0x89f2,0x89f3,0x8b1e,0x8b18,0x8b16,0x8b11,0x8b05,0x8b0b,0x8b22,
+    0x8b0f,0x8b12,0x8b15,0x8b07,0x8b0d,0x8b08,0x8b06,0x8b1c,0x8b13,0x8b1a,
+    0x8c4f,0x8c70,0x8c72,0x8c71,0x8c6f,0x8c95,0x8c94,0x8cf9,0x8d6f,0x8e4e,
+    0x8e4d,0x8e53,0x8e50,0x8e4c,0x8e47,0x8f43,0x8f40,0x9085,0x907e,0x9138,
+    0x919a,0x91a2,0x919b,0x9199,0x919f,0x91a1,0x919d,0x91a0,0x93a1,0x9383,
+    0x93af,0x9364,0x9356,0x9347
+  },
+  {				/* ku 40 */
+    0x937c,0x9358,0x935c,0x9376,0x9349,0x9350,0x9351,0x9360,0x936d,0x938f,
+    0x934c,0x936a,0x9379,0x9357,0x9355,0x9352,0x934f,0x9371,0x9377,0x937b,
+    0x9361,0x935e,0x9363,0x9367,0x934e,0x9359,0x95c7,0x95c0,0x95c9,0x95c3,
+    0x95c5,0x95b7,0x96ae,0x96b0,0x96ac,0x9720,0x971f,0x9718,0x971d,0x9719,
+    0x979a,0x97a1,0x979c,0x979e,0x979d,0x97d5,0x97d4,0x97f1,0x9841,0x9844,
+    0x984a,0x9849,0x9845,0x9843,0x9925,0x992b,0x992c,0x992a,0x9933,0x9932,
+    0x992f,0x992d,0x9931,0x9930,0x9998,0x99a3,0x99a1,0x9a02,0x99fa,0x99f4,
+    0x99f7,0x99f9,0x99f8,0x99f6,0x99fb,0x99fd,0x99fe,0x99fc,0x9a03,0x9abe,
+    0x9afe,0x9afd,0x9b01,0x9afc,0x9b48,0x9b9a,0x9ba8,0x9b9e,0x9b9b,0x9ba6,
+    0x9ba1,0x9ba5,0x9ba4,0x9b86
+  },
+  {				/* ku 41 */
+    0x9ba2,0x9ba0,0x9baf,0x9d33,0x9d41,0x9d67,0x9d36,0x9d2e,0x9d2f,0x9d31,
+    0x9d38,0x9d30,0x9d45,0x9d42,0x9d43,0x9d3e,0x9d37,0x9d40,0x9d3d,0x7ff5,
+    0x9d2d,0x9e8a,0x9e89,0x9e8d,0x9eb0,0x9ec8,0x9eda,0x9efb,0x9eff,0x9f24,
+    0x9f23,0x9f22,0x9f54,0x9fa0,0x5131,0x512d,0x512e,0x5698,0x569c,0x5697,
+    0x569a,0x569d,0x5699,0x5970,0x5b3c,0x5c69,0x5c6a,0x5dc0,0x5e6d,0x5e6e,
+    0x61d8,0x61df,0x61ed,0x61ee,0x61f1,0x61ea,0x61f0,0x61eb,0x61d6,0x61e9,
+    0x64ff,0x6504,0x64fd,0x64f8,0x6501,0x6503,0x64fc,0x6594,0x65db,0x66da,
+    0x66db,0x66d8,0x6ac5,0x6ab9,0x6abd,0x6ae1,0x6ac6,0x6aba,0x6ab6,0x6ab7,
+    0x6ac7,0x6ab4,0x6aad,0x6b5e,0x6bc9,0x6c0b,0x7007,0x700c,0x700d,0x7001,
+    0x7005,0x7014,0x700e,0x6fff
+  },
+  {				/* ku 42 */
+    0x7000,0x6ffb,0x7026,0x6ffc,0x6ff7,0x700a,0x7201,0x71ff,0x71f9,0x7203,
+    0x71fd,0x7376,0x74b8,0x74c0,0x74b5,0x74c1,0x74be,0x74b6,0x74bb,0x74c2,
+    0x7514,0x7513,0x765c,0x7664,0x7659,0x7650,0x7653,0x7657,0x765a,0x76a6,
+    0x76bd,0x76ec,0x77c2,0x77ba,0x790c,0x7913,0x7914,0x7909,0x7910,0x7912,
+    0x7911,0x79ad,0x79ac,0x7a5f,0x7c1c,0x7c29,0x7c19,0x7c20,0x7c1f,0x7c2d,
+    0x7c1d,0x7c26,0x7c28,0x7c22,0x7c25,0x7c30,0x7e5c,0x7e50,0x7e56,0x7e63,
+    0x7e58,0x7e62,0x7e5f,0x7e51,0x7e60,0x7e57,0x7e53,0x7fb5,0x7fb3,0x7ff7,
+    0x7ff8,0x8075,0x81d1,0x81d2,0x81d0,0x825f,0x825e,0x85b4,0x85c6,0x85c0,
+    0x85c3,0x85c2,0x85b3,0x85b5,0x85bd,0x85c7,0x85c4,0x85bf,0x85cb,0x85ce,
+    0x85c8,0x85c5,0x85b1,0x85b6
+  },
+  {				/* ku 43 */
+    0x85d2,0x8624,0x85b8,0x85b7,0x85be,0x8669,0x87e7,0x87e6,0x87e2,0x87db,
+    0x87eb,0x87ea,0x87e5,0x87df,0x87f3,0x87e4,0x87d4,0x87dc,0x87d3,0x87ed,
+    0x87d8,0x87e3,0x87d7,0x87d9,0x8801,0x87f4,0x87e8,0x87dd,0x8953,0x894b,
+    0x894f,0x894c,0x8946,0x8950,0x8951,0x8949,0x8b2a,0x8b27,0x8b23,0x8b33,
+    0x8b30,0x8b35,0x8b47,0x8b2f,0x8b3c,0x8b3e,0x8b31,0x8b25,0x8b37,0x8b26,
+    0x8b36,0x8b2e,0x8b24,0x8b3b,0x8b3d,0x8b3a,0x8c42,0x8c75,0x8c99,0x8c98,
+    0x8c97,0x8cfe,0x8d04,0x8d02,0x8d00,0x8e5c,0x8e62,0x8e60,0x8e57,0x8e56,
+    0x8e5e,0x8e65,0x8e67,0x8e5b,0x8e5a,0x8e61,0x8e5d,0x8e69,0x8e54,0x8f46,
+    0x8f47,0x8f48,0x8f4b,0x9128,0x913a,0x913b,0x913e,0x91a8,0x91a5,0x91a7,
+    0x91af,0x91aa,0x93b5,0x938c
+  },
+  {				/* ku 44 */
+    0x9392,0x93b7,0x939b,0x939d,0x9389,0x93a7,0x938e,0x93aa,0x939e,0x93a6,
+    0x9395,0x9388,0x9399,0x939f,0x9380,0x938d,0x93b1,0x9391,0x93b2,0x93a4,
+    0x93a8,0x93b4,0x93a3,0x95d2,0x95d3,0x95d1,0x96b3,0x96d7,0x96da,0x5dc2,
+    0x96df,0x96d8,0x96dd,0x9723,0x9722,0x9725,0x97ac,0x97ae,0x97a8,0x97ab,
+    0x97a4,0x97aa,0x97a2,0x97a5,0x97d7,0x97d9,0x97d6,0x97d8,0x97fa,0x9850,
+    0x9851,0x9852,0x98b8,0x9941,0x993c,0x993a,0x9a0f,0x9a0b,0x9a09,0x9a0d,
+    0x9a04,0x9a11,0x9a0a,0x9a05,0x9a07,0x9a06,0x9ac0,0x9adc,0x9b08,0x9b04,
+    0x9b05,0x9b29,0x9b35,0x9b4a,0x9b4c,0x9b4b,0x9bc7,0x9bc6,0x9bc3,0x9bbf,
+    0x9bc1,0x9bb5,0x9bb8,0x9bd3,0x9bb6,0x9bc4,0x9bb9,0x9bbd,0x9d5c,0x9d53,
+    0x9d4f,0x9d4a,0x9d5b,0x9d4b
+  },
+  {				/* ku 45 */
+    0x9d59,0x9d56,0x9d4c,0x9d57,0x9d52,0x9d54,0x9d5f,0x9d58,0x9d5a,0x9e8e,
+    0x9e8c,0x9edf,0x9f01,0x9f00,0x9f16,0x9f25,0x9f2b,0x9f2a,0x9f29,0x9f28,
+    0x9f4c,0x9f55,0x5134,0x5135,0x5296,0x52f7,0x53b4,0x56ab,0x56ad,0x56a6,
+    0x56a7,0x56aa,0x56ac,0x58da,0x58dd,0x58db,0x5912,0x5b3d,0x5b3e,0x5b3f,
+    0x5dc3,0x5e70,0x5fbf,0x61fb,0x6507,0x6510,0x650d,0x6509,0x650c,0x650e,
+    0x6584,0x65de,0x65dd,0x66de,0x6ae7,0x6ae0,0x6acc,0x6ad1,0x6ad9,0x6acb,
+    0x6adf,0x6adc,0x6ad0,0x6aeb,0x6acf,0x6acd,0x6ade,0x6b60,0x6bb0,0x6c0c,
+    0x7019,0x7027,0x7020,0x7016,0x702b,0x7021,0x7022,0x7023,0x7029,0x7017,
+    0x7024,0x701c,0x720c,0x720a,0x7207,0x7202,0x7205,0x72a5,0x72a6,0x72a4,
+    0x72a3,0x72a1,0x74cb,0x74c5
+  },
+  {				/* ku 46 */
+    0x74b7,0x74c3,0x7516,0x7660,0x77c9,0x77ca,0x77c4,0x77f1,0x791d,0x791b,
+    0x7921,0x791c,0x7917,0x791e,0x79b0,0x7a67,0x7a68,0x7c33,0x7c3c,0x7c39,
+    0x7c2c,0x7c3b,0x7cec,0x7cea,0x7e76,0x7e75,0x7e78,0x7e70,0x7e77,0x7e6f,
+    0x7e7a,0x7e72,0x7e74,0x7e68,0x7f4b,0x7f4a,0x7f83,0x7f86,0x7fb7,0x7ffd,
+    0x7ffe,0x8078,0x81d7,0x81d5,0x820b,0x8264,0x8261,0x8263,0x85eb,0x85f1,
+    0x85ed,0x85d9,0x85e1,0x85e8,0x85da,0x85d7,0x85ec,0x85f2,0x85f8,0x85d8,
+    0x85df,0x85e3,0x85dc,0x85d1,0x85f0,0x85e6,0x85ef,0x85de,0x85e2,0x8800,
+    0x87fa,0x8803,0x87f6,0x87f7,0x8809,0x880c,0x880b,0x8806,0x87fc,0x8808,
+    0x87ff,0x880a,0x8802,0x8962,0x895a,0x895b,0x8957,0x8961,0x895c,0x8958,
+    0x895d,0x8959,0x8988,0x89b7
+  },
+  {				/* ku 47 */
+    0x89b6,0x89f6,0x8b50,0x8b48,0x8b4a,0x8b40,0x8b53,0x8b56,0x8b54,0x8b4b,
+    0x8b55,0x8b51,0x8b42,0x8b52,0x8b57,0x8c43,0x8c77,0x8c76,0x8c9a,0x8d06,
+    0x8d07,0x8d09,0x8dac,0x8daa,0x8dad,0x8dab,0x8e6d,0x8e78,0x8e73,0x8e6a,
+    0x8e6f,0x8e7b,0x8ec2,0x8f52,0x8f51,0x8f4f,0x8f50,0x8f53,0x8fb4,0x9140,
+    0x913f,0x91b0,0x91ad,0x93de,0x93c7,0x93cf,0x93c2,0x93da,0x93d0,0x93f9,
+    0x93ec,0x93cc,0x93d9,0x93a9,0x93e6,0x93ca,0x93d4,0x93ee,0x93e3,0x93d5,
+    0x93c4,0x93ce,0x93c0,0x93d2,0x93a5,0x93e7,0x957d,0x95da,0x95db,0x96e1,
+    0x9729,0x972b,0x972c,0x9728,0x9726,0x97b3,0x97b7,0x97b6,0x97dd,0x97de,
+    0x97df,0x985c,0x9859,0x985d,0x9857,0x98bf,0x98bd,0x98bb,0x98be,0x9948,
+    0x9947,0x9943,0x99a6,0x99a7
+  },
+  {				/* ku 48 */
+    0x9a1a,0x9a15,0x9a25,0x9a1d,0x9a24,0x9a1b,0x9a22,0x9a20,0x9a27,0x9a23,
+    0x9a1e,0x9a1c,0x9a14,0x9ac2,0x9b0b,0x9b0a,0x9b0e,0x9b0c,0x9b37,0x9bea,
+    0x9beb,0x9be0,0x9bde,0x9be4,0x9be6,0x9be2,0x9bf0,0x9bd4,0x9bd7,0x9bec,
+    0x9bdc,0x9bd9,0x9be5,0x9bd5,0x9be1,0x9bda,0x9d77,0x9d81,0x9d8a,0x9d84,
+    0x9d88,0x9d71,0x9d80,0x9d78,0x9d86,0x9d8b,0x9d8c,0x9d7d,0x9d6b,0x9d74,
+    0x9d75,0x9d70,0x9d69,0x9d85,0x9d73,0x9d7b,0x9d82,0x9d6f,0x9d79,0x9d7f,
+    0x9d87,0x9d68,0x9e94,0x9e91,0x9ec0,0x9efc,0x9f2d,0x9f40,0x9f41,0x9f4d,
+    0x9f56,0x9f57,0x9f58,0x5337,0x56b2,0x56b5,0x56b3,0x58e3,0x5b45,0x5dc6,
+    0x5dc7,0x5eee,0x5eef,0x5fc0,0x5fc1,0x61f9,0x6517,0x6516,0x6515,0x6513,
+    0x65df,0x66e8,0x66e3,0x66e4
+  },
+  {				/* ku 49 */
+    0x6af3,0x6af0,0x6aea,0x6ae8,0x6af9,0x6af1,0x6aee,0x6aef,0x703c,0x7035,
+    0x702f,0x7037,0x7034,0x7031,0x7042,0x7038,0x703f,0x703a,0x7039,0x702a,
+    0x7040,0x703b,0x7033,0x7041,0x7213,0x7214,0x72a8,0x737d,0x737c,0x74ba,
+    0x76ab,0x76aa,0x76be,0x76ed,0x77cc,0x77ce,0x77cf,0x77cd,0x77f2,0x7925,
+    0x7923,0x7927,0x7928,0x7924,0x7929,0x79b2,0x7a6e,0x7a6c,0x7a6d,0x7af7,
+    0x7c49,0x7c48,0x7c4a,0x7c47,0x7c45,0x7cee,0x7e7b,0x7e7e,0x7e81,0x7e80,
+    0x7fba,0x7fff,0x8079,0x81db,0x81d9,0x8268,0x8269,0x8622,0x85ff,0x8601,
+    0x85fe,0x861b,0x8600,0x85f6,0x8604,0x8609,0x8605,0x860c,0x85fd,0x8819,
+    0x8810,0x8811,0x8817,0x8813,0x8816,0x8963,0x8966,0x89b9,0x89f7,0x8b60,
+    0x8b6a,0x8b5d,0x8b68,0x8b63
+  },
+  {				/* ku 4a */
+    0x8b65,0x8b67,0x8b6d,0x8dae,0x8e86,0x8e88,0x8e84,0x8f59,0x8f56,0x8f57,
+    0x8f55,0x8f58,0x8f5a,0x908d,0x9143,0x9141,0x91b7,0x91b5,0x91b2,0x91b3,
+    0x940b,0x9413,0x93fb,0x9420,0x940f,0x9414,0x93fe,0x9415,0x9410,0x9428,
+    0x9419,0x940d,0x93f5,0x9400,0x93f7,0x9407,0x940e,0x9416,0x9412,0x93fa,
+    0x9409,0x93f8,0x943c,0x940a,0x93ff,0x93fc,0x940c,0x93f6,0x9411,0x9406,
+    0x95de,0x95e0,0x95df,0x972e,0x972f,0x97b9,0x97bb,0x97fd,0x97fe,0x9860,
+    0x9862,0x9863,0x985f,0x98c1,0x98c2,0x9950,0x994e,0x9959,0x994c,0x994b,
+    0x9953,0x9a32,0x9a34,0x9a31,0x9a2c,0x9a2a,0x9a36,0x9a29,0x9a2e,0x9a38,
+    0x9a2d,0x9ac7,0x9aca,0x9ac6,0x9b10,0x9b12,0x9b11,0x9c0b,0x9c08,0x9bf7,
+    0x9c05,0x9c12,0x9bf8,0x9c40
+  },
+  {				/* ku 4b */
+    0x9c07,0x9c0e,0x9c06,0x9c17,0x9c14,0x9c09,0x9d9f,0x9d99,0x9da4,0x9d9d,
+    0x9d92,0x9d98,0x9d90,0x9d9b,0x9da0,0x9d94,0x9d9c,0x9daa,0x9d97,0x9da1,
+    0x9d9a,0x9da2,0x9da8,0x9d9e,0x9da3,0x9dbf,0x9da9,0x9d96,0x9da6,0x9da7,
+    0x9e99,0x9e9b,0x9e9a,0x9ee5,0x9ee4,0x9ee7,0x9ee6,0x9f30,0x9f2e,0x9f5b,
+    0x9f60,0x9f5e,0x9f5d,0x9f59,0x9f91,0x513a,0x5139,0x5298,0x5297,0x56c3,
+    0x56bd,0x56be,0x5b48,0x5b47,0x5dcb,0x5dcf,0x5ef1,0x61fd,0x651b,0x6b02,
+    0x6afc,0x6b03,0x6af8,0x6b00,0x7043,0x7044,0x704a,0x7048,0x7049,0x7045,
+    0x7046,0x721d,0x721a,0x7219,0x737e,0x7517,0x766a,0x77d0,0x792d,0x7931,
+    0x792f,0x7c54,0x7c53,0x7cf2,0x7e8a,0x7e87,0x7e88,0x7e8b,0x7e86,0x7e8d,
+    0x7f4d,0x7fbb,0x8030,0x81dd
+  },
+  {				/* ku 4c */
+    0x8618,0x862a,0x8626,0x861f,0x8623,0x861c,0x8619,0x8627,0x862e,0x8621,
+    0x8620,0x8629,0x861e,0x8625,0x8829,0x881d,0x881b,0x8820,0x8824,0x881c,
+    0x882b,0x884a,0x896d,0x8969,0x896e,0x896b,0x89fa,0x8b79,0x8b78,0x8b45,
+    0x8b7a,0x8b7b,0x8d10,0x8d14,0x8daf,0x8e8e,0x8e8c,0x8f5e,0x8f5b,0x8f5d,
+    0x9146,0x9144,0x9145,0x91b9,0x943f,0x943b,0x9436,0x9429,0x943d,0x9430,
+    0x9439,0x942a,0x9437,0x942c,0x9440,0x9431,0x95e5,0x95e4,0x95e3,0x9735,
+    0x973a,0x97bf,0x97e1,0x9864,0x98c9,0x98c6,0x98c0,0x9958,0x9956,0x9a39,
+    0x9a3d,0x9a46,0x9a44,0x9a42,0x9a41,0x9a3a,0x9a3f,0x9acd,0x9b15,0x9b17,
+    0x9b18,0x9b16,0x9b3a,0x9b52,0x9c2b,0x9c1d,0x9c1c,0x9c2c,0x9c23,0x9c28,
+    0x9c29,0x9c24,0x9c21,0x9db7
+  },
+  {				/* ku 4d */
+    0x9db6,0x9dbc,0x9dc1,0x9dc7,0x9dca,0x9dcf,0x9dbe,0x9dc5,0x9dc3,0x9dbb,
+    0x9db5,0x9dce,0x9db9,0x9dba,0x9dac,0x9dc8,0x9db1,0x9dad,0x9dcc,0x9db3,
+    0x9dcd,0x9db2,0x9e7a,0x9e9c,0x9eeb,0x9eee,0x9eed,0x9f1b,0x9f18,0x9f1a,
+    0x9f31,0x9f4e,0x9f65,0x9f64,0x9f92,0x4eb9,0x56c6,0x56c5,0x56cb,0x5971,
+    0x5b4b,0x5b4c,0x5dd5,0x5dd1,0x5ef2,0x6521,0x6520,0x6526,0x6522,0x6b0b,
+    0x6b08,0x6b09,0x6c0d,0x7055,0x7056,0x7057,0x7052,0x721e,0x721f,0x72a9,
+    0x737f,0x74d8,0x74d5,0x74d9,0x74d7,0x766d,0x76ad,0x7935,0x79b4,0x7a70,
+    0x7a71,0x7c57,0x7c5c,0x7c59,0x7c5b,0x7c5a,0x7cf4,0x7cf1,0x7e91,0x7f4f,
+    0x7f87,0x81de,0x826b,0x8634,0x8635,0x8633,0x862c,0x8632,0x8636,0x882c,
+    0x8828,0x8826,0x882a,0x8825
+  },
+  {				/* ku 4e */
+    0x8971,0x89bf,0x89be,0x89fb,0x8b7e,0x8b84,0x8b82,0x8b86,0x8b85,0x8b7f,
+    0x8d15,0x8e95,0x8e94,0x8e9a,0x8e92,0x8e90,0x8e96,0x8e97,0x8f60,0x8f62,
+    0x9147,0x944c,0x9450,0x944a,0x944b,0x944f,0x9447,0x9445,0x9448,0x9449,
+    0x9446,0x973f,0x97e3,0x986a,0x9869,0x98cb,0x9954,0x995b,0x9a4e,0x9a53,
+    0x9a54,0x9a4c,0x9a4f,0x9a48,0x9a4a,0x9a49,0x9a52,0x9a50,0x9ad0,0x9b19,
+    0x9b2b,0x9b3b,0x9b56,0x9b55,0x9c46,0x9c48,0x9c3f,0x9c44,0x9c39,0x9c33,
+    0x9c41,0x9c3c,0x9c37,0x9c34,0x9c32,0x9c3d,0x9c36,0x9ddb,0x9dd2,0x9dde,
+    0x9dda,0x9dcb,0x9dd0,0x9ddc,0x9dd1,0x9ddf,0x9de9,0x9dd9,0x9dd8,0x9dd6,
+    0x9df5,0x9dd5,0x9ddd,0x9eb6,0x9ef0,0x9f35,0x9f33,0x9f32,0x9f42,0x9f6b,
+    0x9f95,0x9fa2,0x513d,0x5299
+  },
+  {				/* ku 4f */
+    0x58e8,0x58e7,0x5972,0x5b4d,0x5dd8,0x882f,0x5f4f,0x6201,0x6203,0x6204,
+    0x6529,0x6525,0x6596,0x66eb,0x6b11,0x6b12,0x6b0f,0x6bca,0x705b,0x705a,
+    0x7222,0x7382,0x7381,0x7383,0x7670,0x77d4,0x7c67,0x7c66,0x7e95,0x826c,
+    0x863a,0x8640,0x8639,0x863c,0x8631,0x863b,0x863e,0x8830,0x8832,0x882e,
+    0x8833,0x8976,0x8974,0x8973,0x89fe,0x8b8c,0x8b8e,0x8b8b,0x8b88,0x8c45,
+    0x8d19,0x8e98,0x8f64,0x8f63,0x91bc,0x9462,0x9455,0x945d,0x9457,0x945e,
+    0x97c4,0x97c5,0x9800,0x9a56,0x9a59,0x9b1e,0x9b1f,0x9b20,0x9c52,0x9c58,
+    0x9c50,0x9c4a,0x9c4d,0x9c4b,0x9c55,0x9c59,0x9c4c,0x9c4e,0x9dfb,0x9df7,
+    0x9def,0x9de3,0x9deb,0x9df8,0x9de4,0x9df6,0x9de1,0x9dee,0x9de6,0x9df2,
+    0x9df0,0x9de2,0x9dec,0x9df4
+  },
+  {				/* ku 50 */
+    0x9df3,0x9de8,0x9ded,0x9ec2,0x9ed0,0x9ef2,0x9ef3,0x9f06,0x9f1c,0x9f38,
+    0x9f37,0x9f36,0x9f43,0x9f4f,0x9f71,0x9f70,0x9f6e,0x9f6f,0x56d3,0x56cd,
+    0x5b4e,0x5c6d,0x652d,0x66ed,0x66ee,0x6b13,0x705f,0x7061,0x705d,0x7060,
+    0x7223,0x74db,0x74e5,0x77d5,0x7938,0x79b7,0x79b6,0x7c6a,0x7e97,0x7f89,
+    0x826d,0x8643,0x8838,0x8837,0x8835,0x884b,0x8b94,0x8b95,0x8e9e,0x8e9f,
+    0x8ea0,0x8e9d,0x91be,0x91bd,0x91c2,0x946b,0x9468,0x9469,0x96e5,0x9746,
+    0x9743,0x9747,0x97c7,0x97e5,0x9a5e,0x9ad5,0x9b59,0x9c63,0x9c67,0x9c66,
+    0x9c62,0x9c5e,0x9c60,0x9e02,0x9dfe,0x9e07,0x9e03,0x9e06,0x9e05,0x9e00,
+    0x9e01,0x9e09,0x9dff,0x9dfd,0x9e04,0x9ea0,0x9f1e,0x9f46,0x9f74,0x9f75,
+    0x9f76,0x56d4,0x652e,0x65b8
+  },
+  {				/* ku 51 */
+    0x6b18,0x6b19,0x6b17,0x6b1a,0x7062,0x7226,0x72aa,0x77d8,0x77d9,0x7939,
+    0x7c69,0x7c6b,0x7cf6,0x7e9a,0x7e98,0x7e9b,0x7e99,0x81e0,0x81e1,0x8646,
+    0x8647,0x8648,0x8979,0x897a,0x897c,0x897b,0x89ff,0x8b98,0x8b99,0x8ea5,
+    0x8ea4,0x8ea3,0x946e,0x946d,0x946f,0x9471,0x9473,0x9749,0x9872,0x995f,
+    0x9c68,0x9c6e,0x9c6d,0x9e0b,0x9e0d,0x9e10,0x9e0f,0x9e12,0x9e11,0x9ea1,
+    0x9ef5,0x9f09,0x9f47,0x9f78,0x9f7b,0x9f7a,0x9f79,0x571e,0x7066,0x7c6f,
+    0x883c,0x8db2,0x8ea6,0x91c3,0x9474,0x9478,0x9476,0x9475,0x9a60,0x9b2e,
+    0x9c74,0x9c73,0x9c71,0x9c75,0x9e14,0x9e13,0x9ef6,0x9f0a,0x9fa4,0x7068,
+    0x7065,0x7cf7,0x866a,0x883e,0x883d,0x883f,0x8b9e,0x8c9c,0x8ea9,0x8ec9,
+    0x974b,0x9873,0x9874,0x98cc
+  },
+  {				/* ku 52 */
+    0x9961,0x99ab,0x9a64,0x9a66,0x9a67,0x9b24,0x9e15,0x9e17,0x9f48,0x6207,
+    0x6b1e,0x7227,0x864c,0x8ea8,0x9482,0x9480,0x9481,0x9a69,0x9a68,0x9e19,
+    0x864b,0x8b9f,0x9483,0x9c79,0x9eb7,0x7675,0x9a6b,0x9c7a,0x9e1d,0x7069,
+    0x706a,0x7229,0x9ea4,0x9f7e,0x9f49,0x9f98,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  }
+};
+
+#if CNS_EXTENDED
+/* CNS 11643 plane 3 conversion table */
+
+static const unsigned short
+ cns11643_3tab[MAX_CNS11643_KU_3][MAX_CNS11643_TEN] = {
+  {				/* ku 01 */
+    0x4e28,0x4e36,0x4e3f,0x4e85,0x4e05,0x4e04,0x5182,0x5196,0x5338,0x5369,
+    0x53b6,0x4e2a,0x4e87,0x4e49,0x51e2,0x4e46,0x4e8f,0x4ebc,0x4ebe,0x5166,
+    0x51e3,0x5204,0x529c,0x5344,0x5902,0x590a,0x5b80,0x5ddb,0x5e7a,0x5e7f,
+    0x5ef4,0x5f50,0x5f51,0x5f61,0x961d,UBOGON,0x4e63,0x4e62,0x4ea3,0x5185,
+    0x4ec5,0x4ecf,0x4ece,0x4ecc,0x5184,0x5186,UBOGON,0x34c5,0x51e4,0x5205,
+    0x529e,0x529d,0x52fd,0x5300,0x533a,0x3539,0x5346,0x535d,0x5386,0x53b7,
+    0x3555,0x53cc,0x355b,0x53ce,0x5721,0x37a2,0x5e00,0x5f0c,0x6237,0x6238,
+    0x6534,0x6535,0x65e0,0x3e26,0x738d,0x4e97,0x4ee0,0x3432,UBOGON,0x4ee7,
+    0x3433,0x4ee6,0x3434,0x36a2,0x3431,0x34b0,0x56d8,0x518b,0x518c,0x5199,
+    0x51e5,UBOGON,0x520b,0x34dc
+  },
+  {				/* ku 02 */
+    0x361e,0x5304,0x5303,0x5307,UBOGON,0x531e,0x535f,0x536d,0x5389,0x53ba,
+    0x53d0,0x3565,0x53f6,0x53f7,0x53f9,0x3564,0x53f4,0x361d,0x3626,0x5724,
+    0x5904,0x5918,0x5932,0x5930,0x5934,0x368e,0x5975,0x374a,0x5b82,0x5bf9,
+    0x5c14,0x378b,0x37a6,0x37a4,0x37a5,0x37a7,0x382f,0x3832,0x5e81,0x5e83,
+    0x5f0d,0x5f52,0x38d4,0x5fca,0x5fc7,0x6239,0x39c5,0x624f,0x65e7,0x672f,
+    0x6b7a,0x6c39,0x3cba,0x3cb9,0x6c37,0x6c44,0x6c45,0x738c,0x7592,0x7676,
+    0x9093,0x9092,0x48b3,0x49ba,0x4e21,0x4e20,0x4e22,0x4e68,0x4e89,0x4e98,
+    0x4ef9,0x4eef,0x343b,0x343c,0x4ef8,0x4f06,0x4f03,0x4efc,0x4eee,0x4f16,
+    0x3439,0x4f28,0x4f1c,0x4f07,0x4f1a,0x4efa,0x4f17,0x514a,0x34b2,0x5172,
+    UBOGON,0x51b4,0x51b3,0x51b2
+  },
+  {				/* ku 03 */
+    0x34c7,0x51e8,0x342b,0x5214,0x520f,0x5215,0x5218,0x52a8,UBOGON,0x534b,
+    0x534f,0x353b,0x5350,0x3544,0x538b,0x3542,0x53be,0x355c,0x53d2,0x5416,
+    0x53ff,0x3567,0x5400,0x3566,0x5405,0x5413,0x5415,UBOGON,0x361f,0x56e3,
+    0x5735,0x5736,0x5731,0x5732,0x58ee,0x5905,0x4e54,0x368f,0x5936,0x3690,
+    0x36a8,0x36a4,0x597a,0x36a3,0x5986,0x373d,0x374c,0x5b86,0x5f53,0x5c18,
+    0x378c,0x5c3d,0x5c78,0x37a8,0x37ad,0x37af,UBOGON,0x5c80,0x3829,0x5e08,
+    0x3836,0x3871,0x3870,0x386f,0x5ef5,0x5f0e,0x38a9,0x38aa,0x38fb,0x5fd3,
+    0x5fda,0x38fc,0x5fdb,0x39ae,0x620f,0x625d,0x625f,0x6267,0x6257,0x9f50,
+    0x3ac3,0x65eb,0x65ea,0x3b30,0x6737,0x3b41,0x6732,0x6736,0x6b22,0x6bce,
+    0x3c8c,0x6c58,0x6c51,0x6c77
+  },
+  {				/* ku 04 */
+    0x6c3c,0x3cbb,0x6c5a,UBOGON,0x6c53,0x706f,0x7072,0x706e,UBOGON,0x3da1,
+    0x7073,0x72b1,0x72b2,0x3ea8,0x738f,0x3eaa,0x3eab,0x4096,0x793c,0x41c2,
+    0x808d,0x808e,0x4493,0x827b,0x4494,0x8d71,0x8fb9,0x9096,0x909a,0x49bb,
+    0x4e24,0x4e71,UBOGON,0x4e9c,0x4f45,0x4f4a,0x4f39,0x4f37,0x3443,0x4f32,
+    0x4f42,0x3442,0x4f44,0x4f4b,0x3444,0x4f40,0x4f35,0x4f31,0x5151,UBOGON,
+    0x5150,0x514e,0x34b3,0x34b7,0x519d,0x34c8,0x51b5,0x51b8,0x51ec,0x5223,
+    0x5227,0x5226,0x521f,0x522b,0x5220,0x52b4,0x52b3,0x3518,0x5325,0x533b,
+    0x5374,0x3547,0x3546,0x3545,0x356b,0x3569,0x544d,0x3572,0x3571,0x543a,
+    0x356c,0x356f,0x5444,0x544c,0x5423,0x541a,0x5432,0x544b,0x5421,0x3573,
+    0x5434,0x5449,0x5450,0x5422
+  },
+  {				/* ku 05 */
+    0x543f,0x5451,0x545a,0x542f,0x3576,0x56e9,0x56f2,0x56f3,0x56ef,0x56ed,
+    0x56ec,0x56e6,0x5748,0x3627,0x5744,0x573f,0x573c,0x5753,0x5756,0x3630,
+    0x575f,0x5743,0x5758,0x5757,0x3629,0x362a,0x362f,0x5746,0x362c,0x573d,
+    0x362d,0x5742,0x5754,0x5755,0x58f1,0x58f2,0x58f0,0x590b,0x9ea6,0x56f1,
+    0x593d,0x3693,0x5994,0x598c,0x36ad,0x599c,0x36ac,0x36ab,0x599f,0x36a9,
+    0x599b,0x36ae,0x5989,0x599a,0x36aa,0x6588,0x374e,0x5b8d,0x3750,0x5bfe,
+    0x5bff,0x5bfd,0x5c2b,0x37b2,0x5c84,0x5c8e,0x5c9c,0x37b5,0x37b6,0x5c85,
+    0x5df5,0x5e09,0x3839,0x383b,0x5e0b,0x3872,0x5e92,0x5e90,0x5f03,0x38ac,
+    0x5f1e,0x5f63,0x3908,0x5fe7,0x5ffe,0x5fe6,0x5fdc,0x5fce,0x3903,0x5ffc,
+    0x5fdf,0x5fec,0x5ff6,UBOGON
+  },
+  {				/* ku 06 */
+    0x5ff2,0x5ff0,0x5ff9,0x390b,0x6213,0x39af,UBOGON,0x623b,0x623c,0x6282,
+    0x39ce,0x39cb,0x39cc,0x6278,0x628b,0x39cd,0x629e,0x62a5,0x629b,0x629c,
+    0x6299,0x628d,0x6285,0x629d,0x6275,0x3a80,0x3aaf,0x3ad3,0x65f6,0x3ad5,
+    0x3ad4,0x3ad7,0x66f5,0x675b,0x3b42,0x6754,0x6752,0x3b44,0x6758,0x6744,
+    0x674a,0x6761,0x3cc6,0x6c7f,0x6c91,0x6c9e,0x3cc0,0x6c6e,0x6c7c,0x6c9f,
+    0x6c75,0x3cbe,0x6c56,0x6ca2,0x6c79,0x3cca,0x6ca1,0x3cc4,0x6caa,0x6ca0,
+    0x3cc2,0x7079,0x7077,0x707e,0x3da4,0x7075,0x707b,0x7264,0x3e29,0x72bb,
+    0x72bc,0x72c7,0x72b9,0x72be,0x72b6,0x3e60,0x3e5e,0x7398,0x3ead,0x3eae,
+    0x3eac,0x3f57,0x7593,0x7680,0x3fdd,0x7683,0x76c0,0x76c1,0x400e,0x4097,
+    0x77f4,0x77f5,0x4127,0x7acc
+  },
+  {				/* ku 07 */
+    0x7acd,0x7cfa,0x809f,0x8091,0x8097,0x8094,0x4495,0x8286,0x828c,UBOGON,
+    0x8295,0x4498,0x866c,0x459d,0x8fb5,0x8fbe,0x8fc7,0x488a,0x8fc1,0x90a9,
+    0x90a4,0x48b5,0x48b6,0x48b7,0x90a8,0x9627,0x9626,0x962b,0x9633,0x9634,
+    0x9629,0x4e3d,0x3428,0x4e9d,0x4f93,0x4f8a,0x344d,0x3449,0x4f6d,0x4f8e,
+    0x4fa0,0x4fa2,0x4fa1,0x4f9f,0x4fa3,UBOGON,0x4f72,0x3451,0x4f8c,0x5156,
+    UBOGON,UBOGON,0x5190,0x34cb,0x34ca,0x34cc,0x51ed,0x51fe,0x522f,UBOGON,
+    0x523c,0x5234,0x5239,0x52b9,0x52b5,0x52bf,0x5355,0x353d,0x5376,0x537a,
+    0x5393,0x3548,0x53c1,0x53c2,0x53d5,0x5485,0x3578,0x545f,0x5493,0x5489,
+    0x5479,0x9efe,0x548f,0x5469,0x546d,0x357a,0x5494,0x546a,0x548a,0x3577,
+    0x56fd,0x56fb,0x56f8,0x3621
+  },
+  {				/* ku 08 */
+    0x56fc,0x56f6,0x5765,0x5781,0x5763,0x5767,0x3631,0x576e,0x5778,0x577f,
+    0x3633,0x3634,0x58f3,0x594b,0x594c,0x36c1,0x36b0,0x36b4,0x59ad,0x36b8,
+    0x59c4,0x36bc,0x59c2,0x59b0,0x36bf,0x36b5,0x36b1,0x36bd,0x59bf,0x36bb,
+    0x59c9,0x59b8,0x59ac,0x36b3,0x36b6,0x36ba,0x59b7,0x59d7,0x36b7,0x5b60,
+    0x3740,0x5b96,0x5b9e,0x5b94,0x5b9f,0x5b9d,0x3752,0x5c00,0x5c19,0x3790,
+    0x3791,0x5c49,0x5c4a,0x37be,0x5cbb,0x5cc1,0x37c0,0x37c1,0x37b9,0x5cb9,
+    0x5c9e,0x5cb4,0x5cba,0x5df6,0x5e13,0x5e12,0x5e77,0x3879,0x5e98,0x387b,
+    0x5e99,0x5e9d,0x5ef8,0x38a0,0x5ef9,0x3429,0x5f06,0x5f21,0x38ae,0x5f25,
+    0x5f55,0x38cd,0x38cb,0x38d9,0x5f84,0x5f83,0x6030,0x6007,0x390c,0x6036,
+    0x3901,0x3905,0x3902,0x5fe9
+  },
+  {				/* ku 09 */
+    0x603d,0x6008,0x3913,0x3911,0x62ba,0x62b2,0x39e4,0x62b7,0x62e4,0x62a7,
+    0x39da,0x39d5,0x39d3,0x62d5,0x62e1,0x62dd,0x62a6,0x62c1,0x62c5,0x62c0,
+    0x62df,0x62e0,0x62de,0x39d6,0x6589,0x3ab4,0x65a6,0x65ba,0x3ad9,0x65ff,
+    0x3ad8,0x6617,0x6618,0x6601,0x65fe,0x3b33,0x670c,0x3b48,0x676b,0x6796,
+    0x6782,0x678a,0x3b47,0x67a3,0x3b4b,0x67a2,0x678f,0x3b4a,0x67f9,0x6780,
+    0x6b26,0x6b27,0x6b68,0x6b69,0x3c5a,0x6b81,0x6bb4,0x6bd1,0x3c8e,0x3cb4,
+    0x6c1c,0x3ccd,0x3ccc,0x3ccf,0x3ccb,0x3cce,0x6c97,0x6c6c,0x6cdf,0x3cd2,
+    0x6cea,0x3cd1,0x6ce4,0x6cd8,0x6cb2,0x6cce,0x6cc8,0x3da6,0x708b,0x7088,
+    0x7090,0x708f,0x3daa,0x7087,0x7089,0x708d,0x7081,0x3da8,0x708c,0x3e13,
+    0x3e1a,0x7240,0x3e1d,0x3e1e
+  },
+  {				/* ku 0a */
+    0x7265,0x7266,0x7268,0x3e65,0x3e66,0x72cd,0x72d3,0x72db,0x3e64,0x72cf,
+    0x73a7,0x73a3,0x739e,0x3eb0,0x73af,0x3eb3,0x3eb5,0x73aa,0x739c,0x3f19,
+    0x7542,0x7544,0x753b,0x7541,UBOGON,0x759b,0x759e,0x3f75,0x79c4,0x79c3,
+    0x79c6,0x412b,0x412c,0x79c7,0x412d,0x79ca,UBOGON,0x41c3,0x7acf,0x7c76,
+    0x7c74,0x7cff,0x7cfc,0x34ba,0x4350,0x7f59,0x80a8,0x43d3,0x43d0,0x80b0,
+    0x43dc,0x80b3,0x43d2,0x80a4,0x80b6,0x80a7,0x80ac,0x43db,0x80a6,0x5367,
+    0x820e,0x82c4,0x833e,0x829c,0x44a5,0x449f,0x449a,0x449c,0x44a2,0x82aa,
+    0x449b,0x82c9,0x44a3,0x449d,0x82a6,0x82b2,0x4588,0x461a,0x488d,0x8fcc,
+    0x8fd9,0x8fca,0x8fd8,0x8fcf,0x90b7,0x48b8,0x90ad,0x90b9,0x9637,0x49c3,
+    0x9641,0x963e,0x96b6,0x9751
+  },
+  {				/* ku 0b */
+    0x9763,0x4e57,0x4e79,0x4eb2,0x4eb0,0x4eaf,0x4eb1,0x4fd2,0x4fd5,0x345d,
+    0x4fbe,0x4fb8,0x4fb0,0x4fb1,0x4fc8,0x345a,0x3457,0x4fc6,0x4fcc,0x4fe5,
+    0x4fe3,0x4fb4,0x516a,0x34b8,0x519f,0x34c2,0x51c1,0x34cf,0x51c2,0x51c3,
+    0x5245,0x5248,0x34e7,0x34e9,0x524f,0x4452,0x34e8,0x52c5,0x52ca,0x52c4,
+    0x5327,0x5358,0x537d,0x354a,0x53dd,0x53dc,0x53da,0x53d9,0x54b9,0x3580,
+    0x54d0,0x54b4,0x54ca,0x3587,0x54a3,0x54da,0x54a4,0x3584,0x54b2,0x549e,
+    0x549f,0x54b5,0x3582,0x3581,0x54cd,0x3583,0x54cc,0x3622,0x5700,0x57ac,
+    0x5791,0x578e,0x578d,0x5792,0x57a1,0x5790,0x57a6,0x57a8,0x363b,0x579c,
+    0x5796,0x57a7,0x363a,0x3638,0x3639,0x3636,0x58f5,0x3685,0x5909,0x5908,
+    0x3c54,0x5952,0x369a,0x36c4
+  },
+  {				/* ku 0c */
+    0x59df,0x36c5,0x59eb,0x59ef,0x59f0,0x59d5,0x5a0d,0x5a04,0x59f9,0x5a02,
+    0x59f8,0x59e2,0x59d9,0x59e7,0x5b6a,0x3754,0x3755,0x5bab,0x3756,0x5c1b,
+    0x5c2f,0x3796,0x663c,0x3795,0x3794,0x37c4,0x5cd1,0x5cdc,0x5ce6,0x5ce1,
+    0x5ccd,UBOGON,0x5ce2,0x5cdd,0x5ce5,0x5dfb,0x5dfa,0x5e1e,0x3844,0x5ea1,
+    0x387d,0x387e,0x5efc,0x5efb,0x5f2f,0x38b2,0x38b6,0x5f66,UBOGON,0x38dc,
+    0x38df,0x605c,0x3928,0x604e,0x6051,0x3919,0x3910,0x6023,0x6031,0x607c,
+    0x6052,0x392c,0x6060,0x604a,0x6061,0x391b,0x6218,0x39c2,0x39ef,0x39e3,
+    0x39e5,0x39ea,0x39e6,0x39ee,0x631f,0x6317,0x62ea,0x6321,0x6304,0x6305,
+    0x39e8,0x6531,0x6544,0x6540,0x3a85,0x6542,0x65be,0x3ae0,0x6629,0x661b,
+    0x3add,0x6623,0x662c,0x661a
+  },
+  {				/* ku 0d */
+    0x6630,0x663b,0x661e,0x6637,0x6638,0x3ae1,0x670e,0x3b51,0x3b55,0x67e8,
+    0x67d6,0x3b52,0x67c7,0x67bc,0x6852,0x67bf,0x67d5,0x67fe,0x8363,0x67fb,
+    UBOGON,0x67b1,0x6801,0x6805,0x6800,0x67d7,0x409e,0x6b2a,0x6b6b,0x3c52,
+    0x3c5e,0x3c60,0x3c5f,0x6be1,0x3c92,0x3cd6,0x6d23,0x6cff,0x6d14,0x6d05,
+    0x6d13,0x6d06,0x6d21,0x3cde,0x6d15,0x6caf,0x6cf4,0x6d02,0x6d45,UBOGON,
+    0x6d26,0x3cd9,0x6d44,0x3cdd,0x6d24,0x70a5,0x3dac,0x70a3,0x3db0,0x70a2,
+    0x70bb,0x70a0,0x70aa,0x3daf,0x3dae,0x70a8,0x70b6,0x70b2,0x70a7,0x3dad,
+    0x3dab,0x70b9,0x722e,0x3e16,0x723c,0x3e30,0x726d,0x3e33,0x3e31,0x72e7,
+    0x72ed,0x3e6e,0x72ec,0x72e5,0x72e2,0x3eb1,0x73c4,0x73bd,0x73cf,0x73c9,
+    0x73c1,0x73d0,0x3eb7,0x73ce
+  },
+  {				/* ku 0e */
+    0x74ed,0x74eb,0x3f1a,0x74ef,0x7549,0x7550,0x7546,0x754a,0x3f59,0x754d,
+    0x75a6,0x3f7a,0x3f78,0x3f7b,0x75a8,0x3fde,0x3fec,0x76c7,0x76ff,0x401e,
+    0x76fd,0x77e6,0x780a,0x409b,0x7804,0x780b,0x7807,0x409d,0x7815,0x7808,
+    0x40fd,0x79d3,0x79d4,0x79d0,0x79d7,0x7a7c,0x4194,0x4193,0x7a7d,0x7a83,
+    0x7a82,0x41c6,0x7ad4,0x7ad5,0x7ad3,0x7ad0,0x7ad2,0x7afe,0x7afc,0x7c77,
+    0x7c7c,0x7c7b,0x42b8,UBOGON,0x42b7,0x42b9,0x4353,UBOGON,0x4352,0x4351,
+    0x7f8f,0x80d3,0x43e3,0x80cb,0x80d2,0x43e2,0x8109,0x80e2,0x80df,0x80c6,
+    0x4463,0x8224,0x82f7,0x82d8,0x82dd,0x44aa,0x44a6,0x82f8,0x82fc,0x44a8,
+    0x44a9,0x82e9,0x44ab,0x82ee,0x44ac,0x82d0,0x830e,0x82e2,0x830b,0x82fd,
+    0x5179,0x8676,0x459e,0x8678
+  },
+  {				/* ku 0f */
+    0x459f,0x45a0,0x8675,0x867d,0x460f,0x8842,0x8866,0x461c,0x898c,0x8a05,
+    0x46ae,0x8a06,0x46b0,0x8c9f,0x47d4,0x8ff1,0x8fe7,0x8fe9,0x8fef,0x90c2,
+    0x90bc,0x48bb,0x90c6,0x90c0,0x48c1,0x48c2,0x90cd,0x90c9,0x48be,0x90c4,
+    0x48e5,0x9581,0x49c6,0x9cec,0x5032,0x4ff9,0x501d,0x4fff,0x5004,0x4ff0,
+    0x5003,0x462e,0x5002,0x4ffc,0x4ff2,0x5024,0x5008,0x5036,0x502e,0x3465,
+    0x5010,0x5038,0x5039,0x4ffd,0x5056,0x4ffb,0x51a3,0x51a6,0x51a1,0x34d1,
+    0x34d0,0x51c7,0x51c9,0x5260,0x5264,0x5259,0x5265,0x5267,0x5257,0x5263,
+    0x34ee,0x5253,0x34ef,0x52cf,0x351e,0x52ce,0x52d0,0x52d1,0x52cc,0x354b,
+    0x354d,0x3556,0x550d,0x54f4,0x3592,0x5513,0x54ef,0x54f5,0x54f9,0x5502,
+    0x5500,0x3593,0x3590,0x5518
+  },
+  {				/* ku 10 */
+    0x54f0,0x54f6,UBOGON,0x3597,0x5519,0x3623,0x5705,0x57c9,0x363f,0x57b7,
+    0x57cd,0x3643,0x3642,0x3644,0x57be,0x57bb,0x3645,0x57db,0x57c8,0x57c4,
+    0x57c5,0x57d1,0x57ca,0x57c0,0x36d9,0x36de,0x5a21,0x5a2a,0x36cf,0x5a1d,
+    0x36cd,0x5a0b,0x36dd,0x36ce,0x36d3,0x36d6,0x5a22,0x36dc,0x36d1,0x5a24,
+    0x36d0,0x5a14,0x5a31,0x36d5,0x5a2f,0x5a1a,0x5a12,0x36d4,0x36db,0x5a26,
+    UBOGON,0x3743,0x5bbc,0x5bbb,0x5bb7,0x5c05,0x5c06,0x5c52,0x5c53,0x37cd,
+    0x37d1,0x5cfa,0x5ceb,0x37ca,0x5cf3,0x5cf5,0x5ce9,0x5cef,0x37d4,0x5e2a,
+    0x5e30,0x5e2e,0x5e2c,0x5e2f,0x5eaf,0x5ea9,0x3886,0x5efd,0x5f32,0x5f8e,
+    0x5f93,0x5f8f,0x604f,0x6099,0x3933,0x607e,0x3937,0x6074,0x604b,0x6073,
+    0x6075,0x392a,0x391f,0x6056
+  },
+  {				/* ku 11 */
+    0x60a9,0x608b,0x60a6,0x3939,0x6093,0x60ae,0x609e,0x60a7,0x6245,0x39f2,
+    0x39f8,0x632e,0x39f7,0x6352,0x6330,0x635b,0x39f4,0x6319,0x631b,0x39f1,
+    0x6331,0x635d,0x6337,0x6335,0x6353,0x39f5,0x635c,0x633f,0x654b,0x3a87,
+    0x4369,0x658b,0x3ab6,0x659a,0x6650,0x6646,0x664e,0x6640,0x3ae9,0x664b,
+    0x6648,0x3aeb,0x6660,0x6644,0x664d,0x3b34,0x6837,0x6824,0x3b62,0x3b5c,
+    0x681b,0x6836,0x3b60,0x682c,0x6819,0x6856,0x6847,0x683e,0x681e,UBOGON,
+    0x6815,0x6822,0x6827,0x6859,0x6858,0x6855,0x6830,0x6823,0x6b2e,0x6b2b,
+    0x6b30,0x6b6c,0x3c61,0x6b8b,0x3c7f,0x6be9,0x6bea,0x6be5,0x6d6b,0x3ce5,
+    0x3ce6,0x6d73,0x6d57,0x3ce9,0x3cf3,0x6d5d,0x6d56,0x6d8f,0x6d5b,0x6d1c,
+    0x6d9a,0x6d9b,0x6d99,0x3cee
+  },
+  {				/* ku 12 */
+    0x6d81,0x6d71,0x3ced,0x3cec,0x6d72,0x6d5c,0x6d96,0x70c4,0x70db,0x70cc,
+    0x70d0,0x70e3,0x70df,0x3db3,0x70d6,0x70ee,0x70d5,0x3db5,0x3e27,0x3e35,
+    0x3e36,0x727a,0x3e71,0x72f5,0x7302,0x3eb8,0x3ec2,0x73e2,0x73ec,0x73d5,
+    0x73f9,0x73df,0x73e6,0x3ec8,0x3ec0,0x3ec1,0x3ec4,0x73e4,0x73e1,0x74f3,
+    0x3f1f,0x3f1c,0x3f1d,0x3f4d,0x7556,0x7555,0x7558,0x7557,0x755e,0x75c3,
+    0x3f87,0x3f82,0x75b4,0x3f7d,0x75b1,0x3fdf,0x4000,0x76cb,0x76cc,0x772a,
+    0x4020,0x7716,0x770f,0x4022,0x4024,0x773f,0x772b,0x770e,0x7724,0x4021,
+    0x7721,0x7718,0x77dd,0x40a4,0x40a5,0x7824,0x7836,0x4101,0x7958,0x7959,
+    0x4103,0x7962,0x79da,0x79d9,0x4137,0x79e1,0x79e5,0x79e8,0x79db,0x4138,
+    0x79e2,0x79f0,0x4199,0x4198
+  },
+  {				/* ku 13 */
+    0x4197,0x41c9,0x7ada,0x7add,0x41c7,0x7adb,0x7adc,0x41d9,0x41db,0x7b0d,
+    0x7b0b,0x7b14,0x7c8e,0x7c86,0x427b,0x7c87,0x7c83,0x7c8b,0x427c,0x42bd,
+    0x42bc,0x42c3,0x7d24,0x42c1,0x42bf,0x42c4,0x7d25,0x7f62,0x7f93,0x7f99,
+    0x7f97,0x437e,0x437f,0x7fc4,0x7fc6,0x800a,0x43b4,0x43b3,0x8040,0x803c,
+    0x803b,0x80f6,0x80ff,0x80ee,0x8104,0x8103,0x8107,UBOGON,0x43e6,0x80f7,
+    0x4459,0x445a,0x822d,0x4464,0x8227,0x8229,0x831f,0x8357,0x44b4,0x44b9,
+    0x44b7,0x44b5,0x8321,0x44c1,0x44b1,0x8318,0x8358,0x44b3,0x44ba,0x458c,
+    0x458b,0x458d,0x8684,0x869f,0x869b,0x8689,0x86a6,0x8692,0x868f,0x86a0,
+    0x884f,0x8878,0x887a,0x886e,0x887b,0x8884,0x8873,0x4678,0x4677,0x8a0d,
+    0x8a0b,0x8a19,0x46b2,0x47d6
+  },
+  {				/* ku 14 */
+    0x8ed0,0x4845,0x4892,0x4895,0x8ff9,0x9009,0x9008,0x48c6,0x90de,0x9151,
+    0x48e7,0x48e8,0x91db,0x91df,0x91de,0x91d6,0x91e0,0x9585,0x9660,0x9659,
+    0x49cb,0x9656,0x49cd,0x49f1,0x96bd,0x4b22,0x3421,0x5042,0x5059,0x346f,
+    0x5044,0x5066,0x5052,0x5054,0x5071,0x5050,0x507b,0x507c,0x5058,0x3470,
+    0x3464,0x5079,0x506c,0x5078,0x51a8,0x51d1,0x51cf,0x5268,0x5276,0x52d4,
+    0x352d,0x53a0,0x53c4,0x3558,0x5558,0x554c,0x5568,0x35a6,0x5549,0x35a4,
+    0x359f,0x555d,0x5529,UBOGON,0x5554,0x5553,0x35a3,0x555a,0x35a0,0x553a,
+    0x553f,0x552b,0x57ea,0x364a,0x57ef,0x3647,0x3648,0x57dd,0x57fe,UBOGON,
+    0x57de,0x57e6,0x3649,0x57e8,0x57ff,0x5803,0x58f7,0x68a6,0x591f,0x369e,
+    0x595b,0x595d,0x595e,UBOGON
+  },
+  {				/* ku 15 */
+    0x36e8,0x5a2b,0x36ec,0x5a3b,0x36ed,0x36e6,0x5a61,0x5a3a,0x5a6e,0x5a4b,
+    0x5a6b,0x36eb,0x36e7,0x5a45,0x5a4e,0x5a68,0x5a3d,0x5a71,0x5a3f,0x5a6f,
+    0x5a75,0x36e9,0x5a73,0x5a2c,0x5a59,0x5a54,0x5a4f,0x5a63,0x375c,0x375d,
+    0x5bc8,0x3760,0x5bc3,0x375b,0x5c5b,0x5c61,0x3799,0x5d21,0x5d0a,0x5d09,
+    0x37d8,0x5d2c,0x5d08,0x37da,0x37dd,0x5d2a,0x5d15,0x37e0,0x5d10,0x5d13,
+    0x37e5,0x5d2f,0x5d18,0x37d7,0x5de3,0x5e39,0x5e35,0x5e3a,0x5e32,0x384e,
+    0x388c,0x3888,UBOGON,0x5ebb,0x5eba,0x5f34,0x5f39,0x38ce,UBOGON,0x38e5,
+    0x38e6,0x6098,0x3932,0x60d0,0x3940,0x3947,0x394c,0x60d7,0x60aa,0x3935,
+    0x60a1,0x60a4,0x3930,0x60ee,0x3943,0x60e7,0x394d,0x60e8,0x60de,0x39b7,
+    0x39f3,0x637e,0x638b,0x3a02
+  },
+  {				/* ku 16 */
+    0x3a0b,0x6379,0x6386,0x6393,0x3a04,0x6373,0x636a,UBOGON,0x636c,0x3a08,
+    0x637f,0x39fc,0x63b2,0x63ba,0x39ff,0x3a00,0x6366,0x6374,0x3a8b,0x655a,
+    0x3a8d,0x654e,0x654d,0x658d,0x658e,0x65ad,0x3aca,0x65c7,0x65ca,0x3acb,
+    0x65c9,UBOGON,0x65e3,0x6657,0x3af3,0x6663,0x6667,0x671a,0x6719,0x6716,
+    0x3b36,0x3b6a,0x689e,0x68b6,0x6898,0x6873,0x3b6b,0x689a,0x688e,0x68b7,
+    0x68db,0x68a5,0x686c,0x68c1,0x6884,0x3b71,0x3b68,0x6895,0x687a,0x6899,
+    0x3b72,0x68b8,0x68b9,0x6870,0x3c2e,0x6b35,0x3c62,0x6b90,0x6bbb,0x6bed,
+    0x3c98,0x3cb5,0x3ceb,0x6dc1,0x6dc3,0x6dce,0x3cfb,0x3cf8,0x6dad,0x6e04,
+    0x3cf5,0x6db9,0x3d08,0x6de7,UBOGON,0x6e08,0x6e06,0x3d0a,0x6e0a,0x6db0,
+    0x3d06,0x6df8,0x6e0c,0x3cfd
+  },
+  {				/* ku 17 */
+    0x6db1,0x3cfa,0x6e02,0x6e07,0x6e09,0x6e01,0x6e17,0x6dff,0x6e12,0x3dba,
+    0x3db9,0x7103,0x7107,0x7101,0x70f5,0x70f1,0x7108,0x70f2,0x710f,0x3dbb,
+    0x70fe,0x3e18,0x3e40,0x3e3d,0x731a,0x7310,0x730e,0x7402,0x73f3,0x3ecd,
+    0x3ec9,0x73fb,0x3ecb,0x3eca,0x3ece,0x751b,0x7523,0x7561,0x7568,0x3f5e,
+    0x7567,0x75d3,0x3f91,0x3f8c,0x7690,0x3fe1,0x4002,0x76d5,0x76d7,0x76d6,
+    0x7730,0x402b,0x7726,0x402a,0x7740,0x3e14,0x771e,0x40ad,0x40a3,0x40ab,
+    0x7847,0x40af,0x784b,0x7851,0x784f,0x7842,0x7846,0x4104,0x796e,0x796c,
+    0x79f2,0x4144,0x79f1,0x79f5,0x79f3,0x79f9,0x413d,0x4147,0x419c,0x7a9a,
+    0x7a93,0x7a91,0x7ae1,0x41e0,0x41e4,0x7b21,0x7b1c,0x7b16,0x7b17,0x7b36,
+    0x7b1f,0x4280,0x7c93,0x7c99
+  },
+  {				/* ku 18 */
+    0x7c9a,0x7c9c,0x42ca,0x7d49,0x42d4,0x7d34,0x7d37,0x42d2,0x7d2d,0x42cb,
+    0x7d4c,0x42ce,0x42d3,0x7d48,0x4344,0x4348,0x7f3b,0x4345,0x4381,0x4386,
+    0x4385,0x8008,0x801a,0x43a3,0x801d,0x43b5,0x8049,0x8045,0x8044,0x7c9b,
+    0x43fa,0x43f9,0x812a,0x812e,0x43fb,0x43f2,0x8131,0x43ef,0x811a,0x8134,
+    0x8117,0x445b,0x4466,0x44ce,0x831d,0x8371,0x8384,0x8380,0x8372,0x83a1,
+    0x35b4,0x8379,0x8391,0x44c8,0x839f,0x83ad,0x44d1,0x44c5,0x8323,0x44d2,
+    0x8385,0x839c,0x83b7,0x8658,0x865a,0x458f,0x8657,0x86b2,0x45a7,0x86ae,
+    0x45a5,0x45a4,0x4611,0x8845,0x889c,0x8894,0x88a3,0x888f,0x88a5,0x88a9,
+    0x88a6,0x888a,0x88a0,0x8890,0x8992,0x8991,0x8994,0x46b5,0x8a26,0x8a32,
+    0x8a28,0x46b4,0x46bd,0x8a1c
+  },
+  {				/* ku 19 */
+    0x46bb,0x8a2b,0x8a20,0x46b9,0x8a29,0x46c2,0x46be,0x46ba,0x8a21,0x8c3a,
+    0x3ab7,0x8c5b,0x8c58,0x8c7c,0x4758,0x8ca6,0x8cae,0x8cad,0x8d65,0x479b,
+    0x8d7e,0x479c,0x8d7c,0x8d7f,0x8d7a,0x8dbd,0x47da,0x47de,0x8dc0,0x8dbb,
+    0x8ead,0x8eaf,0x8ed6,0x484d,0x4846,0x4847,0x484b,0x484c,0x8ed9,0x4848,
+    0x4899,0x9012,0x900e,0x9025,0x489b,0x9013,0x90ee,0x48ce,0x90ab,0x90f7,
+    0x48eb,0x9159,0x9154,0x91f2,0x91f0,0x91e5,0x91f6,0x491c,0x498c,0x9587,
+    0x49d1,0x965a,0x49d6,0x49d3,0x966e,0x49d4,0x49d0,0x49d5,0x9679,0x4a0b,
+    0x98e1,0x98e6,0x4bc6,0x9ec4,0x9ed2,0x4e80,0x3424,0x4e81,0x508f,0x5097,
+    0x5088,0x5089,0x3474,0x347a,0x5081,0x5160,UBOGON,0x34c3,0x5e42,0x51d3,
+    0x34d4,0x34d5,0x51d2,0x51d6
+  },
+  {				/* ku 1a */
+    0x5273,0x34fb,0x5270,0x34f7,0x3532,UBOGON,0x53a8,0x53a6,0x53c5,0x5597,
+    0x55de,0x35ba,0x35bf,0x5596,0x55b4,0x35c7,0x5585,0x35b7,0x559b,0x55a0,
+    0x35b9,0x5559,0x35c3,0x5586,0x35bd,0x35d0,0x55af,0x557a,0x35c1,0x35be,
+    0x35cd,0x559e,0x35cb,0x55a9,0x570f,0x570e,0x581a,0x364f,0x581f,0x3653,
+    0x583c,0x5818,0x583e,0x5826,0x3655,0x583a,UBOGON,0x5822,0x3651,0x58fb,
+    0x5963,0x5964,0x369f,0x5aa8,0x5aa3,0x5a82,0x5a88,0x5aa1,0x5a85,0x5a98,
+    0x36fe,0x5a99,0x36fb,0x5a89,0x5a81,0x5a96,0x5a80,0x36f1,0x36f5,0x5a91,
+    0x36ef,0x3704,0x3703,0x36f4,0x5acf,0x36f3,0x3702,0x36f7,0x36fa,0x36fd,
+    0x36ee,0x5a87,0x5aa0,0x36f0,0x5a79,0x36f2,0x5a86,0x5aab,0x5aaa,0x5aa4,
+    0x5a8d,0x5a7e,0x3744,0x5bd5
+  },
+  {				/* ku 1b */
+    0x3762,0x3777,0x3dc9,0x5c1e,0x5c5f,0x5c5e,0x5d44,0x5d3e,0x37e8,0x5d48,
+    0x5d1c,0x37ef,0x5d5b,0x5d4d,0x37e6,0x37ed,0x5d57,0x37e7,0x5d53,0x5d4f,
+    0x37eb,0x5d3b,0x5d46,0x382d,0x3855,0x5e46,0x5e47,0x3853,0x5e48,0x5ec0,
+    0x5ebd,0x5ebf,0x3890,0x5f11,0x38be,0x5f3e,0x5f3b,0x38bd,0x5f3a,0x38cf,
+    0x38d0,0x38ec,0x5fa7,0x394b,0x60ea,0x3948,0x6107,0x6122,0x610c,0x3955,
+    0x3951,0x60b3,0x60d6,0x60d2,0x394e,0x60e3,0x60e5,0x60e9,0x396b,0x395e,
+    0x6111,0x60fd,0x3960,0x3967,0x611e,0x6120,0x6121,0x621e,0x39b8,0x63e2,
+    0x63de,0x63e6,0x3a14,0x3a0f,0x3a07,0x3a13,0x63f8,0x3a17,0x63fe,0x63c1,
+    0x63bf,0x63f7,0x63d1,0x655f,0x6560,0x6561,0x3a9a,0x3ab8,0x65d1,0x3af7,
+    0x3af8,0x667d,0x666b,0x667f
+  },
+  {				/* ku 1c */
+    0x3afd,0x3af5,0x6673,0x6681,0x666d,0x6669,0x3afa,0x3b38,0x671e,0x68ed,
+    0x3b87,0x3b80,0x3b88,0x3b79,0x6903,0x3b7c,0x68fe,0x68e5,0x691e,0x6902,
+    0x3b83,0x3b85,0x6909,0x68ca,0x6900,UBOGON,0x6901,0x6918,0x68e2,0x68cf,
+    0x3b7b,0x692e,0x68c5,0x68ff,0x3b86,0x691c,0x68c3,0x3c34,0x6b6f,0x3c55,
+    0x6b6e,0x3c68,0x6bbe,0x3c9c,0x6bf4,0x6c2d,0x3cfc,0x6db6,0x6e75,0x6e1e,
+    0x3d1a,0x6e18,0x3d17,0x6e48,0x3d1b,0x6e4f,0x3d13,0x6e42,0x6e6a,0x6e70,
+    0x6dfe,0x3d05,0x3d07,0x6e6d,0x3d1c,0x6e7b,0x6e7e,0x6e59,0x3d11,0x6e57,
+    0x3d16,0x6e80,0x6e50,0x3d15,0x6e29,0x6e76,0x6e2a,0x6e4c,0x712a,0x3dcb,
+    0x7135,0x712c,0x7137,0x711d,0x3dc5,0x3dc2,0x7138,0x3dcd,0x7134,0x712b,
+    0x7133,0x7127,0x7124,0x3dca
+  },
+  {				/* ku 1d */
+    0x712d,0x7232,0x7283,0x7282,0x7287,0x7306,0x7324,0x7338,0x732a,0x732c,
+    0x732b,0x3e83,0x732f,0x7328,0x7417,0x3ed6,0x3ed5,0x7419,0x7438,0x3ed1,
+    0x741f,0x7414,0x743c,0x73f7,0x741c,0x7415,0x7418,0x7439,0x74f9,0x7524,
+    UBOGON,0x3f52,0x3f5f,0x756e,0x756d,0x7571,0x758e,0x3f95,0x75e5,0x3f9d,
+    0x3f98,0x3f9e,0x3f96,0x7694,0x76b3,0x4003,0x76d9,0x402f,0x7748,0x7749,
+    0x7743,0x4031,0x4033,0x7742,0x77df,0x40b4,0x7863,0x7876,0x40b0,0x785f,
+    0x7866,0x7966,0x7971,0x4108,0x4107,0x7976,0x7984,0x7975,0x79ff,0x7a07,
+    0x414e,0x7a0e,0x7a09,0x4150,0x4152,0x41a1,0x41a3,0x41a5,0x41cc,0x7ae7,
+    0x7ae2,0x7b55,0x41ef,0x41ea,0x7b43,0x7b57,0x7b6c,0x7b42,0x7b53,0x41ed,
+    0x7b41,0x4285,0x4284,0x7ca7
+  },
+  {				/* ku 1e */
+    0x7ca0,0x7ca6,0x7ca4,0x7d74,0x42db,0x7d59,0x42d9,0x7d60,0x7d57,0x7d6c,
+    0x7d7e,0x7d64,0x42d7,0x7d5a,0x7d5d,0x42da,0x42de,0x42d8,0x7d76,0x7d4d,
+    0x7d75,0x42d5,0x7fd3,0x7fd6,0x439c,0x439d,0x8060,0x804e,0x8145,0x813b,
+    0x43fe,0x8148,0x8142,0x8149,0x8140,0x8114,0x8141,0x4407,0x81ef,0x81f6,
+    0x8203,0x446a,0x83ed,0x44e7,0x83da,0x8418,0x83d2,0x8408,0x44e2,0x8400,
+    0x44df,0x44e1,0x44e5,0x8417,0x8346,0x8414,0x83d3,0x8405,0x841f,0x8402,
+    0x8416,0x83cd,0x83e6,0x4591,0x865d,0x86d5,0x86e1,0x45b4,0x45b0,0x45b5,
+    0x45ae,0x86ee,0x8847,0x8846,0x462d,0x462c,0x88bb,0x462b,0x88bf,0x88b4,
+    0x4629,0x88b5,0x467f,0x899a,0x8a43,0x46c9,0x46cb,0x8a5a,0x46c5,0x46c6,
+    0x46ca,0x8a35,0x8a38,0x8a42
+  },
+  {				/* ku 1f */
+    0x8a49,0x8a5d,0x8a4b,0x8a3d,0x46d2,0x46d0,0x472d,0x4735,0x8c60,0x8c5e,
+    0x8c7f,0x8c7e,0x8c83,0x476c,0x8cb1,0x8d87,0x479d,0x47a0,0x8d88,0x8d83,
+    0x47a2,0x479f,0x8d86,0x8d8b,0x8d82,0x8dca,0x8dd2,0x47eb,0x47e2,0x8dd4,
+    0x8dc9,0x8eb0,0x4836,0x4832,0x4850,0x8ef2,0x8ee4,0x8ef3,0x8eea,0x484f,
+    0x8efd,0x4852,0x8f9d,0x902b,0x902a,0x489e,0x9028,0x9029,0x902c,0x48a0,
+    0x489c,0x903a,0x9030,0x9037,0x903b,0x48d1,0x910a,0x48ef,0x48f0,0x48f1,
+    0x91fe,0x9220,0x491d,0x920b,0x491f,0x9218,0x9222,0x491e,0x921b,0x9208,
+    0x4920,0x920e,0x9213,0x498e,0x4991,0x9595,UBOGON,0x4990,0x49d7,0x968c,
+    0x967b,0x967f,0x9681,0x49d9,0x9682,0x49f4,0x49f6,0x3560,0x49f5,0x49f3,
+    0x96ee,0x96ed,0x4a0c,0x96ec
+  },
+  {				/* ku 20 */
+    0x975f,0x976f,0x4a51,0x976d,0x4aa6,0x4aa7,0x4aa8,0x4b27,0x4b24,0x4b25,
+    0x98f0,0x4b2a,0x4b74,0x4bc7,0x9aa9,0x4be7,0x4bed,0x9ae0,0x4eb7,0x342e,
+    0x347b,0x50cc,0x50bc,0x347c,0x50aa,0x50b9,0x347d,0x50ab,0x50c3,0x50cd,
+    0x517e,0x527e,0x5279,0x34fd,UBOGON,0x52e1,0x52e0,0x52e7,0x5380,0x53ab,
+    0x53aa,0x53a9,0x53e0,0x55ea,0x35da,0x55d7,0x35d6,0x35db,0x55c1,0x5715,
+    0x365b,0x586c,0x365c,0x585c,0x5850,0x5861,0x586a,0x5869,0x5856,0x5860,
+    0x5866,0x585f,0x5923,0x5966,0x5968,0x3706,0x370b,0x5ace,0x370d,0x5ac5,
+    0x5ac3,0x370a,0x3713,0x5ad0,0x3710,0x3712,0x3709,0x3708,0x3711,0x370f,
+    0x5b74,0x5b76,0x5bdc,0x5bd7,0x5bda,0x5bdb,0x3767,0x5c20,0x5d6d,0x5d66,
+    0x37f6,0x5d64,0x5d6e,UBOGON
+  },
+  {				/* ku 21 */
+    0x5d60,0x5f42,0x5f5a,0x5f6e,0x3964,0x396c,0x6130,0x613a,0x612a,0x6143,
+    0x6119,0x6131,0x396d,0x613d,0x397a,0x3975,0x3a0d,0x6408,0x6432,0x6438,
+    0x3a1e,0x6431,0x3a1b,0x6419,0x3a2a,0x6411,0x3a1f,0x3a22,0x6429,0x641d,
+    0x3a25,0x3a27,0x3a29,0x643c,0x3a24,0x6446,0x6447,0x3a28,0x3a26,0x643a,
+    0x6407,0x3a23,0x656b,0x3a9f,0x6570,0x656d,0x3ab1,0x65e4,0x6693,0x3b03,
+    0x3b07,0x3b0c,0x3b06,0x668f,0x3b04,0x3b09,0x6692,0x3b05,0x668e,0x3b08,
+    0x6946,0x3b96,0x3b9c,0x3b9f,0x3b9b,0x3b98,0x3b99,0x3b94,0x6931,0x3b8d,
+    0x3ba3,0x693e,0x3b93,0x697c,0x6943,0x3b92,0x6973,UBOGON,0x6955,0x3b8e,
+    0x3b8c,0x6985,0x694d,0x6950,0x6947,0x6967,0x6936,0x6964,0x6961,0x3b9a,
+    0x697d,0x6b44,0x6b40,0x6b71
+  },
+  {				/* ku 22 */
+    0x6b73,0x6b9c,0x3c6a,0x3c6d,0x3c84,0x6bc1,0x3ca0,0x6bfa,0x6c31,0x6c32,
+    0x3d1d,0x3d26,0x6eb8,0x6ea8,0x3d33,0x6e91,0x6ebb,0x3d38,0x6e9a,0x3d30,
+    0x3d28,0x6ea9,0x3d27,0x3d2a,0x6eb5,0x6e6c,0x6ee8,0x3d31,0x6edd,0x6eda,
+    0x6ee6,0x6eac,0x3d34,0x3d2e,0x3d3b,0x6ed9,0x6ee3,0x6ee9,0x6edb,0x3d29,
+    0x716f,0x3dd2,0x3dd8,0x7148,0x3dcf,0x714a,0x716b,0x3dd9,0x714f,0x7157,
+    0x7174,0x3dce,0x3dd3,0x3dd0,0x7145,0x7151,0x716d,0x3ba1,0x7251,0x7250,
+    0x724e,0x3e47,0x7341,0x3e8b,0x732e,0x7346,0x3ed4,0x7427,0x3ede,0x7448,
+    0x7453,0x743d,0x3edf,0x745d,0x7456,0x3ed7,0x741e,0x7447,0x7443,0x7458,
+    0x7449,0x3ee1,0x744c,0x7445,0x743e,0x3f2f,0x7501,0x751e,0x3f62,0x3f63,
+    0x757a,0x75ee,0x7602,0x7697
+  },
+  {				/* ku 23 */
+    0x7698,0x3fe2,0x4004,0x4043,0x775d,0x7764,0x7753,0x7758,0x7882,0x7890,
+    0x788a,0x40be,0x787a,0x787d,0x40ba,0x788b,0x7878,0x40bc,UBOGON,0x788d,
+    0x7888,0x7892,0x7881,0x797e,0x7983,0x410d,0x410e,0x4111,0x7980,0x410f,
+    0x4112,0x4155,0x7a0f,0x4159,0x415b,0x7a1d,0x4157,0x7aa1,0x7aa4,0x41ce,
+    0x7ae9,0x7aea,0x41fe,0x7b62,0x7b6b,0x41fc,0x7b5e,0x41f5,0x7b79,0x41f9,
+    0x41fa,0x7b6f,0x7b68,0x4288,0x4289,0x7cae,0x428a,0x4287,0x428b,0x7cb0,
+    0x42e6,0x7d90,0x42ed,0x7d8a,0x42e5,0x7d8b,0x7d99,0x7d95,0x42e0,0x7d87,
+    0x7d78,0x7d97,0x7d89,0x7d98,0x42e1,0x435b,0x435c,0x7fa3,0x438f,0x438b,
+    0x438d,0x7fdd,0x8057,0x43b9,0x8163,0x816a,0x816c,0x440f,0x4419,0x4413,
+    0x815d,0x8175,0x4418,0x815f
+  },
+  {				/* ku 24 */
+    0x4416,0x817d,0x816d,0x4453,UBOGON,0x8241,0x844f,0x8484,0x44f6,0x847f,
+    0x44f5,0x8448,0x842a,0x847b,0x8472,0x8464,0x842e,0x845c,0x8453,0x44f7,
+    0x8441,0x84c8,0x44f0,0x8462,0x8480,0x843e,0x8483,0x8471,0x44f9,0x844a,
+    0x8455,0x8458,0x4592,0x4595,0x4596,0x86fc,0x86fd,0x8715,0x45b9,0x8716,
+    0x86ff,0x45bd,0x45b8,0x4612,0x8858,0x88cf,0x88e0,0x4680,0x4681,0x469a,
+    0x4698,0x89e7,0x8a6a,0x8a80,0x46d4,0x8a6f,0x8a65,0x46da,0x8a78,0x8a7d,
+    0x8a88,0x46d6,0x46db,0x8a64,0x8a7e,0x46dc,0x8a67,0x8c63,0x8c88,0x4771,
+    0x8ccd,0x4772,0x8cc9,0x47a8,0x8ded,0x47f0,UBOGON,0x47f1,0x47fd,0x4838,
+    0x4837,0x4839,0x8eb1,0x4855,0x4853,0x8f04,0x8f9e,0x8fa0,0x9043,0x9046,
+    0x9048,0x9045,0x9040,0x904c
+  },
+  {				/* ku 25 */
+    0x48d5,0x48bd,0x910c,0x9113,0x9115,0x48f5,0x916b,0x9167,0x925d,0x9255,
+    0x9235,0x4921,0x9259,0x922f,0x923c,0x928f,0x925c,0x926a,0x9262,0x925f,
+    0x926b,0x926e,0x923b,0x9244,0x9241,0x959a,0x4992,0x9599,0x49de,0x49db,
+    0x49da,0x968f,0x49df,0x9696,0x49f9,0x49f8,0x49fa,0x96f4,0x96fc,0x4a0e,
+    0x9755,0x4a43,0x9779,0x4a56,0x4a53,0x4a9e,0x97ee,0x97f5,0x4aa9,0x980b,
+    0x4afa,0x98f3,0x4b31,0x4b30,0x98f7,0x98ff,0x98f5,0x4b32,0x98ec,0x98f1,
+    0x4b29,0x4b2e,0x999a,0x4b76,0x9ae2,0x9b3d,0x9b5d,0x9ce8,0x4ca5,0x9ceb,
+    0x9cef,0x9cee,0x9e81,0x9f14,0x50d0,0x50d9,0x50dc,0x50d8,0x348c,0x50e1,
+    0x50eb,0x348b,0x3489,0x50f4,0x50e2,0x50de,0x348d,0x3486,0x34d7,0x51f4,
+    0x3504,0x3507,0x3503,0x52ed
+  },
+  {				/* ku 26 */
+    0x52ea,0x3522,0x5332,0x3551,0x53ae,0x53b0,0x3561,0x55fb,0x5603,0x560b,
+    0x35e9,0x5607,0x35e5,0x55f8,0x35e4,0x5628,0x561e,0x35e3,0x5618,0x5611,
+    0x5651,0x5605,0x5717,0x5892,0x3665,0x588c,0x3663,0x5878,0x5884,0x5873,
+    0x58ad,0x5897,0x5895,0x5877,0x5872,0x5896,0x588d,0x5910,0x368c,0x596c,
+    0x371a,0x5ae7,0x3715,0x5ae4,0x3720,0x3721,0x5aef,0x5626,0x371c,0x371b,
+    0x5af0,0x5d7b,0x37fe,0x5d83,0x3804,0x3801,0x5d8b,0x5d8c,0x3800,0x5d78,
+    0x5e52,0x386d,0x3893,0x5ed0,0x5ecf,0x38a1,0x5fb3,0x5fb4,0x3976,0x3979,
+    0x3972,0x617b,0x3983,0x616f,0x6181,0x613c,0x6142,0x6138,0x6133,UBOGON,
+    0x6160,0x6169,0x617d,0x6186,0x622c,0x6228,0x3a38,0x644c,0x3a30,0x6457,
+    0x647c,0x3a34,0x3a3a,0x6455
+  },
+  {				/* ku 27 */
+    0x6462,0x6471,0x646a,0x6456,0x643b,0x6481,0x3a35,0x644f,0x647e,0x6464,
+    0x3a3f,0x3a40,0x3a32,0x3a31,0x3a36,0x6571,UBOGON,0x3b0f,0x66a5,0x669a,
+    0x669c,0x3b10,0x66a6,0x3b0d,0x66a4,0x698f,0x69c5,0x69c8,0x6992,0x69b2,
+    0x3ba9,0x3bb4,0x3bac,0x69e3,0x69c0,0x69d6,0x69d1,0x699f,0x69a2,0x69d2,
+    0x3bb8,0x3bae,UBOGON,0x69e1,0x69d5,0x699d,0x3bb3,0x3bba,0x6998,0x3c3f,
+    0x6b74,0x6ba1,0x3d3c,0x6ef0,0x6ef3,0x3d42,0x3d40,0x6f1b,0x6f0c,0x6f1d,
+    0x6f34,0x6f28,0x6f17,0x3d3e,0x6f44,0x6f42,0x6f04,0x6f11,0x6efa,0x6f4a,
+    0x7191,0x718e,0x3de1,0x718b,0x718d,0x717f,0x718c,0x717e,0x717c,0x7183,
+    0x3de6,0x7188,0x3de0,0x3e15,0x7294,0x3e93,0x7355,0x7353,0x734f,0x7354,
+    0x746c,0x7465,0x7466,0x7461
+  },
+  {				/* ku 28 */
+    0x746b,0x7468,0x7476,0x3ee7,0x7460,UBOGON,0x7474,0x7506,0x760e,0x3fad,
+    0x7607,0x3fae,0x3fe3,0x76b9,0x3ff5,0x76b7,0x76e2,0x4006,0x7774,0x7777,
+    0x7776,0x7775,0x404f,0x7778,0x7771,0x4054,0x777a,0x715b,0x777b,0x78a6,
+    0x78ae,0x78b8,0x40cb,0x40e3,0x40c9,0x78b1,0x78af,0x4113,0x7989,0x7987,
+    0x4115,0x4161,0x7a29,0x4166,0x7a2a,0x4164,0x7a2d,0x7a2c,0x4160,0x7a32,
+    0x4163,0x7aec,0x7af0,0x7b81,0x7b9e,0x7b83,0x420a,0x7b92,0x4204,0x7ba3,
+    0x7b9f,0x7b93,0x4207,0x7b86,0x7cb8,0x7cb7,0x428d,0x428f,0x4290,0x4292,
+    0x42ec,0x7dc8,0x7db6,UBOGON,0x7dd1,0x42e7,0x7da8,0x7dab,0x42f2,0x7db3,
+    0x7dcd,0x42ee,0x7dcf,0x7da4,0x42ef,0x434c,0x7f41,0x7f6f,0x7f71,0x435e,
+    0x435f,0x4376,0x4374,0x4372
+  },
+  {				/* ku 29 */
+    0x4390,0x8023,0x805b,0x43be,0x8061,0x805f,0x8181,0x4426,0x4425,0x8184,
+    0x8213,0x4474,0x824a,0x824c,0x44fd,0x4505,0x4501,0x84bd,0x8495,0x4509,
+    0x8492,0x84c3,0x450c,0x8496,0x84a5,0x84b5,0x84b3,0x84a3,0x84e4,0x84d8,
+    0x84d5,0x450d,0x84b7,0x84ad,0x84da,0x8493,0x8736,0x45c0,0x45c5,0x45c9,
+    0x873d,0x872b,0x8747,0x8739,0x45d5,0x8745,0x871d,0x4641,0x88ff,0x88ea,
+    0x4633,0x88f5,0x463a,0x8900,0x88ed,0x8903,0x88e9,0x4640,0x4642,0x89ea,
+    0x46e8,0x8a9b,0x8a8e,0x8aa2,0x46e4,0x8a9c,0x8a94,0x8a90,0x8aa9,0x8aac,
+    0x46e7,0x8a9f,0x46e6,0x46e1,0x8a9d,0x4739,0x8c67,0x475c,0x4775,0x8cd0,
+    0x8cd6,0x8cd4,0x8d98,0x8d9a,0x8d97,0x47ae,0x47b0,0x47fa,0x8e0b,0x8e08,
+    0x8e01,0x8eb4,0x8eb3,0x485b
+  },
+  {				/* ku 2a */
+    0x8fa1,0x8fa2,0x48a5,0x905a,0x48a2,0x9061,0x905f,0x48db,0x48da,0x9125,
+    0x917b,0x9176,0x917c,0x4924,0x9289,0x92f6,0x92b1,0x92ad,0x9292,0x9281,
+    0x9284,0x4926,0x92ae,0x9290,0x929e,0x4998,0x4996,0x499a,0x95a2,0x95a7,
+    0x4997,0x49e1,0x49e0,0x49e3,0x49e2,0x96a0,0x969d,0x969f,0x96d0,0x49fb,
+    0x96d1,0x4a12,0x4a14,0x9759,0x4a45,0x9764,0x4a5c,0x4a5d,0x4ab8,0x9819,
+    0x4aba,0x9814,0x9815,0x981a,0x4b03,0x4b35,0x4b36,0x4b39,0x9906,0x4b2d,
+    0x98f8,0x9901,0x4b7a,0x99be,0x99bc,0x99b7,0x99b6,0x99c0,0x4b78,0x99b8,
+    0x4b7b,0x4b7c,0x4b7e,0x99c4,0x4b7d,0x99bf,0x4bc9,0x9ada,0x9ae4,0x9ae9,
+    0x9ae8,0x9aea,0x9ae5,0x4bf3,0x9b26,0x4c1a,0x4c19,0x9b40,0x4c1f,0x4ca6,
+    0x4ca7,0x4ca8,0x4cab,0x4ca9
+  },
+  {				/* ku 2b */
+    0x4d2e,0x9ebd,0x4d5e,0x3495,0x3493,0x3492,0x510e,0x3496,0x50f7,0x3497,
+    0x50fc,0x510d,0x5101,0x51da,0x51d9,0x51db,0x5286,0x528e,0x52ee,0x5333,
+    0x53b1,0x35f5,0x5647,0x562d,0x5654,0x35ea,0x564b,0x5652,0x5631,0x5644,
+    0x5656,0x5650,0x562b,0x35f3,0x564d,0x5637,0x564f,0x58a2,0x58b7,0x3669,
+    0x58b2,0x366b,0x58aa,0x58b5,0x58b0,0x366c,0x58b4,0x58a4,0x58a7,0x3668,
+    0x5926,0x5afe,0x3728,0x5b04,0x3726,0x5afc,0x3725,0x5b06,0x5b0a,0x5afa,
+    0x5b0d,0x5b00,0x5b0e,0x376b,0x380f,0x3808,0x5d91,0x380c,0x5d8f,0x5d90,
+    0x5d98,0x5da4,0x5d9b,0x5da3,0x5d96,0x5de4,0x5e5a,0x3860,0x3862,0x5e5e,
+    0x3898,0x5fb8,0x6157,0x615c,0x61a6,0x6195,0x6188,0x398a,0x61a3,0x618f,
+    0x3984,0x6164,0x397f,0x6159
+  },
+  {				/* ku 2c */
+    0x6178,0x3982,0x6185,0x6187,0x619e,0x3996,0x3989,0x6198,0x619c,0x398d,
+    0x39bc,0x622f,0x6480,0x649b,0x648e,0x648d,0x6494,0x64c6,0x3a44,0x64a8,
+    0x6483,0x3a3c,0x64b9,0x6486,0x64b4,0x64af,0x6491,0x3a4e,0x64aa,0x64a1,
+    0x64a7,0x66b6,0x66b3,0x3b14,0x66bc,0x66ac,0x3b15,0x66ad,0x6a0e,0x3bce,
+    0x6a1c,0x6a1a,0x3be0,0x3bc2,0x6a0b,0x3bbf,0x69ef,0x6a0c,0x69f0,0x6a22,
+    0x3bc4,0x69d8,0x3bcf,0x6a12,0x69fa,0x3bc8,0x6a2a,0x3bcc,0x6a10,0x3bcd,
+    0x3bc7,0x6a29,0x69f9,0x69ea,0x6a2c,0x6a24,0x4cb7,0x69e9,0x6b52,0x6b4f,
+    0x6b53,0x3c43,0x3cb6,0x6f10,0x6f65,0x6f75,0x3d51,0x3d4a,0x3d4d,0x3d56,
+    0x6fd0,0x3d53,0x6f5c,0x6f3d,0x6f71,0x3d59,0x6f91,0x6f0b,0x6f79,0x6f81,
+    0x6f8f,0x3d4e,0x6f59,0x6f74
+  },
+  {				/* ku 2d */
+    0x3dee,0x71ae,0x3dec,0x71a3,0x71ad,0x3deb,0x3def,0x71ab,0x71a6,0x71a2,
+    0x3ded,0x52f2,0x7257,0x7255,0x7299,0x734b,0x747a,0x3ef2,0x3eef,0x3ef1,
+    0x748c,0x7484,0x3eed,0x3ef0,0x7482,0x7493,0x747b,0x3eee,0x7509,0x4c1b,
+    0x3f50,0x3f66,0x3684,0x3fb8,0x3ff6,0x778a,0x4057,0x7790,0x405e,0x78c6,
+    0x78d3,0x78c0,0x78d2,0x78c7,0x78c2,0x4119,0x799f,0x799d,0x799e,0x4170,
+    0x7a41,0x416e,0x7a38,0x7a3a,0x7a42,0x4172,0x4176,0x7a3e,0x7ab0,0x7bae,
+    0x7bb3,0x4212,0x421f,0x7bbf,0x4211,0x4216,0x7bcd,0x4219,0x7bb2,0x4224,
+    0x4214,0x4225,0x4295,0x4296,0x4293,0x4294,0x7cc4,0x7ccd,0x7cc2,0x7cc6,
+    0x7cc3,0x7cc9,0x7cc7,0x42a0,0x7df8,0x42fb,0x7ded,0x7de2,0x42fc,0x4300,
+    0x42f8,0x7ddc,0x7e02,0x7e01
+  },
+  {				/* ku 2e */
+    0x42f9,0x7dd6,0x4304,0x7de4,0x7dfe,0x4303,0x7e00,0x7dfc,0x7dfd,0x42f3,
+    0x7df5,0x7dff,0x42fa,0x7deb,0x7de5,0x7f78,0x7fae,0x7fe7,0x43bf,0x8065,
+    0x806a,0x8066,0x8068,0x806b,0x8194,0x81a1,0x8192,0x8196,0x8193,0x4479,
+    0x4510,0x8501,0x4514,0x84f8,0x450e,0x84f5,0x451a,0x8504,0x4519,0x4521,
+    0x4523,0x451f,0x851b,0x8503,0x8533,0x8534,0x84ed,0x4525,0x452b,0x8535,
+    0x4516,0x8505,0x4522,0x451b,0x45ce,0x45cf,0x877d,0x45cb,0x45d1,0x45cc,
+    0x8771,0x4617,0x885c,0x88e6,0x890f,0x891b,0x4651,0x89a9,0x89a5,0x89ee,
+    0x8ab1,0x46ed,0x8acc,0x8ace,0x46f4,0x8ab7,0x46f1,0x8ab5,0x8ae9,0x8ab4,
+    0x46f8,0x8ab3,0x8ac1,0x8aaf,0x8aca,0x8ad0,0x472f,0x475e,0x475d,0x8c8e,
+    0x4776,0x4777,0x8ce9,0x8cdb
+  },
+  {				/* ku 2f */
+    0x477e,0x8ceb,0x8da4,0x47b6,0x8da2,0x8d9d,0x47b3,0x47fc,0x4803,0x4800,
+    0x8e2a,0x8e28,0x480a,0x4802,0x8eb8,0x8eb6,0x8eb9,0x8eb7,0x8f22,0x8f2b,
+    0x8f27,0x8f19,0x8fa4,0x4887,0x8fb3,0x48a6,0x9071,0x906a,0x48a9,0x48de,
+    0x9188,0x918c,0x92bf,0x92b8,0x92be,0x92dc,0x92e5,0x492e,0x492d,0x92d4,
+    0x92d6,0x4930,0x92da,0x92ed,0x92f3,0x92db,0x492b,0x92b9,0x92e2,0x92eb,
+    0x95af,0x499e,0x95b2,0x95b3,0x499f,0x49e5,0x49e4,0x96a3,0x96a5,0x49fd,
+    0x49fc,0x4a17,0x4a19,0x970a,0x4a18,0x9787,0x9789,0x978c,0x97ef,0x982a,
+    0x9822,0x4abf,0x981f,0x4b3c,0x9919,0x4b6b,0x99ca,0x99da,0x4b83,0x4b81,
+    0x4b80,0x99de,0x99c8,0x99e0,0x4bca,0x9ab6,0x9ab5,0x4bce,0x9af4,0x4bf6,
+    0x9b6b,0x9b69,0x9b72,0x9b63
+  },
+  {				/* ku 30 */
+    0x4c39,0x9d0d,0x4cae,0x9d01,0x9d0c,0x4cb5,0x9cf8,0x4cb3,0x4cb4,0x9cfe,
+    0x9d02,0x9e84,0x4d22,0x9eab,0x9eaa,0x511d,0x5116,0x3499,0x512b,0x511e,
+    0x511b,0x5290,0x5294,0x5314,UBOGON,0x3602,0x5667,0x3601,0x567b,0x36a1,
+    0x565f,0x5661,0x35fd,0x3673,0x3674,0x3670,0x3676,0x3675,0x3672,0x58c3,
+    0x58ca,0x58bb,0x58c0,0x58c4,0x5901,0x5b1f,0x5b18,0x5b11,0x5b15,0x3729,
+    0x5b12,0x5b1c,0x372a,0x5b22,0x5b79,0x5da6,0x3816,0x5db3,0x5dab,0x5eea,
+    0x3899,0x5f5b,0x38d3,0x38f5,0x61b7,0x61ce,0x61b9,0x61bd,0x61cf,0x61c0,
+    0x6199,0x6197,0x3994,0x61bb,0x61d0,0x61c4,0x6231,0x3a56,0x64d3,0x64c0,
+    0x3a59,0x3a58,0x3a55,0x3a52,0x64dc,0x64d1,0x64c8,0x3a57,0x64d5,0x66c3,
+    0x3b1b,0x3b1c,0x66bf,0x66c5
+  },
+  {				/* ku 31 */
+    0x3b19,0x66cd,0x66c1,0x6706,0x3b3f,0x6724,0x6a63,0x6a42,0x6a52,0x3bdb,
+    0x6a43,0x6a33,0x3be2,0x6a6c,0x6a57,0x3bd7,0x6a4c,0x6a6e,0x3bde,0x3be5,
+    0x3be4,0x3be6,0x3bd6,0x6a37,0x3bdf,0x6a71,0x6a4a,0x6a36,0x3bdc,0x6a53,
+    0x3bda,0x6a45,0x6a70,0x3bd3,0x3bd0,0x6a5c,0x6b58,0x6b57,0x3c86,0x3c87,
+    0x3cad,0x3cb7,0x3d58,0x3d6a,0x6fbb,0x3d62,0x3d61,0x6fbe,0x3d69,0x3d6c,
+    0x3d65,0x6fb5,0x6fd3,0x6f9f,0x3d66,0x6fb7,0x6ff5,0x71b7,0x3df5,0x71bb,
+    0x3df4,0x71d1,0x3df7,0x71ba,0x3df8,0x71b6,0x71cc,0x3dfb,0x3dfc,0x71d3,
+    0x749b,0x3ef5,0x3ef8,0x7496,0x74a2,0x749d,0x750a,0x750e,0x3f3c,0x7581,
+    0x762c,0x7637,0x7636,0x763b,0x3fc5,0x76a1,0x4062,0x4063,0x7798,0x4067,
+    0x7796,0x4066,0x40d9,0x40db
+  },
+  {				/* ku 32 */
+    0x78d6,0x78eb,0x40d8,0x78dc,0x411b,0x79a5,0x79a9,0x9834,0x7a53,0x7a45,
+    0x4179,0x7a4f,0x417d,0x7abd,0x7abb,0x7af1,0x422c,0x4237,0x7bec,0x7bed,
+    0x4230,0x429a,0x7cd3,0x4a00,0x7ce1,0x4305,0x7e19,0x4307,0x4309,0x430a,
+    0x7e27,0x7e26,0x4379,0x43c2,0x806e,0x81af,0x4438,0x4437,0x81ad,0x4421,
+    0x81aa,0x8218,0x445e,0x453d,0x4537,0x4540,0x856f,0x854c,0x451d,0x8542,
+    0x4533,0x855c,0x8570,0x855f,0x4535,0x855a,0x854b,0x853f,0x878a,0x45d8,
+    0x878b,0x87a1,0x878e,0x45dc,0x45de,0x8799,0x885e,0x885f,0x8924,0x89a7,
+    0x8aea,0x8afd,0x8af9,0x8ae3,0x8ae5,0x46fa,0x46fb,0x8aec,0x473d,0x473b,
+    0x473f,0x475f,0x8cf2,0x477f,0x8cef,0x4784,0x8da6,0x47bc,0x4814,0x480f,
+    0x8e3b,0x8e43,0x480e,0x8e32
+  },
+  {				/* ku 33 */
+    0x8f31,0x8f30,0x4860,0x8f2d,0x8f3c,0x8fa7,0x8fa5,0x48ab,0x48ac,0x48aa,
+    0x9137,0x9195,0x918e,0x4904,0x9196,0x4908,0x9345,0x930a,0x4933,0x4934,
+    0x92fd,0x9317,0x931c,0x9307,0x9331,0x9332,0x932c,0x9330,0x9303,0x9305,
+    0x49a2,0x95c2,0x49a4,0x95b8,0x49a5,0x95c1,0x49a7,0x49a6,0x49e7,0x96ab,
+    0x96b7,0x49ff,0x49fe,0x9715,0x9714,0x4a1d,0x4a1c,0x970c,0x9717,0x4a67,
+    0x9793,0x4a94,0x97d2,0x4ac5,0x4ac8,0x9836,0x9831,0x9833,0x983c,0x982e,
+    0x983a,0x4ac9,0x983d,0x4ac7,0x98b5,0x9922,0x9923,0x9920,0x991c,0x991d,
+    0x4b6c,0x99a0,0x4b8a,0x99ef,0x99e8,0x99eb,0x4b88,0x4b87,0x4b86,0x99e1,
+    0x99e6,0x4bcf,0x4bd0,0x9af8,0x9af5,0x4c1c,0x4c23,0x9b83,0x9b94,0x9b84,
+    0x4c49,0x9b8b,0x9b8f,0x4c43
+  },
+  {				/* ku 34 */
+    0x9b8c,0x4c48,0x9b89,0x4c47,0x9b8e,0x4c46,0x4c3f,0x4c44,0x9d24,0x9d0f,
+    0x4cbe,0x9d13,0x9d0a,0x4cc2,0x4cba,0x4cbc,0x4cc6,0x9d2a,0x9d1a,0x4cc8,
+    0x9d27,0x9d16,0x9d21,0x4d23,0x9e85,0x9eac,0x9ec6,0x9ec5,0x9ed7,0x9f53,
+    0x349d,0x5128,0x5127,0x51df,0x3524,0x5335,0x53b3,0x3607,0x568a,0x567d,
+    0x5689,0x3679,0x58cd,0x58d0,0x3678,0x5b2b,0x5b33,0x5b29,0x5b35,0x5b31,
+    0x5b37,0x5c36,0x5dbe,0x3819,0x5db9,0x381c,0x5dbb,0x3818,0x61e2,0x61db,
+    0x61dd,0x61dc,0x61da,UBOGON,0x61d9,0x39bd,0x3a5d,0x64df,0x3a5a,0x3a5e,
+    0x64e1,0x3a5c,0x64ee,0x3a5b,0x65b5,0x66d4,0x66d5,0x3b21,0x66d0,0x66d1,
+    0x66ce,0x66d7,0x3b20,0x3b32,0x6a7d,0x6a8a,0x3bf2,0x6aa7,0x3bf5,0x6a99,
+    0x6a82,0x6a88,0x3bee,0x3bec
+  },
+  {				/* ku 35 */
+    0x6a86,0x3bea,0x6a98,0x6a9d,0x3bed,0x3bf3,0x6a8f,0x3bf6,0x6aaa,0x3c48,
+    0x6b5d,0x3c49,0x6c0a,0x3d75,0x6fd7,0x6fd6,0x6fe5,0x3d6f,0x3d7b,0x3d73,
+    0x6fd9,0x6fda,0x6fea,0x3d70,0x6ff6,UBOGON,0x3d78,0x71e3,0x3dfe,0x71e9,
+    0x3e00,0x71eb,0x71ef,0x71f3,0x71ea,0x3e01,UBOGON,0x3e55,0x3e56,0x3e9d,
+    0x7371,0x3ef9,0x74ae,0x3eff,0x74b3,0x3efd,0x74ac,0x3f43,0x3f41,0x7583,
+    0x7645,0x764e,0x7644,0x76a3,0x76a5,0x77a6,0x77a4,0x406f,0x77a9,0x77af,
+    0x408a,0x40e5,0x40e6,0x78f0,0x78f8,0x78f1,0x417f,0x7a49,0x41b5,0x41b6,
+    0x41bb,0x7ac2,0x7af2,0x7af3,0x7bfa,0x4240,0x7bf6,0x7bfc,0x7c18,0x7c08,
+    0x7c12,0x429d,0x429c,0x7cdb,0x7cda,0x430f,0x4311,0x430d,0x7e2c,0x7e4d,
+    0x4314,0x4313,0x7f46,0x7ff6
+  },
+  {				/* ku 36 */
+    0x802b,0x8074,0x81b8,0x81c8,0x4482,0x4483,0x454d,0x8592,0x8593,0x454f,
+    0x857f,0x85ab,0x8597,0x454c,0x4551,0x85ac,0x45ee,0x45e8,0x4ccb,0x87ce,
+    0x45eb,0x87cd,0x45e2,0x45e6,0x87c1,0x87b1,0x87c7,0x45ec,0x8940,0x4659,
+    0x893f,0x8939,0x465d,0x8943,0x4657,0x465b,0x4656,0x89ab,0x46fe,0x8b1f,
+    0x8b09,0x8b0c,0x4700,0x4701,0x8c40,0x4742,0x8c96,0x4760,0x8cf6,0x8cf7,
+    0x481d,0x8e46,0x8e4f,0x483e,0x4869,0x4865,0x8f3d,0x8f41,0x9366,0x9378,
+    0x935d,0x9369,0x9374,0x937d,0x936e,0x9372,0x9373,0x9362,0x9348,0x9353,
+    0x935f,0x9368,0x4938,0x937f,0x936b,0x49ae,0x95c4,0x49ad,0x96af,0x96ad,
+    0x96b2,0x4a02,0x4a1f,0x971a,0x971b,0x4a22,0x4a20,UBOGON,0x4a6c,0x979b,
+    0x979f,0x4a68,0x4a6d,0x4a6e
+  },
+  {				/* ku 37 */
+    0x4aa0,0x4ace,0x4ad0,0x4ad1,0x4acb,0x9840,0x4ad2,0x9847,0x4ad3,0x98b7,
+    0x4b20,0x4b4e,0x4b4b,0x4b72,0x4b70,0x99a2,0x4b92,0x4b8f,0x9a00,0x99f3,
+    0x4b90,UBOGON,0x99f5,0x4bd9,0x4bd5,0x9abd,0x9b00,0x9b02,0x4bfa,0x9b34,
+    0x9b49,0x9b9f,0x4c4b,0x9ba3,0x9bcd,0x9b99,0x9b9d,0x4cd0,0x4cce,0x9d39,
+    0x4ccf,0x9d44,0x4cc4,0x4ccc,0x9d35,0x4cd2,0x4d35,0x9eaf,0x3e03,0x512f,
+    0x349e,0x34af,0x9f8e,0x360c,0x569f,0x569b,0x569e,0x5696,0x5694,0x56a0,
+    0x367c,0x5b3b,0x3730,0x3731,0x5b3a,0x5dc1,0x5f4d,0x5f5d,0x61f3,0x39a1,
+    0x399e,0x3a68,0x3a61,0x64f6,0x64e5,0x64ea,0x64e7,0x6505,0x3a65,0x64f9,
+    0x3a66,0x3a6a,0x3aab,0x6aab,0x6aed,0x6ab2,0x6ab0,0x6ab5,0x6abe,0x6ac1,
+    0x6ac8,0x3bf9,0x6ac0,0x6abc
+  },
+  {				/* ku 38 */
+    0x6ab1,0x6ac4,0x6abf,0x3c58,0x3c8a,0x7008,0x7003,0x6ffd,0x7010,0x7002,
+    0x7013,0x3e04,0x71fa,0x7200,0x74b9,0x74bc,0x3f02,0x765b,0x7651,0x764f,
+    0x76eb,0x77b8,0x4079,0x77b9,0x77c1,0x77c0,0x77be,0x790b,0x40eb,0x7907,
+    0x790a,0x7908,0x40e9,0x790d,0x7906,0x7915,0x79af,0x4120,0x4121,0x4181,
+    0x7af5,0x424d,0x4259,0x7c2e,0x4258,0x7c1b,UBOGON,0x7c1a,0x7c24,0x42a5,
+    0x42a9,0x7ce6,0x7ce3,0x431a,0x4319,0x7e5d,0x7e4f,0x7e66,0x7e5b,0x7f47,
+    0x7fb4,0x4396,0x4398,0x4397,0x7ffa,0x802e,UBOGON,0x43c8,0x81ce,0x4443,
+    0x4445,0x8219,0x4552,0x4557,0x85cc,0x85b2,0x4555,0x85bb,0x85c1,0x4556,
+    0x4558,0x45f2,0x87e9,0x87ee,0x87f0,0x87d6,0x880e,0x87da,0x8948,0x894a,
+    0x894e,0x894d,0x89b1,0x89b0
+  },
+  {				/* ku 39 */
+    0x89b3,0x4707,0x8b38,0x8b32,0x4708,0x8b2d,0x470a,0x8b34,0x431b,0x8b29,
+    0x8c74,0x4761,0x4762,0x8d03,0x47c2,0x47c6,0x8da9,0x8e58,0x481e,0x4825,
+    0x8ebf,0x8ec1,0x8f4a,0x8fac,0x48b0,0x9089,0x913d,0x913c,0x91a9,0x93a0,
+    0x493d,0x9390,0x493e,0x9393,0x938b,0x93ad,0x93bb,0x93b8,0x4946,0x4945,
+    0x939c,0x95d8,0x95d7,0x4a03,0x4a26,0x4a27,0x975d,0x97a9,0x97da,0x4a98,
+    0x4aad,0x4ad5,0x4ada,0x9854,0x4ad9,0x9855,0x984b,0x4add,0x983f,0x98b9,
+    0x4b15,0x4b16,0x4b17,0x4b21,0x9938,0x9936,0x9940,0x4b4c,0x993b,0x9939,
+    0x99a4,0x4b96,0x4b98,0x9a08,0x9a0c,0x4b9b,0x9a10,0x4bff,0x9b07,0x4c25,
+    0x9bd2,0x4c4f,0x9bc2,0x9bbb,0x9bcc,0x9bcb,0x4c56,0x4c54,0x9d4d,0x9d63,
+    0x9d4e,0x4cd8,0x9d50,0x9d55
+  },
+  {				/* ku 3a */
+    0x4cd7,0x9d5e,0x4d26,0x9e90,0x9eb2,0x9eb1,0x4d38,0x9eca,0x9f02,0x9f27,
+    0x9f26,0x4d8a,0x56af,0x58e0,0x58dc,0x3734,0x5b39,0x3735,UBOGON,0x5b7c,
+    0x5bf3,UBOGON,0x37a1,0x5c6b,0x5dc4,0x650b,0x6508,0x650a,0x3a6c,0x3a6d,
+    0x65dc,0x3b29,0x3b2a,0x66e1,0x66df,0x6ace,0x6ad4,0x6ae3,0x6ad7,0x6ae2,
+    0x3c00,0x3c08,0x3c06,0x3c05,0x6ad8,0x6ad5,0x6ad2,0x3cb1,0x3d88,0x701e,
+    0x702c,0x7025,0x6ff3,0x7204,0x7208,0x7215,0x3e09,0x74c4,0x74c9,0x74c7,
+    0x74c8,0x76a9,0x77c6,0x77c5,0x7918,0x791a,0x7920,0x4122,0x7a66,0x7a64,
+    0x7a6a,0x41d5,0x4261,0x425d,0x4262,0x424f,0x4260,0x7c35,0x7c34,0x42aa,
+    0x4322,0x7e6c,0x4321,0x7e6e,0x7e71,0x4446,0x81d4,0x81d6,0x821a,0x8262,
+    0x8265,0x8276,0x85db,0x85d6
+  },
+  {				/* ku 3b */
+    0x4562,0x85e7,0x4560,0x4564,0x85f4,UBOGON,0x87fd,0x87d5,0x8807,0x45f6,
+    0x880f,0x87f8,UBOGON,0x4619,0x8987,0x4691,0x89b5,0x89f5,0x470d,0x8b3f,
+    0x8b43,0x8b4c,0x4765,0x8d0b,0x8e6b,0x8e68,0x8e70,0x8e75,0x8e77,0x483f,
+    0x8ec3,0x494b,0x93e9,0x93ea,0x93cb,0x93c5,0x93c6,0x4948,0x93ed,0x93d3,
+    0x4952,0x93e5,0x494a,0x4951,0x93db,0x93eb,0x93e0,0x93c1,0x4950,0x494c,
+    0x95dd,0x49ee,0x4a04,0x4a06,0x4a2d,0x4a2e,0x4a2f,0x4a7b,0x4a78,0x4a77,
+    0x97b2,0x97b4,0x97b1,0x97b5,0x97f2,0x4aa2,0x4aa1,0x4ae3,0x9856,0x4b1a,
+    0x4b19,0x4b57,0x9944,0x4b9e,0x9a26,0x9a1f,0x9a18,0x9a21,0x9a17,0x4bdd,
+    0x9b09,0x4c05,0x4c28,0x9bc5,0x9bdf,0x4c60,0x9be3,0x4c66,0x9be9,0x9bee,
+    0x4c67,0x4c68,0x9d66,0x9d7a
+  },
+  {				/* ku 3c */
+    0x4cde,0x9d6e,0x9d91,0x9d83,0x9d76,0x9d7e,0x9d6d,0x4ce1,0x9e95,0x9ee3,
+    0x4d69,0x4d77,0x9f03,0x9f04,UBOGON,0x9f17,0x34a6,0x5136,0x34a5,0x5336,
+    0x3614,0x5b42,0x3736,0x3738,0x5b44,0x5b46,0x5b7e,0x5dca,0x5dc8,0x5dcc,
+    0x5ef0,0x3a70,0x6585,0x66e5,0x66e7,0x3b2b,0x3c11,0x3c0a,0x6af4,0x3c0d,
+    0x6ae9,0x3c16,0x3c10,0x3c09,0x3c0e,0x3c7a,0x703d,0x3d8c,0x7036,0x3d91,
+    0x7216,0x3e0a,0x7212,0x720f,0x7217,0x7211,0x720b,0x3e08,0x3e0b,0x74cd,
+    0x74d0,0x74cc,0x74ce,0x74d1,0x3f07,0x7589,0x40f2,0x7a6f,0x7c4b,0x7c44,
+    0x7c55,0x42ae,0x4324,0x4326,0x4327,0x7e7f,0x8b71,0x4399,0x802f,0x807a,
+    0x807b,0x807c,0x455f,0x456a,0x4571,0x85fc,0x8610,0x8602,0x456c,0x456f,
+    0x85ee,0x8603,0x4568,0x860d
+  },
+  {				/* ku 3d */
+    0x8613,0x8608,0x860f,0x8818,0x8812,0x4601,0x4668,0x8967,0x8965,0x89bb,
+    0x8b69,0x8b62,0x4713,0x8b6e,0x4716,0x8b61,0x4718,0x8b64,0x8b4d,0x8c51,
+    0x4789,0x47c8,0x8e83,0x8ec6,0x4884,0x941f,0x4954,0x9404,0x9417,0x9408,
+    0x9405,0x4956,0x93f3,0x941e,0x9402,0x941a,0x941b,0x9427,0x941c,0x495a,
+    0x96b5,0x4a05,0x4a07,0x9733,0x4a31,0x9734,0x9731,0x97b8,0x97ba,0x4aa3,
+    0x97fc,0x4aeb,0x4b1c,0x98c3,0x4b5a,0x994d,0x4b5b,0x9a2f,0x4ba6,0x4baa,
+    0x4ba5,0x9ac9,0x4be1,0x9ac8,0x9ac4,0x9b2a,0x9b38,0x9b50,0x4c2a,0x9c0a,
+    0x9bfb,0x9c04,0x9bfc,0x9bfe,0x4c72,0x4c6f,0x4c73,0x9c02,0x9bf6,0x9c1b,
+    0x9bf9,0x9c15,0x9c10,0x9bff,0x9c00,0x9c0c,0x4c6b,0x4ce6,0x9d95,0x9da5,
+    0x4ce9,0x4cec,0x4ce8,0x4cf0
+  },
+  {				/* ku 3e */
+    0x9e98,0x9ec1,0x4d8c,0x9f5a,0x5164,0x56bb,0x3615,0x58e6,0x5b49,0x5bf7,
+    0x3771,0x3826,0x5dd0,0x38c6,0x5fc2,0x39a8,0x6511,0x3a73,0x6aff,0x6afe,
+    0x6afd,0x3c15,0x6b01,0x3d98,0x3d97,0x704b,0x704d,0x7047,0x74d3,0x7668,
+    0x7667,0x3fd7,0x4080,0x77d1,0x7930,0x7932,0x792e,0x4188,0x9f9d,0x7ac9,
+    0x7ac8,0x4269,0x7c56,0x7c51,0x426b,0x4329,0x4328,0x7e85,0x7e89,0x7e8e,
+    0x7e84,0x445f,0x826a,0x862b,0x862f,0x8628,0x4574,0x8616,0x8615,0x861d,
+    0x881a,0x4602,0x466a,0x4694,0x89bc,0x8b75,0x8b7c,0x478a,0x8d11,0x8d12,
+    0x8f5c,0x91bb,0x4964,0x93f4,0x495e,0x4961,0x942d,0x4965,0x4966,0x96e4,
+    0x9737,0x9736,0x9767,0x97be,0x97bd,0x97e2,0x9868,0x9866,0x98c8,0x98ca,
+    0x98c7,0x98dc,0x4b5f,0x994f
+  },
+  {				/* ku 3f */
+    0x99a9,0x9a3c,0x4baf,0x9a3b,0x9ace,0x4c0d,0x9b14,0x9b53,0x4c7c,0x9c2e,
+    0x4c7a,0x9c1f,0x4c76,0x4c79,0x4c7d,0x4c77,0x9db0,0x9dbd,0x4cf6,0x4cf1,
+    0x9dae,0x9dc4,0x9e7b,0x400b,0x4d29,0x9e9e,0x4d6f,0x9f05,0x4d9a,0x9f69,
+    0x9fa1,0x56c7,0x571d,0x5b4a,0x5dd3,0x3869,0x5f72,0x6202,0x39ab,0x6235,
+    0x6527,0x651e,0x651f,0x3b2c,0x3b2d,0x6b07,0x6b06,0x3c17,0x3d9a,0x7054,
+    0x721c,0x7220,0x7af8,0x426e,0x7c5d,0x7c58,0x432c,0x7e92,0x7f4e,0x43ca,
+    0x4578,0x4606,0x8827,0x4607,0x8b81,0x8b83,0x4720,0x8c44,0x4753,0x47ce,
+    0x487a,0x4879,0x9442,0x944d,0x9454,0x944e,0x496b,0x9443,0x4967,0x496d,
+    0x973c,0x9740,0x97c0,0x4a85,0x4ab0,0x4af3,0x4b63,0x995a,0x9a51,0x4bb6,
+    0x9add,0x4c82,0x4c7f,0x9c38
+  },
+  {				/* ku 40 */
+    0x4c86,0x9c45,0x9c3a,0x4c84,0x9c35,0x4cfc,0x4cfd,0x4cfa,0x9ef1,0x4d87,
+    0x9f93,0x529a,0x361a,0x3619,0x8641,0x5dd7,0x3a75,0x6528,0x3c1a,0x3c1b,
+    0x3c19,0x7053,0x7059,0x3d9c,0x7221,0x3e10,0x766f,0x7937,0x79b5,0x7c62,
+    0x7c5e,0x7cf5,0x457b,0x457c,0x863d,0x4608,0x882d,0x8989,0x8b8d,0x8b87,
+    0x8b90,0x8d1a,0x8e99,0x4841,0x48e3,0x4972,0x945f,0x4973,0x4968,0x9456,
+    0x9461,0x945b,0x945a,0x945c,0x9465,0x4a35,0x9741,0x4a88,0x4a9d,0x986e,
+    0x986c,0x986d,0x4275,0x99aa,0x9a5c,0x9a58,0x9ade,0x4c8f,0x9c4f,0x9c51,
+    0x4c8e,0x9c53,0x4d05,0x4d04,0x4cff,0x9dfc,0x9f39,0x4d9e,0x513e,0x3554,
+    0x56d2,0x3681,0x5b4f,0x6b14,0x40fa,0x7a72,0x7a73,0x4332,0x4670,0x466e,
+    0x8b91,UBOGON,0x487c,0x91bf
+  },
+  {				/* ku 41 */
+    0x4975,0x946c,0x4974,0x4977,0x96e6,0x9745,0x4a37,0x97c8,0x97e4,0x995d,
+    0x4bba,0x9b21,0x4c11,0x9b2c,0x9b57,0x4c92,0x4c99,0x9c5d,0x9c61,0x9c65,
+    0x9e08,0x4d0a,0x4d2a,0x4d2b,0x4d44,0x4d79,0x9f45,0x34aa,0x3748,0x6205,
+    0x66ef,0x6b1b,0x6b1d,0x7225,0x7224,0x7c6d,0x42b4,0x8642,0x8649,0x460d,
+    0x8978,0x898a,0x8b97,0x4754,0x8c9b,0x8d1c,0x4830,0x8ea2,0x4a09,0x4a38,
+    0x4a36,0x4a8b,0x4af7,0x4b66,0x4bbd,0x4c1e,0x9c6c,0x4c96,0x9c6f,0x4d0d,
+    0x9e0e,0x4d73,0x9f08,0x9f1d,0x9fa3,0x373b,0x373c,0x5f60,0x6b1c,0x3da0,
+    0x40fb,UBOGON,0x7cf3,0x4581,0x8b9b,0x8ea7,0x91c4,0x4978,0x947a,0x4a8d,
+    0x4b73,0x9a61,0x9a63,0x9ad7,0x9c76,0x4da6,0x9fa5,0x39ad,0x7067,0x3e11,
+    0x72ab,0x864a,0x897d,0x8b9d
+  },
+  {				/* ku 42 */
+    0x8c53,0x8f65,0x947b,0x4a39,0x98cd,0x98dd,0x4bbf,0x9b30,0x9e16,0x4d0f,
+    0x4da7,0x4db5,0x3fdc,0x4831,0x96e7,0x9e18,0x9ea2,0x4da8,0x9f7c,0x4125,
+    0x7e9e,0x9484,0x4bc1,0x9e1c,0x4190,0x7c71,0x97ca,0x4696,0x487f,0x4d10,
+    0x9ea3,0x4a0a,0x9c7b,0x9f97,0x4d12,0x4a3a,0x9750,0x4a3b,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 43 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 44 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4f66,
+    0x4f68,0x4fe7,0x503f,UBOGON,0x50a6,0x510f,0x523e,0x5324,0x5365,0x539b,
+    0x517f,0x54cb,0x5573,0x5571,0x556b,0x55f4,0x5622,0x5620,0x5692,0x56ba,
+    0x5691,0x56b0,0x5759,0x578a,0x580f,0x5812,0x5813,0x5847,0x589b,0x5900,
+    0x594d,0x5ad1,0x5ad3,0x5b67,0x5c57,0x5c77,0x5cd5,0x5d75,0x5d8e,0x5da5,
+    0x5db6,0x5dbf,0x5e65,0x5ecd,0x5eed,0x5f94,0x5f9a,0x5fba,0x6125,0x6150,
+    0x62a3,0x6360,0x6364,0x63b6
+  },
+  {				/* ku 45 */
+    0x6403,0x64b6,0x651a,0x7a25,0x5c21,0x66e2,0x6702,0x67a4,0x67ac,0x6810,
+    0x6806,0x685e,0x685a,0x692c,0x6929,0x6a2d,0x6a77,0x6a7a,0x6aca,0x6ae6,
+    0x6af5,0x6b0d,0x6b0e,0x6bdc,0x6bdd,0x6bf6,0x6c1e,0x6c63,0x6da5,0x6e0f,
+    0x6e8a,0x6e84,0x6e8b,0x6e7c,0x6f4c,0x6f48,0x6f49,0x6f9d,0x6f99,0x6ff8,
+    0x702e,0x702d,0x705c,0x79cc,0x70bf,0x70ea,0x70e5,0x7111,0x7112,0x713f,
+    0x7139,0x713b,0x713d,0x7177,0x7175,0x7176,0x7171,0x7196,0x7193,0x71b4,
+    0x71dd,0x71de,0x720e,0x5911,0x7218,0x7347,0x7348,0x73ef,0x7412,0x743b,
+    0x74a4,0x748d,0x74b4,0x7673,0x7677,0x76bc,0x7819,0x781b,0x783d,0x7853,
+    0x7854,0x7858,0x78b7,0x78d8,0x78ee,0x7922,0x794d,0x7986,0x7999,0x79a3,
+    0x79bc,0x7aa7,0x7b37,0x7b59
+  },
+  {				/* ku 46 */
+    0x7bd0,0x7c2f,0x7c32,0x7c42,0x7c4e,0x7c68,0x7ca9,0x7ced,0x7dd0,0x7e07,
+    0x7dd3,0x7e64,0x7f40,UBOGON,0x8041,0x8063,0x80bb,0x6711,0x6725,0x8248,
+    0x8310,0x8362,0x8312,0x8421,0x841e,0x84e2,0x84de,0x84e1,0x8573,0x85d4,
+    0x85f5,0x8637,0x8645,0x8672,0x874a,0x87a9,0x87a5,0x87f5,0x8834,0x8850,
+    0x8887,0x8954,0x8984,0x8b03,0x8c52,0x8cd8,0x8d0c,0x8d18,0x8db0,0x8ebc,
+    0x8ed5,0x8faa,0x909c,UBOGON,0x915c,0x922b,0x9221,0x9273,0x92f4,0x92f5,
+    0x933f,0x9342,0x9386,0x93be,0x93bc,0x93bd,0x93f1,0x93f2,0x93ef,0x9422,
+    0x9423,0x9424,0x9467,0x9466,0x9597,0x95ce,0x95e7,0x973b,0x974d,0x98e4,
+    0x9942,0x9b1d,0x9b98,UBOGON,0x9d49,0x6449,0x5e71,0x5e85,0x61d3,0x990e,
+    0x8002,0x781e,UBOGON,UBOGON
+  },
+  {				/* ku 47 */
+    0x5528,0x5572,0x55ba,0x55f0,0x55ee,0x56b8,0x56b9,0x56c4,0x8053,0x92b0,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  }
+};
+
+/* CNS 11643 plane 4 conversion table */
+
+static const unsigned short
+ cns11643_4tab[MAX_CNS11643_KU_4][MAX_CNS11643_TEN] = {
+  {				/* ku 01 */
+    UBOGON,0x4e40,0x4e41,0x4e5a,UBOGON,0x4e02,0x4e29,UBOGON,UBOGON,0x5202,
+    0x353e,0x5ddc,UBOGON,UBOGON,UBOGON,0x5342,0x536a,0x5b52,UBOGON,UBOGON,
+    UBOGON,0x5fc4,0x624c,0x72ad,0x4e12,0x4e2f,0x4e96,0x4ed0,0x5142,0x5183,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5383,0x53b8,UBOGON,UBOGON,UBOGON,
+    0x5928,UBOGON,0x5c23,0x5e01,0x5f00,UBOGON,0x3cb8,0x706c,0x722b,0x5188,
+    0x8279,0x8fb6,0x4e17,UBOGON,0x340c,UBOGON,0x3430,0x4ee2,0x4edb,UBOGON,
+    UBOGON,0x51ad,UBOGON,0x51f7,0x34da,UBOGON,UBOGON,0x3513,0x531b,0x5388,
+    0x5387,UBOGON,0x53cf,0x53fd,0x3563,0x53e7,0x56dc,UBOGON,0x56d9,0x5725,
+    0x5727,0x5933,0x5c13,UBOGON,UBOGON,0x5c75,UBOGON,UBOGON,UBOGON,0x39c4,
+    0x39c3,0x66f1,UBOGON,UBOGON
+  },
+  {				/* ku 02 */
+    0x7f52,UBOGON,UBOGON,0x3401,UBOGON,UBOGON,0x4e51,0x4e6a,UBOGON,0x4f0c,
+    UBOGON,UBOGON,0x4efe,0x4f1b,UBOGON,UBOGON,0x343a,UBOGON,0x34ab,0x5173,
+    UBOGON,0x518e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x34dd,UBOGON,UBOGON,
+    0x52a5,0x3515,0x52a7,0x52a4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x53bd,
+    UBOGON,UBOGON,UBOGON,0x5402,UBOGON,UBOGON,UBOGON,UBOGON,0x572b,0x591b,
+    0x5935,UBOGON,0x36a7,0x36a5,UBOGON,UBOGON,0x36a6,UBOGON,UBOGON,0x5c17,
+    0x377c,UBOGON,0x5c70,0x5c7d,0x37a9,UBOGON,0x5de9,UBOGON,0x3834,0x3835,
+    UBOGON,UBOGON,UBOGON,0x38a8,0x5f19,0x5f1c,0x5f75,UBOGON,UBOGON,0x38ff,
+    0x5fc8,UBOGON,0x39c7,0x39c6,0x39c8,UBOGON,UBOGON,0x3ad0,0x3ad1,UBOGON,
+    UBOGON,0x3c59,UBOGON,UBOGON
+  },
+  {				/* ku 03 */
+    0x6c12,0x3cbd,UBOGON,UBOGON,UBOGON,0x3e28,0x72b3,UBOGON,0x3ea9,0x7390,
+    0x7536,UBOGON,0x43cc,UBOGON,0x8281,0x8fb8,UBOGON,0x48b4,UBOGON,UBOGON,
+    0x4e23,0x3416,0x342c,UBOGON,0x4f2e,UBOGON,0x514f,UBOGON,0x51ba,0x34df,
+    0x34e0,0x5222,UBOGON,UBOGON,UBOGON,0x3517,UBOGON,0x52af,0x52b0,0x52b1,
+    UBOGON,UBOGON,0x352f,UBOGON,0x5364,UBOGON,0x53d3,UBOGON,0x3574,UBOGON,
+    0x3570,0x356d,UBOGON,UBOGON,UBOGON,UBOGON,0x356e,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x362b,0x3628,UBOGON,UBOGON,0x593f,UBOGON,UBOGON,0x3692,UBOGON,
+    0x598b,UBOGON,0x5991,0x5995,UBOGON,UBOGON,0x373f,UBOGON,0x5b8a,0x374f,
+    0x3774,UBOGON,UBOGON,0x377d,UBOGON,0x37b7,0x37a3,0x37b0,0x37b1,0x5c87,
+    0x37ab,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 04 */
+    0x383a,0x3837,0x5e0d,0x3838,0x3840,UBOGON,UBOGON,0x5e8e,0x389f,UBOGON,
+    UBOGON,0x5f7a,UBOGON,0x3904,0x3909,0x3906,0x38fd,0x390a,0x3907,UBOGON,
+    UBOGON,0x39ca,UBOGON,UBOGON,0x6290,0x39c9,UBOGON,0x629a,UBOGON,0x653c,
+    0x653a,0x3a7f,0x6598,UBOGON,0x3ad2,UBOGON,UBOGON,0x6765,UBOGON,0x3b43,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3cc1,UBOGON,0x3cc5,0x3da3,
+    UBOGON,UBOGON,0x3e2a,0x3e5f,UBOGON,UBOGON,0x3e5d,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x3f17,UBOGON,UBOGON,0x3f71,0x3f72,UBOGON,UBOGON,0x400f,UBOGON,
+    UBOGON,0x79c2,0x4191,UBOGON,UBOGON,UBOGON,0x43b2,0x43cf,0x43ce,0x809e,
+    UBOGON,UBOGON,0x81eb,UBOGON,0x8289,0x4496,UBOGON,UBOGON,0x8296,UBOGON,
+    0x8287,UBOGON,0x4497,UBOGON
+  },
+  {				/* ku 05 */
+    0x8fc0,0x488b,0x8fc3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x9578,UBOGON,UBOGON,0x9625,UBOGON,0x4e75,0x4e74,UBOGON,UBOGON,0x342d,
+    UBOGON,0x4f99,UBOGON,0x3450,0x344b,UBOGON,0x344f,0x344c,UBOGON,0x4f71,
+    0x5153,0x51bf,UBOGON,UBOGON,0x51c0,UBOGON,0x51ee,UBOGON,0x34e4,0x34e3,
+    UBOGON,0x34e1,UBOGON,0x34e2,UBOGON,0x523d,0x3519,0x52bd,0x530c,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x3541,0x7f37,UBOGON,0x53c0,0x355e,UBOGON,UBOGON,
+    0x3579,UBOGON,0x546e,0x5483,UBOGON,UBOGON,0x545e,0x545d,0x577e,0x5779,
+    UBOGON,0x577a,0x576c,UBOGON,UBOGON,UBOGON,0x3632,0x5787,UBOGON,0x591d,
+    0x3694,0x5946,0x3697,UBOGON,0x5943,UBOGON,0x3696,0x3698,UBOGON,UBOGON,
+    0x36b2,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 06 */
+    0x36b9,0x5b61,0x5b66,UBOGON,0x5b90,0x3775,0x377f,0x377e,0x5c29,0x378f,
+    UBOGON,UBOGON,UBOGON,0x37bd,0x5cb2,UBOGON,0x37bb,0x37bc,UBOGON,0x5cc0,
+    UBOGON,0x383d,0x383e,0x3874,UBOGON,0x387a,0x3876,0x3878,0x3875,UBOGON,
+    UBOGON,0x38af,0x38b0,0x38c7,0x38cc,UBOGON,UBOGON,0x3916,UBOGON,0x3912,
+    0x391d,UBOGON,UBOGON,0x3915,0x390f,0x3914,0x601f,0x5fe2,UBOGON,UBOGON,
+    UBOGON,0x39b0,0x39bf,0x39c0,UBOGON,0x39d2,0x39d9,UBOGON,0x3a7a,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x6616,0x65f9,0x3ada,UBOGON,0x6788,UBOGON,
+    0x679b,UBOGON,0x676e,0x679e,UBOGON,0x3c22,0x3c1f,UBOGON,UBOGON,0x3c21,
+    0x6b24,UBOGON,UBOGON,UBOGON,0x3c5c,0x6b7d,UBOGON,0x3c7d,0x3c8d,0x3c8f,
+    0x6ce6,UBOGON,0x6ccb,0x3cd0
+  },
+  {				/* ku 07 */
+    UBOGON,0x3cd8,UBOGON,UBOGON,UBOGON,0x6cb5,0x3da7,UBOGON,0x7097,UBOGON,
+    0x709b,0x3e12,UBOGON,UBOGON,0x3e2f,UBOGON,0x726b,0x3e2e,0x3e2c,0x3e5c,
+    UBOGON,0x72d5,UBOGON,UBOGON,0x3e62,0x3e67,0x3eb4,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x7543,UBOGON,UBOGON,0x759c,UBOGON,UBOGON,0x3fea,UBOGON,0x3ffb,
+    UBOGON,0x4014,UBOGON,0x4013,0x4012,0x4010,0x4011,UBOGON,0x4086,0x77e4,
+    0x4098,UBOGON,UBOGON,0x412a,UBOGON,UBOGON,UBOGON,UBOGON,0x7ace,0x42b5,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x8013,0x43d6,0x43d8,0x80b7,0x43d9,0x43d4,
+    0x43d7,UBOGON,0x80b9,UBOGON,UBOGON,0x81e4,0x81fd,0x820f,0x4460,UBOGON,
+    UBOGON,0x449e,0x44a1,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x82bf,
+    0x82ca,UBOGON,UBOGON,0x82c1
+  },
+  {				/* ku 08 */
+    0x44a0,UBOGON,UBOGON,UBOGON,UBOGON,0x8fd0,UBOGON,UBOGON,0x48b9,UBOGON,
+    0x90ae,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x49c1,0x49c2,0x9638,UBOGON,
+    0x341c,UBOGON,0x345e,0x4fbc,0x3459,0x345c,UBOGON,0x345f,0x4fe9,0x4fbd,
+    0x4fe2,0x5158,UBOGON,UBOGON,0x34ce,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x52c6,UBOGON,0x52c8,UBOGON,UBOGON,0x5328,UBOGON,0x5329,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x355f,UBOGON,0x3585,UBOGON,UBOGON,0x3586,
+    UBOGON,0x57b4,UBOGON,0x57a9,0x3687,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x36ca,UBOGON,0x36c3,UBOGON,UBOGON,UBOGON,0x36c2,0x5b68,UBOGON,0x3741,
+    UBOGON,UBOGON,UBOGON,0x3780,0x3781,UBOGON,UBOGON,0x3793,0x3792,UBOGON,
+    0x37c5,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 09 */
+    0x3846,0x3841,0x3845,0x3842,0x383f,UBOGON,UBOGON,0x3882,0x3881,0x387f,
+    0x38a5,0x5f2b,0x38b3,0x38b5,UBOGON,UBOGON,0x5f8d,0x38da,UBOGON,0x38db,
+    0x390d,0x6018,0x390e,UBOGON,0x391e,0x3925,0x3926,0x391c,0x3921,0x6057,
+    0x6048,0x3927,0x391a,UBOGON,UBOGON,UBOGON,0x6038,UBOGON,UBOGON,0x3924,
+    UBOGON,UBOGON,0x6071,UBOGON,0x39c1,0x39e1,UBOGON,UBOGON,0x6312,0x39eb,
+    UBOGON,0x39e2,0x39d7,0x39e9,UBOGON,UBOGON,0x630a,UBOGON,0x6323,UBOGON,
+    0x3a84,UBOGON,UBOGON,UBOGON,0x3ab5,0x3abc,0x3adc,0x3ade,0x3adf,UBOGON,
+    0x662a,UBOGON,UBOGON,UBOGON,UBOGON,0x3b54,0x67e0,0x67be,0x3b53,0x3c24,
+    0x3c25,0x6b29,0x3c28,0x3c27,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x3c8b,UBOGON,UBOGON,0x3cdc
+  },
+  {				/* ku 0a */
+    0x6d43,UBOGON,UBOGON,UBOGON,UBOGON,0x70a6,0x3db2,0x70c0,UBOGON,0x722f,
+    UBOGON,0x3e1b,UBOGON,0x3e32,0x7271,UBOGON,UBOGON,0x3e6b,UBOGON,0x3e6c,
+    0x3e6d,UBOGON,0x3eb9,0x3eba,0x3f09,0x3f0a,UBOGON,0x74ea,0x3f1b,UBOGON,
+    UBOGON,0x7520,0x3f58,UBOGON,0x3f5a,UBOGON,UBOGON,0x3f77,UBOGON,UBOGON,
+    0x3f79,0x75a9,UBOGON,0x7685,UBOGON,0x3feb,UBOGON,0x3ffd,0x3ffc,0x7706,
+    0x4015,0x4018,0x76f6,0x4016,0x4017,0x4019,0x7700,0x401b,UBOGON,UBOGON,
+    0x7702,UBOGON,0x4087,UBOGON,UBOGON,0x409c,UBOGON,0x409a,UBOGON,0x40ff,
+    0x40fe,UBOGON,0x4131,0x412e,0x4130,0x4132,UBOGON,UBOGON,0x412f,UBOGON,
+    0x4195,0x4196,UBOGON,UBOGON,UBOGON,0x41c5,0x427a,UBOGON,0x4342,UBOGON,
+    0x4354,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0b */
+    UBOGON,UBOGON,UBOGON,UBOGON,0x8009,UBOGON,0x439f,0x43a0,0x43a2,0x43e0,
+    UBOGON,0x43e1,UBOGON,UBOGON,0x43df,UBOGON,UBOGON,0x4462,0x4461,UBOGON,
+    UBOGON,0x44a7,UBOGON,UBOGON,UBOGON,0x82da,UBOGON,UBOGON,0x830a,0x4589,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x461d,UBOGON,UBOGON,
+    0x472a,UBOGON,UBOGON,0x47d3,0x4842,0x4843,UBOGON,0x4891,UBOGON,UBOGON,
+    0x4890,0x48bf,UBOGON,0x48bc,UBOGON,0x48c0,0x49c7,0x49c5,0x9655,UBOGON,
+    0x9652,0x4e35,UBOGON,UBOGON,0x5034,0x5001,UBOGON,0x500a,0x3466,UBOGON,
+    UBOGON,UBOGON,0x34ad,UBOGON,UBOGON,UBOGON,UBOGON,0x5258,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x351d,UBOGON,0x3531,0x532b,UBOGON,0x354c,
+    UBOGON,UBOGON,0x3595,0x3591
+  },
+  {				/* ku 0c */
+    0x3594,UBOGON,UBOGON,UBOGON,0x358f,0x54ec,UBOGON,0x5515,0x54fe,UBOGON,
+    UBOGON,UBOGON,0x54e3,0x5516,0x3640,UBOGON,0x3641,UBOGON,0x57d3,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x5959,0x5a27,0x36d8,0x36d2,0x36da,0x5a28,0x5a10,
+    0x36d7,0x5a0e,0x3742,0x3757,UBOGON,UBOGON,UBOGON,0x5baf,UBOGON,0x5bba,
+    0x5bb1,UBOGON,UBOGON,0x3778,0x3782,0x3797,UBOGON,UBOGON,0x37c9,UBOGON,
+    0x37c8,0x37d6,0x37cc,UBOGON,0x37d0,UBOGON,UBOGON,0x37ce,0x37c7,0x5cfc,
+    UBOGON,0x37cf,0x37cb,0x5cf2,0x5cfe,UBOGON,UBOGON,0x5df8,UBOGON,0x3847,
+    UBOGON,0x3848,UBOGON,UBOGON,0x3883,0x3885,0x3884,UBOGON,UBOGON,0x5f2c,
+    0x38b8,0x38bc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0d */
+    UBOGON,0x3931,0x3934,0x3936,0x6082,UBOGON,UBOGON,0x3923,UBOGON,UBOGON,
+    0x393a,0x6091,0x608f,UBOGON,0x39b4,0x39b5,0x39ed,0x39ec,0x39d8,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x39f6,0x39e7,UBOGON,UBOGON,
+    0x3a7c,0x3a7b,UBOGON,UBOGON,0x6547,0x654c,UBOGON,UBOGON,0x658a,UBOGON,
+    0x3abe,UBOGON,0x3ae7,0x3ae5,0x3aee,0x67e1,0x684a,UBOGON,0x3b59,0x3b5e,
+    UBOGON,0x3b5a,0x683f,0x3b61,0x3b58,0x3b5b,0x67bd,UBOGON,0x3b5f,UBOGON,
+    0x3c2a,0x3c2d,UBOGON,0x3c23,0x3c2b,0x3c2c,UBOGON,0x3c7e,UBOGON,0x3c93,
+    0x3c99,UBOGON,UBOGON,0x3cb3,0x3ce7,0x3cea,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3db4,UBOGON,0x70c9,0x3e17,UBOGON,UBOGON,UBOGON,0x3e21,
+    UBOGON,0x3e38,0x3e37,0x3e74
+  },
+  {				/* ku 0e */
+    0x3e73,0x3e75,UBOGON,UBOGON,UBOGON,0x3e76,0x3e78,UBOGON,UBOGON,0x73ba,
+    0x3f0c,0x3f20,0x3f1e,UBOGON,0x3f5b,UBOGON,0x3f5c,UBOGON,0x3f83,0x75c6,
+    0x3f80,0x3f81,0x3f7e,0x3f88,0x3f85,0x3f89,0x3f7f,0x3f8e,UBOGON,UBOGON,
+    0x3f84,0x75b7,0x768c,UBOGON,0x768d,UBOGON,0x3fee,0x3fed,0x3ffe,UBOGON,
+    0x3fff,UBOGON,UBOGON,UBOGON,0x4023,UBOGON,0x7717,UBOGON,0x771c,0x401f,
+    UBOGON,UBOGON,0x7714,UBOGON,0x408f,0x4090,UBOGON,UBOGON,UBOGON,0x40a0,
+    UBOGON,0x40a6,0x409f,UBOGON,0x40a7,0x40a1,UBOGON,0x4102,0x4136,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x41c8,UBOGON,UBOGON,0x41d8,
+    0x7b0c,0x41dd,0x41dc,UBOGON,0x41d7,UBOGON,0x41da,0x42ba,UBOGON,UBOGON,
+    UBOGON,0x42be,0x42c2,0x42bb
+  },
+  {				/* ku 0f */
+    0x42c0,UBOGON,UBOGON,UBOGON,0x7d23,UBOGON,UBOGON,UBOGON,0x4343,0x4355,
+    UBOGON,UBOGON,0x4357,0x4368,0x7f98,0x7f90,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x43a1,UBOGON,0x803a,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x43ea,UBOGON,0x43e7,UBOGON,UBOGON,UBOGON,UBOGON,0x43e8,0x43e9,UBOGON,
+    UBOGON,0x4454,UBOGON,UBOGON,UBOGON,UBOGON,0x8226,0x4465,UBOGON,UBOGON,
+    0x448a,UBOGON,0x44b0,UBOGON,UBOGON,UBOGON,0x44bc,0x832e,UBOGON,0x8355,
+    0x831a,0x44b8,0x833d,UBOGON,0x44b2,UBOGON,0x8330,0x44bd,UBOGON,UBOGON,
+    0x458a,0x8651,0x45a1,UBOGON,0x45a2,UBOGON,0x8688,UBOGON,0x4615,UBOGON,
+    UBOGON,0x4620,0x4673,UBOGON,0x898e,0x898d,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x8a09,0x8a14,0x46b1
+  },
+  {				/* ku 10 */
+    UBOGON,UBOGON,0x472b,UBOGON,0x4745,UBOGON,0x4797,0x4798,UBOGON,0x47d5,
+    UBOGON,UBOGON,0x4893,0x4896,0x9007,0x4894,UBOGON,UBOGON,0x48c7,0x48c5,
+    UBOGON,UBOGON,UBOGON,0x48c4,UBOGON,0x9579,0x9584,0x49ce,0x49ca,0x49cc,
+    0x9657,0x49c9,0x96ba,UBOGON,UBOGON,UBOGON,0x346e,UBOGON,0x5067,UBOGON,
+    UBOGON,0x3471,UBOGON,0x34bb,0x34d3,UBOGON,UBOGON,UBOGON,UBOGON,0x34f3,
+    0x34ed,0x34f5,UBOGON,UBOGON,0x34f1,0x34f2,0x34f6,0x3520,UBOGON,0x3528,
+    UBOGON,0x5318,0x532c,0x5359,UBOGON,UBOGON,UBOGON,0x5368,0x537e,UBOGON,
+    UBOGON,0x53a1,UBOGON,0x35a1,0x555b,0x35aa,0x35a9,UBOGON,0x35b5,0x35a5,
+    0x35a8,0x5542,0x35a7,0x5547,UBOGON,UBOGON,0x553d,UBOGON,UBOGON,0x5560,
+    0x57eb,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 11 */
+    0x364d,UBOGON,UBOGON,UBOGON,0x369c,0x595f,UBOGON,0x36ea,0x36e5,UBOGON,
+    UBOGON,0x5b6f,UBOGON,0x375e,UBOGON,UBOGON,UBOGON,0x3786,0x3784,UBOGON,
+    0x5c5a,UBOGON,0x37d9,UBOGON,0x37de,UBOGON,UBOGON,UBOGON,0x37db,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x3831,UBOGON,UBOGON,0x384b,UBOGON,0x3849,0x384a,
+    0x384c,UBOGON,UBOGON,0x388a,UBOGON,0x3889,0x388b,UBOGON,0x38bb,0x5fa2,
+    0x5f9d,0x38e4,UBOGON,UBOGON,0x5fa3,UBOGON,UBOGON,0x393b,0x392e,0x393e,
+    0x3946,0x3953,UBOGON,0x3944,UBOGON,0x393f,0x3942,0x394f,UBOGON,0x3952,
+    0x394a,0x60c2,UBOGON,0x395a,0x60a5,0x3949,UBOGON,0x621c,UBOGON,0x621d,
+    0x3a03,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6395,0x639a,0x3a01,0x3a06,
+    0x39fb,0x39f9,UBOGON,0x3a05
+  },
+  {				/* ku 12 */
+    0x39fa,UBOGON,0x63a6,UBOGON,0x39fe,UBOGON,0x3a7d,UBOGON,UBOGON,UBOGON,
+    0x6550,UBOGON,UBOGON,UBOGON,0x6552,UBOGON,UBOGON,UBOGON,UBOGON,0x65c8,
+    UBOGON,0x3af0,0x3af2,UBOGON,0x6658,0x3af1,0x3ae6,UBOGON,UBOGON,UBOGON,
+    0x6888,UBOGON,0x3b6f,0x3b6d,0x3b69,UBOGON,UBOGON,0x3b6e,UBOGON,0x3c2f,
+    0x3c30,0x3c63,UBOGON,UBOGON,UBOGON,0x6bb8,0x3c80,0x6bb9,0x3c9a,0x3c94,
+    0x3c96,0x3c95,0x3c97,UBOGON,0x3cf4,0x3cfe,UBOGON,0x3d01,UBOGON,0x3d02,
+    UBOGON,0x3cf9,UBOGON,UBOGON,UBOGON,UBOGON,0x3cf6,0x3cf7,UBOGON,UBOGON,
+    UBOGON,0x3cff,UBOGON,UBOGON,UBOGON,UBOGON,0x6e0b,UBOGON,UBOGON,0x3dbf,
+    0x3dbc,0x7105,UBOGON,UBOGON,UBOGON,0x3dbe,0x3dc0,UBOGON,0x3e3b,0x3e39,
+    UBOGON,UBOGON,UBOGON,0x3e3c
+  },
+  {				/* ku 13 */
+    UBOGON,0x7314,0x7304,UBOGON,0x3e7d,UBOGON,0x3e7f,0x3e7a,0x3e7c,0x7305,
+    0x3e7e,0x7315,0x730d,0x3e80,0x3ebf,0x3ec3,UBOGON,UBOGON,0x3ecc,0x3f0e,
+    0x3f0d,UBOGON,0x3f26,0x3f24,0x3f25,0x3f23,0x3f21,0x3f29,UBOGON,UBOGON,
+    0x3f8f,0x3f8d,UBOGON,0x3f8b,0x3f92,UBOGON,0x3f90,UBOGON,0x3fef,0x3ff0,
+    UBOGON,UBOGON,0x4001,UBOGON,0x402e,0x402d,0x772e,0x4028,0x4029,0x402c,
+    UBOGON,UBOGON,UBOGON,0x7741,0x4088,UBOGON,0x4092,0x4091,0x77ea,UBOGON,
+    0x7844,0x40a9,0x40ac,0x40ae,0x40aa,0x4106,0x4105,0x414a,0x413e,0x413c,
+    0x413b,UBOGON,0x4142,0x4141,0x4143,UBOGON,0x4145,UBOGON,0x419a,0x419b,
+    0x419f,0x419e,UBOGON,UBOGON,UBOGON,0x41de,0x41e2,0x41e6,UBOGON,0x7b29,
+    0x41e3,0x7b27,0x41df,UBOGON
+  },
+  {				/* ku 14 */
+    UBOGON,0x7c9d,UBOGON,UBOGON,0x427e,0x42c9,0x42cc,UBOGON,0x42d1,UBOGON,
+    0x42d0,UBOGON,0x42cf,0x42c8,UBOGON,0x42cd,UBOGON,UBOGON,0x4349,0x4347,
+    0x4358,0x436b,0x436c,0x436a,UBOGON,0x4380,0x4382,0x4384,0x7fc8,0x4383,
+    UBOGON,UBOGON,0x43b6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8126,0x43f1,
+    UBOGON,0x43f6,0x43f3,0x43f0,0x811c,UBOGON,UBOGON,0x8128,0x43f5,0x43f4,
+    0x43f7,UBOGON,UBOGON,UBOGON,UBOGON,0x4455,UBOGON,UBOGON,UBOGON,0x448b,
+    0x44cb,0x44c2,UBOGON,UBOGON,UBOGON,0x44ca,0x44cc,UBOGON,0x44c7,0x44c9,
+    0x8370,UBOGON,0x44c6,UBOGON,UBOGON,0x44c3,0x8382,UBOGON,0x83ac,UBOGON,
+    0x44c4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x45a9,0x86ad,
+    0x45a8,0x45a6,UBOGON,UBOGON
+  },
+  {				/* ku 15 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x86ca,0x8851,UBOGON,UBOGON,0x4622,
+    UBOGON,0x4626,0x4624,0x4625,0x889d,0x462a,0x4674,UBOGON,0x4679,0x8990,
+    0x467a,UBOGON,UBOGON,0x89d8,0x89d7,0x4697,UBOGON,UBOGON,0x8a2e,UBOGON,
+    0x46bc,UBOGON,0x46b3,UBOGON,0x46bf,0x46b7,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4734,0x4746,0x4748,0x8c59,UBOGON,UBOGON,0x4756,0x4767,UBOGON,
+    UBOGON,0x4768,0x4799,0x479a,UBOGON,UBOGON,0x47d8,UBOGON,0x47db,0x47dc,
+    0x47dd,0x47d7,UBOGON,UBOGON,0x4849,0x484a,0x8eda,UBOGON,UBOGON,0x9033,
+    UBOGON,0x9018,0x489a,UBOGON,0x48cd,0x48ca,UBOGON,0x48cb,UBOGON,0x48cf,
+    UBOGON,UBOGON,0x48cc,0x48ea,0x48ed,UBOGON,UBOGON,0x48e9,UBOGON,0x491a,
+    0x91ef,0x498d,0x49d2,UBOGON
+  },
+  {				/* ku 16 */
+    UBOGON,UBOGON,UBOGON,0x49f2,UBOGON,UBOGON,UBOGON,0x4a3d,UBOGON,0x4a3e,
+    0x4af8,0x4b23,0x9ad9,0x4eb4,UBOGON,0x50a0,0x5090,0x3475,0x5086,0x5084,
+    UBOGON,0x508a,0x3476,0x3473,0x509f,0x50a1,UBOGON,0x5093,0x34bd,UBOGON,
+    0x51d5,UBOGON,UBOGON,0x34f9,UBOGON,UBOGON,0x34fa,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3521,UBOGON,0x3529,UBOGON,UBOGON,0x3538,0x354e,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x35c8,0x35bc,UBOGON,UBOGON,0x5590,
+    UBOGON,0x35bb,0x35c2,0x35c0,UBOGON,UBOGON,0x35ca,UBOGON,0x35c9,UBOGON,
+    0x35b8,0x5710,0x5817,UBOGON,0x364e,UBOGON,0x5844,0x3650,0x582b,UBOGON,
+    0x5845,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x368a,UBOGON,0x5965,UBOGON,
+    UBOGON,UBOGON,0x36fc,0x36f9
+  },
+  {				/* ku 17 */
+    UBOGON,0x3763,UBOGON,0x5bcf,UBOGON,UBOGON,UBOGON,0x3787,0x3788,UBOGON,
+    0x379a,UBOGON,UBOGON,UBOGON,0x5d56,UBOGON,UBOGON,0x37e9,UBOGON,0x37ea,
+    0x5d54,0x3850,UBOGON,UBOGON,0x3856,0x3852,0x384f,0x3854,0x3851,UBOGON,
+    UBOGON,0x388e,0x388f,UBOGON,UBOGON,UBOGON,0x5f3d,UBOGON,UBOGON,0x38ed,
+    0x38eb,0x5fa4,UBOGON,UBOGON,UBOGON,0x3962,UBOGON,0x395d,UBOGON,UBOGON,
+    UBOGON,0x3961,0x3965,0x395c,UBOGON,UBOGON,0x395f,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x63ec,0x3a16,0x3a0a,UBOGON,0x3a0e,0x3a12,UBOGON,
+    UBOGON,0x3a11,UBOGON,UBOGON,0x3a10,UBOGON,UBOGON,0x3a09,0x63fa,0x3a15,
+    0x63d4,UBOGON,UBOGON,UBOGON,0x3a91,0x3a95,0x3a93,0x3a92,0x3a8f,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x3af6
+  },
+  {				/* ku 18 */
+    UBOGON,0x3afb,UBOGON,0x6675,0x3af9,UBOGON,UBOGON,UBOGON,0x671c,0x3b7d,
+    UBOGON,0x3b7a,0x3b7f,UBOGON,0x3b78,UBOGON,UBOGON,0x68d9,UBOGON,0x3b70,
+    0x3b82,UBOGON,0x3b84,UBOGON,0x3c33,UBOGON,0x3c32,0x3c36,UBOGON,UBOGON,
+    0x3c56,UBOGON,UBOGON,0x3c67,UBOGON,0x3c65,0x3c64,0x3c66,UBOGON,UBOGON,
+    0x3c81,0x3c82,0x3c83,0x3c9e,UBOGON,0x6bf1,0x3c9d,UBOGON,0x3d0f,0x3d12,
+    UBOGON,UBOGON,UBOGON,0x3d10,0x3d18,UBOGON,0x3d14,0x3d19,0x6e37,UBOGON,
+    UBOGON,0x6e7d,0x6e86,0x3dc8,0x3dc4,0x3dc6,UBOGON,0x3dc7,0x3dc3,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x3e19,0x3e1c,UBOGON,UBOGON,UBOGON,0x3e41,
+    UBOGON,0x3e42,0x3e43,UBOGON,UBOGON,UBOGON,0x3e82,UBOGON,0x3e81,0x3e94,
+    0x3e84,UBOGON,0x3ed2,0x3f0f
+  },
+  {				/* ku 19 */
+    0x3f22,UBOGON,0x3f27,0x3f2a,0x74fa,0x3f28,UBOGON,0x3f60,UBOGON,UBOGON,
+    UBOGON,0x7572,UBOGON,UBOGON,0x3f9b,0x3f9c,UBOGON,0x3f93,0x3f94,0x75dc,
+    0x3fa0,0x3f99,UBOGON,0x3fa1,UBOGON,0x3ff1,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4036,UBOGON,0x4037,0x403f,0x403c,UBOGON,0x4034,0x4039,0x403b,0x4035,
+    0x4030,0x4032,0x4038,0x403e,0x403a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x40b6,0x7867,UBOGON,UBOGON,UBOGON,0x40b3,0x4109,0x7977,UBOGON,UBOGON,
+    UBOGON,0x414c,UBOGON,UBOGON,0x4153,0x414d,0x4151,0x414f,0x7a9b,UBOGON,
+    0x41a2,UBOGON,UBOGON,0x41cd,UBOGON,UBOGON,0x41e7,UBOGON,0x41f0,UBOGON,
+    0x41e9,0x41ec,UBOGON,0x41e8,0x41ee,0x4202,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4282,0x4283,0x4286,UBOGON
+  },
+  {				/* ku 1a */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7d2a,0x7d65,0x434a,UBOGON,0x435a,
+    0x7f64,UBOGON,0x436e,UBOGON,UBOGON,0x4370,0x436f,UBOGON,0x438a,0x4387,
+    0x4388,UBOGON,UBOGON,0x8020,0x43b7,0x43fd,0x8120,UBOGON,0x4405,0x813c,
+    0x4408,0x4403,0x4402,0x4404,0x3b39,0x4409,0x43ff,UBOGON,0x813f,UBOGON,
+    0x43fc,0x4401,0x440a,0x81f0,0x81f5,0x446b,0x446c,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x44de,UBOGON,UBOGON,0x44db,UBOGON,0x44dd,0x44e3,
+    UBOGON,0x44e0,0x44d9,0x44d8,0x44e4,UBOGON,UBOGON,0x44da,0x44ef,UBOGON,
+    0x8415,0x83be,UBOGON,UBOGON,UBOGON,0x44d7,0x45b3,0x45bb,0x86e5,0x45b2,
+    0x86d2,0x45ad,UBOGON,0x45af,UBOGON,0x86e0,UBOGON,0x4616,0x4628,0x4623,
+    0x88b3,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1b */
+    0x4675,0x467e,0x467c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x46ce,0x46cd,
+    0x46cf,0x8a53,UBOGON,UBOGON,0x8a37,0x8a47,0x8a5c,UBOGON,0x46c4,0x46cc,
+    0x46c8,0x46c7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x475a,
+    0x476a,UBOGON,0x476b,0x476d,0x476f,UBOGON,0x479e,UBOGON,0x47a4,0x47a3,
+    0x47e4,0x47e8,0x47e9,0x47e0,0x47e3,UBOGON,0x47ea,0x47e1,0x47ed,0x4834,
+    0x4835,0x4851,0x8ef0,UBOGON,0x489d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x48d0,UBOGON,0x48ee,UBOGON,UBOGON,UBOGON,0x48f2,UBOGON,0x921d,
+    0x4988,UBOGON,UBOGON,UBOGON,0x498f,UBOGON,0x49d8,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x4a3f,UBOGON,0x4a52,0x976b,UBOGON,0x4a50,UBOGON,
+    0x4ab1,UBOGON,UBOGON,0x4af9
+  },
+  {				/* ku 1c */
+    UBOGON,UBOGON,UBOGON,0x4b26,0x4b28,UBOGON,UBOGON,0x3480,0x50c0,0x3481,
+    UBOGON,0x347e,0x347f,UBOGON,UBOGON,UBOGON,UBOGON,0x34be,UBOGON,0x34d6,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x52e5,UBOGON,0x3534,
+    UBOGON,0x53af,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x35d5,0x35d8,UBOGON,
+    UBOGON,0x35d4,0x55d8,0x35d9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5711,
+    0x5867,UBOGON,UBOGON,0x365d,0x5843,0x365e,0x3659,UBOGON,0x365a,0x36a0,
+    UBOGON,UBOGON,0x3705,UBOGON,0x3707,UBOGON,0x370e,0x370c,UBOGON,UBOGON,
+    0x3745,UBOGON,UBOGON,0x3764,UBOGON,0x3765,UBOGON,0x5bdd,0x3766,UBOGON,
+    0x3789,0x37ec,0x37f1,0x5d70,0x5d6a,0x37f0,0x37f8,0x5d74,0x5d5f,UBOGON,
+    0x5d61,0x5d73,UBOGON,0x37f2
+  },
+  {				/* ku 1d */
+    0x37f4,UBOGON,0x3858,UBOGON,UBOGON,0x385a,0x3859,0x3857,0x385b,0x5e50,
+    UBOGON,UBOGON,0x38a6,0x38c2,0x38c1,0x5f3f,UBOGON,UBOGON,0x38ef,0x5fb0,
+    UBOGON,UBOGON,0x3968,0x6135,0x612d,0x3973,0x396e,0x3974,0x6102,0x3966,
+    UBOGON,UBOGON,UBOGON,0x39b9,0x6226,UBOGON,0x3a0c,UBOGON,UBOGON,0x3a20,
+    UBOGON,0x3a1d,UBOGON,0x3a1c,UBOGON,0x3a21,0x3a1a,0x3a19,UBOGON,UBOGON,
+    UBOGON,0x3a7e,UBOGON,UBOGON,UBOGON,UBOGON,0x3a9d,UBOGON,0x3a9e,UBOGON,
+    0x656e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x65b1,0x65d4,0x3acd,UBOGON,
+    0x3b0b,0x3b0a,0x6685,UBOGON,0x3b8f,0x6972,0x3b95,0x3b90,0x3b91,UBOGON,
+    0x693a,0x3bb9,UBOGON,UBOGON,0x3b97,0x3b9e,UBOGON,0x3b8b,UBOGON,UBOGON,
+    0x3c3b,0x3c3a,0x3c3c,0x3c3d
+  },
+  {				/* ku 1e */
+    0x3c39,0x3c3e,0x3c6b,0x3c6c,UBOGON,UBOGON,0x3ca2,0x3ca1,0x3c9f,UBOGON,
+    UBOGON,UBOGON,0x3d2d,UBOGON,0x3d36,0x3d2b,UBOGON,0x3d37,UBOGON,UBOGON,
+    UBOGON,0x6ead,0x3d25,0x3d2f,0x3d2c,UBOGON,UBOGON,0x3d32,UBOGON,UBOGON,
+    0x6e95,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3dd5,UBOGON,0x3dd4,
+    0x3dd6,UBOGON,0x3dd1,0x7243,UBOGON,0x3e46,0x728f,UBOGON,UBOGON,0x3e8c,
+    0x3e8a,0x3e88,UBOGON,UBOGON,UBOGON,UBOGON,0x3edd,UBOGON,UBOGON,UBOGON,
+    0x3f2d,UBOGON,UBOGON,0x3f2e,0x3f2c,0x3f2b,0x3f30,UBOGON,0x3f4e,UBOGON,
+    UBOGON,0x3f64,0x3f61,UBOGON,0x7575,UBOGON,0x3f70,0x3fa6,0x3fa4,UBOGON,
+    UBOGON,UBOGON,0x3fa8,0x3fa2,UBOGON,0x3fa7,0x75ec,0x3fa5,UBOGON,0x3fa9,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1f */
+    UBOGON,0x403d,UBOGON,UBOGON,0x4044,0x4045,0x4046,UBOGON,0x7757,UBOGON,
+    0x4047,0x4048,0x4042,UBOGON,UBOGON,0x4041,UBOGON,UBOGON,0x4094,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x40c0,0x40b8,0x40c1,0x40c2,0x40bb,0x40bd,0x40bf,
+    0x40b9,0x40b7,UBOGON,0x40c7,UBOGON,0x410c,0x410b,0x797b,0x4110,UBOGON,
+    0x415d,0x7a21,0x415a,0x4158,0x4156,UBOGON,0x4154,0x7a16,UBOGON,0x41a8,
+    0x41a7,0x41cf,0x41d0,UBOGON,0x7ae8,UBOGON,UBOGON,0x41d1,0x41eb,UBOGON,
+    0x41fb,0x7b6a,UBOGON,0x41fd,0x41f8,0x41f7,0x4200,UBOGON,UBOGON,0x41f6,
+    0x7b5f,UBOGON,UBOGON,0x42df,UBOGON,UBOGON,UBOGON,0x42e2,0x42e4,UBOGON,
+    0x7d82,UBOGON,0x42e3,UBOGON,0x4359,0x4371,0x438e,0x438c,UBOGON,0x43a4,
+    UBOGON,0x8055,0x4414,UBOGON
+  },
+  {				/* ku 20 */
+    UBOGON,UBOGON,0x4411,UBOGON,0x441b,0x4412,0x440e,0x4415,0x8168,0x4410,
+    UBOGON,0x4417,0x8246,0x8243,0x4470,0x44ed,UBOGON,0x44ee,UBOGON,UBOGON,
+    UBOGON,0x8481,UBOGON,UBOGON,UBOGON,0x44f4,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x847c,UBOGON,UBOGON,0x846a,UBOGON,0x8488,0x44f2,0x44f8,
+    0x44f3,UBOGON,UBOGON,0x44fa,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8710,
+    UBOGON,UBOGON,0x871f,0x45b6,0x45b7,UBOGON,0x870f,UBOGON,0x45ba,UBOGON,
+    0x45bc,UBOGON,UBOGON,0x463b,0x88d3,0x462f,UBOGON,UBOGON,UBOGON,0x4637,
+    0x4699,UBOGON,UBOGON,UBOGON,UBOGON,0x46d9,0x46d8,0x46d7,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x4736,UBOGON,UBOGON,UBOGON,0x8c87,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x8cc6
+  },
+  {				/* ku 21 */
+    0x4770,UBOGON,UBOGON,UBOGON,UBOGON,0x47a5,0x47a6,0x47a9,0x47ee,0x4854,
+    UBOGON,0x4857,UBOGON,UBOGON,0x48a1,UBOGON,UBOGON,UBOGON,UBOGON,0x48d3,
+    UBOGON,0x48d4,UBOGON,0x48d7,0x90cc,0x916d,0x9170,0x48f7,0x48f6,0x48f9,
+    0x48f8,0x9258,0x9242,0x9268,0x9269,UBOGON,UBOGON,0x9243,UBOGON,0x9247,
+    0x498a,UBOGON,UBOGON,UBOGON,UBOGON,0x4994,UBOGON,0x4993,UBOGON,UBOGON,
+    0x959d,0x49dd,0x49dc,0x49f7,0x96cf,UBOGON,UBOGON,0x4a42,UBOGON,UBOGON,
+    0x4a54,UBOGON,0x4a55,UBOGON,0x4a8f,UBOGON,0x97f4,0x4ab4,0x4ab3,UBOGON,
+    UBOGON,0x9809,UBOGON,UBOGON,UBOGON,UBOGON,0x4afb,0x4afd,UBOGON,UBOGON,
+    0x98ab,0x4afc,UBOGON,0x4b2c,0x4b2f,UBOGON,0x4b2b,UBOGON,0x4b33,0x4b34,
+    0x98fb,UBOGON,0x9aac,0x9aae
+  },
+  {				/* ku 22 */
+    0x9aaa,0x4be8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9b5c,UBOGON,
+    UBOGON,0x4d5d,0x50d2,0x3485,0x3488,UBOGON,UBOGON,0x348e,0x3484,UBOGON,
+    0x50df,UBOGON,0x3483,UBOGON,UBOGON,UBOGON,UBOGON,0x3502,UBOGON,0x3506,
+    0x3505,UBOGON,0x34fe,0x3501,0x3500,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x35e7,0x5619,UBOGON,UBOGON,UBOGON,0x35e6,UBOGON,0x35ed,0x35e2,
+    0x35eb,UBOGON,0x35e8,0x35ec,0x560a,0x3624,0x589a,UBOGON,0x3662,UBOGON,
+    0x3661,0x3660,0x3664,0x368b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3719,
+    0x3716,0x3718,0x3722,UBOGON,0x371d,0x3717,0x371e,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x3769,0x376a,UBOGON,0x376c,0x377a,0x378a,UBOGON,
+    UBOGON,UBOGON,0x379c,UBOGON
+  },
+  {				/* ku 23 */
+    0x37fd,0x37f9,UBOGON,0x37ff,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x37fc,
+    UBOGON,0x5d85,0x37fb,0x3802,0x385f,0x5e56,0x385e,0x385d,0x385c,UBOGON,
+    0x5e51,0x3892,UBOGON,UBOGON,0x3894,0x3895,0x38d1,UBOGON,0x38f1,UBOGON,
+    0x5fb1,UBOGON,UBOGON,0x3977,0x396f,UBOGON,UBOGON,0x3987,0x397d,0x397c,
+    0x397e,0x3985,0x398b,0x3986,0x3980,UBOGON,UBOGON,0x3978,UBOGON,UBOGON,
+    UBOGON,0x39ba,UBOGON,0x3a33,UBOGON,0x3a2d,UBOGON,UBOGON,UBOGON,0x3a37,
+    0x645a,0x6463,UBOGON,UBOGON,0x3a2e,UBOGON,UBOGON,0x3a3d,UBOGON,0x3aa0,
+    UBOGON,UBOGON,0x3aa3,UBOGON,0x669b,UBOGON,0x66a3,0x3b0e,0x669e,UBOGON,
+    0x3bb6,UBOGON,0x3bab,0x3bad,0x3ba6,UBOGON,0x69b8,0x3baa,0x69ba,0x3bb1,
+    UBOGON,0x3ba8,0x3baf,0x3bb0
+  },
+  {				/* ku 24 */
+    0x3ba7,0x3bb2,0x3b9d,0x3ba5,0x3bb5,UBOGON,0x69c7,0x69d7,UBOGON,0x3c41,
+    UBOGON,UBOGON,0x6b70,UBOGON,UBOGON,0x3c72,0x6b9d,0x3c6f,0x3c71,UBOGON,
+    0x3c85,UBOGON,UBOGON,0x3ca4,0x3ca5,0x3ca6,UBOGON,0x3ca8,UBOGON,UBOGON,
+    0x3ca3,UBOGON,UBOGON,UBOGON,0x6f16,0x6f24,UBOGON,0x3d43,UBOGON,UBOGON,
+    0x3d3d,0x3d45,UBOGON,UBOGON,0x3d44,UBOGON,UBOGON,UBOGON,UBOGON,0x6f45,
+    UBOGON,UBOGON,UBOGON,0x3de3,0x7179,UBOGON,0x3ddf,0x3de4,0x717a,0x3de5,
+    UBOGON,0x7254,0x3e22,0x3e4a,UBOGON,0x3e49,0x3e44,0x3e4b,0x3e87,0x3e89,
+    0x3e92,0x3e91,0x3e90,0x3e8e,UBOGON,UBOGON,UBOGON,UBOGON,0x3f12,0x3f10,
+    0x3f11,UBOGON,0x3f32,0x3f34,0x3f37,0x3f33,0x3f36,0x3f35,0x3f65,UBOGON,
+    0x757c,0x757b,UBOGON,0x7612
+  },
+  {				/* ku 25 */
+    0x3fb0,UBOGON,0x3faf,0x3faa,UBOGON,UBOGON,UBOGON,0x3fab,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ff3,UBOGON,0x3ff4,UBOGON,0x76b6,
+    0x76e0,0x4008,0x404e,0x4055,0x404b,UBOGON,UBOGON,0x404d,0x7773,UBOGON,
+    0x4052,0x7772,0x404c,0x7770,0x4050,0x4053,UBOGON,0x4051,UBOGON,UBOGON,
+    UBOGON,0x4089,UBOGON,0x4095,0x40cc,0x40c8,0x40ce,UBOGON,0x40ca,UBOGON,
+    0x789d,UBOGON,0x40cd,UBOGON,0x415c,0x4167,0x4169,0x4165,0x4162,UBOGON,
+    0x7a27,0x7a35,UBOGON,0x41aa,UBOGON,UBOGON,0x41d2,0x7ba2,0x4203,0x420c,
+    UBOGON,0x4209,0x4206,0x4205,0x7b89,UBOGON,0x420b,0x4208,UBOGON,0x7ba5,
+    UBOGON,0x428e,UBOGON,0x7cb6,0x42e8,UBOGON,UBOGON,UBOGON,0x42ea,UBOGON,
+    0x7da5,0x7dc3,UBOGON,0x42e9
+  },
+  {				/* ku 26 */
+    0x42eb,UBOGON,0x42f0,UBOGON,0x434b,0x7fab,0x4373,0x4375,0x4392,0x4391,
+    0x4393,0x8025,0x43a7,0x43a6,0x43a8,0x43aa,UBOGON,0x43a9,0x8059,0x43bb,
+    0x43bc,0x43ba,0x43bd,0x4427,0x8185,UBOGON,0x4424,0x441e,0x441f,0x441d,
+    0x4420,0x4423,0x4429,0x4422,UBOGON,UBOGON,0x441c,0x818e,0x4428,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4471,0x4473,0x4472,UBOGON,
+    0x4502,UBOGON,UBOGON,UBOGON,0x44fe,0x84be,UBOGON,UBOGON,UBOGON,0x4508,
+    UBOGON,UBOGON,UBOGON,0x4507,0x4504,UBOGON,UBOGON,0x4500,0x44fc,UBOGON,
+    0x4544,UBOGON,0x44f1,UBOGON,UBOGON,0x84a6,0x4506,UBOGON,UBOGON,0x45c6,
+    0x45c3,0x45c1,0x45c2,UBOGON,0x45c4,0x45c7,UBOGON,0x45bf,0x45d2,UBOGON,
+    0x45ca,UBOGON,UBOGON,0x872f
+  },
+  {				/* ku 27 */
+    UBOGON,UBOGON,0x4613,UBOGON,0x4630,0x463e,0x4639,UBOGON,UBOGON,0x463c,
+    0x463f,UBOGON,0x4634,0x463d,UBOGON,UBOGON,0x4638,UBOGON,UBOGON,UBOGON,
+    0x89a0,0x4682,UBOGON,0x4683,UBOGON,0x469b,UBOGON,0x46e0,0x46dd,UBOGON,
+    UBOGON,0x46de,UBOGON,0x46e3,0x46e5,UBOGON,0x8a97,0x46e2,UBOGON,UBOGON,
+    UBOGON,0x46df,UBOGON,0x472e,UBOGON,0x4737,0x4738,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x8c8b,UBOGON,0x3562,UBOGON,0x4794,0x4793,0x47ab,0x47ad,UBOGON,
+    UBOGON,0x47f5,0x47f7,UBOGON,0x47f6,0x47f8,UBOGON,0x47fb,0x47f9,0x4858,
+    0x485a,UBOGON,0x4859,0x8f0f,0x4885,0x48a4,0x48d8,0x48d9,UBOGON,0x48dd,
+    0x48c8,UBOGON,0x48fa,0x48fb,0x9275,0x4927,0x929f,0x492a,0x4925,UBOGON,
+    0x4928,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 28 */
+    UBOGON,0x95a6,0x4995,0x969a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x4a0f,0x4a11,UBOGON,UBOGON,0x4a10,UBOGON,0x4a15,0x4a13,
+    0x9757,UBOGON,0x4a47,0x4a46,UBOGON,0x4a59,0x4a5b,UBOGON,0x4a5e,UBOGON,
+    UBOGON,0x4a5a,0x4a91,0x4a92,0x4a90,0x4a93,UBOGON,0x97f7,0x4abe,UBOGON,
+    UBOGON,UBOGON,0x4abc,0x4abb,0x4ab7,0x4ab9,UBOGON,0x4b01,0x4afe,UBOGON,
+    UBOGON,0x4b02,UBOGON,0x4aff,0x98b0,UBOGON,0x4b00,UBOGON,0x4b37,0x4b3a,
+    0x4b6f,0x4b77,0x4b79,0x99c6,UBOGON,0x4bc8,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4bf2,UBOGON,0x4bf1,0x4bf0,0x9b62,UBOGON,0x4c34,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x4d2c,0x4d2d,UBOGON,UBOGON,UBOGON,UBOGON,0x50fa,UBOGON,
+    0x3491,UBOGON,0x3494,UBOGON
+  },
+  {				/* ku 29 */
+    UBOGON,0x34c4,0x350a,UBOGON,0x5285,UBOGON,0x3552,UBOGON,0x3559,0x366f,
+    UBOGON,0x35f2,0x35f4,0x5643,UBOGON,0x35f1,0x563c,UBOGON,0x366a,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3724,UBOGON,0x3723,UBOGON,UBOGON,
+    UBOGON,0x3727,UBOGON,UBOGON,0x376d,0x5bed,0x376e,0x376f,UBOGON,UBOGON,
+    0x5c35,0x379f,0x380a,0x3806,0x380e,UBOGON,0x380d,0x3805,UBOGON,UBOGON,
+    0x380b,0x3810,0x382e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3896,0x3897,
+    0x38c4,0x5f47,0x38c5,UBOGON,0x38d2,UBOGON,UBOGON,UBOGON,0x3981,UBOGON,
+    0x398e,0x3990,0x398f,UBOGON,0x3991,0x3995,0x3993,UBOGON,0x616d,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x3a3b,0x3a48,UBOGON,UBOGON,0x3a46,0x3a47,
+    UBOGON,UBOGON,UBOGON,0x3a4c
+  },
+  {				/* ku 2a */
+    UBOGON,0x3a4a,0x3a50,0x3a43,UBOGON,UBOGON,UBOGON,0x3a49,0x3aa6,0x3aa5,
+    0x3aa4,UBOGON,UBOGON,0x3ab9,UBOGON,0x3ace,0x3acf,0x3b13,UBOGON,UBOGON,
+    UBOGON,0x3bc6,0x3bc5,0x3bca,0x3bd9,0x3bc1,UBOGON,UBOGON,0x69f5,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x3bcb,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6a03,
+    UBOGON,UBOGON,0x6a65,0x3c42,UBOGON,0x6b75,0x3c74,0x3c73,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x6f8a,0x6f56,0x3d52,UBOGON,UBOGON,UBOGON,
+    0x3d50,UBOGON,0x3d4b,UBOGON,0x3d4c,0x3d6d,UBOGON,0x6f98,UBOGON,UBOGON,
+    UBOGON,0x3d4f,0x6f68,0x3df0,UBOGON,0x7234,0x7245,0x3e4d,0x3e4c,UBOGON,
+    0x3e4f,0x3e4e,0x3e50,UBOGON,0x735c,0x3e96,0x7356,UBOGON,UBOGON,0x3e97,
+    0x3e95,0x3e98,UBOGON,UBOGON
+  },
+  {				/* ku 2b */
+    0x3eec,0x3eeb,0x3f13,0x3f14,0x3f38,0x3f3a,0x3f39,UBOGON,0x3f68,0x3f67,
+    UBOGON,UBOGON,UBOGON,0x3fbe,0x3fbc,UBOGON,UBOGON,UBOGON,0x3fbb,UBOGON,
+    0x3fba,UBOGON,0x3fb9,0x3fb7,UBOGON,UBOGON,0x3fc1,UBOGON,0x3ff7,UBOGON,
+    0x4060,UBOGON,UBOGON,0x4059,0x405c,0x405a,0x4058,UBOGON,0x405b,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x405d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x40d4,0x40d3,0x78bf,0x40d2,0x78bd,UBOGON,0x40d7,0x40d1,
+    0x78e4,0x40d5,UBOGON,UBOGON,0x416d,0x416f,0x7a34,0x4175,0x416c,0x4174,
+    UBOGON,0x4173,UBOGON,UBOGON,0x7a36,0x41ac,UBOGON,UBOGON,UBOGON,0x4210,
+    UBOGON,UBOGON,0x7bba,0x7bbc,0x420f,0x7bc8,0x4223,0x7bc3,0x421d,0x7bb6,
+    0x420e,UBOGON,UBOGON,0x4215
+  },
+  {				/* ku 2c */
+    0x7bc2,0x4213,UBOGON,UBOGON,0x421b,0x7bc5,0x4222,0x4226,UBOGON,0x7bbd,
+    0x7bb0,0x4221,0x421c,0x4217,UBOGON,0x421a,0x7bbb,UBOGON,UBOGON,UBOGON,
+    0x4299,UBOGON,0x4297,UBOGON,UBOGON,0x42fd,UBOGON,0x42f6,0x42fe,0x42f5,
+    0x42ff,0x42f7,UBOGON,UBOGON,UBOGON,0x4301,0x7e04,UBOGON,UBOGON,UBOGON,
+    0x4377,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43ab,UBOGON,UBOGON,0x43c0,
+    UBOGON,0x4431,0x442e,UBOGON,UBOGON,0x442c,UBOGON,UBOGON,0x4432,0x442f,
+    0x442b,0x442d,0x4433,UBOGON,UBOGON,0x81f1,0x4457,0x445c,0x447b,UBOGON,
+    UBOGON,0x447a,UBOGON,0x8522,0x4513,0x451e,0x4517,0x4520,0x452a,0x4511,
+    0x4515,0x450f,0x4518,0x8538,UBOGON,UBOGON,0x452c,0x8532,UBOGON,0x8510,
+    UBOGON,UBOGON,0x451c,UBOGON
+  },
+  {				/* ku 2d */
+    0x4529,UBOGON,UBOGON,0x4512,0x854f,0x4597,UBOGON,0x8772,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x45d4,0x45d0,0x877c,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x45d3,0x4614,UBOGON,0x4646,0x4645,UBOGON,0x4643,UBOGON,0x890d,
+    0x4644,0x4648,UBOGON,0x4647,UBOGON,UBOGON,UBOGON,0x8908,0x4649,0x4685,
+    UBOGON,0x4684,UBOGON,0x469d,UBOGON,0x469e,0x46a0,UBOGON,0x469c,UBOGON,
+    0x469f,UBOGON,0x46f7,0x46ea,UBOGON,0x46ef,0x46e9,0x46f3,0x46f0,0x46eb,
+    UBOGON,0x46ec,0x46f2,0x46f5,0x46ee,UBOGON,UBOGON,0x473a,0x474b,UBOGON,
+    0x474a,0x474c,UBOGON,UBOGON,UBOGON,0x4779,0x477b,0x4778,UBOGON,UBOGON,
+    0x47b5,UBOGON,0x47b4,0x47b7,0x8d9e,0x4809,0x47fe,0x4808,0x4807,UBOGON,
+    UBOGON,UBOGON,0x4806,0x4804
+  },
+  {				/* ku 2e */
+    0x4805,0x47ff,0x480b,UBOGON,UBOGON,0x483b,0x485d,0x485c,0x485f,0x485e,
+    0x8f28,UBOGON,0x8f21,0x4883,UBOGON,UBOGON,0x48a7,0x9066,0x906c,UBOGON,
+    0x48a8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x90f6,0x48e0,0x48df,0x48fe,
+    0x48fc,0x48ff,0x48fd,UBOGON,0x492c,0x92ec,0x92ba,0x92e3,0x92bd,0x499d,
+    UBOGON,0x95b4,UBOGON,0x4a40,UBOGON,UBOGON,0x4a5f,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x97d1,UBOGON,0x4ac0,0x9823,UBOGON,0x4ac1,
+    0x4ac6,UBOGON,UBOGON,0x4b04,0x4b05,UBOGON,0x990b,0x4b3e,0x4b3d,0x4b40,
+    0x4b3f,UBOGON,0x4b42,UBOGON,UBOGON,UBOGON,0x4b84,0x4b82,0x4b7f,0x4b85,
+    UBOGON,UBOGON,0x4bcc,0x9ab2,0x4bcb,0x4bcd,UBOGON,UBOGON,0x9adb,UBOGON,
+    0x4bf5,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2f */
+    0x9af0,UBOGON,UBOGON,0x4c20,0x4c21,UBOGON,UBOGON,0x4c37,0x4c3e,0x9b73,
+    0x4c3d,0x9b6e,UBOGON,UBOGON,UBOGON,0x9b65,UBOGON,0x4c3c,UBOGON,0x4c38,
+    0x9b6a,UBOGON,0x9b6d,UBOGON,0x4c3b,UBOGON,0x4cb0,UBOGON,UBOGON,UBOGON,
+    0x4cad,0x4cb2,0x4cb8,0x9d0b,UBOGON,0x4caf,UBOGON,UBOGON,0x4d1a,0x9e76,
+    0x4d20,0x4d21,0x4d30,0x9ea8,0x4d2f,UBOGON,UBOGON,UBOGON,UBOGON,0x4d5f,
+    0x4d60,UBOGON,UBOGON,0x9f11,UBOGON,UBOGON,0x348a,0x5119,0x349c,UBOGON,
+    0x349a,UBOGON,UBOGON,UBOGON,0x350c,0x350b,0x350d,0x5292,UBOGON,UBOGON,
+    0x35fe,UBOGON,UBOGON,0x35ff,0x35fb,0x35fc,0x3609,UBOGON,0x3600,UBOGON,
+    0x5675,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3671,UBOGON,UBOGON,
+    0x596f,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 30 */
+    0x372b,UBOGON,UBOGON,UBOGON,0x3814,0x3811,0x3812,UBOGON,0x3863,UBOGON,
+    0x386e,0x389a,UBOGON,0x389b,UBOGON,UBOGON,0x38c8,UBOGON,UBOGON,0x38f6,
+    UBOGON,UBOGON,0x61a5,0x398c,0x3997,0x39a2,0x61a0,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3a54,UBOGON,UBOGON,UBOGON,
+    0x3aa8,UBOGON,UBOGON,0x3aa9,UBOGON,0x65b4,0x65d8,0x66c2,0x3b18,0x3b17,
+    0x3b1d,UBOGON,UBOGON,0x3b31,UBOGON,UBOGON,0x3bd8,0x3bd5,UBOGON,UBOGON,
+    UBOGON,0x3be1,UBOGON,0x3bd4,UBOGON,UBOGON,UBOGON,0x3be3,UBOGON,0x3c44,
+    0x3c45,UBOGON,UBOGON,0x3c76,0x3c75,UBOGON,0x6ba8,0x3c88,0x3caa,UBOGON,
+    0x3cab,0x3cac,UBOGON,0x3d57,0x6f83,0x3d60,0x3d5d,0x3d6b,UBOGON,0x3d63,
+    0x3d67,UBOGON,0x3d5e,UBOGON
+  },
+  {				/* ku 31 */
+    UBOGON,0x6fc5,0x71cd,0x3df9,0x3df3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x3df6,UBOGON,0x729c,0x3e51,0x3e53,0x3e52,UBOGON,0x3e9b,UBOGON,0x3e9c,
+    UBOGON,UBOGON,0x3ef7,0x7499,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x3f3b,UBOGON,0x3f3e,0x3f3d,UBOGON,0x3f69,UBOGON,UBOGON,UBOGON,0x3fc3,
+    0x3fc4,0x3fc7,UBOGON,UBOGON,0x7639,0x3fc6,0x762e,0x3fc8,UBOGON,UBOGON,
+    UBOGON,0x769f,0x76a0,0x3fe6,0x3ff8,UBOGON,UBOGON,0x4007,UBOGON,0x4064,
+    0x4068,UBOGON,0x7794,0x4065,0x77ae,UBOGON,UBOGON,0x4069,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x40da,0x40e0,0x78e6,UBOGON,0x40de,
+    UBOGON,UBOGON,UBOGON,0x411c,0x411d,0x411a,UBOGON,0x417b,0x417a,0x417c,
+    UBOGON,0x4178,0x4177,UBOGON
+  },
+  {				/* ku 32 */
+    UBOGON,0x41b1,UBOGON,0x41b2,0x41b0,UBOGON,0x7abc,UBOGON,0x4236,UBOGON,
+    0x422e,UBOGON,0x7bd6,UBOGON,0x4234,UBOGON,UBOGON,UBOGON,UBOGON,0x422a,
+    UBOGON,0x4233,0x422d,0x422f,0x4231,0x422b,0x4232,UBOGON,0x4235,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7ccf,UBOGON,UBOGON,0x4308,UBOGON,
+    0x4306,UBOGON,UBOGON,0x7e18,UBOGON,0x434d,0x4361,UBOGON,UBOGON,UBOGON,
+    0x4378,UBOGON,0x4394,0x4395,UBOGON,UBOGON,UBOGON,0x43c1,0x43c3,0x806d,
+    UBOGON,0x4439,UBOGON,UBOGON,0x443a,0x443b,0x4435,0x4436,UBOGON,0x443c,
+    0x8190,UBOGON,UBOGON,UBOGON,0x4458,0x447c,0x447d,0x448d,0x448c,UBOGON,
+    UBOGON,0x453b,0x453f,UBOGON,UBOGON,0x4532,0x452d,UBOGON,0x452f,0x4539,
+    0x452e,0x453a,UBOGON,0x4536
+  },
+  {				/* ku 33 */
+    0x4531,0x453e,0x4538,0x8552,0x4534,UBOGON,0x4541,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4530,UBOGON,UBOGON,UBOGON,UBOGON,0x4543,UBOGON,0x8550,UBOGON,
+    UBOGON,0x4598,UBOGON,UBOGON,0x87a0,UBOGON,UBOGON,0x8786,0x45da,0x45d7,
+    UBOGON,UBOGON,0x8795,UBOGON,UBOGON,0x878c,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4618,0x8860,UBOGON,UBOGON,UBOGON,0x4652,0x8928,UBOGON,0x464e,
+    0x8920,UBOGON,0x464f,0x4650,UBOGON,UBOGON,0x89a8,0x4686,0x4687,0x4689,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x46a2,0x46a3,UBOGON,0x46a1,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x46f9,0x46fd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x473e,0x473c,UBOGON,0x474d,UBOGON,0x474e,UBOGON,0x4781,0x4783,
+    0x4782,UBOGON,0x4780,0x4788
+  },
+  {				/* ku 34 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47b9,UBOGON,UBOGON,0x8e3a,UBOGON,
+    UBOGON,UBOGON,0x4811,0x480d,0x4810,0x4813,UBOGON,0x483c,0x4862,0x4863,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4903,0x4906,0x4902,0x4901,UBOGON,
+    UBOGON,0x4905,UBOGON,0x9194,0x9311,UBOGON,0x9337,0x4936,UBOGON,0x4935,
+    0x9343,UBOGON,0x49a1,0x49a3,UBOGON,UBOGON,0x49a0,UBOGON,0x49ea,0x96a6,
+    0x49e8,UBOGON,UBOGON,UBOGON,UBOGON,0x4a21,0x4a1b,UBOGON,UBOGON,0x4a49,
+    0x4a48,UBOGON,0x9795,0x4a62,0x4a61,0x4a64,0x4a60,0x4a63,UBOGON,UBOGON,
+    0x9796,0x4a66,0x4aac,0x4aab,UBOGON,UBOGON,0x4ac3,UBOGON,0x4ac4,0x9825,
+    UBOGON,UBOGON,0x4b08,0x4b09,0x4b0a,0x4b06,0x4b07,0x4b41,UBOGON,0x4b45,
+    UBOGON,0x4b43,0x4b44,0x9926
+  },
+  {				/* ku 35 */
+    0x9934,0x4b47,UBOGON,UBOGON,UBOGON,0x4b71,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x4b8b,0x4bd4,0x4bd3,0x4bd1,0x9aba,0x4bd2,UBOGON,UBOGON,
+    0x4bf7,0x4bf8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4c22,UBOGON,0x4c45,0x4c41,0x9b81,0x4c40,0x9b8a,UBOGON,0x9b7f,0x4c42,
+    UBOGON,0x4cc1,0x4cc5,UBOGON,0x4cbb,0x4cb9,0x4cbd,0x4cc9,UBOGON,0x9d11,
+    UBOGON,0x4cbf,0x4cc7,UBOGON,0x4cc3,0x4d24,0x4d31,0x4d33,UBOGON,0x4d32,
+    0x4d34,0x4d52,0x4d61,0x9ed9,0x4d7a,0x4d82,0x9f3c,UBOGON,0x5123,UBOGON,
+    UBOGON,UBOGON,0x512c,UBOGON,UBOGON,0x350f,0x5295,UBOGON,0x3523,0x3525,
+    UBOGON,0x3606,0x3608,0x5688,UBOGON,UBOGON,UBOGON,0x568b,UBOGON,UBOGON,
+    0x367a,0x3677,UBOGON,UBOGON
+  },
+  {				/* ku 36 */
+    UBOGON,0x372e,UBOGON,0x372f,UBOGON,UBOGON,0x381b,0x3813,UBOGON,UBOGON,
+    0x3866,UBOGON,0x3865,UBOGON,0x38f7,UBOGON,UBOGON,0x61e1,0x61d7,UBOGON,
+    UBOGON,0x399c,UBOGON,UBOGON,0x3a53,UBOGON,UBOGON,UBOGON,UBOGON,0x3aba,
+    0x65a3,0x3b22,0x66d3,UBOGON,UBOGON,UBOGON,0x6a8b,UBOGON,UBOGON,0x3beb,
+    0x3bdd,UBOGON,0x3bef,UBOGON,UBOGON,0x3c47,0x3c46,UBOGON,0x3c78,0x6bac,
+    0x3c89,UBOGON,UBOGON,0x3d68,0x3d76,0x3d74,0x3d79,UBOGON,0x3d7a,0x3d77,
+    UBOGON,0x3d71,UBOGON,0x3d72,UBOGON,0x3dff,UBOGON,0x3e05,UBOGON,UBOGON,
+    0x3e54,UBOGON,UBOGON,0x3e9e,0x3e9f,0x7374,UBOGON,UBOGON,0x3efa,UBOGON,
+    0x3f44,0x3f3f,0x3f40,UBOGON,0x3f42,UBOGON,UBOGON,0x3f51,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 37 */
+    0x7640,0x3fca,UBOGON,0x7641,0x3fce,0x3fc9,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4009,0x76e8,0x406c,0x406e,0x4070,0x406d,0x406b,0x4071,0x4072,
+    UBOGON,UBOGON,UBOGON,0x408c,0x40e4,UBOGON,0x40e1,UBOGON,UBOGON,0x78f6,
+    0x40e7,0x7900,0x40e2,0x411f,UBOGON,UBOGON,0x417e,UBOGON,0x4180,0x7a59,
+    0x7a55,UBOGON,0x41b9,0x41b7,0x41b8,UBOGON,0x41ba,0x7af4,UBOGON,0x41d3,
+    0x423f,0x7c04,0x4245,0x4241,0x7c15,0x4242,0x4243,0x423b,0x4238,UBOGON,
+    UBOGON,0x423a,0x7bf5,UBOGON,UBOGON,0x423c,UBOGON,UBOGON,0x423e,UBOGON,
+    UBOGON,UBOGON,0x429e,0x429f,0x42a1,UBOGON,0x429b,0x4312,UBOGON,UBOGON,
+    UBOGON,0x4318,0x430c,UBOGON,0x4362,UBOGON,0x437a,UBOGON,UBOGON,0x43ae,
+    0x43af,UBOGON,0x43ad,UBOGON
+  },
+  {				/* ku 38 */
+    0x43c4,0x43c7,0x43c6,0x43c5,UBOGON,UBOGON,0x81c1,0x4440,UBOGON,UBOGON,
+    0x443f,0x4441,UBOGON,UBOGON,UBOGON,0x447f,UBOGON,0x4486,0x4481,0x4480,
+    0x448e,0x454a,UBOGON,0x4547,UBOGON,UBOGON,0x454b,0x4546,0x454e,0x857d,
+    UBOGON,0x85a5,UBOGON,0x4548,UBOGON,0x4545,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x45db,0x45e7,0x45e4,UBOGON,UBOGON,0x45e1,
+    UBOGON,0x45e9,UBOGON,0x45e5,0x45e0,0x45e3,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x45ea,UBOGON,UBOGON,0x893a,0x4654,0x4658,0x465c,UBOGON,
+    0x4655,0x468b,0x468c,0x46a6,0x46a5,UBOGON,UBOGON,UBOGON,UBOGON,0x46ff,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4730,0x4740,0x4741,UBOGON,UBOGON,0x4786,
+    UBOGON,0x47bf,0x47bd,UBOGON
+  },
+  {				/* ku 39 */
+    UBOGON,UBOGON,UBOGON,UBOGON,0x47be,0x4819,UBOGON,0x481c,UBOGON,0x481b,
+    0x4817,0x4818,0x8e51,UBOGON,UBOGON,0x483d,0x486a,0x4866,UBOGON,UBOGON,
+    0x4867,UBOGON,0x4868,0x48ad,0x48ae,UBOGON,UBOGON,0x48d6,0x4909,UBOGON,
+    0x9198,UBOGON,0x490c,0x490a,UBOGON,0x493b,0x493a,0x9384,0x9381,UBOGON,
+    0x936f,UBOGON,UBOGON,UBOGON,0x49af,0x49aa,0x49ab,UBOGON,UBOGON,0x49b1,
+    UBOGON,0x49ac,0x49ec,UBOGON,UBOGON,0x4a01,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4a23,UBOGON,0x4a24,0x4a1e,UBOGON,0x4a4a,0x4a65,0x4a6a,UBOGON,UBOGON,
+    UBOGON,0x4a69,UBOGON,UBOGON,0x4a95,UBOGON,UBOGON,UBOGON,UBOGON,0x9842,
+    UBOGON,UBOGON,0x4acc,UBOGON,UBOGON,UBOGON,0x4acf,UBOGON,UBOGON,0x4b0f,
+    UBOGON,0x4b0e,0x4b0b,0x4b10
+  },
+  {				/* ku 3a */
+    0x4b0d,0x4b0c,UBOGON,UBOGON,UBOGON,UBOGON,0x4b46,0x4b48,0x9937,0x4b49,
+    UBOGON,UBOGON,0x4b91,0x4b8e,UBOGON,0x4bd8,0x4bd6,UBOGON,0x4bda,UBOGON,
+    0x4bd7,UBOGON,0x9aff,0x4bf9,UBOGON,UBOGON,0x4bfc,UBOGON,UBOGON,UBOGON,
+    0x9ba9,0x4c4a,0x9ba7,0x4c4e,0x9bb3,0x9bac,0x9bb0,UBOGON,UBOGON,UBOGON,
+    0x9b9c,UBOGON,UBOGON,UBOGON,0x9d3c,0x9d1c,0x9d3a,0x4cd3,0x4ccd,0x4cd1,
+    UBOGON,UBOGON,0x9d32,0x9d34,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x9ec7,UBOGON,0x4d62,UBOGON,UBOGON,UBOGON,0x4d83,0x9f3f,UBOGON,0x4d92,
+    0x349f,0x34a0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3527,UBOGON,0x360b,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x368d,
+    UBOGON,UBOGON,0x3770,UBOGON
+  },
+  {				/* ku 3b */
+    0x5eeb,UBOGON,0x399a,0x399f,0x399d,UBOGON,UBOGON,UBOGON,0x399b,UBOGON,
+    0x61d5,UBOGON,0x3a60,0x3a64,0x3a69,0x3a63,0x3a67,0x3a62,UBOGON,UBOGON,
+    UBOGON,0x6502,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x3b26,0x3b23,0x3b25,UBOGON,UBOGON,0x3bf8,UBOGON,UBOGON,UBOGON,0x3bf7,
+    0x3bfb,0x3bfa,UBOGON,UBOGON,UBOGON,UBOGON,0x3cb0,0x3caf,UBOGON,UBOGON,
+    UBOGON,0x3d7e,UBOGON,0x3d7d,0x3d80,UBOGON,UBOGON,0x3d7f,0x3d86,UBOGON,
+    UBOGON,0x7012,UBOGON,0x3d81,UBOGON,UBOGON,UBOGON,0x3e24,0x3e58,0x3e57,
+    0x3ea0,UBOGON,0x3efe,UBOGON,UBOGON,0x3f15,UBOGON,0x3f47,0x3f46,UBOGON,
+    UBOGON,0x3f6b,0x3f6c,0x7585,0x7654,UBOGON,0x3fcc,UBOGON,0x7655,UBOGON,
+    0x3fcb,0x76a7,0x76a8,0x3ff9
+  },
+  {				/* ku 3c */
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4078,0x407a,0x4075,UBOGON,0x4076,0x4077,
+    UBOGON,UBOGON,0x40ea,0x40ee,0x40ed,UBOGON,0x40ec,0x790f,UBOGON,UBOGON,
+    0x4184,0x4185,0x4183,UBOGON,0x41bc,0x41bd,0x41d4,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4255,UBOGON,0x4250,0x424c,0x4248,UBOGON,0x4253,UBOGON,0x4257,
+    0x4254,0x424e,0x424a,0x4251,UBOGON,UBOGON,0x4249,0x424b,0x4263,UBOGON,
+    UBOGON,0x42a7,0x42a6,0x42a4,UBOGON,UBOGON,UBOGON,0x7ce4,0x7ce5,UBOGON,
+    UBOGON,0x7e65,0x7e4e,0x4317,UBOGON,0x4316,UBOGON,UBOGON,0x4363,UBOGON,
+    UBOGON,0x7f82,UBOGON,0x437b,0x437c,UBOGON,UBOGON,UBOGON,UBOGON,0x43b0,
+    0x802d,UBOGON,UBOGON,0x4442,UBOGON,0x4444,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4488,0x448f,0x4553
+  },
+  {				/* ku 3d */
+    0x455b,UBOGON,0x4559,UBOGON,UBOGON,UBOGON,UBOGON,0x85ca,UBOGON,UBOGON,
+    0x4554,0x85bc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4599,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x45f1,UBOGON,0x45ef,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4662,UBOGON,0x4663,UBOGON,0x4660,
+    0x4661,0x465f,UBOGON,UBOGON,UBOGON,0x468d,UBOGON,0x468e,UBOGON,UBOGON,
+    UBOGON,0x4709,UBOGON,UBOGON,0x4705,UBOGON,UBOGON,0x4703,0x4706,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4731,UBOGON,UBOGON,0x474f,UBOGON,UBOGON,
+    UBOGON,0x4766,0x8cff,0x47c4,UBOGON,0x47c3,0x47c1,0x47c5,UBOGON,UBOGON,
+    UBOGON,0x4821,UBOGON,0x481f,0x4822,UBOGON,0x4827,0x4820,UBOGON,0x486d,
+    0x486c,0x486b,0x486f,0x4870
+  },
+  {				/* ku 3e */
+    UBOGON,UBOGON,UBOGON,0x91a6,UBOGON,UBOGON,0x4942,UBOGON,0x93b6,UBOGON,
+    0x4944,0x4940,UBOGON,UBOGON,0x493f,UBOGON,0x93ab,0x498b,UBOGON,UBOGON,
+    0x4a25,0x4a28,UBOGON,0x9721,UBOGON,UBOGON,0x4a75,0x4a72,UBOGON,0x4a6f,
+    UBOGON,UBOGON,0x4a76,0x4a71,0x97a7,UBOGON,0x4a97,UBOGON,0x4ad7,UBOGON,
+    0x4ad6,UBOGON,0x4ad8,0x4adc,0x4adb,0x4ad4,0x983e,0x4b13,0x4b11,0x4b14,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4b51,0x4b50,0x4b53,0x4b54,0x4b52,UBOGON,
+    UBOGON,UBOGON,0x4b6d,UBOGON,UBOGON,0x4b95,0x4b99,UBOGON,0x4b9a,UBOGON,
+    0x4b93,0x4b97,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4bdc,UBOGON,0x4bfd,
+    UBOGON,UBOGON,0x4bfe,0x4c00,0x4c02,0x4c01,0x4c03,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4c27,0x4c26,0x4c24
+  },
+  {				/* ku 3f */
+    0x4c4c,0x9bbc,0x4c50,0x4c55,0x4c53,0x9bb7,0x4c52,UBOGON,0x4c57,0x9bbe,
+    0x4c58,0x4cd6,UBOGON,UBOGON,0x4cd4,UBOGON,0x4cda,0x4cd9,UBOGON,0x9d62,
+    0x4cd5,0x4ce4,UBOGON,0x4cdc,0x4d1b,0x9e8f,0x4d37,0x4d36,0x4d4b,0x9ecb,
+    0x4d66,0x4d76,UBOGON,0x4d7e,0x4d7d,0x4d7f,0x4d84,0x4d8b,UBOGON,0x4d94,
+    0x34a1,0x3511,UBOGON,0x3610,0x56a9,UBOGON,UBOGON,UBOGON,UBOGON,0x5913,
+    UBOGON,0x3732,0x5bf4,UBOGON,UBOGON,UBOGON,UBOGON,0x3820,UBOGON,UBOGON,
+    UBOGON,0x389d,UBOGON,0x61ec,0x61ef,UBOGON,UBOGON,0x39a5,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c02,0x3bfe,0x3c01,
+    0x6ad6,0x3c03,0x3bff,UBOGON,0x3c04,UBOGON,0x3c4a,UBOGON,0x3d87,UBOGON,
+    0x3d84,UBOGON,0x3d85,0x7209
+  },
+  {				/* ku 40 */
+    UBOGON,UBOGON,UBOGON,0x3e59,0x7379,UBOGON,0x74c6,UBOGON,UBOGON,0x3f04,
+    0x3f49,0x3f48,UBOGON,0x3f6d,0x3fd2,0x3fd3,UBOGON,0x3fd1,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3fe7,0x400a,0x77c3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x40f0,UBOGON,UBOGON,0x791f,UBOGON,UBOGON,0x7a65,UBOGON,UBOGON,0x41be,
+    0x41bf,UBOGON,0x7ac6,0x7c3a,UBOGON,0x7c36,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x425e,UBOGON,UBOGON,0x425b,UBOGON,UBOGON,UBOGON,0x7ceb,0x42ab,UBOGON,
+    0x42ac,UBOGON,UBOGON,UBOGON,UBOGON,0x431f,0x431d,UBOGON,UBOGON,0x431c,
+    UBOGON,0x431e,UBOGON,UBOGON,UBOGON,UBOGON,0x4364,UBOGON,0x7f84,UBOGON,
+    UBOGON,UBOGON,0x4448,0x4447,UBOGON,UBOGON,0x455e,0x4561,UBOGON,0x85e0,
+    0x85f3,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 41 */
+    0x45f7,UBOGON,UBOGON,0x45f4,0x45f8,0x881e,UBOGON,UBOGON,UBOGON,0x4664,
+    UBOGON,0x4692,0x468f,0x4690,0x89b4,0x4693,0x46a8,UBOGON,UBOGON,0x46a9,
+    UBOGON,UBOGON,0x89f9,UBOGON,UBOGON,0x8b44,0x470e,UBOGON,0x470f,UBOGON,
+    UBOGON,0x470b,UBOGON,UBOGON,UBOGON,UBOGON,0x4710,0x4751,UBOGON,0x4750,
+    UBOGON,0x4763,UBOGON,UBOGON,0x47c7,UBOGON,0x8e71,0x4824,0x4826,0x8e6e,
+    UBOGON,0x8e79,UBOGON,0x8ec4,0x4874,0x4873,0x4872,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x48b1,0x908c,UBOGON,0x490e,0x4911,0x4910,0x490f,0x4912,0x4949,
+    0x93c9,0x494f,0x494d,UBOGON,UBOGON,0x4955,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x4a2c,0x4a2b,UBOGON,UBOGON,0x4a79,UBOGON,UBOGON,UBOGON,
+    0x4a7a,0x97b0,0x4a99,0x4a9a
+  },
+  {				/* ku 42 */
+    UBOGON,0x4aae,0x4aaf,UBOGON,0x4ae4,0x4ae1,0x4ade,0x4ae6,0x4adf,UBOGON,
+    0x4ae7,0x4ae2,0x4ae0,UBOGON,0x4ae5,0x985a,UBOGON,0x4b18,UBOGON,UBOGON,
+    UBOGON,0x4b56,UBOGON,0x9946,UBOGON,UBOGON,UBOGON,0x4b6e,UBOGON,UBOGON,
+    0x4b9d,0x4ba0,0x4b9c,UBOGON,UBOGON,0x4ba1,0x4ba2,0x4b9f,0x4bdf,0x4bde,
+    0x9ac3,0x4bea,UBOGON,0x4c06,UBOGON,0x4c04,0x9b0f,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4c5f,0x9bf4,0x9bfa,0x4c5c,UBOGON,0x4c5e,UBOGON,UBOGON,0x9bdd,
+    0x4c59,UBOGON,UBOGON,0x4c64,0x4c5d,0x4c62,UBOGON,0x4c65,UBOGON,0x9bed,
+    0x4c5b,0x9bef,UBOGON,0x4cdd,UBOGON,0x4cdf,UBOGON,UBOGON,0x4ce2,UBOGON,
+    UBOGON,0x4d27,UBOGON,UBOGON,0x9e96,0x4d3a,0x4d3c,UBOGON,0x4d39,UBOGON,
+    UBOGON,0x4d3d,0x4d3b,0x9eb3
+  },
+  {				/* ku 43 */
+    0x4d4c,UBOGON,0x4d68,0x9ee2,UBOGON,0x4d80,0x4d85,UBOGON,0x4d95,UBOGON,
+    0x4d96,UBOGON,0x9f8f,UBOGON,0x34a4,0x3512,0x56b1,0x3625,UBOGON,0x5b41,
+    0x3737,UBOGON,UBOGON,UBOGON,UBOGON,0x3868,0x3867,0x389e,UBOGON,UBOGON,
+    UBOGON,0x39aa,UBOGON,0x39a9,0x39a4,UBOGON,UBOGON,0x3a71,0x3a6f,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x3aad,UBOGON,0x6af6,0x3c0c,0x6af2,0x3c0b,UBOGON,
+    UBOGON,0x3c0f,0x3c79,UBOGON,UBOGON,UBOGON,UBOGON,0x3d8d,0x3d8f,UBOGON,
+    UBOGON,0x3d8e,0x3e0c,UBOGON,UBOGON,UBOGON,0x3ea6,UBOGON,0x3ea3,0x3ea4,
+    0x3ea5,0x7588,0x3f6e,UBOGON,UBOGON,0x3ffa,UBOGON,0x407c,0x407e,0x407b,
+    0x407d,UBOGON,UBOGON,0x408d,0x40f4,0x40f3,UBOGON,UBOGON,0x4189,UBOGON,
+    UBOGON,0x41c0,UBOGON,0x4265
+  },
+  {				/* ku 44 */
+    UBOGON,UBOGON,0x42ad,0x4325,UBOGON,UBOGON,UBOGON,0x43c9,UBOGON,0x444a,
+    UBOGON,0x8267,0x4489,UBOGON,0x4566,0x4570,UBOGON,0x456d,0x4569,0x4567,
+    UBOGON,0x4572,0x860e,0x456e,UBOGON,0x459c,0x45fc,0x45fd,0x4604,0x45ff,
+    UBOGON,0x45fe,0x4600,UBOGON,0x4666,0x4669,UBOGON,0x46aa,0x46ab,0x4717,
+    UBOGON,UBOGON,UBOGON,0x4715,0x8b5e,0x4712,0x8d0e,UBOGON,UBOGON,UBOGON,
+    0x47ca,UBOGON,0x47c9,0x47cb,UBOGON,UBOGON,UBOGON,0x4829,0x4828,UBOGON,
+    UBOGON,UBOGON,0x4840,0x4875,0x4876,UBOGON,0x4888,UBOGON,0x91b6,0x4957,
+    0x9401,UBOGON,0x495f,UBOGON,0x941d,0x4958,0x495b,UBOGON,0x942f,UBOGON,
+    0x49b3,UBOGON,0x49ef,UBOGON,0x4a30,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4a41,0x4a4b,UBOGON,0x4a7d
+  },
+  {				/* ku 45 */
+    UBOGON,UBOGON,0x4a7c,UBOGON,UBOGON,UBOGON,0x97e0,UBOGON,0x97db,UBOGON,
+    UBOGON,0x9861,UBOGON,UBOGON,0x4ae8,0x4aea,0x4ae9,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4b1b,UBOGON,UBOGON,0x4b55,0x994a,0x4b59,0x4b58,UBOGON,UBOGON,
+    UBOGON,0x4ba4,0x4ba3,UBOGON,UBOGON,UBOGON,UBOGON,0x9a33,0x4ba7,UBOGON,
+    0x4be0,UBOGON,UBOGON,UBOGON,0x4c08,0x4c0a,0x4c09,UBOGON,UBOGON,UBOGON,
+    0x4c71,0x9c0f,0x4c6c,UBOGON,0x9c11,UBOGON,0x9c03,0x9c01,0x4c6e,UBOGON,
+    0x9c16,UBOGON,UBOGON,UBOGON,0x4ce0,0x4cee,UBOGON,0x4ceb,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x9d93,0x4cea,0x4cef,0x4ce7,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4d48,0x4d49,UBOGON,UBOGON,UBOGON,0x4d4d,UBOGON,UBOGON,0x4d55,UBOGON,
+    UBOGON,0x4d6a,0x4d6c,UBOGON
+  },
+  {				/* ku 46 */
+    0x4d6b,UBOGON,UBOGON,UBOGON,0x4d98,0x4d99,0x4d97,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x535b,UBOGON,0x3616,UBOGON,0x56bf,
+    UBOGON,UBOGON,0x3739,UBOGON,UBOGON,0x3825,0x5dce,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x3a74,UBOGON,UBOGON,0x3aae,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x3d92,0x3d94,UBOGON,0x3d95,UBOGON,0x3e0d,UBOGON,0x3e25,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3fd5,0x3fd6,0x76ac,0x3fe8,UBOGON,
+    0x407f,0x77d2,0x40f5,0x40f6,0x40f7,UBOGON,0x4124,0x418d,0x418a,UBOGON,
+    UBOGON,0x426c,0x4266,0x426a,UBOGON,0x4267,0x426d,0x4268,0x7c52,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4365,UBOGON,0x439a,UBOGON
+  },
+  {				/* ku 47 */
+    0x43b1,0x444b,0x444d,0x444c,0x444e,UBOGON,0x4573,0x4575,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4603,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x471e,UBOGON,0x8b73,UBOGON,0x4719,0x471c,
+    0x471a,0x471d,0x8b76,UBOGON,UBOGON,0x4743,0x4752,UBOGON,UBOGON,0x4795,
+    UBOGON,0x47cc,UBOGON,0x482b,UBOGON,UBOGON,UBOGON,0x482a,0x8ec7,0x4877,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4913,0x4914,0x9434,
+    UBOGON,UBOGON,0x495d,UBOGON,0x4960,0x943e,0x4962,UBOGON,UBOGON,0x49b2,
+    0x49f0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4a4c,UBOGON,0x4a82,
+    0x97bc,0x4a81,0x4a9b,UBOGON,0x4aa4,0x4aee,0x4aec,UBOGON,0x4aed,UBOGON,
+    0x4af0,0x4aef,UBOGON,0x4b1d
+  },
+  {				/* ku 48 */
+    UBOGON,0x4b60,0x4b5e,0x4b5d,UBOGON,UBOGON,UBOGON,0x4bb1,0x4bab,0x4bac,
+    0x4bad,UBOGON,0x4bae,UBOGON,UBOGON,0x4be2,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x9b39,UBOGON,UBOGON,0x9c2a,0x4c7b,0x9c26,0x4c78,0x4c75,0x9c27,
+    UBOGON,0x4cf2,0x4cf4,0x4cf3,0x9dc0,0x9dc9,UBOGON,UBOGON,UBOGON,0x4d3f,
+    0x4d3e,0x4d40,0x4d4e,0x4d57,0x4d59,0x4d58,0x4d56,UBOGON,UBOGON,0x4d6e,
+    UBOGON,UBOGON,UBOGON,0x9eec,UBOGON,UBOGON,0x4d81,0x4d86,UBOGON,0x4d8f,
+    UBOGON,UBOGON,UBOGON,0x9f68,0x4d9b,0x4db1,0x4db3,UBOGON,0x373a,UBOGON,
+    UBOGON,0x3827,UBOGON,UBOGON,0x386a,0x39ac,UBOGON,0x3c18,UBOGON,UBOGON,
+    0x3c4c,UBOGON,0x3d96,UBOGON,0x3f4a,UBOGON,UBOGON,0x4081,UBOGON,0x4083,
+    0x40f9,0x40f8,UBOGON,0x418e
+  },
+  {				/* ku 49 */
+    0x418f,0x41c1,UBOGON,UBOGON,UBOGON,0x4270,UBOGON,0x4271,UBOGON,0x432a,
+    0x432d,0x437d,0x8032,0x8031,UBOGON,0x444f,UBOGON,UBOGON,0x4490,UBOGON,
+    UBOGON,UBOGON,0x4579,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4605,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x89fd,UBOGON,UBOGON,0x4721,
+    UBOGON,UBOGON,UBOGON,0x4732,UBOGON,UBOGON,0x47cf,UBOGON,UBOGON,0x908e,
+    0x4916,0x4915,0x49b5,0x4a08,UBOGON,0x4a32,UBOGON,0x4a33,0x4a34,0x4a3c,
+    UBOGON,0x97c2,UBOGON,0x4a9c,UBOGON,0x4af4,0x4af2,UBOGON,0x4b62,UBOGON,
+    0x4b61,0x4b64,0x4bb5,0x9a4b,0x4bb4,UBOGON,UBOGON,0x4be3,UBOGON,UBOGON,
+    0x9b1c,0x4c0e,UBOGON,0x9b1b,UBOGON,0x4c2c,0x4c2b,UBOGON,UBOGON,UBOGON,
+    0x4c85,0x4c81,0x4c7e,0x4c83
+  },
+  {				/* ku 4a */
+    0x4c80,UBOGON,0x9c42,UBOGON,0x9dd4,0x4cfb,0x4cf7,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4cf8,UBOGON,UBOGON,UBOGON,UBOGON,0x4d5a,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x4d78,UBOGON,UBOGON,UBOGON,UBOGON,0x4d9d,0x4d9c,UBOGON,
+    UBOGON,UBOGON,0x34a9,0x34bf,0x56d0,0x56cf,UBOGON,0x5dda,UBOGON,0x3a77,
+    0x3a76,UBOGON,0x3abb,0x66ea,UBOGON,0x3d9b,UBOGON,0x3e0f,0x3e5b,UBOGON,
+    0x3f4c,0x3f6f,0x3fd9,UBOGON,0x4082,UBOGON,UBOGON,UBOGON,UBOGON,0x4274,
+    0x4272,UBOGON,UBOGON,UBOGON,0x4273,UBOGON,UBOGON,UBOGON,0x42b1,0x432e,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x434e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x460b,UBOGON,UBOGON,
+    0x466c,0x8b89,UBOGON,UBOGON
+  },
+  {				/* ku 4b */
+    0x478b,UBOGON,0x47d0,0x482d,UBOGON,0x48e4,0x4971,UBOGON,0x9458,0x496f,
+    UBOGON,0x4a87,0x4aa5,UBOGON,UBOGON,0x4b1e,0x4b65,0x4bb9,0x4bb7,0x4bb8,
+    0x4be4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4c8c,0x4c89,0x4c8a,UBOGON,
+    UBOGON,0x4c8b,UBOGON,UBOGON,UBOGON,0x4d01,0x4cfe,0x9de7,0x4d03,0x4d06,
+    UBOGON,0x9dea,0x9df1,UBOGON,0x4d1d,0x4d43,UBOGON,UBOGON,UBOGON,0x4d4f,
+    UBOGON,UBOGON,0x4d5b,0x4d70,UBOGON,0x4d88,UBOGON,UBOGON,0x4d89,0x9f44,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x9f6d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x5dd9,UBOGON,UBOGON,UBOGON,UBOGON,0x3d9e,0x3d9f,0x3ea7,0x3f4b,
+    0x3fdb,0x3fda,UBOGON,0x77d6,0x408e,0x4276,UBOGON,0x4330,0x432f,UBOGON,
+    0x4366,UBOGON,0x457e,UBOGON
+  },
+  {				/* ku 4c */
+    UBOGON,UBOGON,0x883a,UBOGON,0x8975,0x466f,UBOGON,0x47d1,0x482f,UBOGON,
+    UBOGON,0x48b2,0x4918,0x4917,UBOGON,0x4976,UBOGON,UBOGON,0x4a4f,0x4a89,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4af5,0x4b1f,UBOGON,UBOGON,0x9a5d,0x4be5,
+    UBOGON,UBOGON,0x4c10,UBOGON,0x4c0f,UBOGON,UBOGON,UBOGON,UBOGON,0x4c2f,
+    0x4c30,0x9c64,UBOGON,UBOGON,0x4c93,0x4c94,UBOGON,0x4d07,0x4d09,0x4d08,
+    UBOGON,0x4d0b,UBOGON,0x9e0a,UBOGON,UBOGON,UBOGON,0x4d50,0x4d71,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4d7b,0x4d7c,UBOGON,0x9f73,UBOGON,0x4da1,
+    UBOGON,UBOGON,0x4da0,0x4da2,UBOGON,0x361b,UBOGON,0x3682,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3fe9,UBOGON,0x4084,0x77e1,UBOGON,UBOGON,UBOGON,0x42b3,
+    0x4334,0x4333,0x4580,UBOGON
+  },
+  {				/* ku 4d */
+    UBOGON,0x46ad,UBOGON,0x4744,0x4755,UBOGON,0x47d2,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x4a8a,UBOGON,UBOGON,0x4b67,UBOGON,UBOGON,0x4be6,UBOGON,
+    0x4c13,UBOGON,0x9b2d,UBOGON,0x4c97,0x9e0c,UBOGON,UBOGON,0x4d0c,UBOGON,
+    UBOGON,UBOGON,0x4d46,0x4d5c,0x4d74,0x4d72,UBOGON,UBOGON,UBOGON,0x9f1f,
+    UBOGON,UBOGON,0x4da4,0x4da3,UBOGON,UBOGON,UBOGON,UBOGON,0x4db4,UBOGON,
+    0x3536,UBOGON,UBOGON,UBOGON,0x3cb2,UBOGON,UBOGON,0x3f16,0x7c70,0x4277,
+    UBOGON,0x457f,UBOGON,UBOGON,0x487d,0x9479,UBOGON,0x974a,0x4a8c,UBOGON,
+    0x4b68,0x4bbe,0x4c15,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d75,0x4da5,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4278,0x4335,0x7e9d,0x4582,UBOGON,
+    0x4583,UBOGON,0x4671,UBOGON
+  },
+  {				/* ku 4e */
+    0x487e,0x4a8e,UBOGON,0x9960,0x4b69,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4c9a,0x4c9b,UBOGON,UBOGON,UBOGON,0x4d90,UBOGON,0x9f9e,UBOGON,
+    UBOGON,0x4586,0x4585,UBOGON,0x460e,UBOGON,0x4695,UBOGON,0x4919,UBOGON,
+    0x4bc0,UBOGON,UBOGON,UBOGON,0x9ef8,0x9f3a,0x9f7d,UBOGON,UBOGON,0x400d,
+    0x4c16,UBOGON,0x4da9,0x4daa,0x4085,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x9f96,UBOGON,0x4bc2,0x4c31,0x4d11,0x4dab,0x4c9c,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  }
+};
+
+/* CNS 11643 plane 5 conversion table */
+
+static const unsigned short
+ cns11643_5tab[MAX_CNS11643_KU_5][MAX_CNS11643_TEN] = {
+  {				/* ku 01 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x355a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6729,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x3cbc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x49b9,UBOGON
+  },
+  {				/* ku 02 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x34de,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3543,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x37ac,0x37aa,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5e07,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5fcb,
+    0x38fe,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 03 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3441,
+    UBOGON,UBOGON,0x34b4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x37b3,
+    UBOGON,UBOGON,UBOGON,0x37b4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 04 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c1d,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c7c,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f55,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4126,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x49bc,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 05 */
+    UBOGON,UBOGON,UBOGON,UBOGON,0x344a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x344e,UBOGON,UBOGON,0x34c9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x52b7,0x52b8,UBOGON,0x52b6,0x52ba,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x357b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x3620,UBOGON,UBOGON,UBOGON,UBOGON,0x3689,0x3695,UBOGON,UBOGON,UBOGON,
+    0x36be,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x37c3,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 06 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3877,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x39d4,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b4c,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x3c20,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c5b,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3e2d,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 07 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x3e63,UBOGON,UBOGON,UBOGON,0x3f18,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3f74,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4128,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43da,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x44a4,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x488e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 08 */
+    0x345b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3753,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 09 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3880,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x38dd,UBOGON,UBOGON,UBOGON,0x38de,UBOGON,
+    0x3922,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6306,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3adb,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x6b85,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x3cda,0x3cdb,UBOGON,UBOGON
+  },
+  {				/* ku 0a */
+    UBOGON,UBOGON,UBOGON,0x3cd7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x401a,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0b */
+    0x41d6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43de,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x43e5,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4672,UBOGON,
+    0x46af,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x49c4,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3463,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x34ec,UBOGON,UBOGON
+  },
+  {				/* ku 0c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x3598,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x3758,UBOGON,UBOGON
+  },
+  {				/* ku 0d */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x37d3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38e2,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x3954,UBOGON,UBOGON,0x392f,UBOGON,UBOGON,
+    0x39b6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0e */
+    UBOGON,UBOGON,UBOGON,UBOGON,0x3b35,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x3b5d,UBOGON,UBOGON,0x3c29,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x3e1f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3e72,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f0b,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0f */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x40a2,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43ec,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 10 */
+    0x44bb,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4621,UBOGON,UBOGON,UBOGON,0x461f,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8c38,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x4791,0x4796,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 11 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x34bc,UBOGON,UBOGON,0x34d8,UBOGON,
+    UBOGON,0x34f4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3785,UBOGON,0x3783,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 12 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38ba,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3969,UBOGON,UBOGON,0x3945,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b6c,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 13 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3d04,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x3e3a,UBOGON,UBOGON,UBOGON,0x3e79,UBOGON,
+    UBOGON,0x7309,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f5d,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f8a,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4027,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 14 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x4146,0x4140,UBOGON,0x413f,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x419d,0x41cb,UBOGON,0x41e1,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x427f,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x4346,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x441a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 15 */
+    UBOGON,UBOGON,UBOGON,0x44d3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x44d0,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x458e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x46c3,0x46b6,UBOGON,UBOGON,UBOGON,0x8a2f,UBOGON,
+    0x46c0,0x46b8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x47d9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 16 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x48ec,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x52dc,UBOGON,UBOGON,UBOGON,0x35cc,UBOGON,0x35a2,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x35b6,UBOGON,UBOGON,0x35c5,0x35c6,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 17 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3683,0x5921,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x36f8,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x36f6,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x379b,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x5e3f,UBOGON,UBOGON
+  },
+  {				/* ku 18 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x388d,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x3956,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x395b,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x3a96,UBOGON,UBOGON
+  },
+  {				/* ku 19 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b7e,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x3b81,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x3c35,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c9b,UBOGON,
+    UBOGON,0x3d00,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1a */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3ed3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f9f,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x40b1,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x414b,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1b */
+    UBOGON,UBOGON,UBOGON,0x7b3f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x42d6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4389,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4400,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x44dc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x83d0,0x4590,
+    UBOGON,UBOGON,UBOGON,0x45b1,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x86e7,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x45aa,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x467d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x4769,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47a1,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47e7,
+    UBOGON,UBOGON,0x47ec,UBOGON,UBOGON,UBOGON,0x47df,UBOGON,UBOGON,UBOGON,
+    0x4833,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1d */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4bee,
+    UBOGON,0x4c32,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x34fc,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x352a,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1e */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x35d3,UBOGON,UBOGON,UBOGON,0x35d7,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x37f3,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1f */
+    0x3891,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38c0,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6117,UBOGON,0x3963,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x3970,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b02,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 20 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3d35,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ee0,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x3f9a,UBOGON,UBOGON,UBOGON,0x3fa3,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4005,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 21 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x415e,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x41a6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x435d,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43b8,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 22 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4434,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x446f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4594,0x4593,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x8714,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x88d1,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 23 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x8ccb,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4792,
+    UBOGON,UBOGON,UBOGON,0x47aa,UBOGON,UBOGON,UBOGON,0x47a7,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x47ef,UBOGON,UBOGON,UBOGON,UBOGON,0x8eed,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4922,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 24 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4ab5,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4b75,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x3482,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x52ec,UBOGON,UBOGON,UBOGON,
+    0x52e8,UBOGON,UBOGON,UBOGON,UBOGON,0x3535,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 25 */
+    UBOGON,0x35f0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x38f0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 26 */
+    UBOGON,UBOGON,0x3a3e,UBOGON,0x3a39,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3aa1,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b3b,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3bb7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3c57,0x3c70,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x3ca7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3d54,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 27 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f31,
+    0x7527,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3fbf,UBOGON,0x3fe4,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x404a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x40cf,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x798c
+  },
+  {				/* ku 28 */
+    UBOGON,0x7991,UBOGON,0x4114,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x420d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4201,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x42f1,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 29 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4476,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x450a,0x4503,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8660,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4635,0x4636,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2a */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4773,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47b1,UBOGON,0x47af,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47f4,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x48dc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4999,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2b */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4ab6,
+    0x4abd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x9904,UBOGON,0x999b,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4bf4,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4c35,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4caa,UBOGON,0x4d1f,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3550,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x377b,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x3809,UBOGON,UBOGON,UBOGON,0x3807,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2d */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x39bb,UBOGON,UBOGON,0x3a4b,UBOGON,UBOGON,UBOGON,0x3a4d,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3ac2,UBOGON,UBOGON,UBOGON,UBOGON,0x3b1a,UBOGON,UBOGON,
+    0x3b12,UBOGON,UBOGON,UBOGON,UBOGON,0x3b3c,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x3bc3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3bc0,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2e */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x729f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3fe5,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x405f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4118,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2f */
+    UBOGON,UBOGON,0x41ad,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x421e,UBOGON,UBOGON,
+    UBOGON,0x4227,UBOGON,UBOGON,UBOGON,UBOGON,0x4218,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4220,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x42f4,0x4302,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 30 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4524,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x8770,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 31 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x477d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8e37,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4864,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 32 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9703,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x4ac2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 33 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x4cac,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x349b,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x52f6,0x3526,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 34 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x3815,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x389c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x64cc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 35 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3d64,0x3d6e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x3d5f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x3ef6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x764a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 36 */
+    UBOGON,0x4073,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x40dd,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7ab9,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x7bd7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 37 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 38 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4688,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x47bb,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47ba,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4812,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4861,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x48e1
+  },
+  {				/* ku 39 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 3a */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x999f,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4b89,UBOGON,0x4b8c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x9b8d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9e77,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 3b */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x381a,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x3998,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x3bf1,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 3c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x3f6a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x764b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x76a2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4485,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4239,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x423d,0x4244
+  },
+  {				/* ku 3d */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4246,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x430e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4310,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x443e,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4484,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4549,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 3e */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x45df,UBOGON,UBOGON,
+    0x45f0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x468a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x4702,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47c0,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4815,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 3f */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x48e2,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 40 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4b4d,UBOGON,UBOGON,UBOGON,UBOGON,0x4b4a,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 41 */
+    UBOGON,UBOGON,0x4d63,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x4d93,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x350e,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x360a,UBOGON,UBOGON,UBOGON,UBOGON,0x360d,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 42 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x4074,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 43 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4256,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x425a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x42a3,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x42a8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 44 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x453c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x459b,0x459a,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x87f1,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x465e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x46a7,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 45 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x486e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x490d,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4943,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x4a73,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4a74,UBOGON,UBOGON,0x4a70
+  },
+  {				/* ku 46 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4bdb,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4c29,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4c51,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9bba,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 47 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4cdb,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d65,UBOGON,
+    UBOGON,0x4d64,0x4d67,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3611,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x3733,UBOGON,UBOGON,UBOGON,UBOGON,0x3821,0x3822,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x39a6,UBOGON,UBOGON,UBOGON,UBOGON,0x39a3,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 48 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ea1,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x425f,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x425c,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 49 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x45f5,UBOGON,0x8804,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4711,0x470c,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 4a */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x494e,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4b94,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 4b */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4c63,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4c61,UBOGON,0x9bd8,UBOGON,
+    0x4c5a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4ce3,UBOGON,UBOGON,
+    0x9d7c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x4daf,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3613,UBOGON,UBOGON,0x3680,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 4c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4db0,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7c46,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 4d */
+    UBOGON,0x4323,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4449,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x45fa,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 4e */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4959,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4a7e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4ba8,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4ba9,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 4f */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9d8d,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d54,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d6d,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4d8e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 50 */
+    UBOGON,UBOGON,UBOGON,0x3a72,UBOGON,UBOGON,0x3c14,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3d93,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x426f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x42b0,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x352e,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 51 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x4969,0x957e,UBOGON,UBOGON,UBOGON,UBOGON,0x49b4,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4a4d,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x4a83,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 52 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x4bb0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4c0c,UBOGON,0x4c18,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x9c20,UBOGON,UBOGON,0x9c22,UBOGON,UBOGON,0x9c1e,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4cf5,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 53 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x3e0e,UBOGON,UBOGON,UBOGON,UBOGON,0x3fd8,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 54 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x8970,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x482c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x496e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4a86,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4bb3,UBOGON,UBOGON,UBOGON,0x4beb,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 55 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x9c43,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9de0,UBOGON,UBOGON,0x4d42,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4d41,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4dac,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b2f,0x3b2e,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c4d,0x3c7b,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 56 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x42b2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x4722,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x9459,UBOGON,0x4970,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 57 */
+    UBOGON,UBOGON,UBOGON,0x4c95,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4d00,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d02,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4d9f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 58 */
+    UBOGON,UBOGON,UBOGON,UBOGON,0x457d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4af6,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4c12,
+    UBOGON,UBOGON,UBOGON,0x4c91,UBOGON,UBOGON,UBOGON,UBOGON,0x4c90,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 59 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3a79,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x3c4e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x4d1e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 5a */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x9c72,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 5b */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3828,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d91,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 5c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4587,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  }
+};
+
+/* CNS 11643 plane 6 conversion table */
+
+static const unsigned short
+ cns11643_6tab[MAX_CNS11643_KU_6][MAX_CNS11643_TEN] = {
+  {				/* ku 01 */
+    UBOGON,UBOGON,0x3405,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x353f,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x382a,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38a7,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x38fa
+  },
+  {				/* ku 02 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x3400,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x34db,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 03 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3438,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6530,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x353a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 04 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38c9,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 05 */
+    UBOGON,UBOGON,UBOGON,UBOGON,0x3c4f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x43cd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4492,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x3445,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x34b5,UBOGON,0x34b6,UBOGON
+  },
+  {				/* ku 06 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x3537,UBOGON,0x3530,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x373e,0x374d,0x3751,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 07 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3873,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x39be,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 08 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c1e,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3cc8,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x3cc3,0x3cc7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f56,UBOGON,0x3540,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 09 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x49bd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x351a,UBOGON,
+    UBOGON,0x352c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0a */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3549,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x357c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x37bf,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x37ba,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0b */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38d8,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x39b2,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ac4,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x3e2b,UBOGON,UBOGON,UBOGON,0x3e61,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x72dd
+  },
+  {				/* ku 0d */
+    0x3eb2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4129,UBOGON,UBOGON,UBOGON,UBOGON,0x4192,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0e */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3458,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0f */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x351c,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3637,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 10 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3843,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38b4,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 11 */
+    UBOGON,UBOGON,UBOGON,UBOGON,0x38e0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x3ae4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x6804,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c26,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 12 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x3e6f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 13 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x401c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4100,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x42b6,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x43e4,UBOGON
+  },
+  {				/* ku 14 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x44ad,UBOGON,0x82ff,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x8fec,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x48c3,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 15 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x3467,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x53de,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3596,UBOGON
+  },
+  {				/* ku 16 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x5a30,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x3759,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5bb2,
+    UBOGON,0x3776,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x37d2,UBOGON,UBOGON
+  },
+  {				/* ku 17 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x3920,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3929,UBOGON,UBOGON,
+    UBOGON,0x3938,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 18 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x3a89,0x3ab0,UBOGON,UBOGON,UBOGON,0x3abf,UBOGON,UBOGON,UBOGON,0x3ac5,
+    UBOGON,UBOGON,0x3aea,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c37,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x3ce4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 19 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ce8,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x3e20,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x3f86,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1a */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4356,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x4367,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1b */
+    0x8038,UBOGON,UBOGON,0x8081,UBOGON,UBOGON,UBOGON,0x43d1,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43eb,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x44b6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x45a3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x4610,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x491b,UBOGON,0x4987,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1d */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x3557,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1e */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x369d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x375f,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3779,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x3798,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x37dc,UBOGON,UBOGON,0x37df,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1f */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 20 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x39fd,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3af4,UBOGON,0x3aef,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c31,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 21 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x3d03,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3d09,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3e3e,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3e77,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x3e7b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 22 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x413a,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x41a0,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x41e5,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 23 */
+    UBOGON,0x427d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x436d,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43f8,UBOGON,0x8158,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4450,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4468,
+    0x4467,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 24 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x44cf,UBOGON,UBOGON,
+    UBOGON,0x44cd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x45ab,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x46c1,UBOGON,UBOGON,0x8a24,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 25 */
+    UBOGON,0x4747,UBOGON,0x4757,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x8dc3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x484e,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 26 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3477,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x51f2,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 27 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x55b6,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x35c4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3652,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 28 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x386b,0x5ec3,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3941,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x3950,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 29 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x3ac0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3afc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x3479,UBOGON,UBOGON,0x440b
+  },
+  {				/* ku 2a */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3d1e,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2b */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x3e85,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f97,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4093,UBOGON,UBOGON,UBOGON,0x7861,UBOGON,UBOGON,UBOGON,0x40b2,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7a01,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x41a4,UBOGON,UBOGON,0x41f2,UBOGON,UBOGON,UBOGON,UBOGON,0x41f1,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x4281,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x42dc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2d */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x440c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x446d,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2e */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x44e6,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8849,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x8999,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x46d1,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x472c,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2f */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x476e,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x47e5,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47e6,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x489f,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x921f,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 30 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4a0d,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x34f8,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x5313,UBOGON,0x3533,UBOGON,UBOGON,UBOGON,0x353c,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 31 */
+    UBOGON,0x354f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x35dc,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x55e0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 32 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x37f5,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x38c3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6139,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3971,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 33 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b01,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 34 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6ed7,UBOGON,0x3d41,UBOGON,UBOGON,
+    UBOGON,0x3dd7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3e45,UBOGON,UBOGON,
+    UBOGON,0x733d,UBOGON,UBOGON
+  },
+  {				/* ku 35 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ff2,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4049,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 36 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x41a9,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43cb,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x440d,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 37 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 38 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4631,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x46d5,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 39 */
+    UBOGON,UBOGON,UBOGON,0x4856,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x48f4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 3a */
+    UBOGON,UBOGON,UBOGON,0x9775,UBOGON,UBOGON,UBOGON,0x4a58,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3487,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 3b */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 3c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x37fa,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x38f2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 3d */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3a2f,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ac1,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c40,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 3e */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3d3f,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x3d46,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3e8f,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 3f */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3fac,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4168,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x41ab,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 40 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4291,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7fe4,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x8088,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4430,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 41 */
+    0x445d,UBOGON,UBOGON,0x4475,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x44ff,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x450b,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x45c8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 42 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x4774,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x47ac,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 43 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4a16,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 44 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4b3b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4bef,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  }
+};
+
+/* CNS 11643 plane 7 conversion table */
+
+static const unsigned short
+ cns11643_7tab[MAX_CNS11643_KU_7][MAX_CNS11643_TEN] = {
+  {				/* ku 01 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x35f6,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5655,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x3667,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 02 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x617f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x3992,UBOGON,UBOGON
+  },
+  {				/* ku 03 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3a45,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3bc9,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 04 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x3d55,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 05 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3ee8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3fb6,UBOGON,UBOGON,UBOGON,0x3fbd,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 06 */
+    UBOGON,UBOGON,UBOGON,0x40d6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4171,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4298,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 07 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 08 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x45cd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x46f6,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 09 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x477a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47b8,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4801,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0a */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x492f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4931,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x499c,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x49e6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0b */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x4b38,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x4c3a,UBOGON,UBOGON,0x4cb1,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d47,UBOGON,0x4d51,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0d */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3747,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x3817,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38a3,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0e */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b1e,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0f */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x71d7,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x3e9a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 10 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x3fc2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x40dc,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x41b3,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 11 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 12 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x8666,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x45d9,UBOGON,0x45dd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 13 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x46fc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 14 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8f3a,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4907,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x933d,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x49a8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 15 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4aca,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 16 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4b8d,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4cc0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4cca,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d25,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d4a,UBOGON,
+    0x4d53,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 17 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3605,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 18 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3bf0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 19 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3e02,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3e23,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1a */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4315,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1b */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x455d,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x465a,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4785,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x490b,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4939,UBOGON,UBOGON,UBOGON,
+    0x4937,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1d */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x4a6b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x4acd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1e */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4c4d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3510,UBOGON
+  },
+  {				/* ku 1f */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x367b,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x381d,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x64f5,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3b27,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 20 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x3fcf,UBOGON,UBOGON,UBOGON,0x3fcd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 21 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x4182,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4252,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x7f80,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 22 */
+    UBOGON,UBOGON,UBOGON,0x4451,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x455a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 23 */
+    UBOGON,0x4665,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8d01,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x48af,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 24 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4941,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4a29,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x4a2a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4a96,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x4b12
+  },
+  {				/* ku 25 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 26 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x367e,0x58e1,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 27 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x39a7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4320,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 28 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x7ce9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x81cb,UBOGON,UBOGON
+  },
+  {				/* ku 29 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4565,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2a */
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4704,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x4764,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4823,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2b */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x95d9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2d */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x34b9,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2e */
+    UBOGON,0x3c4b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x40f1,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2f */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 30 */
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4667,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4714,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x4889,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 31 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4c0b,UBOGON,
+    UBOGON,UBOGON,0x4c17,UBOGON
+  },
+  {				/* ku 32 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4c6d,UBOGON,0x4c70,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x4ced,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4d8d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x34a7,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 33 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6707,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x3e5a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 34 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x42af,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x456b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 35 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x471b,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4963,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 36 */
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4a80,0x4a84,0x4a7f,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4af1,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9a47,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 37 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4d1c,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x34a8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 38 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x418b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x432b,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x457a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 39 */
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4609,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x466d,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x471f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x496a,0x496c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 3a */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4bb2,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x4c1d,UBOGON,UBOGON,UBOGON,0x4c2d,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x4d45,UBOGON
+  },
+  {				/* ku 3b */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 3c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x460a,UBOGON,UBOGON,UBOGON,UBOGON,0x460c,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x482e,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 3d */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 3e */
+    UBOGON,UBOGON,0x4c8d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 3f */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4331,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 40 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x4bbc,0x4bbb,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 41 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x4c14,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 42 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x361c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x3772,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 43 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x4d0e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 44 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7674,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x4bec,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 45 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4279,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  }
+};
+
+#if CNS_OBSOLETE
+/* CNS 11643 plane 14 conversion table */
+
+static const unsigned short
+ cns11643_14tab[MAX_CNS11643_KU_14][MAX_CNS11643_TEN] = {
+  {				/* ku 01 */
+    0x4e28,0x4e36,0x4e3f,0x4e85,0x4e05,0x4e04,0x5182,0x5196,0x5338,0x5369,
+    0x53b6,0x4e2a,0x4e87,0x4e49,0x51e2,0x4e46,0x4e8f,0x4ebc,0x4ebe,0x5166,
+    0x51e3,0x5204,0x529c,UBOGON,0x5902,0x590a,0x5b80,0x5ddb,0x5e7a,0x5e7f,
+    0x5ef4,0x5f50,0x5f51,0x5f61,0x961d,UBOGON,0x4e63,0x4e62,0x4ea3,0x5185,
+    0x4ec5,0x4ecf,0x4ece,0x4ecc,0x5184,0x5186,UBOGON,UBOGON,0x51e4,0x5205,
+    0x529e,0x529d,0x52fd,0x5300,0x533a,UBOGON,0x5346,0x535d,0x5386,0x53b7,
+    UBOGON,0x53cc,UBOGON,0x53ce,0x5721,UBOGON,0x5e00,0x5f0c,0x6237,0x6238,
+    0x6534,0x6535,0x65e0,UBOGON,0x738d,0x4e97,0x4ee0,UBOGON,UBOGON,0x4ee7,
+    UBOGON,0x4ee6,UBOGON,UBOGON,UBOGON,UBOGON,0x56d8,0x518b,0x518c,0x5199,
+    0x51e5,UBOGON,0x520b,UBOGON
+  },
+  {				/* ku 02 */
+    UBOGON,0x5304,0x5303,0x5307,UBOGON,0x531e,0x535f,0x536d,0x5389,0x53ba,
+    0x53d0,UBOGON,0x53f6,0x53f7,0x53f9,UBOGON,0x53f4,UBOGON,UBOGON,0x5724,
+    0x5904,0x5918,0x5932,0x5930,0x5934,UBOGON,0x5975,UBOGON,0x5b82,0x5bf9,
+    0x5c14,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5e81,0x5e83,
+    0x5f0d,0x5f52,UBOGON,0x5fca,0x5fc7,0x6239,UBOGON,0x624f,0x65e7,0x672f,
+    0x6b7a,0x6c39,UBOGON,UBOGON,0x6c37,0x6c44,0x6c45,0x738c,0x7592,0x7676,
+    0x9093,0x9092,UBOGON,UBOGON,0x4e21,0x4e20,0x4e22,0x4e68,0x4e89,0x4e98,
+    0x4ef9,0x4eef,UBOGON,UBOGON,0x4ef8,0x4f06,0x4f03,0x4efc,0x4eee,0x4f16,
+    UBOGON,0x4f28,0x4f1c,0x4f07,0x4f1a,0x4efa,0x4f17,0x514a,UBOGON,0x5172,
+    UBOGON,0x51b4,0x51b3,0x51b2
+  },
+  {				/* ku 03 */
+    UBOGON,0x51e8,UBOGON,0x5214,0x520f,0x5215,0x5218,0x52a8,UBOGON,0x534b,
+    0x534f,UBOGON,0x5350,UBOGON,0x538b,UBOGON,0x53be,UBOGON,0x53d2,0x5416,
+    0x53ff,UBOGON,0x5400,UBOGON,0x5405,0x5413,0x5415,UBOGON,UBOGON,0x56e3,
+    0x5735,0x5736,0x5731,0x5732,0x58ee,0x5905,0x4e54,UBOGON,0x5936,UBOGON,
+    UBOGON,UBOGON,0x597a,UBOGON,0x5986,UBOGON,UBOGON,0x5b86,0x5f53,0x5c18,
+    UBOGON,0x5c3d,0x5c78,UBOGON,UBOGON,UBOGON,UBOGON,0x5c80,UBOGON,0x5e08,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x5ef5,0x5f0e,UBOGON,UBOGON,UBOGON,0x5fd3,
+    0x5fda,UBOGON,0x5fdb,UBOGON,0x620f,0x625d,0x625f,0x6267,0x6257,0x9f50,
+    UBOGON,0x65eb,0x65ea,UBOGON,0x6737,UBOGON,0x6732,0x6736,0x6b22,0x6bce,
+    UBOGON,0x6c58,0x6c51,0x6c77
+  },
+  {				/* ku 04 */
+    0x6c3c,UBOGON,0x6c5a,UBOGON,0x6c53,0x706f,0x7072,0x706e,UBOGON,UBOGON,
+    0x7073,0x72b1,0x72b2,UBOGON,0x738f,UBOGON,UBOGON,UBOGON,0x793c,UBOGON,
+    0x808d,0x808e,UBOGON,0x827b,UBOGON,0x8d71,0x8fb9,0x9096,0x909a,UBOGON,
+    0x4e24,0x4e71,UBOGON,0x4e9c,0x4f45,0x4f4a,0x4f39,0x4f37,UBOGON,0x4f32,
+    0x4f42,UBOGON,0x4f44,0x4f4b,UBOGON,0x4f40,0x4f35,0x4f31,0x5151,UBOGON,
+    0x5150,0x514e,UBOGON,UBOGON,0x519d,UBOGON,0x51b5,0x51b8,0x51ec,0x5223,
+    0x5227,0x5226,0x521f,0x522b,0x5220,0x52b4,0x52b3,UBOGON,0x5325,0x533b,
+    0x5374,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x544d,UBOGON,UBOGON,0x543a,
+    UBOGON,UBOGON,0x5444,0x544c,0x5423,0x541a,0x5432,0x544b,0x5421,UBOGON,
+    0x5434,0x5449,0x5450,0x5422
+  },
+  {				/* ku 05 */
+    0x543f,0x5451,0x545a,0x542f,UBOGON,0x56e9,0x56f2,0x56f3,0x56ef,0x56ed,
+    0x56ec,0x56e6,0x5748,UBOGON,0x5744,0x573f,0x573c,0x5753,0x5756,UBOGON,
+    0x575f,0x5743,0x5758,0x5757,UBOGON,UBOGON,UBOGON,0x5746,UBOGON,0x573d,
+    UBOGON,0x5742,0x5754,0x5755,0x58f1,0x58f2,0x58f0,0x590b,0x9ea6,0x56f1,
+    0x593d,UBOGON,0x5994,0x598c,UBOGON,0x599c,UBOGON,UBOGON,0x599f,UBOGON,
+    0x599b,UBOGON,0x5989,0x599a,UBOGON,0x6588,UBOGON,0x5b8d,UBOGON,0x5bfe,
+    0x5bff,0x5bfd,0x5c2b,UBOGON,0x5c84,0x5c8e,0x5c9c,UBOGON,UBOGON,0x5c85,
+    0x5df5,0x5e09,UBOGON,UBOGON,0x5e0b,UBOGON,0x5e92,0x5e90,0x5f03,UBOGON,
+    0x5f1e,0x5f63,UBOGON,0x5fe7,0x5ffe,0x5fe6,0x5fdc,0x5fce,UBOGON,0x5ffc,
+    0x5fdf,0x5fec,0x5ff6,UBOGON
+  },
+  {				/* ku 06 */
+    0x5ff2,0x5ff0,0x5ff9,UBOGON,0x6213,UBOGON,UBOGON,0x623b,0x623c,0x6282,
+    UBOGON,UBOGON,UBOGON,0x6278,0x628b,UBOGON,0x629e,0x62a5,0x629b,0x629c,
+    0x6299,0x628d,0x6285,0x629d,0x6275,UBOGON,UBOGON,UBOGON,0x65f6,UBOGON,
+    UBOGON,UBOGON,0x66f5,0x675b,UBOGON,0x6754,0x6752,UBOGON,0x6758,0x6744,
+    0x674a,0x6761,UBOGON,0x6c7f,0x6c91,0x6c9e,UBOGON,0x6c6e,0x6c7c,0x6c9f,
+    0x6c75,UBOGON,0x6c56,0x6ca2,0x6c79,UBOGON,0x6ca1,UBOGON,0x6caa,0x6ca0,
+    UBOGON,0x7079,0x7077,0x707e,UBOGON,0x7075,0x707b,0x7264,UBOGON,0x72bb,
+    0x72bc,0x72c7,0x72b9,0x72be,0x72b6,UBOGON,UBOGON,0x7398,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x7593,0x7680,UBOGON,0x7683,0x76c0,0x76c1,UBOGON,UBOGON,
+    0x77f4,0x77f5,UBOGON,0x7acc
+  },
+  {				/* ku 07 */
+    0x7acd,0x7cfa,0x809f,0x8091,0x8097,0x8094,UBOGON,0x8286,0x828c,UBOGON,
+    0x8295,UBOGON,0x866c,UBOGON,0x8fb5,0x8fbe,0x8fc7,UBOGON,0x8fc1,0x90a9,
+    0x90a4,UBOGON,UBOGON,UBOGON,0x90a8,0x9627,0x9626,0x962b,0x9633,0x9634,
+    0x9629,0x4e3d,UBOGON,0x4e9d,0x4f93,0x4f8a,UBOGON,UBOGON,0x4f6d,0x4f8e,
+    0x4fa0,0x4fa2,0x4fa1,0x4f9f,0x4fa3,UBOGON,0x4f72,UBOGON,0x4f8c,0x5156,
+    UBOGON,UBOGON,0x5190,UBOGON,UBOGON,UBOGON,0x51ed,0x51fe,0x522f,UBOGON,
+    0x523c,0x5234,0x5239,0x52b9,0x52b5,0x52bf,0x5355,UBOGON,0x5376,0x537a,
+    0x5393,UBOGON,0x53c1,0x53c2,0x53d5,0x5485,UBOGON,0x545f,0x5493,0x5489,
+    0x5479,0x9efe,0x548f,0x5469,0x546d,UBOGON,0x5494,0x546a,0x548a,UBOGON,
+    0x56fd,0x56fb,0x56f8,UBOGON
+  },
+  {				/* ku 08 */
+    0x56fc,0x56f6,0x5765,0x5781,0x5763,0x5767,UBOGON,0x576e,0x5778,0x577f,
+    UBOGON,UBOGON,0x58f3,0x594b,0x594c,UBOGON,UBOGON,UBOGON,0x59ad,UBOGON,
+    0x59c4,UBOGON,0x59c2,0x59b0,UBOGON,UBOGON,UBOGON,UBOGON,0x59bf,UBOGON,
+    0x59c9,0x59b8,0x59ac,UBOGON,UBOGON,UBOGON,0x59b7,0x59d7,UBOGON,0x5b60,
+    UBOGON,0x5b96,0x5b9e,0x5b94,0x5b9f,0x5b9d,UBOGON,0x5c00,0x5c19,UBOGON,
+    UBOGON,0x5c49,0x5c4a,UBOGON,0x5cbb,0x5cc1,UBOGON,UBOGON,UBOGON,0x5cb9,
+    0x5c9e,0x5cb4,0x5cba,0x5df6,0x5e13,0x5e12,0x5e77,UBOGON,0x5e98,UBOGON,
+    0x5e99,0x5e9d,0x5ef8,UBOGON,0x5ef9,UBOGON,0x5f06,0x5f21,UBOGON,0x5f25,
+    0x5f55,UBOGON,UBOGON,UBOGON,0x5f84,0x5f83,0x6030,0x6007,UBOGON,0x6036,
+    UBOGON,UBOGON,UBOGON,0x5fe9
+  },
+  {				/* ku 09 */
+    0x603d,0x6008,UBOGON,UBOGON,0x62ba,0x62b2,UBOGON,0x62b7,0x62e4,0x62a7,
+    UBOGON,UBOGON,UBOGON,0x62d5,0x62e1,0x62dd,0x62a6,0x62c1,0x62c5,0x62c0,
+    0x62df,0x62e0,0x62de,UBOGON,0x6589,UBOGON,0x65a6,0x65ba,UBOGON,0x65ff,
+    UBOGON,0x6617,0x6618,0x6601,0x65fe,UBOGON,0x670c,UBOGON,0x676b,0x6796,
+    0x6782,0x678a,UBOGON,0x67a3,UBOGON,0x67a2,0x678f,UBOGON,0x67f9,0x6780,
+    0x6b26,0x6b27,0x6b68,0x6b69,UBOGON,0x6b81,0x6bb4,0x6bd1,UBOGON,UBOGON,
+    0x6c1c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6c97,0x6c6c,0x6cdf,UBOGON,
+    0x6cea,UBOGON,0x6ce4,0x6cd8,0x6cb2,0x6cce,0x6cc8,UBOGON,0x708b,0x7088,
+    0x7090,0x708f,UBOGON,0x7087,0x7089,0x708d,0x7081,UBOGON,0x708c,UBOGON,
+    UBOGON,0x7240,UBOGON,UBOGON
+  },
+  {				/* ku 0a */
+    0x7265,0x7266,0x7268,UBOGON,UBOGON,0x72cd,0x72d3,0x72db,UBOGON,0x72cf,
+    0x73a7,0x73a3,0x739e,UBOGON,0x73af,UBOGON,UBOGON,0x73aa,0x739c,UBOGON,
+    0x7542,0x7544,0x753b,0x7541,UBOGON,0x759b,0x759e,UBOGON,0x79c4,0x79c3,
+    0x79c6,UBOGON,UBOGON,0x79c7,UBOGON,0x79ca,UBOGON,UBOGON,0x7acf,0x7c76,
+    0x7c74,0x7cff,0x7cfc,UBOGON,UBOGON,0x7f59,0x80a8,UBOGON,UBOGON,0x80b0,
+    UBOGON,0x80b3,UBOGON,0x80a4,0x80b6,0x80a7,0x80ac,UBOGON,0x80a6,0x5367,
+    0x820e,0x82c4,0x833e,0x829c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x82aa,
+    UBOGON,0x82c9,UBOGON,UBOGON,0x82a6,0x82b2,UBOGON,UBOGON,UBOGON,0x8fcc,
+    0x8fd9,0x8fca,0x8fd8,0x8fcf,0x90b7,UBOGON,0x90ad,0x90b9,0x9637,UBOGON,
+    0x9641,0x963e,0x96b6,0x9751
+  },
+  {				/* ku 0b */
+    0x9763,0x4e57,0x4e79,0x4eb2,0x4eb0,0x4eaf,0x4eb1,0x4fd2,0x4fd5,UBOGON,
+    0x4fbe,0x4fb8,0x4fb0,0x4fb1,0x4fc8,UBOGON,UBOGON,0x4fc6,0x4fcc,0x4fe5,
+    0x4fe3,0x4fb4,0x516a,UBOGON,0x519f,UBOGON,0x51c1,UBOGON,0x51c2,0x51c3,
+    0x5245,0x5248,UBOGON,UBOGON,0x524f,UBOGON,UBOGON,0x52c5,0x52ca,0x52c4,
+    0x5327,0x5358,0x537d,UBOGON,0x53dd,0x53dc,0x53da,0x53d9,0x54b9,UBOGON,
+    0x54d0,0x54b4,0x54ca,UBOGON,0x54a3,0x54da,0x54a4,UBOGON,0x54b2,0x549e,
+    0x549f,0x54b5,UBOGON,UBOGON,0x54cd,UBOGON,0x54cc,UBOGON,0x5700,0x57ac,
+    0x5791,0x578e,0x578d,0x5792,0x57a1,0x5790,0x57a6,0x57a8,UBOGON,0x579c,
+    0x5796,0x57a7,UBOGON,UBOGON,UBOGON,UBOGON,0x58f5,UBOGON,0x5909,0x5908,
+    UBOGON,0x5952,UBOGON,UBOGON
+  },
+  {				/* ku 0c */
+    0x59df,UBOGON,0x59eb,0x59ef,0x59f0,0x59d5,0x5a0d,0x5a04,0x59f9,0x5a02,
+    0x59f8,0x59e2,0x59d9,0x59e7,0x5b6a,UBOGON,UBOGON,0x5bab,UBOGON,0x5c1b,
+    0x5c2f,UBOGON,0x663c,UBOGON,UBOGON,UBOGON,0x5cd1,0x5cdc,0x5ce6,0x5ce1,
+    0x5ccd,UBOGON,0x5ce2,0x5cdd,0x5ce5,0x5dfb,0x5dfa,0x5e1e,UBOGON,0x5ea1,
+    UBOGON,UBOGON,0x5efc,0x5efb,0x5f2f,UBOGON,UBOGON,0x5f66,UBOGON,UBOGON,
+    UBOGON,0x605c,UBOGON,0x604e,0x6051,UBOGON,UBOGON,0x6023,0x6031,0x607c,
+    0x6052,UBOGON,0x6060,0x604a,0x6061,UBOGON,0x6218,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x631f,0x6317,0x62ea,0x6321,0x6304,0x6305,
+    UBOGON,0x6531,0x6544,0x6540,UBOGON,0x6542,0x65be,UBOGON,0x6629,0x661b,
+    UBOGON,0x6623,0x662c,0x661a
+  },
+  {				/* ku 0d */
+    0x6630,0x663b,0x661e,0x6637,0x6638,UBOGON,0x670e,UBOGON,UBOGON,0x67e8,
+    0x67d6,UBOGON,0x67c7,0x67bc,0x6852,0x67bf,0x67d5,0x67fe,0x8363,0x67fb,
+    UBOGON,0x67b1,0x6801,0x6805,0x6800,0x67d7,UBOGON,0x6b2a,0x6b6b,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x6be1,UBOGON,UBOGON,0x6d23,0x6cff,0x6d14,0x6d05,
+    0x6d13,0x6d06,0x6d21,UBOGON,0x6d15,0x6caf,0x6cf4,0x6d02,0x6d45,UBOGON,
+    0x6d26,UBOGON,0x6d44,UBOGON,0x6d24,0x70a5,UBOGON,0x70a3,UBOGON,0x70a2,
+    0x70bb,0x70a0,0x70aa,UBOGON,UBOGON,0x70a8,0x70b6,0x70b2,0x70a7,UBOGON,
+    UBOGON,0x70b9,0x722e,UBOGON,0x723c,UBOGON,0x726d,UBOGON,UBOGON,0x72e7,
+    0x72ed,UBOGON,0x72ec,0x72e5,0x72e2,UBOGON,0x73c4,0x73bd,0x73cf,0x73c9,
+    0x73c1,0x73d0,UBOGON,0x73ce
+  },
+  {				/* ku 0e */
+    0x74ed,0x74eb,UBOGON,0x74ef,0x7549,0x7550,0x7546,0x754a,UBOGON,0x754d,
+    0x75a6,UBOGON,UBOGON,UBOGON,0x75a8,UBOGON,UBOGON,0x76c7,0x76ff,UBOGON,
+    0x76fd,0x77e6,0x780a,UBOGON,0x7804,0x780b,0x7807,UBOGON,0x7815,0x7808,
+    UBOGON,0x79d3,0x79d4,0x79d0,0x79d7,0x7a7c,UBOGON,UBOGON,0x7a7d,0x7a83,
+    0x7a82,UBOGON,0x7ad4,0x7ad5,0x7ad3,0x7ad0,0x7ad2,0x7afe,0x7afc,0x7c77,
+    0x7c7c,0x7c7b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x7f8f,0x80d3,UBOGON,0x80cb,0x80d2,UBOGON,0x8109,0x80e2,0x80df,0x80c6,
+    UBOGON,0x8224,0x82f7,0x82d8,0x82dd,UBOGON,UBOGON,0x82f8,0x82fc,UBOGON,
+    UBOGON,0x82e9,UBOGON,0x82ee,UBOGON,0x82d0,0x830e,0x82e2,0x830b,0x82fd,
+    0x5179,0x8676,UBOGON,0x8678
+  },
+  {				/* ku 0f */
+    UBOGON,UBOGON,0x8675,0x867d,UBOGON,0x8842,0x8866,UBOGON,0x898c,0x8a05,
+    UBOGON,0x8a06,UBOGON,0x8c9f,UBOGON,0x8ff1,0x8fe7,0x8fe9,0x8fef,0x90c2,
+    0x90bc,UBOGON,0x90c6,0x90c0,UBOGON,UBOGON,0x90cd,0x90c9,UBOGON,0x90c4,
+    UBOGON,0x9581,UBOGON,0x9cec,0x5032,0x4ff9,0x501d,0x4fff,0x5004,0x4ff0,
+    0x5003,UBOGON,0x5002,0x4ffc,0x4ff2,0x5024,0x5008,0x5036,0x502e,UBOGON,
+    0x5010,0x5038,0x5039,0x4ffd,0x5056,0x4ffb,0x51a3,0x51a6,0x51a1,UBOGON,
+    UBOGON,0x51c7,0x51c9,0x5260,0x5264,0x5259,0x5265,0x5267,0x5257,0x5263,
+    UBOGON,0x5253,UBOGON,0x52cf,UBOGON,0x52ce,0x52d0,0x52d1,0x52cc,UBOGON,
+    UBOGON,UBOGON,0x550d,0x54f4,UBOGON,0x5513,0x54ef,0x54f5,0x54f9,0x5502,
+    0x5500,UBOGON,UBOGON,0x5518
+  },
+  {				/* ku 10 */
+    0x54f0,0x54f6,UBOGON,UBOGON,0x5519,UBOGON,0x5705,0x57c9,UBOGON,0x57b7,
+    0x57cd,UBOGON,UBOGON,UBOGON,0x57be,0x57bb,UBOGON,0x57db,0x57c8,0x57c4,
+    0x57c5,0x57d1,0x57ca,0x57c0,UBOGON,UBOGON,0x5a21,0x5a2a,UBOGON,0x5a1d,
+    UBOGON,0x5a0b,UBOGON,UBOGON,UBOGON,UBOGON,0x5a22,UBOGON,UBOGON,0x5a24,
+    UBOGON,0x5a14,0x5a31,UBOGON,0x5a2f,0x5a1a,0x5a12,UBOGON,UBOGON,0x5a26,
+    UBOGON,UBOGON,0x5bbc,0x5bbb,0x5bb7,0x5c05,0x5c06,0x5c52,0x5c53,UBOGON,
+    UBOGON,0x5cfa,0x5ceb,UBOGON,0x5cf3,0x5cf5,0x5ce9,0x5cef,UBOGON,0x5e2a,
+    0x5e30,0x5e2e,0x5e2c,0x5e2f,0x5eaf,0x5ea9,UBOGON,0x5efd,0x5f32,0x5f8e,
+    0x5f93,0x5f8f,0x604f,0x6099,UBOGON,0x607e,UBOGON,0x6074,0x604b,0x6073,
+    0x6075,UBOGON,UBOGON,0x6056
+  },
+  {				/* ku 11 */
+    0x60a9,0x608b,0x60a6,UBOGON,0x6093,0x60ae,0x609e,0x60a7,0x6245,UBOGON,
+    UBOGON,0x632e,UBOGON,0x6352,0x6330,0x635b,UBOGON,0x6319,0x631b,UBOGON,
+    0x6331,0x635d,0x6337,0x6335,0x6353,UBOGON,0x635c,0x633f,0x654b,UBOGON,
+    UBOGON,0x658b,UBOGON,0x659a,0x6650,0x6646,0x664e,0x6640,UBOGON,0x664b,
+    0x6648,UBOGON,0x6660,0x6644,0x664d,UBOGON,0x6837,0x6824,UBOGON,UBOGON,
+    0x681b,0x6836,UBOGON,0x682c,0x6819,0x6856,0x6847,0x683e,0x681e,UBOGON,
+    0x6815,0x6822,0x6827,0x6859,0x6858,0x6855,0x6830,0x6823,0x6b2e,0x6b2b,
+    0x6b30,0x6b6c,UBOGON,0x6b8b,UBOGON,0x6be9,0x6bea,0x6be5,0x6d6b,UBOGON,
+    UBOGON,0x6d73,0x6d57,UBOGON,UBOGON,0x6d5d,0x6d56,0x6d8f,0x6d5b,0x6d1c,
+    0x6d9a,0x6d9b,0x6d99,UBOGON
+  },
+  {				/* ku 12 */
+    0x6d81,0x6d71,UBOGON,UBOGON,0x6d72,0x6d5c,0x6d96,0x70c4,0x70db,0x70cc,
+    0x70d0,0x70e3,0x70df,UBOGON,0x70d6,0x70ee,0x70d5,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x727a,UBOGON,0x72f5,0x7302,UBOGON,UBOGON,0x73e2,0x73ec,0x73d5,
+    0x73f9,0x73df,0x73e6,UBOGON,UBOGON,UBOGON,UBOGON,0x73e4,0x73e1,0x74f3,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x7556,0x7555,0x7558,0x7557,0x755e,0x75c3,
+    UBOGON,UBOGON,0x75b4,UBOGON,0x75b1,UBOGON,UBOGON,0x76cb,0x76cc,0x772a,
+    UBOGON,0x7716,0x770f,UBOGON,UBOGON,0x773f,0x772b,0x770e,0x7724,UBOGON,
+    0x7721,0x7718,0x77dd,UBOGON,UBOGON,0x7824,0x7836,UBOGON,0x7958,0x7959,
+    UBOGON,0x7962,0x79da,0x79d9,UBOGON,0x79e1,0x79e5,0x79e8,0x79db,UBOGON,
+    0x79e2,0x79f0,UBOGON,UBOGON
+  },
+  {				/* ku 13 */
+    UBOGON,UBOGON,0x7ada,0x7add,UBOGON,0x7adb,0x7adc,UBOGON,UBOGON,0x7b0d,
+    0x7b0b,0x7b14,0x7c8e,0x7c86,UBOGON,0x7c87,0x7c83,0x7c8b,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x7d24,UBOGON,UBOGON,UBOGON,0x7d25,0x7f62,0x7f93,0x7f99,
+    0x7f97,UBOGON,UBOGON,0x7fc4,0x7fc6,0x800a,UBOGON,UBOGON,0x8040,0x803c,
+    0x803b,0x80f6,0x80ff,0x80ee,0x8104,0x8103,0x8107,UBOGON,UBOGON,0x80f7,
+    UBOGON,UBOGON,0x822d,UBOGON,0x8227,0x8229,0x831f,0x8357,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x8321,UBOGON,UBOGON,0x8318,0x8358,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x8684,0x869f,0x869b,0x8689,0x86a6,0x8692,0x868f,0x86a0,
+    0x884f,0x8878,0x887a,0x886e,0x887b,0x8884,0x8873,UBOGON,UBOGON,0x8a0d,
+    0x8a0b,0x8a19,UBOGON,UBOGON
+  },
+  {				/* ku 14 */
+    UBOGON,UBOGON,UBOGON,UBOGON,0x8ff9,0x9009,0x9008,UBOGON,0x90de,0x9151,
+    UBOGON,UBOGON,0x91db,0x91df,0x91de,0x91d6,0x91e0,0x9585,0x9660,0x9659,
+    UBOGON,0x9656,UBOGON,UBOGON,0x96bd,UBOGON,UBOGON,0x5042,0x5059,UBOGON,
+    0x5044,0x5066,0x5052,0x5054,0x5071,0x5050,0x507b,0x507c,0x5058,UBOGON,
+    UBOGON,0x5079,0x506c,0x5078,0x51a8,0x51d1,0x51cf,0x5268,0x5276,0x52d4,
+    UBOGON,0x53a0,0x53c4,UBOGON,0x5558,0x554c,0x5568,UBOGON,0x5549,UBOGON,
+    UBOGON,0x555d,0x5529,UBOGON,0x5554,0x5553,UBOGON,0x555a,UBOGON,0x553a,
+    0x553f,0x552b,0x57ea,UBOGON,0x57ef,UBOGON,UBOGON,0x57dd,0x57fe,UBOGON,
+    0x57de,0x57e6,UBOGON,0x57e8,0x57ff,0x5803,0x58f7,0x68a6,0x591f,UBOGON,
+    0x595b,0x595d,0x595e,UBOGON
+  },
+  {				/* ku 15 */
+    UBOGON,0x5a2b,UBOGON,0x5a3b,UBOGON,UBOGON,0x5a61,0x5a3a,0x5a6e,0x5a4b,
+    0x5a6b,UBOGON,UBOGON,0x5a45,0x5a4e,0x5a68,0x5a3d,0x5a71,0x5a3f,0x5a6f,
+    0x5a75,UBOGON,0x5a73,0x5a2c,0x5a59,0x5a54,0x5a4f,0x5a63,UBOGON,UBOGON,
+    0x5bc8,UBOGON,0x5bc3,UBOGON,0x5c5b,0x5c61,UBOGON,0x5d21,0x5d0a,0x5d09,
+    UBOGON,0x5d2c,0x5d08,UBOGON,UBOGON,0x5d2a,0x5d15,UBOGON,0x5d10,0x5d13,
+    UBOGON,0x5d2f,0x5d18,UBOGON,0x5de3,0x5e39,0x5e35,0x5e3a,0x5e32,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x5ebb,0x5eba,0x5f34,0x5f39,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x6098,UBOGON,0x60d0,UBOGON,UBOGON,UBOGON,0x60d7,0x60aa,UBOGON,
+    0x60a1,0x60a4,UBOGON,0x60ee,UBOGON,0x60e7,UBOGON,UBOGON,0x60de,UBOGON,
+    UBOGON,0x637e,0x638b,UBOGON
+  },
+  {				/* ku 16 */
+    UBOGON,0x6379,0x6386,0x6393,UBOGON,0x6373,0x636a,UBOGON,0x636c,UBOGON,
+    0x637f,UBOGON,0x63b2,0x63ba,UBOGON,UBOGON,0x6366,0x6374,UBOGON,0x655a,
+    UBOGON,0x654e,0x654d,0x658d,0x658e,0x65ad,UBOGON,0x65c7,0x65ca,UBOGON,
+    0x65c9,UBOGON,0x65e3,0x6657,UBOGON,0x6663,0x6667,0x671a,0x6719,0x6716,
+    UBOGON,UBOGON,0x689e,0x68b6,0x6898,0x6873,UBOGON,0x689a,0x688e,0x68b7,
+    0x68db,0x68a5,0x686c,0x68c1,0x6884,UBOGON,UBOGON,0x6895,0x687a,0x6899,
+    UBOGON,0x68b8,0x68b9,0x6870,UBOGON,0x6b35,UBOGON,0x6b90,0x6bbb,0x6bed,
+    UBOGON,UBOGON,UBOGON,0x6dc1,0x6dc3,0x6dce,UBOGON,UBOGON,0x6dad,0x6e04,
+    UBOGON,0x6db9,UBOGON,0x6de7,UBOGON,0x6e08,0x6e06,UBOGON,0x6e0a,0x6db0,
+    UBOGON,0x6df8,0x6e0c,UBOGON
+  },
+  {				/* ku 17 */
+    0x6db1,UBOGON,0x6e02,0x6e07,0x6e09,0x6e01,0x6e17,0x6dff,0x6e12,UBOGON,
+    UBOGON,0x7103,0x7107,0x7101,0x70f5,0x70f1,0x7108,0x70f2,0x710f,UBOGON,
+    0x70fe,UBOGON,UBOGON,UBOGON,0x731a,0x7310,0x730e,0x7402,0x73f3,UBOGON,
+    UBOGON,0x73fb,UBOGON,UBOGON,UBOGON,0x751b,0x7523,0x7561,0x7568,UBOGON,
+    0x7567,0x75d3,UBOGON,UBOGON,0x7690,UBOGON,UBOGON,0x76d5,0x76d7,0x76d6,
+    0x7730,UBOGON,0x7726,UBOGON,0x7740,UBOGON,0x771e,UBOGON,UBOGON,UBOGON,
+    0x7847,UBOGON,0x784b,0x7851,0x784f,0x7842,0x7846,UBOGON,0x796e,0x796c,
+    0x79f2,UBOGON,0x79f1,0x79f5,0x79f3,0x79f9,UBOGON,UBOGON,UBOGON,0x7a9a,
+    0x7a93,0x7a91,0x7ae1,UBOGON,UBOGON,0x7b21,0x7b1c,0x7b16,0x7b17,0x7b36,
+    0x7b1f,UBOGON,0x7c93,0x7c99
+  },
+  {				/* ku 18 */
+    0x7c9a,0x7c9c,UBOGON,0x7d49,UBOGON,0x7d34,0x7d37,UBOGON,0x7d2d,UBOGON,
+    0x7d4c,UBOGON,UBOGON,0x7d48,UBOGON,UBOGON,0x7f3b,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x8008,0x801a,UBOGON,0x801d,UBOGON,0x8049,0x8045,0x8044,0x7c9b,
+    UBOGON,UBOGON,0x812a,0x812e,UBOGON,UBOGON,0x8131,UBOGON,0x811a,0x8134,
+    0x8117,UBOGON,UBOGON,UBOGON,0x831d,0x8371,0x8384,0x8380,0x8372,0x83a1,
+    UBOGON,0x8379,0x8391,UBOGON,0x839f,0x83ad,UBOGON,UBOGON,0x8323,UBOGON,
+    0x8385,0x839c,0x83b7,0x8658,0x865a,UBOGON,0x8657,0x86b2,UBOGON,0x86ae,
+    UBOGON,UBOGON,UBOGON,0x8845,0x889c,0x8894,0x88a3,0x888f,0x88a5,0x88a9,
+    0x88a6,0x888a,0x88a0,0x8890,0x8992,0x8991,0x8994,UBOGON,0x8a26,0x8a32,
+    0x8a28,UBOGON,UBOGON,0x8a1c
+  },
+  {				/* ku 19 */
+    UBOGON,0x8a2b,0x8a20,UBOGON,0x8a29,UBOGON,UBOGON,UBOGON,0x8a21,0x8c3a,
+    UBOGON,0x8c5b,0x8c58,0x8c7c,UBOGON,0x8ca6,0x8cae,0x8cad,0x8d65,UBOGON,
+    0x8d7e,UBOGON,0x8d7c,0x8d7f,0x8d7a,0x8dbd,UBOGON,UBOGON,0x8dc0,0x8dbb,
+    0x8ead,0x8eaf,0x8ed6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8ed9,UBOGON,
+    UBOGON,0x9012,0x900e,0x9025,UBOGON,0x9013,0x90ee,UBOGON,0x90ab,0x90f7,
+    UBOGON,0x9159,0x9154,0x91f2,0x91f0,0x91e5,0x91f6,UBOGON,UBOGON,0x9587,
+    UBOGON,0x965a,UBOGON,UBOGON,0x966e,UBOGON,UBOGON,UBOGON,0x9679,UBOGON,
+    0x98e1,0x98e6,UBOGON,0x9ec4,0x9ed2,0x4e80,UBOGON,0x4e81,0x508f,0x5097,
+    0x5088,0x5089,UBOGON,UBOGON,0x5081,0x5160,UBOGON,UBOGON,0x5e42,0x51d3,
+    UBOGON,UBOGON,0x51d2,0x51d6
+  },
+  {				/* ku 1a */
+    0x5273,UBOGON,0x5270,UBOGON,UBOGON,UBOGON,0x53a8,0x53a6,0x53c5,0x5597,
+    0x55de,UBOGON,UBOGON,0x5596,0x55b4,UBOGON,0x5585,UBOGON,0x559b,0x55a0,
+    UBOGON,0x5559,UBOGON,0x5586,UBOGON,UBOGON,0x55af,0x557a,UBOGON,UBOGON,
+    UBOGON,0x559e,UBOGON,0x55a9,0x570f,0x570e,0x581a,UBOGON,0x581f,UBOGON,
+    0x583c,0x5818,0x583e,0x5826,UBOGON,0x583a,UBOGON,0x5822,UBOGON,0x58fb,
+    0x5963,0x5964,UBOGON,0x5aa8,0x5aa3,0x5a82,0x5a88,0x5aa1,0x5a85,0x5a98,
+    UBOGON,0x5a99,UBOGON,0x5a89,0x5a81,0x5a96,0x5a80,UBOGON,UBOGON,0x5a91,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x5acf,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x5a87,0x5aa0,UBOGON,0x5a79,UBOGON,0x5a86,0x5aab,0x5aaa,0x5aa4,
+    0x5a8d,0x5a7e,UBOGON,0x5bd5
+  },
+  {				/* ku 1b */
+    UBOGON,UBOGON,UBOGON,0x5c1e,0x5c5f,0x5c5e,0x5d44,0x5d3e,UBOGON,0x5d48,
+    0x5d1c,UBOGON,0x5d5b,0x5d4d,UBOGON,UBOGON,0x5d57,UBOGON,0x5d53,0x5d4f,
+    UBOGON,0x5d3b,0x5d46,UBOGON,UBOGON,0x5e46,0x5e47,UBOGON,0x5e48,0x5ec0,
+    0x5ebd,0x5ebf,UBOGON,0x5f11,UBOGON,0x5f3e,0x5f3b,UBOGON,0x5f3a,UBOGON,
+    UBOGON,UBOGON,0x5fa7,UBOGON,0x60ea,UBOGON,0x6107,0x6122,0x610c,UBOGON,
+    UBOGON,0x60b3,0x60d6,0x60d2,UBOGON,0x60e3,0x60e5,0x60e9,UBOGON,UBOGON,
+    0x6111,0x60fd,UBOGON,UBOGON,0x611e,0x6120,0x6121,0x621e,UBOGON,0x63e2,
+    0x63de,0x63e6,UBOGON,UBOGON,UBOGON,UBOGON,0x63f8,UBOGON,0x63fe,0x63c1,
+    0x63bf,0x63f7,0x63d1,0x655f,0x6560,0x6561,UBOGON,UBOGON,0x65d1,UBOGON,
+    UBOGON,0x667d,0x666b,0x667f
+  },
+  {				/* ku 1c */
+    UBOGON,UBOGON,0x6673,0x6681,0x666d,0x6669,UBOGON,UBOGON,0x671e,0x68ed,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x6903,UBOGON,0x68fe,0x68e5,0x691e,0x6902,
+    UBOGON,UBOGON,0x6909,0x68ca,0x6900,UBOGON,0x6901,0x6918,0x68e2,0x68cf,
+    UBOGON,0x692e,0x68c5,0x68ff,UBOGON,0x691c,0x68c3,UBOGON,0x6b6f,UBOGON,
+    0x6b6e,UBOGON,0x6bbe,UBOGON,0x6bf4,0x6c2d,UBOGON,0x6db6,0x6e75,0x6e1e,
+    UBOGON,0x6e18,UBOGON,0x6e48,UBOGON,0x6e4f,UBOGON,0x6e42,0x6e6a,0x6e70,
+    0x6dfe,UBOGON,UBOGON,0x6e6d,UBOGON,0x6e7b,0x6e7e,0x6e59,UBOGON,0x6e57,
+    UBOGON,0x6e80,0x6e50,UBOGON,0x6e29,0x6e76,0x6e2a,0x6e4c,0x712a,UBOGON,
+    0x7135,0x712c,0x7137,0x711d,UBOGON,UBOGON,0x7138,UBOGON,0x7134,0x712b,
+    0x7133,0x7127,0x7124,UBOGON
+  },
+  {				/* ku 1d */
+    0x712d,0x7232,0x7283,0x7282,0x7287,0x7306,0x7324,0x7338,0x732a,0x732c,
+    0x732b,UBOGON,0x732f,0x7328,0x7417,UBOGON,UBOGON,0x7419,0x7438,UBOGON,
+    0x741f,0x7414,0x743c,0x73f7,0x741c,0x7415,0x7418,0x7439,0x74f9,0x7524,
+    UBOGON,UBOGON,UBOGON,0x756e,0x756d,0x7571,0x758e,UBOGON,0x75e5,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x7694,0x76b3,UBOGON,0x76d9,UBOGON,0x7748,0x7749,
+    0x7743,UBOGON,UBOGON,0x7742,0x77df,UBOGON,0x7863,0x7876,UBOGON,0x785f,
+    0x7866,0x7966,0x7971,UBOGON,UBOGON,0x7976,0x7984,0x7975,0x79ff,0x7a07,
+    UBOGON,0x7a0e,0x7a09,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7ae7,
+    0x7ae2,0x7b55,UBOGON,UBOGON,0x7b43,0x7b57,0x7b6c,0x7b42,0x7b53,UBOGON,
+    0x7b41,UBOGON,UBOGON,0x7ca7
+  },
+  {				/* ku 1e */
+    0x7ca0,0x7ca6,0x7ca4,0x7d74,UBOGON,0x7d59,UBOGON,0x7d60,0x7d57,0x7d6c,
+    0x7d7e,0x7d64,UBOGON,0x7d5a,0x7d5d,UBOGON,UBOGON,UBOGON,0x7d76,0x7d4d,
+    0x7d75,UBOGON,0x7fd3,0x7fd6,UBOGON,UBOGON,0x8060,0x804e,0x8145,0x813b,
+    UBOGON,0x8148,0x8142,0x8149,0x8140,0x8114,0x8141,UBOGON,0x81ef,0x81f6,
+    0x8203,UBOGON,0x83ed,UBOGON,0x83da,0x8418,0x83d2,0x8408,UBOGON,0x8400,
+    UBOGON,UBOGON,UBOGON,0x8417,0x8346,0x8414,0x83d3,0x8405,0x841f,0x8402,
+    0x8416,0x83cd,0x83e6,UBOGON,0x865d,0x86d5,0x86e1,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x86ee,0x8847,0x8846,UBOGON,UBOGON,0x88bb,UBOGON,0x88bf,0x88b4,
+    UBOGON,0x88b5,UBOGON,0x899a,0x8a43,UBOGON,UBOGON,0x8a5a,UBOGON,UBOGON,
+    UBOGON,0x8a35,0x8a38,0x8a42
+  },
+  {				/* ku 1f */
+    0x8a49,0x8a5d,0x8a4b,0x8a3d,UBOGON,UBOGON,UBOGON,UBOGON,0x8c60,0x8c5e,
+    0x8c7f,0x8c7e,0x8c83,UBOGON,0x8cb1,0x8d87,UBOGON,UBOGON,0x8d88,0x8d83,
+    UBOGON,UBOGON,0x8d86,0x8d8b,0x8d82,0x8dca,0x8dd2,UBOGON,UBOGON,0x8dd4,
+    0x8dc9,0x8eb0,UBOGON,UBOGON,UBOGON,0x8ef2,0x8ee4,0x8ef3,0x8eea,UBOGON,
+    0x8efd,UBOGON,0x8f9d,0x902b,0x902a,UBOGON,0x9028,0x9029,0x902c,UBOGON,
+    UBOGON,0x903a,0x9030,0x9037,0x903b,UBOGON,0x910a,UBOGON,UBOGON,UBOGON,
+    0x91fe,0x9220,UBOGON,0x920b,UBOGON,0x9218,0x9222,UBOGON,0x921b,0x9208,
+    UBOGON,0x920e,0x9213,UBOGON,UBOGON,0x9595,UBOGON,UBOGON,UBOGON,0x968c,
+    0x967b,0x967f,0x9681,UBOGON,0x9682,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x96ee,0x96ed,UBOGON,0x96ec
+  },
+  {				/* ku 20 */
+    0x975f,0x976f,UBOGON,0x976d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x98f0,UBOGON,UBOGON,UBOGON,0x9aa9,UBOGON,UBOGON,0x9ae0,0x4eb7,UBOGON,
+    UBOGON,0x50cc,0x50bc,UBOGON,0x50aa,0x50b9,UBOGON,0x50ab,0x50c3,0x50cd,
+    0x517e,0x527e,0x5279,UBOGON,UBOGON,0x52e1,0x52e0,0x52e7,0x5380,0x53ab,
+    0x53aa,0x53a9,0x53e0,0x55ea,UBOGON,0x55d7,UBOGON,UBOGON,0x55c1,0x5715,
+    UBOGON,0x586c,UBOGON,0x585c,0x5850,0x5861,0x586a,0x5869,0x5856,0x5860,
+    0x5866,0x585f,0x5923,0x5966,0x5968,UBOGON,UBOGON,0x5ace,UBOGON,0x5ac5,
+    0x5ac3,UBOGON,UBOGON,0x5ad0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x5b74,0x5b76,0x5bdc,0x5bd7,0x5bda,0x5bdb,UBOGON,0x5c20,0x5d6d,0x5d66,
+    UBOGON,0x5d64,0x5d6e,UBOGON
+  },
+  {				/* ku 21 */
+    0x5d60,0x5f42,0x5f5a,0x5f6e,UBOGON,UBOGON,0x6130,0x613a,0x612a,0x6143,
+    0x6119,0x6131,UBOGON,0x613d,UBOGON,UBOGON,UBOGON,0x6408,0x6432,0x6438,
+    UBOGON,0x6431,UBOGON,0x6419,UBOGON,0x6411,UBOGON,UBOGON,0x6429,0x641d,
+    UBOGON,UBOGON,UBOGON,0x643c,UBOGON,0x6446,0x6447,UBOGON,UBOGON,0x643a,
+    0x6407,UBOGON,0x656b,UBOGON,0x6570,0x656d,UBOGON,0x65e4,0x6693,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x668f,UBOGON,UBOGON,0x6692,UBOGON,0x668e,UBOGON,
+    0x6946,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6931,UBOGON,
+    UBOGON,0x693e,UBOGON,0x697c,0x6943,UBOGON,0x6973,UBOGON,0x6955,UBOGON,
+    UBOGON,0x6985,0x694d,0x6950,0x6947,0x6967,0x6936,0x6964,0x6961,UBOGON,
+    0x697d,0x6b44,0x6b40,0x6b71
+  },
+  {				/* ku 22 */
+    0x6b73,0x6b9c,UBOGON,UBOGON,UBOGON,0x6bc1,UBOGON,0x6bfa,0x6c31,0x6c32,
+    UBOGON,UBOGON,0x6eb8,0x6ea8,UBOGON,0x6e91,0x6ebb,UBOGON,0x6e9a,UBOGON,
+    UBOGON,0x6ea9,UBOGON,UBOGON,0x6eb5,0x6e6c,0x6ee8,UBOGON,0x6edd,0x6eda,
+    0x6ee6,0x6eac,UBOGON,UBOGON,UBOGON,0x6ed9,0x6ee3,0x6ee9,0x6edb,UBOGON,
+    0x716f,UBOGON,UBOGON,0x7148,UBOGON,0x714a,0x716b,UBOGON,0x714f,0x7157,
+    0x7174,UBOGON,UBOGON,UBOGON,0x7145,0x7151,0x716d,UBOGON,0x7251,0x7250,
+    0x724e,UBOGON,0x7341,UBOGON,0x732e,0x7346,UBOGON,0x7427,UBOGON,0x7448,
+    0x7453,0x743d,UBOGON,0x745d,0x7456,UBOGON,0x741e,0x7447,0x7443,0x7458,
+    0x7449,UBOGON,0x744c,0x7445,0x743e,UBOGON,0x7501,0x751e,UBOGON,UBOGON,
+    0x757a,0x75ee,0x7602,0x7697
+  },
+  {				/* ku 23 */
+    0x7698,UBOGON,UBOGON,UBOGON,0x775d,0x7764,0x7753,0x7758,0x7882,0x7890,
+    0x788a,UBOGON,0x787a,0x787d,UBOGON,0x788b,0x7878,UBOGON,UBOGON,0x788d,
+    0x7888,0x7892,0x7881,0x797e,0x7983,UBOGON,UBOGON,UBOGON,0x7980,UBOGON,
+    UBOGON,UBOGON,0x7a0f,UBOGON,UBOGON,0x7a1d,UBOGON,0x7aa1,0x7aa4,UBOGON,
+    0x7ae9,0x7aea,UBOGON,0x7b62,0x7b6b,UBOGON,0x7b5e,UBOGON,0x7b79,UBOGON,
+    UBOGON,0x7b6f,0x7b68,UBOGON,UBOGON,0x7cae,UBOGON,UBOGON,UBOGON,0x7cb0,
+    UBOGON,0x7d90,UBOGON,0x7d8a,UBOGON,0x7d8b,0x7d99,0x7d95,UBOGON,0x7d87,
+    0x7d78,0x7d97,0x7d89,0x7d98,UBOGON,UBOGON,UBOGON,0x7fa3,UBOGON,UBOGON,
+    UBOGON,0x7fdd,0x8057,UBOGON,0x8163,0x816a,0x816c,UBOGON,UBOGON,UBOGON,
+    0x815d,0x8175,UBOGON,0x815f
+  },
+  {				/* ku 24 */
+    UBOGON,0x817d,0x816d,UBOGON,UBOGON,0x8241,0x844f,0x8484,UBOGON,0x847f,
+    UBOGON,0x8448,0x842a,0x847b,0x8472,0x8464,0x842e,0x845c,0x8453,UBOGON,
+    0x8441,0x84c8,UBOGON,0x8462,0x8480,0x843e,0x8483,0x8471,UBOGON,0x844a,
+    0x8455,0x8458,UBOGON,UBOGON,UBOGON,0x86fc,0x86fd,0x8715,UBOGON,0x8716,
+    0x86ff,UBOGON,UBOGON,UBOGON,0x8858,0x88cf,0x88e0,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x89e7,0x8a6a,0x8a80,UBOGON,0x8a6f,0x8a65,UBOGON,0x8a78,0x8a7d,
+    0x8a88,UBOGON,UBOGON,0x8a64,0x8a7e,UBOGON,0x8a67,0x8c63,0x8c88,UBOGON,
+    0x8ccd,UBOGON,0x8cc9,UBOGON,0x8ded,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x8eb1,UBOGON,UBOGON,0x8f04,0x8f9e,0x8fa0,0x9043,0x9046,
+    0x9048,0x9045,0x9040,0x904c
+  },
+  {				/* ku 25 */
+    UBOGON,UBOGON,0x910c,0x9113,0x9115,UBOGON,0x916b,0x9167,0x925d,0x9255,
+    0x9235,UBOGON,0x9259,0x922f,0x923c,0x928f,0x925c,0x926a,0x9262,0x925f,
+    0x926b,0x926e,0x923b,0x9244,0x9241,0x959a,UBOGON,0x9599,UBOGON,UBOGON,
+    UBOGON,0x968f,UBOGON,0x9696,UBOGON,UBOGON,UBOGON,0x96f4,0x96fc,UBOGON,
+    0x9755,UBOGON,0x9779,UBOGON,UBOGON,UBOGON,0x97ee,0x97f5,UBOGON,0x980b,
+    UBOGON,0x98f3,UBOGON,UBOGON,0x98f7,0x98ff,0x98f5,UBOGON,0x98ec,0x98f1,
+    UBOGON,UBOGON,0x999a,UBOGON,0x9ae2,0x9b3d,0x9b5d,0x9ce8,UBOGON,0x9ceb,
+    0x9cef,0x9cee,0x9e81,0x9f14,0x50d0,0x50d9,0x50dc,0x50d8,UBOGON,0x50e1,
+    0x50eb,UBOGON,UBOGON,0x50f4,0x50e2,0x50de,UBOGON,UBOGON,UBOGON,0x51f4,
+    UBOGON,UBOGON,UBOGON,0x52ed
+  },
+  {				/* ku 26 */
+    0x52ea,UBOGON,0x5332,UBOGON,0x53ae,0x53b0,UBOGON,0x55fb,0x5603,0x560b,
+    UBOGON,0x5607,UBOGON,0x55f8,UBOGON,0x5628,0x561e,UBOGON,0x5618,0x5611,
+    0x5651,0x5605,0x5717,0x5892,UBOGON,0x588c,UBOGON,0x5878,0x5884,0x5873,
+    0x58ad,0x5897,0x5895,0x5877,0x5872,0x5896,0x588d,0x5910,UBOGON,0x596c,
+    UBOGON,0x5ae7,UBOGON,0x5ae4,UBOGON,UBOGON,0x5aef,0x5626,UBOGON,UBOGON,
+    0x5af0,0x5d7b,UBOGON,0x5d83,UBOGON,UBOGON,0x5d8b,0x5d8c,UBOGON,0x5d78,
+    0x5e52,UBOGON,UBOGON,0x5ed0,0x5ecf,UBOGON,0x5fb3,0x5fb4,UBOGON,UBOGON,
+    UBOGON,0x617b,UBOGON,0x616f,0x6181,0x613c,0x6142,0x6138,0x6133,UBOGON,
+    0x6160,0x6169,0x617d,0x6186,0x622c,0x6228,UBOGON,0x644c,UBOGON,0x6457,
+    0x647c,UBOGON,UBOGON,0x6455
+  },
+  {				/* ku 27 */
+    0x6462,0x6471,0x646a,0x6456,0x643b,0x6481,UBOGON,0x644f,0x647e,0x6464,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6571,UBOGON,UBOGON,0x66a5,0x669a,
+    0x669c,UBOGON,0x66a6,UBOGON,0x66a4,0x698f,0x69c5,0x69c8,0x6992,0x69b2,
+    UBOGON,UBOGON,UBOGON,0x69e3,0x69c0,0x69d6,0x69d1,0x699f,0x69a2,0x69d2,
+    UBOGON,UBOGON,UBOGON,0x69e1,0x69d5,0x699d,UBOGON,UBOGON,0x6998,UBOGON,
+    0x6b74,0x6ba1,UBOGON,0x6ef0,0x6ef3,UBOGON,UBOGON,0x6f1b,0x6f0c,0x6f1d,
+    0x6f34,0x6f28,0x6f17,UBOGON,0x6f44,0x6f42,0x6f04,0x6f11,0x6efa,0x6f4a,
+    0x7191,0x718e,UBOGON,0x718b,0x718d,0x717f,0x718c,0x717e,0x717c,0x7183,
+    UBOGON,0x7188,UBOGON,UBOGON,0x7294,UBOGON,0x7355,0x7353,0x734f,0x7354,
+    0x746c,0x7465,0x7466,0x7461
+  },
+  {				/* ku 28 */
+    0x746b,0x7468,0x7476,UBOGON,0x7460,UBOGON,0x7474,0x7506,0x760e,UBOGON,
+    0x7607,UBOGON,UBOGON,0x76b9,UBOGON,0x76b7,0x76e2,UBOGON,0x7774,0x7777,
+    0x7776,0x7775,UBOGON,0x7778,0x7771,UBOGON,0x777a,0x715b,0x777b,0x78a6,
+    0x78ae,0x78b8,UBOGON,UBOGON,UBOGON,0x78b1,0x78af,UBOGON,0x7989,0x7987,
+    UBOGON,UBOGON,0x7a29,UBOGON,0x7a2a,UBOGON,0x7a2d,0x7a2c,UBOGON,0x7a32,
+    UBOGON,0x7aec,0x7af0,0x7b81,0x7b9e,0x7b83,UBOGON,0x7b92,UBOGON,0x7ba3,
+    0x7b9f,0x7b93,UBOGON,0x7b86,0x7cb8,0x7cb7,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x7dc8,0x7db6,UBOGON,0x7dd1,UBOGON,0x7da8,0x7dab,UBOGON,0x7db3,
+    0x7dcd,UBOGON,0x7dcf,0x7da4,UBOGON,UBOGON,0x7f41,0x7f6f,0x7f71,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 29 */
+    UBOGON,0x8023,0x805b,UBOGON,0x8061,0x805f,0x8181,UBOGON,UBOGON,0x8184,
+    0x8213,UBOGON,0x824a,0x824c,UBOGON,UBOGON,UBOGON,0x84bd,0x8495,UBOGON,
+    0x8492,0x84c3,UBOGON,0x8496,0x84a5,0x84b5,0x84b3,0x84a3,0x84e4,0x84d8,
+    0x84d5,UBOGON,0x84b7,0x84ad,0x84da,0x8493,0x8736,UBOGON,UBOGON,UBOGON,
+    0x873d,0x872b,0x8747,0x8739,UBOGON,0x8745,0x871d,UBOGON,0x88ff,0x88ea,
+    UBOGON,0x88f5,UBOGON,0x8900,0x88ed,0x8903,0x88e9,UBOGON,UBOGON,0x89ea,
+    UBOGON,0x8a9b,0x8a8e,0x8aa2,UBOGON,0x8a9c,0x8a94,0x8a90,0x8aa9,0x8aac,
+    UBOGON,0x8a9f,UBOGON,UBOGON,0x8a9d,UBOGON,0x8c67,UBOGON,UBOGON,0x8cd0,
+    0x8cd6,0x8cd4,0x8d98,0x8d9a,0x8d97,UBOGON,UBOGON,UBOGON,0x8e0b,0x8e08,
+    0x8e01,0x8eb4,0x8eb3,UBOGON
+  },
+  {				/* ku 2a */
+    0x8fa1,0x8fa2,UBOGON,0x905a,UBOGON,0x9061,0x905f,UBOGON,UBOGON,0x9125,
+    0x917b,0x9176,0x917c,UBOGON,0x9289,0x92f6,0x92b1,0x92ad,0x9292,0x9281,
+    0x9284,UBOGON,0x92ae,0x9290,0x929e,UBOGON,UBOGON,UBOGON,0x95a2,0x95a7,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x96a0,0x969d,0x969f,0x96d0,UBOGON,
+    0x96d1,UBOGON,UBOGON,0x9759,UBOGON,0x9764,UBOGON,UBOGON,UBOGON,0x9819,
+    UBOGON,0x9814,0x9815,0x981a,UBOGON,UBOGON,UBOGON,UBOGON,0x9906,UBOGON,
+    0x98f8,0x9901,UBOGON,0x99be,0x99bc,0x99b7,0x99b6,0x99c0,UBOGON,0x99b8,
+    UBOGON,UBOGON,UBOGON,0x99c4,UBOGON,0x99bf,UBOGON,0x9ada,0x9ae4,0x9ae9,
+    0x9ae8,0x9aea,0x9ae5,UBOGON,0x9b26,UBOGON,UBOGON,0x9b40,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2b */
+    UBOGON,0x9ebd,UBOGON,UBOGON,UBOGON,UBOGON,0x510e,UBOGON,0x50f7,UBOGON,
+    0x50fc,0x510d,0x5101,0x51da,0x51d9,0x51db,0x5286,0x528e,0x52ee,0x5333,
+    0x53b1,UBOGON,0x5647,0x562d,0x5654,UBOGON,0x564b,0x5652,0x5631,0x5644,
+    0x5656,0x5650,0x562b,UBOGON,0x564d,0x5637,0x564f,0x58a2,0x58b7,UBOGON,
+    0x58b2,UBOGON,0x58aa,0x58b5,0x58b0,UBOGON,0x58b4,0x58a4,0x58a7,UBOGON,
+    0x5926,0x5afe,UBOGON,0x5b04,UBOGON,0x5afc,UBOGON,0x5b06,0x5b0a,0x5afa,
+    0x5b0d,0x5b00,0x5b0e,UBOGON,UBOGON,UBOGON,0x5d91,UBOGON,0x5d8f,0x5d90,
+    0x5d98,0x5da4,0x5d9b,0x5da3,0x5d96,0x5de4,0x5e5a,UBOGON,UBOGON,0x5e5e,
+    UBOGON,0x5fb8,0x6157,0x615c,0x61a6,0x6195,0x6188,UBOGON,0x61a3,0x618f,
+    UBOGON,0x6164,UBOGON,0x6159
+  },
+  {				/* ku 2c */
+    0x6178,UBOGON,0x6185,0x6187,0x619e,UBOGON,UBOGON,0x6198,0x619c,UBOGON,
+    UBOGON,0x622f,0x6480,0x649b,0x648e,0x648d,0x6494,0x64c6,UBOGON,0x64a8,
+    0x6483,UBOGON,0x64b9,0x6486,0x64b4,0x64af,0x6491,UBOGON,0x64aa,0x64a1,
+    0x64a7,0x66b6,0x66b3,UBOGON,0x66bc,0x66ac,UBOGON,0x66ad,0x6a0e,UBOGON,
+    0x6a1c,0x6a1a,UBOGON,UBOGON,0x6a0b,UBOGON,0x69ef,0x6a0c,0x69f0,0x6a22,
+    UBOGON,0x69d8,UBOGON,0x6a12,0x69fa,UBOGON,0x6a2a,UBOGON,0x6a10,UBOGON,
+    UBOGON,0x6a29,0x69f9,0x69ea,0x6a2c,0x6a24,UBOGON,0x69e9,0x6b52,0x6b4f,
+    0x6b53,UBOGON,UBOGON,0x6f10,0x6f65,0x6f75,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x6fd0,UBOGON,0x6f5c,0x6f3d,0x6f71,UBOGON,0x6f91,0x6f0b,0x6f79,0x6f81,
+    0x6f8f,UBOGON,0x6f59,0x6f74
+  },
+  {				/* ku 2d */
+    UBOGON,0x71ae,UBOGON,0x71a3,0x71ad,UBOGON,UBOGON,0x71ab,0x71a6,0x71a2,
+    UBOGON,0x52f2,0x7257,0x7255,0x7299,0x734b,0x747a,UBOGON,UBOGON,UBOGON,
+    0x748c,0x7484,UBOGON,UBOGON,0x7482,0x7493,0x747b,UBOGON,0x7509,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x778a,UBOGON,0x7790,UBOGON,0x78c6,
+    0x78d3,0x78c0,0x78d2,0x78c7,0x78c2,UBOGON,0x799f,0x799d,0x799e,UBOGON,
+    0x7a41,UBOGON,0x7a38,0x7a3a,0x7a42,UBOGON,UBOGON,0x7a3e,0x7ab0,0x7bae,
+    0x7bb3,UBOGON,UBOGON,0x7bbf,UBOGON,UBOGON,0x7bcd,UBOGON,0x7bb2,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7cc4,0x7ccd,0x7cc2,0x7cc6,
+    0x7cc3,0x7cc9,0x7cc7,UBOGON,0x7df8,UBOGON,0x7ded,0x7de2,UBOGON,UBOGON,
+    UBOGON,0x7ddc,0x7e02,0x7e01
+  },
+  {				/* ku 2e */
+    UBOGON,0x7dd6,UBOGON,0x7de4,0x7dfe,UBOGON,0x7e00,0x7dfc,0x7dfd,UBOGON,
+    0x7df5,0x7dff,UBOGON,0x7deb,0x7de5,0x7f78,0x7fae,0x7fe7,UBOGON,0x8065,
+    0x806a,0x8066,0x8068,0x806b,0x8194,0x81a1,0x8192,0x8196,0x8193,UBOGON,
+    UBOGON,0x8501,UBOGON,0x84f8,UBOGON,0x84f5,UBOGON,0x8504,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x851b,0x8503,0x8533,0x8534,0x84ed,UBOGON,UBOGON,0x8535,
+    UBOGON,0x8505,UBOGON,UBOGON,UBOGON,UBOGON,0x877d,UBOGON,UBOGON,UBOGON,
+    0x8771,UBOGON,0x885c,0x88e6,0x890f,0x891b,UBOGON,0x89a9,0x89a5,0x89ee,
+    0x8ab1,UBOGON,0x8acc,0x8ace,UBOGON,0x8ab7,UBOGON,0x8ab5,0x8ae9,0x8ab4,
+    UBOGON,0x8ab3,0x8ac1,0x8aaf,0x8aca,0x8ad0,UBOGON,UBOGON,UBOGON,0x8c8e,
+    UBOGON,UBOGON,0x8ce9,0x8cdb
+  },
+  {				/* ku 2f */
+    UBOGON,0x8ceb,0x8da4,UBOGON,0x8da2,0x8d9d,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x8e2a,0x8e28,UBOGON,UBOGON,0x8eb8,0x8eb6,0x8eb9,0x8eb7,0x8f22,0x8f2b,
+    0x8f27,0x8f19,0x8fa4,UBOGON,0x8fb3,UBOGON,0x9071,0x906a,UBOGON,UBOGON,
+    0x9188,0x918c,0x92bf,0x92b8,0x92be,0x92dc,0x92e5,UBOGON,UBOGON,0x92d4,
+    0x92d6,UBOGON,0x92da,0x92ed,0x92f3,0x92db,UBOGON,0x92b9,0x92e2,0x92eb,
+    0x95af,UBOGON,0x95b2,0x95b3,UBOGON,UBOGON,UBOGON,0x96a3,0x96a5,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x970a,UBOGON,0x9787,0x9789,0x978c,0x97ef,0x982a,
+    0x9822,UBOGON,0x981f,UBOGON,0x9919,UBOGON,0x99ca,0x99da,UBOGON,UBOGON,
+    UBOGON,0x99de,0x99c8,0x99e0,UBOGON,0x9ab6,0x9ab5,UBOGON,0x9af4,UBOGON,
+    0x9b6b,0x9b69,0x9b72,0x9b63
+  },
+  {				/* ku 30 */
+    UBOGON,0x9d0d,UBOGON,0x9d01,0x9d0c,UBOGON,0x9cf8,UBOGON,UBOGON,0x9cfe,
+    0x9d02,0x9e84,UBOGON,0x9eab,0x9eaa,0x511d,0x5116,UBOGON,0x512b,0x511e,
+    0x511b,0x5290,0x5294,0x5314,UBOGON,UBOGON,0x5667,UBOGON,0x567b,UBOGON,
+    0x565f,0x5661,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x58c3,
+    0x58ca,0x58bb,0x58c0,0x58c4,0x5901,0x5b1f,0x5b18,0x5b11,0x5b15,UBOGON,
+    0x5b12,0x5b1c,UBOGON,0x5b22,0x5b79,0x5da6,UBOGON,0x5db3,0x5dab,0x5eea,
+    UBOGON,0x5f5b,UBOGON,UBOGON,0x61b7,0x61ce,0x61b9,0x61bd,0x61cf,0x61c0,
+    0x6199,0x6197,UBOGON,0x61bb,0x61d0,0x61c4,0x6231,UBOGON,0x64d3,0x64c0,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x64dc,0x64d1,0x64c8,UBOGON,0x64d5,0x66c3,
+    UBOGON,UBOGON,0x66bf,0x66c5
+  },
+  {				/* ku 31 */
+    UBOGON,0x66cd,0x66c1,0x6706,UBOGON,0x6724,0x6a63,0x6a42,0x6a52,UBOGON,
+    0x6a43,0x6a33,UBOGON,0x6a6c,0x6a57,UBOGON,0x6a4c,0x6a6e,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x6a37,UBOGON,0x6a71,0x6a4a,0x6a36,UBOGON,0x6a53,
+    UBOGON,0x6a45,0x6a70,UBOGON,UBOGON,0x6a5c,0x6b58,0x6b57,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x6fbb,UBOGON,UBOGON,0x6fbe,UBOGON,UBOGON,
+    UBOGON,0x6fb5,0x6fd3,0x6f9f,UBOGON,0x6fb7,0x6ff5,0x71b7,UBOGON,0x71bb,
+    UBOGON,0x71d1,UBOGON,0x71ba,UBOGON,0x71b6,0x71cc,UBOGON,UBOGON,0x71d3,
+    0x749b,UBOGON,UBOGON,0x7496,0x74a2,0x749d,0x750a,0x750e,UBOGON,0x7581,
+    0x762c,0x7637,0x7636,0x763b,UBOGON,0x76a1,UBOGON,UBOGON,0x7798,UBOGON,
+    0x7796,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 32 */
+    0x78d6,0x78eb,UBOGON,0x78dc,UBOGON,0x79a5,0x79a9,0x9834,0x7a53,0x7a45,
+    UBOGON,0x7a4f,UBOGON,0x7abd,0x7abb,0x7af1,UBOGON,UBOGON,0x7bec,0x7bed,
+    UBOGON,UBOGON,0x7cd3,UBOGON,0x7ce1,UBOGON,0x7e19,UBOGON,UBOGON,UBOGON,
+    0x7e27,0x7e26,UBOGON,UBOGON,0x806e,0x81af,UBOGON,UBOGON,0x81ad,UBOGON,
+    0x81aa,0x8218,UBOGON,UBOGON,UBOGON,UBOGON,0x856f,0x854c,UBOGON,0x8542,
+    UBOGON,0x855c,0x8570,0x855f,UBOGON,0x855a,0x854b,0x853f,0x878a,UBOGON,
+    0x878b,0x87a1,0x878e,UBOGON,UBOGON,0x8799,0x885e,0x885f,0x8924,0x89a7,
+    0x8aea,0x8afd,0x8af9,0x8ae3,0x8ae5,UBOGON,UBOGON,0x8aec,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x8cf2,UBOGON,0x8cef,UBOGON,0x8da6,UBOGON,UBOGON,UBOGON,
+    0x8e3b,0x8e43,UBOGON,0x8e32
+  },
+  {				/* ku 33 */
+    0x8f31,0x8f30,UBOGON,0x8f2d,0x8f3c,0x8fa7,0x8fa5,UBOGON,UBOGON,UBOGON,
+    0x9137,0x9195,0x918e,UBOGON,0x9196,UBOGON,0x9345,0x930a,UBOGON,UBOGON,
+    0x92fd,0x9317,0x931c,0x9307,0x9331,0x9332,0x932c,0x9330,0x9303,0x9305,
+    UBOGON,0x95c2,UBOGON,0x95b8,UBOGON,0x95c1,UBOGON,UBOGON,UBOGON,0x96ab,
+    0x96b7,UBOGON,UBOGON,0x9715,0x9714,UBOGON,UBOGON,0x970c,0x9717,UBOGON,
+    0x9793,UBOGON,0x97d2,UBOGON,UBOGON,0x9836,0x9831,0x9833,0x983c,0x982e,
+    0x983a,UBOGON,0x983d,UBOGON,0x98b5,0x9922,0x9923,0x9920,0x991c,0x991d,
+    UBOGON,0x99a0,UBOGON,0x99ef,0x99e8,0x99eb,UBOGON,UBOGON,UBOGON,0x99e1,
+    0x99e6,UBOGON,UBOGON,0x9af8,0x9af5,UBOGON,UBOGON,0x9b83,0x9b94,0x9b84,
+    UBOGON,0x9b8b,0x9b8f,UBOGON
+  },
+  {				/* ku 34 */
+    0x9b8c,UBOGON,0x9b89,UBOGON,0x9b8e,UBOGON,UBOGON,UBOGON,0x9d24,0x9d0f,
+    UBOGON,0x9d13,0x9d0a,UBOGON,UBOGON,UBOGON,UBOGON,0x9d2a,0x9d1a,UBOGON,
+    0x9d27,0x9d16,0x9d21,UBOGON,0x9e85,0x9eac,0x9ec6,0x9ec5,0x9ed7,0x9f53,
+    UBOGON,0x5128,0x5127,0x51df,UBOGON,0x5335,0x53b3,UBOGON,0x568a,0x567d,
+    0x5689,UBOGON,0x58cd,0x58d0,UBOGON,0x5b2b,0x5b33,0x5b29,0x5b35,0x5b31,
+    0x5b37,0x5c36,0x5dbe,UBOGON,0x5db9,UBOGON,0x5dbb,UBOGON,0x61e2,0x61db,
+    0x61dd,0x61dc,0x61da,UBOGON,0x61d9,UBOGON,UBOGON,0x64df,UBOGON,UBOGON,
+    0x64e1,UBOGON,0x64ee,UBOGON,0x65b5,0x66d4,0x66d5,UBOGON,0x66d0,0x66d1,
+    0x66ce,0x66d7,UBOGON,UBOGON,0x6a7d,0x6a8a,UBOGON,0x6aa7,UBOGON,0x6a99,
+    0x6a82,0x6a88,UBOGON,UBOGON
+  },
+  {				/* ku 35 */
+    0x6a86,UBOGON,0x6a98,0x6a9d,UBOGON,UBOGON,0x6a8f,UBOGON,0x6aaa,UBOGON,
+    0x6b5d,UBOGON,0x6c0a,UBOGON,0x6fd7,0x6fd6,0x6fe5,UBOGON,UBOGON,UBOGON,
+    0x6fd9,0x6fda,0x6fea,UBOGON,0x6ff6,UBOGON,UBOGON,0x71e3,UBOGON,0x71e9,
+    UBOGON,0x71eb,0x71ef,0x71f3,0x71ea,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x7371,UBOGON,0x74ae,UBOGON,0x74b3,UBOGON,0x74ac,UBOGON,UBOGON,0x7583,
+    0x7645,0x764e,0x7644,0x76a3,0x76a5,0x77a6,0x77a4,UBOGON,0x77a9,0x77af,
+    UBOGON,UBOGON,UBOGON,0x78f0,0x78f8,0x78f1,UBOGON,0x7a49,UBOGON,UBOGON,
+    UBOGON,0x7ac2,0x7af2,0x7af3,0x7bfa,UBOGON,0x7bf6,0x7bfc,0x7c18,0x7c08,
+    0x7c12,UBOGON,UBOGON,0x7cdb,0x7cda,UBOGON,UBOGON,UBOGON,0x7e2c,0x7e4d,
+    UBOGON,UBOGON,0x7f46,0x7ff6
+  },
+  {				/* ku 36 */
+    0x802b,0x8074,0x81b8,0x81c8,UBOGON,UBOGON,UBOGON,0x8592,0x8593,UBOGON,
+    0x857f,0x85ab,0x8597,UBOGON,UBOGON,0x85ac,UBOGON,UBOGON,UBOGON,0x87ce,
+    UBOGON,0x87cd,UBOGON,UBOGON,0x87c1,0x87b1,0x87c7,UBOGON,0x8940,UBOGON,
+    0x893f,0x8939,UBOGON,0x8943,UBOGON,UBOGON,UBOGON,0x89ab,UBOGON,0x8b1f,
+    0x8b09,0x8b0c,UBOGON,UBOGON,0x8c40,UBOGON,0x8c96,UBOGON,0x8cf6,0x8cf7,
+    UBOGON,0x8e46,0x8e4f,UBOGON,UBOGON,UBOGON,0x8f3d,0x8f41,0x9366,0x9378,
+    0x935d,0x9369,0x9374,0x937d,0x936e,0x9372,0x9373,0x9362,0x9348,0x9353,
+    0x935f,0x9368,UBOGON,0x937f,0x936b,UBOGON,0x95c4,UBOGON,0x96af,0x96ad,
+    0x96b2,UBOGON,UBOGON,0x971a,0x971b,UBOGON,UBOGON,UBOGON,UBOGON,0x979b,
+    0x979f,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 37 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9840,UBOGON,0x9847,UBOGON,0x98b7,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x99a2,UBOGON,UBOGON,0x9a00,0x99f3,
+    UBOGON,UBOGON,0x99f5,UBOGON,UBOGON,0x9abd,0x9b00,0x9b02,UBOGON,0x9b34,
+    0x9b49,0x9b9f,UBOGON,0x9ba3,0x9bcd,0x9b99,0x9b9d,UBOGON,UBOGON,0x9d39,
+    UBOGON,0x9d44,UBOGON,UBOGON,0x9d35,UBOGON,UBOGON,0x9eaf,UBOGON,0x512f,
+    UBOGON,UBOGON,0x9f8e,UBOGON,0x569f,0x569b,0x569e,0x5696,0x5694,0x56a0,
+    UBOGON,0x5b3b,UBOGON,UBOGON,0x5b3a,0x5dc1,0x5f4d,0x5f5d,0x61f3,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x64f6,0x64e5,0x64ea,0x64e7,0x6505,UBOGON,0x64f9,
+    UBOGON,UBOGON,UBOGON,0x6aab,0x6aed,0x6ab2,0x6ab0,0x6ab5,0x6abe,0x6ac1,
+    0x6ac8,UBOGON,0x6ac0,0x6abc
+  },
+  {				/* ku 38 */
+    0x6ab1,0x6ac4,0x6abf,UBOGON,UBOGON,0x7008,0x7003,0x6ffd,0x7010,0x7002,
+    0x7013,UBOGON,0x71fa,0x7200,0x74b9,0x74bc,UBOGON,0x765b,0x7651,0x764f,
+    0x76eb,0x77b8,UBOGON,0x77b9,0x77c1,0x77c0,0x77be,0x790b,UBOGON,0x7907,
+    0x790a,0x7908,UBOGON,0x790d,0x7906,0x7915,0x79af,UBOGON,UBOGON,UBOGON,
+    0x7af5,UBOGON,UBOGON,0x7c2e,UBOGON,0x7c1b,UBOGON,0x7c1a,0x7c24,UBOGON,
+    UBOGON,0x7ce6,0x7ce3,UBOGON,UBOGON,0x7e5d,0x7e4f,0x7e66,0x7e5b,0x7f47,
+    0x7fb4,UBOGON,UBOGON,UBOGON,0x7ffa,0x802e,UBOGON,UBOGON,0x81ce,UBOGON,
+    UBOGON,0x8219,UBOGON,UBOGON,0x85cc,0x85b2,UBOGON,0x85bb,0x85c1,UBOGON,
+    UBOGON,UBOGON,0x87e9,0x87ee,0x87f0,0x87d6,0x880e,0x87da,0x8948,0x894a,
+    0x894e,0x894d,0x89b1,0x89b0
+  },
+  {				/* ku 39 */
+    0x89b3,UBOGON,0x8b38,0x8b32,UBOGON,0x8b2d,UBOGON,0x8b34,UBOGON,0x8b29,
+    0x8c74,UBOGON,UBOGON,0x8d03,UBOGON,UBOGON,0x8da9,0x8e58,UBOGON,UBOGON,
+    0x8ebf,0x8ec1,0x8f4a,0x8fac,UBOGON,0x9089,0x913d,0x913c,0x91a9,0x93a0,
+    UBOGON,0x9390,UBOGON,0x9393,0x938b,0x93ad,0x93bb,0x93b8,UBOGON,UBOGON,
+    0x939c,0x95d8,0x95d7,UBOGON,UBOGON,UBOGON,0x975d,0x97a9,0x97da,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x9854,UBOGON,0x9855,0x984b,UBOGON,0x983f,0x98b9,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x9938,0x9936,0x9940,UBOGON,0x993b,0x9939,
+    0x99a4,UBOGON,UBOGON,0x9a08,0x9a0c,UBOGON,0x9a10,UBOGON,0x9b07,UBOGON,
+    0x9bd2,UBOGON,0x9bc2,0x9bbb,0x9bcc,0x9bcb,UBOGON,UBOGON,0x9d4d,0x9d63,
+    0x9d4e,UBOGON,0x9d50,0x9d55
+  },
+  {				/* ku 3a */
+    UBOGON,0x9d5e,UBOGON,0x9e90,0x9eb2,0x9eb1,UBOGON,0x9eca,0x9f02,0x9f27,
+    0x9f26,UBOGON,0x56af,0x58e0,0x58dc,UBOGON,0x5b39,UBOGON,UBOGON,0x5b7c,
+    0x5bf3,UBOGON,UBOGON,0x5c6b,0x5dc4,0x650b,0x6508,0x650a,UBOGON,UBOGON,
+    0x65dc,UBOGON,UBOGON,0x66e1,0x66df,0x6ace,0x6ad4,0x6ae3,0x6ad7,0x6ae2,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x6ad8,0x6ad5,0x6ad2,UBOGON,UBOGON,0x701e,
+    0x702c,0x7025,0x6ff3,0x7204,0x7208,0x7215,UBOGON,0x74c4,0x74c9,0x74c7,
+    0x74c8,0x76a9,0x77c6,0x77c5,0x7918,0x791a,0x7920,UBOGON,0x7a66,0x7a64,
+    0x7a6a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7c35,0x7c34,UBOGON,
+    UBOGON,0x7e6c,UBOGON,0x7e6e,0x7e71,UBOGON,0x81d4,0x81d6,0x821a,0x8262,
+    0x8265,0x8276,0x85db,0x85d6
+  },
+  {				/* ku 3b */
+    UBOGON,0x85e7,UBOGON,UBOGON,0x85f4,UBOGON,0x87fd,0x87d5,0x8807,UBOGON,
+    0x880f,0x87f8,UBOGON,UBOGON,0x8987,UBOGON,0x89b5,0x89f5,UBOGON,0x8b3f,
+    0x8b43,0x8b4c,UBOGON,0x8d0b,0x8e6b,0x8e68,0x8e70,0x8e75,0x8e77,UBOGON,
+    0x8ec3,UBOGON,0x93e9,0x93ea,0x93cb,0x93c5,0x93c6,UBOGON,0x93ed,0x93d3,
+    UBOGON,0x93e5,UBOGON,UBOGON,0x93db,0x93eb,0x93e0,0x93c1,UBOGON,UBOGON,
+    0x95dd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x97b2,0x97b4,0x97b1,0x97b5,0x97f2,UBOGON,UBOGON,UBOGON,0x9856,UBOGON,
+    UBOGON,UBOGON,0x9944,UBOGON,0x9a26,0x9a1f,0x9a18,0x9a21,0x9a17,UBOGON,
+    0x9b09,UBOGON,UBOGON,0x9bc5,0x9bdf,UBOGON,0x9be3,UBOGON,0x9be9,0x9bee,
+    UBOGON,UBOGON,0x9d66,0x9d7a
+  },
+  {				/* ku 3c */
+    UBOGON,0x9d6e,0x9d91,0x9d83,0x9d76,0x9d7e,0x9d6d,UBOGON,0x9e95,0x9ee3,
+    UBOGON,UBOGON,0x9f03,0x9f04,UBOGON,0x9f17,UBOGON,0x5136,UBOGON,0x5336,
+    UBOGON,0x5b42,UBOGON,UBOGON,0x5b44,0x5b46,0x5b7e,0x5dca,0x5dc8,0x5dcc,
+    0x5ef0,UBOGON,0x6585,0x66e5,0x66e7,UBOGON,UBOGON,UBOGON,0x6af4,UBOGON,
+    0x6ae9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x703d,UBOGON,0x7036,UBOGON,
+    0x7216,UBOGON,0x7212,0x720f,0x7217,0x7211,0x720b,UBOGON,UBOGON,0x74cd,
+    0x74d0,0x74cc,0x74ce,0x74d1,UBOGON,0x7589,UBOGON,0x7a6f,0x7c4b,0x7c44,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7e7f,0x8b71,UBOGON,0x802f,0x807a,
+    0x807b,0x807c,UBOGON,UBOGON,UBOGON,0x85fc,0x8610,0x8602,UBOGON,UBOGON,
+    0x85ee,0x8603,UBOGON,0x860d
+  },
+  {				/* ku 3d */
+    0x8613,0x8608,0x860f,0x8818,0x8812,UBOGON,UBOGON,0x8967,0x8965,0x89bb,
+    0x8b69,0x8b62,UBOGON,0x8b6e,UBOGON,0x8b61,UBOGON,0x8b64,0x8b4d,0x8c51,
+    UBOGON,UBOGON,0x8e83,0x8ec6,UBOGON,0x941f,UBOGON,0x9404,0x9417,0x9408,
+    0x9405,UBOGON,0x93f3,0x941e,0x9402,0x941a,0x941b,0x9427,0x941c,UBOGON,
+    0x96b5,UBOGON,UBOGON,0x9733,UBOGON,0x9734,0x9731,0x97b8,0x97ba,UBOGON,
+    0x97fc,UBOGON,UBOGON,0x98c3,UBOGON,0x994d,UBOGON,0x9a2f,UBOGON,UBOGON,
+    UBOGON,0x9ac9,UBOGON,0x9ac8,0x9ac4,0x9b2a,0x9b38,0x9b50,UBOGON,0x9c0a,
+    0x9bfb,0x9c04,0x9bfc,0x9bfe,UBOGON,UBOGON,UBOGON,0x9c02,0x9bf6,0x9c1b,
+    0x9bf9,0x9c15,0x9c10,0x9bff,0x9c00,0x9c0c,UBOGON,UBOGON,0x9d95,0x9da5,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 3e */
+    0x9e98,0x9ec1,UBOGON,0x9f5a,0x5164,0x56bb,UBOGON,0x58e6,0x5b49,0x5bf7,
+    UBOGON,UBOGON,0x5dd0,UBOGON,0x5fc2,UBOGON,0x6511,UBOGON,0x6aff,0x6afe,
+    0x6afd,UBOGON,0x6b01,UBOGON,UBOGON,0x704b,0x704d,0x7047,0x74d3,0x7668,
+    0x7667,UBOGON,UBOGON,0x77d1,0x7930,0x7932,0x792e,UBOGON,0x9f9d,0x7ac9,
+    0x7ac8,UBOGON,0x7c56,0x7c51,UBOGON,UBOGON,UBOGON,0x7e85,0x7e89,0x7e8e,
+    0x7e84,UBOGON,0x826a,0x862b,0x862f,0x8628,UBOGON,0x8616,0x8615,0x861d,
+    0x881a,UBOGON,UBOGON,UBOGON,0x89bc,0x8b75,0x8b7c,UBOGON,0x8d11,0x8d12,
+    0x8f5c,0x91bb,UBOGON,0x93f4,UBOGON,UBOGON,0x942d,UBOGON,UBOGON,0x96e4,
+    0x9737,0x9736,0x9767,0x97be,0x97bd,0x97e2,0x9868,0x9866,0x98c8,0x98ca,
+    0x98c7,0x98dc,UBOGON,0x994f
+  },
+  {				/* ku 3f */
+    0x99a9,0x9a3c,UBOGON,0x9a3b,0x9ace,UBOGON,0x9b14,0x9b53,UBOGON,0x9c2e,
+    UBOGON,0x9c1f,UBOGON,UBOGON,UBOGON,UBOGON,0x9db0,0x9dbd,UBOGON,UBOGON,
+    0x9dae,0x9dc4,0x9e7b,UBOGON,UBOGON,0x9e9e,UBOGON,0x9f05,UBOGON,0x9f69,
+    0x9fa1,0x56c7,0x571d,0x5b4a,0x5dd3,UBOGON,0x5f72,0x6202,UBOGON,0x6235,
+    0x6527,0x651e,0x651f,UBOGON,UBOGON,0x6b07,0x6b06,UBOGON,UBOGON,0x7054,
+    0x721c,0x7220,0x7af8,UBOGON,0x7c5d,0x7c58,UBOGON,0x7e92,0x7f4e,UBOGON,
+    UBOGON,UBOGON,0x8827,UBOGON,0x8b81,0x8b83,UBOGON,0x8c44,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x9442,0x944d,0x9454,0x944e,UBOGON,0x9443,UBOGON,UBOGON,
+    0x973c,0x9740,0x97c0,UBOGON,UBOGON,UBOGON,UBOGON,0x995a,0x9a51,UBOGON,
+    0x9add,UBOGON,UBOGON,0x9c38
+  },
+  {				/* ku 40 */
+    UBOGON,0x9c45,0x9c3a,UBOGON,0x9c35,UBOGON,UBOGON,UBOGON,0x9ef1,UBOGON,
+    0x9f93,0x529a,UBOGON,UBOGON,0x8641,0x5dd7,UBOGON,0x6528,UBOGON,UBOGON,
+    UBOGON,0x7053,0x7059,UBOGON,0x7221,UBOGON,0x766f,0x7937,0x79b5,0x7c62,
+    0x7c5e,0x7cf5,UBOGON,UBOGON,0x863d,UBOGON,0x882d,0x8989,0x8b8d,0x8b87,
+    0x8b90,0x8d1a,0x8e99,UBOGON,UBOGON,UBOGON,0x945f,UBOGON,UBOGON,0x9456,
+    0x9461,0x945b,0x945a,0x945c,0x9465,UBOGON,0x9741,UBOGON,UBOGON,0x986e,
+    0x986c,0x986d,UBOGON,0x99aa,0x9a5c,0x9a58,0x9ade,UBOGON,0x9c4f,0x9c51,
+    UBOGON,0x9c53,UBOGON,UBOGON,UBOGON,0x9dfc,0x9f39,UBOGON,0x513e,UBOGON,
+    0x56d2,UBOGON,0x5b4f,0x6b14,UBOGON,0x7a72,0x7a73,UBOGON,UBOGON,UBOGON,
+    0x8b91,UBOGON,UBOGON,0x91bf
+  },
+  {				/* ku 41 */
+    UBOGON,0x946c,UBOGON,UBOGON,0x96e6,0x9745,UBOGON,0x97c8,0x97e4,0x995d,
+    UBOGON,0x9b21,UBOGON,0x9b2c,0x9b57,UBOGON,UBOGON,0x9c5d,0x9c61,0x9c65,
+    0x9e08,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9f45,UBOGON,UBOGON,0x6205,
+    0x66ef,0x6b1b,0x6b1d,0x7225,0x7224,0x7c6d,UBOGON,0x8642,0x8649,UBOGON,
+    0x8978,0x898a,0x8b97,UBOGON,0x8c9b,0x8d1c,UBOGON,0x8ea2,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9c6c,UBOGON,0x9c6f,UBOGON,
+    0x9e0e,UBOGON,0x9f08,0x9f1d,0x9fa3,UBOGON,UBOGON,0x5f60,0x6b1c,UBOGON,
+    UBOGON,UBOGON,0x7cf3,UBOGON,0x8b9b,0x8ea7,0x91c4,UBOGON,0x947a,UBOGON,
+    UBOGON,0x9a61,0x9a63,0x9ad7,0x9c76,UBOGON,0x9fa5,UBOGON,0x7067,UBOGON,
+    0x72ab,0x864a,0x897d,0x8b9d
+  },
+  {				/* ku 42 */
+    0x8c53,0x8f65,0x947b,UBOGON,0x98cd,0x98dd,UBOGON,0x9b30,0x9e16,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x96e7,0x9e18,0x9ea2,UBOGON,0x9f7c,UBOGON,
+    0x7e9e,0x9484,UBOGON,0x9e1c,UBOGON,0x7c71,0x97ca,UBOGON,UBOGON,UBOGON,
+    0x9ea3,UBOGON,0x9c7b,0x9f97,UBOGON,UBOGON,0x9750,UBOGON,UBOGON,UBOGON,
+    0x5727,0x5c13,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5fc8,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x6765,UBOGON,UBOGON,0x52bd,UBOGON,0x5b66,
+    UBOGON,0x65f9,0x6788,0x6ce6,0x6ccb,UBOGON,0x4fbd,0x5f8d,UBOGON,0x6018,
+    0x6048,UBOGON,0x6b29,0x70a6,UBOGON,0x7706,UBOGON,UBOGON,UBOGON,0x5a10,
+    0x5cfc,0x5cfe,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x70c9,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 43 */
+    UBOGON,UBOGON,0x9579,UBOGON,0x96ba,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x7b29,0x8128,UBOGON,0x8a2e,UBOGON,UBOGON,UBOGON,0x9ad9,
+    UBOGON,0x582b,0x5845,UBOGON,0x63fa,UBOGON,UBOGON,UBOGON,0x6e86,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x5867,UBOGON,0x5bdd,0x656e,UBOGON,UBOGON,
+    UBOGON,0x8c87,UBOGON,0x50d2,0x50df,UBOGON,UBOGON,UBOGON,UBOGON,0x69ba,
+    UBOGON,0x6b9d,UBOGON,0x8059,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6f8a,UBOGON,UBOGON,0x7bc3,
+    0x7bc2,UBOGON,UBOGON,UBOGON,UBOGON,0x90f6,UBOGON,0x9823,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x71cd,0x7499,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x9842,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 44 */
+    UBOGON,0x7f84,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8d0e,UBOGON,0x9861,
+    UBOGON,UBOGON,0x8b73,UBOGON,0x9c27,UBOGON,0x9458,0x77d6,0x9b2d,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4f66,
+    0x4f68,0x4fe7,0x503f,UBOGON,0x50a6,0x510f,0x523e,0x5324,0x5365,0x539b,
+    0x517f,0x54cb,0x5573,0x5571,0x556b,0x55f4,0x5622,0x5620,0x5692,0x56ba,
+    0x5691,0x56b0,0x5759,0x578a,0x580f,0x5812,0x5813,0x5847,0x589b,0x5900,
+    0x594d,0x5ad1,0x5ad3,0x5b67,0x5c57,0x5c77,0x5cd5,0x5d75,0x5d8e,0x5da5,
+    0x5db6,0x5dbf,0x5e65,0x5ecd,0x5eed,0x5f94,0x5f9a,0x5fba,0x6125,0x6150,
+    0x62a3,0x6360,0x6364,0x63b6
+  },
+  {				/* ku 45 */
+    0x6403,0x64b6,0x651a,0x7a25,0x5c21,0x66e2,0x6702,0x67a4,0x67ac,0x6810,
+    0x6806,0x685e,0x685a,0x692c,0x6929,0x6a2d,0x6a77,0x6a7a,0x6aca,0x6ae6,
+    0x6af5,0x6b0d,0x6b0e,0x6bdc,0x6bdd,0x6bf6,0x6c1e,0x6c63,0x6da5,0x6e0f,
+    0x6e8a,0x6e84,0x6e8b,0x6e7c,0x6f4c,0x6f48,0x6f49,0x6f9d,0x6f99,0x6ff8,
+    0x702e,0x702d,0x705c,0x79cc,0x70bf,0x70ea,0x70e5,0x7111,0x7112,0x713f,
+    0x7139,0x713b,0x713d,0x7177,0x7175,0x7176,0x7171,0x7196,0x7193,0x71b4,
+    0x71dd,0x71de,0x720e,0x5911,0x7218,0x7347,0x7348,0x73ef,0x7412,0x743b,
+    0x74a4,0x748d,0x74b4,0x7673,0x7677,0x76bc,0x7819,0x781b,0x783d,0x7853,
+    0x7854,0x7858,0x78b7,0x78d8,0x78ee,0x7922,0x794d,0x7986,0x7999,0x79a3,
+    0x79bc,0x7aa7,0x7b37,0x7b59
+  },
+  {				/* ku 46 */
+    0x7bd0,0x7c2f,0x7c32,0x7c42,0x7c4e,0x7c68,0x7ca9,0x7ced,0x7dd0,0x7e07,
+    0x7dd3,0x7e64,0x7f40,UBOGON,0x8041,0x8063,0x80bb,0x6711,0x6725,0x8248,
+    0x8310,0x8362,0x8312,0x8421,0x841e,0x84e2,0x84de,0x84e1,0x8573,0x85d4,
+    0x85f5,0x8637,0x8645,0x8672,0x874a,0x87a9,0x87a5,0x87f5,0x8834,0x8850,
+    0x8887,0x8954,0x8984,0x8b03,0x8c52,0x8cd8,0x8d0c,0x8d18,0x8db0,0x8ebc,
+    0x8ed5,0x8faa,0x909c,UBOGON,0x915c,0x922b,0x9221,0x9273,0x92f4,0x92f5,
+    0x933f,0x9342,0x9386,0x93be,0x93bc,0x93bd,0x93f1,0x93f2,0x93ef,0x9422,
+    0x9423,0x9424,0x9467,0x9466,0x9597,0x95ce,0x95e7,0x973b,0x974d,0x98e4,
+    0x9942,0x9b1d,0x9b98,UBOGON,0x9d49,0x6449,0x5e71,0x5e85,0x61d3,0x990e,
+    0x8002,0x781e,UBOGON,UBOGON
+  },
+  {				/* ku 47 */
+    0x5528,0x5572,0x55ba,0x55f0,0x55ee,0x56b8,0x56b9,0x56c4,0x8053,0x92b0,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  }
+};
+#endif
+
+#if CNS_EXTENSION
+/* CNS 11643 plane 15 conversion table */
+
+static const unsigned short
+ cns11643_15tab[MAX_CNS11643_KU_15][MAX_CNS11643_TEN] = {
+  {				/* ku 01 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5301,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3436,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x53fa,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9f99,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6c49,
+    UBOGON,UBOGON,UBOGON,0x8fb7,UBOGON,0x3406,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4f29,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 02 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x534e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5c81,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5f10,UBOGON,UBOGON,0x6268,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x6742,0x6740,0x51ea,UBOGON,UBOGON,UBOGON,
+    0x6c62,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7391,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x8fbb,0x8fbc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 03 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x3575,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x56e8,UBOGON,0x575b,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x5c97,UBOGON,UBOGON
+  },
+  {				/* ku 04 */
+    UBOGON,0x6762,UBOGON,UBOGON,0x383c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x62a4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x6766,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x6ca3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x707f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 05 */
+    UBOGON,UBOGON,0x77f6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8fc8,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4fab,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x3453,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x5c2d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x549c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 06 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5788,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x34ac,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 07 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x62c3,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6619,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x3b49,UBOGON,0x67a1,UBOGON,0x67a6,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c91,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3cd3,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 08 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x77fe,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x7f57,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x43d5,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x82c5,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8fdf,UBOGON,UBOGON,
+    0x8fdc,0x488c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 09 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x4fe4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x551b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3588,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x57aa,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x57ab,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0a */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x36c9,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x5ba9,UBOGON,UBOGON,UBOGON,UBOGON,0x3917,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0b */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6811,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7551,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ebd,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x7553,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7818,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4133,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7ad7,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0d */
+    0x7c7e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x867e,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4844,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0e */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x5266,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x5520,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x5521,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x57d7,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x36e1,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x36e2,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x5bbe
+  },
+  {				/* ku 0f */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x387c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x38e3,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3aec,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 10 */
+    UBOGON,UBOGON,UBOGON,0x6857,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 11 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7f3c,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 12 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8273,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4627,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x96be,UBOGON,
+    UBOGON,UBOGON,0x66fa,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 13 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x35ab,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x364b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x5a72,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 14 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x37e2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 15 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x68bd,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 16 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6e15,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3dc1,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x7413,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x74f8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x7b3d
+  },
+  {				/* ku 17 */
+    UBOGON,UBOGON,0x76d8,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x79fc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x7b39,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x7d4b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x83b9,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 18 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x86cf,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8eae,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 19 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x96eb,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x55b0,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x5840,0x5842
+  },
+  {				/* ku 1a */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3701,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1b */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x692b,UBOGON,0x6916,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1c */
+    0x691b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6927,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6bf5,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x3d20,UBOGON,UBOGON,UBOGON,0x6e82,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3d21,UBOGON,UBOGON,
+    0x6e7a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x7129
+  },
+  {				/* ku 1d */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3eda,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1e */
+    0x7cab,UBOGON,0x7cac,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x83f7,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x44ea,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 1f */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4989,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x9596
+  },
+  {				/* ku 20 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x4ab2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x55f1,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 21 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x5f41,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 22 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x698a,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x698c,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6980,UBOGON,
+    0x697f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3dda,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 23 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3ddb,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x3ee2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x3ee3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 24 */
+    UBOGON,UBOGON,UBOGON,UBOGON,0x789c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7b7b,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 25 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x47f3,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x90d2,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x95a0,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 26 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4a57,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x51a9,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 27 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 28 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3bbc,
+    UBOGON,UBOGON,0x3ba4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 29 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x7195,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3de8,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x7198,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7478,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2a */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x78b9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7a33,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2b */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7cc0,UBOGON,UBOGON,UBOGON,
+    0x7cc1,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8744,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4886,UBOGON,UBOGON,UBOGON,0x9064,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2d */
+    UBOGON,0x9277,UBOGON,UBOGON,UBOGON,UBOGON,0x92af,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2e */
+    UBOGON,UBOGON,UBOGON,UBOGON,0x366d,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x366e,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x5e64,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2f */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x6a2b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6f46,UBOGON,
+    UBOGON,UBOGON,0x6f9a,UBOGON
+  },
+  {				/* ku 30 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f53,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 31 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4526,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x4527,UBOGON,UBOGON,0x4528,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 32 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x92f2,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 33 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9b79,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x567a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 34 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x372c,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x5f5c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x65d9,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x6a72,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 35 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6a78,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x6b5a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3efb,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 36 */
+    UBOGON,0x3efc,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 37 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 38 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8ebe,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x933b,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x9340,UBOGON,UBOGON,UBOGON,0x933a,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 39 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x9b96,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 3a */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x39a0,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x71f5,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 3b */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3f01,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7a50,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 3c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x481a,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 3d */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x9387,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x9385,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x493c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9bb1,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 3e */
+    UBOGON,UBOGON,UBOGON,0x9d47,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x3a6b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 3f */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 40 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x455c,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4787,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 41 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x93b9,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x93bf,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x9bcf,UBOGON,UBOGON,UBOGON,UBOGON,0x9d64,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x9ebf,UBOGON,UBOGON
+  },
+  {				/* ku 42 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x3c07,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3f05,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 43 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x45f9,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x89b8,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 44 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4953,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x9bf3,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x4c69,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 45 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3c12,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x7c4f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 46 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x9425,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 47 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 48 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x4878,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x95e6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 49 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9c2f,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x6b0c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 4a */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9c47,
+    0x4c88,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7936,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 4b */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6b15,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 4c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4584,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 4d */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x53b5,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  }
+};
+#endif
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/charset/decomtab.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,2909 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Unicode decomposition tables (current as of Unicode 5.0)
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	13 April 2006
+ * Last Edited:	6 December 2006
+ */
+
+/* BMP decompositions */
+
+#define UCS4_BMPLOMIN 0x00a0
+#define UCS4_BMPLOMAX 0x33ff
+#define UCS4_BMPLOIXMASK 0x1fff
+#define UCS4_BMPLOSIZEMASK 0xe000
+#define UCS4_BMPLOSIZESHIFT 13
+
+	/* BMP low decomposition indices - sssi iiii iiii iiii */
+static unsigned short ucs4_dbmploixtab[13152] = {
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x2001,0x0000,0x0003,0x0000,0x0000,0x0000,0x0000,0x2004,
+  0x0000,0x0000,0x0006,0x0007,0x2008,0x000a,0x0000,0x0000,
+  0x200b,0x000d,0x000e,0x0000,0x400f,0x4012,0x4015,0x0000,
+  0x2018,0x201a,0x201c,0x201e,0x2020,0x2022,0x0000,0x2024,
+  0x2026,0x2028,0x202a,0x202c,0x202e,0x2030,0x2032,0x2034,
+  0x0000,0x2036,0x2038,0x203a,0x203c,0x203e,0x2040,0x0000,
+  0x0000,0x2042,0x2044,0x2046,0x2048,0x204a,0x0000,0x0000,
+  0x204c,0x204e,0x2050,0x2052,0x2054,0x2056,0x0000,0x2058,
+  0x205a,0x205c,0x205e,0x2060,0x2062,0x2064,0x2066,0x2068,
+  0x0000,0x206a,0x206c,0x206e,0x2070,0x2072,0x2074,0x0000,
+  0x0000,0x2076,0x2078,0x207a,0x207c,0x207e,0x0000,0x2080,
+  0x2082,0x2084,0x2086,0x2088,0x208a,0x208c,0x208e,0x2090,
+  0x2092,0x2094,0x2096,0x2098,0x209a,0x209c,0x209e,0x20a0,
+  0x0000,0x0000,0x20a2,0x20a4,0x20a6,0x20a8,0x20aa,0x20ac,
+  0x20ae,0x20b0,0x20b2,0x20b4,0x20b6,0x20b8,0x20ba,0x20bc,
+  0x20be,0x20c0,0x20c2,0x20c4,0x20c6,0x20c8,0x0000,0x0000,
+  0x20ca,0x20cc,0x20ce,0x20d0,0x20d2,0x20d4,0x20d6,0x20d8,
+  0x20da,0x0000,0x20dc,0x20de,0x20e0,0x20e2,0x20e4,0x20e6,
+  0x0000,0x20e8,0x20ea,0x20ec,0x20ee,0x20f0,0x20f2,0x20f4,
+  0x20f6,0x0000,0x0000,0x20f8,0x20fa,0x20fc,0x20fe,0x2100,
+  0x2102,0x2104,0x0000,0x0000,0x2106,0x2108,0x210a,0x210c,
+  0x210e,0x2110,0x0000,0x0000,0x2112,0x2114,0x2116,0x2118,
+  0x211a,0x211c,0x211e,0x2120,0x2122,0x2124,0x2126,0x2128,
+  0x212a,0x212c,0x212e,0x2130,0x2132,0x2134,0x0000,0x0000,
+  0x2136,0x2138,0x213a,0x213c,0x213e,0x2140,0x2142,0x2144,
+  0x2146,0x2148,0x214a,0x214c,0x214e,0x2150,0x2152,0x2154,
+  0x2156,0x2158,0x215a,0x215c,0x215e,0x2160,0x2162,0x0164,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x2165,0x2167,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x2169,
+  0x216b,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x216d,0x216f,0x2171,0x2173,
+  0x2175,0x2177,0x2179,0x217b,0x217d,0x217f,0x2181,0x2183,
+  0x2185,0x2187,0x2189,0x218b,0x218d,0x218f,0x2191,0x2193,
+  0x2195,0x2197,0x2199,0x219b,0x219d,0x0000,0x219f,0x21a1,
+  0x21a3,0x21a5,0x21a7,0x21a9,0x0000,0x0000,0x21ab,0x21ad,
+  0x21af,0x21b1,0x21b3,0x21b5,0x21b7,0x21b9,0x21bb,0x21bd,
+  0x21bf,0x21c1,0x21c3,0x21c5,0x21c7,0x21c9,0x0000,0x0000,
+  0x21cb,0x21cd,0x21cf,0x21d1,0x21d3,0x21d5,0x21d7,0x21d9,
+  0x21db,0x21dd,0x21df,0x21e1,0x21e3,0x21e5,0x21e7,0x21e9,
+  0x21eb,0x21ed,0x21ef,0x21f1,0x21f3,0x21f5,0x21f7,0x21f9,
+  0x21fb,0x21fd,0x21ff,0x2201,0x2203,0x2205,0x2207,0x2209,
+  0x220b,0x220d,0x220f,0x2211,0x0000,0x0000,0x2213,0x2215,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x2217,0x2219,
+  0x221b,0x221d,0x221f,0x2221,0x2223,0x2225,0x2227,0x2229,
+  0x222b,0x222d,0x222f,0x2231,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0233,0x0234,0x0235,0x0236,0x0237,0x0238,0x0239,0x023a,
+  0x023b,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x223c,0x223e,0x2240,0x2242,0x2244,0x2246,0x0000,0x0000,
+  0x0248,0x0249,0x024a,0x024b,0x024c,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x024d,0x024e,0x0000,0x024f,0x2250,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0252,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x2253,0x0000,0x0000,0x0000,0x0255,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x2256,0x2258,0x225a,0x025c,
+  0x225d,0x225f,0x2261,0x0000,0x2263,0x0000,0x2265,0x2267,
+  0x2269,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x226b,0x226d,0x226f,0x2271,0x2273,0x2275,
+  0x2277,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x2279,0x227b,0x227d,0x227f,0x2281,0x0000,
+  0x0283,0x0284,0x0285,0x2286,0x2288,0x028a,0x028b,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x028c,0x028d,0x028e,0x0000,0x028f,0x0290,0x0000,0x0000,
+  0x0000,0x0291,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x2292,0x2294,0x0000,0x2296,0x0000,0x0000,0x0000,0x2298,
+  0x0000,0x0000,0x0000,0x0000,0x229a,0x229c,0x229e,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x22a0,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x22a2,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x22a4,0x22a6,0x0000,0x22a8,0x0000,0x0000,0x0000,0x22aa,
+  0x0000,0x0000,0x0000,0x0000,0x22ac,0x22ae,0x22b0,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x22b2,0x22b4,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x22b6,0x22b8,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x22ba,0x22bc,0x22be,0x22c0,0x0000,0x0000,0x22c2,0x22c4,
+  0x0000,0x0000,0x22c6,0x22c8,0x22ca,0x22cc,0x22ce,0x22d0,
+  0x0000,0x0000,0x22d2,0x22d4,0x22d6,0x22d8,0x22da,0x22dc,
+  0x0000,0x0000,0x22de,0x22e0,0x22e2,0x22e4,0x22e6,0x22e8,
+  0x22ea,0x22ec,0x22ee,0x22f0,0x22f2,0x22f4,0x0000,0x0000,
+  0x22f6,0x22f8,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x22fa,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x22fc,0x22fe,0x2300,0x2302,0x2304,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x2306,0x2308,0x230a,
+  0x230c,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x230e,0x0000,0x2310,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x2312,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x2314,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x2316,0x0000,0x0000,0x2318,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x231a,0x231c,0x231e,0x2320,0x2322,0x2324,0x2326,0x2328,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x232a,0x232c,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x232e,0x2330,0x0000,0x2332,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x2334,0x0000,0x0000,0x2336,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x2338,0x233a,0x233c,0x0000,0x0000,0x233e,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x2340,0x0000,0x0000,0x2342,0x2344,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x2346,0x2348,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x234a,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x234c,0x234e,0x2350,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x2352,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x2354,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x2356,
+  0x2358,0x0000,0x235a,0x235c,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x235e,0x2360,0x2362,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x2364,0x0000,0x2366,0x2368,0x236a,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x236c,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x236e,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x2370,0x2372,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0374,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x2375,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x2377,0x0000,0x0000,
+  0x0000,0x0000,0x2379,0x0000,0x0000,0x0000,0x0000,0x237b,
+  0x0000,0x0000,0x0000,0x0000,0x237d,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x237f,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x2381,0x0000,0x2383,0x2385,0x2387,
+  0x2389,0x238b,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x238d,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x238f,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x2391,0x0000,0x0000,
+  0x0000,0x0000,0x2393,0x0000,0x0000,0x0000,0x0000,0x2395,
+  0x0000,0x0000,0x0000,0x0000,0x2397,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x2399,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x239b,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x039d,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x239e,0x0000,
+  0x23a0,0x0000,0x23a2,0x0000,0x23a4,0x0000,0x23a6,0x0000,
+  0x0000,0x0000,0x23a8,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x23aa,0x0000,0x23ac,0x0000,0x0000,
+  0x23ae,0x23b0,0x0000,0x23b2,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x03b4,0x03b5,0x03b6,0x0000,
+  0x03b7,0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,
+  0x03bf,0x03c0,0x03c1,0x0000,0x03c2,0x03c3,0x03c4,0x03c5,
+  0x03c6,0x03c7,0x03c8,0x03c9,0x03ca,0x03cb,0x03cc,0x03cd,
+  0x03ce,0x03cf,0x03d0,0x03d1,0x03d2,0x03d3,0x0000,0x03d4,
+  0x03d5,0x03d6,0x03d7,0x03d8,0x03d9,0x03da,0x03db,0x03dc,
+  0x03dd,0x03de,0x03df,0x03e0,0x03e1,0x03e2,0x03e3,0x03e4,
+  0x03e5,0x03e6,0x03e7,0x03e8,0x03e9,0x03ea,0x03eb,0x03ec,
+  0x03ed,0x03ee,0x03ef,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x03f0,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x03f1,0x03f2,0x03f3,0x03f4,0x03f5,
+  0x03f6,0x03f7,0x03f8,0x03f9,0x03fa,0x03fb,0x03fc,0x03fd,
+  0x03fe,0x03ff,0x0400,0x0401,0x0402,0x0403,0x0404,0x0405,
+  0x0406,0x0407,0x0408,0x0409,0x040a,0x040b,0x040c,0x040d,
+  0x040e,0x040f,0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x2416,0x2418,0x241a,0x241c,0x241e,0x2420,0x2422,0x2424,
+  0x2426,0x2428,0x242a,0x242c,0x242e,0x2430,0x2432,0x2434,
+  0x2436,0x2438,0x243a,0x243c,0x243e,0x2440,0x2442,0x2444,
+  0x2446,0x2448,0x244a,0x244c,0x244e,0x2450,0x2452,0x2454,
+  0x2456,0x2458,0x245a,0x245c,0x245e,0x2460,0x2462,0x2464,
+  0x2466,0x2468,0x246a,0x246c,0x246e,0x2470,0x2472,0x2474,
+  0x2476,0x2478,0x247a,0x247c,0x247e,0x2480,0x2482,0x2484,
+  0x2486,0x2488,0x248a,0x248c,0x248e,0x2490,0x2492,0x2494,
+  0x2496,0x2498,0x249a,0x249c,0x249e,0x24a0,0x24a2,0x24a4,
+  0x24a6,0x24a8,0x24aa,0x24ac,0x24ae,0x24b0,0x24b2,0x24b4,
+  0x24b6,0x24b8,0x24ba,0x24bc,0x24be,0x24c0,0x24c2,0x24c4,
+  0x24c6,0x24c8,0x24ca,0x24cc,0x24ce,0x24d0,0x24d2,0x24d4,
+  0x24d6,0x24d8,0x24da,0x24dc,0x24de,0x24e0,0x24e2,0x24e4,
+  0x24e6,0x24e8,0x24ea,0x24ec,0x24ee,0x24f0,0x24f2,0x24f4,
+  0x24f6,0x24f8,0x24fa,0x24fc,0x24fe,0x2500,0x2502,0x2504,
+  0x2506,0x2508,0x250a,0x250c,0x250e,0x2510,0x2512,0x2514,
+  0x2516,0x2518,0x251a,0x251c,0x251e,0x2520,0x2522,0x2524,
+  0x2526,0x2528,0x252a,0x252c,0x252e,0x2530,0x2532,0x2534,
+  0x2536,0x2538,0x253a,0x253c,0x253e,0x2540,0x2542,0x2544,
+  0x2546,0x2548,0x254a,0x254c,0x0000,0x0000,0x0000,0x0000,
+  0x254e,0x2550,0x2552,0x2554,0x2556,0x2558,0x255a,0x255c,
+  0x255e,0x2560,0x2562,0x2564,0x2566,0x2568,0x256a,0x256c,
+  0x256e,0x2570,0x2572,0x2574,0x2576,0x2578,0x257a,0x257c,
+  0x257e,0x2580,0x2582,0x2584,0x2586,0x2588,0x258a,0x258c,
+  0x258e,0x2590,0x2592,0x2594,0x2596,0x2598,0x259a,0x259c,
+  0x259e,0x25a0,0x25a2,0x25a4,0x25a6,0x25a8,0x25aa,0x25ac,
+  0x25ae,0x25b0,0x25b2,0x25b4,0x25b6,0x25b8,0x25ba,0x25bc,
+  0x25be,0x25c0,0x25c2,0x25c4,0x25c6,0x25c8,0x25ca,0x25cc,
+  0x25ce,0x25d0,0x25d2,0x25d4,0x25d6,0x25d8,0x25da,0x25dc,
+  0x25de,0x25e0,0x25e2,0x25e4,0x25e6,0x25e8,0x25ea,0x25ec,
+  0x25ee,0x25f0,0x25f2,0x25f4,0x25f6,0x25f8,0x25fa,0x25fc,
+  0x25fe,0x2600,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x2602,0x2604,0x2606,0x2608,0x260a,0x260c,0x260e,0x2610,
+  0x2612,0x2614,0x2616,0x2618,0x261a,0x261c,0x261e,0x2620,
+  0x2622,0x2624,0x2626,0x2628,0x262a,0x262c,0x0000,0x0000,
+  0x262e,0x2630,0x2632,0x2634,0x2636,0x2638,0x0000,0x0000,
+  0x263a,0x263c,0x263e,0x2640,0x2642,0x2644,0x2646,0x2648,
+  0x264a,0x264c,0x264e,0x2650,0x2652,0x2654,0x2656,0x2658,
+  0x265a,0x265c,0x265e,0x2660,0x2662,0x2664,0x2666,0x2668,
+  0x266a,0x266c,0x266e,0x2670,0x2672,0x2674,0x2676,0x2678,
+  0x267a,0x267c,0x267e,0x2680,0x2682,0x2684,0x0000,0x0000,
+  0x2686,0x2688,0x268a,0x268c,0x268e,0x2690,0x0000,0x0000,
+  0x2692,0x2694,0x2696,0x2698,0x269a,0x269c,0x269e,0x26a0,
+  0x0000,0x26a2,0x0000,0x26a4,0x0000,0x26a6,0x0000,0x26a8,
+  0x26aa,0x26ac,0x26ae,0x26b0,0x26b2,0x26b4,0x26b6,0x26b8,
+  0x26ba,0x26bc,0x26be,0x26c0,0x26c2,0x26c4,0x26c6,0x26c8,
+  0x26ca,0x06cc,0x26cd,0x06cf,0x26d0,0x06d2,0x26d3,0x06d5,
+  0x26d6,0x06d8,0x26d9,0x06db,0x26dc,0x06de,0x0000,0x0000,
+  0x26df,0x26e1,0x26e3,0x26e5,0x26e7,0x26e9,0x26eb,0x26ed,
+  0x26ef,0x26f1,0x26f3,0x26f5,0x26f7,0x26f9,0x26fb,0x26fd,
+  0x26ff,0x2701,0x2703,0x2705,0x2707,0x2709,0x270b,0x270d,
+  0x270f,0x2711,0x2713,0x2715,0x2717,0x2719,0x271b,0x271d,
+  0x271f,0x2721,0x2723,0x2725,0x2727,0x2729,0x272b,0x272d,
+  0x272f,0x2731,0x2733,0x2735,0x2737,0x2739,0x273b,0x273d,
+  0x273f,0x2741,0x2743,0x2745,0x2747,0x0000,0x2749,0x274b,
+  0x274d,0x274f,0x2751,0x0753,0x2754,0x2756,0x0758,0x2759,
+  0x275b,0x275d,0x275f,0x2761,0x2763,0x0000,0x2765,0x2767,
+  0x2769,0x076b,0x276c,0x076e,0x276f,0x2771,0x2773,0x2775,
+  0x2777,0x2779,0x277b,0x077d,0x0000,0x0000,0x277e,0x2780,
+  0x2782,0x2784,0x2786,0x0788,0x0000,0x2789,0x278b,0x278d,
+  0x278f,0x2791,0x2793,0x0795,0x2796,0x2798,0x279a,0x279c,
+  0x279e,0x27a0,0x27a2,0x07a4,0x27a5,0x27a7,0x07a9,0x07aa,
+  0x0000,0x0000,0x27ab,0x27ad,0x27af,0x0000,0x27b1,0x27b3,
+  0x27b5,0x07b7,0x27b8,0x07ba,0x27bb,0x07bd,0x27be,0x0000,
+  0x07c0,0x07c1,0x07c2,0x07c3,0x07c4,0x07c5,0x07c6,0x07c7,
+  0x07c8,0x07c9,0x07ca,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x07cb,0x0000,0x0000,0x0000,0x0000,0x0000,0x27cc,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x07ce,0x27cf,0x47d1,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x07d4,
+  0x0000,0x0000,0x0000,0x27d5,0x47d7,0x0000,0x27da,0x47dc,
+  0x0000,0x0000,0x0000,0x0000,0x27df,0x0000,0x27e1,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x27e3,
+  0x27e5,0x27e7,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x67e9,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x07ed,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x07ee,0x07ef,0x0000,0x0000,0x07f0,0x07f1,0x07f2,0x07f3,
+  0x07f4,0x07f5,0x07f6,0x07f7,0x07f8,0x07f9,0x07fa,0x07fb,
+  0x07fc,0x07fd,0x07fe,0x07ff,0x0800,0x0801,0x0802,0x0803,
+  0x0804,0x0805,0x0806,0x0807,0x0808,0x0809,0x080a,0x0000,
+  0x080b,0x080c,0x080d,0x080e,0x080f,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x2810,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x4812,0x4815,0x0818,0x2819,0x0000,0x481b,0x481e,0x0821,
+  0x0000,0x2822,0x0824,0x0825,0x0826,0x0827,0x0828,0x0829,
+  0x082a,0x082b,0x082c,0x082d,0x0000,0x082e,0x282f,0x0000,
+  0x0000,0x0831,0x0832,0x0833,0x0834,0x0835,0x0000,0x0000,
+  0x2836,0x4838,0x283b,0x0000,0x083d,0x0000,0x083e,0x0000,
+  0x083f,0x0000,0x0840,0x0841,0x0842,0x0843,0x0000,0x0844,
+  0x0845,0x0846,0x0000,0x0847,0x0848,0x0849,0x084a,0x084b,
+  0x084c,0x084d,0x0000,0x484e,0x0851,0x0852,0x0853,0x0854,
+  0x0855,0x0000,0x0000,0x0000,0x0000,0x0856,0x0857,0x0858,
+  0x0859,0x085a,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x485b,0x485e,0x4861,0x4864,0x4867,
+  0x486a,0x486d,0x4870,0x4873,0x4876,0x4879,0x487c,0x287f,
+  0x0881,0x2882,0x4884,0x2887,0x0889,0x288a,0x488c,0x688f,
+  0x2893,0x0895,0x2896,0x4898,0x089b,0x089c,0x089d,0x089e,
+  0x089f,0x28a0,0x48a2,0x28a5,0x08a7,0x28a8,0x48aa,0x68ad,
+  0x28b1,0x08b3,0x28b4,0x48b6,0x08b9,0x08ba,0x08bb,0x08bc,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x28bd,0x28bf,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x28c1,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x28c3,0x28c5,0x28c7,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x28c9,0x0000,0x0000,0x0000,
+  0x0000,0x28cb,0x0000,0x0000,0x28cd,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x28cf,0x0000,0x28d1,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x28d3,0x48d5,0x0000,0x28d8,
+  0x48da,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x28dd,0x0000,0x0000,0x28df,0x0000,0x0000,0x28e1,
+  0x0000,0x28e3,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x28e5,0x0000,0x28e7,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x28e9,0x28eb,0x28ed,
+  0x28ef,0x28f1,0x0000,0x0000,0x28f3,0x28f5,0x0000,0x0000,
+  0x28f7,0x28f9,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x28fb,0x28fd,0x0000,0x0000,0x28ff,0x2901,0x0000,0x0000,
+  0x2903,0x2905,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x2907,0x2909,0x290b,0x290d,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x290f,0x2911,0x2913,0x2915,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x2917,0x2919,0x291b,0x291d,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x091f,0x0920,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0921,0x0922,0x0923,0x0924,0x0925,0x0926,0x0927,0x0928,
+  0x0929,0x292a,0x292c,0x292e,0x2930,0x2932,0x2934,0x2936,
+  0x2938,0x293a,0x293c,0x293e,0x4940,0x4943,0x4946,0x4949,
+  0x494c,0x494f,0x4952,0x4955,0x4958,0x695b,0x695f,0x6963,
+  0x6967,0x696b,0x696f,0x6973,0x6977,0x697b,0x697f,0x6983,
+  0x2987,0x2989,0x298b,0x298d,0x298f,0x2991,0x2993,0x2995,
+  0x2997,0x4999,0x499c,0x499f,0x49a2,0x49a5,0x49a8,0x49ab,
+  0x49ae,0x49b1,0x49b4,0x49b7,0x49ba,0x49bd,0x49c0,0x49c3,
+  0x49c6,0x49c9,0x49cc,0x49cf,0x49d2,0x49d5,0x49d8,0x49db,
+  0x49de,0x49e1,0x49e4,0x49e7,0x49ea,0x49ed,0x49f0,0x49f3,
+  0x49f6,0x49f9,0x49fc,0x49ff,0x4a02,0x4a05,0x0a08,0x0a09,
+  0x0a0a,0x0a0b,0x0a0c,0x0a0d,0x0a0e,0x0a0f,0x0a10,0x0a11,
+  0x0a12,0x0a13,0x0a14,0x0a15,0x0a16,0x0a17,0x0a18,0x0a19,
+  0x0a1a,0x0a1b,0x0a1c,0x0a1d,0x0a1e,0x0a1f,0x0a20,0x0a21,
+  0x0a22,0x0a23,0x0a24,0x0a25,0x0a26,0x0a27,0x0a28,0x0a29,
+  0x0a2a,0x0a2b,0x0a2c,0x0a2d,0x0a2e,0x0a2f,0x0a30,0x0a31,
+  0x0a32,0x0a33,0x0a34,0x0a35,0x0a36,0x0a37,0x0a38,0x0a39,
+  0x0a3a,0x0a3b,0x0a3c,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x6a3d,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x4a41,0x2a44,0x4a46,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x2a49,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0a4b,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0a4c,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0a4d,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0a4e,0x0a4f,0x0a50,0x0a51,0x0a52,0x0a53,0x0a54,0x0a55,
+  0x0a56,0x0a57,0x0a58,0x0a59,0x0a5a,0x0a5b,0x0a5c,0x0a5d,
+  0x0a5e,0x0a5f,0x0a60,0x0a61,0x0a62,0x0a63,0x0a64,0x0a65,
+  0x0a66,0x0a67,0x0a68,0x0a69,0x0a6a,0x0a6b,0x0a6c,0x0a6d,
+  0x0a6e,0x0a6f,0x0a70,0x0a71,0x0a72,0x0a73,0x0a74,0x0a75,
+  0x0a76,0x0a77,0x0a78,0x0a79,0x0a7a,0x0a7b,0x0a7c,0x0a7d,
+  0x0a7e,0x0a7f,0x0a80,0x0a81,0x0a82,0x0a83,0x0a84,0x0a85,
+  0x0a86,0x0a87,0x0a88,0x0a89,0x0a8a,0x0a8b,0x0a8c,0x0a8d,
+  0x0a8e,0x0a8f,0x0a90,0x0a91,0x0a92,0x0a93,0x0a94,0x0a95,
+  0x0a96,0x0a97,0x0a98,0x0a99,0x0a9a,0x0a9b,0x0a9c,0x0a9d,
+  0x0a9e,0x0a9f,0x0aa0,0x0aa1,0x0aa2,0x0aa3,0x0aa4,0x0aa5,
+  0x0aa6,0x0aa7,0x0aa8,0x0aa9,0x0aaa,0x0aab,0x0aac,0x0aad,
+  0x0aae,0x0aaf,0x0ab0,0x0ab1,0x0ab2,0x0ab3,0x0ab4,0x0ab5,
+  0x0ab6,0x0ab7,0x0ab8,0x0ab9,0x0aba,0x0abb,0x0abc,0x0abd,
+  0x0abe,0x0abf,0x0ac0,0x0ac1,0x0ac2,0x0ac3,0x0ac4,0x0ac5,
+  0x0ac6,0x0ac7,0x0ac8,0x0ac9,0x0aca,0x0acb,0x0acc,0x0acd,
+  0x0ace,0x0acf,0x0ad0,0x0ad1,0x0ad2,0x0ad3,0x0ad4,0x0ad5,
+  0x0ad6,0x0ad7,0x0ad8,0x0ad9,0x0ada,0x0adb,0x0adc,0x0add,
+  0x0ade,0x0adf,0x0ae0,0x0ae1,0x0ae2,0x0ae3,0x0ae4,0x0ae5,
+  0x0ae6,0x0ae7,0x0ae8,0x0ae9,0x0aea,0x0aeb,0x0aec,0x0aed,
+  0x0aee,0x0aef,0x0af0,0x0af1,0x0af2,0x0af3,0x0af4,0x0af5,
+  0x0af6,0x0af7,0x0af8,0x0af9,0x0afa,0x0afb,0x0afc,0x0afd,
+  0x0afe,0x0aff,0x0b00,0x0b01,0x0b02,0x0b03,0x0b04,0x0b05,
+  0x0b06,0x0b07,0x0b08,0x0b09,0x0b0a,0x0b0b,0x0b0c,0x0b0d,
+  0x0b0e,0x0b0f,0x0b10,0x0b11,0x0b12,0x0b13,0x0b14,0x0b15,
+  0x0b16,0x0b17,0x0b18,0x0b19,0x0b1a,0x0b1b,0x0b1c,0x0b1d,
+  0x0b1e,0x0b1f,0x0b20,0x0b21,0x0b22,0x0b23,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0b24,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0b25,0x0000,
+  0x0b26,0x0b27,0x0b28,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x2b29,0x0000,0x2b2b,0x0000,
+  0x2b2d,0x0000,0x2b2f,0x0000,0x2b31,0x0000,0x2b33,0x0000,
+  0x2b35,0x0000,0x2b37,0x0000,0x2b39,0x0000,0x2b3b,0x0000,
+  0x2b3d,0x0000,0x2b3f,0x0000,0x0000,0x2b41,0x0000,0x2b43,
+  0x0000,0x2b45,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x2b47,0x2b49,0x0000,0x2b4b,0x2b4d,0x0000,0x2b4f,0x2b51,
+  0x0000,0x2b53,0x2b55,0x0000,0x2b57,0x2b59,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x2b5b,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x2b5d,0x2b5f,0x0000,0x2b61,0x2b63,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x2b65,0x0000,0x2b67,0x0000,
+  0x2b69,0x0000,0x2b6b,0x0000,0x2b6d,0x0000,0x2b6f,0x0000,
+  0x2b71,0x0000,0x2b73,0x0000,0x2b75,0x0000,0x2b77,0x0000,
+  0x2b79,0x0000,0x2b7b,0x0000,0x0000,0x2b7d,0x0000,0x2b7f,
+  0x0000,0x2b81,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x2b83,0x2b85,0x0000,0x2b87,0x2b89,0x0000,0x2b8b,0x2b8d,
+  0x0000,0x2b8f,0x2b91,0x0000,0x2b93,0x2b95,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x2b97,0x0000,0x0000,0x2b99,
+  0x2b9b,0x2b9d,0x2b9f,0x0000,0x0000,0x0000,0x2ba1,0x2ba3,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0ba5,0x0ba6,0x0ba7,0x0ba8,0x0ba9,0x0baa,0x0bab,
+  0x0bac,0x0bad,0x0bae,0x0baf,0x0bb0,0x0bb1,0x0bb2,0x0bb3,
+  0x0bb4,0x0bb5,0x0bb6,0x0bb7,0x0bb8,0x0bb9,0x0bba,0x0bbb,
+  0x0bbc,0x0bbd,0x0bbe,0x0bbf,0x0bc0,0x0bc1,0x0bc2,0x0bc3,
+  0x0bc4,0x0bc5,0x0bc6,0x0bc7,0x0bc8,0x0bc9,0x0bca,0x0bcb,
+  0x0bcc,0x0bcd,0x0bce,0x0bcf,0x0bd0,0x0bd1,0x0bd2,0x0bd3,
+  0x0bd4,0x0bd5,0x0bd6,0x0bd7,0x0bd8,0x0bd9,0x0bda,0x0bdb,
+  0x0bdc,0x0bdd,0x0bde,0x0bdf,0x0be0,0x0be1,0x0be2,0x0be3,
+  0x0be4,0x0be5,0x0be6,0x0be7,0x0be8,0x0be9,0x0bea,0x0beb,
+  0x0bec,0x0bed,0x0bee,0x0bef,0x0bf0,0x0bf1,0x0bf2,0x0bf3,
+  0x0bf4,0x0bf5,0x0bf6,0x0bf7,0x0bf8,0x0bf9,0x0bfa,0x0bfb,
+  0x0bfc,0x0bfd,0x0bfe,0x0bff,0x0c00,0x0c01,0x0c02,0x0000,
+  0x0000,0x0000,0x0c03,0x0c04,0x0c05,0x0c06,0x0c07,0x0c08,
+  0x0c09,0x0c0a,0x0c0b,0x0c0c,0x0c0d,0x0c0e,0x0c0f,0x0c10,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x4c11,0x4c14,0x4c17,0x4c1a,0x4c1d,0x4c20,0x4c23,0x4c26,
+  0x4c29,0x4c2c,0x4c2f,0x4c32,0x4c35,0x4c38,0x6c3b,0x6c3f,
+  0x6c43,0x6c47,0x6c4b,0x6c4f,0x6c53,0x6c57,0x6c5b,0x6c5f,
+  0x6c63,0x6c67,0x6c6b,0x6c6f,0x6c73,0xcc77,0xac7e,0x0000,
+  0x4c84,0x4c87,0x4c8a,0x4c8d,0x4c90,0x4c93,0x4c96,0x4c99,
+  0x4c9c,0x4c9f,0x4ca2,0x4ca5,0x4ca8,0x4cab,0x4cae,0x4cb1,
+  0x4cb4,0x4cb7,0x4cba,0x4cbd,0x4cc0,0x4cc3,0x4cc6,0x4cc9,
+  0x4ccc,0x4ccf,0x4cd2,0x4cd5,0x4cd8,0x4cdb,0x4cde,0x4ce1,
+  0x4ce4,0x4ce7,0x4cea,0x4ced,0x0000,0x0000,0x0000,0x0000,
+  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x4cf0,0x2cf3,0x2cf5,0x2cf7,0x2cf9,0x2cfb,0x2cfd,0x2cff,
+  0x2d01,0x2d03,0x2d05,0x2d07,0x2d09,0x2d0b,0x2d0d,0x2d0f,
+  0x0d11,0x0d12,0x0d13,0x0d14,0x0d15,0x0d16,0x0d17,0x0d18,
+  0x0d19,0x0d1a,0x0d1b,0x0d1c,0x0d1d,0x0d1e,0x2d1f,0x2d21,
+  0x2d23,0x2d25,0x2d27,0x2d29,0x2d2b,0x2d2d,0x2d2f,0x2d31,
+  0x2d33,0x2d35,0x2d37,0x2d39,0x8d3b,0x6d40,0x2d44,0x0000,
+  0x0d46,0x0d47,0x0d48,0x0d49,0x0d4a,0x0d4b,0x0d4c,0x0d4d,
+  0x0d4e,0x0d4f,0x0d50,0x0d51,0x0d52,0x0d53,0x0d54,0x0d55,
+  0x0d56,0x0d57,0x0d58,0x0d59,0x0d5a,0x0d5b,0x0d5c,0x0d5d,
+  0x0d5e,0x0d5f,0x0d60,0x0d61,0x0d62,0x0d63,0x0d64,0x0d65,
+  0x0d66,0x0d67,0x0d68,0x0d69,0x0d6a,0x0d6b,0x0d6c,0x0d6d,
+  0x0d6e,0x0d6f,0x0d70,0x0d71,0x0d72,0x0d73,0x0d74,0x0d75,
+  0x0d76,0x2d77,0x2d79,0x2d7b,0x2d7d,0x2d7f,0x2d81,0x2d83,
+  0x2d85,0x2d87,0x2d89,0x2d8b,0x2d8d,0x2d8f,0x2d91,0x2d93,
+  0x2d95,0x2d97,0x2d99,0x2d9b,0x2d9d,0x2d9f,0x2da1,0x2da3,
+  0x2da5,0x4da7,0x4daa,0x4dad,0x2db0,0x4db2,0x2db5,0x4db7,
+  0x0dba,0x0dbb,0x0dbc,0x0dbd,0x0dbe,0x0dbf,0x0dc0,0x0dc1,
+  0x0dc2,0x0dc3,0x0dc4,0x0dc5,0x0dc6,0x0dc7,0x0dc8,0x0dc9,
+  0x0dca,0x0dcb,0x0dcc,0x0dcd,0x0dce,0x0dcf,0x0dd0,0x0dd1,
+  0x0dd2,0x0dd3,0x0dd4,0x0dd5,0x0dd6,0x0dd7,0x0dd8,0x0dd9,
+  0x0dda,0x0ddb,0x0ddc,0x0ddd,0x0dde,0x0ddf,0x0de0,0x0de1,
+  0x0de2,0x0de3,0x0de4,0x0de5,0x0de6,0x0de7,0x0de8,0x0000,
+  0x6de9,0x6ded,0x6df1,0x4df5,0x6df8,0x4dfc,0x4dff,0x8e02,
+  0x6e07,0x4e0b,0x4e0e,0x4e11,0x6e14,0x6e18,0x4e1c,0x4e1f,
+  0x2e22,0x4e24,0x6e27,0x6e2b,0x2e2f,0x8e31,0xae36,0x8e3c,
+  0x4e41,0x8e44,0x8e49,0x6e4e,0x4e52,0x4e55,0x4e58,0x6e5b,
+  0x8e5f,0x6e64,0x4e68,0x4e6b,0x4e6e,0x2e71,0x2e73,0x2e75,
+  0x2e77,0x4e79,0x4e7c,0x8e7f,0x4e84,0x6e87,0x8e8b,0x4e90,
+  0x2e93,0x2e95,0x8e97,0x6e9c,0x8ea0,0x4ea5,0x8ea8,0x2ead,
+  0x4eaf,0x4eb2,0x4eb5,0x4eb8,0x4ebb,0x6ebe,0x4ec2,0x2ec5,
+  0x4ec7,0x4eca,0x4ecd,0x6ed0,0x4ed4,0x4ed7,0x4eda,0x8edd,
+  0x6ee2,0x2ee6,0x8ee8,0x2eed,0x6eef,0x6ef3,0x4ef7,0x4efa,
+  0x4efd,0x6f00,0x2f04,0x4f06,0x6f09,0x2f0d,0x8f0f,0x4f14,
+  0x2f17,0x2f19,0x2f1b,0x2f1d,0x2f1f,0x2f21,0x2f23,0x2f25,
+  0x2f27,0x2f29,0x4f2b,0x4f2e,0x4f31,0x4f34,0x4f37,0x4f3a,
+  0x4f3d,0x4f40,0x4f43,0x4f46,0x4f49,0x4f4c,0x4f4f,0x4f52,
+  0x4f55,0x4f58,0x2f5b,0x2f5d,0x4f5f,0x2f62,0x2f64,0x2f66,
+  0x4f68,0x4f6b,0x2f6e,0x2f70,0x2f72,0x2f74,0x2f76,0x6f78,
+  0x2f7c,0x2f7e,0x2f80,0x2f82,0x2f84,0x2f86,0x2f88,0x2f8a,
+  0x4f8c,0x6f8f,0x2f93,0x2f95,0x2f97,0x2f99,0x2f9b,0x2f9d,
+  0x2f9f,0x4fa1,0x4fa4,0x4fa7,0x4faa,0x2fad,0x2faf,0x2fb1,
+  0x2fb3,0x2fb5,0x2fb7,0x2fb9,0x2fbb,0x2fbd,0x2fbf,0x4fc1,
+  0x4fc4,0x2fc7,0x4fc9,0x4fcc,0x4fcf,0x2fd2,0x4fd4,0x4fd7,
+  0x6fda,0x2fde,0x4fe0,0x4fe3,0x4fe6,0x4fe9,0x8fec,0xaff1,
+  0x2ff7,0x2ff9,0x2ffb,0x2ffd,0x2fff,0x3001,0x3003,0x3005,
+  0x3007,0x3009,0x300b,0x300d,0x300f,0x3011,0x3013,0x3015,
+  0x3017,0x3019,0x701b,0x301f,0x3021,0x3023,0x7025,0x5029,
+  0x302c,0x302e,0x3030,0x3032,0x3034,0x3036,0x3038,0x303a,
+  0x303c,0x303e,0x5040,0x3043,0x3045,0x5047,0x504a,0x304d,
+  0x704f,0x5053,0x3056,0x3058,0x305a,0x305c,0x505e,0x5061,
+  0x3064,0x3066,0x3068,0x306a,0x306c,0x306e,0x3070,0x3072,
+  0x3074,0x5076,0x5079,0x507c,0x507f,0x5082,0x5085,0x5088,
+  0x508b,0x508e,0x5091,0x5094,0x5097,0x509a,0x509d,0x50a0,
+  0x50a3,0x50a6,0x50a9,0x50ac,0x50af,0x50b2,0x50b5,0x50b8,
+};
+
+	/* BMP low decompositions */
+static unsigned short ucs4_dbmplotab[4283] = {
+  0x0020,0x0020,0x0308,0x0061,0x0020,0x0304,0x0032,0x0033,
+  0x0020,0x0301,0x03bc,0x0020,0x0327,0x0031,0x006f,0x0031,
+  0x2044,0x0034,0x0031,0x2044,0x0032,0x0033,0x2044,0x0034,
+  0x0041,0x0300,0x0041,0x0301,0x0041,0x0302,0x0041,0x0303,
+  0x0041,0x0308,0x0041,0x030a,0x0043,0x0327,0x0045,0x0300,
+  0x0045,0x0301,0x0045,0x0302,0x0045,0x0308,0x0049,0x0300,
+  0x0049,0x0301,0x0049,0x0302,0x0049,0x0308,0x004e,0x0303,
+  0x004f,0x0300,0x004f,0x0301,0x004f,0x0302,0x004f,0x0303,
+  0x004f,0x0308,0x0055,0x0300,0x0055,0x0301,0x0055,0x0302,
+  0x0055,0x0308,0x0059,0x0301,0x0061,0x0300,0x0061,0x0301,
+  0x0061,0x0302,0x0061,0x0303,0x0061,0x0308,0x0061,0x030a,
+  0x0063,0x0327,0x0065,0x0300,0x0065,0x0301,0x0065,0x0302,
+  0x0065,0x0308,0x0069,0x0300,0x0069,0x0301,0x0069,0x0302,
+  0x0069,0x0308,0x006e,0x0303,0x006f,0x0300,0x006f,0x0301,
+  0x006f,0x0302,0x006f,0x0303,0x006f,0x0308,0x0075,0x0300,
+  0x0075,0x0301,0x0075,0x0302,0x0075,0x0308,0x0079,0x0301,
+  0x0079,0x0308,0x0041,0x0304,0x0061,0x0304,0x0041,0x0306,
+  0x0061,0x0306,0x0041,0x0328,0x0061,0x0328,0x0043,0x0301,
+  0x0063,0x0301,0x0043,0x0302,0x0063,0x0302,0x0043,0x0307,
+  0x0063,0x0307,0x0043,0x030c,0x0063,0x030c,0x0044,0x030c,
+  0x0064,0x030c,0x0045,0x0304,0x0065,0x0304,0x0045,0x0306,
+  0x0065,0x0306,0x0045,0x0307,0x0065,0x0307,0x0045,0x0328,
+  0x0065,0x0328,0x0045,0x030c,0x0065,0x030c,0x0047,0x0302,
+  0x0067,0x0302,0x0047,0x0306,0x0067,0x0306,0x0047,0x0307,
+  0x0067,0x0307,0x0047,0x0327,0x0067,0x0327,0x0048,0x0302,
+  0x0068,0x0302,0x0049,0x0303,0x0069,0x0303,0x0049,0x0304,
+  0x0069,0x0304,0x0049,0x0306,0x0069,0x0306,0x0049,0x0328,
+  0x0069,0x0328,0x0049,0x0307,0x0049,0x004a,0x0069,0x006a,
+  0x004a,0x0302,0x006a,0x0302,0x004b,0x0327,0x006b,0x0327,
+  0x004c,0x0301,0x006c,0x0301,0x004c,0x0327,0x006c,0x0327,
+  0x004c,0x030c,0x006c,0x030c,0x004c,0x00b7,0x006c,0x00b7,
+  0x004e,0x0301,0x006e,0x0301,0x004e,0x0327,0x006e,0x0327,
+  0x004e,0x030c,0x006e,0x030c,0x02bc,0x006e,0x004f,0x0304,
+  0x006f,0x0304,0x004f,0x0306,0x006f,0x0306,0x004f,0x030b,
+  0x006f,0x030b,0x0052,0x0301,0x0072,0x0301,0x0052,0x0327,
+  0x0072,0x0327,0x0052,0x030c,0x0072,0x030c,0x0053,0x0301,
+  0x0073,0x0301,0x0053,0x0302,0x0073,0x0302,0x0053,0x0327,
+  0x0073,0x0327,0x0053,0x030c,0x0073,0x030c,0x0054,0x0327,
+  0x0074,0x0327,0x0054,0x030c,0x0074,0x030c,0x0055,0x0303,
+  0x0075,0x0303,0x0055,0x0304,0x0075,0x0304,0x0055,0x0306,
+  0x0075,0x0306,0x0055,0x030a,0x0075,0x030a,0x0055,0x030b,
+  0x0075,0x030b,0x0055,0x0328,0x0075,0x0328,0x0057,0x0302,
+  0x0077,0x0302,0x0059,0x0302,0x0079,0x0302,0x0059,0x0308,
+  0x005a,0x0301,0x007a,0x0301,0x005a,0x0307,0x007a,0x0307,
+  0x005a,0x030c,0x007a,0x030c,0x0073,0x004f,0x031b,0x006f,
+  0x031b,0x0055,0x031b,0x0075,0x031b,0x0044,0x017d,0x0044,
+  0x017e,0x0064,0x017e,0x004c,0x004a,0x004c,0x006a,0x006c,
+  0x006a,0x004e,0x004a,0x004e,0x006a,0x006e,0x006a,0x0041,
+  0x030c,0x0061,0x030c,0x0049,0x030c,0x0069,0x030c,0x004f,
+  0x030c,0x006f,0x030c,0x0055,0x030c,0x0075,0x030c,0x00dc,
+  0x0304,0x00fc,0x0304,0x00dc,0x0301,0x00fc,0x0301,0x00dc,
+  0x030c,0x00fc,0x030c,0x00dc,0x0300,0x00fc,0x0300,0x00c4,
+  0x0304,0x00e4,0x0304,0x0226,0x0304,0x0227,0x0304,0x00c6,
+  0x0304,0x00e6,0x0304,0x0047,0x030c,0x0067,0x030c,0x004b,
+  0x030c,0x006b,0x030c,0x004f,0x0328,0x006f,0x0328,0x01ea,
+  0x0304,0x01eb,0x0304,0x01b7,0x030c,0x0292,0x030c,0x006a,
+  0x030c,0x0044,0x005a,0x0044,0x007a,0x0064,0x007a,0x0047,
+  0x0301,0x0067,0x0301,0x004e,0x0300,0x006e,0x0300,0x00c5,
+  0x0301,0x00e5,0x0301,0x00c6,0x0301,0x00e6,0x0301,0x00d8,
+  0x0301,0x00f8,0x0301,0x0041,0x030f,0x0061,0x030f,0x0041,
+  0x0311,0x0061,0x0311,0x0045,0x030f,0x0065,0x030f,0x0045,
+  0x0311,0x0065,0x0311,0x0049,0x030f,0x0069,0x030f,0x0049,
+  0x0311,0x0069,0x0311,0x004f,0x030f,0x006f,0x030f,0x004f,
+  0x0311,0x006f,0x0311,0x0052,0x030f,0x0072,0x030f,0x0052,
+  0x0311,0x0072,0x0311,0x0055,0x030f,0x0075,0x030f,0x0055,
+  0x0311,0x0075,0x0311,0x0053,0x0326,0x0073,0x0326,0x0054,
+  0x0326,0x0074,0x0326,0x0048,0x030c,0x0068,0x030c,0x0041,
+  0x0307,0x0061,0x0307,0x0045,0x0327,0x0065,0x0327,0x00d6,
+  0x0304,0x00f6,0x0304,0x00d5,0x0304,0x00f5,0x0304,0x004f,
+  0x0307,0x006f,0x0307,0x022e,0x0304,0x022f,0x0304,0x0059,
+  0x0304,0x0079,0x0304,0x0068,0x0266,0x006a,0x0072,0x0279,
+  0x027b,0x0281,0x0077,0x0079,0x0020,0x0306,0x0020,0x0307,
+  0x0020,0x030a,0x0020,0x0328,0x0020,0x0303,0x0020,0x030b,
+  0x0263,0x006c,0x0073,0x0078,0x0295,0x0300,0x0301,0x0313,
+  0x0308,0x0301,0x02b9,0x0020,0x0345,0x003b,0x0020,0x0301,
+  0x00a8,0x0301,0x0391,0x0301,0x00b7,0x0395,0x0301,0x0397,
+  0x0301,0x0399,0x0301,0x039f,0x0301,0x03a5,0x0301,0x03a9,
+  0x0301,0x03ca,0x0301,0x0399,0x0308,0x03a5,0x0308,0x03b1,
+  0x0301,0x03b5,0x0301,0x03b7,0x0301,0x03b9,0x0301,0x03cb,
+  0x0301,0x03b9,0x0308,0x03c5,0x0308,0x03bf,0x0301,0x03c5,
+  0x0301,0x03c9,0x0301,0x03b2,0x03b8,0x03a5,0x03d2,0x0301,
+  0x03d2,0x0308,0x03c6,0x03c0,0x03ba,0x03c1,0x03c2,0x0398,
+  0x03b5,0x03a3,0x0415,0x0300,0x0415,0x0308,0x0413,0x0301,
+  0x0406,0x0308,0x041a,0x0301,0x0418,0x0300,0x0423,0x0306,
+  0x0418,0x0306,0x0438,0x0306,0x0435,0x0300,0x0435,0x0308,
+  0x0433,0x0301,0x0456,0x0308,0x043a,0x0301,0x0438,0x0300,
+  0x0443,0x0306,0x0474,0x030f,0x0475,0x030f,0x0416,0x0306,
+  0x0436,0x0306,0x0410,0x0306,0x0430,0x0306,0x0410,0x0308,
+  0x0430,0x0308,0x0415,0x0306,0x0435,0x0306,0x04d8,0x0308,
+  0x04d9,0x0308,0x0416,0x0308,0x0436,0x0308,0x0417,0x0308,
+  0x0437,0x0308,0x0418,0x0304,0x0438,0x0304,0x0418,0x0308,
+  0x0438,0x0308,0x041e,0x0308,0x043e,0x0308,0x04e8,0x0308,
+  0x04e9,0x0308,0x042d,0x0308,0x044d,0x0308,0x0423,0x0304,
+  0x0443,0x0304,0x0423,0x0308,0x0443,0x0308,0x0423,0x030b,
+  0x0443,0x030b,0x0427,0x0308,0x0447,0x0308,0x042b,0x0308,
+  0x044b,0x0308,0x0565,0x0582,0x0627,0x0653,0x0627,0x0654,
+  0x0648,0x0654,0x0627,0x0655,0x064a,0x0654,0x0627,0x0674,
+  0x0648,0x0674,0x06c7,0x0674,0x064a,0x0674,0x06d5,0x0654,
+  0x06c1,0x0654,0x06d2,0x0654,0x0928,0x093c,0x0930,0x093c,
+  0x0933,0x093c,0x0915,0x093c,0x0916,0x093c,0x0917,0x093c,
+  0x091c,0x093c,0x0921,0x093c,0x0922,0x093c,0x092b,0x093c,
+  0x092f,0x093c,0x09c7,0x09be,0x09c7,0x09d7,0x09a1,0x09bc,
+  0x09a2,0x09bc,0x09af,0x09bc,0x0a32,0x0a3c,0x0a38,0x0a3c,
+  0x0a16,0x0a3c,0x0a17,0x0a3c,0x0a1c,0x0a3c,0x0a2b,0x0a3c,
+  0x0b47,0x0b56,0x0b47,0x0b3e,0x0b47,0x0b57,0x0b21,0x0b3c,
+  0x0b22,0x0b3c,0x0b92,0x0bd7,0x0bc6,0x0bbe,0x0bc7,0x0bbe,
+  0x0bc6,0x0bd7,0x0c46,0x0c56,0x0cbf,0x0cd5,0x0cc6,0x0cd5,
+  0x0cc6,0x0cd6,0x0cc6,0x0cc2,0x0cca,0x0cd5,0x0d46,0x0d3e,
+  0x0d47,0x0d3e,0x0d46,0x0d57,0x0dd9,0x0dca,0x0dd9,0x0dcf,
+  0x0ddc,0x0dca,0x0dd9,0x0ddf,0x0e4d,0x0e32,0x0ecd,0x0eb2,
+  0x0eab,0x0e99,0x0eab,0x0ea1,0x0f0b,0x0f42,0x0fb7,0x0f4c,
+  0x0fb7,0x0f51,0x0fb7,0x0f56,0x0fb7,0x0f5b,0x0fb7,0x0f40,
+  0x0fb5,0x0f71,0x0f72,0x0f71,0x0f74,0x0fb2,0x0f80,0x0fb2,
+  0x0f81,0x0fb3,0x0f80,0x0fb3,0x0f81,0x0f71,0x0f80,0x0f92,
+  0x0fb7,0x0f9c,0x0fb7,0x0fa1,0x0fb7,0x0fa6,0x0fb7,0x0fab,
+  0x0fb7,0x0f90,0x0fb5,0x1025,0x102e,0x10dc,0x1b05,0x1b35,
+  0x1b07,0x1b35,0x1b09,0x1b35,0x1b0b,0x1b35,0x1b0d,0x1b35,
+  0x1b11,0x1b35,0x1b3a,0x1b35,0x1b3c,0x1b35,0x1b3e,0x1b35,
+  0x1b3f,0x1b35,0x1b42,0x1b35,0x0041,0x00c6,0x0042,0x0044,
+  0x0045,0x018e,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c,
+  0x004d,0x004e,0x004f,0x0222,0x0050,0x0052,0x0054,0x0055,
+  0x0057,0x0061,0x0250,0x0251,0x1d02,0x0062,0x0064,0x0065,
+  0x0259,0x025b,0x025c,0x0067,0x006b,0x006d,0x014b,0x006f,
+  0x0254,0x1d16,0x1d17,0x0070,0x0074,0x0075,0x1d1d,0x026f,
+  0x0076,0x1d25,0x03b2,0x03b3,0x03b4,0x03c6,0x03c7,0x0069,
+  0x0072,0x0075,0x0076,0x03b2,0x03b3,0x03c1,0x03c6,0x03c7,
+  0x043d,0x0252,0x0063,0x0255,0x00f0,0x025c,0x0066,0x025f,
+  0x0261,0x0265,0x0268,0x0269,0x026a,0x1d7b,0x029d,0x026d,
+  0x1d85,0x029f,0x0271,0x0270,0x0272,0x0273,0x0274,0x0275,
+  0x0278,0x0282,0x0283,0x01ab,0x0289,0x028a,0x1d1c,0x028b,
+  0x028c,0x007a,0x0290,0x0291,0x0292,0x03b8,0x0041,0x0325,
+  0x0061,0x0325,0x0042,0x0307,0x0062,0x0307,0x0042,0x0323,
+  0x0062,0x0323,0x0042,0x0331,0x0062,0x0331,0x00c7,0x0301,
+  0x00e7,0x0301,0x0044,0x0307,0x0064,0x0307,0x0044,0x0323,
+  0x0064,0x0323,0x0044,0x0331,0x0064,0x0331,0x0044,0x0327,
+  0x0064,0x0327,0x0044,0x032d,0x0064,0x032d,0x0112,0x0300,
+  0x0113,0x0300,0x0112,0x0301,0x0113,0x0301,0x0045,0x032d,
+  0x0065,0x032d,0x0045,0x0330,0x0065,0x0330,0x0228,0x0306,
+  0x0229,0x0306,0x0046,0x0307,0x0066,0x0307,0x0047,0x0304,
+  0x0067,0x0304,0x0048,0x0307,0x0068,0x0307,0x0048,0x0323,
+  0x0068,0x0323,0x0048,0x0308,0x0068,0x0308,0x0048,0x0327,
+  0x0068,0x0327,0x0048,0x032e,0x0068,0x032e,0x0049,0x0330,
+  0x0069,0x0330,0x00cf,0x0301,0x00ef,0x0301,0x004b,0x0301,
+  0x006b,0x0301,0x004b,0x0323,0x006b,0x0323,0x004b,0x0331,
+  0x006b,0x0331,0x004c,0x0323,0x006c,0x0323,0x1e36,0x0304,
+  0x1e37,0x0304,0x004c,0x0331,0x006c,0x0331,0x004c,0x032d,
+  0x006c,0x032d,0x004d,0x0301,0x006d,0x0301,0x004d,0x0307,
+  0x006d,0x0307,0x004d,0x0323,0x006d,0x0323,0x004e,0x0307,
+  0x006e,0x0307,0x004e,0x0323,0x006e,0x0323,0x004e,0x0331,
+  0x006e,0x0331,0x004e,0x032d,0x006e,0x032d,0x00d5,0x0301,
+  0x00f5,0x0301,0x00d5,0x0308,0x00f5,0x0308,0x014c,0x0300,
+  0x014d,0x0300,0x014c,0x0301,0x014d,0x0301,0x0050,0x0301,
+  0x0070,0x0301,0x0050,0x0307,0x0070,0x0307,0x0052,0x0307,
+  0x0072,0x0307,0x0052,0x0323,0x0072,0x0323,0x1e5a,0x0304,
+  0x1e5b,0x0304,0x0052,0x0331,0x0072,0x0331,0x0053,0x0307,
+  0x0073,0x0307,0x0053,0x0323,0x0073,0x0323,0x015a,0x0307,
+  0x015b,0x0307,0x0160,0x0307,0x0161,0x0307,0x1e62,0x0307,
+  0x1e63,0x0307,0x0054,0x0307,0x0074,0x0307,0x0054,0x0323,
+  0x0074,0x0323,0x0054,0x0331,0x0074,0x0331,0x0054,0x032d,
+  0x0074,0x032d,0x0055,0x0324,0x0075,0x0324,0x0055,0x0330,
+  0x0075,0x0330,0x0055,0x032d,0x0075,0x032d,0x0168,0x0301,
+  0x0169,0x0301,0x016a,0x0308,0x016b,0x0308,0x0056,0x0303,
+  0x0076,0x0303,0x0056,0x0323,0x0076,0x0323,0x0057,0x0300,
+  0x0077,0x0300,0x0057,0x0301,0x0077,0x0301,0x0057,0x0308,
+  0x0077,0x0308,0x0057,0x0307,0x0077,0x0307,0x0057,0x0323,
+  0x0077,0x0323,0x0058,0x0307,0x0078,0x0307,0x0058,0x0308,
+  0x0078,0x0308,0x0059,0x0307,0x0079,0x0307,0x005a,0x0302,
+  0x007a,0x0302,0x005a,0x0323,0x007a,0x0323,0x005a,0x0331,
+  0x007a,0x0331,0x0068,0x0331,0x0074,0x0308,0x0077,0x030a,
+  0x0079,0x030a,0x0061,0x02be,0x017f,0x0307,0x0041,0x0323,
+  0x0061,0x0323,0x0041,0x0309,0x0061,0x0309,0x00c2,0x0301,
+  0x00e2,0x0301,0x00c2,0x0300,0x00e2,0x0300,0x00c2,0x0309,
+  0x00e2,0x0309,0x00c2,0x0303,0x00e2,0x0303,0x1ea0,0x0302,
+  0x1ea1,0x0302,0x0102,0x0301,0x0103,0x0301,0x0102,0x0300,
+  0x0103,0x0300,0x0102,0x0309,0x0103,0x0309,0x0102,0x0303,
+  0x0103,0x0303,0x1ea0,0x0306,0x1ea1,0x0306,0x0045,0x0323,
+  0x0065,0x0323,0x0045,0x0309,0x0065,0x0309,0x0045,0x0303,
+  0x0065,0x0303,0x00ca,0x0301,0x00ea,0x0301,0x00ca,0x0300,
+  0x00ea,0x0300,0x00ca,0x0309,0x00ea,0x0309,0x00ca,0x0303,
+  0x00ea,0x0303,0x1eb8,0x0302,0x1eb9,0x0302,0x0049,0x0309,
+  0x0069,0x0309,0x0049,0x0323,0x0069,0x0323,0x004f,0x0323,
+  0x006f,0x0323,0x004f,0x0309,0x006f,0x0309,0x00d4,0x0301,
+  0x00f4,0x0301,0x00d4,0x0300,0x00f4,0x0300,0x00d4,0x0309,
+  0x00f4,0x0309,0x00d4,0x0303,0x00f4,0x0303,0x1ecc,0x0302,
+  0x1ecd,0x0302,0x01a0,0x0301,0x01a1,0x0301,0x01a0,0x0300,
+  0x01a1,0x0300,0x01a0,0x0309,0x01a1,0x0309,0x01a0,0x0303,
+  0x01a1,0x0303,0x01a0,0x0323,0x01a1,0x0323,0x0055,0x0323,
+  0x0075,0x0323,0x0055,0x0309,0x0075,0x0309,0x01af,0x0301,
+  0x01b0,0x0301,0x01af,0x0300,0x01b0,0x0300,0x01af,0x0309,
+  0x01b0,0x0309,0x01af,0x0303,0x01b0,0x0303,0x01af,0x0323,
+  0x01b0,0x0323,0x0059,0x0300,0x0079,0x0300,0x0059,0x0323,
+  0x0079,0x0323,0x0059,0x0309,0x0079,0x0309,0x0059,0x0303,
+  0x0079,0x0303,0x03b1,0x0313,0x03b1,0x0314,0x1f00,0x0300,
+  0x1f01,0x0300,0x1f00,0x0301,0x1f01,0x0301,0x1f00,0x0342,
+  0x1f01,0x0342,0x0391,0x0313,0x0391,0x0314,0x1f08,0x0300,
+  0x1f09,0x0300,0x1f08,0x0301,0x1f09,0x0301,0x1f08,0x0342,
+  0x1f09,0x0342,0x03b5,0x0313,0x03b5,0x0314,0x1f10,0x0300,
+  0x1f11,0x0300,0x1f10,0x0301,0x1f11,0x0301,0x0395,0x0313,
+  0x0395,0x0314,0x1f18,0x0300,0x1f19,0x0300,0x1f18,0x0301,
+  0x1f19,0x0301,0x03b7,0x0313,0x03b7,0x0314,0x1f20,0x0300,
+  0x1f21,0x0300,0x1f20,0x0301,0x1f21,0x0301,0x1f20,0x0342,
+  0x1f21,0x0342,0x0397,0x0313,0x0397,0x0314,0x1f28,0x0300,
+  0x1f29,0x0300,0x1f28,0x0301,0x1f29,0x0301,0x1f28,0x0342,
+  0x1f29,0x0342,0x03b9,0x0313,0x03b9,0x0314,0x1f30,0x0300,
+  0x1f31,0x0300,0x1f30,0x0301,0x1f31,0x0301,0x1f30,0x0342,
+  0x1f31,0x0342,0x0399,0x0313,0x0399,0x0314,0x1f38,0x0300,
+  0x1f39,0x0300,0x1f38,0x0301,0x1f39,0x0301,0x1f38,0x0342,
+  0x1f39,0x0342,0x03bf,0x0313,0x03bf,0x0314,0x1f40,0x0300,
+  0x1f41,0x0300,0x1f40,0x0301,0x1f41,0x0301,0x039f,0x0313,
+  0x039f,0x0314,0x1f48,0x0300,0x1f49,0x0300,0x1f48,0x0301,
+  0x1f49,0x0301,0x03c5,0x0313,0x03c5,0x0314,0x1f50,0x0300,
+  0x1f51,0x0300,0x1f50,0x0301,0x1f51,0x0301,0x1f50,0x0342,
+  0x1f51,0x0342,0x03a5,0x0314,0x1f59,0x0300,0x1f59,0x0301,
+  0x1f59,0x0342,0x03c9,0x0313,0x03c9,0x0314,0x1f60,0x0300,
+  0x1f61,0x0300,0x1f60,0x0301,0x1f61,0x0301,0x1f60,0x0342,
+  0x1f61,0x0342,0x03a9,0x0313,0x03a9,0x0314,0x1f68,0x0300,
+  0x1f69,0x0300,0x1f68,0x0301,0x1f69,0x0301,0x1f68,0x0342,
+  0x1f69,0x0342,0x03b1,0x0300,0x03ac,0x03b5,0x0300,0x03ad,
+  0x03b7,0x0300,0x03ae,0x03b9,0x0300,0x03af,0x03bf,0x0300,
+  0x03cc,0x03c5,0x0300,0x03cd,0x03c9,0x0300,0x03ce,0x1f00,
+  0x0345,0x1f01,0x0345,0x1f02,0x0345,0x1f03,0x0345,0x1f04,
+  0x0345,0x1f05,0x0345,0x1f06,0x0345,0x1f07,0x0345,0x1f08,
+  0x0345,0x1f09,0x0345,0x1f0a,0x0345,0x1f0b,0x0345,0x1f0c,
+  0x0345,0x1f0d,0x0345,0x1f0e,0x0345,0x1f0f,0x0345,0x1f20,
+  0x0345,0x1f21,0x0345,0x1f22,0x0345,0x1f23,0x0345,0x1f24,
+  0x0345,0x1f25,0x0345,0x1f26,0x0345,0x1f27,0x0345,0x1f28,
+  0x0345,0x1f29,0x0345,0x1f2a,0x0345,0x1f2b,0x0345,0x1f2c,
+  0x0345,0x1f2d,0x0345,0x1f2e,0x0345,0x1f2f,0x0345,0x1f60,
+  0x0345,0x1f61,0x0345,0x1f62,0x0345,0x1f63,0x0345,0x1f64,
+  0x0345,0x1f65,0x0345,0x1f66,0x0345,0x1f67,0x0345,0x1f68,
+  0x0345,0x1f69,0x0345,0x1f6a,0x0345,0x1f6b,0x0345,0x1f6c,
+  0x0345,0x1f6d,0x0345,0x1f6e,0x0345,0x1f6f,0x0345,0x03b1,
+  0x0306,0x03b1,0x0304,0x1f70,0x0345,0x03b1,0x0345,0x03ac,
+  0x0345,0x03b1,0x0342,0x1fb6,0x0345,0x0391,0x0306,0x0391,
+  0x0304,0x0391,0x0300,0x0386,0x0391,0x0345,0x0020,0x0313,
+  0x03b9,0x0020,0x0313,0x0020,0x0342,0x00a8,0x0342,0x1f74,
+  0x0345,0x03b7,0x0345,0x03ae,0x0345,0x03b7,0x0342,0x1fc6,
+  0x0345,0x0395,0x0300,0x0388,0x0397,0x0300,0x0389,0x0397,
+  0x0345,0x1fbf,0x0300,0x1fbf,0x0301,0x1fbf,0x0342,0x03b9,
+  0x0306,0x03b9,0x0304,0x03ca,0x0300,0x0390,0x03b9,0x0342,
+  0x03ca,0x0342,0x0399,0x0306,0x0399,0x0304,0x0399,0x0300,
+  0x038a,0x1ffe,0x0300,0x1ffe,0x0301,0x1ffe,0x0342,0x03c5,
+  0x0306,0x03c5,0x0304,0x03cb,0x0300,0x03b0,0x03c1,0x0313,
+  0x03c1,0x0314,0x03c5,0x0342,0x03cb,0x0342,0x03a5,0x0306,
+  0x03a5,0x0304,0x03a5,0x0300,0x038e,0x03a1,0x0314,0x00a8,
+  0x0300,0x0385,0x0060,0x1f7c,0x0345,0x03c9,0x0345,0x03ce,
+  0x0345,0x03c9,0x0342,0x1ff6,0x0345,0x039f,0x0300,0x038c,
+  0x03a9,0x0300,0x038f,0x03a9,0x0345,0x00b4,0x0020,0x0314,
+  0x2002,0x2003,0x0020,0x0020,0x0020,0x0020,0x0020,0x0020,
+  0x0020,0x0020,0x0020,0x2010,0x0020,0x0333,0x002e,0x002e,
+  0x002e,0x002e,0x002e,0x002e,0x0020,0x2032,0x2032,0x2032,
+  0x2032,0x2032,0x2035,0x2035,0x2035,0x2035,0x2035,0x0021,
+  0x0021,0x0020,0x0305,0x003f,0x003f,0x003f,0x0021,0x0021,
+  0x003f,0x2032,0x2032,0x2032,0x2032,0x0020,0x0030,0x0069,
+  0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x002b,0x2212,
+  0x003d,0x0028,0x0029,0x006e,0x0030,0x0031,0x0032,0x0033,
+  0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x002b,0x2212,
+  0x003d,0x0028,0x0029,0x0061,0x0065,0x006f,0x0078,0x0259,
+  0x0052,0x0073,0x0061,0x002f,0x0063,0x0061,0x002f,0x0073,
+  0x0043,0x00b0,0x0043,0x0063,0x002f,0x006f,0x0063,0x002f,
+  0x0075,0x0190,0x00b0,0x0046,0x0067,0x0048,0x0048,0x0048,
+  0x0068,0x0127,0x0049,0x0049,0x004c,0x006c,0x004e,0x004e,
+  0x006f,0x0050,0x0051,0x0052,0x0052,0x0052,0x0053,0x004d,
+  0x0054,0x0045,0x004c,0x0054,0x004d,0x005a,0x03a9,0x005a,
+  0x004b,0x00c5,0x0042,0x0043,0x0065,0x0045,0x0046,0x004d,
+  0x006f,0x05d0,0x05d1,0x05d2,0x05d3,0x0069,0x0046,0x0041,
+  0x0058,0x03c0,0x03b3,0x0393,0x03a0,0x2211,0x0044,0x0064,
+  0x0065,0x0069,0x006a,0x0031,0x2044,0x0033,0x0032,0x2044,
+  0x0033,0x0031,0x2044,0x0035,0x0032,0x2044,0x0035,0x0033,
+  0x2044,0x0035,0x0034,0x2044,0x0035,0x0031,0x2044,0x0036,
+  0x0035,0x2044,0x0036,0x0031,0x2044,0x0038,0x0033,0x2044,
+  0x0038,0x0035,0x2044,0x0038,0x0037,0x2044,0x0038,0x0031,
+  0x2044,0x0049,0x0049,0x0049,0x0049,0x0049,0x0049,0x0049,
+  0x0056,0x0056,0x0056,0x0049,0x0056,0x0049,0x0049,0x0056,
+  0x0049,0x0049,0x0049,0x0049,0x0058,0x0058,0x0058,0x0049,
+  0x0058,0x0049,0x0049,0x004c,0x0043,0x0044,0x004d,0x0069,
+  0x0069,0x0069,0x0069,0x0069,0x0069,0x0069,0x0076,0x0076,
+  0x0076,0x0069,0x0076,0x0069,0x0069,0x0076,0x0069,0x0069,
+  0x0069,0x0069,0x0078,0x0078,0x0078,0x0069,0x0078,0x0069,
+  0x0069,0x006c,0x0063,0x0064,0x006d,0x2190,0x0338,0x2192,
+  0x0338,0x2194,0x0338,0x21d0,0x0338,0x21d4,0x0338,0x21d2,
+  0x0338,0x2203,0x0338,0x2208,0x0338,0x220b,0x0338,0x2223,
+  0x0338,0x2225,0x0338,0x222b,0x222b,0x222b,0x222b,0x222b,
+  0x222e,0x222e,0x222e,0x222e,0x222e,0x223c,0x0338,0x2243,
+  0x0338,0x2245,0x0338,0x2248,0x0338,0x003d,0x0338,0x2261,
+  0x0338,0x224d,0x0338,0x003c,0x0338,0x003e,0x0338,0x2264,
+  0x0338,0x2265,0x0338,0x2272,0x0338,0x2273,0x0338,0x2276,
+  0x0338,0x2277,0x0338,0x227a,0x0338,0x227b,0x0338,0x2282,
+  0x0338,0x2283,0x0338,0x2286,0x0338,0x2287,0x0338,0x22a2,
+  0x0338,0x22a8,0x0338,0x22a9,0x0338,0x22ab,0x0338,0x227c,
+  0x0338,0x227d,0x0338,0x2291,0x0338,0x2292,0x0338,0x22b2,
+  0x0338,0x22b3,0x0338,0x22b4,0x0338,0x22b5,0x0338,0x3008,
+  0x3009,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,
+  0x0038,0x0039,0x0031,0x0030,0x0031,0x0031,0x0031,0x0032,
+  0x0031,0x0033,0x0031,0x0034,0x0031,0x0035,0x0031,0x0036,
+  0x0031,0x0037,0x0031,0x0038,0x0031,0x0039,0x0032,0x0030,
+  0x0028,0x0031,0x0029,0x0028,0x0032,0x0029,0x0028,0x0033,
+  0x0029,0x0028,0x0034,0x0029,0x0028,0x0035,0x0029,0x0028,
+  0x0036,0x0029,0x0028,0x0037,0x0029,0x0028,0x0038,0x0029,
+  0x0028,0x0039,0x0029,0x0028,0x0031,0x0030,0x0029,0x0028,
+  0x0031,0x0031,0x0029,0x0028,0x0031,0x0032,0x0029,0x0028,
+  0x0031,0x0033,0x0029,0x0028,0x0031,0x0034,0x0029,0x0028,
+  0x0031,0x0035,0x0029,0x0028,0x0031,0x0036,0x0029,0x0028,
+  0x0031,0x0037,0x0029,0x0028,0x0031,0x0038,0x0029,0x0028,
+  0x0031,0x0039,0x0029,0x0028,0x0032,0x0030,0x0029,0x0031,
+  0x002e,0x0032,0x002e,0x0033,0x002e,0x0034,0x002e,0x0035,
+  0x002e,0x0036,0x002e,0x0037,0x002e,0x0038,0x002e,0x0039,
+  0x002e,0x0031,0x0030,0x002e,0x0031,0x0031,0x002e,0x0031,
+  0x0032,0x002e,0x0031,0x0033,0x002e,0x0031,0x0034,0x002e,
+  0x0031,0x0035,0x002e,0x0031,0x0036,0x002e,0x0031,0x0037,
+  0x002e,0x0031,0x0038,0x002e,0x0031,0x0039,0x002e,0x0032,
+  0x0030,0x002e,0x0028,0x0061,0x0029,0x0028,0x0062,0x0029,
+  0x0028,0x0063,0x0029,0x0028,0x0064,0x0029,0x0028,0x0065,
+  0x0029,0x0028,0x0066,0x0029,0x0028,0x0067,0x0029,0x0028,
+  0x0068,0x0029,0x0028,0x0069,0x0029,0x0028,0x006a,0x0029,
+  0x0028,0x006b,0x0029,0x0028,0x006c,0x0029,0x0028,0x006d,
+  0x0029,0x0028,0x006e,0x0029,0x0028,0x006f,0x0029,0x0028,
+  0x0070,0x0029,0x0028,0x0071,0x0029,0x0028,0x0072,0x0029,
+  0x0028,0x0073,0x0029,0x0028,0x0074,0x0029,0x0028,0x0075,
+  0x0029,0x0028,0x0076,0x0029,0x0028,0x0077,0x0029,0x0028,
+  0x0078,0x0029,0x0028,0x0079,0x0029,0x0028,0x007a,0x0029,
+  0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,
+  0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,0x0050,
+  0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,
+  0x0059,0x005a,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,
+  0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,
+  0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,
+  0x0077,0x0078,0x0079,0x007a,0x0030,0x222b,0x222b,0x222b,
+  0x222b,0x003a,0x003a,0x003d,0x003d,0x003d,0x003d,0x003d,
+  0x003d,0x2add,0x0338,0x2d61,0x6bcd,0x9f9f,0x4e00,0x4e28,
+  0x4e36,0x4e3f,0x4e59,0x4e85,0x4e8c,0x4ea0,0x4eba,0x513f,
+  0x5165,0x516b,0x5182,0x5196,0x51ab,0x51e0,0x51f5,0x5200,
+  0x529b,0x52f9,0x5315,0x531a,0x5338,0x5341,0x535c,0x5369,
+  0x5382,0x53b6,0x53c8,0x53e3,0x56d7,0x571f,0x58eb,0x5902,
+  0x590a,0x5915,0x5927,0x5973,0x5b50,0x5b80,0x5bf8,0x5c0f,
+  0x5c22,0x5c38,0x5c6e,0x5c71,0x5ddb,0x5de5,0x5df1,0x5dfe,
+  0x5e72,0x5e7a,0x5e7f,0x5ef4,0x5efe,0x5f0b,0x5f13,0x5f50,
+  0x5f61,0x5f73,0x5fc3,0x6208,0x6236,0x624b,0x652f,0x6534,
+  0x6587,0x6597,0x65a4,0x65b9,0x65e0,0x65e5,0x66f0,0x6708,
+  0x6728,0x6b20,0x6b62,0x6b79,0x6bb3,0x6bcb,0x6bd4,0x6bdb,
+  0x6c0f,0x6c14,0x6c34,0x706b,0x722a,0x7236,0x723b,0x723f,
+  0x7247,0x7259,0x725b,0x72ac,0x7384,0x7389,0x74dc,0x74e6,
+  0x7518,0x751f,0x7528,0x7530,0x758b,0x7592,0x7676,0x767d,
+  0x76ae,0x76bf,0x76ee,0x77db,0x77e2,0x77f3,0x793a,0x79b8,
+  0x79be,0x7a74,0x7acb,0x7af9,0x7c73,0x7cf8,0x7f36,0x7f51,
+  0x7f8a,0x7fbd,0x8001,0x800c,0x8012,0x8033,0x807f,0x8089,
+  0x81e3,0x81ea,0x81f3,0x81fc,0x820c,0x821b,0x821f,0x826e,
+  0x8272,0x8278,0x864d,0x866b,0x8840,0x884c,0x8863,0x897e,
+  0x898b,0x89d2,0x8a00,0x8c37,0x8c46,0x8c55,0x8c78,0x8c9d,
+  0x8d64,0x8d70,0x8db3,0x8eab,0x8eca,0x8f9b,0x8fb0,0x8fb5,
+  0x9091,0x9149,0x91c6,0x91cc,0x91d1,0x9577,0x9580,0x961c,
+  0x96b6,0x96b9,0x96e8,0x9751,0x975e,0x9762,0x9769,0x97cb,
+  0x97ed,0x97f3,0x9801,0x98a8,0x98db,0x98df,0x9996,0x9999,
+  0x99ac,0x9aa8,0x9ad8,0x9adf,0x9b25,0x9b2f,0x9b32,0x9b3c,
+  0x9b5a,0x9ce5,0x9e75,0x9e7f,0x9ea5,0x9ebb,0x9ec3,0x9ecd,
+  0x9ed1,0x9ef9,0x9efd,0x9f0e,0x9f13,0x9f20,0x9f3b,0x9f4a,
+  0x9f52,0x9f8d,0x9f9c,0x9fa0,0x0020,0x3012,0x5341,0x5344,
+  0x5345,0x304b,0x3099,0x304d,0x3099,0x304f,0x3099,0x3051,
+  0x3099,0x3053,0x3099,0x3055,0x3099,0x3057,0x3099,0x3059,
+  0x3099,0x305b,0x3099,0x305d,0x3099,0x305f,0x3099,0x3061,
+  0x3099,0x3064,0x3099,0x3066,0x3099,0x3068,0x3099,0x306f,
+  0x3099,0x306f,0x309a,0x3072,0x3099,0x3072,0x309a,0x3075,
+  0x3099,0x3075,0x309a,0x3078,0x3099,0x3078,0x309a,0x307b,
+  0x3099,0x307b,0x309a,0x3046,0x3099,0x0020,0x3099,0x0020,
+  0x309a,0x309d,0x3099,0x3088,0x308a,0x30ab,0x3099,0x30ad,
+  0x3099,0x30af,0x3099,0x30b1,0x3099,0x30b3,0x3099,0x30b5,
+  0x3099,0x30b7,0x3099,0x30b9,0x3099,0x30bb,0x3099,0x30bd,
+  0x3099,0x30bf,0x3099,0x30c1,0x3099,0x30c4,0x3099,0x30c6,
+  0x3099,0x30c8,0x3099,0x30cf,0x3099,0x30cf,0x309a,0x30d2,
+  0x3099,0x30d2,0x309a,0x30d5,0x3099,0x30d5,0x309a,0x30d8,
+  0x3099,0x30d8,0x309a,0x30db,0x3099,0x30db,0x309a,0x30a6,
+  0x3099,0x30ef,0x3099,0x30f0,0x3099,0x30f1,0x3099,0x30f2,
+  0x3099,0x30fd,0x3099,0x30b3,0x30c8,0x1100,0x1101,0x11aa,
+  0x1102,0x11ac,0x11ad,0x1103,0x1104,0x1105,0x11b0,0x11b1,
+  0x11b2,0x11b3,0x11b4,0x11b5,0x111a,0x1106,0x1107,0x1108,
+  0x1121,0x1109,0x110a,0x110b,0x110c,0x110d,0x110e,0x110f,
+  0x1110,0x1111,0x1112,0x1161,0x1162,0x1163,0x1164,0x1165,
+  0x1166,0x1167,0x1168,0x1169,0x116a,0x116b,0x116c,0x116d,
+  0x116e,0x116f,0x1170,0x1171,0x1172,0x1173,0x1174,0x1175,
+  0x1160,0x1114,0x1115,0x11c7,0x11c8,0x11cc,0x11ce,0x11d3,
+  0x11d7,0x11d9,0x111c,0x11dd,0x11df,0x111d,0x111e,0x1120,
+  0x1122,0x1123,0x1127,0x1129,0x112b,0x112c,0x112d,0x112e,
+  0x112f,0x1132,0x1136,0x1140,0x1147,0x114c,0x11f1,0x11f2,
+  0x1157,0x1158,0x1159,0x1184,0x1185,0x1188,0x1191,0x1192,
+  0x1194,0x119e,0x11a1,0x4e00,0x4e8c,0x4e09,0x56db,0x4e0a,
+  0x4e2d,0x4e0b,0x7532,0x4e59,0x4e19,0x4e01,0x5929,0x5730,
+  0x4eba,0x0028,0x1100,0x0029,0x0028,0x1102,0x0029,0x0028,
+  0x1103,0x0029,0x0028,0x1105,0x0029,0x0028,0x1106,0x0029,
+  0x0028,0x1107,0x0029,0x0028,0x1109,0x0029,0x0028,0x110b,
+  0x0029,0x0028,0x110c,0x0029,0x0028,0x110e,0x0029,0x0028,
+  0x110f,0x0029,0x0028,0x1110,0x0029,0x0028,0x1111,0x0029,
+  0x0028,0x1112,0x0029,0x0028,0x1100,0x1161,0x0029,0x0028,
+  0x1102,0x1161,0x0029,0x0028,0x1103,0x1161,0x0029,0x0028,
+  0x1105,0x1161,0x0029,0x0028,0x1106,0x1161,0x0029,0x0028,
+  0x1107,0x1161,0x0029,0x0028,0x1109,0x1161,0x0029,0x0028,
+  0x110b,0x1161,0x0029,0x0028,0x110c,0x1161,0x0029,0x0028,
+  0x110e,0x1161,0x0029,0x0028,0x110f,0x1161,0x0029,0x0028,
+  0x1110,0x1161,0x0029,0x0028,0x1111,0x1161,0x0029,0x0028,
+  0x1112,0x1161,0x0029,0x0028,0x110c,0x116e,0x0029,0x0028,
+  0x110b,0x1169,0x110c,0x1165,0x11ab,0x0029,0x0028,0x110b,
+  0x1169,0x1112,0x116e,0x0029,0x0028,0x4e00,0x0029,0x0028,
+  0x4e8c,0x0029,0x0028,0x4e09,0x0029,0x0028,0x56db,0x0029,
+  0x0028,0x4e94,0x0029,0x0028,0x516d,0x0029,0x0028,0x4e03,
+  0x0029,0x0028,0x516b,0x0029,0x0028,0x4e5d,0x0029,0x0028,
+  0x5341,0x0029,0x0028,0x6708,0x0029,0x0028,0x706b,0x0029,
+  0x0028,0x6c34,0x0029,0x0028,0x6728,0x0029,0x0028,0x91d1,
+  0x0029,0x0028,0x571f,0x0029,0x0028,0x65e5,0x0029,0x0028,
+  0x682a,0x0029,0x0028,0x6709,0x0029,0x0028,0x793e,0x0029,
+  0x0028,0x540d,0x0029,0x0028,0x7279,0x0029,0x0028,0x8ca1,
+  0x0029,0x0028,0x795d,0x0029,0x0028,0x52b4,0x0029,0x0028,
+  0x4ee3,0x0029,0x0028,0x547c,0x0029,0x0028,0x5b66,0x0029,
+  0x0028,0x76e3,0x0029,0x0028,0x4f01,0x0029,0x0028,0x8cc7,
+  0x0029,0x0028,0x5354,0x0029,0x0028,0x796d,0x0029,0x0028,
+  0x4f11,0x0029,0x0028,0x81ea,0x0029,0x0028,0x81f3,0x0029,
+  0x0050,0x0054,0x0045,0x0032,0x0031,0x0032,0x0032,0x0032,
+  0x0033,0x0032,0x0034,0x0032,0x0035,0x0032,0x0036,0x0032,
+  0x0037,0x0032,0x0038,0x0032,0x0039,0x0033,0x0030,0x0033,
+  0x0031,0x0033,0x0032,0x0033,0x0033,0x0033,0x0034,0x0033,
+  0x0035,0x1100,0x1102,0x1103,0x1105,0x1106,0x1107,0x1109,
+  0x110b,0x110c,0x110e,0x110f,0x1110,0x1111,0x1112,0x1100,
+  0x1161,0x1102,0x1161,0x1103,0x1161,0x1105,0x1161,0x1106,
+  0x1161,0x1107,0x1161,0x1109,0x1161,0x110b,0x1161,0x110c,
+  0x1161,0x110e,0x1161,0x110f,0x1161,0x1110,0x1161,0x1111,
+  0x1161,0x1112,0x1161,0x110e,0x1161,0x11b7,0x1100,0x1169,
+  0x110c,0x116e,0x110b,0x1174,0x110b,0x116e,0x4e00,0x4e8c,
+  0x4e09,0x56db,0x4e94,0x516d,0x4e03,0x516b,0x4e5d,0x5341,
+  0x6708,0x706b,0x6c34,0x6728,0x91d1,0x571f,0x65e5,0x682a,
+  0x6709,0x793e,0x540d,0x7279,0x8ca1,0x795d,0x52b4,0x79d8,
+  0x7537,0x5973,0x9069,0x512a,0x5370,0x6ce8,0x9805,0x4f11,
+  0x5199,0x6b63,0x4e0a,0x4e2d,0x4e0b,0x5de6,0x53f3,0x533b,
+  0x5b97,0x5b66,0x76e3,0x4f01,0x8cc7,0x5354,0x591c,0x0033,
+  0x0036,0x0033,0x0037,0x0033,0x0038,0x0033,0x0039,0x0034,
+  0x0030,0x0034,0x0031,0x0034,0x0032,0x0034,0x0033,0x0034,
+  0x0034,0x0034,0x0035,0x0034,0x0036,0x0034,0x0037,0x0034,
+  0x0038,0x0034,0x0039,0x0035,0x0030,0x0031,0x6708,0x0032,
+  0x6708,0x0033,0x6708,0x0034,0x6708,0x0035,0x6708,0x0036,
+  0x6708,0x0037,0x6708,0x0038,0x6708,0x0039,0x6708,0x0031,
+  0x0030,0x6708,0x0031,0x0031,0x6708,0x0031,0x0032,0x6708,
+  0x0048,0x0067,0x0065,0x0072,0x0067,0x0065,0x0056,0x004c,
+  0x0054,0x0044,0x30a2,0x30a4,0x30a6,0x30a8,0x30aa,0x30ab,
+  0x30ad,0x30af,0x30b1,0x30b3,0x30b5,0x30b7,0x30b9,0x30bb,
+  0x30bd,0x30bf,0x30c1,0x30c4,0x30c6,0x30c8,0x30ca,0x30cb,
+  0x30cc,0x30cd,0x30ce,0x30cf,0x30d2,0x30d5,0x30d8,0x30db,
+  0x30de,0x30df,0x30e0,0x30e1,0x30e2,0x30e4,0x30e6,0x30e8,
+  0x30e9,0x30ea,0x30eb,0x30ec,0x30ed,0x30ef,0x30f0,0x30f1,
+  0x30f2,0x30a2,0x30d1,0x30fc,0x30c8,0x30a2,0x30eb,0x30d5,
+  0x30a1,0x30a2,0x30f3,0x30da,0x30a2,0x30a2,0x30fc,0x30eb,
+  0x30a4,0x30cb,0x30f3,0x30b0,0x30a4,0x30f3,0x30c1,0x30a6,
+  0x30a9,0x30f3,0x30a8,0x30b9,0x30af,0x30fc,0x30c9,0x30a8,
+  0x30fc,0x30ab,0x30fc,0x30aa,0x30f3,0x30b9,0x30aa,0x30fc,
+  0x30e0,0x30ab,0x30a4,0x30ea,0x30ab,0x30e9,0x30c3,0x30c8,
+  0x30ab,0x30ed,0x30ea,0x30fc,0x30ac,0x30ed,0x30f3,0x30ac,
+  0x30f3,0x30de,0x30ae,0x30ac,0x30ae,0x30cb,0x30fc,0x30ad,
+  0x30e5,0x30ea,0x30fc,0x30ae,0x30eb,0x30c0,0x30fc,0x30ad,
+  0x30ed,0x30ad,0x30ed,0x30b0,0x30e9,0x30e0,0x30ad,0x30ed,
+  0x30e1,0x30fc,0x30c8,0x30eb,0x30ad,0x30ed,0x30ef,0x30c3,
+  0x30c8,0x30b0,0x30e9,0x30e0,0x30b0,0x30e9,0x30e0,0x30c8,
+  0x30f3,0x30af,0x30eb,0x30bc,0x30a4,0x30ed,0x30af,0x30ed,
+  0x30fc,0x30cd,0x30b1,0x30fc,0x30b9,0x30b3,0x30eb,0x30ca,
+  0x30b3,0x30fc,0x30dd,0x30b5,0x30a4,0x30af,0x30eb,0x30b5,
+  0x30f3,0x30c1,0x30fc,0x30e0,0x30b7,0x30ea,0x30f3,0x30b0,
+  0x30bb,0x30f3,0x30c1,0x30bb,0x30f3,0x30c8,0x30c0,0x30fc,
+  0x30b9,0x30c7,0x30b7,0x30c9,0x30eb,0x30c8,0x30f3,0x30ca,
+  0x30ce,0x30ce,0x30c3,0x30c8,0x30cf,0x30a4,0x30c4,0x30d1,
+  0x30fc,0x30bb,0x30f3,0x30c8,0x30d1,0x30fc,0x30c4,0x30d0,
+  0x30fc,0x30ec,0x30eb,0x30d4,0x30a2,0x30b9,0x30c8,0x30eb,
+  0x30d4,0x30af,0x30eb,0x30d4,0x30b3,0x30d3,0x30eb,0x30d5,
+  0x30a1,0x30e9,0x30c3,0x30c9,0x30d5,0x30a3,0x30fc,0x30c8,
+  0x30d6,0x30c3,0x30b7,0x30a7,0x30eb,0x30d5,0x30e9,0x30f3,
+  0x30d8,0x30af,0x30bf,0x30fc,0x30eb,0x30da,0x30bd,0x30da,
+  0x30cb,0x30d2,0x30d8,0x30eb,0x30c4,0x30da,0x30f3,0x30b9,
+  0x30da,0x30fc,0x30b8,0x30d9,0x30fc,0x30bf,0x30dd,0x30a4,
+  0x30f3,0x30c8,0x30dc,0x30eb,0x30c8,0x30db,0x30f3,0x30dd,
+  0x30f3,0x30c9,0x30db,0x30fc,0x30eb,0x30db,0x30fc,0x30f3,
+  0x30de,0x30a4,0x30af,0x30ed,0x30de,0x30a4,0x30eb,0x30de,
+  0x30c3,0x30cf,0x30de,0x30eb,0x30af,0x30de,0x30f3,0x30b7,
+  0x30e7,0x30f3,0x30df,0x30af,0x30ed,0x30f3,0x30df,0x30ea,
+  0x30df,0x30ea,0x30d0,0x30fc,0x30eb,0x30e1,0x30ac,0x30e1,
+  0x30ac,0x30c8,0x30f3,0x30e1,0x30fc,0x30c8,0x30eb,0x30e4,
+  0x30fc,0x30c9,0x30e4,0x30fc,0x30eb,0x30e6,0x30a2,0x30f3,
+  0x30ea,0x30c3,0x30c8,0x30eb,0x30ea,0x30e9,0x30eb,0x30d4,
+  0x30fc,0x30eb,0x30fc,0x30d6,0x30eb,0x30ec,0x30e0,0x30ec,
+  0x30f3,0x30c8,0x30b2,0x30f3,0x30ef,0x30c3,0x30c8,0x0030,
+  0x70b9,0x0031,0x70b9,0x0032,0x70b9,0x0033,0x70b9,0x0034,
+  0x70b9,0x0035,0x70b9,0x0036,0x70b9,0x0037,0x70b9,0x0038,
+  0x70b9,0x0039,0x70b9,0x0031,0x0030,0x70b9,0x0031,0x0031,
+  0x70b9,0x0031,0x0032,0x70b9,0x0031,0x0033,0x70b9,0x0031,
+  0x0034,0x70b9,0x0031,0x0035,0x70b9,0x0031,0x0036,0x70b9,
+  0x0031,0x0037,0x70b9,0x0031,0x0038,0x70b9,0x0031,0x0039,
+  0x70b9,0x0032,0x0030,0x70b9,0x0032,0x0031,0x70b9,0x0032,
+  0x0032,0x70b9,0x0032,0x0033,0x70b9,0x0032,0x0034,0x70b9,
+  0x0068,0x0050,0x0061,0x0064,0x0061,0x0041,0x0055,0x0062,
+  0x0061,0x0072,0x006f,0x0056,0x0070,0x0063,0x0064,0x006d,
+  0x0064,0x006d,0x00b2,0x0064,0x006d,0x00b3,0x0049,0x0055,
+  0x5e73,0x6210,0x662d,0x548c,0x5927,0x6b63,0x660e,0x6cbb,
+  0x682a,0x5f0f,0x4f1a,0x793e,0x0070,0x0041,0x006e,0x0041,
+  0x03bc,0x0041,0x006d,0x0041,0x006b,0x0041,0x004b,0x0042,
+  0x004d,0x0042,0x0047,0x0042,0x0063,0x0061,0x006c,0x006b,
+  0x0063,0x0061,0x006c,0x0070,0x0046,0x006e,0x0046,0x03bc,
+  0x0046,0x03bc,0x0067,0x006d,0x0067,0x006b,0x0067,0x0048,
+  0x007a,0x006b,0x0048,0x007a,0x004d,0x0048,0x007a,0x0047,
+  0x0048,0x007a,0x0054,0x0048,0x007a,0x03bc,0x2113,0x006d,
+  0x2113,0x0064,0x2113,0x006b,0x2113,0x0066,0x006d,0x006e,
+  0x006d,0x03bc,0x006d,0x006d,0x006d,0x0063,0x006d,0x006b,
+  0x006d,0x006d,0x006d,0x00b2,0x0063,0x006d,0x00b2,0x006d,
+  0x00b2,0x006b,0x006d,0x00b2,0x006d,0x006d,0x00b3,0x0063,
+  0x006d,0x00b3,0x006d,0x00b3,0x006b,0x006d,0x00b3,0x006d,
+  0x2215,0x0073,0x006d,0x2215,0x0073,0x00b2,0x0050,0x0061,
+  0x006b,0x0050,0x0061,0x004d,0x0050,0x0061,0x0047,0x0050,
+  0x0061,0x0072,0x0061,0x0064,0x0072,0x0061,0x0064,0x2215,
+  0x0073,0x0072,0x0061,0x0064,0x2215,0x0073,0x00b2,0x0070,
+  0x0073,0x006e,0x0073,0x03bc,0x0073,0x006d,0x0073,0x0070,
+  0x0056,0x006e,0x0056,0x03bc,0x0056,0x006d,0x0056,0x006b,
+  0x0056,0x004d,0x0056,0x0070,0x0057,0x006e,0x0057,0x03bc,
+  0x0057,0x006d,0x0057,0x006b,0x0057,0x004d,0x0057,0x006b,
+  0x03a9,0x004d,0x03a9,0x0061,0x002e,0x006d,0x002e,0x0042,
+  0x0071,0x0063,0x0063,0x0063,0x0064,0x0043,0x2215,0x006b,
+  0x0067,0x0043,0x006f,0x002e,0x0064,0x0042,0x0047,0x0079,
+  0x0068,0x0061,0x0048,0x0050,0x0069,0x006e,0x004b,0x004b,
+  0x004b,0x004d,0x006b,0x0074,0x006c,0x006d,0x006c,0x006e,
+  0x006c,0x006f,0x0067,0x006c,0x0078,0x006d,0x0062,0x006d,
+  0x0069,0x006c,0x006d,0x006f,0x006c,0x0050,0x0048,0x0070,
+  0x002e,0x006d,0x002e,0x0050,0x0050,0x004d,0x0050,0x0052,
+  0x0073,0x0072,0x0053,0x0076,0x0057,0x0062,0x0056,0x2215,
+  0x006d,0x0041,0x2215,0x006d,0x0031,0x65e5,0x0032,0x65e5,
+  0x0033,0x65e5,0x0034,0x65e5,0x0035,0x65e5,0x0036,0x65e5,
+  0x0037,0x65e5,0x0038,0x65e5,0x0039,0x65e5,0x0031,0x0030,
+  0x65e5,0x0031,0x0031,0x65e5,0x0031,0x0032,0x65e5,0x0031,
+  0x0033,0x65e5,0x0031,0x0034,0x65e5,0x0031,0x0035,0x65e5,
+  0x0031,0x0036,0x65e5,0x0031,0x0037,0x65e5,0x0031,0x0038,
+  0x65e5,0x0031,0x0039,0x65e5,0x0032,0x0030,0x65e5,0x0032,
+  0x0031,0x65e5,0x0032,0x0032,0x65e5,0x0032,0x0033,0x65e5,
+  0x0032,0x0034,0x65e5,0x0032,0x0035,0x65e5,0x0032,0x0036,
+  0x65e5,0x0032,0x0037,0x65e5,0x0032,0x0038,0x65e5,0x0032,
+  0x0039,0x65e5,0x0033,0x0030,0x65e5,0x0033,0x0031,0x65e5,
+  0x0067,0x0061,0x006c
+};
+
+
+#define UCS4_BMPCJKMIN 0xf900
+#define UCS4_BMPCJKMAX 0xface
+
+	/* CJK Compatibility - 0 means hole (no decomposition) */
+static const unsigned short ucs4_bmpcjk1decomptab[463] = {
+  0x8c48,0x66f4,0x8eca,0x8cc8,0x6ed1,0x4e32,0x53e5,0x9f9c,
+  0x9f9c,0x5951,0x91d1,0x5587,0x5948,0x61f6,0x7669,0x7f85,
+  0x863f,0x87ba,0x88f8,0x908f,0x6a02,0x6d1b,0x70d9,0x73de,
+  0x843d,0x916a,0x99f1,0x4e82,0x5375,0x6b04,0x721b,0x862d,
+  0x9e1e,0x5d50,0x6feb,0x85cd,0x8964,0x62c9,0x81d8,0x881f,
+  0x5eca,0x6717,0x6d6a,0x72fc,0x90ce,0x4f86,0x51b7,0x52de,
+  0x64c4,0x6ad3,0x7210,0x76e7,0x8001,0x8606,0x865c,0x8def,
+  0x9732,0x9b6f,0x9dfa,0x788c,0x797f,0x7da0,0x83c9,0x9304,
+  0x9e7f,0x8ad6,0x58df,0x5f04,0x7c60,0x807e,0x7262,0x78ca,
+  0x8cc2,0x96f7,0x58d8,0x5c62,0x6a13,0x6dda,0x6f0f,0x7d2f,
+  0x7e37,0x964b,0x52d2,0x808b,0x51dc,0x51cc,0x7a1c,0x7dbe,
+  0x83f1,0x9675,0x8b80,0x62cf,0x6a02,0x8afe,0x4e39,0x5be7,
+  0x6012,0x7387,0x7570,0x5317,0x78fb,0x4fbf,0x5fa9,0x4e0d,
+  0x6ccc,0x6578,0x7d22,0x53c3,0x585e,0x7701,0x8449,0x8aaa,
+  0x6bba,0x8fb0,0x6c88,0x62fe,0x82e5,0x63a0,0x7565,0x4eae,
+  0x5169,0x51c9,0x6881,0x7ce7,0x826f,0x8ad2,0x91cf,0x52f5,
+  0x5442,0x5973,0x5eec,0x65c5,0x6ffe,0x792a,0x95ad,0x9a6a,
+  0x9e97,0x9ece,0x529b,0x66c6,0x6b77,0x8f62,0x5e74,0x6190,
+  0x6200,0x649a,0x6f23,0x7149,0x7489,0x79ca,0x7df4,0x806f,
+  0x8f26,0x84ee,0x9023,0x934a,0x5217,0x52a3,0x54bd,0x70c8,
+  0x88c2,0x8aaa,0x5ec9,0x5ff5,0x637b,0x6bae,0x7c3e,0x7375,
+  0x4ee4,0x56f9,0x5be7,0x5dba,0x601c,0x73b2,0x7469,0x7f9a,
+  0x8046,0x9234,0x96f6,0x9748,0x9818,0x4f8b,0x79ae,0x91b4,
+  0x96b8,0x60e1,0x4e86,0x50da,0x5bee,0x5c3f,0x6599,0x6a02,
+  0x71ce,0x7642,0x84fc,0x907c,0x9f8d,0x6688,0x962e,0x5289,
+  0x677b,0x67f3,0x6d41,0x6e9c,0x7409,0x7559,0x786b,0x7d10,
+  0x985e,0x516d,0x622e,0x9678,0x502b,0x5d19,0x6dea,0x8f2a,
+  0x5f8b,0x6144,0x6817,0x7387,0x9686,0x5229,0x540f,0x5c65,
+  0x6613,0x674e,0x68a8,0x6ce5,0x7406,0x75e2,0x7f79,0x88cf,
+  0x88e1,0x91cc,0x96e2,0x533f,0x6eba,0x541d,0x71d0,0x7498,
+  0x85fa,0x96a3,0x9c57,0x9e9f,0x6797,0x6dcb,0x81e8,0x7acb,
+  0x7b20,0x7c92,0x72c0,0x7099,0x8b58,0x4ec0,0x8336,0x523a,
+  0x5207,0x5ea6,0x62d3,0x7cd6,0x5b85,0x6d1e,0x66b4,0x8f3b,
+  0x884c,0x964d,0x898b,0x5ed3,0x5140,0x55c0,0x0000,0x0000,
+  0x585a,0x0000,0x6674,0x0000,0x0000,0x51de,0x732a,0x76ca,
+  0x793c,0x795e,0x7965,0x798f,0x9756,0x7cbe,0x7fbd,0x0000,
+  0x8612,0x0000,0x8af8,0x0000,0x0000,0x9038,0x90fd,0x0000,
+  0x0000,0x0000,0x98ef,0x98fc,0x9928,0x9db4,0x0000,0x0000,
+  0x4fae,0x50e7,0x514d,0x52c9,0x52e4,0x5351,0x559d,0x5606,
+  0x5668,0x5840,0x58a8,0x5c64,0x5c6e,0x6094,0x6168,0x618e,
+  0x61f2,0x654f,0x65e2,0x6691,0x6885,0x6d77,0x6e1a,0x6f22,
+  0x716e,0x722b,0x7422,0x7891,0x793e,0x7949,0x7948,0x7950,
+  0x7956,0x795d,0x798d,0x798e,0x7a40,0x7a81,0x7bc0,0x7df4,
+  0x7e09,0x7e41,0x7f72,0x8005,0x81ed,0x8279,0x8279,0x8457,
+  0x8910,0x8996,0x8b01,0x8b39,0x8cd3,0x8d08,0x8fb6,0x9038,
+  0x96e3,0x97ff,0x983b,0x0000,0x0000,0x0000,0x0000,0x0000,
+  0x4e26,0x51b5,0x5168,0x4f80,0x5145,0x5180,0x52c7,0x52fa,
+  0x559d,0x5555,0x5599,0x55e2,0x585a,0x58b3,0x5944,0x5954,
+  0x5a62,0x5b28,0x5ed2,0x5ed9,0x5f69,0x5fad,0x60d8,0x614e,
+  0x6108,0x618e,0x6160,0x61f2,0x6234,0x63c4,0x641c,0x6452,
+  0x6556,0x6674,0x6717,0x671b,0x6756,0x6b79,0x6bba,0x6d41,
+  0x6edb,0x6ecb,0x6f22,0x701e,0x716e,0x77a7,0x7235,0x72af,
+  0x732a,0x7471,0x7506,0x753b,0x761d,0x761f,0x76ca,0x76db,
+  0x76f4,0x774a,0x7740,0x78cc,0x7ab1,0x7bc0,0x7c7b,0x7d5b,
+  0x7df4,0x7f3e,0x8005,0x8352,0x83ef,0x8779,0x8941,0x8986,
+  0x8996,0x8abf,0x8af8,0x8acb,0x8b01,0x8afe,0x8aed,0x8b39,
+  0x8b8a,0x8d08,0x8f38,0x9072,0x9199,0x9276,0x967c,0x96e3,
+  0x9756,0x97db,0x97ff,0x980b,0x983b,0x9b12,0x9f9c
+};
+
+
+#define UCS4_BMPCJK2MIN 0xfacf
+#define UCS4_BMPCJK2MAX 0xfad9
+
+
+	/* CJK Compatibility - some values not in BMP */
+static const unsigned long ucs4_bmpcjk2decomptab[11] = {
+  0x2284a,0x22844,0x233d5, 0x3b9d, 0x4018, 0x4039,
+  0x25249,0x25cd0,0x27ed3, 0x9f43, 0x9f8e
+};
+
+
+#define UCS4_BMPHIMIN 0xfb00
+#define UCS4_BMPHIMAX 0xfefc
+#define UCS4_BMPHIIXMASK 0x7ff
+#define UCS4_BMPHISIZEMASK 0xf800
+#define UCS4_BMPHISIZESHIFT 11
+
+	/* BMP hi decomposition indices - ssss siii iiii iiii */
+static unsigned short ucs4_dbmphiixtab[1021] = {
+0x0800,0x0802,0x0804,0x1006,0x1009,0x080c,0x080e,0x0000,
+0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+0x0000,0x0000,0x0000,0x0810,0x0812,0x0814,0x0816,0x0818,
+0x0000,0x0000,0x0000,0x0000,0x0000,0x081a,0x0000,0x081c,
+0x001e,0x001f,0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,
+0x0026,0x0027,0x0828,0x082a,0x082c,0x082e,0x0830,0x0832,
+0x0834,0x0836,0x0838,0x083a,0x083c,0x083e,0x0840,0x0000,
+0x0842,0x0844,0x0846,0x0848,0x084a,0x0000,0x084c,0x0000,
+0x084e,0x0850,0x0000,0x0852,0x0854,0x0000,0x0856,0x0858,
+0x085a,0x085c,0x085e,0x0860,0x0862,0x0864,0x0866,0x0868,
+0x006a,0x006b,0x006c,0x006d,0x006e,0x006f,0x0070,0x0071,
+0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,
+0x007a,0x007b,0x007c,0x007d,0x007e,0x007f,0x0080,0x0081,
+0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,0x0088,0x0089,
+0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,0x0090,0x0091,
+0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,0x0098,0x0099,
+0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,0x00a0,0x00a1,
+0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,0x00a8,0x00a9,
+0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,0x00b0,0x00b1,
+0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,0x00b8,0x00b9,
+0x00ba,0x00bb,0x00bc,0x00bd,0x00be,0x00bf,0x00c0,0x00c1,
+0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7,0x00c8,0x00c9,
+0x00ca,0x00cb,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+0x0000,0x0000,0x0000,0x00cc,0x00cd,0x00ce,0x00cf,0x00d0,
+0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00d7,0x00d8,
+0x00d9,0x00da,0x00db,0x00dc,0x00dd,0x00de,0x00df,0x00e0,
+0x00e1,0x00e2,0x08e3,0x08e5,0x08e7,0x08e9,0x08eb,0x08ed,
+0x08ef,0x08f1,0x08f3,0x08f5,0x08f7,0x08f9,0x08fb,0x08fd,
+0x08ff,0x0901,0x0903,0x0905,0x0107,0x0108,0x0109,0x010a,
+0x090b,0x090d,0x090f,0x0911,0x0913,0x0915,0x0917,0x0919,
+0x091b,0x091d,0x091f,0x0921,0x0923,0x0925,0x0927,0x0929,
+0x092b,0x092d,0x092f,0x0931,0x0933,0x0935,0x0937,0x0939,
+0x093b,0x093d,0x093f,0x0941,0x0943,0x0945,0x0947,0x0949,
+0x094b,0x094d,0x094f,0x0951,0x0953,0x0955,0x0957,0x0959,
+0x095b,0x095d,0x095f,0x0961,0x0963,0x0965,0x0967,0x0969,
+0x096b,0x096d,0x096f,0x0971,0x0973,0x0975,0x0977,0x0979,
+0x097b,0x097d,0x097f,0x0981,0x0983,0x0985,0x0987,0x0989,
+0x098b,0x098d,0x098f,0x0991,0x0993,0x0995,0x0997,0x0999,
+0x099b,0x099d,0x099f,0x09a1,0x09a3,0x09a5,0x09a7,0x09a9,
+0x09ab,0x09ad,0x09af,0x09b1,0x09b3,0x09b5,0x09b7,0x09b9,
+0x09bb,0x09bd,0x09bf,0x09c1,0x09c3,0x09c5,0x11c7,0x11ca,
+0x11cd,0x11d0,0x11d3,0x11d6,0x09d9,0x09db,0x09dd,0x09df,
+0x09e1,0x09e3,0x09e5,0x09e7,0x09e9,0x09eb,0x09ed,0x09ef,
+0x09f1,0x09f3,0x09f5,0x09f7,0x09f9,0x09fb,0x09fd,0x09ff,
+0x0a01,0x0a03,0x0a05,0x0a07,0x0a09,0x0a0b,0x0a0d,0x0a0f,
+0x0a11,0x0a13,0x0a15,0x0a17,0x0a19,0x0a1b,0x0a1d,0x0a1f,
+0x0a21,0x0a23,0x0a25,0x0a27,0x0a29,0x0a2b,0x0a2d,0x0a2f,
+0x0a31,0x0a33,0x0a35,0x0a37,0x0a39,0x0a3b,0x0a3d,0x0a3f,
+0x0a41,0x0a43,0x0a45,0x0a47,0x0a49,0x0a4b,0x0a4d,0x0a4f,
+0x0a51,0x0a53,0x0a55,0x0a57,0x0a59,0x0a5b,0x0a5d,0x0a5f,
+0x0a61,0x0a63,0x0a65,0x0a67,0x0a69,0x0a6b,0x0a6d,0x0a6f,
+0x0a71,0x0a73,0x0a75,0x0a77,0x0a79,0x0a7b,0x0a7d,0x0a7f,
+0x0a81,0x0a83,0x0a85,0x0a87,0x0a89,0x0a8b,0x0a8d,0x0a8f,
+0x0a91,0x0a93,0x0a95,0x0a97,0x0a99,0x0a9b,0x0a9d,0x0a9f,
+0x0aa1,0x0aa3,0x0aa5,0x0aa7,0x0aa9,0x0aab,0x0aad,0x0aaf,
+0x0ab1,0x0ab3,0x0ab5,0x0ab7,0x0ab9,0x0abb,0x0abd,0x0abf,
+0x0ac1,0x0ac3,0x0ac5,0x0ac7,0x0ac9,0x0acb,0x0acd,0x0acf,
+0x0ad1,0x0ad3,0x0ad5,0x0ad7,0x0ad9,0x0adb,0x0add,0x0adf,
+0x0ae1,0x0ae3,0x0ae5,0x0ae7,0x0ae9,0x0aeb,0x0aed,0x0aef,
+0x0af1,0x0af3,0x12f5,0x12f8,0x12fb,0x0afe,0x0b00,0x0b02,
+0x0b04,0x0b06,0x0b08,0x0b0a,0x0b0c,0x0b0e,0x0b10,0x0b12,
+0x0b14,0x0b16,0x0b18,0x0b1a,0x0b1c,0x0b1e,0x0b20,0x0b22,
+0x0b24,0x0b26,0x0b28,0x0b2a,0x0b2c,0x0b2e,0x0b30,0x0b32,
+0x0b34,0x0b36,0x0b38,0x0b3a,0x0b3c,0x0b3e,0x0b40,0x0b42,
+0x0b44,0x0b46,0x0b48,0x0b4a,0x0b4c,0x0b4e,0x0b50,0x0b52,
+0x0b54,0x0b56,0x0b58,0x0b5a,0x0b5c,0x0b5e,0x0b60,0x0b62,
+0x0b64,0x0b66,0x0b68,0x0b6a,0x0b6c,0x0b6e,0x0b70,0x0b72,
+0x0b74,0x0b76,0x0b78,0x0b7a,0x0b7c,0x0b7e,0x0b80,0x0b82,
+0x0b84,0x0b86,0x0b88,0x0b8a,0x0b8c,0x0b8e,0x0000,0x0000,
+0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+0x1390,0x1393,0x1396,0x1399,0x139c,0x139f,0x13a2,0x13a5,
+0x13a8,0x13ab,0x13ae,0x13b1,0x13b4,0x13b7,0x13ba,0x13bd,
+0x13c0,0x13c3,0x13c6,0x13c9,0x13cc,0x13cf,0x13d2,0x13d5,
+0x13d8,0x13db,0x13de,0x13e1,0x13e4,0x13e7,0x13ea,0x13ed,
+0x13f0,0x13f3,0x13f6,0x13f9,0x13fc,0x13ff,0x1402,0x1405,
+0x1408,0x140b,0x140e,0x1411,0x1414,0x1417,0x141a,0x141d,
+0x1420,0x1423,0x1426,0x1429,0x142c,0x142f,0x1432,0x1435,
+0x1438,0x143b,0x143e,0x1441,0x1444,0x1447,0x144a,0x144d,
+0x0000,0x0000,0x1450,0x1453,0x1456,0x1459,0x145c,0x145f,
+0x1462,0x1465,0x1468,0x146b,0x146e,0x1471,0x1474,0x1477,
+0x147a,0x147d,0x1480,0x1483,0x1486,0x1489,0x148c,0x148f,
+0x1492,0x1495,0x1498,0x149b,0x149e,0x14a1,0x14a4,0x14a7,
+0x14aa,0x14ad,0x14b0,0x14b3,0x14b6,0x14b9,0x14bc,0x14bf,
+0x14c2,0x14c5,0x14c8,0x14cb,0x14ce,0x14d1,0x14d4,0x14d7,
+0x14da,0x14dd,0x14e0,0x14e3,0x14e6,0x14e9,0x14ec,0x14ef,
+0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+0x14f2,0x14f5,0x1cf8,0x1cfc,0x1d00,0x1d04,0x1d08,0x1d0c,
+0x1d10,0x1514,0x8d17,0x3d29,0x1d31,0x0000,0x0000,0x0000,
+0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+0x0535,0x0536,0x0537,0x0538,0x0539,0x053a,0x053b,0x053c,
+0x053d,0x053e,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+0x053f,0x0540,0x0541,0x0542,0x0543,0x0544,0x0545,0x0546,
+0x0547,0x0548,0x0549,0x054a,0x054b,0x054c,0x054d,0x054e,
+0x054f,0x0550,0x0551,0x0552,0x0553,0x0000,0x0000,0x0554,
+0x0555,0x0556,0x0557,0x0558,0x0559,0x055a,0x055b,0x055c,
+0x055d,0x055e,0x055f,0x0000,0x0560,0x0561,0x0562,0x0563,
+0x0564,0x0565,0x0566,0x0567,0x0568,0x0569,0x056a,0x056b,
+0x056c,0x056d,0x056e,0x056f,0x0570,0x0571,0x0572,0x0000,
+0x0573,0x0574,0x0575,0x0576,0x0000,0x0000,0x0000,0x0000,
+0x0d77,0x0d79,0x0d7b,0x0000,0x0d7d,0x0000,0x0d7f,0x0d81,
+0x0d83,0x0d85,0x0d87,0x0d89,0x0d8b,0x0d8d,0x0d8f,0x0d91,
+0x0593,0x0594,0x0595,0x0596,0x0597,0x0598,0x0599,0x059a,
+0x059b,0x059c,0x059d,0x059e,0x059f,0x05a0,0x05a1,0x05a2,
+0x05a3,0x05a4,0x05a5,0x05a6,0x05a7,0x05a8,0x05a9,0x05aa,
+0x05ab,0x05ac,0x05ad,0x05ae,0x05af,0x05b0,0x05b1,0x05b2,
+0x05b3,0x05b4,0x05b5,0x05b6,0x05b7,0x05b8,0x05b9,0x05ba,
+0x05bb,0x05bc,0x05bd,0x05be,0x05bf,0x05c0,0x05c1,0x05c2,
+0x05c3,0x05c4,0x05c5,0x05c6,0x05c7,0x05c8,0x05c9,0x05ca,
+0x05cb,0x05cc,0x05cd,0x05ce,0x05cf,0x05d0,0x05d1,0x05d2,
+0x05d3,0x05d4,0x05d5,0x05d6,0x05d7,0x05d8,0x05d9,0x05da,
+0x05db,0x05dc,0x05dd,0x05de,0x05df,0x05e0,0x05e1,0x05e2,
+0x05e3,0x05e4,0x05e5,0x05e6,0x05e7,0x05e8,0x05e9,0x05ea,
+0x05eb,0x05ec,0x05ed,0x05ee,0x05ef,0x05f0,0x05f1,0x05f2,
+0x05f3,0x05f4,0x05f5,0x05f6,0x05f7,0x05f8,0x05f9,0x05fa,
+0x05fb,0x05fc,0x05fd,0x05fe,0x05ff,0x0600,0x0601,0x0602,
+0x0603,0x0604,0x0605,0x0606,0x0607,0x0e08,0x0e0a,0x0e0c,
+0x0e0e,0x0e10,0x0e12,0x0e14,0x0e16
+};
+
+	/* BMP high decompositions */
+static unsigned short ucs4_dbmphitab[1560] = {
+0x0066,0x0066,0x0066,0x0069,0x0066,0x006c,0x0066,0x0066,
+0x0069,0x0066,0x0066,0x006c,0x017f,0x0074,0x0073,0x0074,
+0x0574,0x0576,0x0574,0x0565,0x0574,0x056b,0x057e,0x0576,
+0x0574,0x056d,0x05d9,0x05b4,0x05f2,0x05b7,0x05e2,0x05d0,
+0x05d3,0x05d4,0x05db,0x05dc,0x05dd,0x05e8,0x05ea,0x002b,
+0x05e9,0x05c1,0x05e9,0x05c2,0xfb49,0x05c1,0xfb49,0x05c2,
+0x05d0,0x05b7,0x05d0,0x05b8,0x05d0,0x05bc,0x05d1,0x05bc,
+0x05d2,0x05bc,0x05d3,0x05bc,0x05d4,0x05bc,0x05d5,0x05bc,
+0x05d6,0x05bc,0x05d8,0x05bc,0x05d9,0x05bc,0x05da,0x05bc,
+0x05db,0x05bc,0x05dc,0x05bc,0x05de,0x05bc,0x05e0,0x05bc,
+0x05e1,0x05bc,0x05e3,0x05bc,0x05e4,0x05bc,0x05e6,0x05bc,
+0x05e7,0x05bc,0x05e8,0x05bc,0x05e9,0x05bc,0x05ea,0x05bc,
+0x05d5,0x05b9,0x05d1,0x05bf,0x05db,0x05bf,0x05e4,0x05bf,
+0x05d0,0x05dc,0x0671,0x0671,0x067b,0x067b,0x067b,0x067b,
+0x067e,0x067e,0x067e,0x067e,0x0680,0x0680,0x0680,0x0680,
+0x067a,0x067a,0x067a,0x067a,0x067f,0x067f,0x067f,0x067f,
+0x0679,0x0679,0x0679,0x0679,0x06a4,0x06a4,0x06a4,0x06a4,
+0x06a6,0x06a6,0x06a6,0x06a6,0x0684,0x0684,0x0684,0x0684,
+0x0683,0x0683,0x0683,0x0683,0x0686,0x0686,0x0686,0x0686,
+0x0687,0x0687,0x0687,0x0687,0x068d,0x068d,0x068c,0x068c,
+0x068e,0x068e,0x0688,0x0688,0x0698,0x0698,0x0691,0x0691,
+0x06a9,0x06a9,0x06a9,0x06a9,0x06af,0x06af,0x06af,0x06af,
+0x06b3,0x06b3,0x06b3,0x06b3,0x06b1,0x06b1,0x06b1,0x06b1,
+0x06ba,0x06ba,0x06bb,0x06bb,0x06bb,0x06bb,0x06c0,0x06c0,
+0x06c1,0x06c1,0x06c1,0x06c1,0x06be,0x06be,0x06be,0x06be,
+0x06d2,0x06d2,0x06d3,0x06d3,0x06ad,0x06ad,0x06ad,0x06ad,
+0x06c7,0x06c7,0x06c6,0x06c6,0x06c8,0x06c8,0x0677,0x06cb,
+0x06cb,0x06c5,0x06c5,0x06c9,0x06c9,0x06d0,0x06d0,0x06d0,
+0x06d0,0x0649,0x0649,0x0626,0x0627,0x0626,0x0627,0x0626,
+0x06d5,0x0626,0x06d5,0x0626,0x0648,0x0626,0x0648,0x0626,
+0x06c7,0x0626,0x06c7,0x0626,0x06c6,0x0626,0x06c6,0x0626,
+0x06c8,0x0626,0x06c8,0x0626,0x06d0,0x0626,0x06d0,0x0626,
+0x06d0,0x0626,0x0649,0x0626,0x0649,0x0626,0x0649,0x06cc,
+0x06cc,0x06cc,0x06cc,0x0626,0x062c,0x0626,0x062d,0x0626,
+0x0645,0x0626,0x0649,0x0626,0x064a,0x0628,0x062c,0x0628,
+0x062d,0x0628,0x062e,0x0628,0x0645,0x0628,0x0649,0x0628,
+0x064a,0x062a,0x062c,0x062a,0x062d,0x062a,0x062e,0x062a,
+0x0645,0x062a,0x0649,0x062a,0x064a,0x062b,0x062c,0x062b,
+0x0645,0x062b,0x0649,0x062b,0x064a,0x062c,0x062d,0x062c,
+0x0645,0x062d,0x062c,0x062d,0x0645,0x062e,0x062c,0x062e,
+0x062d,0x062e,0x0645,0x0633,0x062c,0x0633,0x062d,0x0633,
+0x062e,0x0633,0x0645,0x0635,0x062d,0x0635,0x0645,0x0636,
+0x062c,0x0636,0x062d,0x0636,0x062e,0x0636,0x0645,0x0637,
+0x062d,0x0637,0x0645,0x0638,0x0645,0x0639,0x062c,0x0639,
+0x0645,0x063a,0x062c,0x063a,0x0645,0x0641,0x062c,0x0641,
+0x062d,0x0641,0x062e,0x0641,0x0645,0x0641,0x0649,0x0641,
+0x064a,0x0642,0x062d,0x0642,0x0645,0x0642,0x0649,0x0642,
+0x064a,0x0643,0x0627,0x0643,0x062c,0x0643,0x062d,0x0643,
+0x062e,0x0643,0x0644,0x0643,0x0645,0x0643,0x0649,0x0643,
+0x064a,0x0644,0x062c,0x0644,0x062d,0x0644,0x062e,0x0644,
+0x0645,0x0644,0x0649,0x0644,0x064a,0x0645,0x062c,0x0645,
+0x062d,0x0645,0x062e,0x0645,0x0645,0x0645,0x0649,0x0645,
+0x064a,0x0646,0x062c,0x0646,0x062d,0x0646,0x062e,0x0646,
+0x0645,0x0646,0x0649,0x0646,0x064a,0x0647,0x062c,0x0647,
+0x0645,0x0647,0x0649,0x0647,0x064a,0x064a,0x062c,0x064a,
+0x062d,0x064a,0x062e,0x064a,0x0645,0x064a,0x0649,0x064a,
+0x064a,0x0630,0x0670,0x0631,0x0670,0x0649,0x0670,0x0020,
+0x064c,0x0651,0x0020,0x064d,0x0651,0x0020,0x064e,0x0651,
+0x0020,0x064f,0x0651,0x0020,0x0650,0x0651,0x0020,0x0651,
+0x0670,0x0626,0x0631,0x0626,0x0632,0x0626,0x0645,0x0626,
+0x0646,0x0626,0x0649,0x0626,0x064a,0x0628,0x0631,0x0628,
+0x0632,0x0628,0x0645,0x0628,0x0646,0x0628,0x0649,0x0628,
+0x064a,0x062a,0x0631,0x062a,0x0632,0x062a,0x0645,0x062a,
+0x0646,0x062a,0x0649,0x062a,0x064a,0x062b,0x0631,0x062b,
+0x0632,0x062b,0x0645,0x062b,0x0646,0x062b,0x0649,0x062b,
+0x064a,0x0641,0x0649,0x0641,0x064a,0x0642,0x0649,0x0642,
+0x064a,0x0643,0x0627,0x0643,0x0644,0x0643,0x0645,0x0643,
+0x0649,0x0643,0x064a,0x0644,0x0645,0x0644,0x0649,0x0644,
+0x064a,0x0645,0x0627,0x0645,0x0645,0x0646,0x0631,0x0646,
+0x0632,0x0646,0x0645,0x0646,0x0646,0x0646,0x0649,0x0646,
+0x064a,0x0649,0x0670,0x064a,0x0631,0x064a,0x0632,0x064a,
+0x0645,0x064a,0x0646,0x064a,0x0649,0x064a,0x064a,0x0626,
+0x062c,0x0626,0x062d,0x0626,0x062e,0x0626,0x0645,0x0626,
+0x0647,0x0628,0x062c,0x0628,0x062d,0x0628,0x062e,0x0628,
+0x0645,0x0628,0x0647,0x062a,0x062c,0x062a,0x062d,0x062a,
+0x062e,0x062a,0x0645,0x062a,0x0647,0x062b,0x0645,0x062c,
+0x062d,0x062c,0x0645,0x062d,0x062c,0x062d,0x0645,0x062e,
+0x062c,0x062e,0x0645,0x0633,0x062c,0x0633,0x062d,0x0633,
+0x062e,0x0633,0x0645,0x0635,0x062d,0x0635,0x062e,0x0635,
+0x0645,0x0636,0x062c,0x0636,0x062d,0x0636,0x062e,0x0636,
+0x0645,0x0637,0x062d,0x0638,0x0645,0x0639,0x062c,0x0639,
+0x0645,0x063a,0x062c,0x063a,0x0645,0x0641,0x062c,0x0641,
+0x062d,0x0641,0x062e,0x0641,0x0645,0x0642,0x062d,0x0642,
+0x0645,0x0643,0x062c,0x0643,0x062d,0x0643,0x062e,0x0643,
+0x0644,0x0643,0x0645,0x0644,0x062c,0x0644,0x062d,0x0644,
+0x062e,0x0644,0x0645,0x0644,0x0647,0x0645,0x062c,0x0645,
+0x062d,0x0645,0x062e,0x0645,0x0645,0x0646,0x062c,0x0646,
+0x062d,0x0646,0x062e,0x0646,0x0645,0x0646,0x0647,0x0647,
+0x062c,0x0647,0x0645,0x0647,0x0670,0x064a,0x062c,0x064a,
+0x062d,0x064a,0x062e,0x064a,0x0645,0x064a,0x0647,0x0626,
+0x0645,0x0626,0x0647,0x0628,0x0645,0x0628,0x0647,0x062a,
+0x0645,0x062a,0x0647,0x062b,0x0645,0x062b,0x0647,0x0633,
+0x0645,0x0633,0x0647,0x0634,0x0645,0x0634,0x0647,0x0643,
+0x0644,0x0643,0x0645,0x0644,0x0645,0x0646,0x0645,0x0646,
+0x0647,0x064a,0x0645,0x064a,0x0647,0x0640,0x064e,0x0651,
+0x0640,0x064f,0x0651,0x0640,0x0650,0x0651,0x0637,0x0649,
+0x0637,0x064a,0x0639,0x0649,0x0639,0x064a,0x063a,0x0649,
+0x063a,0x064a,0x0633,0x0649,0x0633,0x064a,0x0634,0x0649,
+0x0634,0x064a,0x062d,0x0649,0x062d,0x064a,0x062c,0x0649,
+0x062c,0x064a,0x062e,0x0649,0x062e,0x064a,0x0635,0x0649,
+0x0635,0x064a,0x0636,0x0649,0x0636,0x064a,0x0634,0x062c,
+0x0634,0x062d,0x0634,0x062e,0x0634,0x0645,0x0634,0x0631,
+0x0633,0x0631,0x0635,0x0631,0x0636,0x0631,0x0637,0x0649,
+0x0637,0x064a,0x0639,0x0649,0x0639,0x064a,0x063a,0x0649,
+0x063a,0x064a,0x0633,0x0649,0x0633,0x064a,0x0634,0x0649,
+0x0634,0x064a,0x062d,0x0649,0x062d,0x064a,0x062c,0x0649,
+0x062c,0x064a,0x062e,0x0649,0x062e,0x064a,0x0635,0x0649,
+0x0635,0x064a,0x0636,0x0649,0x0636,0x064a,0x0634,0x062c,
+0x0634,0x062d,0x0634,0x062e,0x0634,0x0645,0x0634,0x0631,
+0x0633,0x0631,0x0635,0x0631,0x0636,0x0631,0x0634,0x062c,
+0x0634,0x062d,0x0634,0x062e,0x0634,0x0645,0x0633,0x0647,
+0x0634,0x0647,0x0637,0x0645,0x0633,0x062c,0x0633,0x062d,
+0x0633,0x062e,0x0634,0x062c,0x0634,0x062d,0x0634,0x062e,
+0x0637,0x0645,0x0638,0x0645,0x0627,0x064b,0x0627,0x064b,
+0x062a,0x062c,0x0645,0x062a,0x062d,0x062c,0x062a,0x062d,
+0x062c,0x062a,0x062d,0x0645,0x062a,0x062e,0x0645,0x062a,
+0x0645,0x062c,0x062a,0x0645,0x062d,0x062a,0x0645,0x062e,
+0x062c,0x0645,0x062d,0x062c,0x0645,0x062d,0x062d,0x0645,
+0x064a,0x062d,0x0645,0x0649,0x0633,0x062d,0x062c,0x0633,
+0x062c,0x062d,0x0633,0x062c,0x0649,0x0633,0x0645,0x062d,
+0x0633,0x0645,0x062d,0x0633,0x0645,0x062c,0x0633,0x0645,
+0x0645,0x0633,0x0645,0x0645,0x0635,0x062d,0x062d,0x0635,
+0x062d,0x062d,0x0635,0x0645,0x0645,0x0634,0x062d,0x0645,
+0x0634,0x062d,0x0645,0x0634,0x062c,0x064a,0x0634,0x0645,
+0x062e,0x0634,0x0645,0x062e,0x0634,0x0645,0x0645,0x0634,
+0x0645,0x0645,0x0636,0x062d,0x0649,0x0636,0x062e,0x0645,
+0x0636,0x062e,0x0645,0x0637,0x0645,0x062d,0x0637,0x0645,
+0x062d,0x0637,0x0645,0x0645,0x0637,0x0645,0x064a,0x0639,
+0x062c,0x0645,0x0639,0x0645,0x0645,0x0639,0x0645,0x0645,
+0x0639,0x0645,0x0649,0x063a,0x0645,0x0645,0x063a,0x0645,
+0x064a,0x063a,0x0645,0x0649,0x0641,0x062e,0x0645,0x0641,
+0x062e,0x0645,0x0642,0x0645,0x062d,0x0642,0x0645,0x0645,
+0x0644,0x062d,0x0645,0x0644,0x062d,0x064a,0x0644,0x062d,
+0x0649,0x0644,0x062c,0x062c,0x0644,0x062c,0x062c,0x0644,
+0x062e,0x0645,0x0644,0x062e,0x0645,0x0644,0x0645,0x062d,
+0x0644,0x0645,0x062d,0x0645,0x062d,0x062c,0x0645,0x062d,
+0x0645,0x0645,0x062d,0x064a,0x0645,0x062c,0x062d,0x0645,
+0x062c,0x0645,0x0645,0x062e,0x062c,0x0645,0x062e,0x0645,
+0x0645,0x062c,0x062e,0x0647,0x0645,0x062c,0x0647,0x0645,
+0x0645,0x0646,0x062d,0x0645,0x0646,0x062d,0x0649,0x0646,
+0x062c,0x0645,0x0646,0x062c,0x0645,0x0646,0x062c,0x0649,
+0x0646,0x0645,0x064a,0x0646,0x0645,0x0649,0x064a,0x0645,
+0x0645,0x064a,0x0645,0x0645,0x0628,0x062e,0x064a,0x062a,
+0x062c,0x064a,0x062a,0x062c,0x0649,0x062a,0x062e,0x064a,
+0x062a,0x062e,0x0649,0x062a,0x0645,0x064a,0x062a,0x0645,
+0x0649,0x062c,0x0645,0x064a,0x062c,0x062d,0x0649,0x062c,
+0x0645,0x0649,0x0633,0x062e,0x0649,0x0635,0x062d,0x064a,
+0x0634,0x062d,0x064a,0x0636,0x062d,0x064a,0x0644,0x062c,
+0x064a,0x0644,0x0645,0x064a,0x064a,0x062d,0x064a,0x064a,
+0x062c,0x064a,0x064a,0x0645,0x064a,0x0645,0x0645,0x064a,
+0x0642,0x0645,0x064a,0x0646,0x062d,0x064a,0x0642,0x0645,
+0x062d,0x0644,0x062d,0x0645,0x0639,0x0645,0x064a,0x0643,
+0x0645,0x064a,0x0646,0x062c,0x062d,0x0645,0x062e,0x064a,
+0x0644,0x062c,0x0645,0x0643,0x0645,0x0645,0x0644,0x062c,
+0x0645,0x0646,0x062c,0x062d,0x062c,0x062d,0x064a,0x062d,
+0x062c,0x064a,0x0645,0x062c,0x064a,0x0641,0x0645,0x064a,
+0x0628,0x062d,0x064a,0x0643,0x0645,0x0645,0x0639,0x062c,
+0x0645,0x0635,0x0645,0x0645,0x0633,0x062e,0x064a,0x0646,
+0x062c,0x064a,0x0635,0x0644,0x06d2,0x0642,0x0644,0x06d2,
+0x0627,0x0644,0x0644,0x0647,0x0627,0x0643,0x0628,0x0631,
+0x0645,0x062d,0x0645,0x062f,0x0635,0x0644,0x0639,0x0645,
+0x0631,0x0633,0x0648,0x0644,0x0639,0x0644,0x064a,0x0647,
+0x0648,0x0633,0x0644,0x0645,0x0635,0x0644,0x0649,0x0635,
+0x0644,0x0649,0x0020,0x0627,0x0644,0x0644,0x0647,0x0020,
+0x0639,0x0644,0x064a,0x0647,0x0020,0x0648,0x0633,0x0644,
+0x0645,0x062c,0x0644,0x0020,0x062c,0x0644,0x0627,0x0644,
+0x0647,0x0631,0x06cc,0x0627,0x0644,0x002c,0x3001,0x3002,
+0x003a,0x003b,0x0021,0x003f,0x3016,0x3017,0x2026,0x2025,
+0x2014,0x2013,0x005f,0x005f,0x0028,0x0029,0x007b,0x007d,
+0x3014,0x3015,0x3010,0x3011,0x300a,0x300b,0x3008,0x3009,
+0x300c,0x300d,0x300e,0x300f,0x005b,0x005d,0x203e,0x203e,
+0x203e,0x203e,0x005f,0x005f,0x005f,0x002c,0x3001,0x002e,
+0x003b,0x003a,0x003f,0x0021,0x2014,0x0028,0x0029,0x007b,
+0x007d,0x3014,0x3015,0x0023,0x0026,0x002a,0x002b,0x002d,
+0x003c,0x003e,0x003d,0x005c,0x0024,0x0025,0x0040,0x0020,
+0x064b,0x0640,0x064b,0x0020,0x064c,0x0020,0x064d,0x0020,
+0x064e,0x0640,0x064e,0x0020,0x064f,0x0640,0x064f,0x0020,
+0x0650,0x0640,0x0650,0x0020,0x0651,0x0640,0x0651,0x0020,
+0x0652,0x0640,0x0652,0x0621,0x0622,0x0622,0x0623,0x0623,
+0x0624,0x0624,0x0625,0x0625,0x0626,0x0626,0x0626,0x0626,
+0x0627,0x0627,0x0628,0x0628,0x0628,0x0628,0x0629,0x0629,
+0x062a,0x062a,0x062a,0x062a,0x062b,0x062b,0x062b,0x062b,
+0x062c,0x062c,0x062c,0x062c,0x062d,0x062d,0x062d,0x062d,
+0x062e,0x062e,0x062e,0x062e,0x062f,0x062f,0x0630,0x0630,
+0x0631,0x0631,0x0632,0x0632,0x0633,0x0633,0x0633,0x0633,
+0x0634,0x0634,0x0634,0x0634,0x0635,0x0635,0x0635,0x0635,
+0x0636,0x0636,0x0636,0x0636,0x0637,0x0637,0x0637,0x0637,
+0x0638,0x0638,0x0638,0x0638,0x0639,0x0639,0x0639,0x0639,
+0x063a,0x063a,0x063a,0x063a,0x0641,0x0641,0x0641,0x0641,
+0x0642,0x0642,0x0642,0x0642,0x0643,0x0643,0x0643,0x0643,
+0x0644,0x0644,0x0644,0x0644,0x0645,0x0645,0x0645,0x0645,
+0x0646,0x0646,0x0646,0x0646,0x0647,0x0647,0x0647,0x0647,
+0x0648,0x0648,0x0649,0x0649,0x064a,0x064a,0x064a,0x064a,
+0x0644,0x0622,0x0644,0x0622,0x0644,0x0623,0x0644,0x0623,
+0x0644,0x0625,0x0644,0x0625,0x0644,0x0627,0x0644,0x0627,
+};
+
+
+#define UCS4_BMPHALFFULLMIN 0xff00
+#define UCS4_BMPHALFFULLMAX 0xffef
+
+static const unsigned short ucs4_bmphalffulldecomptab[240] = {
+  0x0000,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,
+  0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f,
+  0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,
+  0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f,
+  0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,
+  0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,
+  0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,
+  0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f,
+  0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,
+  0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f,
+  0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,
+  0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x2985,
+  0x2986,0x3002,0x300c,0x300d,0x3001,0x30fb,0x30f2,0x30a1,
+  0x30a3,0x30a5,0x30a7,0x30a9,0x30e3,0x30e5,0x30e7,0x30c3,
+  0x30fc,0x30a2,0x30a4,0x30a6,0x30a8,0x30aa,0x30ab,0x30ad,
+  0x30af,0x30b1,0x30b3,0x30b5,0x30b7,0x30b9,0x30bb,0x30bd,
+  0x30bf,0x30c1,0x30c4,0x30c6,0x30c8,0x30ca,0x30cb,0x30cc,
+  0x30cd,0x30ce,0x30cf,0x30d2,0x30d5,0x30d8,0x30db,0x30de,
+  0x30df,0x30e0,0x30e1,0x30e2,0x30e4,0x30e6,0x30e8,0x30e9,
+  0x30ea,0x30eb,0x30ec,0x30ed,0x30ef,0x30f3,0x3099,0x309a,
+  0x3164,0x3131,0x3132,0x3133,0x3134,0x3135,0x3136,0x3137,
+  0x3138,0x3139,0x313a,0x313b,0x313c,0x313d,0x313e,0x313f,
+  0x3140,0x3141,0x3142,0x3143,0x3144,0x3145,0x3146,0x3147,
+  0x3148,0x3149,0x314a,0x314b,0x314c,0x314d,0x314e,0x0000,
+  0x0000,0x0000,0x314f,0x3150,0x3151,0x3152,0x3153,0x3154,
+  0x0000,0x0000,0x3155,0x3156,0x3157,0x3158,0x3159,0x315a,
+  0x0000,0x0000,0x315b,0x315c,0x315d,0x315e,0x315f,0x3160,
+  0x0000,0x0000,0x3161,0x3162,0x3163,0x0000,0x0000,0x0000,
+  0x00a2,0x00a3,0x00ac,0x00af,0x00a6,0x00a5,0x20a9,0x0000,
+  0x2502,0x2190,0x2191,0x2192,0x2193,0x25a0,0x25cb,0x0000
+};
+
+/* SMP decompositions */
+
+	/* Musical */
+
+#define UCS4_SMPMUSIC1MIN 0x1d15e
+#define UCS4_SMPMUSIC1MAX 0x1d164
+
+static const unsigned long ucs4_smpmusic1decomptab[7][2] = {
+  {0x1d157,0x1d165},{0x1d158,0x1d165},{0x1d15f,0x1d16e},{0x1d15f,0x1d16f},
+  {0x1d15f,0x1d170},{0x1d15f,0x1d171},{0x1d15f,0x1d172}
+};
+
+
+#define UCS4_SMPMUSIC2MIN 0x1d1bb
+#define UCS4_SMPMUSIC2MAX 0x1d1c0
+
+static const unsigned long ucs4_smpmusic2decomptab[6][2] = {
+  {0x1d1b9,0x1d165},{0x1d1ba,0x1d165},{0x1d1bb,0x1d16e},
+  {0x1d1bc,0x1d16e},{0x1d1bb,0x1d16f},{0x1d1bc,0x1d16f}
+};
+
+
+#define UCS4_SMPMATHMIN 0x1d400
+#define UCS4_SMPMATHMAX 0x1d7ff
+
+	/* Mathematical - 0 means hole (no decomposition) */
+static const unsigned short ucs4_smpmathdecomptab[1024] = {
+  0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,
+  0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,0x0050,
+  0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,
+  0x0059,0x005a,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,
+  0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,
+  0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,
+  0x0077,0x0078,0x0079,0x007a,0x0041,0x0042,0x0043,0x0044,
+  0x0045,0x0046,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c,
+  0x004d,0x004e,0x004f,0x0050,0x0051,0x0052,0x0053,0x0054,
+  0x0055,0x0056,0x0057,0x0058,0x0059,0x005a,0x0061,0x0062,
+  0x0063,0x0064,0x0065,0x0066,0x0067,0x0000,0x0069,0x006a,
+  0x006b,0x006c,0x006d,0x006e,0x006f,0x0070,0x0071,0x0072,
+  0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a,
+  0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,
+  0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,0x0050,
+  0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,
+  0x0059,0x005a,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,
+  0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,
+  0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,
+  0x0077,0x0078,0x0079,0x007a,0x0041,0x0000,0x0043,0x0044,
+  0x0000,0x0000,0x0047,0x0000,0x004a,0x004b,0x0000,0x0000,
+  0x004e,0x004f,0x0050,0x0051,0x0000,0x0053,0x0054,0x0055,
+  0x0000,0x0056,0x0057,0x0058,0x0059,0x005a,0x0061,0x0062,
+  0x0063,0x0064,0x0000,0x0066,0x0000,0x0068,0x0069,0x006a,
+  0x006b,0x006c,0x006d,0x006e,0x0000,0x0070,0x0071,0x0072,
+  0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a,
+  0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,
+  0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,0x0050,
+  0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,
+  0x0059,0x005a,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,
+  0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,
+  0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,
+  0x0077,0x0078,0x0079,0x007a,0x0041,0x0042,0x0000,0x0044,
+  0x0045,0x0046,0x0047,0x0000,0x004a,0x004b,0x004c,0x004d,
+  0x0000,0x004e,0x004f,0x0050,0x0051,0x0000,0x0053,0x0054,
+  0x0055,0x0056,0x0057,0x0058,0x0059,0x0000,0x0061,0x0062,
+  0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006a,
+  0x006b,0x006c,0x006d,0x006e,0x006f,0x0070,0x0071,0x0072,
+  0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a,
+  0x0041,0x0042,0x0000,0x0044,0x0045,0x0046,0x0047,0x0000,
+  0x0049,0x004a,0x004b,0x004c,0x004d,0x0000,0x004f,0x0000,
+  0x0000,0x0000,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,
+  0x0059,0x0000,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,
+  0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,
+  0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,
+  0x0077,0x0078,0x0079,0x007a,0x0041,0x0042,0x0043,0x0044,
+  0x0045,0x0046,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c,
+  0x004d,0x004e,0x004f,0x0050,0x0051,0x0052,0x0053,0x0054,
+  0x0055,0x0056,0x0057,0x0058,0x0059,0x005a,0x0061,0x0062,
+  0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006a,
+  0x006b,0x006c,0x006d,0x006e,0x006f,0x0070,0x0071,0x0072,
+  0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a,
+  0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,
+  0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,0x0050,
+  0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,
+  0x0059,0x005a,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,
+  0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,
+  0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,
+  0x0077,0x0078,0x0079,0x007a,0x0041,0x0042,0x0043,0x0044,
+  0x0045,0x0046,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c,
+  0x004d,0x004e,0x004f,0x0050,0x0051,0x0052,0x0053,0x0054,
+  0x0055,0x0056,0x0057,0x0058,0x0059,0x005a,0x0061,0x0062,
+  0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006a,
+  0x006b,0x006c,0x006d,0x006e,0x006f,0x0070,0x0071,0x0072,
+  0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a,
+  0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,
+  0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,0x0050,
+  0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,
+  0x0059,0x005a,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,
+  0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,
+  0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,
+  0x0077,0x0078,0x0079,0x007a,0x0041,0x0042,0x0043,0x0044,
+  0x0045,0x0046,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c,
+  0x004d,0x004e,0x004f,0x0050,0x0051,0x0052,0x0053,0x0054,
+  0x0055,0x0056,0x0057,0x0058,0x0059,0x005a,0x0061,0x0062,
+  0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006a,
+  0x006b,0x006c,0x006d,0x006e,0x006f,0x0070,0x0071,0x0072,
+  0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a,
+  0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,
+  0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,0x0050,
+  0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,
+  0x0059,0x005a,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,
+  0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,
+  0x006f,0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,
+  0x0077,0x0078,0x0079,0x007a,0x0131,0x0237,0x0000,0x0000,
+  0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,0x0398,
+  0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0,
+  0x03a1,0x03f4,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,0x03a8,
+  0x03a9,0x2207,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,
+  0x03b7,0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,
+  0x03bf,0x03c0,0x03c1,0x03c2,0x03c3,0x03c4,0x03c5,0x03c6,
+  0x03c7,0x03c8,0x03c9,0x2202,0x03f5,0x03d1,0x03f0,0x03d5,
+  0x03f1,0x03d6,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,
+  0x0397,0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,
+  0x039f,0x03a0,0x03a1,0x03f4,0x03a3,0x03a4,0x03a5,0x03a6,
+  0x03a7,0x03a8,0x03a9,0x2207,0x03b1,0x03b2,0x03b3,0x03b4,
+  0x03b5,0x03b6,0x03b7,0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,
+  0x03bd,0x03be,0x03bf,0x03c0,0x03c1,0x03c2,0x03c3,0x03c4,
+  0x03c5,0x03c6,0x03c7,0x03c8,0x03c9,0x2202,0x03f5,0x03d1,
+  0x03f0,0x03d5,0x03f1,0x03d6,0x0391,0x0392,0x0393,0x0394,
+  0x0395,0x0396,0x0397,0x0398,0x0399,0x039a,0x039b,0x039c,
+  0x039d,0x039e,0x039f,0x03a0,0x03a1,0x03f4,0x03a3,0x03a4,
+  0x03a5,0x03a6,0x03a7,0x03a8,0x03a9,0x2207,0x03b1,0x03b2,
+  0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8,0x03b9,0x03ba,
+  0x03bb,0x03bc,0x03bd,0x03be,0x03bf,0x03c0,0x03c1,0x03c2,
+  0x03c3,0x03c4,0x03c5,0x03c6,0x03c7,0x03c8,0x03c9,0x2202,
+  0x03f5,0x03d1,0x03f0,0x03d5,0x03f1,0x03d6,0x0391,0x0392,
+  0x0393,0x0394,0x0395,0x0396,0x0397,0x0398,0x0399,0x039a,
+  0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0,0x03a1,0x03f4,
+  0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,0x03a8,0x03a9,0x2207,
+  0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8,
+  0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,0x03c0,
+  0x03c1,0x03c2,0x03c3,0x03c4,0x03c5,0x03c6,0x03c7,0x03c8,
+  0x03c9,0x2202,0x03f5,0x03d1,0x03f0,0x03d5,0x03f1,0x03d6,
+  0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,0x0398,
+  0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0,
+  0x03a1,0x03f4,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,0x03a8,
+  0x03a9,0x2207,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,
+  0x03b7,0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,
+  0x03bf,0x03c0,0x03c1,0x03c2,0x03c3,0x03c4,0x03c5,0x03c6,
+  0x03c7,0x03c8,0x03c9,0x2202,0x03f5,0x03d1,0x03f0,0x03d5,
+  0x03f1,0x03d6,0x03dc,0x03dd,0x0000,0x0000,0x0030,0x0031,
+  0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,
+  0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,
+  0x0038,0x0039,0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,
+  0x0036,0x0037,0x0038,0x0039,0x0030,0x0031,0x0032,0x0033,
+  0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x0030,0x0031,
+  0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039
+};
+
+/* SIP decompositions */
+
+#define UCS4_SIPMIN 0x2f800
+#define UCS4_SIPMAX 0x2fa1d
+
+	/* CJK compatibility ideographs - no holes */
+static const unsigned long ucs4_sipdecomptab[542] = {
+   0x4e3d, 0x4e38, 0x4e41,0x20122, 0x4f60, 0x4fae, 0x4fbb, 0x5002,
+   0x507a, 0x5099, 0x50e7, 0x50cf, 0x349e,0x2063a, 0x514d, 0x5154,
+   0x5164, 0x5177,0x2051c, 0x34b9, 0x5167, 0x518d,0x2054b, 0x5197,
+   0x51a4, 0x4ecc, 0x51ac, 0x51b5,0x291df, 0x51f5, 0x5203, 0x34df,
+   0x523b, 0x5246, 0x5272, 0x5277, 0x3515, 0x52c7, 0x52c9, 0x52e4,
+   0x52fa, 0x5305, 0x5306, 0x5317, 0x5349, 0x5351, 0x535a, 0x5373,
+   0x537d, 0x537f, 0x537f, 0x537f,0x20a2c, 0x7070, 0x53ca, 0x53df,
+  0x20b63, 0x53eb, 0x53f1, 0x5406, 0x549e, 0x5438, 0x5448, 0x5468,
+   0x54a2, 0x54f6, 0x5510, 0x5553, 0x5563, 0x5584, 0x5584, 0x5599,
+   0x55ab, 0x55b3, 0x55c2, 0x5716, 0x5606, 0x5717, 0x5651, 0x5674,
+   0x5207, 0x58ee, 0x57ce, 0x57f4, 0x580d, 0x578b, 0x5832, 0x5831,
+   0x58ac,0x214e4, 0x58f2, 0x58f7, 0x5906, 0x591a, 0x5922, 0x5962,
+  0x216a8,0x216ea, 0x59ec, 0x5a1b, 0x5a27, 0x59d8, 0x5a66, 0x36ee,
+   0x36fc, 0x5b08, 0x5b3e, 0x5b3e,0x219c8, 0x5bc3, 0x5bd8, 0x5be7,
+   0x5bf3,0x21b18, 0x5bff, 0x5c06, 0x5f53, 0x5c22, 0x3781, 0x5c60,
+   0x5c6e, 0x5cc0, 0x5c8d,0x21de4, 0x5d43,0x21de6, 0x5d6e, 0x5d6b,
+   0x5d7c, 0x5de1, 0x5de2, 0x382f, 0x5dfd, 0x5e28, 0x5e3d, 0x5e69,
+   0x3862,0x22183, 0x387c, 0x5eb0, 0x5eb3, 0x5eb6, 0x5eca,0x2a392,
+   0x5efe,0x22331,0x22331, 0x8201, 0x5f22, 0x5f22, 0x38c7,0x232b8,
+  0x261da, 0x5f62, 0x5f6b, 0x38e3, 0x5f9a, 0x5fcd, 0x5fd7, 0x5ff9,
+   0x6081, 0x393a, 0x391c, 0x6094,0x226d4, 0x60c7, 0x6148, 0x614c,
+   0x614e, 0x614c, 0x617a, 0x618e, 0x61b2, 0x61a4, 0x61af, 0x61de,
+   0x61f2, 0x61f6, 0x6210, 0x621b, 0x625d, 0x62b1, 0x62d4, 0x6350,
+  0x22b0c, 0x633d, 0x62fc, 0x6368, 0x6383, 0x63e4,0x22bf1, 0x6422,
+   0x63c5, 0x63a9, 0x3a2e, 0x6469, 0x647e, 0x649d, 0x6477, 0x3a6c,
+   0x654f, 0x656c,0x2300a, 0x65e3, 0x66f8, 0x6649, 0x3b19, 0x6691,
+   0x3b08, 0x3ae4, 0x5192, 0x5195, 0x6700, 0x669c, 0x80ad, 0x43d9,
+   0x6717, 0x671b, 0x6721, 0x675e, 0x6753,0x233c3, 0x3b49, 0x67fa,
+   0x6785, 0x6852, 0x6885,0x2346d, 0x688e, 0x681f, 0x6914, 0x3b9d,
+   0x6942, 0x69a3, 0x69ea, 0x6aa8,0x236a3, 0x6adb, 0x3c18, 0x6b21,
+  0x238a7, 0x6b54, 0x3c4e, 0x6b72, 0x6b9f, 0x6bba, 0x6bbb,0x23a8d,
+  0x21d0b,0x23afa, 0x6c4e,0x23cbc, 0x6cbf, 0x6ccd, 0x6c67, 0x6d16,
+   0x6d3e, 0x6d77, 0x6d41, 0x6d69, 0x6d78, 0x6d85,0x23d1e, 0x6d34,
+   0x6e2f, 0x6e6e, 0x3d33, 0x6ecb, 0x6ec7,0x23ed1, 0x6df9, 0x6f6e,
+  0x23f5e,0x23f8e, 0x6fc6, 0x7039, 0x701e, 0x701b, 0x3d96, 0x704a,
+   0x707d, 0x7077, 0x70ad,0x20525, 0x7145,0x24263, 0x719c,0x243ab,
+   0x7228, 0x7235, 0x7250,0x24608, 0x7280, 0x7295,0x24735,0x24814,
+   0x737a, 0x738b, 0x3eac, 0x73a5, 0x3eb8, 0x3eb8, 0x7447, 0x745c,
+   0x7471, 0x7485, 0x74ca, 0x3f1b, 0x7524,0x24c36, 0x753e,0x24c92,
+   0x7570,0x2219f, 0x7610,0x24fa1,0x24fb8,0x25044, 0x3ffc, 0x4008,
+   0x76f4,0x250f3,0x250f2,0x25119,0x25133, 0x771e, 0x771f, 0x771f,
+   0x774a, 0x4039, 0x778b, 0x4046, 0x4096,0x2541d, 0x784e, 0x788c,
+   0x78cc, 0x40e3,0x25626, 0x7956,0x2569a,0x256c5, 0x798f, 0x79eb,
+   0x412f, 0x7a40, 0x7a4a, 0x7a4f,0x2597c,0x25aa7,0x25aa7, 0x7aee,
+   0x4202,0x25bab, 0x7bc6, 0x7bc9, 0x4227,0x25c80, 0x7cd2, 0x42a0,
+   0x7ce8, 0x7ce3, 0x7d00,0x25f86, 0x7d63, 0x4301, 0x7dc7, 0x7e02,
+   0x7e45, 0x4334,0x26228,0x26247, 0x4359,0x262d9, 0x7f7a,0x2633e,
+   0x7f95, 0x7ffa, 0x8005,0x264da,0x26523, 0x8060,0x265a8, 0x8070,
+  0x2335f, 0x43d5, 0x80b2, 0x8103, 0x440b, 0x813e, 0x5ab5,0x267a7,
+  0x267b5,0x23393,0x2339c, 0x8201, 0x8204, 0x8f9e, 0x446b, 0x8291,
+   0x828b, 0x829d, 0x52b3, 0x82b1, 0x82b3, 0x82bd, 0x82e6,0x26b3c,
+   0x82e5, 0x831d, 0x8363, 0x83ad, 0x8323, 0x83bd, 0x83e7, 0x8457,
+   0x8353, 0x83ca, 0x83cc, 0x83dc,0x26c36,0x26d6b,0x26cd5, 0x452b,
+   0x84f1, 0x84f3, 0x8516,0x273ca, 0x8564,0x26f2c, 0x455d, 0x4561,
+  0x26fb1,0x270d2, 0x456b, 0x8650, 0x865c, 0x8667, 0x8669, 0x86a9,
+   0x8688, 0x870e, 0x86e2, 0x8779, 0x8728, 0x876b, 0x8786, 0x45d7,
+   0x87e1, 0x8801, 0x45f9, 0x8860, 0x8863,0x27667, 0x88d7, 0x88de,
+   0x4635, 0x88fa, 0x34bb,0x278ae,0x27966, 0x46be, 0x46c7, 0x8aa0,
+   0x8aed, 0x8b8a, 0x8c55,0x27ca8, 0x8cab, 0x8cc1, 0x8d1b, 0x8d77,
+  0x27f2f,0x20804, 0x8dcb, 0x8dbc, 0x8df0,0x208de, 0x8ed4, 0x8f38,
+  0x285d2,0x285ed, 0x9094, 0x90f1, 0x9111,0x2872e, 0x911b, 0x9238,
+   0x92d7, 0x92d8, 0x927c, 0x93f9, 0x9415,0x28bfa, 0x958b, 0x4995,
+   0x95b7,0x28d77, 0x49e6, 0x96c3, 0x5db2, 0x9723,0x29145,0x2921a,
+   0x4a6e, 0x4a76, 0x97e0,0x2940a, 0x4ab2,0x29496, 0x980b, 0x980b,
+   0x9829,0x295b6, 0x98e2, 0x4b33, 0x9929, 0x99a7, 0x99c2, 0x99fe,
+   0x4bce,0x29b30, 0x9b12, 0x9c40, 0x9cfd, 0x4cce, 0x4ced, 0x9d67,
+  0x2a0ce, 0x4cf8,0x2a105,0x2a20e,0x2a291, 0x9ebb, 0x4d56, 0x9ef9,
+   0x9efe, 0x9f05, 0x9f0f, 0x9f16, 0x9f3b,0x2a600
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/charset/gb_12345.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1114 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	GB 12345 conversion table
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	15 May 1998
+ * Last Edited:	30 August 2006
+ */
+
+/* GB 12345 is the national standard of the People's Republic of China
+ * (mainland China) for traditional Chinese characters.
+ */
+
+#define BASE_GB12345_KU 0xa1
+#define BASE_GB12345_TEN 0xa1
+#define MAX_GB12345_KU 89
+#define MAX_GB12345_TEN 94
+
+
+#define GB12345TOUNICODE(c,c1,ku,ten)					\
+  ((((ku = (c & 0x7f) - BASE_GB12345_KU) < MAX_GB12345_KU) &&		\
+    ((ten = (c1 & 0x7f) - BASE_GB12345_TEN) < MAX_GB12345_TEN)) ?	\
+   gb12345tab[ku][ten] : UBOGON)
+
+
+static const unsigned short gb12345tab[MAX_GB12345_KU][MAX_GB12345_TEN] = {
+  {				/* ku 01 */
+    0x3000,0x3001,0x3002,0x30fb,0x02c9,0x02c7,0x00a8,0x3003,0x3005,0x2015,
+    0xff5e,0x2225,0x2026,0x2018,0x2019,0x201c,0x201d,0x3014,0x3015,0x3008,
+    0x3009,0x300a,0x300b,0x300c,0x300d,0x300e,0x300f,0x3016,0x3017,0x3010,
+    0x3011,0x00b1,0x00d7,0x00f7,0x2236,0x2227,0x2228,0x2211,0x220f,0x222a,
+    0x2229,0x2208,0x2237,0x221a,0x22a5,0x2225,0x2220,0x2312,0x2299,0x222b,
+    0x222e,0x2261,0x224c,0x2248,0x223d,0x221d,0x2260,0x226e,0x226f,0x2264,
+    0x2265,0x221e,0x2235,0x2234,0x2642,0x2640,0x00b0,0x2032,0x2033,0x2103,
+    0xff04,0x00a4,0xffe0,0xffe1,0x2030,0x00a7,0x2116,0x2606,0x2605,0x25cb,
+    0x25cf,0x25ce,0x25c7,0x25c6,0x25a1,0x25a0,0x25b3,0x25b2,0x203b,0x2192,
+    0x2190,0x2191,0x2193,0x3013
+  },
+  {				/* ku 02 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x2488,0x2489,0x248a,0x248b,
+    0x248c,0x248d,0x248e,0x248f,0x2490,0x2491,0x2492,0x2493,0x2494,0x2495,
+    0x2496,0x2497,0x2498,0x2499,0x249a,0x249b,0x2474,0x2475,0x2476,0x2477,
+    0x2478,0x2479,0x247a,0x247b,0x247c,0x247d,0x247e,0x247f,0x2480,0x2481,
+    0x2482,0x2483,0x2484,0x2485,0x2486,0x2487,0x2460,0x2461,0x2462,0x2463,
+    0x2464,0x2465,0x2466,0x2467,0x2468,0x2469,UBOGON,UBOGON,0x3220,0x3221,
+    0x3222,0x3223,0x3224,0x3225,0x3226,0x3227,0x3228,0x3229,UBOGON,UBOGON,
+    0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,0x2169,
+    0x216a,0x216b,UBOGON,UBOGON
+  },
+  {				/* ku 03 */
+    0xff01,0xff02,0xff03,0xffe5,0xff05,0xff06,0xff07,0xff08,0xff09,0xff0a,
+    0xff0b,0xff0c,0xff0d,0xff0e,0xff0f,0xff10,0xff11,0xff12,0xff13,0xff14,
+    0xff15,0xff16,0xff17,0xff18,0xff19,0xff1a,0xff1b,0xff1c,0xff1d,0xff1e,
+    0xff1f,0xff20,0xff21,0xff22,0xff23,0xff24,0xff25,0xff26,0xff27,0xff28,
+    0xff29,0xff2a,0xff2b,0xff2c,0xff2d,0xff2e,0xff2f,0xff30,0xff31,0xff32,
+    0xff33,0xff34,0xff35,0xff36,0xff37,0xff38,0xff39,0xff3a,0xff3b,0xff3c,
+    0xff3d,0xff3e,0xff3f,0xff40,0xff41,0xff42,0xff43,0xff44,0xff45,0xff46,
+    0xff47,0xff48,0xff49,0xff4a,0xff4b,0xff4c,0xff4d,0xff4e,0xff4f,0xff50,
+    0xff51,0xff52,0xff53,0xff54,0xff55,0xff56,0xff57,0xff58,0xff59,0xff5a,
+    0xff5b,0xff5c,0xff5d,0xffe3
+  },
+  {				/* ku 04 */
+    0x3041,0x3042,0x3043,0x3044,0x3045,0x3046,0x3047,0x3048,0x3049,0x304a,
+    0x304b,0x304c,0x304d,0x304e,0x304f,0x3050,0x3051,0x3052,0x3053,0x3054,
+    0x3055,0x3056,0x3057,0x3058,0x3059,0x305a,0x305b,0x305c,0x305d,0x305e,
+    0x305f,0x3060,0x3061,0x3062,0x3063,0x3064,0x3065,0x3066,0x3067,0x3068,
+    0x3069,0x306a,0x306b,0x306c,0x306d,0x306e,0x306f,0x3070,0x3071,0x3072,
+    0x3073,0x3074,0x3075,0x3076,0x3077,0x3078,0x3079,0x307a,0x307b,0x307c,
+    0x307d,0x307e,0x307f,0x3080,0x3081,0x3082,0x3083,0x3084,0x3085,0x3086,
+    0x3087,0x3088,0x3089,0x308a,0x308b,0x308c,0x308d,0x308e,0x308f,0x3090,
+    0x3091,0x3092,0x3093,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 05 */
+    0x30a1,0x30a2,0x30a3,0x30a4,0x30a5,0x30a6,0x30a7,0x30a8,0x30a9,0x30aa,
+    0x30ab,0x30ac,0x30ad,0x30ae,0x30af,0x30b0,0x30b1,0x30b2,0x30b3,0x30b4,
+    0x30b5,0x30b6,0x30b7,0x30b8,0x30b9,0x30ba,0x30bb,0x30bc,0x30bd,0x30be,
+    0x30bf,0x30c0,0x30c1,0x30c2,0x30c3,0x30c4,0x30c5,0x30c6,0x30c7,0x30c8,
+    0x30c9,0x30ca,0x30cb,0x30cc,0x30cd,0x30ce,0x30cf,0x30d0,0x30d1,0x30d2,
+    0x30d3,0x30d4,0x30d5,0x30d6,0x30d7,0x30d8,0x30d9,0x30da,0x30db,0x30dc,
+    0x30dd,0x30de,0x30df,0x30e0,0x30e1,0x30e2,0x30e3,0x30e4,0x30e5,0x30e6,
+    0x30e7,0x30e8,0x30e9,0x30ea,0x30eb,0x30ec,0x30ed,0x30ee,0x30ef,0x30f0,
+    0x30f1,0x30f2,0x30f3,0x30f4,0x30f5,0x30f6,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 06 */
+    0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,0x0398,0x0399,0x039a,
+    0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0,0x03a1,0x03a3,0x03a4,0x03a5,
+    0x03a6,0x03a7,0x03a8,0x03a9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8,
+    0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,0x03c0,0x03c1,0x03c3,
+    0x03c4,0x03c5,0x03c6,0x03c7,0x03c8,0x03c9,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 07 */
+    0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0401,0x0416,0x0417,0x0418,
+    0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f,0x0420,0x0421,0x0422,
+    0x0423,0x0424,0x0425,0x0426,0x0427,0x0428,0x0429,0x042a,0x042b,0x042c,
+    0x042d,0x042e,0x042f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x0430,0x0431,
+    0x0432,0x0433,0x0434,0x0435,0x0451,0x0436,0x0437,0x0438,0x0439,0x043a,
+    0x043b,0x043c,0x043d,0x043e,0x043f,0x0440,0x0441,0x0442,0x0443,0x0444,
+    0x0445,0x0446,0x0447,0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,
+    0x044f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 08 */
+    0x0101,0x00e1,0x01ce,0x00e0,0x0113,0x00e9,0x011b,0x00e8,0x012b,0x00ed,
+    0x01d0,0x00ec,0x014d,0x00f3,0x01d2,0x00f2,0x016b,0x00fa,0x01d4,0x00f9,
+    0x01d6,0x01d8,0x01da,0x01dc,0x00fc,0x00ea,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3105,0x3106,0x3107,0x3108,
+    0x3109,0x310a,0x310b,0x310c,0x310d,0x310e,0x310f,0x3110,0x3111,0x3112,
+    0x3113,0x3114,0x3115,0x3116,0x3117,0x3118,0x3119,0x311a,0x311b,0x311c,
+    0x311d,0x311e,0x311f,0x3120,0x3121,0x3122,0x3123,0x3124,0x3125,0x3126,
+    0x3127,0x3128,0x3129,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 09 */
+    UBOGON,UBOGON,UBOGON,0x2500,0x2501,0x2502,0x2503,0x2504,0x2505,0x2506,
+    0x2507,0x2508,0x2509,0x250a,0x250b,0x250c,0x250d,0x250e,0x250f,0x2510,
+    0x2511,0x2512,0x2513,0x2514,0x2515,0x2516,0x2517,0x2518,0x2519,0x251a,
+    0x251b,0x251c,0x251d,0x251e,0x251f,0x2520,0x2521,0x2522,0x2523,0x2524,
+    0x2525,0x2526,0x2527,0x2528,0x2529,0x252a,0x252b,0x252c,0x252d,0x252e,
+    0x252f,0x2530,0x2531,0x2532,0x2533,0x2534,0x2535,0x2536,0x2537,0x2538,
+    0x2539,0x253a,0x253b,0x253c,0x253d,0x253e,0x253f,0x2540,0x2541,0x2542,
+    0x2543,0x2544,0x2545,0x2546,0x2547,0x2548,0x2549,0x254a,0x254b,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0a */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0b */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0d */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0e */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0f */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 10 */
+    0x554a,0x963f,0x57c3,0x6328,0x54ce,0x5509,0x54c0,0x769a,0x764c,0x85f9,
+    0x77ee,0x827e,0x7919,0x611b,0x9698,0x978d,0x6c28,0x5b89,0x4ffa,0x6309,
+    0x6697,0x5cb8,0x80fa,0x6848,0x9aaf,0x6602,0x76ce,0x51f9,0x6556,0x71ac,
+    0x7ff1,0x8956,0x50b2,0x5965,0x61ca,0x6fb3,0x82ad,0x634c,0x6252,0x53ed,
+    0x5427,0x7b06,0x516b,0x75a4,0x5df4,0x62d4,0x8dcb,0x9776,0x628a,0x8019,
+    0x58e9,0x9738,0x7f77,0x7238,0x767d,0x67cf,0x767e,0x64fa,0x4f70,0x6557,
+    0x62dc,0x7a17,0x6591,0x73ed,0x642c,0x6273,0x822c,0x9812,0x677f,0x7248,
+    0x626e,0x62cc,0x4f34,0x74e3,0x534a,0x8fa6,0x7d46,0x90a6,0x5e6b,0x6886,
+    0x699c,0x8180,0x7d81,0x68d2,0x78c5,0x868c,0x938a,0x508d,0x8b17,0x82de,
+    0x80de,0x5305,0x8912,0x5265
+  },
+  {				/* ku 11 */
+    0x8584,0x96f9,0x4fdd,0x5821,0x98fd,0x5bf6,0x62b1,0x5831,0x66b4,0x8c79,
+    0x9b91,0x7206,0x676f,0x7891,0x60b2,0x5351,0x5317,0x8f29,0x80cc,0x8c9d,
+    0x92c7,0x500d,0x72fd,0x5099,0x618a,0x7119,0x88ab,0x5954,0x82ef,0x672c,
+    0x7b28,0x5d29,0x7db3,0x752d,0x6cf5,0x8e66,0x8ff8,0x903c,0x9f3b,0x6bd4,
+    0x9119,0x7b46,0x5f7c,0x78a7,0x84d6,0x853d,0x7562,0x6583,0x6bd6,0x5e63,
+    0x5e87,0x75f9,0x9589,0x655d,0x5f0a,0x5fc5,0x8f9f,0x58c1,0x81c2,0x907f,
+    0x965b,0x97ad,0x908a,0x7de8,0x8cb6,0x6241,0x4fbf,0x8b8a,0x535e,0x8fa8,
+    0x8faf,0x8fae,0x904d,0x6a19,0x5f6a,0x8198,0x8868,0x9c49,0x618b,0x522b,
+    0x765f,0x5f6c,0x658c,0x7015,0x6ff1,0x8cd3,0x64ef,0x5175,0x51b0,0x67c4,
+    0x4e19,0x79c9,0x9905,0x70b3
+  },
+  {				/* ku 12 */
+    0x75c5,0x5e76,0x73bb,0x83e0,0x64ad,0x64a5,0x9262,0x6ce2,0x535a,0x52c3,
+    0x640f,0x9251,0x7b94,0x4f2f,0x5e1b,0x8236,0x8116,0x818a,0x6e24,0x6cca,
+    0x99c1,0x6355,0x535c,0x54fa,0x88dc,0x57e0,0x4e0d,0x5e03,0x6b65,0x7c3f,
+    0x90e8,0x6016,0x64e6,0x731c,0x88c1,0x6750,0x624d,0x8ca1,0x776c,0x8e29,
+    0x91c7,0x5f69,0x83dc,0x8521,0x9910,0x53c3,0x8836,0x6b98,0x615a,0x6158,
+    0x71e6,0x84bc,0x8259,0x5009,0x6ec4,0x85cf,0x64cd,0x7cd9,0x69fd,0x66f9,
+    0x8349,0x53a0,0x7b56,0x5074,0x518c,0x6e2c,0x5c64,0x8e6d,0x63d2,0x53c9,
+    0x832c,0x8336,0x67e5,0x78b4,0x643d,0x5bdf,0x5c94,0x5dee,0x8a6b,0x62c6,
+    0x67f4,0x8c7a,0x6519,0x647b,0x87ec,0x995e,0x8b92,0x7e8f,0x93df,0x7523,
+    0x95e1,0x986b,0x660c,0x7316
+  },
+  {				/* ku 13 */
+    0x5834,0x5617,0x5e38,0x9577,0x511f,0x8178,0x5ee0,0x655e,0x66a2,0x5531,
+    0x5021,0x8d85,0x6284,0x9214,0x671d,0x5632,0x6f6e,0x5de2,0x5435,0x7092,
+    0x8eca,0x626f,0x64a4,0x63a3,0x5fb9,0x6f88,0x90f4,0x81e3,0x8fb0,0x5875,
+    0x6668,0x5ff1,0x6c89,0x9673,0x8d81,0x896f,0x6491,0x7a31,0x57ce,0x6a59,
+    0x6210,0x5448,0x4e58,0x7a0b,0x61f2,0x6f84,0x8aa0,0x627f,0x901e,0x9a01,
+    0x79e4,0x5403,0x75f4,0x6301,0x5319,0x6c60,0x9072,0x5f1b,0x99b3,0x803b,
+    0x9f52,0x4f88,0x5c3a,0x8d64,0x7fc5,0x65a5,0x71be,0x5145,0x885d,0x87f2,
+    0x5d07,0x5bf5,0x62bd,0x916c,0x7587,0x8e8a,0x7a20,0x6101,0x7c4c,0x4ec7,
+    0x7da2,0x7785,0x919c,0x81ed,0x521d,0x51fa,0x6a71,0x53a8,0x8e87,0x92e4,
+    0x96db,0x6ec1,0x9664,0x695a
+  },
+  {				/* ku 14 */
+    0x790e,0x5132,0x77d7,0x6410,0x89f8,0x8655,0x63e3,0x5ddd,0x7a7f,0x693d,
+    0x50b3,0x8239,0x5598,0x4e32,0x7621,0x7a97,0x5e62,0x5e8a,0x95d6,0x5275,
+    0x5439,0x708a,0x6376,0x9318,0x5782,0x6625,0x693f,0x9187,0x5507,0x6df3,
+    0x7d14,0x8822,0x6233,0x7dbd,0x75b5,0x8328,0x78c1,0x96cc,0x8fad,0x6148,
+    0x74f7,0x8a5e,0x6b64,0x523a,0x8cdc,0x6b21,0x8070,0x8471,0x56f1,0x5306,
+    0x5f9e,0x53e2,0x51d1,0x7c97,0x918b,0x7c07,0x4fc3,0x8ea5,0x7be1,0x7ac4,
+    0x6467,0x5d14,0x50ac,0x8106,0x7601,0x7cb9,0x6dec,0x7fe0,0x6751,0x5b58,
+    0x5bf8,0x78cb,0x64ae,0x6413,0x63aa,0x632b,0x932f,0x642d,0x9054,0x7b54,
+    0x7629,0x6253,0x5927,0x5446,0x6b79,0x50a3,0x6234,0x5e36,0x6b86,0x4ee3,
+    0x8cb8,0x888b,0x5f85,0x902e
+  },
+  {				/* ku 15 */
+    0x6020,0x803d,0x64d4,0x4e39,0x55ae,0x9132,0x64a3,0x81bd,0x65e6,0x6c2e,
+    0x4f46,0x619a,0x6de1,0x8a95,0x5f48,0x86cb,0x7576,0x64cb,0x9ee8,0x8569,
+    0x6a94,0x5200,0x6417,0x8e48,0x5012,0x5cf6,0x79b1,0x5c0e,0x5230,0x7a3b,
+    0x60bc,0x9053,0x76d7,0x5fb7,0x5f97,0x7684,0x8e6c,0x71c8,0x767b,0x7b49,
+    0x77aa,0x51f3,0x9127,0x5824,0x4f4e,0x6ef4,0x8fea,0x6575,0x7b1b,0x72c4,
+    0x6ecc,0x7fdf,0x5ae1,0x62b5,0x5e95,0x5730,0x8482,0x7b2c,0x5e1d,0x5f1f,
+    0x905e,0x7de0,0x985b,0x6382,0x6ec7,0x7898,0x9ede,0x5178,0x975b,0x588a,
+    0x96fb,0x4f43,0x7538,0x5e97,0x60e6,0x5960,0x6fb1,0x6bbf,0x7889,0x53fc,
+    0x96d5,0x51cb,0x5201,0x6389,0x540a,0x91e3,0x8abf,0x8dcc,0x7239,0x789f,
+    0x8776,0x8fed,0x8adc,0x758a
+  },
+  {				/* ku 16 */
+    0x4e01,0x76ef,0x53ee,0x91d8,0x9802,0x9f0e,0x9320,0x5b9a,0x8a02,0x4e22,
+    0x6771,0x51ac,0x8463,0x61c2,0x52d5,0x68df,0x4f97,0x606b,0x51cd,0x6d1e,
+    0x515c,0x6296,0x9b25,0x9661,0x8c46,0x9017,0x75d8,0x90fd,0x7763,0x6bd2,
+    0x72a2,0x7368,0x8b80,0x5835,0x7779,0x8ced,0x675c,0x934d,0x809a,0x5ea6,
+    0x6e21,0x5992,0x7aef,0x77ed,0x935b,0x6bb5,0x65b7,0x7dde,0x5806,0x5151,
+    0x968a,0x5c0d,0x58a9,0x5678,0x8e72,0x6566,0x9813,0x56e4,0x920d,0x76fe,
+    0x9041,0x6387,0x54c6,0x591a,0x596a,0x579b,0x8eb2,0x6735,0x8dfa,0x8235,
+    0x5241,0x60f0,0x58ae,0x86fe,0x5ce8,0x9d5d,0x4fc4,0x984d,0x8a1b,0x5a25,
+    0x60e1,0x5384,0x627c,0x904f,0x9102,0x9913,0x6069,0x800c,0x5152,0x8033,
+    0x723e,0x990c,0x6d31,0x4e8c
+  },
+  {				/* ku 17 */
+    0x8cb3,0x767c,0x7f70,0x7b4f,0x4f10,0x4e4f,0x95a5,0x6cd5,0x73d0,0x85e9,
+    0x5e06,0x756a,0x7ffb,0x6a0a,0x792c,0x91e9,0x7e41,0x51e1,0x7169,0x53cd,
+    0x8fd4,0x7bc4,0x8ca9,0x72af,0x98ef,0x6cdb,0x574a,0x82b3,0x65b9,0x80aa,
+    0x623f,0x9632,0x59a8,0x4eff,0x8a2a,0x7d21,0x653e,0x83f2,0x975e,0x5561,
+    0x98db,0x80a5,0x532a,0x8ab9,0x5420,0x80ba,0x5ee2,0x6cb8,0x8cbb,0x82ac,
+    0x915a,0x5429,0x6c1b,0x5206,0x7d1b,0x58b3,0x711a,0x6c7e,0x7c89,0x596e,
+    0x4efd,0x5fff,0x61a4,0x7cde,0x8c50,0x5c01,0x6953,0x8702,0x5cf0,0x92d2,
+    0x98a8,0x760b,0x70fd,0x9022,0x99ae,0x7e2b,0x8af7,0x5949,0x9cf3,0x4f5b,
+    0x5426,0x592b,0x6577,0x819a,0x5b75,0x6276,0x62c2,0x8f3b,0x5e45,0x6c1f,
+    0x7b26,0x4f0f,0x4fd8,0x670d
+  },
+  {				/* ku 18 */
+    0x6d6e,0x6daa,0x798f,0x88b1,0x5f17,0x752b,0x64ab,0x8f14,0x4fef,0x91dc,
+    0x65a7,0x812f,0x8151,0x5e9c,0x8150,0x8d74,0x526f,0x8986,0x8ce6,0x5fa9,
+    0x5085,0x4ed8,0x961c,0x7236,0x8179,0x8ca0,0x5bcc,0x8a03,0x9644,0x5a66,
+    0x7e1b,0x5490,0x5676,0x560e,0x8a72,0x6539,0x6982,0x9223,0x84cb,0x6e89,
+    0x5e79,0x7518,0x6746,0x67d1,0x7aff,0x809d,0x8d95,0x611f,0x79c6,0x6562,
+    0x8d1b,0x5ca1,0x525b,0x92fc,0x7f38,0x809b,0x7db1,0x5d17,0x6e2f,0x6760,
+    0x7bd9,0x768b,0x9ad8,0x818f,0x7f94,0x7cd5,0x641e,0x93ac,0x7a3f,0x544a,
+    0x54e5,0x6b4c,0x64f1,0x6208,0x9d3f,0x80f3,0x7599,0x5272,0x9769,0x845b,
+    0x683c,0x86e4,0x95a3,0x9694,0x927b,0x500b,0x5404,0x7d66,0x6839,0x8ddf,
+    0x8015,0x66f4,0x5e9a,0x7fb9
+  },
+  {				/* ku 19 */
+    0x57c2,0x803f,0x6897,0x5de5,0x653b,0x529f,0x606d,0x9f94,0x4f9b,0x8eac,
+    0x516c,0x5bab,0x5f13,0x978f,0x6c5e,0x62f1,0x8ca2,0x5171,0x920e,0x52fe,
+    0x6e9d,0x82df,0x72d7,0x57a2,0x69cb,0x8cfc,0x591f,0x8f9c,0x83c7,0x5495,
+    0x7b8d,0x4f30,0x6cbd,0x5b64,0x59d1,0x9f13,0x53e4,0x8831,0x9aa8,0x8c37,
+    0x80a1,0x6545,0x9867,0x56fa,0x96c7,0x522e,0x74dc,0x526e,0x5be1,0x6302,
+    0x8902,0x4e56,0x62d0,0x602a,0x68fa,0x95dc,0x5b98,0x51a0,0x89c0,0x7ba1,
+    0x9928,0x7f50,0x6163,0x704c,0x8cab,0x5149,0x5ee3,0x901b,0x7470,0x898f,
+    0x572d,0x7845,0x6b78,0x9f9c,0x95a8,0x8ecc,0x9b3c,0x8a6d,0x7678,0x6842,
+    0x6ac3,0x8dea,0x8cb4,0x528a,0x8f25,0x6eda,0x68cd,0x934b,0x90ed,0x570b,
+    0x679c,0x88f9,0x904e,0x54c8
+  },
+  {				/* ku 1a */
+    0x9ab8,0x5b69,0x6d77,0x6c26,0x4ea5,0x5bb3,0x99ed,0x9163,0x61a8,0x90af,
+    0x97d3,0x542b,0x6db5,0x5bd2,0x51fd,0x558a,0x7f55,0x7ff0,0x64bc,0x634d,
+    0x65f1,0x61be,0x608d,0x710a,0x6c57,0x6f22,0x592f,0x676d,0x822a,0x58d5,
+    0x568e,0x8c6a,0x6beb,0x90dd,0x597d,0x8017,0x865f,0x6d69,0x5475,0x559d,
+    0x8377,0x83cf,0x6838,0x79be,0x548c,0x4f55,0x5408,0x76d2,0x8c89,0x95a1,
+    0x6cb3,0x6db8,0x8d6b,0x8910,0x9db4,0x8cc0,0x563f,0x9ed1,0x75d5,0x5f88,
+    0x72e0,0x6068,0x54fc,0x4ea8,0x6a2a,0x8861,0x6052,0x8f5f,0x54c4,0x70d8,
+    0x8679,0x9d3b,0x6d2a,0x5b8f,0x5f18,0x7d05,0x5589,0x4faf,0x7334,0x543c,
+    0x539a,0x5019,0x5f8c,0x547c,0x4e4e,0x5ffd,0x745a,0x58fa,0x846b,0x80e1,
+    0x8774,0x72d0,0x7cca,0x6e56
+  },
+  {				/* ku 1b */
+    0x5f27,0x864e,0x552c,0x8b77,0x4e92,0x6eec,0x6237,0x82b1,0x5629,0x83ef,
+    0x733e,0x6ed1,0x756b,0x5283,0x5316,0x8a71,0x69d0,0x5f8a,0x61f7,0x6dee,
+    0x58de,0x6b61,0x74b0,0x6853,0x9084,0x7de9,0x63db,0x60a3,0x559a,0x7613,
+    0x8c62,0x7165,0x6e19,0x5ba6,0x5e7b,0x8352,0x614c,0x9ec4,0x78fa,0x8757,
+    0x7c27,0x7687,0x51f0,0x60f6,0x714c,0x6643,0x5e4c,0x604d,0x8b0a,0x7070,
+    0x63ee,0x8f1d,0x5fbd,0x6062,0x86d4,0x56de,0x6bc1,0x6094,0x6167,0x5349,
+    0x60e0,0x6666,0x8cc4,0x7a62,0x6703,0x71f4,0x532f,0x8af1,0x8aa8,0x7e6a,
+    0x8477,0x660f,0x5a5a,0x9b42,0x6e3e,0x6df7,0x8c41,0x6d3b,0x4f19,0x706b,
+    0x7372,0x6216,0x60d1,0x970d,0x8ca8,0x798d,0x64ca,0x573e,0x57fa,0x6a5f,
+    0x7578,0x7a3d,0x7a4d,0x7b95
+  },
+  {				/* ku 1c */
+    0x808c,0x9951,0x8ff9,0x6fc0,0x8b4f,0x9dc4,0x59ec,0x7e3e,0x7ddd,0x5409,
+    0x6975,0x68d8,0x8f2f,0x7c4d,0x96c6,0x53ca,0x6025,0x75be,0x6c72,0x5373,
+    0x5ac9,0x7d1a,0x64e0,0x5e7e,0x810a,0x5df1,0x858a,0x6280,0x5180,0x5b63,
+    0x4f0e,0x796d,0x5291,0x60b8,0x6fdf,0x5bc4,0x5bc2,0x8a08,0x8a18,0x65e2,
+    0x5fcc,0x969b,0x5993,0x7e7c,0x7d00,0x5609,0x67b7,0x593e,0x4f73,0x5bb6,
+    0x52a0,0x83a2,0x9830,0x8cc8,0x7532,0x9240,0x5047,0x7a3c,0x50f9,0x67b6,
+    0x99d5,0x5ac1,0x6bb2,0x76e3,0x5805,0x5c16,0x7b8b,0x9593,0x714e,0x517c,
+    0x80a9,0x8271,0x5978,0x7dd8,0x7e6d,0x6aa2,0x67ec,0x78b1,0x9e7c,0x63c0,
+    0x64bf,0x7c21,0x5109,0x526a,0x51cf,0x85a6,0x6abb,0x9452,0x8e10,0x8ce4,
+    0x898b,0x9375,0x7bad,0x4ef6
+  },
+  {				/* ku 1d */
+    0x5065,0x8266,0x528d,0x991e,0x6f38,0x6ffa,0x6f97,0x5efa,0x50f5,0x59dc,
+    0x5c07,0x6f3f,0x6c5f,0x7586,0x8523,0x69f3,0x596c,0x8b1b,0x5320,0x91ac,
+    0x964d,0x8549,0x6912,0x7901,0x7126,0x81a0,0x4ea4,0x90ca,0x6f86,0x9a55,
+    0x5b0c,0x56bc,0x652a,0x9278,0x77ef,0x50e5,0x811a,0x72e1,0x89d2,0x9903,
+    0x7e73,0x7d5e,0x527f,0x6559,0x9175,0x8f4e,0x8f03,0x53eb,0x7a96,0x63ed,
+    0x63a5,0x7686,0x79f8,0x8857,0x968e,0x622a,0x52ab,0x7bc0,0x6854,0x6770,
+    0x6377,0x776b,0x7aed,0x6f54,0x7d50,0x89e3,0x59d0,0x6212,0x85c9,0x82a5,
+    0x754c,0x501f,0x4ecb,0x75a5,0x8aa1,0x5c4a,0x5dfe,0x7b4b,0x65a4,0x91d1,
+    0x4eca,0x6d25,0x895f,0x7dca,0x9326,0x50c5,0x8b39,0x9032,0x9773,0x6649,
+    0x7981,0x8fd1,0x71fc,0x6d78
+  },
+  {				/* ku 1e */
+    0x76e1,0x52c1,0x8346,0x5162,0x8396,0x775b,0x6676,0x9be8,0x4eac,0x9a5a,
+    0x7cbe,0x7cb3,0x7d93,0x4e95,0x8b66,0x666f,0x9838,0x975c,0x5883,0x656c,
+    0x93e1,0x5f91,0x75d9,0x9756,0x7adf,0x7af6,0x51c8,0x70af,0x7a98,0x63ea,
+    0x7a76,0x7cfe,0x7396,0x97ed,0x4e45,0x7078,0x4e5d,0x9152,0x53a9,0x6551,
+    0x820a,0x81fc,0x8205,0x548e,0x5c31,0x759a,0x97a0,0x62d8,0x72d9,0x75bd,
+    0x5c45,0x99d2,0x83ca,0x5c40,0x5480,0x77e9,0x8209,0x6cae,0x805a,0x62d2,
+    0x64da,0x5de8,0x5177,0x8ddd,0x8e1e,0x92f8,0x4ff1,0x53e5,0x61fc,0x70ac,
+    0x5287,0x6350,0x9d51,0x5a1f,0x5026,0x7737,0x5377,0x7d79,0x6485,0x652b,
+    0x6289,0x6398,0x5014,0x7235,0x89ba,0x51b3,0x8a23,0x7d76,0x5747,0x83cc,
+    0x921e,0x8ecd,0x541b,0x5cfb
+  },
+  {				/* ku 1f */
+    0x4fca,0x7ae3,0x6d5a,0x90e1,0x99ff,0x5580,0x5496,0x5361,0x54af,0x958b,
+    0x63e9,0x6977,0x51f1,0x6168,0x520a,0x582a,0x52d8,0x574e,0x780d,0x770b,
+    0x5eb7,0x6177,0x7ce0,0x625b,0x6297,0x4ea2,0x7095,0x8003,0x62f7,0x70e4,
+    0x9760,0x5777,0x82db,0x67ef,0x68f5,0x78d5,0x9846,0x79d1,0x6bbb,0x54b3,
+    0x53ef,0x6e34,0x514b,0x523b,0x5ba2,0x8ab2,0x80af,0x5543,0x58be,0x61c7,
+    0x5751,0x542d,0x7a7a,0x6050,0x5b54,0x63a7,0x6473,0x53e3,0x6263,0x5bc7,
+    0x67af,0x54ed,0x7a9f,0x82e6,0x9177,0x5eab,0x8932,0x8a87,0x57ae,0x630e,
+    0x8de8,0x80ef,0x584a,0x7b77,0x5108,0x5feb,0x5bec,0x6b3e,0x5321,0x7b50,
+    0x72c2,0x6846,0x7926,0x7736,0x66e0,0x51b5,0x8667,0x76d4,0x5dcb,0x7aba,
+    0x8475,0x594e,0x9b41,0x5080
+  },
+  {				/* ku 20 */
+    0x994b,0x6127,0x6f70,0x5764,0x6606,0x6346,0x56f0,0x62ec,0x64f4,0x5ed3,
+    0x95ca,0x5783,0x62c9,0x5587,0x881f,0x81d8,0x8fa3,0x5566,0x840a,0x4f86,
+    0x8cf4,0x85cd,0x5a6a,0x6b04,0x6514,0x7c43,0x95cc,0x862d,0x703e,0x8b95,
+    0x652c,0x89bd,0x61f6,0x7e9c,0x721b,0x6feb,0x7405,0x6994,0x72fc,0x5eca,
+    0x90ce,0x6717,0x6d6a,0x6488,0x52de,0x7262,0x8001,0x4f6c,0x59e5,0x916a,
+    0x70d9,0x6f87,0x52d2,0x6a02,0x96f7,0x9433,0x857e,0x78ca,0x7d2f,0x5121,
+    0x58d8,0x64c2,0x808b,0x985e,0x6cea,0x68f1,0x695e,0x51b7,0x5398,0x68a8,
+    0x7281,0x9ece,0x7c6c,0x72f8,0x96e2,0x7055,0x7406,0x674e,0x88cf,0x9bc9,
+    0x79ae,0x8389,0x8354,0x540f,0x6817,0x9e97,0x53b2,0x52f5,0x792b,0x6b77,
+    0x5229,0x5088,0x4f8b,0x4fd0
+  },
+  {				/* ku 21 */
+    0x75e2,0x7acb,0x7c92,0x701d,0x96b8,0x529b,0x7483,0x54e9,0x5006,0x806f,
+    0x84ee,0x9023,0x942e,0x5ec9,0x6190,0x6f23,0x7c3e,0x6582,0x81c9,0x93c8,
+    0x6200,0x7149,0x7df4,0x7ce7,0x51c9,0x6881,0x7cb1,0x826f,0x5169,0x8f1b,
+    0x91cf,0x667e,0x4eae,0x8ad2,0x64a9,0x804a,0x50da,0x7642,0x71ce,0x5be5,
+    0x907c,0x6f66,0x4e86,0x6482,0x9410,0x5ed6,0x6599,0x5217,0x88c2,0x70c8,
+    0x52a3,0x7375,0x7433,0x6797,0x78f7,0x9716,0x81e8,0x9130,0x9c57,0x6dcb,
+    0x51db,0x8cc3,0x541d,0x62ce,0x73b2,0x83f1,0x96f6,0x9f61,0x9234,0x4f36,
+    0x7f9a,0x51cc,0x9748,0x9675,0x5dba,0x9818,0x53e6,0x4ee4,0x6e9c,0x7409,
+    0x69b4,0x786b,0x993e,0x7559,0x5289,0x7624,0x6d41,0x67f3,0x516d,0x9f8d,
+    0x807e,0x56a8,0x7c60,0x7abf
+  },
+  {				/* ku 22 */
+    0x9686,0x58df,0x650f,0x96b4,0x6a13,0x5a41,0x645f,0x7c0d,0x6f0f,0x964b,
+    0x8606,0x76e7,0x9871,0x5eec,0x7210,0x64c4,0x6ef7,0x865c,0x9b6f,0x9e93,
+    0x788c,0x9732,0x8def,0x8cc2,0x9e7f,0x6f5e,0x7984,0x9332,0x9678,0x622e,
+    0x9a62,0x5415,0x92c1,0x4fa3,0x65c5,0x5c65,0x5c62,0x7e37,0x616e,0x6c2f,
+    0x5f8b,0x7387,0x6ffe,0x7dd1,0x5dd2,0x6523,0x5b7f,0x7064,0x5375,0x4e82,
+    0x63a0,0x7565,0x6384,0x8f2a,0x502b,0x4f96,0x6dea,0x7db8,0x8ad6,0x863f,
+    0x87ba,0x7f85,0x908f,0x947c,0x7c6e,0x9a3e,0x88f8,0x843d,0x6d1b,0x99f1,
+    0x7d61,0x5abd,0x9ebb,0x746a,0x78bc,0x879e,0x99ac,0x99e1,0x561b,0x55ce,
+    0x57cb,0x8cb7,0x9ea5,0x8ce3,0x9081,0x8109,0x779e,0x9945,0x883b,0x6eff,
+    0x8513,0x66fc,0x6162,0x6f2b
+  },
+  {				/* ku 23 */
+    0x8b3e,0x8292,0x832b,0x76f2,0x6c13,0x5fd9,0x83bd,0x732b,0x8305,0x9328,
+    0x6bdb,0x77db,0x925a,0x536f,0x8302,0x5192,0x5e3d,0x8c8c,0x8cbf,0x9ebd,
+    0x73ab,0x679a,0x6885,0x9176,0x9709,0x7164,0x6ca1,0x7709,0x5a92,0x9382,
+    0x6bcf,0x7f8e,0x6627,0x5bd0,0x59b9,0x5a9a,0x9580,0x60b6,0x5011,0x840c,
+    0x8499,0x6aac,0x76df,0x9333,0x731b,0x5922,0x5b5f,0x772f,0x919a,0x9761,
+    0x7cdc,0x8ff7,0x8b0e,0x5f4c,0x7c73,0x79d8,0x8993,0x6ccc,0x871c,0x5bc6,
+    0x5e42,0x68c9,0x7720,0x7dbf,0x5195,0x514d,0x52c9,0x5a29,0x7dec,0x9762,
+    0x82d7,0x63cf,0x7784,0x85d0,0x79d2,0x6e3a,0x5edf,0x5999,0x8511,0x6ec5,
+    0x6c11,0x62bf,0x76bf,0x654f,0x61ab,0x95a9,0x660e,0x879f,0x9cf4,0x9298,
+    0x540d,0x547d,0x8b2c,0x6478
+  },
+  {				/* ku 24 */
+    0x6479,0x8611,0x6a21,0x819c,0x78e8,0x6469,0x9b54,0x62b9,0x672b,0x83ab,
+    0x58a8,0x9ed8,0x6cab,0x6f20,0x5bde,0x964c,0x8b00,0x725f,0x67d0,0x62c7,
+    0x7261,0x755d,0x59c6,0x6bcd,0x5893,0x66ae,0x5e55,0x52df,0x6155,0x6728,
+    0x76ee,0x7766,0x7267,0x7a46,0x62ff,0x54ea,0x5450,0x9209,0x90a3,0x5a1c,
+    0x7d0d,0x6c16,0x4e43,0x5976,0x8010,0x5948,0x5357,0x7537,0x96e3,0x56ca,
+    0x6493,0x8166,0x60f1,0x9b27,0x6dd6,0x5462,0x9912,0x5185,0x5ae9,0x80fd,
+    0x59ae,0x9713,0x502a,0x6ce5,0x5c3c,0x64ec,0x4f60,0x533f,0x81a9,0x9006,
+    0x6eba,0x852b,0x62c8,0x5e74,0x78be,0x6506,0x637b,0x5ff5,0x5a18,0x91c0,
+    0x9ce5,0x5c3f,0x634f,0x8076,0x5b7d,0x5699,0x9477,0x93b3,0x6d85,0x60a8,
+    0x6ab8,0x7370,0x51dd,0x5be7
+  },
+  {				/* ku 25 */
+    0x64f0,0x6fd8,0x725b,0x626d,0x9215,0x7d10,0x81bf,0x6fc3,0x8fb2,0x5f04,
+    0x5974,0x52aa,0x6012,0x5973,0x6696,0x8650,0x7627,0x632a,0x61e6,0x7cef,
+    0x8afe,0x54e6,0x6b50,0x9dd7,0x6bc6,0x85d5,0x5614,0x5076,0x6f1a,0x556a,
+    0x8db4,0x722c,0x5e15,0x6015,0x7436,0x62cd,0x6392,0x724c,0x5f98,0x6e43,
+    0x6d3e,0x6500,0x6f58,0x76e4,0x78d0,0x76fc,0x7554,0x5224,0x53db,0x4e53,
+    0x9f90,0x65c1,0x802a,0x80d6,0x629b,0x5486,0x5228,0x70ae,0x888d,0x8dd1,
+    0x6ce1,0x5478,0x80da,0x57f9,0x88f4,0x8ce0,0x966a,0x914d,0x4f69,0x6c9b,
+    0x5674,0x76c6,0x7830,0x62a8,0x70f9,0x6f8e,0x5f6d,0x84ec,0x68da,0x787c,
+    0x7bf7,0x81a8,0x670b,0x9d6c,0x6367,0x78b0,0x576f,0x7812,0x9739,0x6279,
+    0x62ab,0x5288,0x7435,0x6bd7
+  },
+  {				/* ku 26 */
+    0x5564,0x813e,0x75b2,0x76ae,0x5339,0x75de,0x50fb,0x5c41,0x8b6c,0x7bc7,
+    0x504f,0x7247,0x9a19,0x98c4,0x6f02,0x74e2,0x7968,0x6487,0x77a5,0x62fc,
+    0x983b,0x8ca7,0x54c1,0x8058,0x4e52,0x576a,0x860b,0x840d,0x5e73,0x6191,
+    0x74f6,0x8a55,0x5c4f,0x5761,0x6f51,0x9817,0x5a46,0x7834,0x9b44,0x8feb,
+    0x7c95,0x5256,0x64b2,0x92ea,0x50d5,0x8386,0x8461,0x83e9,0x84b2,0x57d4,
+    0x6a38,0x5703,0x666e,0x6d66,0x8b5c,0x66dd,0x7011,0x671f,0x6b3a,0x68f2,
+    0x621a,0x59bb,0x4e03,0x51c4,0x6f06,0x67d2,0x6c8f,0x5176,0x68cb,0x5947,
+    0x6b67,0x7566,0x5d0e,0x81cd,0x9f4a,0x65d7,0x7948,0x7941,0x9a0e,0x8d77,
+    0x8c48,0x4e5e,0x4f01,0x5553,0x5951,0x780c,0x5668,0x6c23,0x8fc4,0x68c4,
+    0x6c7d,0x6ce3,0x8a16,0x6390
+  },
+  {				/* ku 27 */
+    0x6070,0x6d3d,0x727d,0x6266,0x91fa,0x925b,0x5343,0x9077,0x7c3d,0x4edf,
+    0x8b19,0x4e7e,0x9ed4,0x9322,0x9257,0x524d,0x6f5b,0x9063,0x6dfa,0x8b74,
+    0x5879,0x5d4c,0x6b20,0x6b49,0x69cd,0x55c6,0x8154,0x7f8c,0x58bb,0x8594,
+    0x5f3a,0x6436,0x6a47,0x936c,0x6572,0x6084,0x6a4b,0x77a7,0x55ac,0x50d1,
+    0x5de7,0x9798,0x64ac,0x7ff9,0x5ced,0x4fcf,0x7ac5,0x5207,0x8304,0x4e14,
+    0x602f,0x7aca,0x6b3d,0x4fb5,0x89aa,0x79e6,0x7434,0x52e4,0x82b9,0x64d2,
+    0x79bd,0x5be2,0x6c81,0x9752,0x8f15,0x6c2b,0x50be,0x537f,0x6e05,0x64ce,
+    0x6674,0x6c30,0x60c5,0x9803,0x8acb,0x6176,0x74ca,0x7aae,0x79cb,0x4e18,
+    0x90b1,0x7403,0x6c42,0x56da,0x914b,0x6cc5,0x8da8,0x5340,0x86c6,0x66f2,
+    0x8ec0,0x5c48,0x9a45,0x6e20
+  },
+  {				/* ku 28 */
+    0x53d6,0x5a36,0x9f72,0x8da3,0x53bb,0x5708,0x9874,0x6b0a,0x919b,0x6cc9,
+    0x5168,0x75ca,0x62f3,0x72ac,0x5238,0x52f8,0x7f3a,0x7094,0x7638,0x5374,
+    0x9d72,0x69b7,0x78ba,0x96c0,0x88d9,0x7fa4,0x7136,0x71c3,0x5189,0x67d3,
+    0x74e4,0x58e4,0x6518,0x56b7,0x8b93,0x9952,0x64fe,0x7e5e,0x60f9,0x71b1,
+    0x58ec,0x4ec1,0x4eba,0x5fcd,0x97cc,0x4efb,0x8a8d,0x5203,0x598a,0x7d09,
+    0x6254,0x4ecd,0x65e5,0x620e,0x8338,0x84c9,0x69ae,0x878d,0x7194,0x6eb6,
+    0x5bb9,0x7d68,0x5197,0x63c9,0x67d4,0x8089,0x8339,0x8815,0x5112,0x5b7a,
+    0x5982,0x8fb1,0x4e73,0x6c5d,0x5165,0x8925,0x8edf,0x962e,0x854a,0x745e,
+    0x92ed,0x958f,0x6f64,0x82e5,0x5f31,0x6492,0x7051,0x85a9,0x816e,0x9c13,
+    0x585e,0x8cfd,0x4e09,0x53c1
+  },
+  {				/* ku 29 */
+    0x5098,0x6563,0x6851,0x55d3,0x55aa,0x6414,0x9a37,0x6383,0x5ac2,0x745f,
+    0x8272,0x6f80,0x68ee,0x50e7,0x838e,0x7802,0x6bba,0x5239,0x6c99,0x7d17,
+    0x50bb,0x5565,0x715e,0x7be9,0x66ec,0x73ca,0x82eb,0x6749,0x5c71,0x5220,
+    0x717d,0x886b,0x9583,0x965d,0x64c5,0x8d0d,0x81b3,0x5584,0x6c55,0x6247,
+    0x7e55,0x5892,0x50b7,0x5546,0x8cde,0x664c,0x4e0a,0x5c1a,0x88f3,0x68a2,
+    0x634e,0x7a0d,0x71d2,0x828d,0x52fa,0x97f6,0x5c11,0x54e8,0x90b5,0x7d39,
+    0x5962,0x8cd2,0x86c7,0x820c,0x6368,0x8d66,0x651d,0x5c04,0x61fe,0x6d89,
+    0x793e,0x8a2d,0x7837,0x7533,0x547b,0x4f38,0x8eab,0x6df1,0x5a20,0x7d33,
+    0x795e,0x6c88,0x5be9,0x5b38,0x751a,0x814e,0x614e,0x6ef2,0x8072,0x751f,
+    0x7525,0x7272,0x5347,0x7e69
+  },
+  {				/* ku 2a */
+    0x7701,0x76db,0x5269,0x52dd,0x8056,0x5e2b,0x5931,0x7345,0x65bd,0x6fd5,
+    0x8a69,0x5c38,0x8671,0x5341,0x77f3,0x62fe,0x6642,0x4ec0,0x98df,0x8755,
+    0x5be6,0x8b58,0x53f2,0x77e2,0x4f7f,0x5c4e,0x99db,0x59cb,0x5f0f,0x793a,
+    0x58eb,0x4e16,0x67ff,0x4e8b,0x62ed,0x8a93,0x901d,0x52e2,0x662f,0x55dc,
+    0x566c,0x9069,0x4ed5,0x4f8d,0x91cb,0x98fe,0x6c0f,0x5e02,0x6043,0x5ba4,
+    0x8996,0x8a66,0x6536,0x624b,0x9996,0x5b88,0x58fd,0x6388,0x552e,0x53d7,
+    0x7626,0x7378,0x852c,0x6a1e,0x68b3,0x6b8a,0x6292,0x8f38,0x53d4,0x8212,
+    0x6dd1,0x758f,0x66f8,0x8d16,0x5b70,0x719f,0x85af,0x6691,0x66d9,0x7f72,
+    0x8700,0x9ecd,0x9f20,0x5c6c,0x8853,0x8ff0,0x6a39,0x675f,0x620d,0x7aea,
+    0x5885,0x5eb6,0x6578,0x6f31
+  },
+  {				/* ku 2b */
+    0x6055,0x5237,0x800d,0x6454,0x8870,0x7529,0x5e25,0x6813,0x62f4,0x971c,
+    0x96d9,0x723d,0x8ab0,0x6c34,0x7761,0x7a0e,0x542e,0x77ac,0x9806,0x821c,
+    0x8aac,0x78a9,0x6714,0x720d,0x65af,0x6495,0x5636,0x601d,0x79c1,0x53f8,
+    0x7d72,0x6b7b,0x8086,0x5bfa,0x55e3,0x56db,0x4f3a,0x4f3c,0x98fc,0x5df3,
+    0x9b06,0x8073,0x616b,0x980c,0x9001,0x5b8b,0x8a1f,0x8aa6,0x641c,0x8258,
+    0x64fb,0x55fd,0x8607,0x9165,0x4fd7,0x7d20,0x901f,0x7c9f,0x50f3,0x5851,
+    0x6eaf,0x5bbf,0x8a34,0x8085,0x9178,0x849c,0x7b97,0x96d6,0x968b,0x96a8,
+    0x7d8f,0x9ad3,0x788e,0x6b72,0x7a57,0x9042,0x96a7,0x795f,0x5b6b,0x640d,
+    0x7b0b,0x84d1,0x68ad,0x5506,0x7e2e,0x7463,0x7d22,0x9396,0x6240,0x584c,
+    0x4ed6,0x5b83,0x5979,0x5854
+  },
+  {				/* ku 2c */
+    0x737a,0x64bb,0x8e4b,0x8e0f,0x80ce,0x82d4,0x62ac,0x81fa,0x6cf0,0x915e,
+    0x592a,0x614b,0x6c70,0x574d,0x6524,0x8caa,0x7671,0x7058,0x58c7,0x6a80,
+    0x75f0,0x6f6d,0x8b5a,0x8ac7,0x5766,0x6bef,0x8892,0x78b3,0x63a2,0x5606,
+    0x70ad,0x6e6f,0x5858,0x642a,0x5802,0x68e0,0x819b,0x5510,0x7cd6,0x5018,
+    0x8eba,0x6dcc,0x8d9f,0x71d9,0x638f,0x6fe4,0x6ed4,0x7e27,0x8404,0x6843,
+    0x9003,0x6dd8,0x9676,0x8a0e,0x5957,0x7279,0x85e4,0x9a30,0x75bc,0x8b04,
+    0x68af,0x5254,0x8e22,0x92bb,0x63d0,0x984c,0x8e44,0x557c,0x9ad4,0x66ff,
+    0x568f,0x60d5,0x6d95,0x5243,0x5c49,0x5929,0x6dfb,0x586b,0x7530,0x751c,
+    0x606c,0x8214,0x8146,0x6311,0x689d,0x8fe2,0x773a,0x8df3,0x8cbc,0x9435,
+    0x5e16,0x5ef3,0x807d,0x70f4
+  },
+  {				/* ku 2d */
+    0x6c40,0x5ef7,0x505c,0x4ead,0x5ead,0x633a,0x8247,0x901a,0x6850,0x916e,
+    0x77b3,0x540c,0x9285,0x5f64,0x7ae5,0x6876,0x6345,0x7b52,0x7d71,0x75db,
+    0x5077,0x6295,0x982d,0x900f,0x51f8,0x79c3,0x7a81,0x5716,0x5f92,0x9014,
+    0x5857,0x5c60,0x571f,0x5410,0x5154,0x6e4d,0x5718,0x63a8,0x983d,0x817f,
+    0x8715,0x892a,0x9000,0x541e,0x5c6f,0x81c0,0x62d6,0x6258,0x8131,0x9d15,
+    0x9640,0x99b1,0x99dd,0x6a62,0x59a5,0x62d3,0x553e,0x6316,0x54c7,0x86d9,
+    0x7aaa,0x5a03,0x74e6,0x896a,0x6b6a,0x5916,0x8c4c,0x5f4e,0x7063,0x73a9,
+    0x9811,0x4e38,0x70f7,0x5b8c,0x7897,0x633d,0x665a,0x7696,0x60cb,0x5b9b,
+    0x5a49,0x842c,0x8155,0x6c6a,0x738b,0x4ea1,0x6789,0x7db2,0x5f80,0x65fa,
+    0x671b,0x5fd8,0x5984,0x5a01
+  },
+  {				/* ku 2e */
+    0x5dcd,0x5fae,0x5371,0x97cb,0x9055,0x6845,0x570d,0x552f,0x60df,0x7232,
+    0x6ff0,0x7dad,0x8466,0x840e,0x59d4,0x5049,0x50de,0x5c3e,0x7def,0x672a,
+    0x851a,0x5473,0x754f,0x80c3,0x5582,0x9b4f,0x4f4d,0x6e2d,0x8b02,0x5c09,
+    0x6170,0x885b,0x761f,0x6e29,0x868a,0x6587,0x805e,0x7d0b,0x543b,0x7a69,
+    0x7d0a,0x554f,0x55e1,0x7fc1,0x74ee,0x64be,0x8778,0x6e26,0x7aa9,0x6211,
+    0x65a1,0x5367,0x63e1,0x6c83,0x5deb,0x55da,0x93a2,0x70cf,0x6c61,0x8aa3,
+    0x5c4b,0x7121,0x856a,0x68a7,0x543e,0x5434,0x6bcb,0x6b66,0x4e94,0x6342,
+    0x5348,0x821e,0x4f0d,0x4fae,0x5862,0x620a,0x9727,0x6664,0x7269,0x52ff,
+    0x52d9,0x609f,0x8aa4,0x6614,0x7199,0x6790,0x897f,0x7852,0x77fd,0x6670,
+    0x563b,0x5438,0x932b,0x72a7
+  },
+  {				/* ku 2f */
+    0x7a00,0x606f,0x5e0c,0x6089,0x819d,0x5915,0x60dc,0x7184,0x70ef,0x6eaa,
+    0x6c50,0x7280,0x6a84,0x8972,0x5e2d,0x7fd2,0x5ab3,0x559c,0x9291,0x6d17,
+    0x7cfb,0x9699,0x6232,0x7d30,0x778e,0x8766,0x5323,0x971e,0x8f44,0x6687,
+    0x5cfd,0x4fe0,0x72f9,0x4e0b,0x53a6,0x590f,0x5687,0x6380,0x9341,0x5148,
+    0x4ed9,0x9bae,0x7e96,0x54b8,0x8ce2,0x929c,0x8237,0x9591,0x6d8e,0x5f26,
+    0x5acc,0x986f,0x96aa,0x73fe,0x737b,0x7e23,0x817a,0x9921,0x7fa1,0x61b2,
+    0x9677,0x9650,0x7dab,0x76f8,0x53a2,0x9472,0x9999,0x7bb1,0x8944,0x6e58,
+    0x9109,0x7fd4,0x7965,0x8a73,0x60f3,0x97ff,0x4eab,0x9805,0x5df7,0x6a61,
+    0x50cf,0x5411,0x8c61,0x856d,0x785d,0x9704,0x524a,0x54ee,0x56c2,0x92b7,
+    0x6d88,0x5bb5,0x6dc6,0x66c9
+  },
+  {				/* ku 30 */
+    0x5c0f,0x5b5d,0x6821,0x8096,0x562f,0x7b11,0x6548,0x6954,0x4e9b,0x6b47,
+    0x874e,0x978b,0x5354,0x633e,0x643a,0x90aa,0x659c,0x8105,0x8ae7,0x5beb,
+    0x68b0,0x5378,0x87f9,0x61c8,0x6cc4,0x7009,0x8b1d,0x5c51,0x85aa,0x82af,
+    0x92c5,0x6b23,0x8f9b,0x65b0,0x5ffb,0x5fc3,0x4fe1,0x91c1,0x661f,0x8165,
+    0x7329,0x60fa,0x8208,0x5211,0x578b,0x5f62,0x90a2,0x884c,0x9192,0x5e78,
+    0x674f,0x6027,0x59d3,0x5144,0x51f6,0x80f8,0x5308,0x6c79,0x96c4,0x718a,
+    0x4f11,0x4fee,0x7f9e,0x673d,0x55c5,0x92b9,0x79c0,0x8896,0x7d89,0x589f,
+    0x620c,0x9700,0x865a,0x5618,0x9808,0x5f90,0x8a31,0x84c4,0x9157,0x53d9,
+    0x65ed,0x5e8f,0x755c,0x6064,0x7d6e,0x5a7f,0x7dd2,0x7e8c,0x8ed2,0x55a7,
+    0x5ba3,0x61f8,0x65cb,0x7384
+  },
+  {				/* ku 31 */
+    0x9078,0x766c,0x7729,0x7d62,0x9774,0x859b,0x5b78,0x7a74,0x96ea,0x8840,
+    0x52db,0x718f,0x5faa,0x65ec,0x8a62,0x5c0b,0x99b4,0x5de1,0x6b89,0x6c5b,
+    0x8a13,0x8a0a,0x905c,0x8fc5,0x58d3,0x62bc,0x9d09,0x9d28,0x5440,0x4e2b,
+    0x82bd,0x7259,0x869c,0x5d16,0x8859,0x6daf,0x96c5,0x555e,0x4e9e,0x8a1d,
+    0x7109,0x54bd,0x95b9,0x70df,0x6df9,0x9e7d,0x56b4,0x7814,0x8712,0x5ca9,
+    0x5ef6,0x8a00,0x9854,0x95bb,0x708e,0x6cbf,0x5944,0x63a9,0x773c,0x884d,
+    0x6f14,0x8277,0x5830,0x71d5,0x53ad,0x786f,0x96c1,0x5501,0x5f66,0x7130,
+    0x5bb4,0x8afa,0x9a57,0x6b83,0x592e,0x9d26,0x79e7,0x694a,0x63da,0x4f6f,
+    0x760d,0x7f8a,0x6d0b,0x967d,0x6c27,0x4ef0,0x7662,0x990a,0x6a23,0x6f3e,
+    0x9080,0x8170,0x5996,0x7476
+  },
+  {				/* ku 32 */
+    0x6447,0x582f,0x9065,0x7a91,0x8b21,0x59da,0x54ac,0x8200,0x85e5,0x8981,
+    0x8000,0x6930,0x564e,0x8036,0x723a,0x91ce,0x51b6,0x4e5f,0x9801,0x6396,
+    0x696d,0x8449,0x66f3,0x814b,0x591c,0x6db2,0x4e00,0x58f9,0x91ab,0x63d6,
+    0x92a5,0x4f9d,0x4f0a,0x8863,0x9824,0x5937,0x907a,0x79fb,0x5100,0x80f0,
+    0x7591,0x6c82,0x5b9c,0x59e8,0x5f5d,0x6905,0x87fb,0x501a,0x5df2,0x4e59,
+    0x77e3,0x4ee5,0x85dd,0x6291,0x6613,0x9091,0x5c79,0x5104,0x5f79,0x81c6,
+    0x9038,0x8084,0x75ab,0x4ea6,0x88d4,0x610f,0x6bc5,0x61b6,0x7fa9,0x76ca,
+    0x6ea2,0x8a63,0x8b70,0x8abc,0x8b6f,0x5f02,0x7ffc,0x7fcc,0x7e79,0x8335,
+    0x852d,0x56e0,0x6bb7,0x97f3,0x9670,0x59fb,0x541f,0x9280,0x6deb,0x5bc5,
+    0x98f2,0x5c39,0x5f15,0x96b1
+  },
+  {				/* ku 33 */
+    0x5370,0x82f1,0x6afb,0x5b30,0x9df9,0x61c9,0x7e93,0x7469,0x87a2,0x71df,
+    0x7192,0x8805,0x8fce,0x8d0f,0x76c8,0x5f71,0x7a4e,0x786c,0x6620,0x55b2,
+    0x64c1,0x50ad,0x81c3,0x7670,0x5eb8,0x96cd,0x8e34,0x86f9,0x548f,0x6cf3,
+    0x6d8c,0x6c38,0x607f,0x52c7,0x7528,0x5e7d,0x512a,0x60a0,0x6182,0x5c24,
+    0x7531,0x90f5,0x923e,0x7336,0x6cb9,0x6e38,0x9149,0x6709,0x53cb,0x53f3,
+    0x4f51,0x91c9,0x8a98,0x53c8,0x5e7c,0x8fc2,0x6de4,0x4e8e,0x76c2,0x6986,
+    0x865e,0x611a,0x8f3f,0x9918,0x4fde,0x903e,0x9b5a,0x6109,0x6e1d,0x6f01,
+    0x9685,0x4e88,0x5a31,0x96e8,0x8207,0x5dbc,0x79b9,0x5b87,0x8a9e,0x7fbd,
+    0x7389,0x57df,0x828b,0x9b31,0x5401,0x9047,0x55bb,0x5cea,0x5fa1,0x6108,
+    0x6b32,0x7344,0x80b2,0x8b7d
+  },
+  {				/* ku 34 */
+    0x6d74,0x5bd3,0x88d5,0x9810,0x8c6b,0x99ad,0x9d1b,0x6df5,0x51a4,0x5143,
+    0x57a3,0x8881,0x539f,0x63f4,0x8f45,0x5712,0x54e1,0x5713,0x733f,0x6e90,
+    0x7de3,0x9060,0x82d1,0x9858,0x6028,0x9662,0x66f0,0x7d04,0x8d8a,0x8e8d,
+    0x9470,0x5cb3,0x7ca4,0x6708,0x60a6,0x95b2,0x8018,0x96f2,0x9116,0x5300,
+    0x9695,0x5141,0x904b,0x85f4,0x9196,0x6688,0x97f5,0x5b55,0x531d,0x7838,
+    0x96dc,0x683d,0x54c9,0x707e,0x5bb0,0x8f09,0x518d,0x5728,0x54b1,0x6522,
+    0x66ab,0x8d0a,0x8d1c,0x81df,0x846c,0x906d,0x7cdf,0x947f,0x85fb,0x68d7,
+    0x65e9,0x6fa1,0x86a4,0x8e81,0x566a,0x9020,0x7682,0x7ac8,0x71e5,0x8cac,
+    0x64c7,0x5247,0x6fa4,0x8cca,0x600e,0x589e,0x618e,0x66fe,0x8d08,0x624e,
+    0x55b3,0x6e23,0x672d,0x8ecb
+  },
+  {				/* ku 35 */
+    0x9358,0x9598,0x7728,0x6805,0x69a8,0x548b,0x4e4d,0x70b8,0x8a50,0x6458,
+    0x9f4b,0x5b85,0x7a84,0x50b5,0x5be8,0x77bb,0x6c08,0x8a79,0x7c98,0x6cbe,
+    0x76de,0x65ac,0x8f3e,0x5d84,0x5c55,0x8638,0x68e7,0x5360,0x6230,0x7ad9,
+    0x6e5b,0x7dbb,0x6a1f,0x7ae0,0x5f70,0x6f33,0x5f35,0x638c,0x6f32,0x6756,
+    0x4e08,0x5e33,0x8cec,0x4ed7,0x8139,0x7634,0x969c,0x62db,0x662d,0x627e,
+    0x6cbc,0x8d99,0x7167,0x7f69,0x5146,0x8087,0x53ec,0x906e,0x6298,0x54f2,
+    0x87c4,0x8f4d,0x8005,0x937a,0x8517,0x9019,0x6d59,0x73cd,0x659f,0x771f,
+    0x7504,0x7827,0x81fb,0x8c9e,0x91dd,0x5075,0x6795,0x75b9,0x8a3a,0x9707,
+    0x632f,0x93ae,0x9663,0x84b8,0x6399,0x775c,0x5f81,0x7319,0x722d,0x6014,
+    0x6574,0x62ef,0x6b63,0x653f
+  },
+  {				/* ku 36 */
+    0x5e40,0x7665,0x912d,0x8b49,0x829d,0x679d,0x652f,0x5431,0x8718,0x77e5,
+    0x80a2,0x8102,0x6c41,0x4e4b,0x7e54,0x8077,0x76f4,0x690d,0x6b96,0x57f7,
+    0x503c,0x4f84,0x5740,0x6307,0x6b62,0x8dbe,0x8879,0x65e8,0x7d19,0x5fd7,
+    0x646f,0x64f2,0x81f3,0x81f4,0x7f6e,0x5e5f,0x5cd9,0x5236,0x667a,0x79e9,
+    0x7a1a,0x8cea,0x7099,0x75d4,0x6eef,0x6cbb,0x7a92,0x4e2d,0x76c5,0x5fe0,
+    0x9418,0x8877,0x7d42,0x7a2e,0x816b,0x91cd,0x4ef2,0x8846,0x821f,0x5468,
+    0x5dde,0x6d32,0x8b05,0x7ca5,0x8ef8,0x8098,0x5e1a,0x5492,0x76ba,0x5b99,
+    0x665d,0x9a5f,0x73e0,0x682a,0x86db,0x6731,0x732a,0x8af8,0x8a85,0x9010,
+    0x7af9,0x71ed,0x716e,0x62c4,0x77da,0x56d1,0x4e3b,0x8457,0x67f1,0x52a9,
+    0x86c0,0x8caf,0x9444,0x7bc9
+  },
+  {				/* ku 37 */
+    0x4f4f,0x6ce8,0x795d,0x99d0,0x6293,0x722a,0x62fd,0x5c08,0x78da,0x8f49,
+    0x64b0,0x8cfa,0x7bc6,0x6a01,0x838a,0x88dd,0x599d,0x649e,0x58ef,0x72c0,
+    0x690e,0x9310,0x8ffd,0x8d05,0x589c,0x7db4,0x8ac4,0x6e96,0x6349,0x62d9,
+    0x5353,0x684c,0x7422,0x8301,0x914c,0x5544,0x7740,0x707c,0x6fc1,0x5179,
+    0x54a8,0x8cc7,0x59ff,0x6ecb,0x6dc4,0x5b5c,0x7d2b,0x4ed4,0x7c7d,0x6ed3,
+    0x5b50,0x81ea,0x6f2c,0x5b57,0x9b03,0x68d5,0x8e2a,0x5b97,0x7d9c,0x7e3d,
+    0x7e31,0x9112,0x8d70,0x594f,0x63cd,0x79df,0x8db3,0x5352,0x65cf,0x7956,
+    0x8a5b,0x963b,0x7d44,0x947d,0x7e82,0x5634,0x9189,0x6700,0x7f6a,0x5c0a,
+    0x9075,0x6628,0x5de6,0x4f50,0x67de,0x505a,0x4f5c,0x5750,0x5ea7,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 38 */
+    0x4e8d,0x4e0c,0x5140,0x4e10,0x5eff,0x5345,0x4e15,0x4e98,0x4e1e,0x9b32,
+    0x5b6c,0x5669,0x4e28,0x79ba,0x4e3f,0x5315,0x4e47,0x592d,0x723b,0x536e,
+    0x6c10,0x56df,0x80e4,0x9997,0x6bd3,0x777e,0x9f17,0x4e36,0x4e9f,0x9f10,
+    0x4e5c,0x4e69,0x4e93,0x8288,0x5b5b,0x55c7,0x560f,0x4ec4,0x5399,0x539d,
+    0x53b4,0x53a5,0x53ae,0x9768,0x8d0b,0x531a,0x53f5,0x532d,0x5331,0x533e,
+    0x8cfe,0x5366,0x5363,0x5202,0x5208,0x520e,0x5244,0x5233,0x528c,0x5274,
+    0x524c,0x525e,0x5261,0x525c,0x84af,0x527d,0x5282,0x5281,0x5290,0x5293,
+    0x5182,0x7f54,0x4ebb,0x4ec3,0x4ec9,0x4ec2,0x4ee8,0x4ee1,0x4eeb,0x4ede,
+    0x50b4,0x4ef3,0x4f22,0x4f64,0x4ef5,0x5000,0x5096,0x4f09,0x4f47,0x4f5e,
+    0x4f67,0x6538,0x4f5a,0x4f5d
+  },
+  {				/* ku 39 */
+    0x4f5f,0x4f57,0x4f32,0x4f3d,0x4f76,0x4f74,0x4f91,0x4f89,0x4f83,0x4f8f,
+    0x4f7e,0x4f7b,0x5115,0x4f7c,0x5102,0x4f94,0x5114,0x513c,0x5137,0x4fc5,
+    0x4fda,0x4fe3,0x4fdc,0x4fd1,0x4fdf,0x4ff8,0x5029,0x504c,0x4ff3,0x502c,
+    0x500f,0x502e,0x502d,0x4ffe,0x501c,0x500c,0x5025,0x5028,0x50e8,0x5043,
+    0x5055,0x5048,0x504e,0x506c,0x50c2,0x513b,0x5110,0x513a,0x50ba,0x50d6,
+    0x5106,0x50ed,0x50ec,0x50e6,0x50ee,0x5107,0x510b,0x4edd,0x6c3d,0x4f58,
+    0x50c9,0x4fce,0x9fa0,0x6c46,0x7cf4,0x516e,0x5dfd,0x9ecc,0x9998,0x56c5,
+    0x5914,0x52f9,0x530d,0x8a07,0x5310,0x9cec,0x5919,0x5155,0x4ea0,0x5156,
+    0x4eb3,0x886e,0x88a4,0x893b,0x81e0,0x88d2,0x7980,0x5b34,0x8803,0x7fb8,
+    0x51ab,0x51b1,0x51bd,0x51bc
+  },
+  {				/* ku 3a */
+    0x51c7,0x5196,0x51a2,0x51a5,0x8a01,0x8a10,0x8a0c,0x8a15,0x8b33,0x8a4e,
+    0x8a25,0x8a41,0x8a36,0x8a46,0x8a54,0x8a58,0x8a52,0x8a86,0x8a84,0x8a7f,
+    0x8a70,0x8a7c,0x8a75,0x8a6c,0x8a6e,0x8acd,0x8ae2,0x8a61,0x8a9a,0x8aa5,
+    0x8a91,0x8a92,0x8acf,0x8ad1,0x8ac9,0x8adb,0x8ad7,0x8ac2,0x8ab6,0x8af6,
+    0x8aeb,0x8b14,0x8b01,0x8ae4,0x8aed,0x8afc,0x8af3,0x8ae6,0x8aee,0x8ade,
+    0x8b28,0x8b9c,0x8b16,0x8b1a,0x8b10,0x8b2b,0x8b2d,0x8b56,0x8b59,0x8b4e,
+    0x8b9e,0x8b6b,0x8b96,0x5369,0x537a,0x961d,0x9622,0x9621,0x9631,0x962a,
+    0x963d,0x963c,0x9642,0x9658,0x9654,0x965f,0x9689,0x966c,0x9672,0x9674,
+    0x9688,0x968d,0x9697,0x96b0,0x9097,0x909b,0x913a,0x9099,0x9114,0x90a1,
+    0x90b4,0x90b3,0x90b6,0x9134
+  },
+  {				/* ku 3b */
+    0x90b8,0x90b0,0x90df,0x90c5,0x90be,0x9136,0x90c4,0x90c7,0x9106,0x9148,
+    0x90e2,0x90dc,0x90d7,0x90db,0x90eb,0x90ef,0x90fe,0x9104,0x9122,0x911e,
+    0x9123,0x9131,0x912f,0x9139,0x9143,0x9146,0x82bb,0x5950,0x52f1,0x52ac,
+    0x52ad,0x52be,0x54ff,0x52d0,0x52d6,0x52f0,0x53df,0x71ee,0x77cd,0x5ef4,
+    0x51f5,0x51fc,0x9b2f,0x53b6,0x5f01,0x755a,0x5df0,0x574c,0x580a,0x57a1,
+    0x587e,0x58bc,0x58c5,0x58d1,0x5729,0x572c,0x572a,0x5733,0x58d9,0x572e,
+    0x572f,0x58e2,0x573b,0x5742,0x5769,0x58e0,0x576b,0x58da,0x577c,0x577b,
+    0x5768,0x576d,0x5776,0x5773,0x57e1,0x57a4,0x578c,0x584f,0x57cf,0x57a7,
+    0x5816,0x5793,0x57a0,0x57d5,0x5852,0x581d,0x5864,0x57d2,0x57b8,0x57f4,
+    0x57ef,0x57f8,0x57e4,0x57dd
+  },
+  {				/* ku 3c */
+    0x580b,0x580d,0x57fd,0x57ed,0x5800,0x581e,0x5819,0x5844,0x5820,0x5865,
+    0x586c,0x5881,0x5889,0x589a,0x5880,0x99a8,0x9f19,0x61ff,0x8279,0x827d,
+    0x827f,0x828f,0x828a,0x82a8,0x8284,0x828e,0x8291,0x858c,0x8299,0x82ab,
+    0x8553,0x82be,0x82b0,0x85f6,0x82ca,0x82e3,0x8298,0x82b7,0x82ae,0x83a7,
+    0x8407,0x84ef,0x82a9,0x82b4,0x82a1,0x82aa,0x829f,0x82c4,0x82e7,0x82a4,
+    0x82e1,0x8309,0x82f7,0x82e4,0x8622,0x8307,0x82dc,0x82f4,0x82d2,0x82d8,
+    0x830c,0x82fb,0x82d3,0x8526,0x831a,0x8306,0x584b,0x7162,0x82e0,0x82d5,
+    0x831c,0x8351,0x8558,0x84fd,0x8308,0x8392,0x833c,0x8334,0x8331,0x839b,
+    0x854e,0x832f,0x834f,0x8347,0x8343,0x8588,0x8340,0x8317,0x85ba,0x832d,
+    0x833a,0x8333,0x7296,0x6ece
+  },
+  {				/* ku 3d */
+    0x8541,0x831b,0x85ce,0x8552,0x84c0,0x8452,0x8464,0x83b0,0x8378,0x8494,
+    0x8435,0x83a0,0x83aa,0x8393,0x839c,0x8385,0x837c,0x859f,0x83a9,0x837d,
+    0x8555,0x837b,0x8398,0x839e,0x83a8,0x9daf,0x8493,0x83c1,0x8401,0x83e5,
+    0x83d8,0x5807,0x8418,0x840b,0x83dd,0x83fd,0x83d6,0x841c,0x8438,0x8411,
+    0x8406,0x83d4,0x83df,0x840f,0x8403,0x83f8,0x83f9,0x83ea,0x83c5,0x83c0,
+    0x7e08,0x83f0,0x83e1,0x845c,0x8451,0x845a,0x8459,0x8473,0x8546,0x8488,
+    0x847a,0x8562,0x8478,0x843c,0x8446,0x8469,0x8476,0x851e,0x848e,0x8431,
+    0x846d,0x84c1,0x84cd,0x84d0,0x9a40,0x84bd,0x84d3,0x84ca,0x84bf,0x84ba,
+    0x863a,0x84a1,0x84b9,0x84b4,0x8497,0x93a3,0x8577,0x850c,0x750d,0x8538,
+    0x84f0,0x861e,0x851f,0x85fa
+  },
+  {				/* ku 3e */
+    0x8556,0x853b,0x84ff,0x84fc,0x8559,0x8548,0x8568,0x8564,0x855e,0x857a,
+    0x77a2,0x8543,0x8604,0x857b,0x85a4,0x85a8,0x8587,0x858f,0x8579,0x85ea,
+    0x859c,0x8585,0x85b9,0x85b7,0x85b0,0x861a,0x85c1,0x85dc,0x85ff,0x8627,
+    0x8605,0x8629,0x8616,0x863c,0x5efe,0x5f08,0x593c,0x5969,0x8037,0x5955,
+    0x595a,0x5958,0x530f,0x5c22,0x5c25,0x5c2c,0x5c37,0x624c,0x636b,0x6476,
+    0x62bb,0x62ca,0x62da,0x62d7,0x62ee,0x649f,0x62f6,0x6339,0x634b,0x6343,
+    0x63ad,0x63f6,0x6371,0x637a,0x638e,0x6451,0x636d,0x63ac,0x638a,0x6369,
+    0x63ae,0x645c,0x63f2,0x63f8,0x63e0,0x64b3,0x63c4,0x63de,0x63ce,0x6452,
+    0x63c6,0x63be,0x6504,0x6441,0x640b,0x641b,0x6420,0x640c,0x6426,0x6421,
+    0x645e,0x6516,0x646d,0x6496
+  },
+  {				/* ku 3f */
+    0x647a,0x64f7,0x64fc,0x6499,0x651b,0x64c0,0x64d0,0x64d7,0x64e4,0x64e2,
+    0x6509,0x6525,0x652e,0x5f0b,0x5fd2,0x7519,0x5f11,0x535f,0x53f1,0x5630,
+    0x53e9,0x53e8,0x53fb,0x5412,0x5416,0x5406,0x544b,0x5638,0x56c8,0x5454,
+    0x56a6,0x5443,0x5421,0x5504,0x54bc,0x5423,0x5432,0x5482,0x5494,0x5477,
+    0x5471,0x5464,0x549a,0x5680,0x5484,0x5476,0x5466,0x565d,0x54d0,0x54ad,
+    0x54c2,0x54b4,0x5660,0x54a7,0x54a6,0x5635,0x55f6,0x5472,0x54a3,0x5666,
+    0x54bb,0x54bf,0x54cc,0x5672,0x54da,0x568c,0x54a9,0x54aa,0x54a4,0x5665,
+    0x54cf,0x54de,0x561c,0x54e7,0x562e,0x54fd,0x5514,0x54f3,0x55e9,0x5523,
+    0x550f,0x5511,0x5527,0x552a,0x5616,0x558f,0x55b5,0x5549,0x56c0,0x5541,
+    0x5555,0x553f,0x5550,0x553c
+  },
+  {				/* ku 40 */
+    0x5537,0x5556,0x5575,0x5576,0x5577,0x5533,0x5530,0x555c,0x558b,0x55d2,
+    0x5583,0x55b1,0x55b9,0x5588,0x5581,0x559f,0x557e,0x55d6,0x5591,0x557b,
+    0x55df,0x560d,0x56b3,0x5594,0x5599,0x55ea,0x55f7,0x55c9,0x561f,0x55d1,
+    0x56c1,0x55ec,0x55d4,0x55e6,0x55dd,0x55c4,0x55ef,0x55e5,0x55f2,0x566f,
+    0x55cc,0x55cd,0x55e8,0x55f5,0x55e4,0x8f61,0x561e,0x5608,0x560c,0x5601,
+    0x56b6,0x5623,0x55fe,0x5600,0x5627,0x562d,0x5658,0x5639,0x5657,0x562c,
+    0x564d,0x5662,0x5659,0x5695,0x564c,0x5654,0x5686,0x5664,0x5671,0x566b,
+    0x567b,0x567c,0x5685,0x5693,0x56af,0x56d4,0x56d7,0x56dd,0x56e1,0x5707,
+    0x56eb,0x56f9,0x56ff,0x5704,0x570a,0x5709,0x571c,0x5e43,0x5e19,0x5e14,
+    0x5e11,0x5e6c,0x5e58,0x5e57
+  },
+  {				/* ku 41 */
+    0x5e37,0x5e44,0x5e54,0x5e5b,0x5e5e,0x5e61,0x5c8c,0x5c7a,0x5c8d,0x5c90,
+    0x5d87,0x5c88,0x5cf4,0x5c99,0x5c91,0x5d50,0x5c9c,0x5cb5,0x5ca2,0x5d2c,
+    0x5cac,0x5cab,0x5cb1,0x5ca3,0x5cc1,0x5cb7,0x5da7,0x5cd2,0x5da0,0x5ccb,
+    0x5d22,0x5d97,0x5d0d,0x5d27,0x5d26,0x5d2e,0x5d24,0x5d1e,0x5d06,0x5d1b,
+    0x5db8,0x5d3e,0x5d34,0x5d3d,0x5d6c,0x5d5b,0x5d6f,0x5d81,0x5d6b,0x5d4b,
+    0x5d4a,0x5d69,0x5d74,0x5d82,0x5d99,0x5d9d,0x8c73,0x5db7,0x5dd4,0x5f73,
+    0x5f77,0x5f82,0x5f87,0x5f89,0x540e,0x5fa0,0x5f99,0x5f9c,0x5fa8,0x5fad,
+    0x5fb5,0x5fbc,0x8862,0x5f61,0x72ad,0x72b0,0x72b4,0x7377,0x7341,0x72c3,
+    0x72c1,0x72ce,0x72cd,0x72d2,0x72e8,0x736a,0x72e9,0x733b,0x72f4,0x72f7,
+    0x7301,0x72f3,0x736b,0x72fa
+  },
+  {				/* ku 42 */
+    0x72fb,0x7317,0x7313,0x7380,0x730a,0x731e,0x731d,0x737c,0x7322,0x7339,
+    0x7325,0x732c,0x7338,0x7331,0x7350,0x734d,0x7357,0x7360,0x736c,0x736f,
+    0x737e,0x821b,0x5925,0x98e7,0x5924,0x5902,0x98e0,0x9933,0x98e9,0x993c,
+    0x98ea,0x98eb,0x98ed,0x98f4,0x9909,0x9911,0x4f59,0x991b,0x9937,0x993f,
+    0x9943,0x9948,0x9949,0x994a,0x994c,0x9962,0x5e80,0x5ee1,0x5e8b,0x5e96,
+    0x5ea5,0x5ea0,0x5eb9,0x5eb5,0x5ebe,0x5eb3,0x8ce1,0x5ed2,0x5ed1,0x5edb,
+    0x5ee8,0x5eea,0x81ba,0x5fc4,0x5fc9,0x5fd6,0x61fa,0x61ae,0x5fee,0x616a,
+    0x5fe1,0x5fe4,0x613e,0x60b5,0x6134,0x5fea,0x5fed,0x5ff8,0x6019,0x6035,
+    0x6026,0x601b,0x600f,0x600d,0x6029,0x602b,0x600a,0x61cc,0x6021,0x615f,
+    0x61e8,0x60fb,0x6137,0x6042
+  },
+  {				/* ku 43 */
+    0x606a,0x60f2,0x6096,0x609a,0x6173,0x609d,0x6083,0x6092,0x608c,0x609b,
+    0x611c,0x60bb,0x60b1,0x60dd,0x60d8,0x60c6,0x60da,0x60b4,0x6120,0x6192,
+    0x6115,0x6123,0x60f4,0x6100,0x610e,0x612b,0x614a,0x6175,0x61ac,0x6194,
+    0x61a7,0x61b7,0x61d4,0x61f5,0x5fdd,0x96b3,0x9582,0x9586,0x95c8,0x958e,
+    0x9594,0x958c,0x95e5,0x95ad,0x95ab,0x9b2e,0x95ac,0x95be,0x95b6,0x9b29,
+    0x95bf,0x95bd,0x95bc,0x95c3,0x95cb,0x95d4,0x95d0,0x95d5,0x95de,0x4e2c,
+    0x723f,0x6215,0x6c35,0x6c54,0x6c5c,0x6c4a,0x7043,0x6c85,0x6c90,0x6c94,
+    0x6c8c,0x6c68,0x6c69,0x6c74,0x6c76,0x6c86,0x6f59,0x6cd0,0x6cd4,0x6cad,
+    0x7027,0x7018,0x6cf1,0x6cd7,0x6cb2,0x6ce0,0x6cd6,0x6ffc,0x6ceb,0x6cee,
+    0x6cb1,0x6cd3,0x6cef,0x6d87
+  },
+  {				/* ku 44 */
+    0x6d39,0x6d27,0x6d0c,0x6d79,0x6e5e,0x6d07,0x6d04,0x6d19,0x6d0e,0x6d2b,
+    0x6fae,0x6d2e,0x6d35,0x6d1a,0x700f,0x6ef8,0x6f6f,0x6d33,0x6d91,0x6d6f,
+    0x6df6,0x6f7f,0x6d5e,0x6d93,0x6d94,0x6d5c,0x6d60,0x6d7c,0x6d63,0x6e1a,
+    0x6dc7,0x6dc5,0x6dde,0x7006,0x6dbf,0x6de0,0x6fa0,0x6de6,0x6ddd,0x6dd9,
+    0x700b,0x6dab,0x6e0c,0x6dae,0x6e2b,0x6e6e,0x6e4e,0x6e6b,0x6eb2,0x6e5f,
+    0x6e86,0x6e53,0x6e54,0x6e32,0x6e25,0x6e44,0x7067,0x6eb1,0x6e98,0x7044,
+    0x6f2d,0x7005,0x6ea5,0x6ea7,0x6ebd,0x6ebb,0x6eb7,0x6f77,0x6eb4,0x6ecf,
+    0x6e8f,0x6ec2,0x6e9f,0x6f62,0x7020,0x701f,0x6f24,0x6f15,0x6ef9,0x6f2f,
+    0x6f36,0x7032,0x6f74,0x6f2a,0x6f09,0x6f29,0x6f89,0x6f8d,0x6f8c,0x6f78,
+    0x6f72,0x6f7c,0x6f7a,0x7028
+  },
+  {				/* ku 45 */
+    0x6fc9,0x6fa7,0x6fb9,0x6fb6,0x6fc2,0x6fe1,0x6fee,0x6fde,0x6fe0,0x6fef,
+    0x701a,0x7023,0x701b,0x7039,0x7035,0x705d,0x705e,0x5b80,0x5b84,0x5b95,
+    0x5b93,0x5ba5,0x5bb8,0x752f,0x9a2b,0x6434,0x5be4,0x5bee,0x8930,0x5bf0,
+    0x8e47,0x8b07,0x8fb6,0x8fd3,0x8fd5,0x8fe5,0x8fee,0x8fe4,0x9087,0x8fe6,
+    0x9015,0x8fe8,0x9005,0x9004,0x900b,0x9090,0x9011,0x900d,0x9016,0x9021,
+    0x9035,0x9036,0x902d,0x902f,0x9044,0x9051,0x9052,0x9050,0x9068,0x9058,
+    0x9062,0x905b,0x66b9,0x9074,0x907d,0x9082,0x9088,0x9083,0x908b,0x5f50,
+    0x5f57,0x5f56,0x5f58,0x5c3b,0x54ab,0x5c50,0x5c59,0x5b71,0x5c63,0x5c68,
+    0x7fbc,0x5f33,0x5f29,0x5f2d,0x8274,0x5f3c,0x9b3b,0x5c6e,0x5981,0x5983,
+    0x598d,0x5af5,0x5ad7,0x59a3
+  },
+  {				/* ku 46 */
+    0x5997,0x59ca,0x5b00,0x599e,0x59a4,0x59d2,0x59b2,0x59af,0x59d7,0x59be,
+    0x5a6d,0x5b08,0x59dd,0x5b4c,0x59e3,0x59d8,0x59f9,0x5a0c,0x5a09,0x5aa7,
+    0x5afb,0x5a11,0x5a23,0x5a13,0x5a40,0x5a67,0x5a4a,0x5a55,0x5a3c,0x5a62,
+    0x5b0b,0x80ec,0x5aaa,0x5a9b,0x5a77,0x5a7a,0x5abe,0x5aeb,0x5ab2,0x5b21,
+    0x5b2a,0x5ab8,0x5ae0,0x5ae3,0x5b19,0x5ad6,0x5ae6,0x5ad8,0x5adc,0x5b09,
+    0x5b17,0x5b16,0x5b32,0x5b37,0x5b40,0x5c15,0x5c1c,0x5b5a,0x5b65,0x5b73,
+    0x5b51,0x5b53,0x5b62,0x99d4,0x99df,0x99d9,0x9a36,0x9a5b,0x99d1,0x99d8,
+    0x9a4d,0x9a4a,0x99e2,0x9a6a,0x9a0f,0x9a0d,0x9a05,0x9a42,0x9a2d,0x9a16,
+    0x9a41,0x9a2e,0x9a38,0x9a43,0x9a44,0x9a4f,0x9a65,0x9a64,0x7cf9,0x7d06,
+    0x7d02,0x7d07,0x7d08,0x7e8a
+  },
+  {				/* ku 47 */
+    0x7d1c,0x7d15,0x7d13,0x7d3a,0x7d32,0x7d31,0x7e10,0x7d3c,0x7d40,0x7d3f,
+    0x7d5d,0x7d4e,0x7d73,0x7d86,0x7d83,0x7d88,0x7dbe,0x7dba,0x7dcb,0x7dd4,
+    0x7dc4,0x7d9e,0x7dac,0x7db9,0x7da3,0x7db0,0x7dc7,0x7dd9,0x7dd7,0x7df9,
+    0x7df2,0x7e62,0x7de6,0x7df6,0x7df1,0x7e0b,0x7de1,0x7e09,0x7e1d,0x7e1f,
+    0x7e1e,0x7e2d,0x7e0a,0x7e11,0x7e7d,0x7e39,0x7e35,0x7e32,0x7e46,0x7e45,
+    0x7e88,0x7e5a,0x7e52,0x7e6e,0x7e7e,0x7e70,0x7e6f,0x7e98,0x5e7a,0x757f,
+    0x5ddb,0x753e,0x9095,0x738e,0x74a3,0x744b,0x73a2,0x739f,0x73cf,0x73c2,
+    0x74cf,0x73b7,0x73b3,0x73c0,0x73c9,0x73c8,0x73e5,0x73d9,0x980a,0x740a,
+    0x73e9,0x73e7,0x73de,0x74bd,0x743f,0x7489,0x742a,0x745b,0x7426,0x7425,
+    0x7428,0x7430,0x742e,0x742c
+  },
+  {				/* ku 48 */
+    0x741b,0x741a,0x7441,0x745c,0x7457,0x7455,0x7459,0x74a6,0x746d,0x747e,
+    0x749c,0x74d4,0x7480,0x7481,0x7487,0x748b,0x749e,0x74a8,0x74a9,0x7490,
+    0x74a7,0x74da,0x74ba,0x97d9,0x97de,0x97dc,0x674c,0x6753,0x675e,0x6748,
+    0x69aa,0x6aea,0x6787,0x676a,0x6773,0x6798,0x6898,0x6775,0x68d6,0x6a05,
+    0x689f,0x678b,0x6777,0x677c,0x67f0,0x6adb,0x67d8,0x6af3,0x67e9,0x67b0,
+    0x6ae8,0x67d9,0x67b5,0x67da,0x67b3,0x67dd,0x6800,0x67c3,0x67b8,0x67e2,
+    0x6adf,0x67c1,0x6a89,0x6832,0x6833,0x690f,0x6a48,0x684e,0x6968,0x6844,
+    0x69bf,0x6883,0x681d,0x6855,0x6a3a,0x6841,0x6a9c,0x6840,0x6b12,0x684a,
+    0x6849,0x6829,0x68b5,0x688f,0x6874,0x6877,0x6893,0x686b,0x6b1e,0x696e,
+    0x68fc,0x6add,0x69e7,0x68f9
+  },
+  {				/* ku 49 */
+    0x6b0f,0x68f0,0x690b,0x6901,0x6957,0x68e3,0x6910,0x6971,0x6939,0x6960,
+    0x6942,0x695d,0x6b16,0x696b,0x6980,0x6998,0x6978,0x6934,0x69cc,0x6aec,
+    0x6ada,0x69ce,0x6af8,0x6966,0x6963,0x6979,0x699b,0x69a7,0x69bb,0x69ab,
+    0x69ad,0x69d4,0x69b1,0x69c1,0x69ca,0x6ab3,0x6995,0x6ae7,0x698d,0x69ff,
+    0x6aa3,0x69ed,0x6a17,0x6a18,0x6a65,0x69f2,0x6a44,0x6a3e,0x6aa0,0x6a50,
+    0x6a5b,0x6a35,0x6a8e,0x6ad3,0x6a3d,0x6a28,0x6a58,0x6ade,0x6a91,0x6a90,
+    0x6aa9,0x6a97,0x6aab,0x7337,0x7352,0x6b81,0x6b82,0x6ba4,0x6b84,0x6b9e,
+    0x6bae,0x6b8d,0x6bab,0x6b9b,0x6baf,0x6baa,0x8ed4,0x8edb,0x8ef2,0x8efb,
+    0x8f64,0x8ef9,0x8efc,0x8eeb,0x8ee4,0x8f62,0x8efa,0x8efe,0x8f0a,0x8f07,
+    0x8f05,0x8f12,0x8f26,0x8f1e
+  },
+  {				/* ku 4a */
+    0x8f1f,0x8f1c,0x8f33,0x8f46,0x8f54,0x8ece,0x6214,0x6227,0x621b,0x621f,
+    0x6222,0x6221,0x6225,0x6224,0x6229,0x81e7,0x750c,0x74f4,0x74ff,0x750f,
+    0x7511,0x7513,0x6534,0x65ee,0x65ef,0x65f0,0x660a,0x66c7,0x6772,0x6603,
+    0x6615,0x6600,0x7085,0x66f7,0x661d,0x6634,0x6631,0x6636,0x6635,0x8006,
+    0x665f,0x66c4,0x6641,0x664f,0x6689,0x6661,0x6657,0x6677,0x6684,0x668c,
+    0x66d6,0x669d,0x66be,0x66db,0x66dc,0x66e6,0x66e9,0x8cc1,0x8cb0,0x8cba,
+    0x8cbd,0x8d04,0x8cb2,0x8cc5,0x8d10,0x8cd1,0x8cda,0x8cd5,0x8ceb,0x8ce7,
+    0x8cfb,0x8998,0x89ac,0x89a1,0x89bf,0x89a6,0x89af,0x89b2,0x89b7,0x726e,
+    0x729f,0x725d,0x7266,0x726f,0x727e,0x727f,0x7284,0x728b,0x728d,0x728f,
+    0x7292,0x6308,0x6332,0x63b0
+  },
+  {				/* ku 4b */
+    0x643f,0x64d8,0x8004,0x6bea,0x6bf3,0x6bfd,0x6bff,0x6bf9,0x6c05,0x6c0c,
+    0x6c06,0x6c0d,0x6c15,0x6c18,0x6c19,0x6c1a,0x6c21,0x6c2c,0x6c24,0x6c2a,
+    0x6c32,0x6535,0x6555,0x656b,0x7258,0x7252,0x7256,0x7230,0x8662,0x5216,
+    0x809f,0x809c,0x8093,0x80bc,0x670a,0x80bd,0x80b1,0x80ab,0x80ad,0x80b4,
+    0x80b7,0x6727,0x8156,0x80e9,0x81da,0x80db,0x80c2,0x80c4,0x80d9,0x80cd,
+    0x80d7,0x6710,0x80dd,0x811b,0x80f1,0x80f4,0x80ed,0x81be,0x810e,0x80f2,
+    0x80fc,0x6715,0x8112,0x8c5a,0x8161,0x811e,0x812c,0x8118,0x8132,0x8148,
+    0x814c,0x8153,0x8174,0x8159,0x815a,0x8171,0x8160,0x8169,0x817c,0x817d,
+    0x816d,0x8167,0x584d,0x5ab5,0x8188,0x8182,0x81cf,0x6ed5,0x81a3,0x81aa,
+    0x81cc,0x6726,0x81ca,0x81bb
+  },
+  {				/* ku 4c */
+    0x81c1,0x81a6,0x6b5f,0x6b37,0x6b39,0x6b43,0x6b46,0x6b59,0x98ae,0x98af,
+    0x98b6,0x98bc,0x98c6,0x98c8,0x6bb3,0x5f40,0x8f42,0x89f3,0x6590,0x9f4f,
+    0x6595,0x65bc,0x65c6,0x65c4,0x65c3,0x65cc,0x65ce,0x65d2,0x65d6,0x716c,
+    0x7152,0x7096,0x7197,0x70bb,0x70c0,0x70b7,0x70ab,0x70b1,0x71c1,0x70ca,
+    0x7110,0x7113,0x71dc,0x712f,0x7131,0x7173,0x715c,0x7168,0x7145,0x7172,
+    0x714a,0x7178,0x717a,0x7198,0x71b3,0x71b5,0x71a8,0x71a0,0x71e0,0x71d4,
+    0x71e7,0x71f9,0x721d,0x7228,0x706c,0x71fe,0x7166,0x71b9,0x623e,0x623d,
+    0x6243,0x6248,0x6249,0x793b,0x7940,0x7946,0x7949,0x795b,0x795c,0x7953,
+    0x795a,0x79b0,0x7957,0x7960,0x798e,0x7967,0x797a,0x79aa,0x798a,0x799a,
+    0x79a7,0x79b3,0x5fd1,0x5fd0
+  },
+  {				/* ku 4d */
+    0x61df,0x605d,0x605a,0x6067,0x6041,0x6059,0x6063,0x6164,0x6106,0x610d,
+    0x615d,0x61a9,0x619d,0x61cb,0x61e3,0x6207,0x8080,0x807f,0x6c93,0x6fa9,
+    0x6dfc,0x78ef,0x77f8,0x78ad,0x7809,0x7868,0x7818,0x7811,0x65ab,0x782d,
+    0x78b8,0x781d,0x7839,0x792a,0x7931,0x781f,0x783c,0x7825,0x782c,0x7823,
+    0x7829,0x784e,0x786d,0x7864,0x78fd,0x7826,0x7850,0x7847,0x784c,0x786a,
+    0x78e7,0x7893,0x789a,0x7887,0x78e3,0x78a1,0x78a3,0x78b2,0x78b9,0x78a5,
+    0x78d4,0x78d9,0x78c9,0x78ec,0x78f2,0x7905,0x78f4,0x7913,0x7924,0x791e,
+    0x7934,0x9f95,0x9ef9,0x9efb,0x9efc,0x76f1,0x7704,0x7798,0x76f9,0x7707,
+    0x7708,0x771a,0x7722,0x7719,0x772d,0x7726,0x7735,0x7738,0x775e,0x77bc,
+    0x7747,0x7743,0x775a,0x7768
+  },
+  {				/* ku 4e */
+    0x7762,0x7765,0x777f,0x778d,0x777d,0x7780,0x778c,0x7791,0x779f,0x77a0,
+    0x77b0,0x77b5,0x77bd,0x753a,0x7540,0x754e,0x754b,0x7548,0x755b,0x7572,
+    0x7579,0x7583,0x7f58,0x7f61,0x7f5f,0x8a48,0x7f68,0x7f86,0x7f71,0x7f79,
+    0x7f88,0x7f7e,0x76cd,0x76e5,0x8832,0x91d2,0x91d3,0x91d4,0x91d9,0x91d7,
+    0x91d5,0x91f7,0x91e7,0x91e4,0x9346,0x91f5,0x91f9,0x9208,0x9226,0x9245,
+    0x9211,0x9210,0x9201,0x9227,0x9204,0x9225,0x9200,0x923a,0x9266,0x9237,
+    0x9233,0x9255,0x923d,0x9238,0x925e,0x926c,0x926d,0x923f,0x9460,0x9230,
+    0x9249,0x9248,0x924d,0x922e,0x9239,0x9438,0x92ac,0x92a0,0x927a,0x92aa,
+    0x92ee,0x92cf,0x9403,0x92e3,0x943a,0x92b1,0x92a6,0x93a7,0x9296,0x92cc,
+    0x92a9,0x93f5,0x9293,0x927f
+  },
+  {				/* ku 4f */
+    0x93a9,0x929a,0x931a,0x92ab,0x9283,0x940b,0x92a8,0x92a3,0x9412,0x9338,
+    0x92f1,0x93d7,0x92e5,0x92f0,0x92ef,0x92e8,0x92bc,0x92dd,0x92f6,0x9426,
+    0x9427,0x92c3,0x92df,0x92e6,0x9312,0x9306,0x9369,0x931b,0x9340,0x9301,
+    0x9315,0x932e,0x9343,0x9307,0x9308,0x931f,0x9319,0x9365,0x9347,0x9376,
+    0x9354,0x9364,0x93aa,0x9370,0x9384,0x93e4,0x93d8,0x9428,0x9387,0x93cc,
+    0x9398,0x93b8,0x93bf,0x93a6,0x93b0,0x93b5,0x944c,0x93e2,0x93dc,0x93dd,
+    0x93cd,0x93de,0x93c3,0x93c7,0x93d1,0x9414,0x941d,0x93f7,0x9465,0x9413,
+    0x946d,0x9420,0x9479,0x93f9,0x9419,0x944a,0x9432,0x943f,0x9454,0x9463,
+    0x937e,0x77e7,0x77ec,0x96c9,0x79d5,0x79ed,0x79e3,0x79eb,0x7a06,0x5d47,
+    0x7a03,0x7a02,0x7a1e,0x7a14
+  },
+  {				/* ku 50 */
+    0x7a39,0x7a37,0x7a61,0x9ecf,0x99a5,0x7a70,0x7688,0x768e,0x7693,0x7699,
+    0x76a4,0x74de,0x74e0,0x752c,0x9ce9,0x9cf6,0x9d07,0x9d06,0x9d23,0x9d87,
+    0x9e15,0x9d1d,0x9d1f,0x9de5,0x9d2f,0x9dd9,0x9d30,0x9d42,0x9e1e,0x9d53,
+    0x9e1d,0x9d60,0x9d52,0x9df3,0x9d5c,0x9d61,0x9d93,0x9d6a,0x9d6f,0x9d89,
+    0x9d98,0x9d9a,0x9dc0,0x9da5,0x9da9,0x9dc2,0x9dbc,0x9e1a,0x9dd3,0x9dda,
+    0x9def,0x9de6,0x9df2,0x9df8,0x9e0c,0x9dfa,0x9e1b,0x7592,0x7594,0x7664,
+    0x7658,0x759d,0x7667,0x75a3,0x75b3,0x75b4,0x75b8,0x75c4,0x75b1,0x75b0,
+    0x75c3,0x75c2,0x7602,0x75cd,0x75e3,0x7646,0x75e6,0x75e4,0x7647,0x75e7,
+    0x7603,0x75f1,0x75fc,0x75ff,0x7610,0x7600,0x7649,0x760c,0x761e,0x760a,
+    0x7625,0x763b,0x7615,0x7619
+  },
+  {				/* ku 51 */
+    0x761b,0x763c,0x7622,0x7620,0x7640,0x762d,0x7630,0x766d,0x7635,0x7643,
+    0x766e,0x7633,0x764d,0x7669,0x7654,0x765c,0x7656,0x7672,0x766f,0x7fca,
+    0x7ae6,0x7a78,0x7a79,0x7a80,0x7a86,0x7a88,0x7a95,0x7ac7,0x7aa0,0x7aac,
+    0x7aa8,0x7ab6,0x7ab3,0x8864,0x8869,0x8872,0x887d,0x887f,0x8882,0x88a2,
+    0x8960,0x88b7,0x88bc,0x88c9,0x8933,0x88ce,0x895d,0x8947,0x88f1,0x891a,
+    0x88fc,0x88e8,0x88fe,0x88f0,0x8921,0x8919,0x8913,0x8938,0x890a,0x8964,
+    0x892b,0x8936,0x8941,0x8966,0x897b,0x758b,0x80e5,0x76b8,0x76b4,0x77dc,
+    0x8012,0x8014,0x8016,0x801c,0x8020,0x802e,0x8025,0x8026,0x802c,0x8029,
+    0x8028,0x8031,0x800b,0x8035,0x8043,0x8046,0x8079,0x8052,0x8075,0x8071,
+    0x8983,0x9807,0x980e,0x980f
+  },
+  {				/* ku 52 */
+    0x9821,0x981c,0x6f41,0x9826,0x9837,0x984e,0x9853,0x9873,0x9862,0x9859,
+    0x9865,0x986c,0x9870,0x864d,0x8654,0x866c,0x87e3,0x8806,0x867a,0x867c,
+    0x867b,0x86a8,0x868d,0x868b,0x8706,0x869d,0x86a7,0x86a3,0x86aa,0x8693,
+    0x86a9,0x86b6,0x86c4,0x86b5,0x8823,0x86b0,0x86ba,0x86b1,0x86af,0x86c9,
+    0x87f6,0x86b4,0x86e9,0x86fa,0x87ef,0x86ed,0x8784,0x86d0,0x8713,0x86de,
+    0x8810,0x86df,0x86d8,0x86d1,0x8703,0x8707,0x86f8,0x8708,0x870a,0x870d,
+    0x8709,0x8723,0x873b,0x871e,0x8725,0x872e,0x871a,0x873e,0x87c8,0x8734,
+    0x8731,0x8729,0x8737,0x873f,0x8782,0x8722,0x877d,0x8811,0x877b,0x8760,
+    0x8770,0x874c,0x876e,0x878b,0x8753,0x8763,0x87bb,0x8764,0x8759,0x8765,
+    0x8793,0x87af,0x87ce,0x87d2
+  },
+  {				/* ku 53 */
+    0x87c6,0x8788,0x8785,0x87ad,0x8797,0x8783,0x87ab,0x87e5,0x87ac,0x87b5,
+    0x87b3,0x87cb,0x87d3,0x87bd,0x87d1,0x87c0,0x87ca,0x87db,0x87ea,0x87e0,
+    0x87ee,0x8816,0x8813,0x87fe,0x880a,0x881b,0x8821,0x8839,0x883c,0x7f36,
+    0x7f4c,0x7f44,0x7f45,0x8210,0x7afa,0x7afd,0x7b08,0x7be4,0x7b04,0x7b67,
+    0x7b0a,0x7b2b,0x7b0f,0x7b47,0x7b38,0x7b2a,0x7b19,0x7b2e,0x7b31,0x7b20,
+    0x7b25,0x7b24,0x7b33,0x7c69,0x7b1e,0x7b58,0x7bf3,0x7b45,0x7b75,0x7b4c,
+    0x7b8f,0x7b60,0x7b6e,0x7b7b,0x7b62,0x7b72,0x7b71,0x7b90,0x7c00,0x7bcb,
+    0x7bb8,0x7bac,0x7b9d,0x7c5c,0x7b85,0x7c1e,0x7b9c,0x7ba2,0x7c2b,0x7bb4,
+    0x7c23,0x7bc1,0x7bcc,0x7bdd,0x7bda,0x7be5,0x7be6,0x7bea,0x7c0c,0x7bfe,
+    0x7bfc,0x7c0f,0x7c6a,0x7c0b
+  },
+  {				/* ku 54 */
+    0x7c1f,0x7c2a,0x7c26,0x7c38,0x7c5f,0x7c40,0x81fe,0x8201,0x8202,0x8204,
+    0x81ec,0x8844,0x8221,0x8222,0x8264,0x822d,0x822f,0x8228,0x822b,0x8238,
+    0x826b,0x8233,0x8234,0x823e,0x8244,0x8249,0x824b,0x824f,0x825a,0x825f,
+    0x8268,0x887e,0x88ca,0x8888,0x88d8,0x88df,0x895e,0x7f9d,0x7fa5,0x7fa7,
+    0x7faf,0x7fb0,0x7fb2,0x7c7c,0x6549,0x7c91,0x7cf2,0x7cf6,0x7c9e,0x7ca2,
+    0x7cb2,0x7cbc,0x7cbd,0x7cdd,0x7cc7,0x7ccc,0x7ccd,0x7cc8,0x7cc5,0x7cd7,
+    0x7ce8,0x826e,0x66a8,0x7fbf,0x7fce,0x7fd5,0x7fe5,0x7fe1,0x7fe6,0x7fe9,
+    0x7fee,0x7ff3,0x7cf8,0x7e36,0x7da6,0x7dae,0x7e47,0x7e9b,0x9ea9,0x9eb4,
+    0x8d73,0x8d84,0x8d94,0x8d91,0x8db2,0x8d67,0x8d6d,0x8c47,0x8c49,0x914a,
+    0x9150,0x914e,0x914f,0x9164
+  },
+  {				/* ku 55 */
+    0x9162,0x9161,0x9170,0x9169,0x916f,0x91c5,0x91c3,0x9172,0x9174,0x9179,
+    0x918c,0x9185,0x9190,0x918d,0x9191,0x91a2,0x91a3,0x91aa,0x91ad,0x91ae,
+    0x91af,0x91b5,0x91b4,0x91ba,0x8c55,0x9e7a,0x8e89,0x8deb,0x8e05,0x8e59,
+    0x8e69,0x8db5,0x8dbf,0x8dbc,0x8dba,0x8e4c,0x8dd6,0x8dd7,0x8dda,0x8e92,
+    0x8dce,0x8dcf,0x8ddb,0x8dc6,0x8dec,0x8e7a,0x8e55,0x8de3,0x8e9a,0x8e8b,
+    0x8de4,0x8e09,0x8dfd,0x8e14,0x8e1d,0x8e1f,0x8e93,0x8e2e,0x8e23,0x8e91,
+    0x8e3a,0x8e40,0x8e39,0x8e35,0x8e3d,0x8e31,0x8e49,0x8e41,0x8e42,0x8ea1,
+    0x8e63,0x8e4a,0x8e70,0x8e76,0x8e7c,0x8e6f,0x8e74,0x8e85,0x8eaa,0x8e94,
+    0x8e90,0x8ea6,0x8e9e,0x8c78,0x8c82,0x8c8a,0x8c85,0x8c98,0x8c94,0x659b,
+    0x89d6,0x89f4,0x89da,0x89dc
+  },
+  {				/* ku 56 */
+    0x89e5,0x89eb,0x89f6,0x8a3e,0x8b26,0x975a,0x96e9,0x9742,0x96ef,0x9706,
+    0x973d,0x9708,0x970f,0x970e,0x972a,0x9744,0x9730,0x973e,0x9f54,0x9f5f,
+    0x9f59,0x9f60,0x9f5c,0x9f66,0x9f6c,0x9f6a,0x9f77,0x9efd,0x9eff,0x9f09,
+    0x96b9,0x96bc,0x96bd,0x96ce,0x96d2,0x77bf,0x8b8e,0x928e,0x947e,0x92c8,
+    0x93e8,0x936a,0x93ca,0x938f,0x943e,0x946b,0x9b77,0x9b74,0x9b81,0x9b83,
+    0x9b8e,0x9c78,0x7a4c,0x9b92,0x9c5f,0x9b90,0x9bad,0x9b9a,0x9baa,0x9b9e,
+    0x9c6d,0x9bab,0x9b9d,0x9c58,0x9bc1,0x9c7a,0x9c31,0x9c39,0x9c23,0x9c37,
+    0x9bc0,0x9bca,0x9bc7,0x9bfd,0x9bd6,0x9bea,0x9beb,0x9be1,0x9be4,0x9be7,
+    0x9bdd,0x9be2,0x9bf0,0x9bdb,0x9bf4,0x9bd4,0x9c5d,0x9c08,0x9c10,0x9c0d,
+    0x9c12,0x9c09,0x9bff,0x9c20
+  },
+  {				/* ku 57 */
+    0x9c32,0x9c2d,0x9c28,0x9c25,0x9c29,0x9c33,0x9c3e,0x9c48,0x9c3b,0x9c35,
+    0x9c45,0x9c56,0x9c54,0x9c52,0x9c67,0x977c,0x9785,0x97c3,0x97bd,0x9794,
+    0x97c9,0x97ab,0x97a3,0x97b2,0x97b4,0x9ab1,0x9ab0,0x9ab7,0x9dbb,0x9ab6,
+    0x9aba,0x9abc,0x9ac1,0x9ac0,0x9acf,0x9ac2,0x9ad6,0x9ad5,0x9ad1,0x9b45,
+    0x9b43,0x9b58,0x9b4e,0x9b48,0x9b4d,0x9b51,0x9957,0x995c,0x992e,0x9955,
+    0x9954,0x9adf,0x9ae1,0x9ae6,0x9aef,0x9aeb,0x9afb,0x9aed,0x9af9,0x9b08,
+    0x9b0f,0x9b22,0x9b1f,0x9b23,0x4e48,0x9ebe,0x7e3b,0x9e82,0x9e87,0x9e88,
+    0x9e8b,0x9e92,0x93d6,0x9e9d,0x9e9f,0x9edb,0x9edc,0x9edd,0x9ee0,0x9edf,
+    0x9ee2,0x9ef7,0x9ee7,0x9ee5,0x9ef2,0x9eef,0x9f22,0x9f2c,0x9f2f,0x9f39,
+    0x9f37,0x9f3d,0x9f3e,0x9f44
+  },
+  {				/* ku 58 */
+    0x896c,0x95c6,0x9336,0x5f46,0x8514,0x7e94,0x5382,0x51b2,0x4e11,0x9f63,
+    0x5679,0x515a,0x6dc0,0x9f15,0x6597,0x5641,0x9aee,0x8303,0x4e30,0x8907,
+    0x5e72,0x7a40,0x98b3,0x5e7f,0x95a4,0x9b0d,0x5212,0x8ff4,0x5f59,0x7a6b,
+    0x98e2,0x51e0,0x50a2,0x4ef7,0x8350,0x8591,0x5118,0x636e,0x6372,0x524b,
+    0x5938,0x774f,0x8721,0x814a,0x7e8d,0x91cc,0x66c6,0x5e18,0x77ad,0x9e75,
+    0x56c9,0x9ef4,0x6fdb,0x61de,0x77c7,0x7030,0x9eb5,0x884a,0x95e2,0x82f9,
+    0x51ed,0x6251,0x4ec6,0x6734,0x97c6,0x7c64,0x7e34,0x97a6,0x9eaf,0x786e,
+    0x820d,0x672f,0x677e,0x56cc,0x53f0,0x98b1,0x6aaf,0x7f4e,0x6d82,0x7cf0,
+    0x4e07,0x4fc2,0x7e6b,0x9e79,0x56ae,0x9b1a,0x846f,0x53f6,0x90c1,0x79a6,
+    0x7c72,0x613f,0x4e91,0x9ad2
+  },
+  {				/* ku 59 */
+    0x75c7,0x96bb,0x53ea,0x7dfb,0x88fd,0x79cd,0x7843,0x7b51,0x51c6,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  }
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/charset/gb_2312.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,2795 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	GBK conversion table
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	3 July 1997
+ * Last Edited:	30 August 2006
+ */
+
+/* GB 2312 is the national standard of the People's Republic of China
+ * (mainland China).  This is actually the GBK extended version.
+ */
+
+#define BASE_GB2312_KU 0x81
+#define BASE_GB2312_TEN 0x40
+#define MAX_GB2312_KU 125
+#define MAX_GB2312_TEN 191
+
+
+#define GBTOUNICODE(c,c1,ku,ten)				\
+  ((((ku = c - BASE_GB2312_KU) < MAX_GB2312_KU) &&		\
+    ((ten = c1 - BASE_GB2312_TEN) < MAX_GB2312_TEN)) ?		\
+   gb2312tab[ku][ten] : UBOGON)
+
+static const unsigned short gb2312tab[MAX_GB2312_KU][MAX_GB2312_TEN] = {
+  {				/* ku 01 */
+    0x4e02,0x4e04,0x4e05,0x4e06,0x4e0f,0x4e12,0x4e17,0x4e1f,0x4e20,0x4e21,
+    0x4e23,0x4e26,0x4e29,0x4e2e,0x4e2f,0x4e31,0x4e33,0x4e35,0x4e37,0x4e3c,
+    0x4e40,0x4e41,0x4e42,0x4e44,0x4e46,0x4e4a,0x4e51,0x4e55,0x4e57,0x4e5a,
+    0x4e5b,0x4e62,0x4e63,0x4e64,0x4e65,0x4e67,0x4e68,0x4e6a,0x4e6b,0x4e6c,
+    0x4e6d,0x4e6e,0x4e6f,0x4e72,0x4e74,0x4e75,0x4e76,0x4e77,0x4e78,0x4e79,
+    0x4e7a,0x4e7b,0x4e7c,0x4e7d,0x4e7f,0x4e80,0x4e81,0x4e82,0x4e83,0x4e84,
+    0x4e85,0x4e87,0x4e8a,UBOGON,0x4e90,0x4e96,0x4e97,0x4e99,0x4e9c,0x4e9d,
+    0x4e9e,0x4ea3,0x4eaa,0x4eaf,0x4eb0,0x4eb1,0x4eb4,0x4eb6,0x4eb7,0x4eb8,
+    0x4eb9,0x4ebc,0x4ebd,0x4ebe,0x4ec8,0x4ecc,0x4ecf,0x4ed0,0x4ed2,0x4eda,
+    0x4edb,0x4edc,0x4ee0,0x4ee2,0x4ee6,0x4ee7,0x4ee9,0x4eed,0x4eee,0x4eef,
+    0x4ef1,0x4ef4,0x4ef8,0x4ef9,0x4efa,0x4efc,0x4efe,0x4f00,0x4f02,0x4f03,
+    0x4f04,0x4f05,0x4f06,0x4f07,0x4f08,0x4f0b,0x4f0c,0x4f12,0x4f13,0x4f14,
+    0x4f15,0x4f16,0x4f1c,0x4f1d,0x4f21,0x4f23,0x4f28,0x4f29,0x4f2c,0x4f2d,
+    0x4f2e,0x4f31,0x4f33,0x4f35,0x4f37,0x4f39,0x4f3b,0x4f3e,0x4f3f,0x4f40,
+    0x4f41,0x4f42,0x4f44,0x4f45,0x4f47,0x4f48,0x4f49,0x4f4a,0x4f4b,0x4f4c,
+    0x4f52,0x4f54,0x4f56,0x4f61,0x4f62,0x4f66,0x4f68,0x4f6a,0x4f6b,0x4f6d,
+    0x4f6e,0x4f71,0x4f72,0x4f75,0x4f77,0x4f78,0x4f79,0x4f7a,0x4f7d,0x4f80,
+    0x4f81,0x4f82,0x4f85,0x4f86,0x4f87,0x4f8a,0x4f8c,0x4f8e,0x4f90,0x4f92,
+    0x4f93,0x4f95,0x4f96,0x4f98,0x4f99,0x4f9a,0x4f9c,0x4f9e,0x4f9f,0x4fa1,
+    0x4fa2
+  },
+  {				/* ku 02 */
+    0x4fa4,0x4fab,0x4fad,0x4fb0,0x4fb1,0x4fb2,0x4fb3,0x4fb4,0x4fb6,0x4fb7,
+    0x4fb8,0x4fb9,0x4fba,0x4fbb,0x4fbc,0x4fbd,0x4fbe,0x4fc0,0x4fc1,0x4fc2,
+    0x4fc6,0x4fc7,0x4fc8,0x4fc9,0x4fcb,0x4fcc,0x4fcd,0x4fd2,0x4fd3,0x4fd4,
+    0x4fd5,0x4fd6,0x4fd9,0x4fdb,0x4fe0,0x4fe2,0x4fe4,0x4fe5,0x4fe7,0x4feb,
+    0x4fec,0x4ff0,0x4ff2,0x4ff4,0x4ff5,0x4ff6,0x4ff7,0x4ff9,0x4ffb,0x4ffc,
+    0x4ffd,0x4fff,0x5000,0x5001,0x5002,0x5003,0x5004,0x5005,0x5006,0x5007,
+    0x5008,0x5009,0x500a,UBOGON,0x500b,0x500e,0x5010,0x5011,0x5013,0x5015,
+    0x5016,0x5017,0x501b,0x501d,0x501e,0x5020,0x5022,0x5023,0x5024,0x5027,
+    0x502b,0x502f,0x5030,0x5031,0x5032,0x5033,0x5034,0x5035,0x5036,0x5037,
+    0x5038,0x5039,0x503b,0x503d,0x503f,0x5040,0x5041,0x5042,0x5044,0x5045,
+    0x5046,0x5049,0x504a,0x504b,0x504d,0x5050,0x5051,0x5052,0x5053,0x5054,
+    0x5056,0x5057,0x5058,0x5059,0x505b,0x505d,0x505e,0x505f,0x5060,0x5061,
+    0x5062,0x5063,0x5064,0x5066,0x5067,0x5068,0x5069,0x506a,0x506b,0x506d,
+    0x506e,0x506f,0x5070,0x5071,0x5072,0x5073,0x5074,0x5075,0x5078,0x5079,
+    0x507a,0x507c,0x507d,0x5081,0x5082,0x5083,0x5084,0x5086,0x5087,0x5089,
+    0x508a,0x508b,0x508c,0x508e,0x508f,0x5090,0x5091,0x5092,0x5093,0x5094,
+    0x5095,0x5096,0x5097,0x5098,0x5099,0x509a,0x509b,0x509c,0x509d,0x509e,
+    0x509f,0x50a0,0x50a1,0x50a2,0x50a4,0x50a6,0x50aa,0x50ab,0x50ad,0x50ae,
+    0x50af,0x50b0,0x50b1,0x50b3,0x50b4,0x50b5,0x50b6,0x50b7,0x50b8,0x50b9,
+    0x50bc
+  },
+  {				/* ku 03 */
+    0x50bd,0x50be,0x50bf,0x50c0,0x50c1,0x50c2,0x50c3,0x50c4,0x50c5,0x50c6,
+    0x50c7,0x50c8,0x50c9,0x50ca,0x50cb,0x50cc,0x50cd,0x50ce,0x50d0,0x50d1,
+    0x50d2,0x50d3,0x50d4,0x50d5,0x50d7,0x50d8,0x50d9,0x50db,0x50dc,0x50dd,
+    0x50de,0x50df,0x50e0,0x50e1,0x50e2,0x50e3,0x50e4,0x50e5,0x50e8,0x50e9,
+    0x50ea,0x50eb,0x50ef,0x50f0,0x50f1,0x50f2,0x50f4,0x50f6,0x50f7,0x50f8,
+    0x50f9,0x50fa,0x50fc,0x50fd,0x50fe,0x50ff,0x5100,0x5101,0x5102,0x5103,
+    0x5104,0x5105,0x5108,UBOGON,0x5109,0x510a,0x510c,0x510d,0x510e,0x510f,
+    0x5110,0x5111,0x5113,0x5114,0x5115,0x5116,0x5117,0x5118,0x5119,0x511a,
+    0x511b,0x511c,0x511d,0x511e,0x511f,0x5120,0x5122,0x5123,0x5124,0x5125,
+    0x5126,0x5127,0x5128,0x5129,0x512a,0x512b,0x512c,0x512d,0x512e,0x512f,
+    0x5130,0x5131,0x5132,0x5133,0x5134,0x5135,0x5136,0x5137,0x5138,0x5139,
+    0x513a,0x513b,0x513c,0x513d,0x513e,0x5142,0x5147,0x514a,0x514c,0x514e,
+    0x514f,0x5150,0x5152,0x5153,0x5157,0x5158,0x5159,0x515b,0x515d,0x515e,
+    0x515f,0x5160,0x5161,0x5163,0x5164,0x5166,0x5167,0x5169,0x516a,0x516f,
+    0x5172,0x517a,0x517e,0x517f,0x5183,0x5184,0x5186,0x5187,0x518a,0x518b,
+    0x518e,0x518f,0x5190,0x5191,0x5193,0x5194,0x5198,0x519a,0x519d,0x519e,
+    0x519f,0x51a1,0x51a3,0x51a6,0x51a7,0x51a8,0x51a9,0x51aa,0x51ad,0x51ae,
+    0x51b4,0x51b8,0x51b9,0x51ba,0x51be,0x51bf,0x51c1,0x51c2,0x51c3,0x51c5,
+    0x51c8,0x51ca,0x51cd,0x51ce,0x51d0,0x51d2,0x51d3,0x51d4,0x51d5,0x51d6,
+    0x51d7
+  },
+  {				/* ku 04 */
+    0x51d8,0x51d9,0x51da,0x51dc,0x51de,0x51df,0x51e2,0x51e3,0x51e5,0x51e6,
+    0x51e7,0x51e8,0x51e9,0x51ea,0x51ec,0x51ee,0x51f1,0x51f2,0x51f4,0x51f7,
+    0x51fe,0x5204,0x5205,0x5209,0x520b,0x520c,0x520f,0x5210,0x5213,0x5214,
+    0x5215,0x521c,0x521e,0x521f,0x5221,0x5222,0x5223,0x5225,0x5226,0x5227,
+    0x522a,0x522c,0x522f,0x5231,0x5232,0x5234,0x5235,0x523c,0x523e,0x5244,
+    0x5245,0x5246,0x5247,0x5248,0x5249,0x524b,0x524e,0x524f,0x5252,0x5253,
+    0x5255,0x5257,0x5258,UBOGON,0x5259,0x525a,0x525b,0x525d,0x525f,0x5260,
+    0x5262,0x5263,0x5264,0x5266,0x5268,0x526b,0x526c,0x526d,0x526e,0x5270,
+    0x5271,0x5273,0x5274,0x5275,0x5276,0x5277,0x5278,0x5279,0x527a,0x527b,
+    0x527c,0x527e,0x5280,0x5283,0x5284,0x5285,0x5286,0x5287,0x5289,0x528a,
+    0x528b,0x528c,0x528d,0x528e,0x528f,0x5291,0x5292,0x5294,0x5295,0x5296,
+    0x5297,0x5298,0x5299,0x529a,0x529c,0x52a4,0x52a5,0x52a6,0x52a7,0x52ae,
+    0x52af,0x52b0,0x52b4,0x52b5,0x52b6,0x52b7,0x52b8,0x52b9,0x52ba,0x52bb,
+    0x52bc,0x52bd,0x52c0,0x52c1,0x52c2,0x52c4,0x52c5,0x52c6,0x52c8,0x52ca,
+    0x52cc,0x52cd,0x52ce,0x52cf,0x52d1,0x52d3,0x52d4,0x52d5,0x52d7,0x52d9,
+    0x52da,0x52db,0x52dc,0x52dd,0x52de,0x52e0,0x52e1,0x52e2,0x52e3,0x52e5,
+    0x52e6,0x52e7,0x52e8,0x52e9,0x52ea,0x52eb,0x52ec,0x52ed,0x52ee,0x52ef,
+    0x52f1,0x52f2,0x52f3,0x52f4,0x52f5,0x52f6,0x52f7,0x52f8,0x52fb,0x52fc,
+    0x52fd,0x5301,0x5302,0x5303,0x5304,0x5307,0x5309,0x530a,0x530b,0x530c,
+    0x530e
+  },
+  {				/* ku 05 */
+    0x5311,0x5312,0x5313,0x5314,0x5318,0x531b,0x531c,0x531e,0x531f,0x5322,
+    0x5324,0x5325,0x5327,0x5328,0x5329,0x532b,0x532c,0x532d,0x532f,0x5330,
+    0x5331,0x5332,0x5333,0x5334,0x5335,0x5336,0x5337,0x5338,0x533c,0x533d,
+    0x5340,0x5342,0x5344,0x5346,0x534b,0x534c,0x534d,0x5350,0x5354,0x5358,
+    0x5359,0x535b,0x535d,0x5365,0x5368,0x536a,0x536c,0x536d,0x5372,0x5376,
+    0x5379,0x537b,0x537c,0x537d,0x537e,0x5380,0x5381,0x5383,0x5387,0x5388,
+    0x538a,0x538e,0x538f,UBOGON,0x5390,0x5391,0x5392,0x5393,0x5394,0x5396,
+    0x5397,0x5399,0x539b,0x539c,0x539e,0x53a0,0x53a1,0x53a4,0x53a7,0x53aa,
+    0x53ab,0x53ac,0x53ad,0x53af,0x53b0,0x53b1,0x53b2,0x53b3,0x53b4,0x53b5,
+    0x53b7,0x53b8,0x53b9,0x53ba,0x53bc,0x53bd,0x53be,0x53c0,0x53c3,0x53c4,
+    0x53c5,0x53c6,0x53c7,0x53ce,0x53cf,0x53d0,0x53d2,0x53d3,0x53d5,0x53da,
+    0x53dc,0x53dd,0x53de,0x53e1,0x53e2,0x53e7,0x53f4,0x53fa,0x53fe,0x53ff,
+    0x5400,0x5402,0x5405,0x5407,0x540b,0x5414,0x5418,0x5419,0x541a,0x541c,
+    0x5422,0x5424,0x5425,0x542a,0x5430,0x5433,0x5436,0x5437,0x543a,0x543d,
+    0x543f,0x5441,0x5442,0x5444,0x5445,0x5447,0x5449,0x544c,0x544d,0x544e,
+    0x544f,0x5451,0x545a,0x545d,0x545e,0x545f,0x5460,0x5461,0x5463,0x5465,
+    0x5467,0x5469,0x546a,0x546b,0x546c,0x546d,0x546e,0x546f,0x5470,0x5474,
+    0x5479,0x547a,0x547e,0x547f,0x5481,0x5483,0x5485,0x5487,0x5488,0x5489,
+    0x548a,0x548d,0x5491,0x5493,0x5497,0x5498,0x549c,0x549e,0x549f,0x54a0,
+    0x54a1
+  },
+  {				/* ku 06 */
+    0x54a2,0x54a5,0x54ae,0x54b0,0x54b2,0x54b5,0x54b6,0x54b7,0x54b9,0x54ba,
+    0x54bc,0x54be,0x54c3,0x54c5,0x54ca,0x54cb,0x54d6,0x54d8,0x54db,0x54e0,
+    0x54e1,0x54e2,0x54e3,0x54e4,0x54eb,0x54ec,0x54ef,0x54f0,0x54f1,0x54f4,
+    0x54f5,0x54f6,0x54f7,0x54f8,0x54f9,0x54fb,0x54fe,0x5500,0x5502,0x5503,
+    0x5504,0x5505,0x5508,0x550a,0x550b,0x550c,0x550d,0x550e,0x5512,0x5513,
+    0x5515,0x5516,0x5517,0x5518,0x5519,0x551a,0x551c,0x551d,0x551e,0x551f,
+    0x5521,0x5525,0x5526,UBOGON,0x5528,0x5529,0x552b,0x552d,0x5532,0x5534,
+    0x5535,0x5536,0x5538,0x5539,0x553a,0x553b,0x553d,0x5540,0x5542,0x5545,
+    0x5547,0x5548,0x554b,0x554c,0x554d,0x554e,0x554f,0x5551,0x5552,0x5553,
+    0x5554,0x5557,0x5558,0x5559,0x555a,0x555b,0x555d,0x555e,0x555f,0x5560,
+    0x5562,0x5563,0x5568,0x5569,0x556b,0x556f,0x5570,0x5571,0x5572,0x5573,
+    0x5574,0x5579,0x557a,0x557d,0x557f,0x5585,0x5586,0x558c,0x558d,0x558e,
+    0x5590,0x5592,0x5593,0x5595,0x5596,0x5597,0x559a,0x559b,0x559e,0x55a0,
+    0x55a1,0x55a2,0x55a3,0x55a4,0x55a5,0x55a6,0x55a8,0x55a9,0x55aa,0x55ab,
+    0x55ac,0x55ad,0x55ae,0x55af,0x55b0,0x55b2,0x55b4,0x55b6,0x55b8,0x55ba,
+    0x55bc,0x55bf,0x55c0,0x55c1,0x55c2,0x55c3,0x55c6,0x55c7,0x55c8,0x55ca,
+    0x55cb,0x55ce,0x55cf,0x55d0,0x55d5,0x55d7,0x55d8,0x55d9,0x55da,0x55db,
+    0x55de,0x55e0,0x55e2,0x55e7,0x55e9,0x55ed,0x55ee,0x55f0,0x55f1,0x55f4,
+    0x55f6,0x55f8,0x55f9,0x55fa,0x55fb,0x55fc,0x55ff,0x5602,0x5603,0x5604,
+    0x5605
+  },
+  {				/* ku 07 */
+    0x5606,0x5607,0x560a,0x560b,0x560d,0x5610,0x5611,0x5612,0x5613,0x5614,
+    0x5615,0x5616,0x5617,0x5619,0x561a,0x561c,0x561d,0x5620,0x5621,0x5622,
+    0x5625,0x5626,0x5628,0x5629,0x562a,0x562b,0x562e,0x562f,0x5630,0x5633,
+    0x5635,0x5637,0x5638,0x563a,0x563c,0x563d,0x563e,0x5640,0x5641,0x5642,
+    0x5643,0x5644,0x5645,0x5646,0x5647,0x5648,0x5649,0x564a,0x564b,0x564f,
+    0x5650,0x5651,0x5652,0x5653,0x5655,0x5656,0x565a,0x565b,0x565d,0x565e,
+    0x565f,0x5660,0x5661,UBOGON,0x5663,0x5665,0x5666,0x5667,0x566d,0x566e,
+    0x566f,0x5670,0x5672,0x5673,0x5674,0x5675,0x5677,0x5678,0x5679,0x567a,
+    0x567d,0x567e,0x567f,0x5680,0x5681,0x5682,0x5683,0x5684,0x5687,0x5688,
+    0x5689,0x568a,0x568b,0x568c,0x568d,0x5690,0x5691,0x5692,0x5694,0x5695,
+    0x5696,0x5697,0x5698,0x5699,0x569a,0x569b,0x569c,0x569d,0x569e,0x569f,
+    0x56a0,0x56a1,0x56a2,0x56a4,0x56a5,0x56a6,0x56a7,0x56a8,0x56a9,0x56aa,
+    0x56ab,0x56ac,0x56ad,0x56ae,0x56b0,0x56b1,0x56b2,0x56b3,0x56b4,0x56b5,
+    0x56b6,0x56b8,0x56b9,0x56ba,0x56bb,0x56bd,0x56be,0x56bf,0x56c0,0x56c1,
+    0x56c2,0x56c3,0x56c4,0x56c5,0x56c6,0x56c7,0x56c8,0x56c9,0x56cb,0x56cc,
+    0x56cd,0x56ce,0x56cf,0x56d0,0x56d1,0x56d2,0x56d3,0x56d5,0x56d6,0x56d8,
+    0x56d9,0x56dc,0x56e3,0x56e5,0x56e6,0x56e7,0x56e8,0x56e9,0x56ea,0x56ec,
+    0x56ee,0x56ef,0x56f2,0x56f3,0x56f6,0x56f7,0x56f8,0x56fb,0x56fc,0x5700,
+    0x5701,0x5702,0x5705,0x5707,0x570b,0x570c,0x570d,0x570e,0x570f,0x5710,
+    0x5711
+  },
+  {				/* ku 08 */
+    0x5712,0x5713,0x5714,0x5715,0x5716,0x5717,0x5718,0x5719,0x571a,0x571b,
+    0x571d,0x571e,0x5720,0x5721,0x5722,0x5724,0x5725,0x5726,0x5727,0x572b,
+    0x5731,0x5732,0x5734,0x5735,0x5736,0x5737,0x5738,0x573c,0x573d,0x573f,
+    0x5741,0x5743,0x5744,0x5745,0x5746,0x5748,0x5749,0x574b,0x5752,0x5753,
+    0x5754,0x5755,0x5756,0x5758,0x5759,0x5762,0x5763,0x5765,0x5767,0x576c,
+    0x576e,0x5770,0x5771,0x5772,0x5774,0x5775,0x5778,0x5779,0x577a,0x577d,
+    0x577e,0x577f,0x5780,UBOGON,0x5781,0x5787,0x5788,0x5789,0x578a,0x578d,
+    0x578e,0x578f,0x5790,0x5791,0x5794,0x5795,0x5796,0x5797,0x5798,0x5799,
+    0x579a,0x579c,0x579d,0x579e,0x579f,0x57a5,0x57a8,0x57aa,0x57ac,0x57af,
+    0x57b0,0x57b1,0x57b3,0x57b5,0x57b6,0x57b7,0x57b9,0x57ba,0x57bb,0x57bc,
+    0x57bd,0x57be,0x57bf,0x57c0,0x57c1,0x57c4,0x57c5,0x57c6,0x57c7,0x57c8,
+    0x57c9,0x57ca,0x57cc,0x57cd,0x57d0,0x57d1,0x57d3,0x57d6,0x57d7,0x57db,
+    0x57dc,0x57de,0x57e1,0x57e2,0x57e3,0x57e5,0x57e6,0x57e7,0x57e8,0x57e9,
+    0x57ea,0x57eb,0x57ec,0x57ee,0x57f0,0x57f1,0x57f2,0x57f3,0x57f5,0x57f6,
+    0x57f7,0x57fb,0x57fc,0x57fe,0x57ff,0x5801,0x5803,0x5804,0x5805,0x5808,
+    0x5809,0x580a,0x580c,0x580e,0x580f,0x5810,0x5812,0x5813,0x5814,0x5816,
+    0x5817,0x5818,0x581a,0x581b,0x581c,0x581d,0x581f,0x5822,0x5823,0x5825,
+    0x5826,0x5827,0x5828,0x5829,0x582b,0x582c,0x582d,0x582e,0x582f,0x5831,
+    0x5832,0x5833,0x5834,0x5836,0x5837,0x5838,0x5839,0x583a,0x583b,0x583c,
+    0x583d
+  },
+  {				/* ku 09 */
+    0x583e,0x583f,0x5840,0x5841,0x5842,0x5843,0x5845,0x5846,0x5847,0x5848,
+    0x5849,0x584a,0x584b,0x584e,0x584f,0x5850,0x5852,0x5853,0x5855,0x5856,
+    0x5857,0x5859,0x585a,0x585b,0x585c,0x585d,0x585f,0x5860,0x5861,0x5862,
+    0x5863,0x5864,0x5866,0x5867,0x5868,0x5869,0x586a,0x586d,0x586e,0x586f,
+    0x5870,0x5871,0x5872,0x5873,0x5874,0x5875,0x5876,0x5877,0x5878,0x5879,
+    0x587a,0x587b,0x587c,0x587d,0x587f,0x5882,0x5884,0x5886,0x5887,0x5888,
+    0x588a,0x588b,0x588c,UBOGON,0x588d,0x588e,0x588f,0x5890,0x5891,0x5894,
+    0x5895,0x5896,0x5897,0x5898,0x589b,0x589c,0x589d,0x58a0,0x58a1,0x58a2,
+    0x58a3,0x58a4,0x58a5,0x58a6,0x58a7,0x58aa,0x58ab,0x58ac,0x58ad,0x58ae,
+    0x58af,0x58b0,0x58b1,0x58b2,0x58b3,0x58b4,0x58b5,0x58b6,0x58b7,0x58b8,
+    0x58b9,0x58ba,0x58bb,0x58bd,0x58be,0x58bf,0x58c0,0x58c2,0x58c3,0x58c4,
+    0x58c6,0x58c7,0x58c8,0x58c9,0x58ca,0x58cb,0x58cc,0x58cd,0x58ce,0x58cf,
+    0x58d0,0x58d2,0x58d3,0x58d4,0x58d6,0x58d7,0x58d8,0x58d9,0x58da,0x58db,
+    0x58dc,0x58dd,0x58de,0x58df,0x58e0,0x58e1,0x58e2,0x58e3,0x58e5,0x58e6,
+    0x58e7,0x58e8,0x58e9,0x58ea,0x58ed,0x58ef,0x58f1,0x58f2,0x58f4,0x58f5,
+    0x58f7,0x58f8,0x58fa,0x58fb,0x58fc,0x58fd,0x58fe,0x58ff,0x5900,0x5901,
+    0x5903,0x5905,0x5906,0x5908,0x5909,0x590a,0x590b,0x590c,0x590e,0x5910,
+    0x5911,0x5912,0x5913,0x5917,0x5918,0x591b,0x591d,0x591e,0x5920,0x5921,
+    0x5922,0x5923,0x5926,0x5928,0x592c,0x5930,0x5932,0x5933,0x5935,0x5936,
+    0x593b
+  },
+  {				/* ku 0a */
+    0x593d,0x593e,0x593f,0x5940,0x5943,0x5945,0x5946,0x594a,0x594c,0x594d,
+    0x5950,0x5952,0x5953,0x5959,0x595b,0x595c,0x595d,0x595e,0x595f,0x5961,
+    0x5963,0x5964,0x5966,0x5967,0x5968,0x5969,0x596a,0x596b,0x596c,0x596d,
+    0x596e,0x596f,0x5970,0x5971,0x5972,0x5975,0x5977,0x597a,0x597b,0x597c,
+    0x597e,0x597f,0x5980,0x5985,0x5989,0x598b,0x598c,0x598e,0x598f,0x5990,
+    0x5991,0x5994,0x5995,0x5998,0x599a,0x599b,0x599c,0x599d,0x599f,0x59a0,
+    0x59a1,0x59a2,0x59a6,UBOGON,0x59a7,0x59ac,0x59ad,0x59b0,0x59b1,0x59b3,
+    0x59b4,0x59b5,0x59b6,0x59b7,0x59b8,0x59ba,0x59bc,0x59bd,0x59bf,0x59c0,
+    0x59c1,0x59c2,0x59c3,0x59c4,0x59c5,0x59c7,0x59c8,0x59c9,0x59cc,0x59cd,
+    0x59ce,0x59cf,0x59d5,0x59d6,0x59d9,0x59db,0x59de,0x59df,0x59e0,0x59e1,
+    0x59e2,0x59e4,0x59e6,0x59e7,0x59e9,0x59ea,0x59eb,0x59ed,0x59ee,0x59ef,
+    0x59f0,0x59f1,0x59f2,0x59f3,0x59f4,0x59f5,0x59f6,0x59f7,0x59f8,0x59fa,
+    0x59fc,0x59fd,0x59fe,0x5a00,0x5a02,0x5a0a,0x5a0b,0x5a0d,0x5a0e,0x5a0f,
+    0x5a10,0x5a12,0x5a14,0x5a15,0x5a16,0x5a17,0x5a19,0x5a1a,0x5a1b,0x5a1d,
+    0x5a1e,0x5a21,0x5a22,0x5a24,0x5a26,0x5a27,0x5a28,0x5a2a,0x5a2b,0x5a2c,
+    0x5a2d,0x5a2e,0x5a2f,0x5a30,0x5a33,0x5a35,0x5a37,0x5a38,0x5a39,0x5a3a,
+    0x5a3b,0x5a3d,0x5a3e,0x5a3f,0x5a41,0x5a42,0x5a43,0x5a44,0x5a45,0x5a47,
+    0x5a48,0x5a4b,0x5a4c,0x5a4d,0x5a4e,0x5a4f,0x5a50,0x5a51,0x5a52,0x5a53,
+    0x5a54,0x5a56,0x5a57,0x5a58,0x5a59,0x5a5b,0x5a5c,0x5a5d,0x5a5e,0x5a5f,
+    0x5a60
+  },
+  {				/* ku 0b */
+    0x5a61,0x5a63,0x5a64,0x5a65,0x5a66,0x5a68,0x5a69,0x5a6b,0x5a6c,0x5a6d,
+    0x5a6e,0x5a6f,0x5a70,0x5a71,0x5a72,0x5a73,0x5a78,0x5a79,0x5a7b,0x5a7c,
+    0x5a7d,0x5a7e,0x5a80,0x5a81,0x5a82,0x5a83,0x5a84,0x5a85,0x5a86,0x5a87,
+    0x5a88,0x5a89,0x5a8a,0x5a8b,0x5a8c,0x5a8d,0x5a8e,0x5a8f,0x5a90,0x5a91,
+    0x5a93,0x5a94,0x5a95,0x5a96,0x5a97,0x5a98,0x5a99,0x5a9c,0x5a9d,0x5a9e,
+    0x5a9f,0x5aa0,0x5aa1,0x5aa2,0x5aa3,0x5aa4,0x5aa5,0x5aa6,0x5aa7,0x5aa8,
+    0x5aa9,0x5aab,0x5aac,UBOGON,0x5aad,0x5aae,0x5aaf,0x5ab0,0x5ab1,0x5ab4,
+    0x5ab6,0x5ab7,0x5ab9,0x5aba,0x5abb,0x5abc,0x5abd,0x5abf,0x5ac0,0x5ac3,
+    0x5ac4,0x5ac5,0x5ac6,0x5ac7,0x5ac8,0x5aca,0x5acb,0x5acd,0x5ace,0x5acf,
+    0x5ad0,0x5ad1,0x5ad3,0x5ad5,0x5ad7,0x5ad9,0x5ada,0x5adb,0x5add,0x5ade,
+    0x5adf,0x5ae2,0x5ae4,0x5ae5,0x5ae7,0x5ae8,0x5aea,0x5aec,0x5aed,0x5aee,
+    0x5aef,0x5af0,0x5af2,0x5af3,0x5af4,0x5af5,0x5af6,0x5af7,0x5af8,0x5af9,
+    0x5afa,0x5afb,0x5afc,0x5afd,0x5afe,0x5aff,0x5b00,0x5b01,0x5b02,0x5b03,
+    0x5b04,0x5b05,0x5b06,0x5b07,0x5b08,0x5b0a,0x5b0b,0x5b0c,0x5b0d,0x5b0e,
+    0x5b0f,0x5b10,0x5b11,0x5b12,0x5b13,0x5b14,0x5b15,0x5b18,0x5b19,0x5b1a,
+    0x5b1b,0x5b1c,0x5b1d,0x5b1e,0x5b1f,0x5b20,0x5b21,0x5b22,0x5b23,0x5b24,
+    0x5b25,0x5b26,0x5b27,0x5b28,0x5b29,0x5b2a,0x5b2b,0x5b2c,0x5b2d,0x5b2e,
+    0x5b2f,0x5b30,0x5b31,0x5b33,0x5b35,0x5b36,0x5b38,0x5b39,0x5b3a,0x5b3b,
+    0x5b3c,0x5b3d,0x5b3e,0x5b3f,0x5b41,0x5b42,0x5b43,0x5b44,0x5b45,0x5b46,
+    0x5b47
+  },
+  {				/* ku 0c */
+    0x5b48,0x5b49,0x5b4a,0x5b4b,0x5b4c,0x5b4d,0x5b4e,0x5b4f,0x5b52,0x5b56,
+    0x5b5e,0x5b60,0x5b61,0x5b67,0x5b68,0x5b6b,0x5b6d,0x5b6e,0x5b6f,0x5b72,
+    0x5b74,0x5b76,0x5b77,0x5b78,0x5b79,0x5b7b,0x5b7c,0x5b7e,0x5b7f,0x5b82,
+    0x5b86,0x5b8a,0x5b8d,0x5b8e,0x5b90,0x5b91,0x5b92,0x5b94,0x5b96,0x5b9f,
+    0x5ba7,0x5ba8,0x5ba9,0x5bac,0x5bad,0x5bae,0x5baf,0x5bb1,0x5bb2,0x5bb7,
+    0x5bba,0x5bbb,0x5bbc,0x5bc0,0x5bc1,0x5bc3,0x5bc8,0x5bc9,0x5bca,0x5bcb,
+    0x5bcd,0x5bce,0x5bcf,UBOGON,0x5bd1,0x5bd4,0x5bd5,0x5bd6,0x5bd7,0x5bd8,
+    0x5bd9,0x5bda,0x5bdb,0x5bdc,0x5be0,0x5be2,0x5be3,0x5be6,0x5be7,0x5be9,
+    0x5bea,0x5beb,0x5bec,0x5bed,0x5bef,0x5bf1,0x5bf2,0x5bf3,0x5bf4,0x5bf5,
+    0x5bf6,0x5bf7,0x5bfd,0x5bfe,0x5c00,0x5c02,0x5c03,0x5c05,0x5c07,0x5c08,
+    0x5c0b,0x5c0c,0x5c0d,0x5c0e,0x5c10,0x5c12,0x5c13,0x5c17,0x5c19,0x5c1b,
+    0x5c1e,0x5c1f,0x5c20,0x5c21,0x5c23,0x5c26,0x5c28,0x5c29,0x5c2a,0x5c2b,
+    0x5c2d,0x5c2e,0x5c2f,0x5c30,0x5c32,0x5c33,0x5c35,0x5c36,0x5c37,0x5c43,
+    0x5c44,0x5c46,0x5c47,0x5c4c,0x5c4d,0x5c52,0x5c53,0x5c54,0x5c56,0x5c57,
+    0x5c58,0x5c5a,0x5c5b,0x5c5c,0x5c5d,0x5c5f,0x5c62,0x5c64,0x5c67,0x5c68,
+    0x5c69,0x5c6a,0x5c6b,0x5c6c,0x5c6d,0x5c70,0x5c72,0x5c73,0x5c74,0x5c75,
+    0x5c76,0x5c77,0x5c78,0x5c7b,0x5c7c,0x5c7d,0x5c7e,0x5c80,0x5c83,0x5c84,
+    0x5c85,0x5c86,0x5c87,0x5c89,0x5c8a,0x5c8b,0x5c8e,0x5c8f,0x5c92,0x5c93,
+    0x5c95,0x5c9d,0x5c9e,0x5c9f,0x5ca0,0x5ca1,0x5ca4,0x5ca5,0x5ca6,0x5ca7,
+    0x5ca8
+  },
+  {				/* ku 0d */
+    0x5caa,0x5cae,0x5caf,0x5cb0,0x5cb2,0x5cb4,0x5cb6,0x5cb9,0x5cba,0x5cbb,
+    0x5cbc,0x5cbe,0x5cc0,0x5cc2,0x5cc3,0x5cc5,0x5cc6,0x5cc7,0x5cc8,0x5cc9,
+    0x5cca,0x5ccc,0x5ccd,0x5cce,0x5ccf,0x5cd0,0x5cd1,0x5cd3,0x5cd4,0x5cd5,
+    0x5cd6,0x5cd7,0x5cd8,0x5cda,0x5cdb,0x5cdc,0x5cdd,0x5cde,0x5cdf,0x5ce0,
+    0x5ce2,0x5ce3,0x5ce7,0x5ce9,0x5ceb,0x5cec,0x5cee,0x5cef,0x5cf1,0x5cf2,
+    0x5cf3,0x5cf4,0x5cf5,0x5cf6,0x5cf7,0x5cf8,0x5cf9,0x5cfa,0x5cfc,0x5cfd,
+    0x5cfe,0x5cff,0x5d00,UBOGON,0x5d01,0x5d04,0x5d05,0x5d08,0x5d09,0x5d0a,
+    0x5d0b,0x5d0c,0x5d0d,0x5d0f,0x5d10,0x5d11,0x5d12,0x5d13,0x5d15,0x5d17,
+    0x5d18,0x5d19,0x5d1a,0x5d1c,0x5d1d,0x5d1f,0x5d20,0x5d21,0x5d22,0x5d23,
+    0x5d25,0x5d28,0x5d2a,0x5d2b,0x5d2c,0x5d2f,0x5d30,0x5d31,0x5d32,0x5d33,
+    0x5d35,0x5d36,0x5d37,0x5d38,0x5d39,0x5d3a,0x5d3b,0x5d3c,0x5d3f,0x5d40,
+    0x5d41,0x5d42,0x5d43,0x5d44,0x5d45,0x5d46,0x5d48,0x5d49,0x5d4d,0x5d4e,
+    0x5d4f,0x5d50,0x5d51,0x5d52,0x5d53,0x5d54,0x5d55,0x5d56,0x5d57,0x5d59,
+    0x5d5a,0x5d5c,0x5d5e,0x5d5f,0x5d60,0x5d61,0x5d62,0x5d63,0x5d64,0x5d65,
+    0x5d66,0x5d67,0x5d68,0x5d6a,0x5d6d,0x5d6e,0x5d70,0x5d71,0x5d72,0x5d73,
+    0x5d75,0x5d76,0x5d77,0x5d78,0x5d79,0x5d7a,0x5d7b,0x5d7c,0x5d7d,0x5d7e,
+    0x5d7f,0x5d80,0x5d81,0x5d83,0x5d84,0x5d85,0x5d86,0x5d87,0x5d88,0x5d89,
+    0x5d8a,0x5d8b,0x5d8c,0x5d8d,0x5d8e,0x5d8f,0x5d90,0x5d91,0x5d92,0x5d93,
+    0x5d94,0x5d95,0x5d96,0x5d97,0x5d98,0x5d9a,0x5d9b,0x5d9c,0x5d9e,0x5d9f,
+    0x5da0
+  },
+  {				/* ku 0e */
+    0x5da1,0x5da2,0x5da3,0x5da4,0x5da5,0x5da6,0x5da7,0x5da8,0x5da9,0x5daa,
+    0x5dab,0x5dac,0x5dad,0x5dae,0x5daf,0x5db0,0x5db1,0x5db2,0x5db3,0x5db4,
+    0x5db5,0x5db6,0x5db8,0x5db9,0x5dba,0x5dbb,0x5dbc,0x5dbd,0x5dbe,0x5dbf,
+    0x5dc0,0x5dc1,0x5dc2,0x5dc3,0x5dc4,0x5dc6,0x5dc7,0x5dc8,0x5dc9,0x5dca,
+    0x5dcb,0x5dcc,0x5dce,0x5dcf,0x5dd0,0x5dd1,0x5dd2,0x5dd3,0x5dd4,0x5dd5,
+    0x5dd6,0x5dd7,0x5dd8,0x5dd9,0x5dda,0x5ddc,0x5ddf,0x5de0,0x5de3,0x5de4,
+    0x5dea,0x5dec,0x5ded,UBOGON,0x5df0,0x5df5,0x5df6,0x5df8,0x5df9,0x5dfa,
+    0x5dfb,0x5dfc,0x5dff,0x5e00,0x5e04,0x5e07,0x5e09,0x5e0a,0x5e0b,0x5e0d,
+    0x5e0e,0x5e12,0x5e13,0x5e17,0x5e1e,0x5e1f,0x5e20,0x5e21,0x5e22,0x5e23,
+    0x5e24,0x5e25,0x5e28,0x5e29,0x5e2a,0x5e2b,0x5e2c,0x5e2f,0x5e30,0x5e32,
+    0x5e33,0x5e34,0x5e35,0x5e36,0x5e39,0x5e3a,0x5e3e,0x5e3f,0x5e40,0x5e41,
+    0x5e43,0x5e46,0x5e47,0x5e48,0x5e49,0x5e4a,0x5e4b,0x5e4d,0x5e4e,0x5e4f,
+    0x5e50,0x5e51,0x5e52,0x5e53,0x5e56,0x5e57,0x5e58,0x5e59,0x5e5a,0x5e5c,
+    0x5e5d,0x5e5f,0x5e60,0x5e63,0x5e64,0x5e65,0x5e66,0x5e67,0x5e68,0x5e69,
+    0x5e6a,0x5e6b,0x5e6c,0x5e6d,0x5e6e,0x5e6f,0x5e70,0x5e71,0x5e75,0x5e77,
+    0x5e79,0x5e7e,0x5e81,0x5e82,0x5e83,0x5e85,0x5e88,0x5e89,0x5e8c,0x5e8d,
+    0x5e8e,0x5e92,0x5e98,0x5e9b,0x5e9d,0x5ea1,0x5ea2,0x5ea3,0x5ea4,0x5ea8,
+    0x5ea9,0x5eaa,0x5eab,0x5eac,0x5eae,0x5eaf,0x5eb0,0x5eb1,0x5eb2,0x5eb4,
+    0x5eba,0x5ebb,0x5ebc,0x5ebd,0x5ebf,0x5ec0,0x5ec1,0x5ec2,0x5ec3,0x5ec4,
+    0x5ec5
+  },
+  {				/* ku 0f */
+    0x5ec6,0x5ec7,0x5ec8,0x5ecb,0x5ecc,0x5ecd,0x5ece,0x5ecf,0x5ed0,0x5ed4,
+    0x5ed5,0x5ed7,0x5ed8,0x5ed9,0x5eda,0x5edc,0x5edd,0x5ede,0x5edf,0x5ee0,
+    0x5ee1,0x5ee2,0x5ee3,0x5ee4,0x5ee5,0x5ee6,0x5ee7,0x5ee9,0x5eeb,0x5eec,
+    0x5eed,0x5eee,0x5eef,0x5ef0,0x5ef1,0x5ef2,0x5ef3,0x5ef5,0x5ef8,0x5ef9,
+    0x5efb,0x5efc,0x5efd,0x5f05,0x5f06,0x5f07,0x5f09,0x5f0c,0x5f0d,0x5f0e,
+    0x5f10,0x5f12,0x5f14,0x5f16,0x5f19,0x5f1a,0x5f1c,0x5f1d,0x5f1e,0x5f21,
+    0x5f22,0x5f23,0x5f24,UBOGON,0x5f28,0x5f2b,0x5f2c,0x5f2e,0x5f30,0x5f32,
+    0x5f33,0x5f34,0x5f35,0x5f36,0x5f37,0x5f38,0x5f3b,0x5f3d,0x5f3e,0x5f3f,
+    0x5f41,0x5f42,0x5f43,0x5f44,0x5f45,0x5f46,0x5f47,0x5f48,0x5f49,0x5f4a,
+    0x5f4b,0x5f4c,0x5f4d,0x5f4e,0x5f4f,0x5f51,0x5f54,0x5f59,0x5f5a,0x5f5b,
+    0x5f5c,0x5f5e,0x5f5f,0x5f60,0x5f63,0x5f65,0x5f67,0x5f68,0x5f6b,0x5f6e,
+    0x5f6f,0x5f72,0x5f74,0x5f75,0x5f76,0x5f78,0x5f7a,0x5f7d,0x5f7e,0x5f7f,
+    0x5f83,0x5f86,0x5f8d,0x5f8e,0x5f8f,0x5f91,0x5f93,0x5f94,0x5f96,0x5f9a,
+    0x5f9b,0x5f9d,0x5f9e,0x5f9f,0x5fa0,0x5fa2,0x5fa3,0x5fa4,0x5fa5,0x5fa6,
+    0x5fa7,0x5fa9,0x5fab,0x5fac,0x5faf,0x5fb0,0x5fb1,0x5fb2,0x5fb3,0x5fb4,
+    0x5fb6,0x5fb8,0x5fb9,0x5fba,0x5fbb,0x5fbe,0x5fbf,0x5fc0,0x5fc1,0x5fc2,
+    0x5fc7,0x5fc8,0x5fca,0x5fcb,0x5fce,0x5fd3,0x5fd4,0x5fd5,0x5fda,0x5fdb,
+    0x5fdc,0x5fde,0x5fdf,0x5fe2,0x5fe3,0x5fe5,0x5fe6,0x5fe8,0x5fe9,0x5fec,
+    0x5fef,0x5ff0,0x5ff2,0x5ff3,0x5ff4,0x5ff6,0x5ff7,0x5ff9,0x5ffa,0x5ffc,
+    0x6007
+  },
+  {				/* ku 10 */
+    0x6008,0x6009,0x600b,0x600c,0x6010,0x6011,0x6013,0x6017,0x6018,0x601a,
+    0x601e,0x601f,0x6022,0x6023,0x6024,0x602c,0x602d,0x602e,0x6030,0x6031,
+    0x6032,0x6033,0x6034,0x6036,0x6037,0x6038,0x6039,0x603a,0x603d,0x603e,
+    0x6040,0x6044,0x6045,0x6046,0x6047,0x6048,0x6049,0x604a,0x604c,0x604e,
+    0x604f,0x6051,0x6053,0x6054,0x6056,0x6057,0x6058,0x605b,0x605c,0x605e,
+    0x605f,0x6060,0x6061,0x6065,0x6066,0x606e,0x6071,0x6072,0x6074,0x6075,
+    0x6077,0x607e,0x6080,UBOGON,0x6081,0x6082,0x6085,0x6086,0x6087,0x6088,
+    0x608a,0x608b,0x608e,0x608f,0x6090,0x6091,0x6093,0x6095,0x6097,0x6098,
+    0x6099,0x609c,0x609e,0x60a1,0x60a2,0x60a4,0x60a5,0x60a7,0x60a9,0x60aa,
+    0x60ae,0x60b0,0x60b3,0x60b5,0x60b6,0x60b7,0x60b9,0x60ba,0x60bd,0x60be,
+    0x60bf,0x60c0,0x60c1,0x60c2,0x60c3,0x60c4,0x60c7,0x60c8,0x60c9,0x60cc,
+    0x60cd,0x60ce,0x60cf,0x60d0,0x60d2,0x60d3,0x60d4,0x60d6,0x60d7,0x60d9,
+    0x60db,0x60de,0x60e1,0x60e2,0x60e3,0x60e4,0x60e5,0x60ea,0x60f1,0x60f2,
+    0x60f5,0x60f7,0x60f8,0x60fb,0x60fc,0x60fd,0x60fe,0x60ff,0x6102,0x6103,
+    0x6104,0x6105,0x6107,0x610a,0x610b,0x610c,0x6110,0x6111,0x6112,0x6113,
+    0x6114,0x6116,0x6117,0x6118,0x6119,0x611b,0x611c,0x611d,0x611e,0x6121,
+    0x6122,0x6125,0x6128,0x6129,0x612a,0x612c,0x612d,0x612e,0x612f,0x6130,
+    0x6131,0x6132,0x6133,0x6134,0x6135,0x6136,0x6137,0x6138,0x6139,0x613a,
+    0x613b,0x613c,0x613d,0x613e,0x6140,0x6141,0x6142,0x6143,0x6144,0x6145,
+    0x6146
+  },
+  {				/* ku 11 */
+    0x6147,0x6149,0x614b,0x614d,0x614f,0x6150,0x6152,0x6153,0x6154,0x6156,
+    0x6157,0x6158,0x6159,0x615a,0x615b,0x615c,0x615e,0x615f,0x6160,0x6161,
+    0x6163,0x6164,0x6165,0x6166,0x6169,0x616a,0x616b,0x616c,0x616d,0x616e,
+    0x616f,0x6171,0x6172,0x6173,0x6174,0x6176,0x6178,0x6179,0x617a,0x617b,
+    0x617c,0x617d,0x617e,0x617f,0x6180,0x6181,0x6182,0x6183,0x6184,0x6185,
+    0x6186,0x6187,0x6188,0x6189,0x618a,0x618c,0x618d,0x618f,0x6190,0x6191,
+    0x6192,0x6193,0x6195,UBOGON,0x6196,0x6197,0x6198,0x6199,0x619a,0x619b,
+    0x619c,0x619e,0x619f,0x61a0,0x61a1,0x61a2,0x61a3,0x61a4,0x61a5,0x61a6,
+    0x61aa,0x61ab,0x61ad,0x61ae,0x61af,0x61b0,0x61b1,0x61b2,0x61b3,0x61b4,
+    0x61b5,0x61b6,0x61b8,0x61b9,0x61ba,0x61bb,0x61bc,0x61bd,0x61bf,0x61c0,
+    0x61c1,0x61c3,0x61c4,0x61c5,0x61c6,0x61c7,0x61c9,0x61cc,0x61cd,0x61ce,
+    0x61cf,0x61d0,0x61d3,0x61d5,0x61d6,0x61d7,0x61d8,0x61d9,0x61da,0x61db,
+    0x61dc,0x61dd,0x61de,0x61df,0x61e0,0x61e1,0x61e2,0x61e3,0x61e4,0x61e5,
+    0x61e7,0x61e8,0x61e9,0x61ea,0x61eb,0x61ec,0x61ed,0x61ee,0x61ef,0x61f0,
+    0x61f1,0x61f2,0x61f3,0x61f4,0x61f6,0x61f7,0x61f8,0x61f9,0x61fa,0x61fb,
+    0x61fc,0x61fd,0x61fe,0x6200,0x6201,0x6202,0x6203,0x6204,0x6205,0x6207,
+    0x6209,0x6213,0x6214,0x6219,0x621c,0x621d,0x621e,0x6220,0x6223,0x6226,
+    0x6227,0x6228,0x6229,0x622b,0x622d,0x622f,0x6230,0x6231,0x6232,0x6235,
+    0x6236,0x6238,0x6239,0x623a,0x623b,0x623c,0x6242,0x6244,0x6245,0x6246,
+    0x624a
+  },
+  {				/* ku 12 */
+    0x624f,0x6250,0x6255,0x6256,0x6257,0x6259,0x625a,0x625c,0x625d,0x625e,
+    0x625f,0x6260,0x6261,0x6262,0x6264,0x6265,0x6268,0x6271,0x6272,0x6274,
+    0x6275,0x6277,0x6278,0x627a,0x627b,0x627d,0x6281,0x6282,0x6283,0x6285,
+    0x6286,0x6287,0x6288,0x628b,0x628c,0x628d,0x628e,0x628f,0x6290,0x6294,
+    0x6299,0x629c,0x629d,0x629e,0x62a3,0x62a6,0x62a7,0x62a9,0x62aa,0x62ad,
+    0x62ae,0x62af,0x62b0,0x62b2,0x62b3,0x62b4,0x62b6,0x62b7,0x62b8,0x62ba,
+    0x62be,0x62c0,0x62c1,UBOGON,0x62c3,0x62cb,0x62cf,0x62d1,0x62d5,0x62dd,
+    0x62de,0x62e0,0x62e1,0x62e4,0x62ea,0x62eb,0x62f0,0x62f2,0x62f5,0x62f8,
+    0x62f9,0x62fa,0x62fb,0x6300,0x6303,0x6304,0x6305,0x6306,0x630a,0x630b,
+    0x630c,0x630d,0x630f,0x6310,0x6312,0x6313,0x6314,0x6315,0x6317,0x6318,
+    0x6319,0x631c,0x6326,0x6327,0x6329,0x632c,0x632d,0x632e,0x6330,0x6331,
+    0x6333,0x6334,0x6335,0x6336,0x6337,0x6338,0x633b,0x633c,0x633e,0x633f,
+    0x6340,0x6341,0x6344,0x6347,0x6348,0x634a,0x6351,0x6352,0x6353,0x6354,
+    0x6356,0x6357,0x6358,0x6359,0x635a,0x635b,0x635c,0x635d,0x6360,0x6364,
+    0x6365,0x6366,0x6368,0x636a,0x636b,0x636c,0x636f,0x6370,0x6372,0x6373,
+    0x6374,0x6375,0x6378,0x6379,0x637c,0x637d,0x637e,0x637f,0x6381,0x6383,
+    0x6384,0x6385,0x6386,0x638b,0x638d,0x6391,0x6393,0x6394,0x6395,0x6397,
+    0x6399,0x639a,0x639b,0x639c,0x639d,0x639e,0x639f,0x63a1,0x63a4,0x63a6,
+    0x63ab,0x63af,0x63b1,0x63b2,0x63b5,0x63b6,0x63b9,0x63bb,0x63bd,0x63bf,
+    0x63c0
+  },
+  {				/* ku 13 */
+    0x63c1,0x63c2,0x63c3,0x63c5,0x63c7,0x63c8,0x63ca,0x63cb,0x63cc,0x63d1,
+    0x63d3,0x63d4,0x63d5,0x63d7,0x63d8,0x63d9,0x63da,0x63db,0x63dc,0x63dd,
+    0x63df,0x63e2,0x63e4,0x63e5,0x63e6,0x63e7,0x63e8,0x63eb,0x63ec,0x63ee,
+    0x63ef,0x63f0,0x63f1,0x63f3,0x63f5,0x63f7,0x63f9,0x63fa,0x63fb,0x63fc,
+    0x63fe,0x6403,0x6404,0x6406,0x6407,0x6408,0x6409,0x640a,0x640d,0x640e,
+    0x6411,0x6412,0x6415,0x6416,0x6417,0x6418,0x6419,0x641a,0x641d,0x641f,
+    0x6422,0x6423,0x6424,UBOGON,0x6425,0x6427,0x6428,0x6429,0x642b,0x642e,
+    0x642f,0x6430,0x6431,0x6432,0x6433,0x6435,0x6436,0x6437,0x6438,0x6439,
+    0x643b,0x643c,0x643e,0x6440,0x6442,0x6443,0x6449,0x644b,0x644c,0x644d,
+    0x644e,0x644f,0x6450,0x6451,0x6453,0x6455,0x6456,0x6457,0x6459,0x645a,
+    0x645b,0x645c,0x645d,0x645f,0x6460,0x6461,0x6462,0x6463,0x6464,0x6465,
+    0x6466,0x6468,0x646a,0x646b,0x646c,0x646e,0x646f,0x6470,0x6471,0x6472,
+    0x6473,0x6474,0x6475,0x6476,0x6477,0x647b,0x647c,0x647d,0x647e,0x647f,
+    0x6480,0x6481,0x6483,0x6486,0x6488,0x6489,0x648a,0x648b,0x648c,0x648d,
+    0x648e,0x648f,0x6490,0x6493,0x6494,0x6497,0x6498,0x649a,0x649b,0x649c,
+    0x649d,0x649f,0x64a0,0x64a1,0x64a2,0x64a3,0x64a5,0x64a6,0x64a7,0x64a8,
+    0x64aa,0x64ab,0x64af,0x64b1,0x64b2,0x64b3,0x64b4,0x64b6,0x64b9,0x64bb,
+    0x64bd,0x64be,0x64bf,0x64c1,0x64c3,0x64c4,0x64c6,0x64c7,0x64c8,0x64c9,
+    0x64ca,0x64cb,0x64cc,0x64cf,0x64d1,0x64d3,0x64d4,0x64d5,0x64d6,0x64d9,
+    0x64da
+  },
+  {				/* ku 14 */
+    0x64db,0x64dc,0x64dd,0x64df,0x64e0,0x64e1,0x64e3,0x64e5,0x64e7,0x64e8,
+    0x64e9,0x64ea,0x64eb,0x64ec,0x64ed,0x64ee,0x64ef,0x64f0,0x64f1,0x64f2,
+    0x64f3,0x64f4,0x64f5,0x64f6,0x64f7,0x64f8,0x64f9,0x64fa,0x64fb,0x64fc,
+    0x64fd,0x64fe,0x64ff,0x6501,0x6502,0x6503,0x6504,0x6505,0x6506,0x6507,
+    0x6508,0x650a,0x650b,0x650c,0x650d,0x650e,0x650f,0x6510,0x6511,0x6513,
+    0x6514,0x6515,0x6516,0x6517,0x6519,0x651a,0x651b,0x651c,0x651d,0x651e,
+    0x651f,0x6520,0x6521,UBOGON,0x6522,0x6523,0x6524,0x6526,0x6527,0x6528,
+    0x6529,0x652a,0x652c,0x652d,0x6530,0x6531,0x6532,0x6533,0x6537,0x653a,
+    0x653c,0x653d,0x6540,0x6541,0x6542,0x6543,0x6544,0x6546,0x6547,0x654a,
+    0x654b,0x654d,0x654e,0x6550,0x6552,0x6553,0x6554,0x6557,0x6558,0x655a,
+    0x655c,0x655f,0x6560,0x6561,0x6564,0x6565,0x6567,0x6568,0x6569,0x656a,
+    0x656d,0x656e,0x656f,0x6571,0x6573,0x6575,0x6576,0x6578,0x6579,0x657a,
+    0x657b,0x657c,0x657d,0x657e,0x657f,0x6580,0x6581,0x6582,0x6583,0x6584,
+    0x6585,0x6586,0x6588,0x6589,0x658a,0x658d,0x658e,0x658f,0x6592,0x6594,
+    0x6595,0x6596,0x6598,0x659a,0x659d,0x659e,0x65a0,0x65a2,0x65a3,0x65a6,
+    0x65a8,0x65aa,0x65ac,0x65ae,0x65b1,0x65b2,0x65b3,0x65b4,0x65b5,0x65b6,
+    0x65b7,0x65b8,0x65ba,0x65bb,0x65be,0x65bf,0x65c0,0x65c2,0x65c7,0x65c8,
+    0x65c9,0x65ca,0x65cd,0x65d0,0x65d1,0x65d3,0x65d4,0x65d5,0x65d8,0x65d9,
+    0x65da,0x65db,0x65dc,0x65dd,0x65de,0x65df,0x65e1,0x65e3,0x65e4,0x65ea,
+    0x65eb
+  },
+  {				/* ku 15 */
+    0x65f2,0x65f3,0x65f4,0x65f5,0x65f8,0x65f9,0x65fb,0x65fc,0x65fd,0x65fe,
+    0x65ff,0x6601,0x6604,0x6605,0x6607,0x6608,0x6609,0x660b,0x660d,0x6610,
+    0x6611,0x6612,0x6616,0x6617,0x6618,0x661a,0x661b,0x661c,0x661e,0x6621,
+    0x6622,0x6623,0x6624,0x6626,0x6629,0x662a,0x662b,0x662c,0x662e,0x6630,
+    0x6632,0x6633,0x6637,0x6638,0x6639,0x663a,0x663b,0x663d,0x663f,0x6640,
+    0x6642,0x6644,0x6645,0x6646,0x6647,0x6648,0x6649,0x664a,0x664d,0x664e,
+    0x6650,0x6651,0x6658,UBOGON,0x6659,0x665b,0x665c,0x665d,0x665e,0x6660,
+    0x6662,0x6663,0x6665,0x6667,0x6669,0x666a,0x666b,0x666c,0x666d,0x6671,
+    0x6672,0x6673,0x6675,0x6678,0x6679,0x667b,0x667c,0x667d,0x667f,0x6680,
+    0x6681,0x6683,0x6685,0x6686,0x6688,0x6689,0x668a,0x668b,0x668d,0x668e,
+    0x668f,0x6690,0x6692,0x6693,0x6694,0x6695,0x6698,0x6699,0x669a,0x669b,
+    0x669c,0x669e,0x669f,0x66a0,0x66a1,0x66a2,0x66a3,0x66a4,0x66a5,0x66a6,
+    0x66a9,0x66aa,0x66ab,0x66ac,0x66ad,0x66af,0x66b0,0x66b1,0x66b2,0x66b3,
+    0x66b5,0x66b6,0x66b7,0x66b8,0x66ba,0x66bb,0x66bc,0x66bd,0x66bf,0x66c0,
+    0x66c1,0x66c2,0x66c3,0x66c4,0x66c5,0x66c6,0x66c7,0x66c8,0x66c9,0x66ca,
+    0x66cb,0x66cc,0x66cd,0x66ce,0x66cf,0x66d0,0x66d1,0x66d2,0x66d3,0x66d4,
+    0x66d5,0x66d6,0x66d7,0x66d8,0x66da,0x66de,0x66df,0x66e0,0x66e1,0x66e2,
+    0x66e3,0x66e4,0x66e5,0x66e7,0x66e8,0x66ea,0x66eb,0x66ec,0x66ed,0x66ee,
+    0x66ef,0x66f1,0x66f5,0x66f6,0x66f8,0x66fa,0x66fb,0x66fd,0x6701,0x6702,
+    0x6703
+  },
+  {				/* ku 16 */
+    0x6704,0x6705,0x6706,0x6707,0x670c,0x670e,0x670f,0x6711,0x6712,0x6713,
+    0x6716,0x6718,0x6719,0x671a,0x671c,0x671e,0x6720,0x6721,0x6722,0x6723,
+    0x6724,0x6725,0x6727,0x6729,0x672e,0x6730,0x6732,0x6733,0x6736,0x6737,
+    0x6738,0x6739,0x673b,0x673c,0x673e,0x673f,0x6741,0x6744,0x6745,0x6747,
+    0x674a,0x674b,0x674d,0x6752,0x6754,0x6755,0x6757,0x6758,0x6759,0x675a,
+    0x675b,0x675d,0x6762,0x6763,0x6764,0x6766,0x6767,0x676b,0x676c,0x676e,
+    0x6771,0x6774,0x6776,UBOGON,0x6778,0x6779,0x677a,0x677b,0x677d,0x6780,
+    0x6782,0x6783,0x6785,0x6786,0x6788,0x678a,0x678c,0x678d,0x678e,0x678f,
+    0x6791,0x6792,0x6793,0x6794,0x6796,0x6799,0x679b,0x679f,0x67a0,0x67a1,
+    0x67a4,0x67a6,0x67a9,0x67ac,0x67ae,0x67b1,0x67b2,0x67b4,0x67b9,0x67ba,
+    0x67bb,0x67bc,0x67bd,0x67be,0x67bf,0x67c0,0x67c2,0x67c5,0x67c6,0x67c7,
+    0x67c8,0x67c9,0x67ca,0x67cb,0x67cc,0x67cd,0x67ce,0x67d5,0x67d6,0x67d7,
+    0x67db,0x67df,0x67e1,0x67e3,0x67e4,0x67e6,0x67e7,0x67e8,0x67ea,0x67eb,
+    0x67ed,0x67ee,0x67f2,0x67f5,0x67f6,0x67f7,0x67f8,0x67f9,0x67fa,0x67fb,
+    0x67fc,0x67fe,0x6801,0x6802,0x6803,0x6804,0x6806,0x680d,0x6810,0x6812,
+    0x6814,0x6815,0x6818,0x6819,0x681a,0x681b,0x681c,0x681e,0x681f,0x6820,
+    0x6822,0x6823,0x6824,0x6825,0x6826,0x6827,0x6828,0x682b,0x682c,0x682d,
+    0x682e,0x682f,0x6830,0x6831,0x6834,0x6835,0x6836,0x683a,0x683b,0x683f,
+    0x6847,0x684b,0x684d,0x684f,0x6852,0x6856,0x6857,0x6858,0x6859,0x685a,
+    0x685b
+  },
+  {				/* ku 17 */
+    0x685c,0x685d,0x685e,0x685f,0x686a,0x686c,0x686d,0x686e,0x686f,0x6870,
+    0x6871,0x6872,0x6873,0x6875,0x6878,0x6879,0x687a,0x687b,0x687c,0x687d,
+    0x687e,0x687f,0x6880,0x6882,0x6884,0x6887,0x6888,0x6889,0x688a,0x688b,
+    0x688c,0x688d,0x688e,0x6890,0x6891,0x6892,0x6894,0x6895,0x6896,0x6898,
+    0x6899,0x689a,0x689b,0x689c,0x689d,0x689e,0x689f,0x68a0,0x68a1,0x68a3,
+    0x68a4,0x68a5,0x68a9,0x68aa,0x68ab,0x68ac,0x68ae,0x68b1,0x68b2,0x68b4,
+    0x68b6,0x68b7,0x68b8,UBOGON,0x68b9,0x68ba,0x68bb,0x68bc,0x68bd,0x68be,
+    0x68bf,0x68c1,0x68c3,0x68c4,0x68c5,0x68c6,0x68c7,0x68c8,0x68ca,0x68cc,
+    0x68ce,0x68cf,0x68d0,0x68d1,0x68d3,0x68d4,0x68d6,0x68d7,0x68d9,0x68db,
+    0x68dc,0x68dd,0x68de,0x68df,0x68e1,0x68e2,0x68e4,0x68e5,0x68e6,0x68e7,
+    0x68e8,0x68e9,0x68ea,0x68eb,0x68ec,0x68ed,0x68ef,0x68f2,0x68f3,0x68f4,
+    0x68f6,0x68f7,0x68f8,0x68fb,0x68fd,0x68fe,0x68ff,0x6900,0x6902,0x6903,
+    0x6904,0x6906,0x6907,0x6908,0x6909,0x690a,0x690c,0x690f,0x6911,0x6913,
+    0x6914,0x6915,0x6916,0x6917,0x6918,0x6919,0x691a,0x691b,0x691c,0x691d,
+    0x691e,0x6921,0x6922,0x6923,0x6925,0x6926,0x6927,0x6928,0x6929,0x692a,
+    0x692b,0x692c,0x692e,0x692f,0x6931,0x6932,0x6933,0x6935,0x6936,0x6937,
+    0x6938,0x693a,0x693b,0x693c,0x693e,0x6940,0x6941,0x6943,0x6944,0x6945,
+    0x6946,0x6947,0x6948,0x6949,0x694a,0x694b,0x694c,0x694d,0x694e,0x694f,
+    0x6950,0x6951,0x6952,0x6953,0x6955,0x6956,0x6958,0x6959,0x695b,0x695c,
+    0x695f
+  },
+  {				/* ku 18 */
+    0x6961,0x6962,0x6964,0x6965,0x6967,0x6968,0x6969,0x696a,0x696c,0x696d,
+    0x696f,0x6970,0x6972,0x6973,0x6974,0x6975,0x6976,0x697a,0x697b,0x697d,
+    0x697e,0x697f,0x6981,0x6983,0x6985,0x698a,0x698b,0x698c,0x698e,0x698f,
+    0x6990,0x6991,0x6992,0x6993,0x6996,0x6997,0x6999,0x699a,0x699d,0x699e,
+    0x699f,0x69a0,0x69a1,0x69a2,0x69a3,0x69a4,0x69a5,0x69a6,0x69a9,0x69aa,
+    0x69ac,0x69ae,0x69af,0x69b0,0x69b2,0x69b3,0x69b5,0x69b6,0x69b8,0x69b9,
+    0x69ba,0x69bc,0x69bd,UBOGON,0x69be,0x69bf,0x69c0,0x69c2,0x69c3,0x69c4,
+    0x69c5,0x69c6,0x69c7,0x69c8,0x69c9,0x69cb,0x69cd,0x69cf,0x69d1,0x69d2,
+    0x69d3,0x69d5,0x69d6,0x69d7,0x69d8,0x69d9,0x69da,0x69dc,0x69dd,0x69de,
+    0x69e1,0x69e2,0x69e3,0x69e4,0x69e5,0x69e6,0x69e7,0x69e8,0x69e9,0x69ea,
+    0x69eb,0x69ec,0x69ee,0x69ef,0x69f0,0x69f1,0x69f3,0x69f4,0x69f5,0x69f6,
+    0x69f7,0x69f8,0x69f9,0x69fa,0x69fb,0x69fc,0x69fe,0x6a00,0x6a01,0x6a02,
+    0x6a03,0x6a04,0x6a05,0x6a06,0x6a07,0x6a08,0x6a09,0x6a0b,0x6a0c,0x6a0d,
+    0x6a0e,0x6a0f,0x6a10,0x6a11,0x6a12,0x6a13,0x6a14,0x6a15,0x6a16,0x6a19,
+    0x6a1a,0x6a1b,0x6a1c,0x6a1d,0x6a1e,0x6a20,0x6a22,0x6a23,0x6a24,0x6a25,
+    0x6a26,0x6a27,0x6a29,0x6a2b,0x6a2c,0x6a2d,0x6a2e,0x6a30,0x6a32,0x6a33,
+    0x6a34,0x6a36,0x6a37,0x6a38,0x6a39,0x6a3a,0x6a3b,0x6a3c,0x6a3f,0x6a40,
+    0x6a41,0x6a42,0x6a43,0x6a45,0x6a46,0x6a48,0x6a49,0x6a4a,0x6a4b,0x6a4c,
+    0x6a4d,0x6a4e,0x6a4f,0x6a51,0x6a52,0x6a53,0x6a54,0x6a55,0x6a56,0x6a57,
+    0x6a5a
+  },
+  {				/* ku 19 */
+    0x6a5c,0x6a5d,0x6a5e,0x6a5f,0x6a60,0x6a62,0x6a63,0x6a64,0x6a66,0x6a67,
+    0x6a68,0x6a69,0x6a6a,0x6a6b,0x6a6c,0x6a6d,0x6a6e,0x6a6f,0x6a70,0x6a72,
+    0x6a73,0x6a74,0x6a75,0x6a76,0x6a77,0x6a78,0x6a7a,0x6a7b,0x6a7d,0x6a7e,
+    0x6a7f,0x6a81,0x6a82,0x6a83,0x6a85,0x6a86,0x6a87,0x6a88,0x6a89,0x6a8a,
+    0x6a8b,0x6a8c,0x6a8d,0x6a8f,0x6a92,0x6a93,0x6a94,0x6a95,0x6a96,0x6a98,
+    0x6a99,0x6a9a,0x6a9b,0x6a9c,0x6a9d,0x6a9e,0x6a9f,0x6aa1,0x6aa2,0x6aa3,
+    0x6aa4,0x6aa5,0x6aa6,UBOGON,0x6aa7,0x6aa8,0x6aaa,0x6aad,0x6aae,0x6aaf,
+    0x6ab0,0x6ab1,0x6ab2,0x6ab3,0x6ab4,0x6ab5,0x6ab6,0x6ab7,0x6ab8,0x6ab9,
+    0x6aba,0x6abb,0x6abc,0x6abd,0x6abe,0x6abf,0x6ac0,0x6ac1,0x6ac2,0x6ac3,
+    0x6ac4,0x6ac5,0x6ac6,0x6ac7,0x6ac8,0x6ac9,0x6aca,0x6acb,0x6acc,0x6acd,
+    0x6ace,0x6acf,0x6ad0,0x6ad1,0x6ad2,0x6ad3,0x6ad4,0x6ad5,0x6ad6,0x6ad7,
+    0x6ad8,0x6ad9,0x6ada,0x6adb,0x6adc,0x6add,0x6ade,0x6adf,0x6ae0,0x6ae1,
+    0x6ae2,0x6ae3,0x6ae4,0x6ae5,0x6ae6,0x6ae7,0x6ae8,0x6ae9,0x6aea,0x6aeb,
+    0x6aec,0x6aed,0x6aee,0x6aef,0x6af0,0x6af1,0x6af2,0x6af3,0x6af4,0x6af5,
+    0x6af6,0x6af7,0x6af8,0x6af9,0x6afa,0x6afb,0x6afc,0x6afd,0x6afe,0x6aff,
+    0x6b00,0x6b01,0x6b02,0x6b03,0x6b04,0x6b05,0x6b06,0x6b07,0x6b08,0x6b09,
+    0x6b0a,0x6b0b,0x6b0c,0x6b0d,0x6b0e,0x6b0f,0x6b10,0x6b11,0x6b12,0x6b13,
+    0x6b14,0x6b15,0x6b16,0x6b17,0x6b18,0x6b19,0x6b1a,0x6b1b,0x6b1c,0x6b1d,
+    0x6b1e,0x6b1f,0x6b25,0x6b26,0x6b28,0x6b29,0x6b2a,0x6b2b,0x6b2c,0x6b2d,
+    0x6b2e
+  },
+  {				/* ku 1a */
+    0x6b2f,0x6b30,0x6b31,0x6b33,0x6b34,0x6b35,0x6b36,0x6b38,0x6b3b,0x6b3c,
+    0x6b3d,0x6b3f,0x6b40,0x6b41,0x6b42,0x6b44,0x6b45,0x6b48,0x6b4a,0x6b4b,
+    0x6b4d,0x6b4e,0x6b4f,0x6b50,0x6b51,0x6b52,0x6b53,0x6b54,0x6b55,0x6b56,
+    0x6b57,0x6b58,0x6b5a,0x6b5b,0x6b5c,0x6b5d,0x6b5e,0x6b5f,0x6b60,0x6b61,
+    0x6b68,0x6b69,0x6b6b,0x6b6c,0x6b6d,0x6b6e,0x6b6f,0x6b70,0x6b71,0x6b72,
+    0x6b73,0x6b74,0x6b75,0x6b76,0x6b77,0x6b78,0x6b7a,0x6b7d,0x6b7e,0x6b7f,
+    0x6b80,0x6b85,0x6b88,UBOGON,0x6b8c,0x6b8e,0x6b8f,0x6b90,0x6b91,0x6b94,
+    0x6b95,0x6b97,0x6b98,0x6b99,0x6b9c,0x6b9d,0x6b9e,0x6b9f,0x6ba0,0x6ba2,
+    0x6ba3,0x6ba4,0x6ba5,0x6ba6,0x6ba7,0x6ba8,0x6ba9,0x6bab,0x6bac,0x6bad,
+    0x6bae,0x6baf,0x6bb0,0x6bb1,0x6bb2,0x6bb6,0x6bb8,0x6bb9,0x6bba,0x6bbb,
+    0x6bbc,0x6bbd,0x6bbe,0x6bc0,0x6bc3,0x6bc4,0x6bc6,0x6bc7,0x6bc8,0x6bc9,
+    0x6bca,0x6bcc,0x6bce,0x6bd0,0x6bd1,0x6bd8,0x6bda,0x6bdc,0x6bdd,0x6bde,
+    0x6bdf,0x6be0,0x6be2,0x6be3,0x6be4,0x6be5,0x6be6,0x6be7,0x6be8,0x6be9,
+    0x6bec,0x6bed,0x6bee,0x6bf0,0x6bf1,0x6bf2,0x6bf4,0x6bf6,0x6bf7,0x6bf8,
+    0x6bfa,0x6bfb,0x6bfc,0x6bfe,0x6bff,0x6c00,0x6c01,0x6c02,0x6c03,0x6c04,
+    0x6c08,0x6c09,0x6c0a,0x6c0b,0x6c0c,0x6c0e,0x6c12,0x6c17,0x6c1c,0x6c1d,
+    0x6c1e,0x6c20,0x6c23,0x6c25,0x6c2b,0x6c2c,0x6c2d,0x6c31,0x6c33,0x6c36,
+    0x6c37,0x6c39,0x6c3a,0x6c3b,0x6c3c,0x6c3e,0x6c3f,0x6c43,0x6c44,0x6c45,
+    0x6c48,0x6c4b,0x6c4c,0x6c4d,0x6c4e,0x6c4f,0x6c51,0x6c52,0x6c53,0x6c56,
+    0x6c58
+  },
+  {				/* ku 1b */
+    0x6c59,0x6c5a,0x6c62,0x6c63,0x6c65,0x6c66,0x6c67,0x6c6b,0x6c6c,0x6c6d,
+    0x6c6e,0x6c6f,0x6c71,0x6c73,0x6c75,0x6c77,0x6c78,0x6c7a,0x6c7b,0x6c7c,
+    0x6c7f,0x6c80,0x6c84,0x6c87,0x6c8a,0x6c8b,0x6c8d,0x6c8e,0x6c91,0x6c92,
+    0x6c95,0x6c96,0x6c97,0x6c98,0x6c9a,0x6c9c,0x6c9d,0x6c9e,0x6ca0,0x6ca2,
+    0x6ca8,0x6cac,0x6caf,0x6cb0,0x6cb4,0x6cb5,0x6cb6,0x6cb7,0x6cba,0x6cc0,
+    0x6cc1,0x6cc2,0x6cc3,0x6cc6,0x6cc7,0x6cc8,0x6ccb,0x6ccd,0x6cce,0x6ccf,
+    0x6cd1,0x6cd2,0x6cd8,UBOGON,0x6cd9,0x6cda,0x6cdc,0x6cdd,0x6cdf,0x6ce4,
+    0x6ce6,0x6ce7,0x6ce9,0x6cec,0x6ced,0x6cf2,0x6cf4,0x6cf9,0x6cff,0x6d00,
+    0x6d02,0x6d03,0x6d05,0x6d06,0x6d08,0x6d09,0x6d0a,0x6d0d,0x6d0f,0x6d10,
+    0x6d11,0x6d13,0x6d14,0x6d15,0x6d16,0x6d18,0x6d1c,0x6d1d,0x6d1f,0x6d20,
+    0x6d21,0x6d22,0x6d23,0x6d24,0x6d26,0x6d28,0x6d29,0x6d2c,0x6d2d,0x6d2f,
+    0x6d30,0x6d34,0x6d36,0x6d37,0x6d38,0x6d3a,0x6d3f,0x6d40,0x6d42,0x6d44,
+    0x6d49,0x6d4c,0x6d50,0x6d55,0x6d56,0x6d57,0x6d58,0x6d5b,0x6d5d,0x6d5f,
+    0x6d61,0x6d62,0x6d64,0x6d65,0x6d67,0x6d68,0x6d6b,0x6d6c,0x6d6d,0x6d70,
+    0x6d71,0x6d72,0x6d73,0x6d75,0x6d76,0x6d79,0x6d7a,0x6d7b,0x6d7d,0x6d7e,
+    0x6d7f,0x6d80,0x6d81,0x6d83,0x6d84,0x6d86,0x6d87,0x6d8a,0x6d8b,0x6d8d,
+    0x6d8f,0x6d90,0x6d92,0x6d96,0x6d97,0x6d98,0x6d99,0x6d9a,0x6d9c,0x6da2,
+    0x6da5,0x6dac,0x6dad,0x6db0,0x6db1,0x6db3,0x6db4,0x6db6,0x6db7,0x6db9,
+    0x6dba,0x6dbb,0x6dbc,0x6dbd,0x6dbe,0x6dc1,0x6dc2,0x6dc3,0x6dc8,0x6dc9,
+    0x6dca
+  },
+  {				/* ku 1c */
+    0x6dcd,0x6dce,0x6dcf,0x6dd0,0x6dd2,0x6dd3,0x6dd4,0x6dd5,0x6dd7,0x6dda,
+    0x6ddb,0x6ddc,0x6ddf,0x6de2,0x6de3,0x6de5,0x6de7,0x6de8,0x6de9,0x6dea,
+    0x6ded,0x6def,0x6df0,0x6df2,0x6df4,0x6df5,0x6df6,0x6df8,0x6dfa,0x6dfd,
+    0x6dfe,0x6dff,0x6e00,0x6e01,0x6e02,0x6e03,0x6e04,0x6e06,0x6e07,0x6e08,
+    0x6e09,0x6e0b,0x6e0f,0x6e12,0x6e13,0x6e15,0x6e18,0x6e19,0x6e1b,0x6e1c,
+    0x6e1e,0x6e1f,0x6e22,0x6e26,0x6e27,0x6e28,0x6e2a,0x6e2c,0x6e2e,0x6e30,
+    0x6e31,0x6e33,0x6e35,UBOGON,0x6e36,0x6e37,0x6e39,0x6e3b,0x6e3c,0x6e3d,
+    0x6e3e,0x6e3f,0x6e40,0x6e41,0x6e42,0x6e45,0x6e46,0x6e47,0x6e48,0x6e49,
+    0x6e4a,0x6e4b,0x6e4c,0x6e4f,0x6e50,0x6e51,0x6e52,0x6e55,0x6e57,0x6e59,
+    0x6e5a,0x6e5c,0x6e5d,0x6e5e,0x6e60,0x6e61,0x6e62,0x6e63,0x6e64,0x6e65,
+    0x6e66,0x6e67,0x6e68,0x6e69,0x6e6a,0x6e6c,0x6e6d,0x6e6f,0x6e70,0x6e71,
+    0x6e72,0x6e73,0x6e74,0x6e75,0x6e76,0x6e77,0x6e78,0x6e79,0x6e7a,0x6e7b,
+    0x6e7c,0x6e7d,0x6e80,0x6e81,0x6e82,0x6e84,0x6e87,0x6e88,0x6e8a,0x6e8b,
+    0x6e8c,0x6e8d,0x6e8e,0x6e91,0x6e92,0x6e93,0x6e94,0x6e95,0x6e96,0x6e97,
+    0x6e99,0x6e9a,0x6e9b,0x6e9d,0x6e9e,0x6ea0,0x6ea1,0x6ea3,0x6ea4,0x6ea6,
+    0x6ea8,0x6ea9,0x6eab,0x6eac,0x6ead,0x6eae,0x6eb0,0x6eb3,0x6eb5,0x6eb8,
+    0x6eb9,0x6ebc,0x6ebe,0x6ebf,0x6ec0,0x6ec3,0x6ec4,0x6ec5,0x6ec6,0x6ec8,
+    0x6ec9,0x6eca,0x6ecc,0x6ecd,0x6ece,0x6ed0,0x6ed2,0x6ed6,0x6ed8,0x6ed9,
+    0x6edb,0x6edc,0x6edd,0x6ee3,0x6ee7,0x6eea,0x6eeb,0x6eec,0x6eed,0x6eee,
+    0x6eef
+  },
+  {				/* ku 1d */
+    0x6ef0,0x6ef1,0x6ef2,0x6ef3,0x6ef5,0x6ef6,0x6ef7,0x6ef8,0x6efa,0x6efb,
+    0x6efc,0x6efd,0x6efe,0x6eff,0x6f00,0x6f01,0x6f03,0x6f04,0x6f05,0x6f07,
+    0x6f08,0x6f0a,0x6f0b,0x6f0c,0x6f0d,0x6f0e,0x6f10,0x6f11,0x6f12,0x6f16,
+    0x6f17,0x6f18,0x6f19,0x6f1a,0x6f1b,0x6f1c,0x6f1d,0x6f1e,0x6f1f,0x6f21,
+    0x6f22,0x6f23,0x6f25,0x6f26,0x6f27,0x6f28,0x6f2c,0x6f2e,0x6f30,0x6f32,
+    0x6f34,0x6f35,0x6f37,0x6f38,0x6f39,0x6f3a,0x6f3b,0x6f3c,0x6f3d,0x6f3f,
+    0x6f40,0x6f41,0x6f42,UBOGON,0x6f43,0x6f44,0x6f45,0x6f48,0x6f49,0x6f4a,
+    0x6f4c,0x6f4e,0x6f4f,0x6f50,0x6f51,0x6f52,0x6f53,0x6f54,0x6f55,0x6f56,
+    0x6f57,0x6f59,0x6f5a,0x6f5b,0x6f5d,0x6f5f,0x6f60,0x6f61,0x6f63,0x6f64,
+    0x6f65,0x6f67,0x6f68,0x6f69,0x6f6a,0x6f6b,0x6f6c,0x6f6f,0x6f70,0x6f71,
+    0x6f73,0x6f75,0x6f76,0x6f77,0x6f79,0x6f7b,0x6f7d,0x6f7e,0x6f7f,0x6f80,
+    0x6f81,0x6f82,0x6f83,0x6f85,0x6f86,0x6f87,0x6f8a,0x6f8b,0x6f8f,0x6f90,
+    0x6f91,0x6f92,0x6f93,0x6f94,0x6f95,0x6f96,0x6f97,0x6f98,0x6f99,0x6f9a,
+    0x6f9b,0x6f9d,0x6f9e,0x6f9f,0x6fa0,0x6fa2,0x6fa3,0x6fa4,0x6fa5,0x6fa6,
+    0x6fa8,0x6fa9,0x6faa,0x6fab,0x6fac,0x6fad,0x6fae,0x6faf,0x6fb0,0x6fb1,
+    0x6fb2,0x6fb4,0x6fb5,0x6fb7,0x6fb8,0x6fba,0x6fbb,0x6fbc,0x6fbd,0x6fbe,
+    0x6fbf,0x6fc1,0x6fc3,0x6fc4,0x6fc5,0x6fc6,0x6fc7,0x6fc8,0x6fca,0x6fcb,
+    0x6fcc,0x6fcd,0x6fce,0x6fcf,0x6fd0,0x6fd3,0x6fd4,0x6fd5,0x6fd6,0x6fd7,
+    0x6fd8,0x6fd9,0x6fda,0x6fdb,0x6fdc,0x6fdd,0x6fdf,0x6fe2,0x6fe3,0x6fe4,
+    0x6fe5
+  },
+  {				/* ku 1e */
+    0x6fe6,0x6fe7,0x6fe8,0x6fe9,0x6fea,0x6feb,0x6fec,0x6fed,0x6ff0,0x6ff1,
+    0x6ff2,0x6ff3,0x6ff4,0x6ff5,0x6ff6,0x6ff7,0x6ff8,0x6ff9,0x6ffa,0x6ffb,
+    0x6ffc,0x6ffd,0x6ffe,0x6fff,0x7000,0x7001,0x7002,0x7003,0x7004,0x7005,
+    0x7006,0x7007,0x7008,0x7009,0x700a,0x700b,0x700c,0x700d,0x700e,0x700f,
+    0x7010,0x7012,0x7013,0x7014,0x7015,0x7016,0x7017,0x7018,0x7019,0x701c,
+    0x701d,0x701e,0x701f,0x7020,0x7021,0x7022,0x7024,0x7025,0x7026,0x7027,
+    0x7028,0x7029,0x702a,UBOGON,0x702b,0x702c,0x702d,0x702e,0x702f,0x7030,
+    0x7031,0x7032,0x7033,0x7034,0x7036,0x7037,0x7038,0x703a,0x703b,0x703c,
+    0x703d,0x703e,0x703f,0x7040,0x7041,0x7042,0x7043,0x7044,0x7045,0x7046,
+    0x7047,0x7048,0x7049,0x704a,0x704b,0x704d,0x704e,0x7050,0x7051,0x7052,
+    0x7053,0x7054,0x7055,0x7056,0x7057,0x7058,0x7059,0x705a,0x705b,0x705c,
+    0x705d,0x705f,0x7060,0x7061,0x7062,0x7063,0x7064,0x7065,0x7066,0x7067,
+    0x7068,0x7069,0x706a,0x706e,0x7071,0x7072,0x7073,0x7074,0x7077,0x7079,
+    0x707a,0x707b,0x707d,0x7081,0x7082,0x7083,0x7084,0x7086,0x7087,0x7088,
+    0x708b,0x708c,0x708d,0x708f,0x7090,0x7091,0x7093,0x7097,0x7098,0x709a,
+    0x709b,0x709e,0x709f,0x70a0,0x70a1,0x70a2,0x70a3,0x70a4,0x70a5,0x70a6,
+    0x70a7,0x70a8,0x70a9,0x70aa,0x70b0,0x70b2,0x70b4,0x70b5,0x70b6,0x70ba,
+    0x70be,0x70bf,0x70c4,0x70c5,0x70c6,0x70c7,0x70c9,0x70cb,0x70cc,0x70cd,
+    0x70ce,0x70cf,0x70d0,0x70d1,0x70d2,0x70d3,0x70d4,0x70d5,0x70d6,0x70d7,
+    0x70da
+  },
+  {				/* ku 1f */
+    0x70dc,0x70dd,0x70de,0x70e0,0x70e1,0x70e2,0x70e3,0x70e5,0x70ea,0x70ee,
+    0x70f0,0x70f1,0x70f2,0x70f3,0x70f4,0x70f5,0x70f6,0x70f8,0x70fa,0x70fb,
+    0x70fc,0x70fe,0x70ff,0x7100,0x7101,0x7102,0x7103,0x7104,0x7105,0x7106,
+    0x7107,0x7108,0x710b,0x710c,0x710d,0x710e,0x710f,0x7111,0x7112,0x7114,
+    0x7117,0x711b,0x711c,0x711d,0x711e,0x711f,0x7120,0x7121,0x7122,0x7123,
+    0x7124,0x7125,0x7127,0x7128,0x7129,0x712a,0x712b,0x712c,0x712d,0x712e,
+    0x7132,0x7133,0x7134,UBOGON,0x7135,0x7137,0x7138,0x7139,0x713a,0x713b,
+    0x713c,0x713d,0x713e,0x713f,0x7140,0x7141,0x7142,0x7143,0x7144,0x7146,
+    0x7147,0x7148,0x7149,0x714b,0x714d,0x714f,0x7150,0x7151,0x7152,0x7153,
+    0x7154,0x7155,0x7156,0x7157,0x7158,0x7159,0x715a,0x715b,0x715d,0x715f,
+    0x7160,0x7161,0x7162,0x7163,0x7165,0x7169,0x716a,0x716b,0x716c,0x716d,
+    0x716f,0x7170,0x7171,0x7174,0x7175,0x7176,0x7177,0x7179,0x717b,0x717c,
+    0x717e,0x717f,0x7180,0x7181,0x7182,0x7183,0x7185,0x7186,0x7187,0x7188,
+    0x7189,0x718b,0x718c,0x718d,0x718e,0x7190,0x7191,0x7192,0x7193,0x7195,
+    0x7196,0x7197,0x719a,0x719b,0x719c,0x719d,0x719e,0x71a1,0x71a2,0x71a3,
+    0x71a4,0x71a5,0x71a6,0x71a7,0x71a9,0x71aa,0x71ab,0x71ad,0x71ae,0x71af,
+    0x71b0,0x71b1,0x71b2,0x71b4,0x71b6,0x71b7,0x71b8,0x71ba,0x71bb,0x71bc,
+    0x71bd,0x71be,0x71bf,0x71c0,0x71c1,0x71c2,0x71c4,0x71c5,0x71c6,0x71c7,
+    0x71c8,0x71c9,0x71ca,0x71cb,0x71cc,0x71cd,0x71cf,0x71d0,0x71d1,0x71d2,
+    0x71d3
+  },
+  {				/* ku 20 */
+    0x71d6,0x71d7,0x71d8,0x71d9,0x71da,0x71db,0x71dc,0x71dd,0x71de,0x71df,
+    0x71e1,0x71e2,0x71e3,0x71e4,0x71e6,0x71e8,0x71e9,0x71ea,0x71eb,0x71ec,
+    0x71ed,0x71ef,0x71f0,0x71f1,0x71f2,0x71f3,0x71f4,0x71f5,0x71f6,0x71f7,
+    0x71f8,0x71fa,0x71fb,0x71fc,0x71fd,0x71fe,0x71ff,0x7200,0x7201,0x7202,
+    0x7203,0x7204,0x7205,0x7207,0x7208,0x7209,0x720a,0x720b,0x720c,0x720d,
+    0x720e,0x720f,0x7210,0x7211,0x7212,0x7213,0x7214,0x7215,0x7216,0x7217,
+    0x7218,0x7219,0x721a,UBOGON,0x721b,0x721c,0x721e,0x721f,0x7220,0x7221,
+    0x7222,0x7223,0x7224,0x7225,0x7226,0x7227,0x7229,0x722b,0x722d,0x722e,
+    0x722f,0x7232,0x7233,0x7234,0x723a,0x723c,0x723e,0x7240,0x7241,0x7242,
+    0x7243,0x7244,0x7245,0x7246,0x7249,0x724a,0x724b,0x724e,0x724f,0x7250,
+    0x7251,0x7253,0x7254,0x7255,0x7257,0x7258,0x725a,0x725c,0x725e,0x7260,
+    0x7263,0x7264,0x7265,0x7268,0x726a,0x726b,0x726c,0x726d,0x7270,0x7271,
+    0x7273,0x7274,0x7276,0x7277,0x7278,0x727b,0x727c,0x727d,0x7282,0x7283,
+    0x7285,0x7286,0x7287,0x7288,0x7289,0x728c,0x728e,0x7290,0x7291,0x7293,
+    0x7294,0x7295,0x7296,0x7297,0x7298,0x7299,0x729a,0x729b,0x729c,0x729d,
+    0x729e,0x72a0,0x72a1,0x72a2,0x72a3,0x72a4,0x72a5,0x72a6,0x72a7,0x72a8,
+    0x72a9,0x72aa,0x72ab,0x72ae,0x72b1,0x72b2,0x72b3,0x72b5,0x72ba,0x72bb,
+    0x72bc,0x72bd,0x72be,0x72bf,0x72c0,0x72c5,0x72c6,0x72c7,0x72c9,0x72ca,
+    0x72cb,0x72cc,0x72cf,0x72d1,0x72d3,0x72d4,0x72d5,0x72d6,0x72d8,0x72da,
+    0x72db
+  },
+  {				/* ku 21 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3000,0x3001,0x3002,
+    0x00b7,0x02c9,0x02c7,0x00a8,0x3003,0x3005,0x2014,0xff5e,0x2016,0x2026,
+    0x2018,0x2019,0x201c,0x201d,0x3014,0x3015,0x3008,0x3009,0x300a,0x300b,
+    0x300c,0x300d,0x300e,0x300f,0x3016,0x3017,0x3010,0x3011,0x00b1,0x00d7,
+    0x00f7,0x2236,0x2227,0x2228,0x2211,0x220f,0x222a,0x2229,0x2208,0x2237,
+    0x221a,0x22a5,0x2225,0x2220,0x2312,0x2299,0x222b,0x222e,0x2261,0x224c,
+    0x2248,0x223d,0x221d,0x2260,0x226e,0x226f,0x2264,0x2265,0x221e,0x2235,
+    0x2234,0x2642,0x2640,0x00b0,0x2032,0x2033,0x2103,0xff04,0x00a4,0xffe0,
+    0xffe1,0x2030,0x00a7,0x2116,0x2606,0x2605,0x25cb,0x25cf,0x25ce,0x25c7,
+    0x25c6,0x25a1,0x25a0,0x25b3,0x25b2,0x203b,0x2192,0x2190,0x2191,0x2193,
+    0x3013
+  },
+  {				/* ku 22 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x2170,0x2171,0x2172,
+    0x2173,0x2174,0x2175,0x2176,0x2177,0x2178,0x2179,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x2488,0x2489,0x248a,0x248b,0x248c,0x248d,0x248e,
+    0x248f,0x2490,0x2491,0x2492,0x2493,0x2494,0x2495,0x2496,0x2497,0x2498,
+    0x2499,0x249a,0x249b,0x2474,0x2475,0x2476,0x2477,0x2478,0x2479,0x247a,
+    0x247b,0x247c,0x247d,0x247e,0x247f,0x2480,0x2481,0x2482,0x2483,0x2484,
+    0x2485,0x2486,0x2487,0x2460,0x2461,0x2462,0x2463,0x2464,0x2465,0x2466,
+    0x2467,0x2468,0x2469,UBOGON,UBOGON,0x3220,0x3221,0x3222,0x3223,0x3224,
+    0x3225,0x3226,0x3227,0x3228,0x3229,UBOGON,UBOGON,0x2160,0x2161,0x2162,
+    0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,0x2169,0x216a,0x216b,UBOGON,
+    UBOGON
+  },
+  {				/* ku 23 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xff01,0xff02,0xff03,
+    0xffe5,0xff05,0xff06,0xff07,0xff08,0xff09,0xff0a,0xff0b,0xff0c,0xff0d,
+    0xff0e,0xff0f,0xff10,0xff11,0xff12,0xff13,0xff14,0xff15,0xff16,0xff17,
+    0xff18,0xff19,0xff1a,0xff1b,0xff1c,0xff1d,0xff1e,0xff1f,0xff20,0xff21,
+    0xff22,0xff23,0xff24,0xff25,0xff26,0xff27,0xff28,0xff29,0xff2a,0xff2b,
+    0xff2c,0xff2d,0xff2e,0xff2f,0xff30,0xff31,0xff32,0xff33,0xff34,0xff35,
+    0xff36,0xff37,0xff38,0xff39,0xff3a,0xff3b,0xff3c,0xff3d,0xff3e,0xff3f,
+    0xff40,0xff41,0xff42,0xff43,0xff44,0xff45,0xff46,0xff47,0xff48,0xff49,
+    0xff4a,0xff4b,0xff4c,0xff4d,0xff4e,0xff4f,0xff50,0xff51,0xff52,0xff53,
+    0xff54,0xff55,0xff56,0xff57,0xff58,0xff59,0xff5a,0xff5b,0xff5c,0xff5d,
+    0xffe3
+  },
+  {				/* ku 24 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3041,0x3042,0x3043,
+    0x3044,0x3045,0x3046,0x3047,0x3048,0x3049,0x304a,0x304b,0x304c,0x304d,
+    0x304e,0x304f,0x3050,0x3051,0x3052,0x3053,0x3054,0x3055,0x3056,0x3057,
+    0x3058,0x3059,0x305a,0x305b,0x305c,0x305d,0x305e,0x305f,0x3060,0x3061,
+    0x3062,0x3063,0x3064,0x3065,0x3066,0x3067,0x3068,0x3069,0x306a,0x306b,
+    0x306c,0x306d,0x306e,0x306f,0x3070,0x3071,0x3072,0x3073,0x3074,0x3075,
+    0x3076,0x3077,0x3078,0x3079,0x307a,0x307b,0x307c,0x307d,0x307e,0x307f,
+    0x3080,0x3081,0x3082,0x3083,0x3084,0x3085,0x3086,0x3087,0x3088,0x3089,
+    0x308a,0x308b,0x308c,0x308d,0x308e,0x308f,0x3090,0x3091,0x3092,0x3093,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON
+  },
+  {				/* ku 25 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x30a1,0x30a2,0x30a3,
+    0x30a4,0x30a5,0x30a6,0x30a7,0x30a8,0x30a9,0x30aa,0x30ab,0x30ac,0x30ad,
+    0x30ae,0x30af,0x30b0,0x30b1,0x30b2,0x30b3,0x30b4,0x30b5,0x30b6,0x30b7,
+    0x30b8,0x30b9,0x30ba,0x30bb,0x30bc,0x30bd,0x30be,0x30bf,0x30c0,0x30c1,
+    0x30c2,0x30c3,0x30c4,0x30c5,0x30c6,0x30c7,0x30c8,0x30c9,0x30ca,0x30cb,
+    0x30cc,0x30cd,0x30ce,0x30cf,0x30d0,0x30d1,0x30d2,0x30d3,0x30d4,0x30d5,
+    0x30d6,0x30d7,0x30d8,0x30d9,0x30da,0x30db,0x30dc,0x30dd,0x30de,0x30df,
+    0x30e0,0x30e1,0x30e2,0x30e3,0x30e4,0x30e5,0x30e6,0x30e7,0x30e8,0x30e9,
+    0x30ea,0x30eb,0x30ec,0x30ed,0x30ee,0x30ef,0x30f0,0x30f1,0x30f2,0x30f3,
+    0x30f4,0x30f5,0x30f6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON
+  },
+  {				/* ku 26 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x0391,0x0392,0x0393,
+    0x0394,0x0395,0x0396,0x0397,0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,
+    0x039e,0x039f,0x03a0,0x03a1,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,0x03a8,
+    0x03a9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x03b1,
+    0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8,0x03b9,0x03ba,0x03bb,
+    0x03bc,0x03bd,0x03be,0x03bf,0x03c0,0x03c1,0x03c3,0x03c4,0x03c5,0x03c6,
+    0x03c7,0x03c8,0x03c9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0xfe35,0xfe36,0xfe39,0xfe3a,0xfe3f,0xfe40,0xfe3d,0xfe3e,0xfe41,0xfe42,
+    0xfe43,0xfe44,UBOGON,UBOGON,0xfe3b,0xfe3c,0xfe37,0xfe38,0xfe31,UBOGON,
+    0xfe33,0xfe34,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON
+  },
+  {				/* ku 27 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x0410,0x0411,0x0412,
+    0x0413,0x0414,0x0415,0x0401,0x0416,0x0417,0x0418,0x0419,0x041a,0x041b,
+    0x041c,0x041d,0x041e,0x041f,0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,
+    0x0426,0x0427,0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x0430,0x0431,0x0432,0x0433,0x0434,
+    0x0435,0x0451,0x0436,0x0437,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,
+    0x043e,0x043f,0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,0x0447,
+    0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,0x044f,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON
+  },
+  {				/* ku 28 */
+    0x02ca,0x02cb,0x02d9,0x2013,0x2015,0x2025,0x2035,0x2105,0x2109,0x2196,
+    0x2197,0x2198,0x2199,0x2215,0x221f,0x2223,0x2252,0x2266,0x2267,0x22bf,
+    0x2550,0x2551,0x2552,0x2553,0x2554,0x2555,0x2556,0x2557,0x2558,0x2559,
+    0x255a,0x255b,0x255c,0x255d,0x255e,0x255f,0x2560,0x2561,0x2562,0x2563,
+    0x2564,0x2565,0x2566,0x2567,0x2568,0x2569,0x256a,0x256b,0x256c,0x256d,
+    0x256e,0x256f,0x2570,0x2571,0x2572,0x2573,0x2581,0x2582,0x2583,0x2584,
+    0x2585,0x2586,0x2587,UBOGON,0x2588,0x2589,0x258a,0x258b,0x258c,0x258d,
+    0x258e,0x258f,0x2593,0x2594,0x2595,0x25bc,0x25bd,0x25e2,0x25e3,0x25e4,
+    0x25e5,0x2609,0x2295,0x3012,0x301d,0x301e,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x0101,0x00e1,0x01ce,
+    0x00e0,0x0113,0x00e9,0x011b,0x00e8,0x012b,0x00ed,0x01d0,0x00ec,0x014d,
+    0x00f3,0x01d2,0x00f2,0x016b,0x00fa,0x01d4,0x00f9,0x01d6,0x01d8,0x01da,
+    0x01dc,0x00fc,0x00ea,0x0251,UBOGON,0x0144,0x0148,UBOGON,0x0261,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x3105,0x3106,0x3107,0x3108,0x3109,0x310a,0x310b,
+    0x310c,0x310d,0x310e,0x310f,0x3110,0x3111,0x3112,0x3113,0x3114,0x3115,
+    0x3116,0x3117,0x3118,0x3119,0x311a,0x311b,0x311c,0x311d,0x311e,0x311f,
+    0x3120,0x3121,0x3122,0x3123,0x3124,0x3125,0x3126,0x3127,0x3128,0x3129,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON
+  },
+  {				/* ku 29 */
+    0x3021,0x3022,0x3023,0x3024,0x3025,0x3026,0x3027,0x3028,0x3029,0x32a3,
+    0x338e,0x338f,0x339c,0x339d,0x339e,0x33a1,0x33c4,0x33ce,0x33d1,0x33d2,
+    0x33d5,0xfe30,0xffe2,0xffe4,UBOGON,0x2121,0x3231,UBOGON,0x2010,UBOGON,
+    UBOGON,UBOGON,0x30fc,0x309b,0x309c,0x30fd,0x30fe,0x3006,0x309d,0x309e,
+    0xfe49,0xfe4a,0xfe4b,0xfe4c,0xfe4d,0xfe4e,0xfe4f,0xfe50,0xfe51,0xfe52,
+    0xfe54,0xfe55,0xfe56,0xfe57,0xfe59,0xfe5a,0xfe5b,0xfe5c,0xfe5d,0xfe5e,
+    0xfe5f,0xfe60,0xfe61,UBOGON,0xfe62,0xfe63,0xfe64,0xfe65,0xfe66,0xfe68,
+    0xfe69,0xfe6a,0xfe6b,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x3007,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x2500,0x2501,0x2502,0x2503,0x2504,0x2505,0x2506,0x2507,0x2508,0x2509,
+    0x250a,0x250b,0x250c,0x250d,0x250e,0x250f,0x2510,0x2511,0x2512,0x2513,
+    0x2514,0x2515,0x2516,0x2517,0x2518,0x2519,0x251a,0x251b,0x251c,0x251d,
+    0x251e,0x251f,0x2520,0x2521,0x2522,0x2523,0x2524,0x2525,0x2526,0x2527,
+    0x2528,0x2529,0x252a,0x252b,0x252c,0x252d,0x252e,0x252f,0x2530,0x2531,
+    0x2532,0x2533,0x2534,0x2535,0x2536,0x2537,0x2538,0x2539,0x253a,0x253b,
+    0x253c,0x253d,0x253e,0x253f,0x2540,0x2541,0x2542,0x2543,0x2544,0x2545,
+    0x2546,0x2547,0x2548,0x2549,0x254a,0x254b,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON
+  },
+  {				/* ku 2a */
+    0x72dc,0x72dd,0x72df,0x72e2,0x72e3,0x72e4,0x72e5,0x72e6,0x72e7,0x72ea,
+    0x72eb,0x72f5,0x72f6,0x72f9,0x72fd,0x72fe,0x72ff,0x7300,0x7302,0x7304,
+    0x7305,0x7306,0x7307,0x7308,0x7309,0x730b,0x730c,0x730d,0x730f,0x7310,
+    0x7311,0x7312,0x7314,0x7318,0x7319,0x731a,0x731f,0x7320,0x7323,0x7324,
+    0x7326,0x7327,0x7328,0x732d,0x732f,0x7330,0x7332,0x7333,0x7335,0x7336,
+    0x733a,0x733b,0x733c,0x733d,0x7340,0x7341,0x7342,0x7343,0x7344,0x7345,
+    0x7346,0x7347,0x7348,UBOGON,0x7349,0x734a,0x734b,0x734c,0x734e,0x734f,
+    0x7351,0x7353,0x7354,0x7355,0x7356,0x7358,0x7359,0x735a,0x735b,0x735c,
+    0x735d,0x735e,0x735f,0x7361,0x7362,0x7363,0x7364,0x7365,0x7366,0x7367,
+    0x7368,0x7369,0x736a,0x736b,0x736e,0x7370,0x7371,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON
+  },
+  {				/* ku 2b */
+    0x7372,0x7373,0x7374,0x7375,0x7376,0x7377,0x7378,0x7379,0x737a,0x737b,
+    0x737c,0x737d,0x737f,0x7380,0x7381,0x7382,0x7383,0x7385,0x7386,0x7388,
+    0x738a,0x738c,0x738d,0x738f,0x7390,0x7392,0x7393,0x7394,0x7395,0x7397,
+    0x7398,0x7399,0x739a,0x739c,0x739d,0x739e,0x73a0,0x73a1,0x73a3,0x73a4,
+    0x73a5,0x73a6,0x73a7,0x73a8,0x73aa,0x73ac,0x73ad,0x73b1,0x73b4,0x73b5,
+    0x73b6,0x73b8,0x73b9,0x73bc,0x73bd,0x73be,0x73bf,0x73c1,0x73c3,0x73c4,
+    0x73c5,0x73c6,0x73c7,UBOGON,0x73cb,0x73cc,0x73ce,0x73d2,0x73d3,0x73d4,
+    0x73d5,0x73d6,0x73d7,0x73d8,0x73da,0x73db,0x73dc,0x73dd,0x73df,0x73e1,
+    0x73e2,0x73e3,0x73e4,0x73e6,0x73e8,0x73ea,0x73eb,0x73ec,0x73ee,0x73ef,
+    0x73f0,0x73f1,0x73f3,0x73f4,0x73f5,0x73f6,0x73f7,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON
+  },
+  {				/* ku 2c */
+    0x73f8,0x73f9,0x73fa,0x73fb,0x73fc,0x73fd,0x73fe,0x73ff,0x7400,0x7401,
+    0x7402,0x7404,0x7407,0x7408,0x740b,0x740c,0x740d,0x740e,0x7411,0x7412,
+    0x7413,0x7414,0x7415,0x7416,0x7417,0x7418,0x7419,0x741c,0x741d,0x741e,
+    0x741f,0x7420,0x7421,0x7423,0x7424,0x7427,0x7429,0x742b,0x742d,0x742f,
+    0x7431,0x7432,0x7437,0x7438,0x7439,0x743a,0x743b,0x743d,0x743e,0x743f,
+    0x7440,0x7442,0x7443,0x7444,0x7445,0x7446,0x7447,0x7448,0x7449,0x744a,
+    0x744b,0x744c,0x744d,UBOGON,0x744e,0x744f,0x7450,0x7451,0x7452,0x7453,
+    0x7454,0x7456,0x7458,0x745d,0x7460,0x7461,0x7462,0x7463,0x7464,0x7465,
+    0x7466,0x7467,0x7468,0x7469,0x746a,0x746b,0x746c,0x746e,0x746f,0x7471,
+    0x7472,0x7473,0x7474,0x7475,0x7478,0x7479,0x747a,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON
+  },
+  {				/* ku 2d */
+    0x747b,0x747c,0x747d,0x747f,0x7482,0x7484,0x7485,0x7486,0x7488,0x7489,
+    0x748a,0x748c,0x748d,0x748f,0x7491,0x7492,0x7493,0x7494,0x7495,0x7496,
+    0x7497,0x7498,0x7499,0x749a,0x749b,0x749d,0x749f,0x74a0,0x74a1,0x74a2,
+    0x74a3,0x74a4,0x74a5,0x74a6,0x74aa,0x74ab,0x74ac,0x74ad,0x74ae,0x74af,
+    0x74b0,0x74b1,0x74b2,0x74b3,0x74b4,0x74b5,0x74b6,0x74b7,0x74b8,0x74b9,
+    0x74bb,0x74bc,0x74bd,0x74be,0x74bf,0x74c0,0x74c1,0x74c2,0x74c3,0x74c4,
+    0x74c5,0x74c6,0x74c7,UBOGON,0x74c8,0x74c9,0x74ca,0x74cb,0x74cc,0x74cd,
+    0x74ce,0x74cf,0x74d0,0x74d1,0x74d3,0x74d4,0x74d5,0x74d6,0x74d7,0x74d8,
+    0x74d9,0x74da,0x74db,0x74dd,0x74df,0x74e1,0x74e5,0x74e7,0x74e8,0x74e9,
+    0x74ea,0x74eb,0x74ec,0x74ed,0x74f0,0x74f1,0x74f2,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON
+  },
+  {				/* ku 2e */
+    0x74f3,0x74f5,0x74f8,0x74f9,0x74fa,0x74fb,0x74fc,0x74fd,0x74fe,0x7500,
+    0x7501,0x7502,0x7503,0x7505,0x7506,0x7507,0x7508,0x7509,0x750a,0x750b,
+    0x750c,0x750e,0x7510,0x7512,0x7514,0x7515,0x7516,0x7517,0x751b,0x751d,
+    0x751e,0x7520,0x7521,0x7522,0x7523,0x7524,0x7526,0x7527,0x752a,0x752e,
+    0x7534,0x7536,0x7539,0x753c,0x753d,0x753f,0x7541,0x7542,0x7543,0x7544,
+    0x7546,0x7547,0x7549,0x754a,0x754d,0x7550,0x7551,0x7552,0x7553,0x7555,
+    0x7556,0x7557,0x7558,UBOGON,0x755d,0x755e,0x755f,0x7560,0x7561,0x7562,
+    0x7563,0x7564,0x7567,0x7568,0x7569,0x756b,0x756c,0x756d,0x756e,0x756f,
+    0x7570,0x7571,0x7573,0x7575,0x7576,0x7577,0x757a,0x757b,0x757c,0x757d,
+    0x757e,0x7580,0x7581,0x7582,0x7584,0x7585,0x7587,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON
+  },
+  {				/* ku 2f */
+    0x7588,0x7589,0x758a,0x758c,0x758d,0x758e,0x7590,0x7593,0x7595,0x7598,
+    0x759b,0x759c,0x759e,0x75a2,0x75a6,0x75a7,0x75a8,0x75a9,0x75aa,0x75ad,
+    0x75b6,0x75b7,0x75ba,0x75bb,0x75bf,0x75c0,0x75c1,0x75c6,0x75cb,0x75cc,
+    0x75ce,0x75cf,0x75d0,0x75d1,0x75d3,0x75d7,0x75d9,0x75da,0x75dc,0x75dd,
+    0x75df,0x75e0,0x75e1,0x75e5,0x75e9,0x75ec,0x75ed,0x75ee,0x75ef,0x75f2,
+    0x75f3,0x75f5,0x75f6,0x75f7,0x75f8,0x75fa,0x75fb,0x75fd,0x75fe,0x7602,
+    0x7604,0x7606,0x7607,UBOGON,0x7608,0x7609,0x760b,0x760d,0x760e,0x760f,
+    0x7611,0x7612,0x7613,0x7614,0x7616,0x761a,0x761c,0x761d,0x761e,0x7621,
+    0x7623,0x7627,0x7628,0x762c,0x762e,0x762f,0x7631,0x7632,0x7636,0x7637,
+    0x7639,0x763a,0x763b,0x763d,0x7641,0x7642,0x7644,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON
+  },
+  {				/* ku 30 */
+    0x7645,0x7646,0x7647,0x7648,0x7649,0x764a,0x764b,0x764e,0x764f,0x7650,
+    0x7651,0x7652,0x7653,0x7655,0x7657,0x7658,0x7659,0x765a,0x765b,0x765d,
+    0x765f,0x7660,0x7661,0x7662,0x7664,0x7665,0x7666,0x7667,0x7668,0x7669,
+    0x766a,0x766c,0x766d,0x766e,0x7670,0x7671,0x7672,0x7673,0x7674,0x7675,
+    0x7676,0x7677,0x7679,0x767a,0x767c,0x767f,0x7680,0x7681,0x7683,0x7685,
+    0x7689,0x768a,0x768c,0x768d,0x768f,0x7690,0x7692,0x7694,0x7695,0x7697,
+    0x7698,0x769a,0x769b,UBOGON,0x769c,0x769d,0x769e,0x769f,0x76a0,0x76a1,
+    0x76a2,0x76a3,0x76a5,0x76a6,0x76a7,0x76a8,0x76a9,0x76aa,0x76ab,0x76ac,
+    0x76ad,0x76af,0x76b0,0x76b3,0x76b5,0x76b6,0x76b7,0x76b8,0x76b9,0x76ba,
+    0x76bb,0x76bc,0x76bd,0x76be,0x76c0,0x76c1,0x76c3,0x554a,0x963f,0x57c3,
+    0x6328,0x54ce,0x5509,0x54c0,0x7691,0x764c,0x853c,0x77ee,0x827e,0x788d,
+    0x7231,0x9698,0x978d,0x6c28,0x5b89,0x4ffa,0x6309,0x6697,0x5cb8,0x80fa,
+    0x6848,0x80ae,0x6602,0x76ce,0x51f9,0x6556,0x71ac,0x7ff1,0x8884,0x50b2,
+    0x5965,0x61ca,0x6fb3,0x82ad,0x634c,0x6252,0x53ed,0x5427,0x7b06,0x516b,
+    0x75a4,0x5df4,0x62d4,0x8dcb,0x9776,0x628a,0x8019,0x575d,0x9738,0x7f62,
+    0x7238,0x767d,0x67cf,0x767e,0x6446,0x4f70,0x8d25,0x62dc,0x7a17,0x6591,
+    0x73ed,0x642c,0x6273,0x822c,0x9881,0x677f,0x7248,0x626e,0x62cc,0x4f34,
+    0x74e3,0x534a,0x529e,0x7eca,0x90a6,0x5e2e,0x6886,0x699c,0x8180,0x7ed1,
+    0x68d2,0x78c5,0x868c,0x9551,0x508d,0x8c24,0x82de,0x80de,0x5305,0x8912,
+    0x5265
+  },
+  {				/* ku 31 */
+    0x76c4,0x76c7,0x76c9,0x76cb,0x76cc,0x76d3,0x76d5,0x76d9,0x76da,0x76dc,
+    0x76dd,0x76de,0x76e0,0x76e1,0x76e2,0x76e3,0x76e4,0x76e6,0x76e7,0x76e8,
+    0x76e9,0x76ea,0x76eb,0x76ec,0x76ed,0x76f0,0x76f3,0x76f5,0x76f6,0x76f7,
+    0x76fa,0x76fb,0x76fd,0x76ff,0x7700,0x7702,0x7703,0x7705,0x7706,0x770a,
+    0x770c,0x770e,0x770f,0x7710,0x7711,0x7712,0x7713,0x7714,0x7715,0x7716,
+    0x7717,0x7718,0x771b,0x771c,0x771d,0x771e,0x7721,0x7723,0x7724,0x7725,
+    0x7727,0x772a,0x772b,UBOGON,0x772c,0x772e,0x7730,0x7731,0x7732,0x7733,
+    0x7734,0x7739,0x773b,0x773d,0x773e,0x773f,0x7742,0x7744,0x7745,0x7746,
+    0x7748,0x7749,0x774a,0x774b,0x774c,0x774d,0x774e,0x774f,0x7752,0x7753,
+    0x7754,0x7755,0x7756,0x7757,0x7758,0x7759,0x775c,0x8584,0x96f9,0x4fdd,
+    0x5821,0x9971,0x5b9d,0x62b1,0x62a5,0x66b4,0x8c79,0x9c8d,0x7206,0x676f,
+    0x7891,0x60b2,0x5351,0x5317,0x8f88,0x80cc,0x8d1d,0x94a1,0x500d,0x72c8,
+    0x5907,0x60eb,0x7119,0x88ab,0x5954,0x82ef,0x672c,0x7b28,0x5d29,0x7ef7,
+    0x752d,0x6cf5,0x8e66,0x8ff8,0x903c,0x9f3b,0x6bd4,0x9119,0x7b14,0x5f7c,
+    0x78a7,0x84d6,0x853d,0x6bd5,0x6bd9,0x6bd6,0x5e01,0x5e87,0x75f9,0x95ed,
+    0x655d,0x5f0a,0x5fc5,0x8f9f,0x58c1,0x81c2,0x907f,0x965b,0x97ad,0x8fb9,
+    0x7f16,0x8d2c,0x6241,0x4fbf,0x53d8,0x535e,0x8fa8,0x8fa9,0x8fab,0x904d,
+    0x6807,0x5f6a,0x8198,0x8868,0x9cd6,0x618b,0x522b,0x762a,0x5f6c,0x658c,
+    0x6fd2,0x6ee8,0x5bbe,0x6448,0x5175,0x51b0,0x67c4,0x4e19,0x79c9,0x997c,
+    0x70b3
+  },
+  {				/* ku 32 */
+    0x775d,0x775e,0x775f,0x7760,0x7764,0x7767,0x7769,0x776a,0x776d,0x776e,
+    0x776f,0x7770,0x7771,0x7772,0x7773,0x7774,0x7775,0x7776,0x7777,0x7778,
+    0x777a,0x777b,0x777c,0x7781,0x7782,0x7783,0x7786,0x7787,0x7788,0x7789,
+    0x778a,0x778b,0x778f,0x7790,0x7793,0x7794,0x7795,0x7796,0x7797,0x7798,
+    0x7799,0x779a,0x779b,0x779c,0x779d,0x779e,0x77a1,0x77a3,0x77a4,0x77a6,
+    0x77a8,0x77ab,0x77ad,0x77ae,0x77af,0x77b1,0x77b2,0x77b4,0x77b6,0x77b7,
+    0x77b8,0x77b9,0x77ba,UBOGON,0x77bc,0x77be,0x77c0,0x77c1,0x77c2,0x77c3,
+    0x77c4,0x77c5,0x77c6,0x77c7,0x77c8,0x77c9,0x77ca,0x77cb,0x77cc,0x77ce,
+    0x77cf,0x77d0,0x77d1,0x77d2,0x77d3,0x77d4,0x77d5,0x77d6,0x77d8,0x77d9,
+    0x77da,0x77dd,0x77de,0x77df,0x77e0,0x77e1,0x77e4,0x75c5,0x5e76,0x73bb,
+    0x83e0,0x64ad,0x62e8,0x94b5,0x6ce2,0x535a,0x52c3,0x640f,0x94c2,0x7b94,
+    0x4f2f,0x5e1b,0x8236,0x8116,0x818a,0x6e24,0x6cca,0x9a73,0x6355,0x535c,
+    0x54fa,0x8865,0x57e0,0x4e0d,0x5e03,0x6b65,0x7c3f,0x90e8,0x6016,0x64e6,
+    0x731c,0x88c1,0x6750,0x624d,0x8d22,0x776c,0x8e29,0x91c7,0x5f69,0x83dc,
+    0x8521,0x9910,0x53c2,0x8695,0x6b8b,0x60ed,0x60e8,0x707f,0x82cd,0x8231,
+    0x4ed3,0x6ca7,0x85cf,0x64cd,0x7cd9,0x69fd,0x66f9,0x8349,0x5395,0x7b56,
+    0x4fa7,0x518c,0x6d4b,0x5c42,0x8e6d,0x63d2,0x53c9,0x832c,0x8336,0x67e5,
+    0x78b4,0x643d,0x5bdf,0x5c94,0x5dee,0x8be7,0x62c6,0x67f4,0x8c7a,0x6400,
+    0x63ba,0x8749,0x998b,0x8c17,0x7f20,0x94f2,0x4ea7,0x9610,0x98a4,0x660c,
+    0x7316
+  },
+  {				/* ku 33 */
+    0x77e6,0x77e8,0x77ea,0x77ef,0x77f0,0x77f1,0x77f2,0x77f4,0x77f5,0x77f7,
+    0x77f9,0x77fa,0x77fb,0x77fc,0x7803,0x7804,0x7805,0x7806,0x7807,0x7808,
+    0x780a,0x780b,0x780e,0x780f,0x7810,0x7813,0x7815,0x7819,0x781b,0x781e,
+    0x7820,0x7821,0x7822,0x7824,0x7828,0x782a,0x782b,0x782e,0x782f,0x7831,
+    0x7832,0x7833,0x7835,0x7836,0x783d,0x783f,0x7841,0x7842,0x7843,0x7844,
+    0x7846,0x7848,0x7849,0x784a,0x784b,0x784d,0x784f,0x7851,0x7853,0x7854,
+    0x7858,0x7859,0x785a,UBOGON,0x785b,0x785c,0x785e,0x785f,0x7860,0x7861,
+    0x7862,0x7863,0x7864,0x7865,0x7866,0x7867,0x7868,0x7869,0x786f,0x7870,
+    0x7871,0x7872,0x7873,0x7874,0x7875,0x7876,0x7878,0x7879,0x787a,0x787b,
+    0x787d,0x787e,0x787f,0x7880,0x7881,0x7882,0x7883,0x573a,0x5c1d,0x5e38,
+    0x957f,0x507f,0x80a0,0x5382,0x655e,0x7545,0x5531,0x5021,0x8d85,0x6284,
+    0x949e,0x671d,0x5632,0x6f6e,0x5de2,0x5435,0x7092,0x8f66,0x626f,0x64a4,
+    0x63a3,0x5f7b,0x6f88,0x90f4,0x81e3,0x8fb0,0x5c18,0x6668,0x5ff1,0x6c89,
+    0x9648,0x8d81,0x886c,0x6491,0x79f0,0x57ce,0x6a59,0x6210,0x5448,0x4e58,
+    0x7a0b,0x60e9,0x6f84,0x8bda,0x627f,0x901e,0x9a8b,0x79e4,0x5403,0x75f4,
+    0x6301,0x5319,0x6c60,0x8fdf,0x5f1b,0x9a70,0x803b,0x9f7f,0x4f88,0x5c3a,
+    0x8d64,0x7fc5,0x65a5,0x70bd,0x5145,0x51b2,0x866b,0x5d07,0x5ba0,0x62bd,
+    0x916c,0x7574,0x8e0c,0x7a20,0x6101,0x7b79,0x4ec7,0x7ef8,0x7785,0x4e11,
+    0x81ed,0x521d,0x51fa,0x6a71,0x53a8,0x8e87,0x9504,0x96cf,0x6ec1,0x9664,
+    0x695a
+  },
+  {				/* ku 34 */
+    0x7884,0x7885,0x7886,0x7888,0x788a,0x788b,0x788f,0x7890,0x7892,0x7894,
+    0x7895,0x7896,0x7899,0x789d,0x789e,0x78a0,0x78a2,0x78a4,0x78a6,0x78a8,
+    0x78a9,0x78aa,0x78ab,0x78ac,0x78ad,0x78ae,0x78af,0x78b5,0x78b6,0x78b7,
+    0x78b8,0x78ba,0x78bb,0x78bc,0x78bd,0x78bf,0x78c0,0x78c2,0x78c3,0x78c4,
+    0x78c6,0x78c7,0x78c8,0x78cc,0x78cd,0x78ce,0x78cf,0x78d1,0x78d2,0x78d3,
+    0x78d6,0x78d7,0x78d8,0x78da,0x78db,0x78dc,0x78dd,0x78de,0x78df,0x78e0,
+    0x78e1,0x78e2,0x78e3,UBOGON,0x78e4,0x78e5,0x78e6,0x78e7,0x78e9,0x78ea,
+    0x78eb,0x78ed,0x78ee,0x78ef,0x78f0,0x78f1,0x78f3,0x78f5,0x78f6,0x78f8,
+    0x78f9,0x78fb,0x78fc,0x78fd,0x78fe,0x78ff,0x7900,0x7902,0x7903,0x7904,
+    0x7906,0x7907,0x7908,0x7909,0x790a,0x790b,0x790c,0x7840,0x50a8,0x77d7,
+    0x6410,0x89e6,0x5904,0x63e3,0x5ddd,0x7a7f,0x693d,0x4f20,0x8239,0x5598,
+    0x4e32,0x75ae,0x7a97,0x5e62,0x5e8a,0x95ef,0x521b,0x5439,0x708a,0x6376,
+    0x9524,0x5782,0x6625,0x693f,0x9187,0x5507,0x6df3,0x7eaf,0x8822,0x6233,
+    0x7ef0,0x75b5,0x8328,0x78c1,0x96cc,0x8f9e,0x6148,0x74f7,0x8bcd,0x6b64,
+    0x523a,0x8d50,0x6b21,0x806a,0x8471,0x56f1,0x5306,0x4ece,0x4e1b,0x51d1,
+    0x7c97,0x918b,0x7c07,0x4fc3,0x8e7f,0x7be1,0x7a9c,0x6467,0x5d14,0x50ac,
+    0x8106,0x7601,0x7cb9,0x6dec,0x7fe0,0x6751,0x5b58,0x5bf8,0x78cb,0x64ae,
+    0x6413,0x63aa,0x632b,0x9519,0x642d,0x8fbe,0x7b54,0x7629,0x6253,0x5927,
+    0x5446,0x6b79,0x50a3,0x6234,0x5e26,0x6b86,0x4ee3,0x8d37,0x888b,0x5f85,
+    0x902e
+  },
+  {				/* ku 35 */
+    0x790d,0x790e,0x790f,0x7910,0x7911,0x7912,0x7914,0x7915,0x7916,0x7917,
+    0x7918,0x7919,0x791a,0x791b,0x791c,0x791d,0x791f,0x7920,0x7921,0x7922,
+    0x7923,0x7925,0x7926,0x7927,0x7928,0x7929,0x792a,0x792b,0x792c,0x792d,
+    0x792e,0x792f,0x7930,0x7931,0x7932,0x7933,0x7935,0x7936,0x7937,0x7938,
+    0x7939,0x793d,0x793f,0x7942,0x7943,0x7944,0x7945,0x7947,0x794a,0x794b,
+    0x794c,0x794d,0x794e,0x794f,0x7950,0x7951,0x7952,0x7954,0x7955,0x7958,
+    0x7959,0x7961,0x7963,UBOGON,0x7964,0x7966,0x7969,0x796a,0x796b,0x796c,
+    0x796e,0x7970,0x7971,0x7972,0x7973,0x7974,0x7975,0x7976,0x7979,0x797b,
+    0x797c,0x797d,0x797e,0x797f,0x7982,0x7983,0x7986,0x7987,0x7988,0x7989,
+    0x798b,0x798c,0x798d,0x798e,0x7990,0x7991,0x7992,0x6020,0x803d,0x62c5,
+    0x4e39,0x5355,0x90f8,0x63b8,0x80c6,0x65e6,0x6c2e,0x4f46,0x60ee,0x6de1,
+    0x8bde,0x5f39,0x86cb,0x5f53,0x6321,0x515a,0x8361,0x6863,0x5200,0x6363,
+    0x8e48,0x5012,0x5c9b,0x7977,0x5bfc,0x5230,0x7a3b,0x60bc,0x9053,0x76d7,
+    0x5fb7,0x5f97,0x7684,0x8e6c,0x706f,0x767b,0x7b49,0x77aa,0x51f3,0x9093,
+    0x5824,0x4f4e,0x6ef4,0x8fea,0x654c,0x7b1b,0x72c4,0x6da4,0x7fdf,0x5ae1,
+    0x62b5,0x5e95,0x5730,0x8482,0x7b2c,0x5e1d,0x5f1f,0x9012,0x7f14,0x98a0,
+    0x6382,0x6ec7,0x7898,0x70b9,0x5178,0x975b,0x57ab,0x7535,0x4f43,0x7538,
+    0x5e97,0x60e6,0x5960,0x6dc0,0x6bbf,0x7889,0x53fc,0x96d5,0x51cb,0x5201,
+    0x6389,0x540a,0x9493,0x8c03,0x8dcc,0x7239,0x789f,0x8776,0x8fed,0x8c0d,
+    0x53e0
+  },
+  {				/* ku 36 */
+    0x7993,0x7994,0x7995,0x7996,0x7997,0x7998,0x7999,0x799b,0x799c,0x799d,
+    0x799e,0x799f,0x79a0,0x79a1,0x79a2,0x79a3,0x79a4,0x79a5,0x79a6,0x79a8,
+    0x79a9,0x79aa,0x79ab,0x79ac,0x79ad,0x79ae,0x79af,0x79b0,0x79b1,0x79b2,
+    0x79b4,0x79b5,0x79b6,0x79b7,0x79b8,0x79bc,0x79bf,0x79c2,0x79c4,0x79c5,
+    0x79c7,0x79c8,0x79ca,0x79cc,0x79ce,0x79cf,0x79d0,0x79d3,0x79d4,0x79d6,
+    0x79d7,0x79d9,0x79da,0x79db,0x79dc,0x79dd,0x79de,0x79e0,0x79e1,0x79e2,
+    0x79e5,0x79e8,0x79ea,UBOGON,0x79ec,0x79ee,0x79f1,0x79f2,0x79f3,0x79f4,
+    0x79f5,0x79f6,0x79f7,0x79f9,0x79fa,0x79fc,0x79fe,0x79ff,0x7a01,0x7a04,
+    0x7a05,0x7a07,0x7a08,0x7a09,0x7a0a,0x7a0c,0x7a0f,0x7a10,0x7a11,0x7a12,
+    0x7a13,0x7a15,0x7a16,0x7a18,0x7a19,0x7a1b,0x7a1c,0x4e01,0x76ef,0x53ee,
+    0x9489,0x9876,0x9f0e,0x952d,0x5b9a,0x8ba2,0x4e22,0x4e1c,0x51ac,0x8463,
+    0x61c2,0x52a8,0x680b,0x4f97,0x606b,0x51bb,0x6d1e,0x515c,0x6296,0x6597,
+    0x9661,0x8c46,0x9017,0x75d8,0x90fd,0x7763,0x6bd2,0x728a,0x72ec,0x8bfb,
+    0x5835,0x7779,0x8d4c,0x675c,0x9540,0x809a,0x5ea6,0x6e21,0x5992,0x7aef,
+    0x77ed,0x953b,0x6bb5,0x65ad,0x7f0e,0x5806,0x5151,0x961f,0x5bf9,0x58a9,
+    0x5428,0x8e72,0x6566,0x987f,0x56e4,0x949d,0x76fe,0x9041,0x6387,0x54c6,
+    0x591a,0x593a,0x579b,0x8eb2,0x6735,0x8dfa,0x8235,0x5241,0x60f0,0x5815,
+    0x86fe,0x5ce8,0x9e45,0x4fc4,0x989d,0x8bb9,0x5a25,0x6076,0x5384,0x627c,
+    0x904f,0x9102,0x997f,0x6069,0x800c,0x513f,0x8033,0x5c14,0x9975,0x6d31,
+    0x4e8c
+  },
+  {				/* ku 37 */
+    0x7a1d,0x7a1f,0x7a21,0x7a22,0x7a24,0x7a25,0x7a26,0x7a27,0x7a28,0x7a29,
+    0x7a2a,0x7a2b,0x7a2c,0x7a2d,0x7a2e,0x7a2f,0x7a30,0x7a31,0x7a32,0x7a34,
+    0x7a35,0x7a36,0x7a38,0x7a3a,0x7a3e,0x7a40,0x7a41,0x7a42,0x7a43,0x7a44,
+    0x7a45,0x7a47,0x7a48,0x7a49,0x7a4a,0x7a4b,0x7a4c,0x7a4d,0x7a4e,0x7a4f,
+    0x7a50,0x7a52,0x7a53,0x7a54,0x7a55,0x7a56,0x7a58,0x7a59,0x7a5a,0x7a5b,
+    0x7a5c,0x7a5d,0x7a5e,0x7a5f,0x7a60,0x7a61,0x7a62,0x7a63,0x7a64,0x7a65,
+    0x7a66,0x7a67,0x7a68,UBOGON,0x7a69,0x7a6a,0x7a6b,0x7a6c,0x7a6d,0x7a6e,
+    0x7a6f,0x7a71,0x7a72,0x7a73,0x7a75,0x7a7b,0x7a7c,0x7a7d,0x7a7e,0x7a82,
+    0x7a85,0x7a87,0x7a89,0x7a8a,0x7a8b,0x7a8c,0x7a8e,0x7a8f,0x7a90,0x7a93,
+    0x7a94,0x7a99,0x7a9a,0x7a9b,0x7a9e,0x7aa1,0x7aa2,0x8d30,0x53d1,0x7f5a,
+    0x7b4f,0x4f10,0x4e4f,0x9600,0x6cd5,0x73d0,0x85e9,0x5e06,0x756a,0x7ffb,
+    0x6a0a,0x77fe,0x9492,0x7e41,0x51e1,0x70e6,0x53cd,0x8fd4,0x8303,0x8d29,
+    0x72af,0x996d,0x6cdb,0x574a,0x82b3,0x65b9,0x80aa,0x623f,0x9632,0x59a8,
+    0x4eff,0x8bbf,0x7eba,0x653e,0x83f2,0x975e,0x5561,0x98de,0x80a5,0x532a,
+    0x8bfd,0x5420,0x80ba,0x5e9f,0x6cb8,0x8d39,0x82ac,0x915a,0x5429,0x6c1b,
+    0x5206,0x7eb7,0x575f,0x711a,0x6c7e,0x7c89,0x594b,0x4efd,0x5fff,0x6124,
+    0x7caa,0x4e30,0x5c01,0x67ab,0x8702,0x5cf0,0x950b,0x98ce,0x75af,0x70fd,
+    0x9022,0x51af,0x7f1d,0x8bbd,0x5949,0x51e4,0x4f5b,0x5426,0x592b,0x6577,
+    0x80a4,0x5b75,0x6276,0x62c2,0x8f90,0x5e45,0x6c1f,0x7b26,0x4f0f,0x4fd8,
+    0x670d
+  },
+  {				/* ku 38 */
+    0x7aa3,0x7aa4,0x7aa7,0x7aa9,0x7aaa,0x7aab,0x7aae,0x7aaf,0x7ab0,0x7ab1,
+    0x7ab2,0x7ab4,0x7ab5,0x7ab6,0x7ab7,0x7ab8,0x7ab9,0x7aba,0x7abb,0x7abc,
+    0x7abd,0x7abe,0x7ac0,0x7ac1,0x7ac2,0x7ac3,0x7ac4,0x7ac5,0x7ac6,0x7ac7,
+    0x7ac8,0x7ac9,0x7aca,0x7acc,0x7acd,0x7ace,0x7acf,0x7ad0,0x7ad1,0x7ad2,
+    0x7ad3,0x7ad4,0x7ad5,0x7ad7,0x7ad8,0x7ada,0x7adb,0x7adc,0x7add,0x7ae1,
+    0x7ae2,0x7ae4,0x7ae7,0x7ae8,0x7ae9,0x7aea,0x7aeb,0x7aec,0x7aee,0x7af0,
+    0x7af1,0x7af2,0x7af3,UBOGON,0x7af4,0x7af5,0x7af6,0x7af7,0x7af8,0x7afb,
+    0x7afc,0x7afe,0x7b00,0x7b01,0x7b02,0x7b05,0x7b07,0x7b09,0x7b0c,0x7b0d,
+    0x7b0e,0x7b10,0x7b12,0x7b13,0x7b16,0x7b17,0x7b18,0x7b1a,0x7b1c,0x7b1d,
+    0x7b1f,0x7b21,0x7b22,0x7b23,0x7b27,0x7b29,0x7b2d,0x6d6e,0x6daa,0x798f,
+    0x88b1,0x5f17,0x752b,0x629a,0x8f85,0x4fef,0x91dc,0x65a7,0x812f,0x8151,
+    0x5e9c,0x8150,0x8d74,0x526f,0x8986,0x8d4b,0x590d,0x5085,0x4ed8,0x961c,
+    0x7236,0x8179,0x8d1f,0x5bcc,0x8ba3,0x9644,0x5987,0x7f1a,0x5490,0x5676,
+    0x560e,0x8be5,0x6539,0x6982,0x9499,0x76d6,0x6e89,0x5e72,0x7518,0x6746,
+    0x67d1,0x7aff,0x809d,0x8d76,0x611f,0x79c6,0x6562,0x8d63,0x5188,0x521a,
+    0x94a2,0x7f38,0x809b,0x7eb2,0x5c97,0x6e2f,0x6760,0x7bd9,0x768b,0x9ad8,
+    0x818f,0x7f94,0x7cd5,0x641e,0x9550,0x7a3f,0x544a,0x54e5,0x6b4c,0x6401,
+    0x6208,0x9e3d,0x80f3,0x7599,0x5272,0x9769,0x845b,0x683c,0x86e4,0x9601,
+    0x9694,0x94ec,0x4e2a,0x5404,0x7ed9,0x6839,0x8ddf,0x8015,0x66f4,0x5e9a,
+    0x7fb9
+  },
+  {				/* ku 39 */
+    0x7b2f,0x7b30,0x7b32,0x7b34,0x7b35,0x7b36,0x7b37,0x7b39,0x7b3b,0x7b3d,
+    0x7b3f,0x7b40,0x7b41,0x7b42,0x7b43,0x7b44,0x7b46,0x7b48,0x7b4a,0x7b4d,
+    0x7b4e,0x7b53,0x7b55,0x7b57,0x7b59,0x7b5c,0x7b5e,0x7b5f,0x7b61,0x7b63,
+    0x7b64,0x7b65,0x7b66,0x7b67,0x7b68,0x7b69,0x7b6a,0x7b6b,0x7b6c,0x7b6d,
+    0x7b6f,0x7b70,0x7b73,0x7b74,0x7b76,0x7b78,0x7b7a,0x7b7c,0x7b7d,0x7b7f,
+    0x7b81,0x7b82,0x7b83,0x7b84,0x7b86,0x7b87,0x7b88,0x7b89,0x7b8a,0x7b8b,
+    0x7b8c,0x7b8e,0x7b8f,UBOGON,0x7b91,0x7b92,0x7b93,0x7b96,0x7b98,0x7b99,
+    0x7b9a,0x7b9b,0x7b9e,0x7b9f,0x7ba0,0x7ba3,0x7ba4,0x7ba5,0x7bae,0x7baf,
+    0x7bb0,0x7bb2,0x7bb3,0x7bb5,0x7bb6,0x7bb7,0x7bb9,0x7bba,0x7bbb,0x7bbc,
+    0x7bbd,0x7bbe,0x7bbf,0x7bc0,0x7bc2,0x7bc3,0x7bc4,0x57c2,0x803f,0x6897,
+    0x5de5,0x653b,0x529f,0x606d,0x9f9a,0x4f9b,0x8eac,0x516c,0x5bab,0x5f13,
+    0x5de9,0x6c5e,0x62f1,0x8d21,0x5171,0x94a9,0x52fe,0x6c9f,0x82df,0x72d7,
+    0x57a2,0x6784,0x8d2d,0x591f,0x8f9c,0x83c7,0x5495,0x7b8d,0x4f30,0x6cbd,
+    0x5b64,0x59d1,0x9f13,0x53e4,0x86ca,0x9aa8,0x8c37,0x80a1,0x6545,0x987e,
+    0x56fa,0x96c7,0x522e,0x74dc,0x5250,0x5be1,0x6302,0x8902,0x4e56,0x62d0,
+    0x602a,0x68fa,0x5173,0x5b98,0x51a0,0x89c2,0x7ba1,0x9986,0x7f50,0x60ef,
+    0x704c,0x8d2f,0x5149,0x5e7f,0x901b,0x7470,0x89c4,0x572d,0x7845,0x5f52,
+    0x9f9f,0x95fa,0x8f68,0x9b3c,0x8be1,0x7678,0x6842,0x67dc,0x8dea,0x8d35,
+    0x523d,0x8f8a,0x6eda,0x68cd,0x9505,0x90ed,0x56fd,0x679c,0x88f9,0x8fc7,
+    0x54c8
+  },
+  {				/* ku 3a */
+    0x7bc5,0x7bc8,0x7bc9,0x7bca,0x7bcb,0x7bcd,0x7bce,0x7bcf,0x7bd0,0x7bd2,
+    0x7bd4,0x7bd5,0x7bd6,0x7bd7,0x7bd8,0x7bdb,0x7bdc,0x7bde,0x7bdf,0x7be0,
+    0x7be2,0x7be3,0x7be4,0x7be7,0x7be8,0x7be9,0x7beb,0x7bec,0x7bed,0x7bef,
+    0x7bf0,0x7bf2,0x7bf3,0x7bf4,0x7bf5,0x7bf6,0x7bf8,0x7bf9,0x7bfa,0x7bfb,
+    0x7bfd,0x7bff,0x7c00,0x7c01,0x7c02,0x7c03,0x7c04,0x7c05,0x7c06,0x7c08,
+    0x7c09,0x7c0a,0x7c0d,0x7c0e,0x7c10,0x7c11,0x7c12,0x7c13,0x7c14,0x7c15,
+    0x7c17,0x7c18,0x7c19,UBOGON,0x7c1a,0x7c1b,0x7c1c,0x7c1d,0x7c1e,0x7c20,
+    0x7c21,0x7c22,0x7c23,0x7c24,0x7c25,0x7c28,0x7c29,0x7c2b,0x7c2c,0x7c2d,
+    0x7c2e,0x7c2f,0x7c30,0x7c31,0x7c32,0x7c33,0x7c34,0x7c35,0x7c36,0x7c37,
+    0x7c39,0x7c3a,0x7c3b,0x7c3c,0x7c3d,0x7c3e,0x7c42,0x9ab8,0x5b69,0x6d77,
+    0x6c26,0x4ea5,0x5bb3,0x9a87,0x9163,0x61a8,0x90af,0x97e9,0x542b,0x6db5,
+    0x5bd2,0x51fd,0x558a,0x7f55,0x7ff0,0x64bc,0x634d,0x65f1,0x61be,0x608d,
+    0x710a,0x6c57,0x6c49,0x592f,0x676d,0x822a,0x58d5,0x568e,0x8c6a,0x6beb,
+    0x90dd,0x597d,0x8017,0x53f7,0x6d69,0x5475,0x559d,0x8377,0x83cf,0x6838,
+    0x79be,0x548c,0x4f55,0x5408,0x76d2,0x8c89,0x9602,0x6cb3,0x6db8,0x8d6b,
+    0x8910,0x9e64,0x8d3a,0x563f,0x9ed1,0x75d5,0x5f88,0x72e0,0x6068,0x54fc,
+    0x4ea8,0x6a2a,0x8861,0x6052,0x8f70,0x54c4,0x70d8,0x8679,0x9e3f,0x6d2a,
+    0x5b8f,0x5f18,0x7ea2,0x5589,0x4faf,0x7334,0x543c,0x539a,0x5019,0x540e,
+    0x547c,0x4e4e,0x5ffd,0x745a,0x58f6,0x846b,0x80e1,0x8774,0x72d0,0x7cca,
+    0x6e56
+  },
+  {				/* ku 3b */
+    0x7c43,0x7c44,0x7c45,0x7c46,0x7c47,0x7c48,0x7c49,0x7c4a,0x7c4b,0x7c4c,
+    0x7c4e,0x7c4f,0x7c50,0x7c51,0x7c52,0x7c53,0x7c54,0x7c55,0x7c56,0x7c57,
+    0x7c58,0x7c59,0x7c5a,0x7c5b,0x7c5c,0x7c5d,0x7c5e,0x7c5f,0x7c60,0x7c61,
+    0x7c62,0x7c63,0x7c64,0x7c65,0x7c66,0x7c67,0x7c68,0x7c69,0x7c6a,0x7c6b,
+    0x7c6c,0x7c6d,0x7c6e,0x7c6f,0x7c70,0x7c71,0x7c72,0x7c75,0x7c76,0x7c77,
+    0x7c78,0x7c79,0x7c7a,0x7c7e,0x7c7f,0x7c80,0x7c81,0x7c82,0x7c83,0x7c84,
+    0x7c85,0x7c86,0x7c87,UBOGON,0x7c88,0x7c8a,0x7c8b,0x7c8c,0x7c8d,0x7c8e,
+    0x7c8f,0x7c90,0x7c93,0x7c94,0x7c96,0x7c99,0x7c9a,0x7c9b,0x7ca0,0x7ca1,
+    0x7ca3,0x7ca6,0x7ca7,0x7ca8,0x7ca9,0x7cab,0x7cac,0x7cad,0x7caf,0x7cb0,
+    0x7cb4,0x7cb5,0x7cb6,0x7cb7,0x7cb8,0x7cba,0x7cbb,0x5f27,0x864e,0x552c,
+    0x62a4,0x4e92,0x6caa,0x6237,0x82b1,0x54d7,0x534e,0x733e,0x6ed1,0x753b,
+    0x5212,0x5316,0x8bdd,0x69d0,0x5f8a,0x6000,0x6dee,0x574f,0x6b22,0x73af,
+    0x6853,0x8fd8,0x7f13,0x6362,0x60a3,0x5524,0x75ea,0x8c62,0x7115,0x6da3,
+    0x5ba6,0x5e7b,0x8352,0x614c,0x9ec4,0x78fa,0x8757,0x7c27,0x7687,0x51f0,
+    0x60f6,0x714c,0x6643,0x5e4c,0x604d,0x8c0e,0x7070,0x6325,0x8f89,0x5fbd,
+    0x6062,0x86d4,0x56de,0x6bc1,0x6094,0x6167,0x5349,0x60e0,0x6666,0x8d3f,
+    0x79fd,0x4f1a,0x70e9,0x6c47,0x8bb3,0x8bf2,0x7ed8,0x8364,0x660f,0x5a5a,
+    0x9b42,0x6d51,0x6df7,0x8c41,0x6d3b,0x4f19,0x706b,0x83b7,0x6216,0x60d1,
+    0x970d,0x8d27,0x7978,0x51fb,0x573e,0x57fa,0x673a,0x7578,0x7a3d,0x79ef,
+    0x7b95
+  },
+  {				/* ku 3c */
+    0x7cbf,0x7cc0,0x7cc2,0x7cc3,0x7cc4,0x7cc6,0x7cc9,0x7ccb,0x7cce,0x7ccf,
+    0x7cd0,0x7cd1,0x7cd2,0x7cd3,0x7cd4,0x7cd8,0x7cda,0x7cdb,0x7cdd,0x7cde,
+    0x7ce1,0x7ce2,0x7ce3,0x7ce4,0x7ce5,0x7ce6,0x7ce7,0x7ce9,0x7cea,0x7ceb,
+    0x7cec,0x7ced,0x7cee,0x7cf0,0x7cf1,0x7cf2,0x7cf3,0x7cf4,0x7cf5,0x7cf6,
+    0x7cf7,0x7cf9,0x7cfa,0x7cfc,0x7cfd,0x7cfe,0x7cff,0x7d00,0x7d01,0x7d02,
+    0x7d03,0x7d04,0x7d05,0x7d06,0x7d07,0x7d08,0x7d09,0x7d0b,0x7d0c,0x7d0d,
+    0x7d0e,0x7d0f,0x7d10,UBOGON,0x7d11,0x7d12,0x7d13,0x7d14,0x7d15,0x7d16,
+    0x7d17,0x7d18,0x7d19,0x7d1a,0x7d1b,0x7d1c,0x7d1d,0x7d1e,0x7d1f,0x7d21,
+    0x7d23,0x7d24,0x7d25,0x7d26,0x7d28,0x7d29,0x7d2a,0x7d2c,0x7d2d,0x7d2e,
+    0x7d30,0x7d31,0x7d32,0x7d33,0x7d34,0x7d35,0x7d36,0x808c,0x9965,0x8ff9,
+    0x6fc0,0x8ba5,0x9e21,0x59ec,0x7ee9,0x7f09,0x5409,0x6781,0x68d8,0x8f91,
+    0x7c4d,0x96c6,0x53ca,0x6025,0x75be,0x6c72,0x5373,0x5ac9,0x7ea7,0x6324,
+    0x51e0,0x810a,0x5df1,0x84df,0x6280,0x5180,0x5b63,0x4f0e,0x796d,0x5242,
+    0x60b8,0x6d4e,0x5bc4,0x5bc2,0x8ba1,0x8bb0,0x65e2,0x5fcc,0x9645,0x5993,
+    0x7ee7,0x7eaa,0x5609,0x67b7,0x5939,0x4f73,0x5bb6,0x52a0,0x835a,0x988a,
+    0x8d3e,0x7532,0x94be,0x5047,0x7a3c,0x4ef7,0x67b6,0x9a7e,0x5ac1,0x6b7c,
+    0x76d1,0x575a,0x5c16,0x7b3a,0x95f4,0x714e,0x517c,0x80a9,0x8270,0x5978,
+    0x7f04,0x8327,0x68c0,0x67ec,0x78b1,0x7877,0x62e3,0x6361,0x7b80,0x4fed,
+    0x526a,0x51cf,0x8350,0x69db,0x9274,0x8df5,0x8d31,0x89c1,0x952e,0x7bad,
+    0x4ef6
+  },
+  {				/* ku 3d */
+    0x7d37,0x7d38,0x7d39,0x7d3a,0x7d3b,0x7d3c,0x7d3d,0x7d3e,0x7d3f,0x7d40,
+    0x7d41,0x7d42,0x7d43,0x7d44,0x7d45,0x7d46,0x7d47,0x7d48,0x7d49,0x7d4a,
+    0x7d4b,0x7d4c,0x7d4d,0x7d4e,0x7d4f,0x7d50,0x7d51,0x7d52,0x7d53,0x7d54,
+    0x7d55,0x7d56,0x7d57,0x7d58,0x7d59,0x7d5a,0x7d5b,0x7d5c,0x7d5d,0x7d5e,
+    0x7d5f,0x7d60,0x7d61,0x7d62,0x7d63,0x7d64,0x7d65,0x7d66,0x7d67,0x7d68,
+    0x7d69,0x7d6a,0x7d6b,0x7d6c,0x7d6d,0x7d6f,0x7d70,0x7d71,0x7d72,0x7d73,
+    0x7d74,0x7d75,0x7d76,UBOGON,0x7d78,0x7d79,0x7d7a,0x7d7b,0x7d7c,0x7d7d,
+    0x7d7e,0x7d7f,0x7d80,0x7d81,0x7d82,0x7d83,0x7d84,0x7d85,0x7d86,0x7d87,
+    0x7d88,0x7d89,0x7d8a,0x7d8b,0x7d8c,0x7d8d,0x7d8e,0x7d8f,0x7d90,0x7d91,
+    0x7d92,0x7d93,0x7d94,0x7d95,0x7d96,0x7d97,0x7d98,0x5065,0x8230,0x5251,
+    0x996f,0x6e10,0x6e85,0x6da7,0x5efa,0x50f5,0x59dc,0x5c06,0x6d46,0x6c5f,
+    0x7586,0x848b,0x6868,0x5956,0x8bb2,0x5320,0x9171,0x964d,0x8549,0x6912,
+    0x7901,0x7126,0x80f6,0x4ea4,0x90ca,0x6d47,0x9a84,0x5a07,0x56bc,0x6405,
+    0x94f0,0x77eb,0x4fa5,0x811a,0x72e1,0x89d2,0x997a,0x7f34,0x7ede,0x527f,
+    0x6559,0x9175,0x8f7f,0x8f83,0x53eb,0x7a96,0x63ed,0x63a5,0x7686,0x79f8,
+    0x8857,0x9636,0x622a,0x52ab,0x8282,0x6854,0x6770,0x6377,0x776b,0x7aed,
+    0x6d01,0x7ed3,0x89e3,0x59d0,0x6212,0x85c9,0x82a5,0x754c,0x501f,0x4ecb,
+    0x75a5,0x8beb,0x5c4a,0x5dfe,0x7b4b,0x65a4,0x91d1,0x4eca,0x6d25,0x895f,
+    0x7d27,0x9526,0x4ec5,0x8c28,0x8fdb,0x9773,0x664b,0x7981,0x8fd1,0x70ec,
+    0x6d78
+  },
+  {				/* ku 3e */
+    0x7d99,0x7d9a,0x7d9b,0x7d9c,0x7d9d,0x7d9e,0x7d9f,0x7da0,0x7da1,0x7da2,
+    0x7da3,0x7da4,0x7da5,0x7da7,0x7da8,0x7da9,0x7daa,0x7dab,0x7dac,0x7dad,
+    0x7daf,0x7db0,0x7db1,0x7db2,0x7db3,0x7db4,0x7db5,0x7db6,0x7db7,0x7db8,
+    0x7db9,0x7dba,0x7dbb,0x7dbc,0x7dbd,0x7dbe,0x7dbf,0x7dc0,0x7dc1,0x7dc2,
+    0x7dc3,0x7dc4,0x7dc5,0x7dc6,0x7dc7,0x7dc8,0x7dc9,0x7dca,0x7dcb,0x7dcc,
+    0x7dcd,0x7dce,0x7dcf,0x7dd0,0x7dd1,0x7dd2,0x7dd3,0x7dd4,0x7dd5,0x7dd6,
+    0x7dd7,0x7dd8,0x7dd9,UBOGON,0x7dda,0x7ddb,0x7ddc,0x7ddd,0x7dde,0x7ddf,
+    0x7de0,0x7de1,0x7de2,0x7de3,0x7de4,0x7de5,0x7de6,0x7de7,0x7de8,0x7de9,
+    0x7dea,0x7deb,0x7dec,0x7ded,0x7dee,0x7def,0x7df0,0x7df1,0x7df2,0x7df3,
+    0x7df4,0x7df5,0x7df6,0x7df7,0x7df8,0x7df9,0x7dfa,0x5c3d,0x52b2,0x8346,
+    0x5162,0x830e,0x775b,0x6676,0x9cb8,0x4eac,0x60ca,0x7cbe,0x7cb3,0x7ecf,
+    0x4e95,0x8b66,0x666f,0x9888,0x9759,0x5883,0x656c,0x955c,0x5f84,0x75c9,
+    0x9756,0x7adf,0x7ade,0x51c0,0x70af,0x7a98,0x63ea,0x7a76,0x7ea0,0x7396,
+    0x97ed,0x4e45,0x7078,0x4e5d,0x9152,0x53a9,0x6551,0x65e7,0x81fc,0x8205,
+    0x548e,0x5c31,0x759a,0x97a0,0x62d8,0x72d9,0x75bd,0x5c45,0x9a79,0x83ca,
+    0x5c40,0x5480,0x77e9,0x4e3e,0x6cae,0x805a,0x62d2,0x636e,0x5de8,0x5177,
+    0x8ddd,0x8e1e,0x952f,0x4ff1,0x53e5,0x60e7,0x70ac,0x5267,0x6350,0x9e43,
+    0x5a1f,0x5026,0x7737,0x5377,0x7ee2,0x6485,0x652b,0x6289,0x6398,0x5014,
+    0x7235,0x89c9,0x51b3,0x8bc0,0x7edd,0x5747,0x83cc,0x94a7,0x519b,0x541b,
+    0x5cfb
+  },
+  {				/* ku 3f */
+    0x7dfb,0x7dfc,0x7dfd,0x7dfe,0x7dff,0x7e00,0x7e01,0x7e02,0x7e03,0x7e04,
+    0x7e05,0x7e06,0x7e07,0x7e08,0x7e09,0x7e0a,0x7e0b,0x7e0c,0x7e0d,0x7e0e,
+    0x7e0f,0x7e10,0x7e11,0x7e12,0x7e13,0x7e14,0x7e15,0x7e16,0x7e17,0x7e18,
+    0x7e19,0x7e1a,0x7e1b,0x7e1c,0x7e1d,0x7e1e,0x7e1f,0x7e20,0x7e21,0x7e22,
+    0x7e23,0x7e24,0x7e25,0x7e26,0x7e27,0x7e28,0x7e29,0x7e2a,0x7e2b,0x7e2c,
+    0x7e2d,0x7e2e,0x7e2f,0x7e30,0x7e31,0x7e32,0x7e33,0x7e34,0x7e35,0x7e36,
+    0x7e37,0x7e38,0x7e39,UBOGON,0x7e3a,0x7e3c,0x7e3d,0x7e3e,0x7e3f,0x7e40,
+    0x7e42,0x7e43,0x7e44,0x7e45,0x7e46,0x7e48,0x7e49,0x7e4a,0x7e4b,0x7e4c,
+    0x7e4d,0x7e4e,0x7e4f,0x7e50,0x7e51,0x7e52,0x7e53,0x7e54,0x7e55,0x7e56,
+    0x7e57,0x7e58,0x7e59,0x7e5a,0x7e5b,0x7e5c,0x7e5d,0x4fca,0x7ae3,0x6d5a,
+    0x90e1,0x9a8f,0x5580,0x5496,0x5361,0x54af,0x5f00,0x63e9,0x6977,0x51ef,
+    0x6168,0x520a,0x582a,0x52d8,0x574e,0x780d,0x770b,0x5eb7,0x6177,0x7ce0,
+    0x625b,0x6297,0x4ea2,0x7095,0x8003,0x62f7,0x70e4,0x9760,0x5777,0x82db,
+    0x67ef,0x68f5,0x78d5,0x9897,0x79d1,0x58f3,0x54b3,0x53ef,0x6e34,0x514b,
+    0x523b,0x5ba2,0x8bfe,0x80af,0x5543,0x57a6,0x6073,0x5751,0x542d,0x7a7a,
+    0x6050,0x5b54,0x63a7,0x62a0,0x53e3,0x6263,0x5bc7,0x67af,0x54ed,0x7a9f,
+    0x82e6,0x9177,0x5e93,0x88e4,0x5938,0x57ae,0x630e,0x8de8,0x80ef,0x5757,
+    0x7b77,0x4fa9,0x5feb,0x5bbd,0x6b3e,0x5321,0x7b50,0x72c2,0x6846,0x77ff,
+    0x7736,0x65f7,0x51b5,0x4e8f,0x76d4,0x5cbf,0x7aa5,0x8475,0x594e,0x9b41,
+    0x5080
+  },
+  {				/* ku 40 */
+    0x7e5e,0x7e5f,0x7e60,0x7e61,0x7e62,0x7e63,0x7e64,0x7e65,0x7e66,0x7e67,
+    0x7e68,0x7e69,0x7e6a,0x7e6b,0x7e6c,0x7e6d,0x7e6e,0x7e6f,0x7e70,0x7e71,
+    0x7e72,0x7e73,0x7e74,0x7e75,0x7e76,0x7e77,0x7e78,0x7e79,0x7e7a,0x7e7b,
+    0x7e7c,0x7e7d,0x7e7e,0x7e7f,0x7e80,0x7e81,0x7e83,0x7e84,0x7e85,0x7e86,
+    0x7e87,0x7e88,0x7e89,0x7e8a,0x7e8b,0x7e8c,0x7e8d,0x7e8e,0x7e8f,0x7e90,
+    0x7e91,0x7e92,0x7e93,0x7e94,0x7e95,0x7e96,0x7e97,0x7e98,0x7e99,0x7e9a,
+    0x7e9c,0x7e9d,0x7e9e,UBOGON,0x7eae,0x7eb4,0x7ebb,0x7ebc,0x7ed6,0x7ee4,
+    0x7eec,0x7ef9,0x7f0a,0x7f10,0x7f1e,0x7f37,0x7f39,0x7f3b,0x7f3c,0x7f3d,
+    0x7f3e,0x7f3f,0x7f40,0x7f41,0x7f43,0x7f46,0x7f47,0x7f48,0x7f49,0x7f4a,
+    0x7f4b,0x7f4c,0x7f4d,0x7f4e,0x7f4f,0x7f52,0x7f53,0x9988,0x6127,0x6e83,
+    0x5764,0x6606,0x6346,0x56f0,0x62ec,0x6269,0x5ed3,0x9614,0x5783,0x62c9,
+    0x5587,0x8721,0x814a,0x8fa3,0x5566,0x83b1,0x6765,0x8d56,0x84dd,0x5a6a,
+    0x680f,0x62e6,0x7bee,0x9611,0x5170,0x6f9c,0x8c30,0x63fd,0x89c8,0x61d2,
+    0x7f06,0x70c2,0x6ee5,0x7405,0x6994,0x72fc,0x5eca,0x90ce,0x6717,0x6d6a,
+    0x635e,0x52b3,0x7262,0x8001,0x4f6c,0x59e5,0x916a,0x70d9,0x6d9d,0x52d2,
+    0x4e50,0x96f7,0x956d,0x857e,0x78ca,0x7d2f,0x5121,0x5792,0x64c2,0x808b,
+    0x7c7b,0x6cea,0x68f1,0x695e,0x51b7,0x5398,0x68a8,0x7281,0x9ece,0x7bf1,
+    0x72f8,0x79bb,0x6f13,0x7406,0x674e,0x91cc,0x9ca4,0x793c,0x8389,0x8354,
+    0x540f,0x6817,0x4e3d,0x5389,0x52b1,0x783e,0x5386,0x5229,0x5088,0x4f8b,
+    0x4fd0
+  },
+  {				/* ku 41 */
+    0x7f56,0x7f59,0x7f5b,0x7f5c,0x7f5d,0x7f5e,0x7f60,0x7f63,0x7f64,0x7f65,
+    0x7f66,0x7f67,0x7f6b,0x7f6c,0x7f6d,0x7f6f,0x7f70,0x7f73,0x7f75,0x7f76,
+    0x7f77,0x7f78,0x7f7a,0x7f7b,0x7f7c,0x7f7d,0x7f7f,0x7f80,0x7f82,0x7f83,
+    0x7f84,0x7f85,0x7f86,0x7f87,0x7f88,0x7f89,0x7f8b,0x7f8d,0x7f8f,0x7f90,
+    0x7f91,0x7f92,0x7f93,0x7f95,0x7f96,0x7f97,0x7f98,0x7f99,0x7f9b,0x7f9c,
+    0x7fa0,0x7fa2,0x7fa3,0x7fa5,0x7fa6,0x7fa8,0x7fa9,0x7faa,0x7fab,0x7fac,
+    0x7fad,0x7fae,0x7fb1,UBOGON,0x7fb3,0x7fb4,0x7fb5,0x7fb6,0x7fb7,0x7fba,
+    0x7fbb,0x7fbe,0x7fc0,0x7fc2,0x7fc3,0x7fc4,0x7fc6,0x7fc7,0x7fc8,0x7fc9,
+    0x7fcb,0x7fcd,0x7fcf,0x7fd0,0x7fd1,0x7fd2,0x7fd3,0x7fd6,0x7fd7,0x7fd9,
+    0x7fda,0x7fdb,0x7fdc,0x7fdd,0x7fde,0x7fe2,0x7fe3,0x75e2,0x7acb,0x7c92,
+    0x6ca5,0x96b6,0x529b,0x7483,0x54e9,0x4fe9,0x8054,0x83b2,0x8fde,0x9570,
+    0x5ec9,0x601c,0x6d9f,0x5e18,0x655b,0x8138,0x94fe,0x604b,0x70bc,0x7ec3,
+    0x7cae,0x51c9,0x6881,0x7cb1,0x826f,0x4e24,0x8f86,0x91cf,0x667e,0x4eae,
+    0x8c05,0x64a9,0x804a,0x50da,0x7597,0x71ce,0x5be5,0x8fbd,0x6f66,0x4e86,
+    0x6482,0x9563,0x5ed6,0x6599,0x5217,0x88c2,0x70c8,0x52a3,0x730e,0x7433,
+    0x6797,0x78f7,0x9716,0x4e34,0x90bb,0x9cde,0x6dcb,0x51db,0x8d41,0x541d,
+    0x62ce,0x73b2,0x83f1,0x96f6,0x9f84,0x94c3,0x4f36,0x7f9a,0x51cc,0x7075,
+    0x9675,0x5cad,0x9886,0x53e6,0x4ee4,0x6e9c,0x7409,0x69b4,0x786b,0x998f,
+    0x7559,0x5218,0x7624,0x6d41,0x67f3,0x516d,0x9f99,0x804b,0x5499,0x7b3c,
+    0x7abf
+  },
+  {				/* ku 42 */
+    0x7fe4,0x7fe7,0x7fe8,0x7fea,0x7feb,0x7fec,0x7fed,0x7fef,0x7ff2,0x7ff4,
+    0x7ff5,0x7ff6,0x7ff7,0x7ff8,0x7ff9,0x7ffa,0x7ffd,0x7ffe,0x7fff,0x8002,
+    0x8007,0x8008,0x8009,0x800a,0x800e,0x800f,0x8011,0x8013,0x801a,0x801b,
+    0x801d,0x801e,0x801f,0x8021,0x8023,0x8024,0x802b,0x802c,0x802d,0x802e,
+    0x802f,0x8030,0x8032,0x8034,0x8039,0x803a,0x803c,0x803e,0x8040,0x8041,
+    0x8044,0x8045,0x8047,0x8048,0x8049,0x804e,0x804f,0x8050,0x8051,0x8053,
+    0x8055,0x8056,0x8057,UBOGON,0x8059,0x805b,0x805c,0x805d,0x805e,0x805f,
+    0x8060,0x8061,0x8062,0x8063,0x8064,0x8065,0x8066,0x8067,0x8068,0x806b,
+    0x806c,0x806d,0x806e,0x806f,0x8070,0x8072,0x8073,0x8074,0x8075,0x8076,
+    0x8077,0x8078,0x8079,0x807a,0x807b,0x807c,0x807d,0x9686,0x5784,0x62e2,
+    0x9647,0x697c,0x5a04,0x6402,0x7bd3,0x6f0f,0x964b,0x82a6,0x5362,0x9885,
+    0x5e90,0x7089,0x63b3,0x5364,0x864f,0x9c81,0x9e93,0x788c,0x9732,0x8def,
+    0x8d42,0x9e7f,0x6f5e,0x7984,0x5f55,0x9646,0x622e,0x9a74,0x5415,0x94dd,
+    0x4fa3,0x65c5,0x5c65,0x5c61,0x7f15,0x8651,0x6c2f,0x5f8b,0x7387,0x6ee4,
+    0x7eff,0x5ce6,0x631b,0x5b6a,0x6ee6,0x5375,0x4e71,0x63a0,0x7565,0x62a1,
+    0x8f6e,0x4f26,0x4ed1,0x6ca6,0x7eb6,0x8bba,0x841d,0x87ba,0x7f57,0x903b,
+    0x9523,0x7ba9,0x9aa1,0x88f8,0x843d,0x6d1b,0x9a86,0x7edc,0x5988,0x9ebb,
+    0x739b,0x7801,0x8682,0x9a6c,0x9a82,0x561b,0x5417,0x57cb,0x4e70,0x9ea6,
+    0x5356,0x8fc8,0x8109,0x7792,0x9992,0x86ee,0x6ee1,0x8513,0x66fc,0x6162,
+    0x6f2b
+  },
+  {				/* ku 43 */
+    0x807e,0x8081,0x8082,0x8085,0x8088,0x808a,0x808d,0x808e,0x808f,0x8090,
+    0x8091,0x8092,0x8094,0x8095,0x8097,0x8099,0x809e,0x80a3,0x80a6,0x80a7,
+    0x80a8,0x80ac,0x80b0,0x80b3,0x80b5,0x80b6,0x80b8,0x80b9,0x80bb,0x80c5,
+    0x80c7,0x80c8,0x80c9,0x80ca,0x80cb,0x80cf,0x80d0,0x80d1,0x80d2,0x80d3,
+    0x80d4,0x80d5,0x80d8,0x80df,0x80e0,0x80e2,0x80e3,0x80e6,0x80ee,0x80f5,
+    0x80f7,0x80f9,0x80fb,0x80fe,0x80ff,0x8100,0x8101,0x8103,0x8104,0x8105,
+    0x8107,0x8108,0x810b,UBOGON,0x810c,0x8115,0x8117,0x8119,0x811b,0x811c,
+    0x811d,0x811f,0x8120,0x8121,0x8122,0x8123,0x8124,0x8125,0x8126,0x8127,
+    0x8128,0x8129,0x812a,0x812b,0x812d,0x812e,0x8130,0x8133,0x8134,0x8135,
+    0x8137,0x8139,0x813a,0x813b,0x813c,0x813d,0x813f,0x8c29,0x8292,0x832b,
+    0x76f2,0x6c13,0x5fd9,0x83bd,0x732b,0x8305,0x951a,0x6bdb,0x77db,0x94c6,
+    0x536f,0x8302,0x5192,0x5e3d,0x8c8c,0x8d38,0x4e48,0x73ab,0x679a,0x6885,
+    0x9176,0x9709,0x7164,0x6ca1,0x7709,0x5a92,0x9541,0x6bcf,0x7f8e,0x6627,
+    0x5bd0,0x59b9,0x5a9a,0x95e8,0x95f7,0x4eec,0x840c,0x8499,0x6aac,0x76df,
+    0x9530,0x731b,0x68a6,0x5b5f,0x772f,0x919a,0x9761,0x7cdc,0x8ff7,0x8c1c,
+    0x5f25,0x7c73,0x79d8,0x89c5,0x6ccc,0x871c,0x5bc6,0x5e42,0x68c9,0x7720,
+    0x7ef5,0x5195,0x514d,0x52c9,0x5a29,0x7f05,0x9762,0x82d7,0x63cf,0x7784,
+    0x85d0,0x79d2,0x6e3a,0x5e99,0x5999,0x8511,0x706d,0x6c11,0x62bf,0x76bf,
+    0x654f,0x60af,0x95fd,0x660e,0x879f,0x9e23,0x94ed,0x540d,0x547d,0x8c2c,
+    0x6478
+  },
+  {				/* ku 44 */
+    0x8140,0x8141,0x8142,0x8143,0x8144,0x8145,0x8147,0x8149,0x814d,0x814e,
+    0x814f,0x8152,0x8156,0x8157,0x8158,0x815b,0x815c,0x815d,0x815e,0x815f,
+    0x8161,0x8162,0x8163,0x8164,0x8166,0x8168,0x816a,0x816b,0x816c,0x816f,
+    0x8172,0x8173,0x8175,0x8176,0x8177,0x8178,0x8181,0x8183,0x8184,0x8185,
+    0x8186,0x8187,0x8189,0x818b,0x818c,0x818d,0x818e,0x8190,0x8192,0x8193,
+    0x8194,0x8195,0x8196,0x8197,0x8199,0x819a,0x819e,0x819f,0x81a0,0x81a1,
+    0x81a2,0x81a4,0x81a5,UBOGON,0x81a7,0x81a9,0x81ab,0x81ac,0x81ad,0x81ae,
+    0x81af,0x81b0,0x81b1,0x81b2,0x81b4,0x81b5,0x81b6,0x81b7,0x81b8,0x81b9,
+    0x81bc,0x81bd,0x81be,0x81bf,0x81c4,0x81c5,0x81c7,0x81c8,0x81c9,0x81cb,
+    0x81cd,0x81ce,0x81cf,0x81d0,0x81d1,0x81d2,0x81d3,0x6479,0x8611,0x6a21,
+    0x819c,0x78e8,0x6469,0x9b54,0x62b9,0x672b,0x83ab,0x58a8,0x9ed8,0x6cab,
+    0x6f20,0x5bde,0x964c,0x8c0b,0x725f,0x67d0,0x62c7,0x7261,0x4ea9,0x59c6,
+    0x6bcd,0x5893,0x66ae,0x5e55,0x52df,0x6155,0x6728,0x76ee,0x7766,0x7267,
+    0x7a46,0x62ff,0x54ea,0x5450,0x94a0,0x90a3,0x5a1c,0x7eb3,0x6c16,0x4e43,
+    0x5976,0x8010,0x5948,0x5357,0x7537,0x96be,0x56ca,0x6320,0x8111,0x607c,
+    0x95f9,0x6dd6,0x5462,0x9981,0x5185,0x5ae9,0x80fd,0x59ae,0x9713,0x502a,
+    0x6ce5,0x5c3c,0x62df,0x4f60,0x533f,0x817b,0x9006,0x6eba,0x852b,0x62c8,
+    0x5e74,0x78be,0x64b5,0x637b,0x5ff5,0x5a18,0x917f,0x9e1f,0x5c3f,0x634f,
+    0x8042,0x5b7d,0x556e,0x954a,0x954d,0x6d85,0x60a8,0x67e0,0x72de,0x51dd,
+    0x5b81
+  },
+  {				/* ku 45 */
+    0x81d4,0x81d5,0x81d6,0x81d7,0x81d8,0x81d9,0x81da,0x81db,0x81dc,0x81dd,
+    0x81de,0x81df,0x81e0,0x81e1,0x81e2,0x81e4,0x81e5,0x81e6,0x81e8,0x81e9,
+    0x81eb,0x81ee,0x81ef,0x81f0,0x81f1,0x81f2,0x81f5,0x81f6,0x81f7,0x81f8,
+    0x81f9,0x81fa,0x81fd,0x81ff,0x8203,0x8207,0x8208,0x8209,0x820a,0x820b,
+    0x820e,0x820f,0x8211,0x8213,0x8215,0x8216,0x8217,0x8218,0x8219,0x821a,
+    0x821d,0x8220,0x8224,0x8225,0x8226,0x8227,0x8229,0x822e,0x8232,0x823a,
+    0x823c,0x823d,0x823f,UBOGON,0x8240,0x8241,0x8242,0x8243,0x8245,0x8246,
+    0x8248,0x824a,0x824c,0x824d,0x824e,0x8250,0x8251,0x8252,0x8253,0x8254,
+    0x8255,0x8256,0x8257,0x8259,0x825b,0x825c,0x825d,0x825e,0x8260,0x8261,
+    0x8262,0x8263,0x8264,0x8265,0x8266,0x8267,0x8269,0x62e7,0x6cde,0x725b,
+    0x626d,0x94ae,0x7ebd,0x8113,0x6d53,0x519c,0x5f04,0x5974,0x52aa,0x6012,
+    0x5973,0x6696,0x8650,0x759f,0x632a,0x61e6,0x7cef,0x8bfa,0x54e6,0x6b27,
+    0x9e25,0x6bb4,0x85d5,0x5455,0x5076,0x6ca4,0x556a,0x8db4,0x722c,0x5e15,
+    0x6015,0x7436,0x62cd,0x6392,0x724c,0x5f98,0x6e43,0x6d3e,0x6500,0x6f58,
+    0x76d8,0x78d0,0x76fc,0x7554,0x5224,0x53db,0x4e53,0x5e9e,0x65c1,0x802a,
+    0x80d6,0x629b,0x5486,0x5228,0x70ae,0x888d,0x8dd1,0x6ce1,0x5478,0x80da,
+    0x57f9,0x88f4,0x8d54,0x966a,0x914d,0x4f69,0x6c9b,0x55b7,0x76c6,0x7830,
+    0x62a8,0x70f9,0x6f8e,0x5f6d,0x84ec,0x68da,0x787c,0x7bf7,0x81a8,0x670b,
+    0x9e4f,0x6367,0x78b0,0x576f,0x7812,0x9739,0x6279,0x62ab,0x5288,0x7435,
+    0x6bd7
+  },
+  {				/* ku 46 */
+    0x826a,0x826b,0x826c,0x826d,0x8271,0x8275,0x8276,0x8277,0x8278,0x827b,
+    0x827c,0x8280,0x8281,0x8283,0x8285,0x8286,0x8287,0x8289,0x828c,0x8290,
+    0x8293,0x8294,0x8295,0x8296,0x829a,0x829b,0x829e,0x82a0,0x82a2,0x82a3,
+    0x82a7,0x82b2,0x82b5,0x82b6,0x82ba,0x82bb,0x82bc,0x82bf,0x82c0,0x82c2,
+    0x82c3,0x82c5,0x82c6,0x82c9,0x82d0,0x82d6,0x82d9,0x82da,0x82dd,0x82e2,
+    0x82e7,0x82e8,0x82e9,0x82ea,0x82ec,0x82ed,0x82ee,0x82f0,0x82f2,0x82f3,
+    0x82f5,0x82f6,0x82f8,UBOGON,0x82fa,0x82fc,0x82fd,0x82fe,0x82ff,0x8300,
+    0x830a,0x830b,0x830d,0x8310,0x8312,0x8313,0x8316,0x8318,0x8319,0x831d,
+    0x831e,0x831f,0x8320,0x8321,0x8322,0x8323,0x8324,0x8325,0x8326,0x8329,
+    0x832a,0x832e,0x8330,0x8332,0x8337,0x833b,0x833d,0x5564,0x813e,0x75b2,
+    0x76ae,0x5339,0x75de,0x50fb,0x5c41,0x8b6c,0x7bc7,0x504f,0x7247,0x9a97,
+    0x98d8,0x6f02,0x74e2,0x7968,0x6487,0x77a5,0x62fc,0x9891,0x8d2b,0x54c1,
+    0x8058,0x4e52,0x576a,0x82f9,0x840d,0x5e73,0x51ed,0x74f6,0x8bc4,0x5c4f,
+    0x5761,0x6cfc,0x9887,0x5a46,0x7834,0x9b44,0x8feb,0x7c95,0x5256,0x6251,
+    0x94fa,0x4ec6,0x8386,0x8461,0x83e9,0x84b2,0x57d4,0x6734,0x5703,0x666e,
+    0x6d66,0x8c31,0x66dd,0x7011,0x671f,0x6b3a,0x6816,0x621a,0x59bb,0x4e03,
+    0x51c4,0x6f06,0x67d2,0x6c8f,0x5176,0x68cb,0x5947,0x6b67,0x7566,0x5d0e,
+    0x8110,0x9f50,0x65d7,0x7948,0x7941,0x9a91,0x8d77,0x5c82,0x4e5e,0x4f01,
+    0x542f,0x5951,0x780c,0x5668,0x6c14,0x8fc4,0x5f03,0x6c7d,0x6ce3,0x8bab,
+    0x6390
+  },
+  {				/* ku 47 */
+    0x833e,0x833f,0x8341,0x8342,0x8344,0x8345,0x8348,0x834a,0x834b,0x834c,
+    0x834d,0x834e,0x8353,0x8355,0x8356,0x8357,0x8358,0x8359,0x835d,0x8362,
+    0x8370,0x8371,0x8372,0x8373,0x8374,0x8375,0x8376,0x8379,0x837a,0x837e,
+    0x837f,0x8380,0x8381,0x8382,0x8383,0x8384,0x8387,0x8388,0x838a,0x838b,
+    0x838c,0x838d,0x838f,0x8390,0x8391,0x8394,0x8395,0x8396,0x8397,0x8399,
+    0x839a,0x839d,0x839f,0x83a1,0x83a2,0x83a3,0x83a4,0x83a5,0x83a6,0x83a7,
+    0x83ac,0x83ad,0x83ae,UBOGON,0x83af,0x83b5,0x83bb,0x83be,0x83bf,0x83c2,
+    0x83c3,0x83c4,0x83c6,0x83c8,0x83c9,0x83cb,0x83cd,0x83ce,0x83d0,0x83d1,
+    0x83d2,0x83d3,0x83d5,0x83d7,0x83d9,0x83da,0x83db,0x83de,0x83e2,0x83e3,
+    0x83e4,0x83e6,0x83e7,0x83e8,0x83eb,0x83ec,0x83ed,0x6070,0x6d3d,0x7275,
+    0x6266,0x948e,0x94c5,0x5343,0x8fc1,0x7b7e,0x4edf,0x8c26,0x4e7e,0x9ed4,
+    0x94b1,0x94b3,0x524d,0x6f5c,0x9063,0x6d45,0x8c34,0x5811,0x5d4c,0x6b20,
+    0x6b49,0x67aa,0x545b,0x8154,0x7f8c,0x5899,0x8537,0x5f3a,0x62a2,0x6a47,
+    0x9539,0x6572,0x6084,0x6865,0x77a7,0x4e54,0x4fa8,0x5de7,0x9798,0x64ac,
+    0x7fd8,0x5ced,0x4fcf,0x7a8d,0x5207,0x8304,0x4e14,0x602f,0x7a83,0x94a6,
+    0x4fb5,0x4eb2,0x79e6,0x7434,0x52e4,0x82b9,0x64d2,0x79bd,0x5bdd,0x6c81,
+    0x9752,0x8f7b,0x6c22,0x503e,0x537f,0x6e05,0x64ce,0x6674,0x6c30,0x60c5,
+    0x9877,0x8bf7,0x5e86,0x743c,0x7a77,0x79cb,0x4e18,0x90b1,0x7403,0x6c42,
+    0x56da,0x914b,0x6cc5,0x8d8b,0x533a,0x86c6,0x66f2,0x8eaf,0x5c48,0x9a71,
+    0x6e20
+  },
+  {				/* ku 48 */
+    0x83ee,0x83ef,0x83f3,0x83f4,0x83f5,0x83f6,0x83f7,0x83fa,0x83fb,0x83fc,
+    0x83fe,0x83ff,0x8400,0x8402,0x8405,0x8407,0x8408,0x8409,0x840a,0x8410,
+    0x8412,0x8413,0x8414,0x8415,0x8416,0x8417,0x8419,0x841a,0x841b,0x841e,
+    0x841f,0x8420,0x8421,0x8422,0x8423,0x8429,0x842a,0x842b,0x842c,0x842d,
+    0x842e,0x842f,0x8430,0x8432,0x8433,0x8434,0x8435,0x8436,0x8437,0x8439,
+    0x843a,0x843b,0x843e,0x843f,0x8440,0x8441,0x8442,0x8443,0x8444,0x8445,
+    0x8447,0x8448,0x8449,UBOGON,0x844a,0x844b,0x844c,0x844d,0x844e,0x844f,
+    0x8450,0x8452,0x8453,0x8454,0x8455,0x8456,0x8458,0x845d,0x845e,0x845f,
+    0x8460,0x8462,0x8464,0x8465,0x8466,0x8467,0x8468,0x846a,0x846e,0x846f,
+    0x8470,0x8472,0x8474,0x8477,0x8479,0x847b,0x847c,0x53d6,0x5a36,0x9f8b,
+    0x8da3,0x53bb,0x5708,0x98a7,0x6743,0x919b,0x6cc9,0x5168,0x75ca,0x62f3,
+    0x72ac,0x5238,0x529d,0x7f3a,0x7094,0x7638,0x5374,0x9e4a,0x69b7,0x786e,
+    0x96c0,0x88d9,0x7fa4,0x7136,0x71c3,0x5189,0x67d3,0x74e4,0x58e4,0x6518,
+    0x56b7,0x8ba9,0x9976,0x6270,0x7ed5,0x60f9,0x70ed,0x58ec,0x4ec1,0x4eba,
+    0x5fcd,0x97e7,0x4efb,0x8ba4,0x5203,0x598a,0x7eab,0x6254,0x4ecd,0x65e5,
+    0x620e,0x8338,0x84c9,0x8363,0x878d,0x7194,0x6eb6,0x5bb9,0x7ed2,0x5197,
+    0x63c9,0x67d4,0x8089,0x8339,0x8815,0x5112,0x5b7a,0x5982,0x8fb1,0x4e73,
+    0x6c5d,0x5165,0x8925,0x8f6f,0x962e,0x854a,0x745e,0x9510,0x95f0,0x6da6,
+    0x82e5,0x5f31,0x6492,0x6d12,0x8428,0x816e,0x9cc3,0x585e,0x8d5b,0x4e09,
+    0x53c1
+  },
+  {				/* ku 49 */
+    0x847d,0x847e,0x847f,0x8480,0x8481,0x8483,0x8484,0x8485,0x8486,0x848a,
+    0x848d,0x848f,0x8490,0x8491,0x8492,0x8493,0x8494,0x8495,0x8496,0x8498,
+    0x849a,0x849b,0x849d,0x849e,0x849f,0x84a0,0x84a2,0x84a3,0x84a4,0x84a5,
+    0x84a6,0x84a7,0x84a8,0x84a9,0x84aa,0x84ab,0x84ac,0x84ad,0x84ae,0x84b0,
+    0x84b1,0x84b3,0x84b5,0x84b6,0x84b7,0x84bb,0x84bc,0x84be,0x84c0,0x84c2,
+    0x84c3,0x84c5,0x84c6,0x84c7,0x84c8,0x84cb,0x84cc,0x84ce,0x84cf,0x84d2,
+    0x84d4,0x84d5,0x84d7,UBOGON,0x84d8,0x84d9,0x84da,0x84db,0x84dc,0x84de,
+    0x84e1,0x84e2,0x84e4,0x84e7,0x84e8,0x84e9,0x84ea,0x84eb,0x84ed,0x84ee,
+    0x84ef,0x84f1,0x84f2,0x84f3,0x84f4,0x84f5,0x84f6,0x84f7,0x84f8,0x84f9,
+    0x84fa,0x84fb,0x84fd,0x84fe,0x8500,0x8501,0x8502,0x4f1e,0x6563,0x6851,
+    0x55d3,0x4e27,0x6414,0x9a9a,0x626b,0x5ac2,0x745f,0x8272,0x6da9,0x68ee,
+    0x50e7,0x838e,0x7802,0x6740,0x5239,0x6c99,0x7eb1,0x50bb,0x5565,0x715e,
+    0x7b5b,0x6652,0x73ca,0x82eb,0x6749,0x5c71,0x5220,0x717d,0x886b,0x95ea,
+    0x9655,0x64c5,0x8d61,0x81b3,0x5584,0x6c55,0x6247,0x7f2e,0x5892,0x4f24,
+    0x5546,0x8d4f,0x664c,0x4e0a,0x5c1a,0x88f3,0x68a2,0x634e,0x7a0d,0x70e7,
+    0x828d,0x52fa,0x97f6,0x5c11,0x54e8,0x90b5,0x7ecd,0x5962,0x8d4a,0x86c7,
+    0x820c,0x820d,0x8d66,0x6444,0x5c04,0x6151,0x6d89,0x793e,0x8bbe,0x7837,
+    0x7533,0x547b,0x4f38,0x8eab,0x6df1,0x5a20,0x7ec5,0x795e,0x6c88,0x5ba1,
+    0x5a76,0x751a,0x80be,0x614e,0x6e17,0x58f0,0x751f,0x7525,0x7272,0x5347,
+    0x7ef3
+  },
+  {				/* ku 4a */
+    0x8503,0x8504,0x8505,0x8506,0x8507,0x8508,0x8509,0x850a,0x850b,0x850d,
+    0x850e,0x850f,0x8510,0x8512,0x8514,0x8515,0x8516,0x8518,0x8519,0x851b,
+    0x851c,0x851d,0x851e,0x8520,0x8522,0x8523,0x8524,0x8525,0x8526,0x8527,
+    0x8528,0x8529,0x852a,0x852d,0x852e,0x852f,0x8530,0x8531,0x8532,0x8533,
+    0x8534,0x8535,0x8536,0x853e,0x853f,0x8540,0x8541,0x8542,0x8544,0x8545,
+    0x8546,0x8547,0x854b,0x854c,0x854d,0x854e,0x854f,0x8550,0x8551,0x8552,
+    0x8553,0x8554,0x8555,UBOGON,0x8557,0x8558,0x855a,0x855b,0x855c,0x855d,
+    0x855f,0x8560,0x8561,0x8562,0x8563,0x8565,0x8566,0x8567,0x8569,0x856a,
+    0x856b,0x856c,0x856d,0x856e,0x856f,0x8570,0x8571,0x8573,0x8575,0x8576,
+    0x8577,0x8578,0x857c,0x857d,0x857f,0x8580,0x8581,0x7701,0x76db,0x5269,
+    0x80dc,0x5723,0x5e08,0x5931,0x72ee,0x65bd,0x6e7f,0x8bd7,0x5c38,0x8671,
+    0x5341,0x77f3,0x62fe,0x65f6,0x4ec0,0x98df,0x8680,0x5b9e,0x8bc6,0x53f2,
+    0x77e2,0x4f7f,0x5c4e,0x9a76,0x59cb,0x5f0f,0x793a,0x58eb,0x4e16,0x67ff,
+    0x4e8b,0x62ed,0x8a93,0x901d,0x52bf,0x662f,0x55dc,0x566c,0x9002,0x4ed5,
+    0x4f8d,0x91ca,0x9970,0x6c0f,0x5e02,0x6043,0x5ba4,0x89c6,0x8bd5,0x6536,
+    0x624b,0x9996,0x5b88,0x5bff,0x6388,0x552e,0x53d7,0x7626,0x517d,0x852c,
+    0x67a2,0x68b3,0x6b8a,0x6292,0x8f93,0x53d4,0x8212,0x6dd1,0x758f,0x4e66,
+    0x8d4e,0x5b70,0x719f,0x85af,0x6691,0x66d9,0x7f72,0x8700,0x9ecd,0x9f20,
+    0x5c5e,0x672f,0x8ff0,0x6811,0x675f,0x620d,0x7ad6,0x5885,0x5eb6,0x6570,
+    0x6f31
+  },
+  {				/* ku 4b */
+    0x8582,0x8583,0x8586,0x8588,0x8589,0x858a,0x858b,0x858c,0x858d,0x858e,
+    0x8590,0x8591,0x8592,0x8593,0x8594,0x8595,0x8596,0x8597,0x8598,0x8599,
+    0x859a,0x859d,0x859e,0x859f,0x85a0,0x85a1,0x85a2,0x85a3,0x85a5,0x85a6,
+    0x85a7,0x85a9,0x85ab,0x85ac,0x85ad,0x85b1,0x85b2,0x85b3,0x85b4,0x85b5,
+    0x85b6,0x85b8,0x85ba,0x85bb,0x85bc,0x85bd,0x85be,0x85bf,0x85c0,0x85c2,
+    0x85c3,0x85c4,0x85c5,0x85c6,0x85c7,0x85c8,0x85ca,0x85cb,0x85cc,0x85cd,
+    0x85ce,0x85d1,0x85d2,UBOGON,0x85d4,0x85d6,0x85d7,0x85d8,0x85d9,0x85da,
+    0x85db,0x85dd,0x85de,0x85df,0x85e0,0x85e1,0x85e2,0x85e3,0x85e5,0x85e6,
+    0x85e7,0x85e8,0x85ea,0x85eb,0x85ec,0x85ed,0x85ee,0x85ef,0x85f0,0x85f1,
+    0x85f2,0x85f3,0x85f4,0x85f5,0x85f6,0x85f7,0x85f8,0x6055,0x5237,0x800d,
+    0x6454,0x8870,0x7529,0x5e05,0x6813,0x62f4,0x971c,0x53cc,0x723d,0x8c01,
+    0x6c34,0x7761,0x7a0e,0x542e,0x77ac,0x987a,0x821c,0x8bf4,0x7855,0x6714,
+    0x70c1,0x65af,0x6495,0x5636,0x601d,0x79c1,0x53f8,0x4e1d,0x6b7b,0x8086,
+    0x5bfa,0x55e3,0x56db,0x4f3a,0x4f3c,0x9972,0x5df3,0x677e,0x8038,0x6002,
+    0x9882,0x9001,0x5b8b,0x8bbc,0x8bf5,0x641c,0x8258,0x64de,0x55fd,0x82cf,
+    0x9165,0x4fd7,0x7d20,0x901f,0x7c9f,0x50f3,0x5851,0x6eaf,0x5bbf,0x8bc9,
+    0x8083,0x9178,0x849c,0x7b97,0x867d,0x968b,0x968f,0x7ee5,0x9ad3,0x788e,
+    0x5c81,0x7a57,0x9042,0x96a7,0x795f,0x5b59,0x635f,0x7b0b,0x84d1,0x68ad,
+    0x5506,0x7f29,0x7410,0x7d22,0x9501,0x6240,0x584c,0x4ed6,0x5b83,0x5979,
+    0x5854
+  },
+  {				/* ku 4c */
+    0x85f9,0x85fa,0x85fc,0x85fd,0x85fe,0x8600,0x8601,0x8602,0x8603,0x8604,
+    0x8606,0x8607,0x8608,0x8609,0x860a,0x860b,0x860c,0x860d,0x860e,0x860f,
+    0x8610,0x8612,0x8613,0x8614,0x8615,0x8617,0x8618,0x8619,0x861a,0x861b,
+    0x861c,0x861d,0x861e,0x861f,0x8620,0x8621,0x8622,0x8623,0x8624,0x8625,
+    0x8626,0x8628,0x862a,0x862b,0x862c,0x862d,0x862e,0x862f,0x8630,0x8631,
+    0x8632,0x8633,0x8634,0x8635,0x8636,0x8637,0x8639,0x863a,0x863b,0x863d,
+    0x863e,0x863f,0x8640,UBOGON,0x8641,0x8642,0x8643,0x8644,0x8645,0x8646,
+    0x8647,0x8648,0x8649,0x864a,0x864b,0x864c,0x8652,0x8653,0x8655,0x8656,
+    0x8657,0x8658,0x8659,0x865b,0x865c,0x865d,0x865f,0x8660,0x8661,0x8663,
+    0x8664,0x8665,0x8666,0x8667,0x8668,0x8669,0x866a,0x736d,0x631e,0x8e4b,
+    0x8e0f,0x80ce,0x82d4,0x62ac,0x53f0,0x6cf0,0x915e,0x592a,0x6001,0x6c70,
+    0x574d,0x644a,0x8d2a,0x762b,0x6ee9,0x575b,0x6a80,0x75f0,0x6f6d,0x8c2d,
+    0x8c08,0x5766,0x6bef,0x8892,0x78b3,0x63a2,0x53f9,0x70ad,0x6c64,0x5858,
+    0x642a,0x5802,0x68e0,0x819b,0x5510,0x7cd6,0x5018,0x8eba,0x6dcc,0x8d9f,
+    0x70eb,0x638f,0x6d9b,0x6ed4,0x7ee6,0x8404,0x6843,0x9003,0x6dd8,0x9676,
+    0x8ba8,0x5957,0x7279,0x85e4,0x817e,0x75bc,0x8a8a,0x68af,0x5254,0x8e22,
+    0x9511,0x63d0,0x9898,0x8e44,0x557c,0x4f53,0x66ff,0x568f,0x60d5,0x6d95,
+    0x5243,0x5c49,0x5929,0x6dfb,0x586b,0x7530,0x751c,0x606c,0x8214,0x8146,
+    0x6311,0x6761,0x8fe2,0x773a,0x8df3,0x8d34,0x94c1,0x5e16,0x5385,0x542c,
+    0x70c3
+  },
+  {				/* ku 4d */
+    0x866d,0x866f,0x8670,0x8672,0x8673,0x8674,0x8675,0x8676,0x8677,0x8678,
+    0x8683,0x8684,0x8685,0x8686,0x8687,0x8688,0x8689,0x868e,0x868f,0x8690,
+    0x8691,0x8692,0x8694,0x8696,0x8697,0x8698,0x8699,0x869a,0x869b,0x869e,
+    0x869f,0x86a0,0x86a1,0x86a2,0x86a5,0x86a6,0x86ab,0x86ad,0x86ae,0x86b2,
+    0x86b3,0x86b7,0x86b8,0x86b9,0x86bb,0x86bc,0x86bd,0x86be,0x86bf,0x86c1,
+    0x86c2,0x86c3,0x86c5,0x86c8,0x86cc,0x86cd,0x86d2,0x86d3,0x86d5,0x86d6,
+    0x86d7,0x86da,0x86dc,UBOGON,0x86dd,0x86e0,0x86e1,0x86e2,0x86e3,0x86e5,
+    0x86e6,0x86e7,0x86e8,0x86ea,0x86eb,0x86ec,0x86ef,0x86f5,0x86f6,0x86f7,
+    0x86fa,0x86fb,0x86fc,0x86fd,0x86ff,0x8701,0x8704,0x8705,0x8706,0x870b,
+    0x870c,0x870e,0x870f,0x8710,0x8711,0x8714,0x8716,0x6c40,0x5ef7,0x505c,
+    0x4ead,0x5ead,0x633a,0x8247,0x901a,0x6850,0x916e,0x77b3,0x540c,0x94dc,
+    0x5f64,0x7ae5,0x6876,0x6345,0x7b52,0x7edf,0x75db,0x5077,0x6295,0x5934,
+    0x900f,0x51f8,0x79c3,0x7a81,0x56fe,0x5f92,0x9014,0x6d82,0x5c60,0x571f,
+    0x5410,0x5154,0x6e4d,0x56e2,0x63a8,0x9893,0x817f,0x8715,0x892a,0x9000,
+    0x541e,0x5c6f,0x81c0,0x62d6,0x6258,0x8131,0x9e35,0x9640,0x9a6e,0x9a7c,
+    0x692d,0x59a5,0x62d3,0x553e,0x6316,0x54c7,0x86d9,0x6d3c,0x5a03,0x74e6,
+    0x889c,0x6b6a,0x5916,0x8c4c,0x5f2f,0x6e7e,0x73a9,0x987d,0x4e38,0x70f7,
+    0x5b8c,0x7897,0x633d,0x665a,0x7696,0x60cb,0x5b9b,0x5a49,0x4e07,0x8155,
+    0x6c6a,0x738b,0x4ea1,0x6789,0x7f51,0x5f80,0x65fa,0x671b,0x5fd8,0x5984,
+    0x5a01
+  },
+  {				/* ku 4e */
+    0x8719,0x871b,0x871d,0x871f,0x8720,0x8724,0x8726,0x8727,0x8728,0x872a,
+    0x872b,0x872c,0x872d,0x872f,0x8730,0x8732,0x8733,0x8735,0x8736,0x8738,
+    0x8739,0x873a,0x873c,0x873d,0x8740,0x8741,0x8742,0x8743,0x8744,0x8745,
+    0x8746,0x874a,0x874b,0x874d,0x874f,0x8750,0x8751,0x8752,0x8754,0x8755,
+    0x8756,0x8758,0x875a,0x875b,0x875c,0x875d,0x875e,0x875f,0x8761,0x8762,
+    0x8766,0x8767,0x8768,0x8769,0x876a,0x876b,0x876c,0x876d,0x876f,0x8771,
+    0x8772,0x8773,0x8775,UBOGON,0x8777,0x8778,0x8779,0x877a,0x877f,0x8780,
+    0x8781,0x8784,0x8786,0x8787,0x8789,0x878a,0x878c,0x878e,0x878f,0x8790,
+    0x8791,0x8792,0x8794,0x8795,0x8796,0x8798,0x8799,0x879a,0x879b,0x879c,
+    0x879d,0x879e,0x87a0,0x87a1,0x87a2,0x87a3,0x87a4,0x5dcd,0x5fae,0x5371,
+    0x97e6,0x8fdd,0x6845,0x56f4,0x552f,0x60df,0x4e3a,0x6f4d,0x7ef4,0x82c7,
+    0x840e,0x59d4,0x4f1f,0x4f2a,0x5c3e,0x7eac,0x672a,0x851a,0x5473,0x754f,
+    0x80c3,0x5582,0x9b4f,0x4f4d,0x6e2d,0x8c13,0x5c09,0x6170,0x536b,0x761f,
+    0x6e29,0x868a,0x6587,0x95fb,0x7eb9,0x543b,0x7a33,0x7d0a,0x95ee,0x55e1,
+    0x7fc1,0x74ee,0x631d,0x8717,0x6da1,0x7a9d,0x6211,0x65a1,0x5367,0x63e1,
+    0x6c83,0x5deb,0x545c,0x94a8,0x4e4c,0x6c61,0x8bec,0x5c4b,0x65e0,0x829c,
+    0x68a7,0x543e,0x5434,0x6bcb,0x6b66,0x4e94,0x6342,0x5348,0x821e,0x4f0d,
+    0x4fae,0x575e,0x620a,0x96fe,0x6664,0x7269,0x52ff,0x52a1,0x609f,0x8bef,
+    0x6614,0x7199,0x6790,0x897f,0x7852,0x77fd,0x6670,0x563b,0x5438,0x9521,
+    0x727a
+  },
+  {				/* ku 4f */
+    0x87a5,0x87a6,0x87a7,0x87a9,0x87aa,0x87ae,0x87b0,0x87b1,0x87b2,0x87b4,
+    0x87b6,0x87b7,0x87b8,0x87b9,0x87bb,0x87bc,0x87be,0x87bf,0x87c1,0x87c2,
+    0x87c3,0x87c4,0x87c5,0x87c7,0x87c8,0x87c9,0x87cc,0x87cd,0x87ce,0x87cf,
+    0x87d0,0x87d4,0x87d5,0x87d6,0x87d7,0x87d8,0x87d9,0x87da,0x87dc,0x87dd,
+    0x87de,0x87df,0x87e1,0x87e2,0x87e3,0x87e4,0x87e6,0x87e7,0x87e8,0x87e9,
+    0x87eb,0x87ec,0x87ed,0x87ef,0x87f0,0x87f1,0x87f2,0x87f3,0x87f4,0x87f5,
+    0x87f6,0x87f7,0x87f8,UBOGON,0x87fa,0x87fb,0x87fc,0x87fd,0x87ff,0x8800,
+    0x8801,0x8802,0x8804,0x8805,0x8806,0x8807,0x8808,0x8809,0x880b,0x880c,
+    0x880d,0x880e,0x880f,0x8810,0x8811,0x8812,0x8814,0x8817,0x8818,0x8819,
+    0x881a,0x881c,0x881d,0x881e,0x881f,0x8820,0x8823,0x7a00,0x606f,0x5e0c,
+    0x6089,0x819d,0x5915,0x60dc,0x7184,0x70ef,0x6eaa,0x6c50,0x7280,0x6a84,
+    0x88ad,0x5e2d,0x4e60,0x5ab3,0x559c,0x94e3,0x6d17,0x7cfb,0x9699,0x620f,
+    0x7ec6,0x778e,0x867e,0x5323,0x971e,0x8f96,0x6687,0x5ce1,0x4fa0,0x72ed,
+    0x4e0b,0x53a6,0x590f,0x5413,0x6380,0x9528,0x5148,0x4ed9,0x9c9c,0x7ea4,
+    0x54b8,0x8d24,0x8854,0x8237,0x95f2,0x6d8e,0x5f26,0x5acc,0x663e,0x9669,
+    0x73b0,0x732e,0x53bf,0x817a,0x9985,0x7fa1,0x5baa,0x9677,0x9650,0x7ebf,
+    0x76f8,0x53a2,0x9576,0x9999,0x7bb1,0x8944,0x6e58,0x4e61,0x7fd4,0x7965,
+    0x8be6,0x60f3,0x54cd,0x4eab,0x9879,0x5df7,0x6a61,0x50cf,0x5411,0x8c61,
+    0x8427,0x785d,0x9704,0x524a,0x54ee,0x56a3,0x9500,0x6d88,0x5bb5,0x6dc6,
+    0x6653
+  },
+  {				/* ku 50 */
+    0x8824,0x8825,0x8826,0x8827,0x8828,0x8829,0x882a,0x882b,0x882c,0x882d,
+    0x882e,0x882f,0x8830,0x8831,0x8833,0x8834,0x8835,0x8836,0x8837,0x8838,
+    0x883a,0x883b,0x883d,0x883e,0x883f,0x8841,0x8842,0x8843,0x8846,0x8847,
+    0x8848,0x8849,0x884a,0x884b,0x884e,0x884f,0x8850,0x8851,0x8852,0x8853,
+    0x8855,0x8856,0x8858,0x885a,0x885b,0x885c,0x885d,0x885e,0x885f,0x8860,
+    0x8866,0x8867,0x886a,0x886d,0x886f,0x8871,0x8873,0x8874,0x8875,0x8876,
+    0x8878,0x8879,0x887a,UBOGON,0x887b,0x887c,0x8880,0x8883,0x8886,0x8887,
+    0x8889,0x888a,0x888c,0x888e,0x888f,0x8890,0x8891,0x8893,0x8894,0x8895,
+    0x8897,0x8898,0x8899,0x889a,0x889b,0x889d,0x889e,0x889f,0x88a0,0x88a1,
+    0x88a3,0x88a5,0x88a6,0x88a7,0x88a8,0x88a9,0x88aa,0x5c0f,0x5b5d,0x6821,
+    0x8096,0x5578,0x7b11,0x6548,0x6954,0x4e9b,0x6b47,0x874e,0x978b,0x534f,
+    0x631f,0x643a,0x90aa,0x659c,0x80c1,0x8c10,0x5199,0x68b0,0x5378,0x87f9,
+    0x61c8,0x6cc4,0x6cfb,0x8c22,0x5c51,0x85aa,0x82af,0x950c,0x6b23,0x8f9b,
+    0x65b0,0x5ffb,0x5fc3,0x4fe1,0x8845,0x661f,0x8165,0x7329,0x60fa,0x5174,
+    0x5211,0x578b,0x5f62,0x90a2,0x884c,0x9192,0x5e78,0x674f,0x6027,0x59d3,
+    0x5144,0x51f6,0x80f8,0x5308,0x6c79,0x96c4,0x718a,0x4f11,0x4fee,0x7f9e,
+    0x673d,0x55c5,0x9508,0x79c0,0x8896,0x7ee3,0x589f,0x620c,0x9700,0x865a,
+    0x5618,0x987b,0x5f90,0x8bb8,0x84c4,0x9157,0x53d9,0x65ed,0x5e8f,0x755c,
+    0x6064,0x7d6e,0x5a7f,0x7eea,0x7eed,0x8f69,0x55a7,0x5ba3,0x60ac,0x65cb,
+    0x7384
+  },
+  {				/* ku 51 */
+    0x88ac,0x88ae,0x88af,0x88b0,0x88b2,0x88b3,0x88b4,0x88b5,0x88b6,0x88b8,
+    0x88b9,0x88ba,0x88bb,0x88bd,0x88be,0x88bf,0x88c0,0x88c3,0x88c4,0x88c7,
+    0x88c8,0x88ca,0x88cb,0x88cc,0x88cd,0x88cf,0x88d0,0x88d1,0x88d3,0x88d6,
+    0x88d7,0x88da,0x88db,0x88dc,0x88dd,0x88de,0x88e0,0x88e1,0x88e6,0x88e7,
+    0x88e9,0x88ea,0x88eb,0x88ec,0x88ed,0x88ee,0x88ef,0x88f2,0x88f5,0x88f6,
+    0x88f7,0x88fa,0x88fb,0x88fd,0x88ff,0x8900,0x8901,0x8903,0x8904,0x8905,
+    0x8906,0x8907,0x8908,UBOGON,0x8909,0x890b,0x890c,0x890d,0x890e,0x890f,
+    0x8911,0x8914,0x8915,0x8916,0x8917,0x8918,0x891c,0x891d,0x891e,0x891f,
+    0x8920,0x8922,0x8923,0x8924,0x8926,0x8927,0x8928,0x8929,0x892c,0x892d,
+    0x892e,0x892f,0x8931,0x8932,0x8933,0x8935,0x8937,0x9009,0x7663,0x7729,
+    0x7eda,0x9774,0x859b,0x5b66,0x7a74,0x96ea,0x8840,0x52cb,0x718f,0x5faa,
+    0x65ec,0x8be2,0x5bfb,0x9a6f,0x5de1,0x6b89,0x6c5b,0x8bad,0x8baf,0x900a,
+    0x8fc5,0x538b,0x62bc,0x9e26,0x9e2d,0x5440,0x4e2b,0x82bd,0x7259,0x869c,
+    0x5d16,0x8859,0x6daf,0x96c5,0x54d1,0x4e9a,0x8bb6,0x7109,0x54bd,0x9609,
+    0x70df,0x6df9,0x76d0,0x4e25,0x7814,0x8712,0x5ca9,0x5ef6,0x8a00,0x989c,
+    0x960e,0x708e,0x6cbf,0x5944,0x63a9,0x773c,0x884d,0x6f14,0x8273,0x5830,
+    0x71d5,0x538c,0x781a,0x96c1,0x5501,0x5f66,0x7130,0x5bb4,0x8c1a,0x9a8c,
+    0x6b83,0x592e,0x9e2f,0x79e7,0x6768,0x626c,0x4f6f,0x75a1,0x7f8a,0x6d0b,
+    0x9633,0x6c27,0x4ef0,0x75d2,0x517b,0x6837,0x6f3e,0x9080,0x8170,0x5996,
+    0x7476
+  },
+  {				/* ku 52 */
+    0x8938,0x8939,0x893a,0x893b,0x893c,0x893d,0x893e,0x893f,0x8940,0x8942,
+    0x8943,0x8945,0x8946,0x8947,0x8948,0x8949,0x894a,0x894b,0x894c,0x894d,
+    0x894e,0x894f,0x8950,0x8951,0x8952,0x8953,0x8954,0x8955,0x8956,0x8957,
+    0x8958,0x8959,0x895a,0x895b,0x895c,0x895d,0x8960,0x8961,0x8962,0x8963,
+    0x8964,0x8965,0x8967,0x8968,0x8969,0x896a,0x896b,0x896c,0x896d,0x896e,
+    0x896f,0x8970,0x8971,0x8972,0x8973,0x8974,0x8975,0x8976,0x8977,0x8978,
+    0x8979,0x897a,0x897c,UBOGON,0x897d,0x897e,0x8980,0x8982,0x8984,0x8985,
+    0x8987,0x8988,0x8989,0x898a,0x898b,0x898c,0x898d,0x898e,0x898f,0x8990,
+    0x8991,0x8992,0x8993,0x8994,0x8995,0x8996,0x8997,0x8998,0x8999,0x899a,
+    0x899b,0x899c,0x899d,0x899e,0x899f,0x89a0,0x89a1,0x6447,0x5c27,0x9065,
+    0x7a91,0x8c23,0x59da,0x54ac,0x8200,0x836f,0x8981,0x8000,0x6930,0x564e,
+    0x8036,0x7237,0x91ce,0x51b6,0x4e5f,0x9875,0x6396,0x4e1a,0x53f6,0x66f3,
+    0x814b,0x591c,0x6db2,0x4e00,0x58f9,0x533b,0x63d6,0x94f1,0x4f9d,0x4f0a,
+    0x8863,0x9890,0x5937,0x9057,0x79fb,0x4eea,0x80f0,0x7591,0x6c82,0x5b9c,
+    0x59e8,0x5f5d,0x6905,0x8681,0x501a,0x5df2,0x4e59,0x77e3,0x4ee5,0x827a,
+    0x6291,0x6613,0x9091,0x5c79,0x4ebf,0x5f79,0x81c6,0x9038,0x8084,0x75ab,
+    0x4ea6,0x88d4,0x610f,0x6bc5,0x5fc6,0x4e49,0x76ca,0x6ea2,0x8be3,0x8bae,
+    0x8c0a,0x8bd1,0x5f02,0x7ffc,0x7fcc,0x7ece,0x8335,0x836b,0x56e0,0x6bb7,
+    0x97f3,0x9634,0x59fb,0x541f,0x94f6,0x6deb,0x5bc5,0x996e,0x5c39,0x5f15,
+    0x9690
+  },
+  {				/* ku 53 */
+    0x89a2,0x89a3,0x89a4,0x89a5,0x89a6,0x89a7,0x89a8,0x89a9,0x89aa,0x89ab,
+    0x89ac,0x89ad,0x89ae,0x89af,0x89b0,0x89b1,0x89b2,0x89b3,0x89b4,0x89b5,
+    0x89b6,0x89b7,0x89b8,0x89b9,0x89ba,0x89bb,0x89bc,0x89bd,0x89be,0x89bf,
+    0x89c0,0x89c3,0x89cd,0x89d3,0x89d4,0x89d5,0x89d7,0x89d8,0x89d9,0x89db,
+    0x89dd,0x89df,0x89e0,0x89e1,0x89e2,0x89e4,0x89e7,0x89e8,0x89e9,0x89ea,
+    0x89ec,0x89ed,0x89ee,0x89f0,0x89f1,0x89f2,0x89f4,0x89f5,0x89f6,0x89f7,
+    0x89f8,0x89f9,0x89fa,UBOGON,0x89fb,0x89fc,0x89fd,0x89fe,0x89ff,0x8a01,
+    0x8a02,0x8a03,0x8a04,0x8a05,0x8a06,0x8a08,0x8a09,0x8a0a,0x8a0b,0x8a0c,
+    0x8a0d,0x8a0e,0x8a0f,0x8a10,0x8a11,0x8a12,0x8a13,0x8a14,0x8a15,0x8a16,
+    0x8a17,0x8a18,0x8a19,0x8a1a,0x8a1b,0x8a1c,0x8a1d,0x5370,0x82f1,0x6a31,
+    0x5a74,0x9e70,0x5e94,0x7f28,0x83b9,0x8424,0x8425,0x8367,0x8747,0x8fce,
+    0x8d62,0x76c8,0x5f71,0x9896,0x786c,0x6620,0x54df,0x62e5,0x4f63,0x81c3,
+    0x75c8,0x5eb8,0x96cd,0x8e0a,0x86f9,0x548f,0x6cf3,0x6d8c,0x6c38,0x607f,
+    0x52c7,0x7528,0x5e7d,0x4f18,0x60a0,0x5fe7,0x5c24,0x7531,0x90ae,0x94c0,
+    0x72b9,0x6cb9,0x6e38,0x9149,0x6709,0x53cb,0x53f3,0x4f51,0x91c9,0x8bf1,
+    0x53c8,0x5e7c,0x8fc2,0x6de4,0x4e8e,0x76c2,0x6986,0x865e,0x611a,0x8206,
+    0x4f59,0x4fde,0x903e,0x9c7c,0x6109,0x6e1d,0x6e14,0x9685,0x4e88,0x5a31,
+    0x96e8,0x4e0e,0x5c7f,0x79b9,0x5b87,0x8bed,0x7fbd,0x7389,0x57df,0x828b,
+    0x90c1,0x5401,0x9047,0x55bb,0x5cea,0x5fa1,0x6108,0x6b32,0x72f1,0x80b2,
+    0x8a89
+  },
+  {				/* ku 54 */
+    0x8a1e,0x8a1f,0x8a20,0x8a21,0x8a22,0x8a23,0x8a24,0x8a25,0x8a26,0x8a27,
+    0x8a28,0x8a29,0x8a2a,0x8a2b,0x8a2c,0x8a2d,0x8a2e,0x8a2f,0x8a30,0x8a31,
+    0x8a32,0x8a33,0x8a34,0x8a35,0x8a36,0x8a37,0x8a38,0x8a39,0x8a3a,0x8a3b,
+    0x8a3c,0x8a3d,0x8a3f,0x8a40,0x8a41,0x8a42,0x8a43,0x8a44,0x8a45,0x8a46,
+    0x8a47,0x8a49,0x8a4a,0x8a4b,0x8a4c,0x8a4d,0x8a4e,0x8a4f,0x8a50,0x8a51,
+    0x8a52,0x8a53,0x8a54,0x8a55,0x8a56,0x8a57,0x8a58,0x8a59,0x8a5a,0x8a5b,
+    0x8a5c,0x8a5d,0x8a5e,UBOGON,0x8a5f,0x8a60,0x8a61,0x8a62,0x8a63,0x8a64,
+    0x8a65,0x8a66,0x8a67,0x8a68,0x8a69,0x8a6a,0x8a6b,0x8a6c,0x8a6d,0x8a6e,
+    0x8a6f,0x8a70,0x8a71,0x8a72,0x8a73,0x8a74,0x8a75,0x8a76,0x8a77,0x8a78,
+    0x8a7a,0x8a7b,0x8a7c,0x8a7d,0x8a7e,0x8a7f,0x8a80,0x6d74,0x5bd3,0x88d5,
+    0x9884,0x8c6b,0x9a6d,0x9e33,0x6e0a,0x51a4,0x5143,0x57a3,0x8881,0x539f,
+    0x63f4,0x8f95,0x56ed,0x5458,0x5706,0x733f,0x6e90,0x7f18,0x8fdc,0x82d1,
+    0x613f,0x6028,0x9662,0x66f0,0x7ea6,0x8d8a,0x8dc3,0x94a5,0x5cb3,0x7ca4,
+    0x6708,0x60a6,0x9605,0x8018,0x4e91,0x90e7,0x5300,0x9668,0x5141,0x8fd0,
+    0x8574,0x915d,0x6655,0x97f5,0x5b55,0x531d,0x7838,0x6742,0x683d,0x54c9,
+    0x707e,0x5bb0,0x8f7d,0x518d,0x5728,0x54b1,0x6512,0x6682,0x8d5e,0x8d43,
+    0x810f,0x846c,0x906d,0x7cdf,0x51ff,0x85fb,0x67a3,0x65e9,0x6fa1,0x86a4,
+    0x8e81,0x566a,0x9020,0x7682,0x7076,0x71e5,0x8d23,0x62e9,0x5219,0x6cfd,
+    0x8d3c,0x600e,0x589e,0x618e,0x66fe,0x8d60,0x624e,0x55b3,0x6e23,0x672d,
+    0x8f67
+  },
+  {				/* ku 55 */
+    0x8a81,0x8a82,0x8a83,0x8a84,0x8a85,0x8a86,0x8a87,0x8a88,0x8a8b,0x8a8c,
+    0x8a8d,0x8a8e,0x8a8f,0x8a90,0x8a91,0x8a92,0x8a94,0x8a95,0x8a96,0x8a97,
+    0x8a98,0x8a99,0x8a9a,0x8a9b,0x8a9c,0x8a9d,0x8a9e,0x8a9f,0x8aa0,0x8aa1,
+    0x8aa2,0x8aa3,0x8aa4,0x8aa5,0x8aa6,0x8aa7,0x8aa8,0x8aa9,0x8aaa,0x8aab,
+    0x8aac,0x8aad,0x8aae,0x8aaf,0x8ab0,0x8ab1,0x8ab2,0x8ab3,0x8ab4,0x8ab5,
+    0x8ab6,0x8ab7,0x8ab8,0x8ab9,0x8aba,0x8abb,0x8abc,0x8abd,0x8abe,0x8abf,
+    0x8ac0,0x8ac1,0x8ac2,UBOGON,0x8ac3,0x8ac4,0x8ac5,0x8ac6,0x8ac7,0x8ac8,
+    0x8ac9,0x8aca,0x8acb,0x8acc,0x8acd,0x8ace,0x8acf,0x8ad0,0x8ad1,0x8ad2,
+    0x8ad3,0x8ad4,0x8ad5,0x8ad6,0x8ad7,0x8ad8,0x8ad9,0x8ada,0x8adb,0x8adc,
+    0x8add,0x8ade,0x8adf,0x8ae0,0x8ae1,0x8ae2,0x8ae3,0x94e1,0x95f8,0x7728,
+    0x6805,0x69a8,0x548b,0x4e4d,0x70b8,0x8bc8,0x6458,0x658b,0x5b85,0x7a84,
+    0x503a,0x5be8,0x77bb,0x6be1,0x8a79,0x7c98,0x6cbe,0x76cf,0x65a9,0x8f97,
+    0x5d2d,0x5c55,0x8638,0x6808,0x5360,0x6218,0x7ad9,0x6e5b,0x7efd,0x6a1f,
+    0x7ae0,0x5f70,0x6f33,0x5f20,0x638c,0x6da8,0x6756,0x4e08,0x5e10,0x8d26,
+    0x4ed7,0x80c0,0x7634,0x969c,0x62db,0x662d,0x627e,0x6cbc,0x8d75,0x7167,
+    0x7f69,0x5146,0x8087,0x53ec,0x906e,0x6298,0x54f2,0x86f0,0x8f99,0x8005,
+    0x9517,0x8517,0x8fd9,0x6d59,0x73cd,0x659f,0x771f,0x7504,0x7827,0x81fb,
+    0x8d1e,0x9488,0x4fa6,0x6795,0x75b9,0x8bca,0x9707,0x632f,0x9547,0x9635,
+    0x84b8,0x6323,0x7741,0x5f81,0x72f0,0x4e89,0x6014,0x6574,0x62ef,0x6b63,
+    0x653f
+  },
+  {				/* ku 56 */
+    0x8ae4,0x8ae5,0x8ae6,0x8ae7,0x8ae8,0x8ae9,0x8aea,0x8aeb,0x8aec,0x8aed,
+    0x8aee,0x8aef,0x8af0,0x8af1,0x8af2,0x8af3,0x8af4,0x8af5,0x8af6,0x8af7,
+    0x8af8,0x8af9,0x8afa,0x8afb,0x8afc,0x8afd,0x8afe,0x8aff,0x8b00,0x8b01,
+    0x8b02,0x8b03,0x8b04,0x8b05,0x8b06,0x8b08,0x8b09,0x8b0a,0x8b0b,0x8b0c,
+    0x8b0d,0x8b0e,0x8b0f,0x8b10,0x8b11,0x8b12,0x8b13,0x8b14,0x8b15,0x8b16,
+    0x8b17,0x8b18,0x8b19,0x8b1a,0x8b1b,0x8b1c,0x8b1d,0x8b1e,0x8b1f,0x8b20,
+    0x8b21,0x8b22,0x8b23,UBOGON,0x8b24,0x8b25,0x8b27,0x8b28,0x8b29,0x8b2a,
+    0x8b2b,0x8b2c,0x8b2d,0x8b2e,0x8b2f,0x8b30,0x8b31,0x8b32,0x8b33,0x8b34,
+    0x8b35,0x8b36,0x8b37,0x8b38,0x8b39,0x8b3a,0x8b3b,0x8b3c,0x8b3d,0x8b3e,
+    0x8b3f,0x8b40,0x8b41,0x8b42,0x8b43,0x8b44,0x8b45,0x5e27,0x75c7,0x90d1,
+    0x8bc1,0x829d,0x679d,0x652f,0x5431,0x8718,0x77e5,0x80a2,0x8102,0x6c41,
+    0x4e4b,0x7ec7,0x804c,0x76f4,0x690d,0x6b96,0x6267,0x503c,0x4f84,0x5740,
+    0x6307,0x6b62,0x8dbe,0x53ea,0x65e8,0x7eb8,0x5fd7,0x631a,0x63b7,0x81f3,
+    0x81f4,0x7f6e,0x5e1c,0x5cd9,0x5236,0x667a,0x79e9,0x7a1a,0x8d28,0x7099,
+    0x75d4,0x6ede,0x6cbb,0x7a92,0x4e2d,0x76c5,0x5fe0,0x949f,0x8877,0x7ec8,
+    0x79cd,0x80bf,0x91cd,0x4ef2,0x4f17,0x821f,0x5468,0x5dde,0x6d32,0x8bcc,
+    0x7ca5,0x8f74,0x8098,0x5e1a,0x5492,0x76b1,0x5b99,0x663c,0x9aa4,0x73e0,
+    0x682a,0x86db,0x6731,0x732a,0x8bf8,0x8bdb,0x9010,0x7af9,0x70db,0x716e,
+    0x62c4,0x77a9,0x5631,0x4e3b,0x8457,0x67f1,0x52a9,0x86c0,0x8d2e,0x94f8,
+    0x7b51
+  },
+  {				/* ku 57 */
+    0x8b46,0x8b47,0x8b48,0x8b49,0x8b4a,0x8b4b,0x8b4c,0x8b4d,0x8b4e,0x8b4f,
+    0x8b50,0x8b51,0x8b52,0x8b53,0x8b54,0x8b55,0x8b56,0x8b57,0x8b58,0x8b59,
+    0x8b5a,0x8b5b,0x8b5c,0x8b5d,0x8b5e,0x8b5f,0x8b60,0x8b61,0x8b62,0x8b63,
+    0x8b64,0x8b65,0x8b67,0x8b68,0x8b69,0x8b6a,0x8b6b,0x8b6d,0x8b6e,0x8b6f,
+    0x8b70,0x8b71,0x8b72,0x8b73,0x8b74,0x8b75,0x8b76,0x8b77,0x8b78,0x8b79,
+    0x8b7a,0x8b7b,0x8b7c,0x8b7d,0x8b7e,0x8b7f,0x8b80,0x8b81,0x8b82,0x8b83,
+    0x8b84,0x8b85,0x8b86,UBOGON,0x8b87,0x8b88,0x8b89,0x8b8a,0x8b8b,0x8b8c,
+    0x8b8d,0x8b8e,0x8b8f,0x8b90,0x8b91,0x8b92,0x8b93,0x8b94,0x8b95,0x8b96,
+    0x8b97,0x8b98,0x8b99,0x8b9a,0x8b9b,0x8b9c,0x8b9d,0x8b9e,0x8b9f,0x8bac,
+    0x8bb1,0x8bbb,0x8bc7,0x8bd0,0x8bea,0x8c09,0x8c1e,0x4f4f,0x6ce8,0x795d,
+    0x9a7b,0x6293,0x722a,0x62fd,0x4e13,0x7816,0x8f6c,0x64b0,0x8d5a,0x7bc6,
+    0x6869,0x5e84,0x88c5,0x5986,0x649e,0x58ee,0x72b6,0x690e,0x9525,0x8ffd,
+    0x8d58,0x5760,0x7f00,0x8c06,0x51c6,0x6349,0x62d9,0x5353,0x684c,0x7422,
+    0x8301,0x914c,0x5544,0x7740,0x707c,0x6d4a,0x5179,0x54a8,0x8d44,0x59ff,
+    0x6ecb,0x6dc4,0x5b5c,0x7d2b,0x4ed4,0x7c7d,0x6ed3,0x5b50,0x81ea,0x6e0d,
+    0x5b57,0x9b03,0x68d5,0x8e2a,0x5b97,0x7efc,0x603b,0x7eb5,0x90b9,0x8d70,
+    0x594f,0x63cd,0x79df,0x8db3,0x5352,0x65cf,0x7956,0x8bc5,0x963b,0x7ec4,
+    0x94bb,0x7e82,0x5634,0x9189,0x6700,0x7f6a,0x5c0a,0x9075,0x6628,0x5de6,
+    0x4f50,0x67de,0x505a,0x4f5c,0x5750,0x5ea7,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON
+  },
+  {				/* ku 58 */
+    0x8c38,0x8c39,0x8c3a,0x8c3b,0x8c3c,0x8c3d,0x8c3e,0x8c3f,0x8c40,0x8c42,
+    0x8c43,0x8c44,0x8c45,0x8c48,0x8c4a,0x8c4b,0x8c4d,0x8c4e,0x8c4f,0x8c50,
+    0x8c51,0x8c52,0x8c53,0x8c54,0x8c56,0x8c57,0x8c58,0x8c59,0x8c5b,0x8c5c,
+    0x8c5d,0x8c5e,0x8c5f,0x8c60,0x8c63,0x8c64,0x8c65,0x8c66,0x8c67,0x8c68,
+    0x8c69,0x8c6c,0x8c6d,0x8c6e,0x8c6f,0x8c70,0x8c71,0x8c72,0x8c74,0x8c75,
+    0x8c76,0x8c77,0x8c7b,0x8c7c,0x8c7d,0x8c7e,0x8c7f,0x8c80,0x8c81,0x8c83,
+    0x8c84,0x8c86,0x8c87,UBOGON,0x8c88,0x8c8b,0x8c8d,0x8c8e,0x8c8f,0x8c90,
+    0x8c91,0x8c92,0x8c93,0x8c95,0x8c96,0x8c97,0x8c99,0x8c9a,0x8c9b,0x8c9c,
+    0x8c9d,0x8c9e,0x8c9f,0x8ca0,0x8ca1,0x8ca2,0x8ca3,0x8ca4,0x8ca5,0x8ca6,
+    0x8ca7,0x8ca8,0x8ca9,0x8caa,0x8cab,0x8cac,0x8cad,0x4e8d,0x4e0c,0x5140,
+    0x4e10,0x5eff,0x5345,0x4e15,0x4e98,0x4e1e,0x9b32,0x5b6c,0x5669,0x4e28,
+    0x79ba,0x4e3f,0x5315,0x4e47,0x592d,0x723b,0x536e,0x6c10,0x56df,0x80e4,
+    0x9997,0x6bd3,0x777e,0x9f17,0x4e36,0x4e9f,0x9f10,0x4e5c,0x4e69,0x4e93,
+    0x8288,0x5b5b,0x556c,0x560f,0x4ec4,0x538d,0x539d,0x53a3,0x53a5,0x53ae,
+    0x9765,0x8d5d,0x531a,0x53f5,0x5326,0x532e,0x533e,0x8d5c,0x5366,0x5363,
+    0x5202,0x5208,0x520e,0x522d,0x5233,0x523f,0x5240,0x524c,0x525e,0x5261,
+    0x525c,0x84af,0x527d,0x5282,0x5281,0x5290,0x5293,0x5182,0x7f54,0x4ebb,
+    0x4ec3,0x4ec9,0x4ec2,0x4ee8,0x4ee1,0x4eeb,0x4ede,0x4f1b,0x4ef3,0x4f22,
+    0x4f64,0x4ef5,0x4f25,0x4f27,0x4f09,0x4f2b,0x4f5e,0x4f67,0x6538,0x4f5a,
+    0x4f5d
+  },
+  {				/* ku 59 */
+    0x8cae,0x8caf,0x8cb0,0x8cb1,0x8cb2,0x8cb3,0x8cb4,0x8cb5,0x8cb6,0x8cb7,
+    0x8cb8,0x8cb9,0x8cba,0x8cbb,0x8cbc,0x8cbd,0x8cbe,0x8cbf,0x8cc0,0x8cc1,
+    0x8cc2,0x8cc3,0x8cc4,0x8cc5,0x8cc6,0x8cc7,0x8cc8,0x8cc9,0x8cca,0x8ccb,
+    0x8ccc,0x8ccd,0x8cce,0x8ccf,0x8cd0,0x8cd1,0x8cd2,0x8cd3,0x8cd4,0x8cd5,
+    0x8cd6,0x8cd7,0x8cd8,0x8cd9,0x8cda,0x8cdb,0x8cdc,0x8cdd,0x8cde,0x8cdf,
+    0x8ce0,0x8ce1,0x8ce2,0x8ce3,0x8ce4,0x8ce5,0x8ce6,0x8ce7,0x8ce8,0x8ce9,
+    0x8cea,0x8ceb,0x8cec,UBOGON,0x8ced,0x8cee,0x8cef,0x8cf0,0x8cf1,0x8cf2,
+    0x8cf3,0x8cf4,0x8cf5,0x8cf6,0x8cf7,0x8cf8,0x8cf9,0x8cfa,0x8cfb,0x8cfc,
+    0x8cfd,0x8cfe,0x8cff,0x8d00,0x8d01,0x8d02,0x8d03,0x8d04,0x8d05,0x8d06,
+    0x8d07,0x8d08,0x8d09,0x8d0a,0x8d0b,0x8d0c,0x8d0d,0x4f5f,0x4f57,0x4f32,
+    0x4f3d,0x4f76,0x4f74,0x4f91,0x4f89,0x4f83,0x4f8f,0x4f7e,0x4f7b,0x4faa,
+    0x4f7c,0x4fac,0x4f94,0x4fe6,0x4fe8,0x4fea,0x4fc5,0x4fda,0x4fe3,0x4fdc,
+    0x4fd1,0x4fdf,0x4ff8,0x5029,0x504c,0x4ff3,0x502c,0x500f,0x502e,0x502d,
+    0x4ffe,0x501c,0x500c,0x5025,0x5028,0x507e,0x5043,0x5055,0x5048,0x504e,
+    0x506c,0x507b,0x50a5,0x50a7,0x50a9,0x50ba,0x50d6,0x5106,0x50ed,0x50ec,
+    0x50e6,0x50ee,0x5107,0x510b,0x4edd,0x6c3d,0x4f58,0x4f65,0x4fce,0x9fa0,
+    0x6c46,0x7c74,0x516e,0x5dfd,0x9ec9,0x9998,0x5181,0x5914,0x52f9,0x530d,
+    0x8a07,0x5310,0x51eb,0x5919,0x5155,0x4ea0,0x5156,0x4eb3,0x886e,0x88a4,
+    0x4eb5,0x8114,0x88d2,0x7980,0x5b34,0x8803,0x7fb8,0x51ab,0x51b1,0x51bd,
+    0x51bc
+  },
+  {				/* ku 5a */
+    0x8d0e,0x8d0f,0x8d10,0x8d11,0x8d12,0x8d13,0x8d14,0x8d15,0x8d16,0x8d17,
+    0x8d18,0x8d19,0x8d1a,0x8d1b,0x8d1c,0x8d20,0x8d51,0x8d52,0x8d57,0x8d5f,
+    0x8d65,0x8d68,0x8d69,0x8d6a,0x8d6c,0x8d6e,0x8d6f,0x8d71,0x8d72,0x8d78,
+    0x8d79,0x8d7a,0x8d7b,0x8d7c,0x8d7d,0x8d7e,0x8d7f,0x8d80,0x8d82,0x8d83,
+    0x8d86,0x8d87,0x8d88,0x8d89,0x8d8c,0x8d8d,0x8d8e,0x8d8f,0x8d90,0x8d92,
+    0x8d93,0x8d95,0x8d96,0x8d97,0x8d98,0x8d99,0x8d9a,0x8d9b,0x8d9c,0x8d9d,
+    0x8d9e,0x8da0,0x8da1,UBOGON,0x8da2,0x8da4,0x8da5,0x8da6,0x8da7,0x8da8,
+    0x8da9,0x8daa,0x8dab,0x8dac,0x8dad,0x8dae,0x8daf,0x8db0,0x8db2,0x8db6,
+    0x8db7,0x8db9,0x8dbb,0x8dbd,0x8dc0,0x8dc1,0x8dc2,0x8dc5,0x8dc7,0x8dc8,
+    0x8dc9,0x8dca,0x8dcd,0x8dd0,0x8dd2,0x8dd3,0x8dd4,0x51c7,0x5196,0x51a2,
+    0x51a5,0x8ba0,0x8ba6,0x8ba7,0x8baa,0x8bb4,0x8bb5,0x8bb7,0x8bc2,0x8bc3,
+    0x8bcb,0x8bcf,0x8bce,0x8bd2,0x8bd3,0x8bd4,0x8bd6,0x8bd8,0x8bd9,0x8bdc,
+    0x8bdf,0x8be0,0x8be4,0x8be8,0x8be9,0x8bee,0x8bf0,0x8bf3,0x8bf6,0x8bf9,
+    0x8bfc,0x8bff,0x8c00,0x8c02,0x8c04,0x8c07,0x8c0c,0x8c0f,0x8c11,0x8c12,
+    0x8c14,0x8c15,0x8c16,0x8c19,0x8c1b,0x8c18,0x8c1d,0x8c1f,0x8c20,0x8c21,
+    0x8c25,0x8c27,0x8c2a,0x8c2b,0x8c2e,0x8c2f,0x8c32,0x8c33,0x8c35,0x8c36,
+    0x5369,0x537a,0x961d,0x9622,0x9621,0x9631,0x962a,0x963d,0x963c,0x9642,
+    0x9649,0x9654,0x965f,0x9667,0x966c,0x9672,0x9674,0x9688,0x968d,0x9697,
+    0x96b0,0x9097,0x909b,0x909d,0x9099,0x90ac,0x90a1,0x90b4,0x90b3,0x90b6,
+    0x90ba
+  },
+  {				/* ku 5b */
+    0x8dd5,0x8dd8,0x8dd9,0x8ddc,0x8de0,0x8de1,0x8de2,0x8de5,0x8de6,0x8de7,
+    0x8de9,0x8ded,0x8dee,0x8df0,0x8df1,0x8df2,0x8df4,0x8df6,0x8dfc,0x8dfe,
+    0x8dff,0x8e00,0x8e01,0x8e02,0x8e03,0x8e04,0x8e06,0x8e07,0x8e08,0x8e0b,
+    0x8e0d,0x8e0e,0x8e10,0x8e11,0x8e12,0x8e13,0x8e15,0x8e16,0x8e17,0x8e18,
+    0x8e19,0x8e1a,0x8e1b,0x8e1c,0x8e20,0x8e21,0x8e24,0x8e25,0x8e26,0x8e27,
+    0x8e28,0x8e2b,0x8e2d,0x8e30,0x8e32,0x8e33,0x8e34,0x8e36,0x8e37,0x8e38,
+    0x8e3b,0x8e3c,0x8e3e,UBOGON,0x8e3f,0x8e43,0x8e45,0x8e46,0x8e4c,0x8e4d,
+    0x8e4e,0x8e4f,0x8e50,0x8e53,0x8e54,0x8e55,0x8e56,0x8e57,0x8e58,0x8e5a,
+    0x8e5b,0x8e5c,0x8e5d,0x8e5e,0x8e5f,0x8e60,0x8e61,0x8e62,0x8e63,0x8e64,
+    0x8e65,0x8e67,0x8e68,0x8e6a,0x8e6b,0x8e6e,0x8e71,0x90b8,0x90b0,0x90cf,
+    0x90c5,0x90be,0x90d0,0x90c4,0x90c7,0x90d3,0x90e6,0x90e2,0x90dc,0x90d7,
+    0x90db,0x90eb,0x90ef,0x90fe,0x9104,0x9122,0x911e,0x9123,0x9131,0x912f,
+    0x9139,0x9143,0x9146,0x520d,0x5942,0x52a2,0x52ac,0x52ad,0x52be,0x54ff,
+    0x52d0,0x52d6,0x52f0,0x53df,0x71ee,0x77cd,0x5ef4,0x51f5,0x51fc,0x9b2f,
+    0x53b6,0x5f01,0x755a,0x5def,0x574c,0x57a9,0x57a1,0x587e,0x58bc,0x58c5,
+    0x58d1,0x5729,0x572c,0x572a,0x5733,0x5739,0x572e,0x572f,0x575c,0x573b,
+    0x5742,0x5769,0x5785,0x576b,0x5786,0x577c,0x577b,0x5768,0x576d,0x5776,
+    0x5773,0x57ad,0x57a4,0x578c,0x57b2,0x57cf,0x57a7,0x57b4,0x5793,0x57a0,
+    0x57d5,0x57d8,0x57da,0x57d9,0x57d2,0x57b8,0x57f4,0x57ef,0x57f8,0x57e4,
+    0x57dd
+  },
+  {				/* ku 5c */
+    0x8e73,0x8e75,0x8e77,0x8e78,0x8e79,0x8e7a,0x8e7b,0x8e7d,0x8e7e,0x8e80,
+    0x8e82,0x8e83,0x8e84,0x8e86,0x8e88,0x8e89,0x8e8a,0x8e8b,0x8e8c,0x8e8d,
+    0x8e8e,0x8e91,0x8e92,0x8e93,0x8e95,0x8e96,0x8e97,0x8e98,0x8e99,0x8e9a,
+    0x8e9b,0x8e9d,0x8e9f,0x8ea0,0x8ea1,0x8ea2,0x8ea3,0x8ea4,0x8ea5,0x8ea6,
+    0x8ea7,0x8ea8,0x8ea9,0x8eaa,0x8ead,0x8eae,0x8eb0,0x8eb1,0x8eb3,0x8eb4,
+    0x8eb5,0x8eb6,0x8eb7,0x8eb8,0x8eb9,0x8ebb,0x8ebc,0x8ebd,0x8ebe,0x8ebf,
+    0x8ec0,0x8ec1,0x8ec2,UBOGON,0x8ec3,0x8ec4,0x8ec5,0x8ec6,0x8ec7,0x8ec8,
+    0x8ec9,0x8eca,0x8ecb,0x8ecc,0x8ecd,0x8ecf,0x8ed0,0x8ed1,0x8ed2,0x8ed3,
+    0x8ed4,0x8ed5,0x8ed6,0x8ed7,0x8ed8,0x8ed9,0x8eda,0x8edb,0x8edc,0x8edd,
+    0x8ede,0x8edf,0x8ee0,0x8ee1,0x8ee2,0x8ee3,0x8ee4,0x580b,0x580d,0x57fd,
+    0x57ed,0x5800,0x581e,0x5819,0x5844,0x5820,0x5865,0x586c,0x5881,0x5889,
+    0x589a,0x5880,0x99a8,0x9f19,0x61ff,0x8279,0x827d,0x827f,0x828f,0x828a,
+    0x82a8,0x8284,0x828e,0x8291,0x8297,0x8299,0x82ab,0x82b8,0x82be,0x82b0,
+    0x82c8,0x82ca,0x82e3,0x8298,0x82b7,0x82ae,0x82cb,0x82cc,0x82c1,0x82a9,
+    0x82b4,0x82a1,0x82aa,0x829f,0x82c4,0x82ce,0x82a4,0x82e1,0x8309,0x82f7,
+    0x82e4,0x830f,0x8307,0x82dc,0x82f4,0x82d2,0x82d8,0x830c,0x82fb,0x82d3,
+    0x8311,0x831a,0x8306,0x8314,0x8315,0x82e0,0x82d5,0x831c,0x8351,0x835b,
+    0x835c,0x8308,0x8392,0x833c,0x8334,0x8331,0x839b,0x835e,0x832f,0x834f,
+    0x8347,0x8343,0x835f,0x8340,0x8317,0x8360,0x832d,0x833a,0x8333,0x8366,
+    0x8365
+  },
+  {				/* ku 5d */
+    0x8ee5,0x8ee6,0x8ee7,0x8ee8,0x8ee9,0x8eea,0x8eeb,0x8eec,0x8eed,0x8eee,
+    0x8eef,0x8ef0,0x8ef1,0x8ef2,0x8ef3,0x8ef4,0x8ef5,0x8ef6,0x8ef7,0x8ef8,
+    0x8ef9,0x8efa,0x8efb,0x8efc,0x8efd,0x8efe,0x8eff,0x8f00,0x8f01,0x8f02,
+    0x8f03,0x8f04,0x8f05,0x8f06,0x8f07,0x8f08,0x8f09,0x8f0a,0x8f0b,0x8f0c,
+    0x8f0d,0x8f0e,0x8f0f,0x8f10,0x8f11,0x8f12,0x8f13,0x8f14,0x8f15,0x8f16,
+    0x8f17,0x8f18,0x8f19,0x8f1a,0x8f1b,0x8f1c,0x8f1d,0x8f1e,0x8f1f,0x8f20,
+    0x8f21,0x8f22,0x8f23,UBOGON,0x8f24,0x8f25,0x8f26,0x8f27,0x8f28,0x8f29,
+    0x8f2a,0x8f2b,0x8f2c,0x8f2d,0x8f2e,0x8f2f,0x8f30,0x8f31,0x8f32,0x8f33,
+    0x8f34,0x8f35,0x8f36,0x8f37,0x8f38,0x8f39,0x8f3a,0x8f3b,0x8f3c,0x8f3d,
+    0x8f3e,0x8f3f,0x8f40,0x8f41,0x8f42,0x8f43,0x8f44,0x8368,0x831b,0x8369,
+    0x836c,0x836a,0x836d,0x836e,0x83b0,0x8378,0x83b3,0x83b4,0x83a0,0x83aa,
+    0x8393,0x839c,0x8385,0x837c,0x83b6,0x83a9,0x837d,0x83b8,0x837b,0x8398,
+    0x839e,0x83a8,0x83ba,0x83bc,0x83c1,0x8401,0x83e5,0x83d8,0x5807,0x8418,
+    0x840b,0x83dd,0x83fd,0x83d6,0x841c,0x8438,0x8411,0x8406,0x83d4,0x83df,
+    0x840f,0x8403,0x83f8,0x83f9,0x83ea,0x83c5,0x83c0,0x8426,0x83f0,0x83e1,
+    0x845c,0x8451,0x845a,0x8459,0x8473,0x8487,0x8488,0x847a,0x8489,0x8478,
+    0x843c,0x8446,0x8469,0x8476,0x848c,0x848e,0x8431,0x846d,0x84c1,0x84cd,
+    0x84d0,0x84e6,0x84bd,0x84d3,0x84ca,0x84bf,0x84ba,0x84e0,0x84a1,0x84b9,
+    0x84b4,0x8497,0x84e5,0x84e3,0x850c,0x750d,0x8538,0x84f0,0x8539,0x851f,
+    0x853a
+  },
+  {				/* ku 5e */
+    0x8f45,0x8f46,0x8f47,0x8f48,0x8f49,0x8f4a,0x8f4b,0x8f4c,0x8f4d,0x8f4e,
+    0x8f4f,0x8f50,0x8f51,0x8f52,0x8f53,0x8f54,0x8f55,0x8f56,0x8f57,0x8f58,
+    0x8f59,0x8f5a,0x8f5b,0x8f5c,0x8f5d,0x8f5e,0x8f5f,0x8f60,0x8f61,0x8f62,
+    0x8f63,0x8f64,0x8f65,0x8f6a,0x8f80,0x8f8c,0x8f92,0x8f9d,0x8fa0,0x8fa1,
+    0x8fa2,0x8fa4,0x8fa5,0x8fa6,0x8fa7,0x8faa,0x8fac,0x8fad,0x8fae,0x8faf,
+    0x8fb2,0x8fb3,0x8fb4,0x8fb5,0x8fb7,0x8fb8,0x8fba,0x8fbb,0x8fbc,0x8fbf,
+    0x8fc0,0x8fc3,0x8fc6,UBOGON,0x8fc9,0x8fca,0x8fcb,0x8fcc,0x8fcd,0x8fcf,
+    0x8fd2,0x8fd6,0x8fd7,0x8fda,0x8fe0,0x8fe1,0x8fe3,0x8fe7,0x8fec,0x8fef,
+    0x8ff1,0x8ff2,0x8ff4,0x8ff5,0x8ff6,0x8ffa,0x8ffb,0x8ffc,0x8ffe,0x8fff,
+    0x9007,0x9008,0x900c,0x900e,0x9013,0x9015,0x9018,0x8556,0x853b,0x84ff,
+    0x84fc,0x8559,0x8548,0x8568,0x8564,0x855e,0x857a,0x77a2,0x8543,0x8572,
+    0x857b,0x85a4,0x85a8,0x8587,0x858f,0x8579,0x85ae,0x859c,0x8585,0x85b9,
+    0x85b7,0x85b0,0x85d3,0x85c1,0x85dc,0x85ff,0x8627,0x8605,0x8629,0x8616,
+    0x863c,0x5efe,0x5f08,0x593c,0x5941,0x8037,0x5955,0x595a,0x5958,0x530f,
+    0x5c22,0x5c25,0x5c2c,0x5c34,0x624c,0x626a,0x629f,0x62bb,0x62ca,0x62da,
+    0x62d7,0x62ee,0x6322,0x62f6,0x6339,0x634b,0x6343,0x63ad,0x63f6,0x6371,
+    0x637a,0x638e,0x63b4,0x636d,0x63ac,0x638a,0x6369,0x63ae,0x63bc,0x63f2,
+    0x63f8,0x63e0,0x63ff,0x63c4,0x63de,0x63ce,0x6452,0x63c6,0x63be,0x6445,
+    0x6441,0x640b,0x641b,0x6420,0x640c,0x6426,0x6421,0x645e,0x6484,0x646d,
+    0x6496
+  },
+  {				/* ku 5f */
+    0x9019,0x901c,0x9023,0x9024,0x9025,0x9027,0x9028,0x9029,0x902a,0x902b,
+    0x902c,0x9030,0x9031,0x9032,0x9033,0x9034,0x9037,0x9039,0x903a,0x903d,
+    0x903f,0x9040,0x9043,0x9045,0x9046,0x9048,0x9049,0x904a,0x904b,0x904c,
+    0x904e,0x9054,0x9055,0x9056,0x9059,0x905a,0x905c,0x905d,0x905e,0x905f,
+    0x9060,0x9061,0x9064,0x9066,0x9067,0x9069,0x906a,0x906b,0x906c,0x906f,
+    0x9070,0x9071,0x9072,0x9073,0x9076,0x9077,0x9078,0x9079,0x907a,0x907b,
+    0x907c,0x907e,0x9081,UBOGON,0x9084,0x9085,0x9086,0x9087,0x9089,0x908a,
+    0x908c,0x908d,0x908e,0x908f,0x9090,0x9092,0x9094,0x9096,0x9098,0x909a,
+    0x909c,0x909e,0x909f,0x90a0,0x90a4,0x90a5,0x90a7,0x90a8,0x90a9,0x90ab,
+    0x90ad,0x90b2,0x90b7,0x90bc,0x90bd,0x90bf,0x90c0,0x647a,0x64b7,0x64b8,
+    0x6499,0x64ba,0x64c0,0x64d0,0x64d7,0x64e4,0x64e2,0x6509,0x6525,0x652e,
+    0x5f0b,0x5fd2,0x7519,0x5f11,0x535f,0x53f1,0x53fd,0x53e9,0x53e8,0x53fb,
+    0x5412,0x5416,0x5406,0x544b,0x5452,0x5453,0x5454,0x5456,0x5443,0x5421,
+    0x5457,0x5459,0x5423,0x5432,0x5482,0x5494,0x5477,0x5471,0x5464,0x549a,
+    0x549b,0x5484,0x5476,0x5466,0x549d,0x54d0,0x54ad,0x54c2,0x54b4,0x54d2,
+    0x54a7,0x54a6,0x54d3,0x54d4,0x5472,0x54a3,0x54d5,0x54bb,0x54bf,0x54cc,
+    0x54d9,0x54da,0x54dc,0x54a9,0x54aa,0x54a4,0x54dd,0x54cf,0x54de,0x551b,
+    0x54e7,0x5520,0x54fd,0x5514,0x54f3,0x5522,0x5523,0x550f,0x5511,0x5527,
+    0x552a,0x5567,0x558f,0x55b5,0x5549,0x556d,0x5541,0x5555,0x553f,0x5550,
+    0x553c
+  },
+  {				/* ku 60 */
+    0x90c2,0x90c3,0x90c6,0x90c8,0x90c9,0x90cb,0x90cc,0x90cd,0x90d2,0x90d4,
+    0x90d5,0x90d6,0x90d8,0x90d9,0x90da,0x90de,0x90df,0x90e0,0x90e3,0x90e4,
+    0x90e5,0x90e9,0x90ea,0x90ec,0x90ee,0x90f0,0x90f1,0x90f2,0x90f3,0x90f5,
+    0x90f6,0x90f7,0x90f9,0x90fa,0x90fb,0x90fc,0x90ff,0x9100,0x9101,0x9103,
+    0x9105,0x9106,0x9107,0x9108,0x9109,0x910a,0x910b,0x910c,0x910d,0x910e,
+    0x910f,0x9110,0x9111,0x9112,0x9113,0x9114,0x9115,0x9116,0x9117,0x9118,
+    0x911a,0x911b,0x911c,UBOGON,0x911d,0x911f,0x9120,0x9121,0x9124,0x9125,
+    0x9126,0x9127,0x9128,0x9129,0x912a,0x912b,0x912c,0x912d,0x912e,0x9130,
+    0x9132,0x9133,0x9134,0x9135,0x9136,0x9137,0x9138,0x913a,0x913b,0x913c,
+    0x913d,0x913e,0x913f,0x9140,0x9141,0x9142,0x9144,0x5537,0x5556,0x5575,
+    0x5576,0x5577,0x5533,0x5530,0x555c,0x558b,0x55d2,0x5583,0x55b1,0x55b9,
+    0x5588,0x5581,0x559f,0x557e,0x55d6,0x5591,0x557b,0x55df,0x55bd,0x55be,
+    0x5594,0x5599,0x55ea,0x55f7,0x55c9,0x561f,0x55d1,0x55eb,0x55ec,0x55d4,
+    0x55e6,0x55dd,0x55c4,0x55ef,0x55e5,0x55f2,0x55f3,0x55cc,0x55cd,0x55e8,
+    0x55f5,0x55e4,0x8f94,0x561e,0x5608,0x560c,0x5601,0x5624,0x5623,0x55fe,
+    0x5600,0x5627,0x562d,0x5658,0x5639,0x5657,0x562c,0x564d,0x5662,0x5659,
+    0x565c,0x564c,0x5654,0x5686,0x5664,0x5671,0x566b,0x567b,0x567c,0x5685,
+    0x5693,0x56af,0x56d4,0x56d7,0x56dd,0x56e1,0x56f5,0x56eb,0x56f9,0x56ff,
+    0x5704,0x570a,0x5709,0x571c,0x5e0f,0x5e19,0x5e14,0x5e11,0x5e31,0x5e3b,
+    0x5e3c
+  },
+  {				/* ku 61 */
+    0x9145,0x9147,0x9148,0x9151,0x9153,0x9154,0x9155,0x9156,0x9158,0x9159,
+    0x915b,0x915c,0x915f,0x9160,0x9166,0x9167,0x9168,0x916b,0x916d,0x9173,
+    0x917a,0x917b,0x917c,0x9180,0x9181,0x9182,0x9183,0x9184,0x9186,0x9188,
+    0x918a,0x918e,0x918f,0x9193,0x9194,0x9195,0x9196,0x9197,0x9198,0x9199,
+    0x919c,0x919d,0x919e,0x919f,0x91a0,0x91a1,0x91a4,0x91a5,0x91a6,0x91a7,
+    0x91a8,0x91a9,0x91ab,0x91ac,0x91b0,0x91b1,0x91b2,0x91b3,0x91b6,0x91b7,
+    0x91b8,0x91b9,0x91bb,UBOGON,0x91bc,0x91bd,0x91be,0x91bf,0x91c0,0x91c1,
+    0x91c2,0x91c3,0x91c4,0x91c5,0x91c6,0x91c8,0x91cb,0x91d0,0x91d2,0x91d3,
+    0x91d4,0x91d5,0x91d6,0x91d7,0x91d8,0x91d9,0x91da,0x91db,0x91dd,0x91de,
+    0x91df,0x91e0,0x91e1,0x91e2,0x91e3,0x91e4,0x91e5,0x5e37,0x5e44,0x5e54,
+    0x5e5b,0x5e5e,0x5e61,0x5c8c,0x5c7a,0x5c8d,0x5c90,0x5c96,0x5c88,0x5c98,
+    0x5c99,0x5c91,0x5c9a,0x5c9c,0x5cb5,0x5ca2,0x5cbd,0x5cac,0x5cab,0x5cb1,
+    0x5ca3,0x5cc1,0x5cb7,0x5cc4,0x5cd2,0x5ce4,0x5ccb,0x5ce5,0x5d02,0x5d03,
+    0x5d27,0x5d26,0x5d2e,0x5d24,0x5d1e,0x5d06,0x5d1b,0x5d58,0x5d3e,0x5d34,
+    0x5d3d,0x5d6c,0x5d5b,0x5d6f,0x5d5d,0x5d6b,0x5d4b,0x5d4a,0x5d69,0x5d74,
+    0x5d82,0x5d99,0x5d9d,0x8c73,0x5db7,0x5dc5,0x5f73,0x5f77,0x5f82,0x5f87,
+    0x5f89,0x5f8c,0x5f95,0x5f99,0x5f9c,0x5fa8,0x5fad,0x5fb5,0x5fbc,0x8862,
+    0x5f61,0x72ad,0x72b0,0x72b4,0x72b7,0x72b8,0x72c3,0x72c1,0x72ce,0x72cd,
+    0x72d2,0x72e8,0x72ef,0x72e9,0x72f2,0x72f4,0x72f7,0x7301,0x72f3,0x7303,
+    0x72fa
+  },
+  {				/* ku 62 */
+    0x91e6,0x91e7,0x91e8,0x91e9,0x91ea,0x91eb,0x91ec,0x91ed,0x91ee,0x91ef,
+    0x91f0,0x91f1,0x91f2,0x91f3,0x91f4,0x91f5,0x91f6,0x91f7,0x91f8,0x91f9,
+    0x91fa,0x91fb,0x91fc,0x91fd,0x91fe,0x91ff,0x9200,0x9201,0x9202,0x9203,
+    0x9204,0x9205,0x9206,0x9207,0x9208,0x9209,0x920a,0x920b,0x920c,0x920d,
+    0x920e,0x920f,0x9210,0x9211,0x9212,0x9213,0x9214,0x9215,0x9216,0x9217,
+    0x9218,0x9219,0x921a,0x921b,0x921c,0x921d,0x921e,0x921f,0x9220,0x9221,
+    0x9222,0x9223,0x9224,UBOGON,0x9225,0x9226,0x9227,0x9228,0x9229,0x922a,
+    0x922b,0x922c,0x922d,0x922e,0x922f,0x9230,0x9231,0x9232,0x9233,0x9234,
+    0x9235,0x9236,0x9237,0x9238,0x9239,0x923a,0x923b,0x923c,0x923d,0x923e,
+    0x923f,0x9240,0x9241,0x9242,0x9243,0x9244,0x9245,0x72fb,0x7317,0x7313,
+    0x7321,0x730a,0x731e,0x731d,0x7315,0x7322,0x7339,0x7325,0x732c,0x7338,
+    0x7331,0x7350,0x734d,0x7357,0x7360,0x736c,0x736f,0x737e,0x821b,0x5925,
+    0x98e7,0x5924,0x5902,0x9963,0x9967,0x9968,0x9969,0x996a,0x996b,0x996c,
+    0x9974,0x9977,0x997d,0x9980,0x9984,0x9987,0x998a,0x998d,0x9990,0x9991,
+    0x9993,0x9994,0x9995,0x5e80,0x5e91,0x5e8b,0x5e96,0x5ea5,0x5ea0,0x5eb9,
+    0x5eb5,0x5ebe,0x5eb3,0x8d53,0x5ed2,0x5ed1,0x5edb,0x5ee8,0x5eea,0x81ba,
+    0x5fc4,0x5fc9,0x5fd6,0x5fcf,0x6003,0x5fee,0x6004,0x5fe1,0x5fe4,0x5ffe,
+    0x6005,0x6006,0x5fea,0x5fed,0x5ff8,0x6019,0x6035,0x6026,0x601b,0x600f,
+    0x600d,0x6029,0x602b,0x600a,0x603f,0x6021,0x6078,0x6079,0x607b,0x607a,
+    0x6042
+  },
+  {				/* ku 63 */
+    0x9246,0x9247,0x9248,0x9249,0x924a,0x924b,0x924c,0x924d,0x924e,0x924f,
+    0x9250,0x9251,0x9252,0x9253,0x9254,0x9255,0x9256,0x9257,0x9258,0x9259,
+    0x925a,0x925b,0x925c,0x925d,0x925e,0x925f,0x9260,0x9261,0x9262,0x9263,
+    0x9264,0x9265,0x9266,0x9267,0x9268,0x9269,0x926a,0x926b,0x926c,0x926d,
+    0x926e,0x926f,0x9270,0x9271,0x9272,0x9273,0x9275,0x9276,0x9277,0x9278,
+    0x9279,0x927a,0x927b,0x927c,0x927d,0x927e,0x927f,0x9280,0x9281,0x9282,
+    0x9283,0x9284,0x9285,UBOGON,0x9286,0x9287,0x9288,0x9289,0x928a,0x928b,
+    0x928c,0x928d,0x928f,0x9290,0x9291,0x9292,0x9293,0x9294,0x9295,0x9296,
+    0x9297,0x9298,0x9299,0x929a,0x929b,0x929c,0x929d,0x929e,0x929f,0x92a0,
+    0x92a1,0x92a2,0x92a3,0x92a4,0x92a5,0x92a6,0x92a7,0x606a,0x607d,0x6096,
+    0x609a,0x60ad,0x609d,0x6083,0x6092,0x608c,0x609b,0x60ec,0x60bb,0x60b1,
+    0x60dd,0x60d8,0x60c6,0x60da,0x60b4,0x6120,0x6126,0x6115,0x6123,0x60f4,
+    0x6100,0x610e,0x612b,0x614a,0x6175,0x61ac,0x6194,0x61a7,0x61b7,0x61d4,
+    0x61f5,0x5fdd,0x96b3,0x95e9,0x95eb,0x95f1,0x95f3,0x95f5,0x95f6,0x95fc,
+    0x95fe,0x9603,0x9604,0x9606,0x9608,0x960a,0x960b,0x960c,0x960d,0x960f,
+    0x9612,0x9615,0x9616,0x9617,0x9619,0x961a,0x4e2c,0x723f,0x6215,0x6c35,
+    0x6c54,0x6c5c,0x6c4a,0x6ca3,0x6c85,0x6c90,0x6c94,0x6c8c,0x6c68,0x6c69,
+    0x6c74,0x6c76,0x6c86,0x6ca9,0x6cd0,0x6cd4,0x6cad,0x6cf7,0x6cf8,0x6cf1,
+    0x6cd7,0x6cb2,0x6ce0,0x6cd6,0x6cfa,0x6ceb,0x6cee,0x6cb1,0x6cd3,0x6cef,
+    0x6cfe
+  },
+  {				/* ku 64 */
+    0x92a8,0x92a9,0x92aa,0x92ab,0x92ac,0x92ad,0x92af,0x92b0,0x92b1,0x92b2,
+    0x92b3,0x92b4,0x92b5,0x92b6,0x92b7,0x92b8,0x92b9,0x92ba,0x92bb,0x92bc,
+    0x92bd,0x92be,0x92bf,0x92c0,0x92c1,0x92c2,0x92c3,0x92c4,0x92c5,0x92c6,
+    0x92c7,0x92c9,0x92ca,0x92cb,0x92cc,0x92cd,0x92ce,0x92cf,0x92d0,0x92d1,
+    0x92d2,0x92d3,0x92d4,0x92d5,0x92d6,0x92d7,0x92d8,0x92d9,0x92da,0x92db,
+    0x92dc,0x92dd,0x92de,0x92df,0x92e0,0x92e1,0x92e2,0x92e3,0x92e4,0x92e5,
+    0x92e6,0x92e7,0x92e8,UBOGON,0x92e9,0x92ea,0x92eb,0x92ec,0x92ed,0x92ee,
+    0x92ef,0x92f0,0x92f1,0x92f2,0x92f3,0x92f4,0x92f5,0x92f6,0x92f7,0x92f8,
+    0x92f9,0x92fa,0x92fb,0x92fc,0x92fd,0x92fe,0x92ff,0x9300,0x9301,0x9302,
+    0x9303,0x9304,0x9305,0x9306,0x9307,0x9308,0x9309,0x6d39,0x6d27,0x6d0c,
+    0x6d43,0x6d48,0x6d07,0x6d04,0x6d19,0x6d0e,0x6d2b,0x6d4d,0x6d2e,0x6d35,
+    0x6d1a,0x6d4f,0x6d52,0x6d54,0x6d33,0x6d91,0x6d6f,0x6d9e,0x6da0,0x6d5e,
+    0x6d93,0x6d94,0x6d5c,0x6d60,0x6d7c,0x6d63,0x6e1a,0x6dc7,0x6dc5,0x6dde,
+    0x6e0e,0x6dbf,0x6de0,0x6e11,0x6de6,0x6ddd,0x6dd9,0x6e16,0x6dab,0x6e0c,
+    0x6dae,0x6e2b,0x6e6e,0x6e4e,0x6e6b,0x6eb2,0x6e5f,0x6e86,0x6e53,0x6e54,
+    0x6e32,0x6e25,0x6e44,0x6edf,0x6eb1,0x6e98,0x6ee0,0x6f2d,0x6ee2,0x6ea5,
+    0x6ea7,0x6ebd,0x6ebb,0x6eb7,0x6ed7,0x6eb4,0x6ecf,0x6e8f,0x6ec2,0x6e9f,
+    0x6f62,0x6f46,0x6f47,0x6f24,0x6f15,0x6ef9,0x6f2f,0x6f36,0x6f4b,0x6f74,
+    0x6f2a,0x6f09,0x6f29,0x6f89,0x6f8d,0x6f8c,0x6f78,0x6f72,0x6f7c,0x6f7a,
+    0x6fd1
+  },
+  {				/* ku 65 */
+    0x930a,0x930b,0x930c,0x930d,0x930e,0x930f,0x9310,0x9311,0x9312,0x9313,
+    0x9314,0x9315,0x9316,0x9317,0x9318,0x9319,0x931a,0x931b,0x931c,0x931d,
+    0x931e,0x931f,0x9320,0x9321,0x9322,0x9323,0x9324,0x9325,0x9326,0x9327,
+    0x9328,0x9329,0x932a,0x932b,0x932c,0x932d,0x932e,0x932f,0x9330,0x9331,
+    0x9332,0x9333,0x9334,0x9335,0x9336,0x9337,0x9338,0x9339,0x933a,0x933b,
+    0x933c,0x933d,0x933f,0x9340,0x9341,0x9342,0x9343,0x9344,0x9345,0x9346,
+    0x9347,0x9348,0x9349,UBOGON,0x934a,0x934b,0x934c,0x934d,0x934e,0x934f,
+    0x9350,0x9351,0x9352,0x9353,0x9354,0x9355,0x9356,0x9357,0x9358,0x9359,
+    0x935a,0x935b,0x935c,0x935d,0x935e,0x935f,0x9360,0x9361,0x9362,0x9363,
+    0x9364,0x9365,0x9366,0x9367,0x9368,0x9369,0x936b,0x6fc9,0x6fa7,0x6fb9,
+    0x6fb6,0x6fc2,0x6fe1,0x6fee,0x6fde,0x6fe0,0x6fef,0x701a,0x7023,0x701b,
+    0x7039,0x7035,0x704f,0x705e,0x5b80,0x5b84,0x5b95,0x5b93,0x5ba5,0x5bb8,
+    0x752f,0x9a9e,0x6434,0x5be4,0x5bee,0x8930,0x5bf0,0x8e47,0x8b07,0x8fb6,
+    0x8fd3,0x8fd5,0x8fe5,0x8fee,0x8fe4,0x8fe9,0x8fe6,0x8ff3,0x8fe8,0x9005,
+    0x9004,0x900b,0x9026,0x9011,0x900d,0x9016,0x9021,0x9035,0x9036,0x902d,
+    0x902f,0x9044,0x9051,0x9052,0x9050,0x9068,0x9058,0x9062,0x905b,0x66b9,
+    0x9074,0x907d,0x9082,0x9088,0x9083,0x908b,0x5f50,0x5f57,0x5f56,0x5f58,
+    0x5c3b,0x54ab,0x5c50,0x5c59,0x5b71,0x5c63,0x5c66,0x7fbc,0x5f2a,0x5f29,
+    0x5f2d,0x8274,0x5f3c,0x9b3b,0x5c6e,0x5981,0x5983,0x598d,0x59a9,0x59aa,
+    0x59a3
+  },
+  {				/* ku 66 */
+    0x936c,0x936d,0x936e,0x936f,0x9370,0x9371,0x9372,0x9373,0x9374,0x9375,
+    0x9376,0x9377,0x9378,0x9379,0x937a,0x937b,0x937c,0x937d,0x937e,0x937f,
+    0x9380,0x9381,0x9382,0x9383,0x9384,0x9385,0x9386,0x9387,0x9388,0x9389,
+    0x938a,0x938b,0x938c,0x938d,0x938e,0x9390,0x9391,0x9392,0x9393,0x9394,
+    0x9395,0x9396,0x9397,0x9398,0x9399,0x939a,0x939b,0x939c,0x939d,0x939e,
+    0x939f,0x93a0,0x93a1,0x93a2,0x93a3,0x93a4,0x93a5,0x93a6,0x93a7,0x93a8,
+    0x93a9,0x93aa,0x93ab,UBOGON,0x93ac,0x93ad,0x93ae,0x93af,0x93b0,0x93b1,
+    0x93b2,0x93b3,0x93b4,0x93b5,0x93b6,0x93b7,0x93b8,0x93b9,0x93ba,0x93bb,
+    0x93bc,0x93bd,0x93be,0x93bf,0x93c0,0x93c1,0x93c2,0x93c3,0x93c4,0x93c5,
+    0x93c6,0x93c7,0x93c8,0x93c9,0x93cb,0x93cc,0x93cd,0x5997,0x59ca,0x59ab,
+    0x599e,0x59a4,0x59d2,0x59b2,0x59af,0x59d7,0x59be,0x5a05,0x5a06,0x59dd,
+    0x5a08,0x59e3,0x59d8,0x59f9,0x5a0c,0x5a09,0x5a32,0x5a34,0x5a11,0x5a23,
+    0x5a13,0x5a40,0x5a67,0x5a4a,0x5a55,0x5a3c,0x5a62,0x5a75,0x80ec,0x5aaa,
+    0x5a9b,0x5a77,0x5a7a,0x5abe,0x5aeb,0x5ab2,0x5ad2,0x5ad4,0x5ab8,0x5ae0,
+    0x5ae3,0x5af1,0x5ad6,0x5ae6,0x5ad8,0x5adc,0x5b09,0x5b17,0x5b16,0x5b32,
+    0x5b37,0x5b40,0x5c15,0x5c1c,0x5b5a,0x5b65,0x5b73,0x5b51,0x5b53,0x5b62,
+    0x9a75,0x9a77,0x9a78,0x9a7a,0x9a7f,0x9a7d,0x9a80,0x9a81,0x9a85,0x9a88,
+    0x9a8a,0x9a90,0x9a92,0x9a93,0x9a96,0x9a98,0x9a9b,0x9a9c,0x9a9d,0x9a9f,
+    0x9aa0,0x9aa2,0x9aa3,0x9aa5,0x9aa7,0x7e9f,0x7ea1,0x7ea3,0x7ea5,0x7ea8,
+    0x7ea9
+  },
+  {				/* ku 67 */
+    0x93ce,0x93cf,0x93d0,0x93d1,0x93d2,0x93d3,0x93d4,0x93d5,0x93d7,0x93d8,
+    0x93d9,0x93da,0x93db,0x93dc,0x93dd,0x93de,0x93df,0x93e0,0x93e1,0x93e2,
+    0x93e3,0x93e4,0x93e5,0x93e6,0x93e7,0x93e8,0x93e9,0x93ea,0x93eb,0x93ec,
+    0x93ed,0x93ee,0x93ef,0x93f0,0x93f1,0x93f2,0x93f3,0x93f4,0x93f5,0x93f6,
+    0x93f7,0x93f8,0x93f9,0x93fa,0x93fb,0x93fc,0x93fd,0x93fe,0x93ff,0x9400,
+    0x9401,0x9402,0x9403,0x9404,0x9405,0x9406,0x9407,0x9408,0x9409,0x940a,
+    0x940b,0x940c,0x940d,UBOGON,0x940e,0x940f,0x9410,0x9411,0x9412,0x9413,
+    0x9414,0x9415,0x9416,0x9417,0x9418,0x9419,0x941a,0x941b,0x941c,0x941d,
+    0x941e,0x941f,0x9420,0x9421,0x9422,0x9423,0x9424,0x9425,0x9426,0x9427,
+    0x9428,0x9429,0x942a,0x942b,0x942c,0x942d,0x942e,0x7ead,0x7eb0,0x7ebe,
+    0x7ec0,0x7ec1,0x7ec2,0x7ec9,0x7ecb,0x7ecc,0x7ed0,0x7ed4,0x7ed7,0x7edb,
+    0x7ee0,0x7ee1,0x7ee8,0x7eeb,0x7eee,0x7eef,0x7ef1,0x7ef2,0x7f0d,0x7ef6,
+    0x7efa,0x7efb,0x7efe,0x7f01,0x7f02,0x7f03,0x7f07,0x7f08,0x7f0b,0x7f0c,
+    0x7f0f,0x7f11,0x7f12,0x7f17,0x7f19,0x7f1c,0x7f1b,0x7f1f,0x7f21,0x7f22,
+    0x7f23,0x7f24,0x7f25,0x7f26,0x7f27,0x7f2a,0x7f2b,0x7f2c,0x7f2d,0x7f2f,
+    0x7f30,0x7f31,0x7f32,0x7f33,0x7f35,0x5e7a,0x757f,0x5ddb,0x753e,0x9095,
+    0x738e,0x7391,0x73ae,0x73a2,0x739f,0x73cf,0x73c2,0x73d1,0x73b7,0x73b3,
+    0x73c0,0x73c9,0x73c8,0x73e5,0x73d9,0x987c,0x740a,0x73e9,0x73e7,0x73de,
+    0x73ba,0x73f2,0x740f,0x742a,0x745b,0x7426,0x7425,0x7428,0x7430,0x742e,
+    0x742c
+  },
+  {				/* ku 68 */
+    0x942f,0x9430,0x9431,0x9432,0x9433,0x9434,0x9435,0x9436,0x9437,0x9438,
+    0x9439,0x943a,0x943b,0x943c,0x943d,0x943f,0x9440,0x9441,0x9442,0x9443,
+    0x9444,0x9445,0x9446,0x9447,0x9448,0x9449,0x944a,0x944b,0x944c,0x944d,
+    0x944e,0x944f,0x9450,0x9451,0x9452,0x9453,0x9454,0x9455,0x9456,0x9457,
+    0x9458,0x9459,0x945a,0x945b,0x945c,0x945d,0x945e,0x945f,0x9460,0x9461,
+    0x9462,0x9463,0x9464,0x9465,0x9466,0x9467,0x9468,0x9469,0x946a,0x946c,
+    0x946d,0x946e,0x946f,UBOGON,0x9470,0x9471,0x9472,0x9473,0x9474,0x9475,
+    0x9476,0x9477,0x9478,0x9479,0x947a,0x947b,0x947c,0x947d,0x947e,0x947f,
+    0x9480,0x9481,0x9482,0x9483,0x9484,0x9491,0x9496,0x9498,0x94c7,0x94cf,
+    0x94d3,0x94d4,0x94da,0x94e6,0x94fb,0x951c,0x9520,0x741b,0x741a,0x7441,
+    0x745c,0x7457,0x7455,0x7459,0x7477,0x746d,0x747e,0x749c,0x748e,0x7480,
+    0x7481,0x7487,0x748b,0x749e,0x74a8,0x74a9,0x7490,0x74a7,0x74d2,0x74ba,
+    0x97ea,0x97eb,0x97ec,0x674c,0x6753,0x675e,0x6748,0x6769,0x67a5,0x6787,
+    0x676a,0x6773,0x6798,0x67a7,0x6775,0x67a8,0x679e,0x67ad,0x678b,0x6777,
+    0x677c,0x67f0,0x6809,0x67d8,0x680a,0x67e9,0x67b0,0x680c,0x67d9,0x67b5,
+    0x67da,0x67b3,0x67dd,0x6800,0x67c3,0x67b8,0x67e2,0x680e,0x67c1,0x67fd,
+    0x6832,0x6833,0x6860,0x6861,0x684e,0x6862,0x6844,0x6864,0x6883,0x681d,
+    0x6855,0x6866,0x6841,0x6867,0x6840,0x683e,0x684a,0x6849,0x6829,0x68b5,
+    0x688f,0x6874,0x6877,0x6893,0x686b,0x68c2,0x696e,0x68fc,0x691f,0x6920,
+    0x68f9
+  },
+  {				/* ku 69 */
+    0x9527,0x9533,0x953d,0x9543,0x9548,0x954b,0x9555,0x955a,0x9560,0x956e,
+    0x9574,0x9575,0x9577,0x9578,0x9579,0x957a,0x957b,0x957c,0x957d,0x957e,
+    0x9580,0x9581,0x9582,0x9583,0x9584,0x9585,0x9586,0x9587,0x9588,0x9589,
+    0x958a,0x958b,0x958c,0x958d,0x958e,0x958f,0x9590,0x9591,0x9592,0x9593,
+    0x9594,0x9595,0x9596,0x9597,0x9598,0x9599,0x959a,0x959b,0x959c,0x959d,
+    0x959e,0x959f,0x95a0,0x95a1,0x95a2,0x95a3,0x95a4,0x95a5,0x95a6,0x95a7,
+    0x95a8,0x95a9,0x95aa,UBOGON,0x95ab,0x95ac,0x95ad,0x95ae,0x95af,0x95b0,
+    0x95b1,0x95b2,0x95b3,0x95b4,0x95b5,0x95b6,0x95b7,0x95b8,0x95b9,0x95ba,
+    0x95bb,0x95bc,0x95bd,0x95be,0x95bf,0x95c0,0x95c1,0x95c2,0x95c3,0x95c4,
+    0x95c5,0x95c6,0x95c7,0x95c8,0x95c9,0x95ca,0x95cb,0x6924,0x68f0,0x690b,
+    0x6901,0x6957,0x68e3,0x6910,0x6971,0x6939,0x6960,0x6942,0x695d,0x6984,
+    0x696b,0x6980,0x6998,0x6978,0x6934,0x69cc,0x6987,0x6988,0x69ce,0x6989,
+    0x6966,0x6963,0x6979,0x699b,0x69a7,0x69bb,0x69ab,0x69ad,0x69d4,0x69b1,
+    0x69c1,0x69ca,0x69df,0x6995,0x69e0,0x698d,0x69ff,0x6a2f,0x69ed,0x6a17,
+    0x6a18,0x6a65,0x69f2,0x6a44,0x6a3e,0x6aa0,0x6a50,0x6a5b,0x6a35,0x6a8e,
+    0x6a79,0x6a3d,0x6a28,0x6a58,0x6a7c,0x6a91,0x6a90,0x6aa9,0x6a97,0x6aab,
+    0x7337,0x7352,0x6b81,0x6b82,0x6b87,0x6b84,0x6b92,0x6b93,0x6b8d,0x6b9a,
+    0x6b9b,0x6ba1,0x6baa,0x8f6b,0x8f6d,0x8f71,0x8f72,0x8f73,0x8f75,0x8f76,
+    0x8f78,0x8f77,0x8f79,0x8f7a,0x8f7c,0x8f7e,0x8f81,0x8f82,0x8f84,0x8f87,
+    0x8f8b
+  },
+  {				/* ku 6a */
+    0x95cc,0x95cd,0x95ce,0x95cf,0x95d0,0x95d1,0x95d2,0x95d3,0x95d4,0x95d5,
+    0x95d6,0x95d7,0x95d8,0x95d9,0x95da,0x95db,0x95dc,0x95dd,0x95de,0x95df,
+    0x95e0,0x95e1,0x95e2,0x95e3,0x95e4,0x95e5,0x95e6,0x95e7,0x95ec,0x95ff,
+    0x9607,0x9613,0x9618,0x961b,0x961e,0x9620,0x9623,0x9624,0x9625,0x9626,
+    0x9627,0x9628,0x9629,0x962b,0x962c,0x962d,0x962f,0x9630,0x9637,0x9638,
+    0x9639,0x963a,0x963e,0x9641,0x9643,0x964a,0x964e,0x964f,0x9651,0x9652,
+    0x9653,0x9656,0x9657,UBOGON,0x9658,0x9659,0x965a,0x965c,0x965d,0x965e,
+    0x9660,0x9663,0x9665,0x9666,0x966b,0x966d,0x966e,0x966f,0x9670,0x9671,
+    0x9673,0x9678,0x9679,0x967a,0x967b,0x967c,0x967d,0x967e,0x967f,0x9680,
+    0x9681,0x9682,0x9683,0x9684,0x9687,0x9689,0x968a,0x8f8d,0x8f8e,0x8f8f,
+    0x8f98,0x8f9a,0x8ece,0x620b,0x6217,0x621b,0x621f,0x6222,0x6221,0x6225,
+    0x6224,0x622c,0x81e7,0x74ef,0x74f4,0x74ff,0x750f,0x7511,0x7513,0x6534,
+    0x65ee,0x65ef,0x65f0,0x660a,0x6619,0x6772,0x6603,0x6615,0x6600,0x7085,
+    0x66f7,0x661d,0x6634,0x6631,0x6636,0x6635,0x8006,0x665f,0x6654,0x6641,
+    0x664f,0x6656,0x6661,0x6657,0x6677,0x6684,0x668c,0x66a7,0x669d,0x66be,
+    0x66db,0x66dc,0x66e6,0x66e9,0x8d32,0x8d33,0x8d36,0x8d3b,0x8d3d,0x8d40,
+    0x8d45,0x8d46,0x8d48,0x8d49,0x8d47,0x8d4d,0x8d55,0x8d59,0x89c7,0x89ca,
+    0x89cb,0x89cc,0x89ce,0x89cf,0x89d0,0x89d1,0x726e,0x729f,0x725d,0x7266,
+    0x726f,0x727e,0x727f,0x7284,0x728b,0x728d,0x728f,0x7292,0x6308,0x6332,
+    0x63b0
+  },
+  {				/* ku 6b */
+    0x968c,0x968e,0x9691,0x9692,0x9693,0x9695,0x9696,0x969a,0x969b,0x969d,
+    0x969e,0x969f,0x96a0,0x96a1,0x96a2,0x96a3,0x96a4,0x96a5,0x96a6,0x96a8,
+    0x96a9,0x96aa,0x96ab,0x96ac,0x96ad,0x96ae,0x96af,0x96b1,0x96b2,0x96b4,
+    0x96b5,0x96b7,0x96b8,0x96ba,0x96bb,0x96bf,0x96c2,0x96c3,0x96c8,0x96ca,
+    0x96cb,0x96d0,0x96d1,0x96d3,0x96d4,0x96d6,0x96d7,0x96d8,0x96d9,0x96da,
+    0x96db,0x96dc,0x96dd,0x96de,0x96df,0x96e1,0x96e2,0x96e3,0x96e4,0x96e5,
+    0x96e6,0x96e7,0x96eb,UBOGON,0x96ec,0x96ed,0x96ee,0x96f0,0x96f1,0x96f2,
+    0x96f4,0x96f5,0x96f8,0x96fa,0x96fb,0x96fc,0x96fd,0x96ff,0x9702,0x9703,
+    0x9705,0x970a,0x970b,0x970c,0x9710,0x9711,0x9712,0x9714,0x9715,0x9717,
+    0x9718,0x9719,0x971a,0x971b,0x971d,0x971f,0x9720,0x643f,0x64d8,0x8004,
+    0x6bea,0x6bf3,0x6bfd,0x6bf5,0x6bf9,0x6c05,0x6c07,0x6c06,0x6c0d,0x6c15,
+    0x6c18,0x6c19,0x6c1a,0x6c21,0x6c29,0x6c24,0x6c2a,0x6c32,0x6535,0x6555,
+    0x656b,0x724d,0x7252,0x7256,0x7230,0x8662,0x5216,0x809f,0x809c,0x8093,
+    0x80bc,0x670a,0x80bd,0x80b1,0x80ab,0x80ad,0x80b4,0x80b7,0x80e7,0x80e8,
+    0x80e9,0x80ea,0x80db,0x80c2,0x80c4,0x80d9,0x80cd,0x80d7,0x6710,0x80dd,
+    0x80eb,0x80f1,0x80f4,0x80ed,0x810d,0x810e,0x80f2,0x80fc,0x6715,0x8112,
+    0x8c5a,0x8136,0x811e,0x812c,0x8118,0x8132,0x8148,0x814c,0x8153,0x8174,
+    0x8159,0x815a,0x8171,0x8160,0x8169,0x817c,0x817d,0x816d,0x8167,0x584d,
+    0x5ab5,0x8188,0x8182,0x8191,0x6ed5,0x81a3,0x81aa,0x81cc,0x6726,0x81ca,
+    0x81bb
+  },
+  {				/* ku 6c */
+    0x9721,0x9722,0x9723,0x9724,0x9725,0x9726,0x9727,0x9728,0x9729,0x972b,
+    0x972c,0x972e,0x972f,0x9731,0x9733,0x9734,0x9735,0x9736,0x9737,0x973a,
+    0x973b,0x973c,0x973d,0x973f,0x9740,0x9741,0x9742,0x9743,0x9744,0x9745,
+    0x9746,0x9747,0x9748,0x9749,0x974a,0x974b,0x974c,0x974d,0x974e,0x974f,
+    0x9750,0x9751,0x9754,0x9755,0x9757,0x9758,0x975a,0x975c,0x975d,0x975f,
+    0x9763,0x9764,0x9766,0x9767,0x9768,0x976a,0x976b,0x976c,0x976d,0x976e,
+    0x976f,0x9770,0x9771,UBOGON,0x9772,0x9775,0x9777,0x9778,0x9779,0x977a,
+    0x977b,0x977d,0x977e,0x977f,0x9780,0x9781,0x9782,0x9783,0x9784,0x9786,
+    0x9787,0x9788,0x9789,0x978a,0x978c,0x978e,0x978f,0x9790,0x9793,0x9795,
+    0x9796,0x9797,0x9799,0x979a,0x979b,0x979c,0x979d,0x81c1,0x81a6,0x6b24,
+    0x6b37,0x6b39,0x6b43,0x6b46,0x6b59,0x98d1,0x98d2,0x98d3,0x98d5,0x98d9,
+    0x98da,0x6bb3,0x5f40,0x6bc2,0x89f3,0x6590,0x9f51,0x6593,0x65bc,0x65c6,
+    0x65c4,0x65c3,0x65cc,0x65ce,0x65d2,0x65d6,0x7080,0x709c,0x7096,0x709d,
+    0x70bb,0x70c0,0x70b7,0x70ab,0x70b1,0x70e8,0x70ca,0x7110,0x7113,0x7116,
+    0x712f,0x7131,0x7173,0x715c,0x7168,0x7145,0x7172,0x714a,0x7178,0x717a,
+    0x7198,0x71b3,0x71b5,0x71a8,0x71a0,0x71e0,0x71d4,0x71e7,0x71f9,0x721d,
+    0x7228,0x706c,0x7118,0x7166,0x71b9,0x623e,0x623d,0x6243,0x6248,0x6249,
+    0x793b,0x7940,0x7946,0x7949,0x795b,0x795c,0x7953,0x795a,0x7962,0x7957,
+    0x7960,0x796f,0x7967,0x797a,0x7985,0x798a,0x799a,0x79a7,0x79b3,0x5fd1,
+    0x5fd0
+  },
+  {				/* ku 6d */
+    0x979e,0x979f,0x97a1,0x97a2,0x97a4,0x97a5,0x97a6,0x97a7,0x97a8,0x97a9,
+    0x97aa,0x97ac,0x97ae,0x97b0,0x97b1,0x97b3,0x97b5,0x97b6,0x97b7,0x97b8,
+    0x97b9,0x97ba,0x97bb,0x97bc,0x97bd,0x97be,0x97bf,0x97c0,0x97c1,0x97c2,
+    0x97c3,0x97c4,0x97c5,0x97c6,0x97c7,0x97c8,0x97c9,0x97ca,0x97cb,0x97cc,
+    0x97cd,0x97ce,0x97cf,0x97d0,0x97d1,0x97d2,0x97d3,0x97d4,0x97d5,0x97d6,
+    0x97d7,0x97d8,0x97d9,0x97da,0x97db,0x97dc,0x97dd,0x97de,0x97df,0x97e0,
+    0x97e1,0x97e2,0x97e3,UBOGON,0x97e4,0x97e5,0x97e8,0x97ee,0x97ef,0x97f0,
+    0x97f1,0x97f2,0x97f4,0x97f7,0x97f8,0x97f9,0x97fa,0x97fb,0x97fc,0x97fd,
+    0x97fe,0x97ff,0x9800,0x9801,0x9802,0x9803,0x9804,0x9805,0x9806,0x9807,
+    0x9808,0x9809,0x980a,0x980b,0x980c,0x980d,0x980e,0x603c,0x605d,0x605a,
+    0x6067,0x6041,0x6059,0x6063,0x60ab,0x6106,0x610d,0x615d,0x61a9,0x619d,
+    0x61cb,0x61d1,0x6206,0x8080,0x807f,0x6c93,0x6cf6,0x6dfc,0x77f6,0x77f8,
+    0x7800,0x7809,0x7817,0x7818,0x7811,0x65ab,0x782d,0x781c,0x781d,0x7839,
+    0x783a,0x783b,0x781f,0x783c,0x7825,0x782c,0x7823,0x7829,0x784e,0x786d,
+    0x7856,0x7857,0x7826,0x7850,0x7847,0x784c,0x786a,0x789b,0x7893,0x789a,
+    0x7887,0x789c,0x78a1,0x78a3,0x78b2,0x78b9,0x78a5,0x78d4,0x78d9,0x78c9,
+    0x78ec,0x78f2,0x7905,0x78f4,0x7913,0x7924,0x791e,0x7934,0x9f9b,0x9ef9,
+    0x9efb,0x9efc,0x76f1,0x7704,0x770d,0x76f9,0x7707,0x7708,0x771a,0x7722,
+    0x7719,0x772d,0x7726,0x7735,0x7738,0x7750,0x7751,0x7747,0x7743,0x775a,
+    0x7768
+  },
+  {				/* ku 6e */
+    0x980f,0x9810,0x9811,0x9812,0x9813,0x9814,0x9815,0x9816,0x9817,0x9818,
+    0x9819,0x981a,0x981b,0x981c,0x981d,0x981e,0x981f,0x9820,0x9821,0x9822,
+    0x9823,0x9824,0x9825,0x9826,0x9827,0x9828,0x9829,0x982a,0x982b,0x982c,
+    0x982d,0x982e,0x982f,0x9830,0x9831,0x9832,0x9833,0x9834,0x9835,0x9836,
+    0x9837,0x9838,0x9839,0x983a,0x983b,0x983c,0x983d,0x983e,0x983f,0x9840,
+    0x9841,0x9842,0x9843,0x9844,0x9845,0x9846,0x9847,0x9848,0x9849,0x984a,
+    0x984b,0x984c,0x984d,UBOGON,0x984e,0x984f,0x9850,0x9851,0x9852,0x9853,
+    0x9854,0x9855,0x9856,0x9857,0x9858,0x9859,0x985a,0x985b,0x985c,0x985d,
+    0x985e,0x985f,0x9860,0x9861,0x9862,0x9863,0x9864,0x9865,0x9866,0x9867,
+    0x9868,0x9869,0x986a,0x986b,0x986c,0x986d,0x986e,0x7762,0x7765,0x777f,
+    0x778d,0x777d,0x7780,0x778c,0x7791,0x779f,0x77a0,0x77b0,0x77b5,0x77bd,
+    0x753a,0x7540,0x754e,0x754b,0x7548,0x755b,0x7572,0x7579,0x7583,0x7f58,
+    0x7f61,0x7f5f,0x8a48,0x7f68,0x7f74,0x7f71,0x7f79,0x7f81,0x7f7e,0x76cd,
+    0x76e5,0x8832,0x9485,0x9486,0x9487,0x948b,0x948a,0x948c,0x948d,0x948f,
+    0x9490,0x9494,0x9497,0x9495,0x949a,0x949b,0x949c,0x94a3,0x94a4,0x94ab,
+    0x94aa,0x94ad,0x94ac,0x94af,0x94b0,0x94b2,0x94b4,0x94b6,0x94b7,0x94b8,
+    0x94b9,0x94ba,0x94bc,0x94bd,0x94bf,0x94c4,0x94c8,0x94c9,0x94ca,0x94cb,
+    0x94cc,0x94cd,0x94ce,0x94d0,0x94d1,0x94d2,0x94d5,0x94d6,0x94d7,0x94d9,
+    0x94d8,0x94db,0x94de,0x94df,0x94e0,0x94e2,0x94e4,0x94e5,0x94e7,0x94e8,
+    0x94ea
+  },
+  {				/* ku 6f */
+    0x986f,0x9870,0x9871,0x9872,0x9873,0x9874,0x988b,0x988e,0x9892,0x9895,
+    0x9899,0x98a3,0x98a8,0x98a9,0x98aa,0x98ab,0x98ac,0x98ad,0x98ae,0x98af,
+    0x98b0,0x98b1,0x98b2,0x98b3,0x98b4,0x98b5,0x98b6,0x98b7,0x98b8,0x98b9,
+    0x98ba,0x98bb,0x98bc,0x98bd,0x98be,0x98bf,0x98c0,0x98c1,0x98c2,0x98c3,
+    0x98c4,0x98c5,0x98c6,0x98c7,0x98c8,0x98c9,0x98ca,0x98cb,0x98cc,0x98cd,
+    0x98cf,0x98d0,0x98d4,0x98d6,0x98d7,0x98db,0x98dc,0x98dd,0x98e0,0x98e1,
+    0x98e2,0x98e3,0x98e4,UBOGON,0x98e5,0x98e6,0x98e9,0x98ea,0x98eb,0x98ec,
+    0x98ed,0x98ee,0x98ef,0x98f0,0x98f1,0x98f2,0x98f3,0x98f4,0x98f5,0x98f6,
+    0x98f7,0x98f8,0x98f9,0x98fa,0x98fb,0x98fc,0x98fd,0x98fe,0x98ff,0x9900,
+    0x9901,0x9902,0x9903,0x9904,0x9905,0x9906,0x9907,0x94e9,0x94eb,0x94ee,
+    0x94ef,0x94f3,0x94f4,0x94f5,0x94f7,0x94f9,0x94fc,0x94fd,0x94ff,0x9503,
+    0x9502,0x9506,0x9507,0x9509,0x950a,0x950d,0x950e,0x950f,0x9512,0x9513,
+    0x9514,0x9515,0x9516,0x9518,0x951b,0x951d,0x951e,0x951f,0x9522,0x952a,
+    0x952b,0x9529,0x952c,0x9531,0x9532,0x9534,0x9536,0x9537,0x9538,0x953c,
+    0x953e,0x953f,0x9542,0x9535,0x9544,0x9545,0x9546,0x9549,0x954c,0x954e,
+    0x954f,0x9552,0x9553,0x9554,0x9556,0x9557,0x9558,0x9559,0x955b,0x955e,
+    0x955f,0x955d,0x9561,0x9562,0x9564,0x9565,0x9566,0x9567,0x9568,0x9569,
+    0x956a,0x956b,0x956c,0x956f,0x9571,0x9572,0x9573,0x953a,0x77e7,0x77ec,
+    0x96c9,0x79d5,0x79ed,0x79e3,0x79eb,0x7a06,0x5d47,0x7a03,0x7a02,0x7a1e,
+    0x7a14
+  },
+  {				/* ku 70 */
+    0x9908,0x9909,0x990a,0x990b,0x990c,0x990e,0x990f,0x9911,0x9912,0x9913,
+    0x9914,0x9915,0x9916,0x9917,0x9918,0x9919,0x991a,0x991b,0x991c,0x991d,
+    0x991e,0x991f,0x9920,0x9921,0x9922,0x9923,0x9924,0x9925,0x9926,0x9927,
+    0x9928,0x9929,0x992a,0x992b,0x992c,0x992d,0x992f,0x9930,0x9931,0x9932,
+    0x9933,0x9934,0x9935,0x9936,0x9937,0x9938,0x9939,0x993a,0x993b,0x993c,
+    0x993d,0x993e,0x993f,0x9940,0x9941,0x9942,0x9943,0x9944,0x9945,0x9946,
+    0x9947,0x9948,0x9949,UBOGON,0x994a,0x994b,0x994c,0x994d,0x994e,0x994f,
+    0x9950,0x9951,0x9952,0x9953,0x9956,0x9957,0x9958,0x9959,0x995a,0x995b,
+    0x995c,0x995d,0x995e,0x995f,0x9960,0x9961,0x9962,0x9964,0x9966,0x9973,
+    0x9978,0x9979,0x997b,0x997e,0x9982,0x9983,0x9989,0x7a39,0x7a37,0x7a51,
+    0x9ecf,0x99a5,0x7a70,0x7688,0x768e,0x7693,0x7699,0x76a4,0x74de,0x74e0,
+    0x752c,0x9e20,0x9e22,0x9e28,0x9e29,0x9e2a,0x9e2b,0x9e2c,0x9e32,0x9e31,
+    0x9e36,0x9e38,0x9e37,0x9e39,0x9e3a,0x9e3e,0x9e41,0x9e42,0x9e44,0x9e46,
+    0x9e47,0x9e48,0x9e49,0x9e4b,0x9e4c,0x9e4e,0x9e51,0x9e55,0x9e57,0x9e5a,
+    0x9e5b,0x9e5c,0x9e5e,0x9e63,0x9e66,0x9e67,0x9e68,0x9e69,0x9e6a,0x9e6b,
+    0x9e6c,0x9e71,0x9e6d,0x9e73,0x7592,0x7594,0x7596,0x75a0,0x759d,0x75ac,
+    0x75a3,0x75b3,0x75b4,0x75b8,0x75c4,0x75b1,0x75b0,0x75c3,0x75c2,0x75d6,
+    0x75cd,0x75e3,0x75e8,0x75e6,0x75e4,0x75eb,0x75e7,0x7603,0x75f1,0x75fc,
+    0x75ff,0x7610,0x7600,0x7605,0x760c,0x7617,0x760a,0x7625,0x7618,0x7615,
+    0x7619
+  },
+  {				/* ku 71 */
+    0x998c,0x998e,0x999a,0x999b,0x999c,0x999d,0x999e,0x999f,0x99a0,0x99a1,
+    0x99a2,0x99a3,0x99a4,0x99a6,0x99a7,0x99a9,0x99aa,0x99ab,0x99ac,0x99ad,
+    0x99ae,0x99af,0x99b0,0x99b1,0x99b2,0x99b3,0x99b4,0x99b5,0x99b6,0x99b7,
+    0x99b8,0x99b9,0x99ba,0x99bb,0x99bc,0x99bd,0x99be,0x99bf,0x99c0,0x99c1,
+    0x99c2,0x99c3,0x99c4,0x99c5,0x99c6,0x99c7,0x99c8,0x99c9,0x99ca,0x99cb,
+    0x99cc,0x99cd,0x99ce,0x99cf,0x99d0,0x99d1,0x99d2,0x99d3,0x99d4,0x99d5,
+    0x99d6,0x99d7,0x99d8,UBOGON,0x99d9,0x99da,0x99db,0x99dc,0x99dd,0x99de,
+    0x99df,0x99e0,0x99e1,0x99e2,0x99e3,0x99e4,0x99e5,0x99e6,0x99e7,0x99e8,
+    0x99e9,0x99ea,0x99eb,0x99ec,0x99ed,0x99ee,0x99ef,0x99f0,0x99f1,0x99f2,
+    0x99f3,0x99f4,0x99f5,0x99f6,0x99f7,0x99f8,0x99f9,0x761b,0x763c,0x7622,
+    0x7620,0x7640,0x762d,0x7630,0x763f,0x7635,0x7643,0x763e,0x7633,0x764d,
+    0x765e,0x7654,0x765c,0x7656,0x766b,0x766f,0x7fca,0x7ae6,0x7a78,0x7a79,
+    0x7a80,0x7a86,0x7a88,0x7a95,0x7aa6,0x7aa0,0x7aac,0x7aa8,0x7aad,0x7ab3,
+    0x8864,0x8869,0x8872,0x887d,0x887f,0x8882,0x88a2,0x88c6,0x88b7,0x88bc,
+    0x88c9,0x88e2,0x88ce,0x88e3,0x88e5,0x88f1,0x891a,0x88fc,0x88e8,0x88fe,
+    0x88f0,0x8921,0x8919,0x8913,0x891b,0x890a,0x8934,0x892b,0x8936,0x8941,
+    0x8966,0x897b,0x758b,0x80e5,0x76b2,0x76b4,0x77dc,0x8012,0x8014,0x8016,
+    0x801c,0x8020,0x8022,0x8025,0x8026,0x8027,0x8029,0x8028,0x8031,0x800b,
+    0x8035,0x8043,0x8046,0x804d,0x8052,0x8069,0x8071,0x8983,0x9878,0x9880,
+    0x9883
+  },
+  {				/* ku 72 */
+    0x99fa,0x99fb,0x99fc,0x99fd,0x99fe,0x99ff,0x9a00,0x9a01,0x9a02,0x9a03,
+    0x9a04,0x9a05,0x9a06,0x9a07,0x9a08,0x9a09,0x9a0a,0x9a0b,0x9a0c,0x9a0d,
+    0x9a0e,0x9a0f,0x9a10,0x9a11,0x9a12,0x9a13,0x9a14,0x9a15,0x9a16,0x9a17,
+    0x9a18,0x9a19,0x9a1a,0x9a1b,0x9a1c,0x9a1d,0x9a1e,0x9a1f,0x9a20,0x9a21,
+    0x9a22,0x9a23,0x9a24,0x9a25,0x9a26,0x9a27,0x9a28,0x9a29,0x9a2a,0x9a2b,
+    0x9a2c,0x9a2d,0x9a2e,0x9a2f,0x9a30,0x9a31,0x9a32,0x9a33,0x9a34,0x9a35,
+    0x9a36,0x9a37,0x9a38,UBOGON,0x9a39,0x9a3a,0x9a3b,0x9a3c,0x9a3d,0x9a3e,
+    0x9a3f,0x9a40,0x9a41,0x9a42,0x9a43,0x9a44,0x9a45,0x9a46,0x9a47,0x9a48,
+    0x9a49,0x9a4a,0x9a4b,0x9a4c,0x9a4d,0x9a4e,0x9a4f,0x9a50,0x9a51,0x9a52,
+    0x9a53,0x9a54,0x9a55,0x9a56,0x9a57,0x9a58,0x9a59,0x9889,0x988c,0x988d,
+    0x988f,0x9894,0x989a,0x989b,0x989e,0x989f,0x98a1,0x98a2,0x98a5,0x98a6,
+    0x864d,0x8654,0x866c,0x866e,0x867f,0x867a,0x867c,0x867b,0x86a8,0x868d,
+    0x868b,0x86ac,0x869d,0x86a7,0x86a3,0x86aa,0x8693,0x86a9,0x86b6,0x86c4,
+    0x86b5,0x86ce,0x86b0,0x86ba,0x86b1,0x86af,0x86c9,0x86cf,0x86b4,0x86e9,
+    0x86f1,0x86f2,0x86ed,0x86f3,0x86d0,0x8713,0x86de,0x86f4,0x86df,0x86d8,
+    0x86d1,0x8703,0x8707,0x86f8,0x8708,0x870a,0x870d,0x8709,0x8723,0x873b,
+    0x871e,0x8725,0x872e,0x871a,0x873e,0x8748,0x8734,0x8731,0x8729,0x8737,
+    0x873f,0x8782,0x8722,0x877d,0x877e,0x877b,0x8760,0x8770,0x874c,0x876e,
+    0x878b,0x8753,0x8763,0x877c,0x8764,0x8759,0x8765,0x8793,0x87af,0x87a8,
+    0x87d2
+  },
+  {				/* ku 73 */
+    0x9a5a,0x9a5b,0x9a5c,0x9a5d,0x9a5e,0x9a5f,0x9a60,0x9a61,0x9a62,0x9a63,
+    0x9a64,0x9a65,0x9a66,0x9a67,0x9a68,0x9a69,0x9a6a,0x9a6b,0x9a72,0x9a83,
+    0x9a89,0x9a8d,0x9a8e,0x9a94,0x9a95,0x9a99,0x9aa6,0x9aa9,0x9aaa,0x9aab,
+    0x9aac,0x9aad,0x9aae,0x9aaf,0x9ab2,0x9ab3,0x9ab4,0x9ab5,0x9ab9,0x9abb,
+    0x9abd,0x9abe,0x9abf,0x9ac3,0x9ac4,0x9ac6,0x9ac7,0x9ac8,0x9ac9,0x9aca,
+    0x9acd,0x9ace,0x9acf,0x9ad0,0x9ad2,0x9ad4,0x9ad5,0x9ad6,0x9ad7,0x9ad9,
+    0x9ada,0x9adb,0x9adc,UBOGON,0x9add,0x9ade,0x9ae0,0x9ae2,0x9ae3,0x9ae4,
+    0x9ae5,0x9ae7,0x9ae8,0x9ae9,0x9aea,0x9aec,0x9aee,0x9af0,0x9af1,0x9af2,
+    0x9af3,0x9af4,0x9af5,0x9af6,0x9af7,0x9af8,0x9afa,0x9afc,0x9afd,0x9afe,
+    0x9aff,0x9b00,0x9b01,0x9b02,0x9b04,0x9b05,0x9b06,0x87c6,0x8788,0x8785,
+    0x87ad,0x8797,0x8783,0x87ab,0x87e5,0x87ac,0x87b5,0x87b3,0x87cb,0x87d3,
+    0x87bd,0x87d1,0x87c0,0x87ca,0x87db,0x87ea,0x87e0,0x87ee,0x8816,0x8813,
+    0x87fe,0x880a,0x881b,0x8821,0x8839,0x883c,0x7f36,0x7f42,0x7f44,0x7f45,
+    0x8210,0x7afa,0x7afd,0x7b08,0x7b03,0x7b04,0x7b15,0x7b0a,0x7b2b,0x7b0f,
+    0x7b47,0x7b38,0x7b2a,0x7b19,0x7b2e,0x7b31,0x7b20,0x7b25,0x7b24,0x7b33,
+    0x7b3e,0x7b1e,0x7b58,0x7b5a,0x7b45,0x7b75,0x7b4c,0x7b5d,0x7b60,0x7b6e,
+    0x7b7b,0x7b62,0x7b72,0x7b71,0x7b90,0x7ba6,0x7ba7,0x7bb8,0x7bac,0x7b9d,
+    0x7ba8,0x7b85,0x7baa,0x7b9c,0x7ba2,0x7bab,0x7bb4,0x7bd1,0x7bc1,0x7bcc,
+    0x7bdd,0x7bda,0x7be5,0x7be6,0x7bea,0x7c0c,0x7bfe,0x7bfc,0x7c0f,0x7c16,
+    0x7c0b
+  },
+  {				/* ku 74 */
+    0x9b07,0x9b09,0x9b0a,0x9b0b,0x9b0c,0x9b0d,0x9b0e,0x9b10,0x9b11,0x9b12,
+    0x9b14,0x9b15,0x9b16,0x9b17,0x9b18,0x9b19,0x9b1a,0x9b1b,0x9b1c,0x9b1d,
+    0x9b1e,0x9b20,0x9b21,0x9b22,0x9b24,0x9b25,0x9b26,0x9b27,0x9b28,0x9b29,
+    0x9b2a,0x9b2b,0x9b2c,0x9b2d,0x9b2e,0x9b30,0x9b31,0x9b33,0x9b34,0x9b35,
+    0x9b36,0x9b37,0x9b38,0x9b39,0x9b3a,0x9b3d,0x9b3e,0x9b3f,0x9b40,0x9b46,
+    0x9b4a,0x9b4b,0x9b4c,0x9b4e,0x9b50,0x9b52,0x9b53,0x9b55,0x9b56,0x9b57,
+    0x9b58,0x9b59,0x9b5a,UBOGON,0x9b5b,0x9b5c,0x9b5d,0x9b5e,0x9b5f,0x9b60,
+    0x9b61,0x9b62,0x9b63,0x9b64,0x9b65,0x9b66,0x9b67,0x9b68,0x9b69,0x9b6a,
+    0x9b6b,0x9b6c,0x9b6d,0x9b6e,0x9b6f,0x9b70,0x9b71,0x9b72,0x9b73,0x9b74,
+    0x9b75,0x9b76,0x9b77,0x9b78,0x9b79,0x9b7a,0x9b7b,0x7c1f,0x7c2a,0x7c26,
+    0x7c38,0x7c41,0x7c40,0x81fe,0x8201,0x8202,0x8204,0x81ec,0x8844,0x8221,
+    0x8222,0x8223,0x822d,0x822f,0x8228,0x822b,0x8238,0x823b,0x8233,0x8234,
+    0x823e,0x8244,0x8249,0x824b,0x824f,0x825a,0x825f,0x8268,0x887e,0x8885,
+    0x8888,0x88d8,0x88df,0x895e,0x7f9d,0x7f9f,0x7fa7,0x7faf,0x7fb0,0x7fb2,
+    0x7c7c,0x6549,0x7c91,0x7c9d,0x7c9c,0x7c9e,0x7ca2,0x7cb2,0x7cbc,0x7cbd,
+    0x7cc1,0x7cc7,0x7ccc,0x7ccd,0x7cc8,0x7cc5,0x7cd7,0x7ce8,0x826e,0x66a8,
+    0x7fbf,0x7fce,0x7fd5,0x7fe5,0x7fe1,0x7fe6,0x7fe9,0x7fee,0x7ff3,0x7cf8,
+    0x7d77,0x7da6,0x7dae,0x7e47,0x7e9b,0x9eb8,0x9eb4,0x8d73,0x8d84,0x8d94,
+    0x8d91,0x8db1,0x8d67,0x8d6d,0x8c47,0x8c49,0x914a,0x9150,0x914e,0x914f,
+    0x9164
+  },
+  {				/* ku 75 */
+    0x9b7c,0x9b7d,0x9b7e,0x9b7f,0x9b80,0x9b81,0x9b82,0x9b83,0x9b84,0x9b85,
+    0x9b86,0x9b87,0x9b88,0x9b89,0x9b8a,0x9b8b,0x9b8c,0x9b8d,0x9b8e,0x9b8f,
+    0x9b90,0x9b91,0x9b92,0x9b93,0x9b94,0x9b95,0x9b96,0x9b97,0x9b98,0x9b99,
+    0x9b9a,0x9b9b,0x9b9c,0x9b9d,0x9b9e,0x9b9f,0x9ba0,0x9ba1,0x9ba2,0x9ba3,
+    0x9ba4,0x9ba5,0x9ba6,0x9ba7,0x9ba8,0x9ba9,0x9baa,0x9bab,0x9bac,0x9bad,
+    0x9bae,0x9baf,0x9bb0,0x9bb1,0x9bb2,0x9bb3,0x9bb4,0x9bb5,0x9bb6,0x9bb7,
+    0x9bb8,0x9bb9,0x9bba,UBOGON,0x9bbb,0x9bbc,0x9bbd,0x9bbe,0x9bbf,0x9bc0,
+    0x9bc1,0x9bc2,0x9bc3,0x9bc4,0x9bc5,0x9bc6,0x9bc7,0x9bc8,0x9bc9,0x9bca,
+    0x9bcb,0x9bcc,0x9bcd,0x9bce,0x9bcf,0x9bd0,0x9bd1,0x9bd2,0x9bd3,0x9bd4,
+    0x9bd5,0x9bd6,0x9bd7,0x9bd8,0x9bd9,0x9bda,0x9bdb,0x9162,0x9161,0x9170,
+    0x9169,0x916f,0x917d,0x917e,0x9172,0x9174,0x9179,0x918c,0x9185,0x9190,
+    0x918d,0x9191,0x91a2,0x91a3,0x91aa,0x91ad,0x91ae,0x91af,0x91b5,0x91b4,
+    0x91ba,0x8c55,0x9e7e,0x8db8,0x8deb,0x8e05,0x8e59,0x8e69,0x8db5,0x8dbf,
+    0x8dbc,0x8dba,0x8dc4,0x8dd6,0x8dd7,0x8dda,0x8dde,0x8dce,0x8dcf,0x8ddb,
+    0x8dc6,0x8dec,0x8df7,0x8df8,0x8de3,0x8df9,0x8dfb,0x8de4,0x8e09,0x8dfd,
+    0x8e14,0x8e1d,0x8e1f,0x8e2c,0x8e2e,0x8e23,0x8e2f,0x8e3a,0x8e40,0x8e39,
+    0x8e35,0x8e3d,0x8e31,0x8e49,0x8e41,0x8e42,0x8e51,0x8e52,0x8e4a,0x8e70,
+    0x8e76,0x8e7c,0x8e6f,0x8e74,0x8e85,0x8e8f,0x8e94,0x8e90,0x8e9c,0x8e9e,
+    0x8c78,0x8c82,0x8c8a,0x8c85,0x8c98,0x8c94,0x659b,0x89d6,0x89de,0x89da,
+    0x89dc
+  },
+  {				/* ku 76 */
+    0x9bdc,0x9bdd,0x9bde,0x9bdf,0x9be0,0x9be1,0x9be2,0x9be3,0x9be4,0x9be5,
+    0x9be6,0x9be7,0x9be8,0x9be9,0x9bea,0x9beb,0x9bec,0x9bed,0x9bee,0x9bef,
+    0x9bf0,0x9bf1,0x9bf2,0x9bf3,0x9bf4,0x9bf5,0x9bf6,0x9bf7,0x9bf8,0x9bf9,
+    0x9bfa,0x9bfb,0x9bfc,0x9bfd,0x9bfe,0x9bff,0x9c00,0x9c01,0x9c02,0x9c03,
+    0x9c04,0x9c05,0x9c06,0x9c07,0x9c08,0x9c09,0x9c0a,0x9c0b,0x9c0c,0x9c0d,
+    0x9c0e,0x9c0f,0x9c10,0x9c11,0x9c12,0x9c13,0x9c14,0x9c15,0x9c16,0x9c17,
+    0x9c18,0x9c19,0x9c1a,UBOGON,0x9c1b,0x9c1c,0x9c1d,0x9c1e,0x9c1f,0x9c20,
+    0x9c21,0x9c22,0x9c23,0x9c24,0x9c25,0x9c26,0x9c27,0x9c28,0x9c29,0x9c2a,
+    0x9c2b,0x9c2c,0x9c2d,0x9c2e,0x9c2f,0x9c30,0x9c31,0x9c32,0x9c33,0x9c34,
+    0x9c35,0x9c36,0x9c37,0x9c38,0x9c39,0x9c3a,0x9c3b,0x89e5,0x89eb,0x89ef,
+    0x8a3e,0x8b26,0x9753,0x96e9,0x96f3,0x96ef,0x9706,0x9701,0x9708,0x970f,
+    0x970e,0x972a,0x972d,0x9730,0x973e,0x9f80,0x9f83,0x9f85,0x9f86,0x9f87,
+    0x9f88,0x9f89,0x9f8a,0x9f8c,0x9efe,0x9f0b,0x9f0d,0x96b9,0x96bc,0x96bd,
+    0x96ce,0x96d2,0x77bf,0x96e0,0x928e,0x92ae,0x92c8,0x933e,0x936a,0x93ca,
+    0x938f,0x943e,0x946b,0x9c7f,0x9c82,0x9c85,0x9c86,0x9c87,0x9c88,0x7a23,
+    0x9c8b,0x9c8e,0x9c90,0x9c91,0x9c92,0x9c94,0x9c95,0x9c9a,0x9c9b,0x9c9e,
+    0x9c9f,0x9ca0,0x9ca1,0x9ca2,0x9ca3,0x9ca5,0x9ca6,0x9ca7,0x9ca8,0x9ca9,
+    0x9cab,0x9cad,0x9cae,0x9cb0,0x9cb1,0x9cb2,0x9cb3,0x9cb4,0x9cb5,0x9cb6,
+    0x9cb7,0x9cba,0x9cbb,0x9cbc,0x9cbd,0x9cc4,0x9cc5,0x9cc6,0x9cc7,0x9cca,
+    0x9ccb
+  },
+  {				/* ku 77 */
+    0x9c3c,0x9c3d,0x9c3e,0x9c3f,0x9c40,0x9c41,0x9c42,0x9c43,0x9c44,0x9c45,
+    0x9c46,0x9c47,0x9c48,0x9c49,0x9c4a,0x9c4b,0x9c4c,0x9c4d,0x9c4e,0x9c4f,
+    0x9c50,0x9c51,0x9c52,0x9c53,0x9c54,0x9c55,0x9c56,0x9c57,0x9c58,0x9c59,
+    0x9c5a,0x9c5b,0x9c5c,0x9c5d,0x9c5e,0x9c5f,0x9c60,0x9c61,0x9c62,0x9c63,
+    0x9c64,0x9c65,0x9c66,0x9c67,0x9c68,0x9c69,0x9c6a,0x9c6b,0x9c6c,0x9c6d,
+    0x9c6e,0x9c6f,0x9c70,0x9c71,0x9c72,0x9c73,0x9c74,0x9c75,0x9c76,0x9c77,
+    0x9c78,0x9c79,0x9c7a,UBOGON,0x9c7b,0x9c7d,0x9c7e,0x9c80,0x9c83,0x9c84,
+    0x9c89,0x9c8a,0x9c8c,0x9c8f,0x9c93,0x9c96,0x9c97,0x9c98,0x9c99,0x9c9d,
+    0x9caa,0x9cac,0x9caf,0x9cb9,0x9cbe,0x9cbf,0x9cc0,0x9cc1,0x9cc2,0x9cc8,
+    0x9cc9,0x9cd1,0x9cd2,0x9cda,0x9cdb,0x9ce0,0x9ce1,0x9ccc,0x9ccd,0x9cce,
+    0x9ccf,0x9cd0,0x9cd3,0x9cd4,0x9cd5,0x9cd7,0x9cd8,0x9cd9,0x9cdc,0x9cdd,
+    0x9cdf,0x9ce2,0x977c,0x9785,0x9791,0x9792,0x9794,0x97af,0x97ab,0x97a3,
+    0x97b2,0x97b4,0x9ab1,0x9ab0,0x9ab7,0x9e58,0x9ab6,0x9aba,0x9abc,0x9ac1,
+    0x9ac0,0x9ac5,0x9ac2,0x9acb,0x9acc,0x9ad1,0x9b45,0x9b43,0x9b47,0x9b49,
+    0x9b48,0x9b4d,0x9b51,0x98e8,0x990d,0x992e,0x9955,0x9954,0x9adf,0x9ae1,
+    0x9ae6,0x9aef,0x9aeb,0x9afb,0x9aed,0x9af9,0x9b08,0x9b0f,0x9b13,0x9b1f,
+    0x9b23,0x9ebd,0x9ebe,0x7e3b,0x9e82,0x9e87,0x9e88,0x9e8b,0x9e92,0x93d6,
+    0x9e9d,0x9e9f,0x9edb,0x9edc,0x9edd,0x9ee0,0x9edf,0x9ee2,0x9ee9,0x9ee7,
+    0x9ee5,0x9eea,0x9eef,0x9f22,0x9f2c,0x9f2f,0x9f39,0x9f37,0x9f3d,0x9f3e,
+    0x9f44
+  },
+  {				/* ku 78 */
+    0x9ce3,0x9ce4,0x9ce5,0x9ce6,0x9ce7,0x9ce8,0x9ce9,0x9cea,0x9ceb,0x9cec,
+    0x9ced,0x9cee,0x9cef,0x9cf0,0x9cf1,0x9cf2,0x9cf3,0x9cf4,0x9cf5,0x9cf6,
+    0x9cf7,0x9cf8,0x9cf9,0x9cfa,0x9cfb,0x9cfc,0x9cfd,0x9cfe,0x9cff,0x9d00,
+    0x9d01,0x9d02,0x9d03,0x9d04,0x9d05,0x9d06,0x9d07,0x9d08,0x9d09,0x9d0a,
+    0x9d0b,0x9d0c,0x9d0d,0x9d0e,0x9d0f,0x9d10,0x9d11,0x9d12,0x9d13,0x9d14,
+    0x9d15,0x9d16,0x9d17,0x9d18,0x9d19,0x9d1a,0x9d1b,0x9d1c,0x9d1d,0x9d1e,
+    0x9d1f,0x9d20,0x9d21,UBOGON,0x9d22,0x9d23,0x9d24,0x9d25,0x9d26,0x9d27,
+    0x9d28,0x9d29,0x9d2a,0x9d2b,0x9d2c,0x9d2d,0x9d2e,0x9d2f,0x9d30,0x9d31,
+    0x9d32,0x9d33,0x9d34,0x9d35,0x9d36,0x9d37,0x9d38,0x9d39,0x9d3a,0x9d3b,
+    0x9d3c,0x9d3d,0x9d3e,0x9d3f,0x9d40,0x9d41,0x9d42,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON
+  },
+  {				/* ku 79 */
+    0x9d43,0x9d44,0x9d45,0x9d46,0x9d47,0x9d48,0x9d49,0x9d4a,0x9d4b,0x9d4c,
+    0x9d4d,0x9d4e,0x9d4f,0x9d50,0x9d51,0x9d52,0x9d53,0x9d54,0x9d55,0x9d56,
+    0x9d57,0x9d58,0x9d59,0x9d5a,0x9d5b,0x9d5c,0x9d5d,0x9d5e,0x9d5f,0x9d60,
+    0x9d61,0x9d62,0x9d63,0x9d64,0x9d65,0x9d66,0x9d67,0x9d68,0x9d69,0x9d6a,
+    0x9d6b,0x9d6c,0x9d6d,0x9d6e,0x9d6f,0x9d70,0x9d71,0x9d72,0x9d73,0x9d74,
+    0x9d75,0x9d76,0x9d77,0x9d78,0x9d79,0x9d7a,0x9d7b,0x9d7c,0x9d7d,0x9d7e,
+    0x9d7f,0x9d80,0x9d81,UBOGON,0x9d82,0x9d83,0x9d84,0x9d85,0x9d86,0x9d87,
+    0x9d88,0x9d89,0x9d8a,0x9d8b,0x9d8c,0x9d8d,0x9d8e,0x9d8f,0x9d90,0x9d91,
+    0x9d92,0x9d93,0x9d94,0x9d95,0x9d96,0x9d97,0x9d98,0x9d99,0x9d9a,0x9d9b,
+    0x9d9c,0x9d9d,0x9d9e,0x9d9f,0x9da0,0x9da1,0x9da2,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON
+  },
+  {				/* ku 7a */
+    0x9da3,0x9da4,0x9da5,0x9da6,0x9da7,0x9da8,0x9da9,0x9daa,0x9dab,0x9dac,
+    0x9dad,0x9dae,0x9daf,0x9db0,0x9db1,0x9db2,0x9db3,0x9db4,0x9db5,0x9db6,
+    0x9db7,0x9db8,0x9db9,0x9dba,0x9dbb,0x9dbc,0x9dbd,0x9dbe,0x9dbf,0x9dc0,
+    0x9dc1,0x9dc2,0x9dc3,0x9dc4,0x9dc5,0x9dc6,0x9dc7,0x9dc8,0x9dc9,0x9dca,
+    0x9dcb,0x9dcc,0x9dcd,0x9dce,0x9dcf,0x9dd0,0x9dd1,0x9dd2,0x9dd3,0x9dd4,
+    0x9dd5,0x9dd6,0x9dd7,0x9dd8,0x9dd9,0x9dda,0x9ddb,0x9ddc,0x9ddd,0x9dde,
+    0x9ddf,0x9de0,0x9de1,UBOGON,0x9de2,0x9de3,0x9de4,0x9de5,0x9de6,0x9de7,
+    0x9de8,0x9de9,0x9dea,0x9deb,0x9dec,0x9ded,0x9dee,0x9def,0x9df0,0x9df1,
+    0x9df2,0x9df3,0x9df4,0x9df5,0x9df6,0x9df7,0x9df8,0x9df9,0x9dfa,0x9dfb,
+    0x9dfc,0x9dfd,0x9dfe,0x9dff,0x9e00,0x9e01,0x9e02,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON
+  },
+  {				/* ku 7b */
+    0x9e03,0x9e04,0x9e05,0x9e06,0x9e07,0x9e08,0x9e09,0x9e0a,0x9e0b,0x9e0c,
+    0x9e0d,0x9e0e,0x9e0f,0x9e10,0x9e11,0x9e12,0x9e13,0x9e14,0x9e15,0x9e16,
+    0x9e17,0x9e18,0x9e19,0x9e1a,0x9e1b,0x9e1c,0x9e1d,0x9e1e,0x9e24,0x9e27,
+    0x9e2e,0x9e30,0x9e34,0x9e3b,0x9e3c,0x9e40,0x9e4d,0x9e50,0x9e52,0x9e53,
+    0x9e54,0x9e56,0x9e59,0x9e5d,0x9e5f,0x9e60,0x9e61,0x9e62,0x9e65,0x9e6e,
+    0x9e6f,0x9e72,0x9e74,0x9e75,0x9e76,0x9e77,0x9e78,0x9e79,0x9e7a,0x9e7b,
+    0x9e7c,0x9e7d,0x9e80,UBOGON,0x9e81,0x9e83,0x9e84,0x9e85,0x9e86,0x9e89,
+    0x9e8a,0x9e8c,0x9e8d,0x9e8e,0x9e8f,0x9e90,0x9e91,0x9e94,0x9e95,0x9e96,
+    0x9e97,0x9e98,0x9e99,0x9e9a,0x9e9b,0x9e9c,0x9e9e,0x9ea0,0x9ea1,0x9ea2,
+    0x9ea3,0x9ea4,0x9ea5,0x9ea7,0x9ea8,0x9ea9,0x9eaa,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON
+  },
+  {				/* ku 7c */
+    0x9eab,0x9eac,0x9ead,0x9eae,0x9eaf,0x9eb0,0x9eb1,0x9eb2,0x9eb3,0x9eb5,
+    0x9eb6,0x9eb7,0x9eb9,0x9eba,0x9ebc,0x9ebf,0x9ec0,0x9ec1,0x9ec2,0x9ec3,
+    0x9ec5,0x9ec6,0x9ec7,0x9ec8,0x9eca,0x9ecb,0x9ecc,0x9ed0,0x9ed2,0x9ed3,
+    0x9ed5,0x9ed6,0x9ed7,0x9ed9,0x9eda,0x9ede,0x9ee1,0x9ee3,0x9ee4,0x9ee6,
+    0x9ee8,0x9eeb,0x9eec,0x9eed,0x9eee,0x9ef0,0x9ef1,0x9ef2,0x9ef3,0x9ef4,
+    0x9ef5,0x9ef6,0x9ef7,0x9ef8,0x9efa,0x9efd,0x9eff,0x9f00,0x9f01,0x9f02,
+    0x9f03,0x9f04,0x9f05,UBOGON,0x9f06,0x9f07,0x9f08,0x9f09,0x9f0a,0x9f0c,
+    0x9f0f,0x9f11,0x9f12,0x9f14,0x9f15,0x9f16,0x9f18,0x9f1a,0x9f1b,0x9f1c,
+    0x9f1d,0x9f1e,0x9f1f,0x9f21,0x9f23,0x9f24,0x9f25,0x9f26,0x9f27,0x9f28,
+    0x9f29,0x9f2a,0x9f2b,0x9f2d,0x9f2e,0x9f30,0x9f31,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON
+  },
+  {				/* ku 7d */
+    0x9f32,0x9f33,0x9f34,0x9f35,0x9f36,0x9f38,0x9f3a,0x9f3c,0x9f3f,0x9f40,
+    0x9f41,0x9f42,0x9f43,0x9f45,0x9f46,0x9f47,0x9f48,0x9f49,0x9f4a,0x9f4b,
+    0x9f4c,0x9f4d,0x9f4e,0x9f4f,0x9f52,0x9f53,0x9f54,0x9f55,0x9f56,0x9f57,
+    0x9f58,0x9f59,0x9f5a,0x9f5b,0x9f5c,0x9f5d,0x9f5e,0x9f5f,0x9f60,0x9f61,
+    0x9f62,0x9f63,0x9f64,0x9f65,0x9f66,0x9f67,0x9f68,0x9f69,0x9f6a,0x9f6b,
+    0x9f6c,0x9f6d,0x9f6e,0x9f6f,0x9f70,0x9f71,0x9f72,0x9f73,0x9f74,0x9f75,
+    0x9f76,0x9f77,0x9f78,UBOGON,0x9f79,0x9f7a,0x9f7b,0x9f7c,0x9f7d,0x9f7e,
+    0x9f81,0x9f82,0x9f8d,0x9f8e,0x9f8f,0x9f90,0x9f91,0x9f92,0x9f93,0x9f94,
+    0x9f95,0x9f96,0x9f97,0x9f98,0x9f9c,0x9f9d,0x9f9e,0x9fa1,0x9fa2,0x9fa3,
+    0x9fa4,0x9fa5,0xf92c,0xf979,0xf995,0xf9e7,0xf9f1,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON
+  }
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/charset/ibm.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,347 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	IBM conversion tables
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	4 November 2002
+ * Last Edited:	30 August 2006
+ */
+
+				/* IBM Latin US */
+static const unsigned short ibm_437tab[128] = {
+  0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7,
+  0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5,
+  0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9,
+  0x00ff,0x00d6,0x00dc,0x00a2,0x00a3,0x00a5,0x20a7,0x0192,
+  0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba,
+  0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb,
+  0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,
+  0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
+  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,
+  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
+  0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,
+  0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
+  0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,
+  0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229,
+  0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,
+  0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0
+};
+
+				/* IBM Greek */
+static const unsigned short ibm_737tab[128] = {
+  0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,0x0398,
+  0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0,
+  0x03a1,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,0x03a8,0x03a9,
+  0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8,
+  0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,0x03c0,
+  0x03c1,0x03c3,0x03c2,0x03c4,0x03c5,0x03c6,0x03c7,0x03c8,
+  0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,
+  0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
+  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,
+  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
+  0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,
+  0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
+  0x03c9,0x03ac,0x03ad,0x03ae,0x03ca,0x03af,0x03cc,0x03cd,
+  0x03cb,0x03ce,0x0386,0x0388,0x0389,0x038a,0x038c,0x038e,
+  0x038f,0x00b1,0x2265,0x2264,0x03aa,0x03ab,0x00f7,0x2248,
+  0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0
+};
+
+				/* IBM Baltic Rim */
+static const unsigned short ibm_775tab[128] = {
+  0x0106,0x00fc,0x00e9,0x0101,0x00e4,0x0123,0x00e5,0x0107,
+  0x0142,0x0113,0x0156,0x0157,0x012b,0x0179,0x00c4,0x00c5,
+  0x00c9,0x00e6,0x00c6,0x014d,0x00f6,0x0122,0x00a2,0x015a,
+  0x015b,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x00d7,0x00a4,
+  0x0100,0x012a,0x00f3,0x017b,0x017c,0x017a,0x201d,0x00a6,
+  0x00a9,0x00ae,0x00ac,0x00bd,0x00bc,0x0141,0x00ab,0x00bb,
+  0x2591,0x2592,0x2593,0x2502,0x2524,0x0104,0x010c,0x0118,
+  0x0116,0x2563,0x2551,0x2557,0x255d,0x012e,0x0160,0x2510,
+  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x0172,0x016a,
+  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x017d,
+  0x0105,0x010d,0x0119,0x0117,0x012f,0x0161,0x0173,0x016b,
+  0x017e,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
+  0x00d3,0x00df,0x014c,0x0143,0x00f5,0x00d5,0x00b5,0x0144,
+  0x0136,0x0137,0x013b,0x013c,0x0146,0x0112,0x0145,0x2019,
+  0x00ad,0x00b1,0x201c,0x00be,0x00b6,0x00a7,0x00f7,0x201e,
+  0x00b0,0x2219,0x00b7,0x00b9,0x00b3,0x00b2,0x25a0,0x00a0
+};
+
+				/* IBM Latin 1 */
+static const unsigned short ibm_850tab[128] = {
+  0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7,
+  0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5,
+  0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9,
+  0x00ff,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x00d7,0x0192,
+  0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba,
+  0x00bf,0x00ae,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb,
+  0x2591,0x2592,0x2593,0x2502,0x2524,0x00c1,0x00c2,0x00c0,
+  0x00a9,0x2563,0x2551,0x2557,0x255d,0x00a2,0x00a5,0x2510,
+  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x00e3,0x00c3,
+  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x00a4,
+  0x00f0,0x00d0,0x00ca,0x00cb,0x00c8,0x0131,0x00cd,0x00ce,
+  0x00cf,0x2518,0x250c,0x2588,0x2584,0x00a6,0x00cc,0x2580,
+  0x00d3,0x00df,0x00d4,0x00d2,0x00f5,0x00d5,0x00b5,0x00fe,
+  0x00de,0x00da,0x00db,0x00d9,0x00fd,0x00dd,0x00af,0x00b4,
+  0x00ad,0x00b1,0x2017,0x00be,0x00b6,0x00a7,0x00f7,0x00b8,
+  0x00b0,0x00a8,0x00b7,0x00b9,0x00b3,0x00b2,0x25a0,0x00a0
+};
+
+				/* IBM Latin 2 */
+static const unsigned short ibm_852tab[128] = {
+  0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x016f,0x0107,0x00e7,
+  0x0142,0x00eb,0x0150,0x0151,0x00ee,0x0179,0x00c4,0x0106,
+  0x00c9,0x0139,0x013a,0x00f4,0x00f6,0x013d,0x013e,0x015a,
+  0x015b,0x00d6,0x00dc,0x0164,0x0165,0x0141,0x00d7,0x010d,
+  0x00e1,0x00ed,0x00f3,0x00fa,0x0104,0x0105,0x017d,0x017e,
+  0x0118,0x0119,0x00ac,0x017a,0x010c,0x015f,0x00ab,0x00bb,
+  0x2591,0x2592,0x2593,0x2502,0x2524,0x00c1,0x00c2,0x011a,
+  0x015e,0x2563,0x2551,0x2557,0x255d,0x017b,0x017c,0x2510,
+  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x0102,0x0103,
+  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x00a4,
+  0x0111,0x0110,0x010e,0x00cb,0x010f,0x0147,0x00cd,0x00ce,
+  0x011b,0x2518,0x250c,0x2588,0x2584,0x0162,0x016e,0x2580,
+  0x00d3,0x00df,0x00d4,0x0143,0x0144,0x0148,0x0160,0x0161,
+  0x0154,0x00da,0x0155,0x0170,0x00fd,0x00dd,0x0163,0x00b4,
+  0x00ad,0x02dd,0x02db,0x02c7,0x02d8,0x00a7,0x00f7,0x00b8,
+  0x00b0,0x00a8,0x02d9,0x0171,0x0158,0x0159,0x25a0,0x00a0
+};
+
+				/* IBM Cyrillic */
+static const unsigned short ibm_855tab[128] = {
+  0x0452,0x0402,0x0453,0x0403,0x0451,0x0401,0x0454,0x0404,
+  0x0455,0x0405,0x0456,0x0406,0x0457,0x0407,0x0458,0x0408,
+  0x0459,0x0409,0x045a,0x040a,0x045b,0x040b,0x045c,0x040c,
+  0x045e,0x040e,0x045f,0x040f,0x044e,0x042e,0x044a,0x042a,
+  0x0430,0x0410,0x0431,0x0411,0x0446,0x0426,0x0434,0x0414,
+  0x0435,0x0415,0x0444,0x0424,0x0433,0x0413,0x00ab,0x00bb,
+  0x2591,0x2592,0x2593,0x2502,0x2524,0x0445,0x0425,0x0438,
+  0x0418,0x2563,0x2551,0x2557,0x255d,0x0439,0x0419,0x2510,
+  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x043a,0x041a,
+  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x00a4,
+  0x043b,0x041b,0x043c,0x041c,0x043d,0x041d,0x043e,0x041e,
+  0x043f,0x2518,0x250c,0x2588,0x2584,0x041f,0x044f,0x2580,
+  0x042f,0x0440,0x0420,0x0441,0x0421,0x0442,0x0422,0x0443,
+  0x0423,0x0436,0x0416,0x0432,0x0412,0x044c,0x042c,0x2116,
+  0x00ad,0x044b,0x042b,0x0437,0x0417,0x0448,0x0428,0x044d,
+  0x042d,0x0449,0x0429,0x0447,0x0427,0x00a7,0x25a0,0x00a0
+};
+
+				/* IBM Turkish */
+static const unsigned short ibm_857tab[128] = {
+  0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7,
+  0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x0131,0x00c4,0x00c5,
+  0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9,
+  0x0130,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x015e,0x015f,
+  0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x011e,0x011f,
+  0x00bf,0x00ae,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb,
+  0x2591,0x2592,0x2593,0x2502,0x2524,0x00c1,0x00c2,0x00c0,
+  0x00a9,0x2563,0x2551,0x2557,0x255d,0x00a2,0x00a5,0x2510,
+  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x00e3,0x00c3,
+  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x00a4,
+  0x00ba,0x00aa,0x00ca,0x00cb,0x00c8,UBOGON,0x00cd,0x00ce,
+  0x00cf,0x2518,0x250c,0x2588,0x2584,0x00a6,0x00cc,0x2580,
+  0x00d3,0x00df,0x00d4,0x00d2,0x00f5,0x00d5,0x00b5,UBOGON,
+  0x00d7,0x00da,0x00db,0x00d9,0x00ec,0x00ff,0x00af,0x00b4,
+  0x00ad,0x00b1,UBOGON,0x00be,0x00b6,0x00a7,0x00f7,0x00b8,
+  0x00b0,0x00a8,0x00b7,0x00b9,0x00b3,0x00b2,0x25a0,0x00a0
+};
+
+				/* IBM Portuguese */
+static const unsigned short ibm_860tab[128] = {
+  0x00c7,0x00fc,0x00e9,0x00e2,0x00e3,0x00e0,0x00c1,0x00e7,
+  0x00ea,0x00ca,0x00e8,0x00cd,0x00d4,0x00ec,0x00c3,0x00c2,
+  0x00c9,0x00c0,0x00c8,0x00f4,0x00f5,0x00f2,0x00da,0x00f9,
+  0x00cc,0x00d5,0x00dc,0x00a2,0x00a3,0x00d9,0x20a7,0x00d3,
+  0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba,
+  0x00bf,0x00d2,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb,
+  0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,
+  0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
+  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,
+  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
+  0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,
+  0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
+  0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,
+  0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229,
+  0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,
+  0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0
+};
+
+				/* IBM Icelandic */
+static const unsigned short ibm_861tab[128] = {
+  0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7,
+  0x00ea,0x00eb,0x00e8,0x00d0,0x00f0,0x00de,0x00c4,0x00c5,
+  0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00fe,0x00fb,0x00dd,
+  0x00fd,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x20a7,0x0192,
+  0x00e1,0x00ed,0x00f3,0x00fa,0x00c1,0x00cd,0x00d3,0x00da,
+  0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb,
+  0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,
+  0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
+  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,
+  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
+  0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,
+  0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
+  0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,
+  0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229,
+  0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,
+  0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0
+};
+
+				/* IBM Hebrew */
+static const unsigned short ibm_862tab[128] = {
+  0x05d0,0x05d1,0x05d2,0x05d3,0x05d4,0x05d5,0x05d6,0x05d7,
+  0x05d8,0x05d9,0x05da,0x05db,0x05dc,0x05dd,0x05de,0x05df,
+  0x05e0,0x05e1,0x05e2,0x05e3,0x05e4,0x05e5,0x05e6,0x05e7,
+  0x05e8,0x05e9,0x05ea,0x00a2,0x00a3,0x00a5,0x20a7,0x0192,
+  0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba,
+  0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb,
+  0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,
+  0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
+  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,
+  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
+  0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,
+  0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
+  0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,
+  0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229,
+  0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,
+  0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0
+};
+
+				/* IBM Canada/French */
+static const unsigned short ibm_863tab[128] = {
+  0x00c7,0x00fc,0x00e9,0x00e2,0x00c2,0x00e0,0x00b6,0x00e7,
+  0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x2017,0x00c0,0x00a7,
+  0x00c9,0x00c8,0x00ca,0x00f4,0x00cb,0x00cf,0x00fb,0x00f9,
+  0x00a4,0x00d4,0x00dc,0x00a2,0x00a3,0x00d9,0x00db,0x0192,
+  0x00a6,0x00b4,0x00f3,0x00fa,0x00a8,0x00b8,0x00b3,0x00af,
+  0x00ce,0x2310,0x00ac,0x00bd,0x00bc,0x00be,0x00ab,0x00bb,
+  0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,
+  0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
+  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,
+  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
+  0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,
+  0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
+  0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,
+  0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229,
+  0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,
+  0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0
+};
+
+				/* IBM Arabic */
+static const unsigned short ibm_864tab[128] = {
+  0x00b0,0x00b7,0x2219,0x221a,0x2592,0x2500,0x2502,0x253c,
+  0x2524,0x252c,0x251c,0x2534,0x2510,0x250c,0x2514,0x2518,
+  0x03b2,0x221e,0x03c6,0x00b1,0x00bd,0x00bc,0x2248,0x00ab,
+  0x00bb,0xfef7,0xfef8,UBOGON,UBOGON,0xfefb,0xfefc,UBOGON,
+  0x00a0,0x00ad,0xfe82,0x00a3,0x00a4,0xfe84,UBOGON,UBOGON,
+  0xfe8e,0xfe8f,0xfe95,0xfe99,0x060c,0xfe9d,0xfea1,0xfea5,
+  0x0660,0x0661,0x0662,0x0663,0x0664,0x0665,0x0666,0x0667,
+  0x0668,0x0669,0xfed1,0x061b,0xfeb1,0xfeb5,0xfeb9,0x061f,
+  0x00a2,0xfe80,0xfe81,0xfe83,0xfe85,0xfeca,0xfe8b,0xfe8d,
+  0xfe91,0xfe93,0xfe97,0xfe9b,0xfe9f,0xfea3,0xfea7,0xfea9,
+  0xfeab,0xfead,0xfeaf,0xfeb3,0xfeb7,0xfebb,0xfebf,0xfec1,
+  0xfec5,0xfecb,0xfecf,0x00a6,0x00ac,0x00f7,0x00d7,0xfec9,
+  0x0640,0xfed3,0xfed7,0xfedb,0xfedf,0xfee3,0xfee7,0xfeeb,
+  0xfeed,0xfeef,0xfef3,0xfebd,0xfecc,0xfece,0xfecd,0xfee1,
+  0xfe7d,0x0651,0xfee5,0xfee9,0xfeec,0xfef0,0xfef2,0xfed0,
+  0xfed5,0xfef5,0xfef6,0xfedd,0xfed9,0xfef1,0x25a0,UBOGON
+};
+
+				/* IBM Nordic */
+static const unsigned short ibm_865tab[128] = {
+  0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7,
+  0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5,
+  0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9,
+  0x00ff,0x00d6,0x00dc,0x00f8,0x00a3,0x00d8,0x20a7,0x0192,
+  0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba,
+  0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00a4,
+  0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,
+  0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
+  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,
+  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
+  0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,
+  0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
+  0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,
+  0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229,
+  0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,
+  0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0
+};
+
+				/* IBM Cyrillic/Russian */
+static const unsigned short ibm_866tab[128] = {
+  0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0416,0x0417,
+  0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f,
+  0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,0x0427,
+  0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f,
+  0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,0x0436,0x0437,
+  0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,0x043f,
+  0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,
+  0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
+  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,
+  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
+  0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,
+  0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
+  0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,0x0447,
+  0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,0x044f,
+  0x0401,0x0451,0x0404,0x0454,0x0407,0x0457,0x040e,0x045e,
+  0x00b0,0x2219,0x00b7,0x221a,0x2116,0x00a4,0x25a0,0x00a0
+};
+
+				/* IBM Greek 2 */
+static const unsigned short ibm_869tab[128] = {
+  UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x0386,UBOGON,
+  0x00b7,0x00ac,0x00a6,0x2018,0x2019,0x0388,0x2015,0x0389,
+  0x038a,0x03aa,0x038c,UBOGON,UBOGON,0x038e,0x03ab,0x00a9,
+  0x038f,0x00b2,0x00b3,0x03ac,0x00a3,0x03ad,0x03ae,0x03af,
+  0x03ca,0x0390,0x03cc,0x03cd,0x0391,0x0392,0x0393,0x0394,
+  0x0395,0x0396,0x0397,0x00bd,0x0398,0x0399,0x00ab,0x00bb,
+  0x2591,0x2592,0x2593,0x2502,0x2524,0x039a,0x039b,0x039c,
+  0x039d,0x2563,0x2551,0x2557,0x255d,0x039e,0x039f,0x2510,
+  0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x03a0,0x03a1,
+  0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x03a3,
+  0x03a4,0x03a5,0x03a6,0x03a7,0x03a8,0x03a9,0x03b1,0x03b2,
+  0x03b3,0x2518,0x250c,0x2588,0x2584,0x03b4,0x03b5,0x2580,
+  0x03b6,0x03b7,0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,
+  0x03be,0x03bf,0x03c0,0x03c1,0x03c3,0x03c2,0x03c4,0x0384,
+  0x00ad,0x00b1,0x03c5,0x03c6,0x03c7,0x00a7,0x03c8,0x0385,
+  0x00b0,0x00a8,0x03c9,0x03cb,0x03b0,0x03ce,0x25a0,0x00a0
+};
+
+				/* IBM Thai */
+static const unsigned short ibm_874tab[128] = {
+  0x20ac,UBOGON,UBOGON,UBOGON,UBOGON,0x2026,UBOGON,UBOGON,
+  UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+  UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
+  UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+  0x00a0,0x0e01,0x0e02,0x0e03,0x0e04,0x0e05,0x0e06,0x0e07,
+  0x0e08,0x0e09,0x0e0a,0x0e0b,0x0e0c,0x0e0d,0x0e0e,0x0e0f,
+  0x0e10,0x0e11,0x0e12,0x0e13,0x0e14,0x0e15,0x0e16,0x0e17,
+  0x0e18,0x0e19,0x0e1a,0x0e1b,0x0e1c,0x0e1d,0x0e1e,0x0e1f,
+  0x0e20,0x0e21,0x0e22,0x0e23,0x0e24,0x0e25,0x0e26,0x0e27,
+  0x0e28,0x0e29,0x0e2a,0x0e2b,0x0e2c,0x0e2d,0x0e2e,0x0e2f,
+  0x0e30,0x0e31,0x0e32,0x0e33,0x0e34,0x0e35,0x0e36,0x0e37,
+  0x0e38,0x0e39,0x0e3a,UBOGON,UBOGON,UBOGON,UBOGON,0x0e3f,
+  0x0e40,0x0e41,0x0e42,0x0e43,0x0e44,0x0e45,0x0e46,0x0e47,
+  0x0e48,0x0e49,0x0e4a,0x0e4b,0x0e4c,0x0e4d,0x0e4e,0x0e4f,
+  0x0e50,0x0e51,0x0e52,0x0e53,0x0e54,0x0e55,0x0e56,0x0e57,
+  0x0e58,0x0e59,0x0e5a,0x0e5b,UBOGON,UBOGON,UBOGON,UBOGON
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/charset/iso_8859.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,308 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	ISO-8859 conversion tables
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	3 July 1997
+ * Last Edited:	30 August 2006
+ */
+
+/* ISO-8859 conversion tables */
+
+				/* Latin-2 (East European) */
+static const unsigned short iso8859_2tab[128] = {
+  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
+  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
+  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
+  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
+  0x00a0,0x0104,0x02d8,0x0141,0x00a4,0x013d,0x015a,0x00a7,
+  0x00a8,0x0160,0x015e,0x0164,0x0179,0x00ad,0x017d,0x017b,
+  0x00b0,0x0105,0x02db,0x0142,0x00b4,0x013e,0x015b,0x02c7,
+  0x00b8,0x0161,0x015f,0x0165,0x017a,0x02dd,0x017e,0x017c,
+  0x0154,0x00c1,0x00c2,0x0102,0x00c4,0x0139,0x0106,0x00c7,
+  0x010c,0x00c9,0x0118,0x00cb,0x011a,0x00cd,0x00ce,0x010e,
+  0x0110,0x0143,0x0147,0x00d3,0x00d4,0x0150,0x00d6,0x00d7,
+  0x0158,0x016e,0x00da,0x0170,0x00dc,0x00dd,0x0162,0x00df,
+  0x0155,0x00e1,0x00e2,0x0103,0x00e4,0x013a,0x0107,0x00e7,
+  0x010d,0x00e9,0x0119,0x00eb,0x011b,0x00ed,0x00ee,0x010f,
+  0x0111,0x0144,0x0148,0x00f3,0x00f4,0x0151,0x00f6,0x00f7,
+  0x0159,0x016f,0x00fa,0x0171,0x00fc,0x00fd,0x0163,0x02d9
+};
+
+
+				/* Latin-3 (South European) */
+static const unsigned short iso8859_3tab[128] = {
+  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
+  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
+  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
+  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
+  0x00a0,0x0126,0x02d8,0x00a3,0x00a4,UBOGON,0x0124,0x00a7,
+  0x00a8,0x0130,0x015e,0x011e,0x0134,0x00ad,UBOGON,0x017b,
+  0x00b0,0x0127,0x00b2,0x00b3,0x00b4,0x00b5,0x0125,0x00b7,
+  0x00b8,0x0131,0x015f,0x011f,0x0135,0x00bd,UBOGON,0x017c,
+  0x00c0,0x00c1,0x00c2,UBOGON,0x00c4,0x010a,0x0108,0x00c7,
+  0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
+  UBOGON,0x00d1,0x00d2,0x00d3,0x00d4,0x0120,0x00d6,0x00d7,
+  0x011c,0x00d9,0x00da,0x00db,0x00dc,0x016c,0x015c,0x00df,
+  0x00e0,0x00e1,0x00e2,UBOGON,0x00e4,0x010b,0x0109,0x00e7,
+  0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef,
+  UBOGON,0x00f1,0x00f2,0x00f3,0x00f4,0x0121,0x00f6,0x00f7,
+  0x011d,0x00f9,0x00fa,0x00fb,0x00fc,0x016d,0x015d,0x02d9
+};
+
+
+				/* Latin-4 (North European) */
+static const unsigned short iso8859_4tab[128] = {
+  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
+  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
+  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
+  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
+  0x00a0,0x0104,0x0138,0x0156,0x00a4,0x0128,0x013b,0x00a7,
+  0x00a8,0x0160,0x0112,0x0122,0x0166,0x00ad,0x017d,0x00af,
+  0x00b0,0x0105,0x02db,0x0157,0x00b4,0x0129,0x013c,0x02c7,
+  0x00b8,0x0161,0x0113,0x0123,0x0167,0x014a,0x017e,0x014b,
+  0x0100,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x012e,
+  0x010c,0x00c9,0x0118,0x00cb,0x0116,0x00cd,0x00ce,0x012a,
+  0x0110,0x0145,0x014c,0x0136,0x00d4,0x00d5,0x00d6,0x00d7,
+  0x00d8,0x0172,0x00da,0x00db,0x00dc,0x0168,0x016a,0x00df,
+  0x0101,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x012f,
+  0x010d,0x00e9,0x0119,0x00eb,0x0117,0x00ed,0x00ee,0x012b,
+  0x0111,0x0146,0x014d,0x0137,0x00f4,0x00f5,0x00f6,0x00f7,
+  0x00f8,0x0173,0x00fa,0x00fb,0x00fc,0x0169,0x016b,0x02d9
+};
+
+
+				/* Cyrillic */
+static const unsigned short iso8859_5tab[128] = {
+  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
+  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
+  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
+  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
+  0x00a0,0x0401,0x0402,0x0403,0x0404,0x0405,0x0406,0x0407,
+  0x0408,0x0409,0x040a,0x040b,0x040c,0x00ad,0x040e,0x040f,
+  0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0416,0x0417,
+  0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f,
+  0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,0x0427,
+  0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f,
+  0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,0x0436,0x0437,
+  0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,0x043f,
+  0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,0x0447,
+  0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,0x044f,
+  0x2116,0x0451,0x0452,0x0453,0x0454,0x0455,0x0456,0x0457,
+  0x0458,0x0459,0x045a,0x045b,0x045c,0x00a7,0x045e,0x045f
+};
+
+
+				/* Arabic */
+static const unsigned short iso8859_6tab[128] = {
+  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
+  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
+  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
+  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
+  0x00a0,UBOGON,UBOGON,UBOGON,0x00a4,UBOGON,UBOGON,UBOGON,
+  UBOGON,UBOGON,UBOGON,UBOGON,0x060c,0x00ad,UBOGON,UBOGON,
+  UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+  UBOGON,UBOGON,UBOGON,0x061b,UBOGON,UBOGON,UBOGON,0x061f,
+  UBOGON,0x0621,0x0622,0x0623,0x0624,0x0625,0x0626,0x0627,
+  0x0628,0x0629,0x062a,0x062b,0x062c,0x062d,0x062e,0x062f,
+  0x0630,0x0631,0x0632,0x0633,0x0634,0x0635,0x0636,0x0637,
+  0x0638,0x0639,0x063a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+  0x0640,0x0641,0x0642,0x0643,0x0644,0x0645,0x0646,0x0647,
+  0x0648,0x0649,0x064a,0x064b,0x064c,0x064d,0x064e,0x064f,
+  0x0650,0x0651,0x0652,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+  UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON
+};
+
+
+				/* Greek */
+static const unsigned short iso8859_7tab[128] = {
+  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
+  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
+  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
+  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
+  0x00a0,0x2018,0x2019,0x00a3,UBOGON,UBOGON,0x00a6,0x00a7,
+  0x00a8,0x00a9,UBOGON,0x00ab,0x00ac,0x00ad,UBOGON,0x2015,
+  0x00b0,0x00b1,0x00b2,0x00b3,0x0384,0x0385,0x0386,0x00b7,
+  0x0388,0x0389,0x038a,0x00bb,0x038c,0x00bd,0x038e,0x038f,
+  0x0390,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,
+  0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,
+  0x03a0,0x03a1,UBOGON,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,
+  0x03a8,0x03a9,0x03aa,0x03ab,0x03ac,0x03ad,0x03ae,0x03af,
+  0x03b0,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,
+  0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,
+  0x03c0,0x03c1,0x03c2,0x03c3,0x03c4,0x03c5,0x03c6,0x03c7,
+  0x03c8,0x03c9,0x03ca,0x03cb,0x03cc,0x03cd,0x03ce,UBOGON
+};
+
+
+				/* Hebrew */
+static const unsigned short iso8859_8tab[128] = {
+  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
+  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
+  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
+  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
+  0x00a0,UBOGON,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,
+  0x00a8,0x00a9,0x00d7,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
+  0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,
+  0x00b8,0x00b9,0x00f7,0x00bb,0x00bc,0x00bd,0x00be,UBOGON,
+  UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+  UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+  UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+  UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x2017,
+  0x05d0,0x05d1,0x05d2,0x05d3,0x05d4,0x05d5,0x05d6,0x05d7,
+  0x05d8,0x05d9,0x05da,0x05db,0x05dc,0x05dd,0x05de,0x05df,
+  0x05e0,0x05e1,0x05e2,0x05e3,0x05e4,0x05e5,0x05e6,0x05e7,
+  0x05e8,0x05e9,0x05ea,UBOGON,UBOGON,0x200e,0x200f,UBOGON
+};
+
+
+				/* Latin-5 (Turkish) */
+static const unsigned short iso8859_9tab[128] = {
+  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
+  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
+  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
+  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
+  0x00a0,0x00a1,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,
+  0x00a8,0x00a9,0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
+  0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,
+  0x00b8,0x00b9,0x00ba,0x00bb,0x00bc,0x00bd,0x00be,0x00bf,
+  0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7,
+  0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
+  0x011e,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00d7,
+  0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x0130,0x015e,0x00df,
+  0x00e0,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x00e7,
+  0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef,
+  0x011f,0x00f1,0x00f2,0x00f3,0x00f4,0x00f5,0x00f6,0x00f7,
+  0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x0131,0x015f,0x00ff
+};
+
+
+				/* Latin-6 (Nordic) */
+static const unsigned short iso8859_10tab[128] = {
+  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
+  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
+  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
+  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
+  0x00a0,0x0104,0x0112,0x0122,0x012a,0x0128,0x0136,0x00a7,
+  0x013b,0x0110,0x0160,0x0166,0x017d,0x00ad,0x016a,0x014a,
+  0x00b0,0x0105,0x0113,0x0123,0x012b,0x0129,0x0137,0x00b7,
+  0x013c,0x0111,0x0161,0x0167,0x017e,0x2015,0x016b,0x014b,
+  0x0100,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x012e,
+  0x010c,0x00c9,0x0118,0x00cb,0x0116,0x00cd,0x00ce,0x00cf,
+  0x00d0,0x0145,0x014c,0x00d3,0x00d4,0x00d5,0x00d6,0x0168,
+  0x00d8,0x0172,0x00da,0x00db,0x00dc,0x00dd,0x00de,0x00df,
+  0x0101,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x012f,
+  0x010d,0x00e9,0x0119,0x00eb,0x0117,0x00ed,0x00ee,0x00ef,
+  0x00f0,0x0146,0x014d,0x00f3,0x00f4,0x00f5,0x00f6,0x0169,
+  0x00f8,0x0173,0x00fa,0x00fb,0x00fc,0x00fd,0x00fe,0x0138
+};
+
+
+				/* Thai */
+#define iso8859_11tab tis620tab
+
+				/* reserved for ISCII Indian */
+
+				/* Latin-7 (Baltic) */
+static const unsigned short iso8859_13tab[128] = {
+  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
+  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
+  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
+  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
+  0x00a0,0x201d,0x00a2,0x00a3,0x00a4,0x201e,0x00a6,0x00a7,
+  0x00d8,0x00a9,0x0156,0x00ab,0x00ac,0x00ad,0x00ae,0x00c6,
+  0x00b0,0x00b1,0x00b2,0x00b3,0x201c,0x00b5,0x00b6,0x00b7,
+  0x00f8,0x00b9,0x0157,0x00bb,0x00bc,0x00bd,0x00be,0x00e6,
+  0x0104,0x012e,0x0100,0x0106,0x00c4,0x00c5,0x0118,0x0112,
+  0x010c,0x00c9,0x0179,0x0116,0x0122,0x0136,0x012a,0x013b,
+  0x0160,0x0143,0x0145,0x00d3,0x014c,0x00d5,0x00d6,0x00d7,
+  0x0172,0x0141,0x015a,0x016a,0x00dc,0x017b,0x017d,0x00df,
+  0x0105,0x012f,0x0101,0x0107,0x00e4,0x00e5,0x0119,0x0113,
+  0x010d,0x00e9,0x017a,0x0117,0x0123,0x0137,0x012b,0x013c,
+  0x0161,0x0144,0x0146,0x00f3,0x014d,0x00f5,0x00f6,0x00f7,
+  0x0173,0x0142,0x015b,0x016b,0x00fc,0x017c,0x017e,0x2019
+};
+
+
+				/* Latin-8 (Celtic) */
+
+static const unsigned short iso8859_14tab[128] = {
+  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
+  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
+  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
+  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
+  0x00a0,0x1e02,0x1e03,0x00a3,0x010a,0x010b,0x1e0a,0x00a7,
+  0x1e80,0x00a9,0x1e82,0x1e0b,0x1ef2,0x00ad,0x00ae,0x0178,
+  0x1e1e,0x1e1f,0x0120,0x0121,0x1e40,0x1e41,0x00b6,0x1e56,
+  0x1e81,0x1e57,0x1e83,0x1e60,0x1ef3,0x1e84,0x1e85,0x1e61,
+  0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7,
+  0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
+  0x0174,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x1e6a,
+  0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x00dd,0x0176,0x00df,
+  0x00e0,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x00e7,
+  0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef,
+  0x0175,0x00f1,0x00f2,0x00f3,0x00f4,0x00f5,0x00f6,0x1e6b,
+  0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x00fd,0x0177,0x00ff
+};
+
+
+				/* Latin-9 a.k.a. Latin-0 (Euro) */
+static const unsigned short iso8859_15tab[128] = {
+  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
+  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
+  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
+  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
+  0x00a0,0x00a1,0x00a2,0x00a3,0x20ac,0x00a5,0x0160,0x00a7,
+  0x0161,0x00a9,0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
+  0x00b0,0x00b1,0x00b2,0x00b3,0x017d,0x00b5,0x00b6,0x00b7,
+  0x017e,0x00b9,0x00ba,0x00bb,0x0152,0x0153,0x0178,0x00bf,
+  0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7,
+  0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
+  0x00d0,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00d7,
+  0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x00dd,0x00de,0x00df,
+  0x00e0,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x00e7,
+  0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef,
+  0x00f0,0x00f1,0x00f2,0x00f3,0x00f4,0x00f5,0x00f6,0x00f7,
+  0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x00fd,0x00fe,0x00ff
+};
+
+
+				/* Latin-10 (Balkan) */
+
+static const unsigned short iso8859_16tab[128] = {
+  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
+  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
+  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
+  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
+  0x00a0,0x0104,0x0105,0x0141,0x20ac,0x201e,0x0160,0x00a7,
+  0x0161,0x00a9,0x0218,0x00ab,0x0179,0x00ad,0x017a,0x017b,
+  0x00b0,0x00b1,0x010c,0x0142,0x017d,0x201d,0x00b6,0x00b7,
+  0x017e,0x010d,0x0219,0x00bb,0x0152,0x0153,0x0178,0x017c,
+  0x00c0,0x00c1,0x00c2,0x0102,0x00c4,0x0106,0x00c6,0x00c7,
+  0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
+  0x0110,0x0143,0x00d2,0x00d3,0x00d4,0x0150,0x00d6,0x015a,
+  0x0170,0x00d9,0x00da,0x00db,0x00dc,0x0118,0x021a,0x00df,
+  0x00e0,0x00e1,0x00e2,0x0103,0x00e4,0x0107,0x00e6,0x00e7,
+  0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef,
+  0x0111,0x0144,0x00f2,0x00f3,0x00f4,0x0151,0x00f6,0x015b,
+  0x0171,0x00f9,0x00fa,0x00fb,0x00fc,0x0119,0x021b,0x00ff
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/charset/jis_0208.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1092 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	JIS X0208 conversion table
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	3 July 1997
+ * Last Edited:	30 August 2006
+ */
+
+/* JIS X0208 is the industrial standard of Japan. */
+
+#define BASE_JIS0208_KU 0x21
+#define BASE_JIS0208_TEN 0x21
+#define MAX_JIS0208_KU 84
+#define MAX_JIS0208_TEN 94
+
+
+#define SJISTOJIS(c,c1)							\
+  c = ((c - ((c < 0xa0) ? 0x70 : 0xb0)) << 1);				\
+  if (c1 < 0x9f) {							\
+    c--;								\
+    c1 -= 0x1f + (c1 > 0x7f);						\
+  }									\
+  else c1 -= 0x7e;
+
+
+#define JISTOUNICODE(c,c1,ku,ten)					\
+  ((((ku = (c & 0x7f) - BASE_JIS0208_KU) < MAX_JIS0208_KU) &&		\
+    ((ten = (c1 & 0x7f) - BASE_JIS0208_TEN) < MAX_JIS0208_TEN)) ?	\
+   jis0208tab[ku][ten] : UBOGON)
+
+
+static const unsigned short jis0208tab[MAX_JIS0208_KU][MAX_JIS0208_TEN] = {
+  {				/* ku 01 */
+    0x3000,0x3001,0x3002,0xff0c,0xff0e,0x30fb,0xff1a,0xff1b,0xff1f,0xff01,
+    0x309b,0x309c,0x00b4,0xff40,0x00a8,0xff3e,0xffe3,0xff3f,0x30fd,0x30fe,
+    0x309d,0x309e,0x3003,0x4edd,0x3005,0x3006,0x3007,0x30fc,0x2015,0x2010,
+    /* Fullwidth/halfwidth correction:
+     * JIS0208.TXT shows 01/32 as U+005C instead of U+FF3C.
+     *
+     * AOL suggests that 01/33 should be U+FF5E instead of U+301C and
+     * 01/34 should be U+2225 instead of U+2016.
+     * I disagree; 01/33 is JIS punctuation (not a tilde); and 01/34 is
+     * double vertical line.
+     */
+    0xff0f,0xff3c,0x301c,0x2016,0xff5c,0x2026,0x2025,0x2018,0x2019,0x201c,
+    0x201d,0xff08,0xff09,0x3014,0x3015,0xff3b,0xff3d,0xff5b,0xff5d,0x3008,
+    0x3009,0x300a,0x300b,0x300c,0x300d,0x300e,0x300f,0x3010,0x3011,0xff0b,
+    /* Fullwidth/halfwidth correction:
+     * JIS0208.TXT 01/61 has U+2212 instead of U+FF0D.
+     */
+    0xff0d,0x00b1,0x00d7,0x00f7,0xff1d,0x2260,0xff1c,0xff1e,0x2266,0x2267,
+    0x221e,0x2234,0x2642,0x2640,0x00b0,0x2032,0x2033,0x2103,0xffe5,0xff04,
+    /* Fullwidth/halfwidth correction:
+     * JIS 0208 shows 01/81 as U+00A2 instead of U+FFE0, and
+     * 01/82 as U+00A3 instead of U+FFE1.
+     */
+    0xffe0,0xffe1,0xff05,0xff03,0xff06,0xff0a,0xff20,0x00a7,0x2606,0x2605,
+    0x25cb,0x25cf,0x25ce,0x25c7
+  },
+  {				/* ku 02 */
+    0x25c6,0x25a1,0x25a0,0x25b3,0x25b2,0x25bd,0x25bc,0x203b,0x3012,0x2192,
+    0x2190,0x2191,0x2193,0x3013,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x2208,0x220b,0x2286,0x2287,0x2282,
+    0x2283,0x222a,0x2229,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    /* Fullwidth/halfwidth correction:
+     * JIS0208.TXT shows 02/44 as U+00AC instead of U+FFE2.
+     */
+    UBOGON,0x2227,0x2228,0xffe2,0x21d2,0x21d4,0x2200,0x2203,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x2220,
+    0x22a5,0x2312,0x2202,0x2207,0x2261,0x2252,0x226a,0x226b,0x221a,0x223d,
+    0x221d,0x2235,0x222b,0x222c,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x212b,0x2030,0x266f,0x266d,0x266a,0x2020,0x2021,0x00b6,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x25ef
+  },
+  {				/* ku 03 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xff10,0xff11,0xff12,0xff13,0xff14,
+    0xff15,0xff16,0xff17,0xff18,0xff19,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xff21,0xff22,0xff23,0xff24,0xff25,0xff26,0xff27,0xff28,
+    0xff29,0xff2a,0xff2b,0xff2c,0xff2d,0xff2e,0xff2f,0xff30,0xff31,0xff32,
+    0xff33,0xff34,0xff35,0xff36,0xff37,0xff38,0xff39,0xff3a,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xff41,0xff42,0xff43,0xff44,0xff45,0xff46,
+    0xff47,0xff48,0xff49,0xff4a,0xff4b,0xff4c,0xff4d,0xff4e,0xff4f,0xff50,
+    0xff51,0xff52,0xff53,0xff54,0xff55,0xff56,0xff57,0xff58,0xff59,0xff5a,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 04 */
+    0x3041,0x3042,0x3043,0x3044,0x3045,0x3046,0x3047,0x3048,0x3049,0x304a,
+    0x304b,0x304c,0x304d,0x304e,0x304f,0x3050,0x3051,0x3052,0x3053,0x3054,
+    0x3055,0x3056,0x3057,0x3058,0x3059,0x305a,0x305b,0x305c,0x305d,0x305e,
+    0x305f,0x3060,0x3061,0x3062,0x3063,0x3064,0x3065,0x3066,0x3067,0x3068,
+    0x3069,0x306a,0x306b,0x306c,0x306d,0x306e,0x306f,0x3070,0x3071,0x3072,
+    0x3073,0x3074,0x3075,0x3076,0x3077,0x3078,0x3079,0x307a,0x307b,0x307c,
+    0x307d,0x307e,0x307f,0x3080,0x3081,0x3082,0x3083,0x3084,0x3085,0x3086,
+    0x3087,0x3088,0x3089,0x308a,0x308b,0x308c,0x308d,0x308e,0x308f,0x3090,
+    0x3091,0x3092,0x3093,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 05 */
+    0x30a1,0x30a2,0x30a3,0x30a4,0x30a5,0x30a6,0x30a7,0x30a8,0x30a9,0x30aa,
+    0x30ab,0x30ac,0x30ad,0x30ae,0x30af,0x30b0,0x30b1,0x30b2,0x30b3,0x30b4,
+    0x30b5,0x30b6,0x30b7,0x30b8,0x30b9,0x30ba,0x30bb,0x30bc,0x30bd,0x30be,
+    0x30bf,0x30c0,0x30c1,0x30c2,0x30c3,0x30c4,0x30c5,0x30c6,0x30c7,0x30c8,
+    0x30c9,0x30ca,0x30cb,0x30cc,0x30cd,0x30ce,0x30cf,0x30d0,0x30d1,0x30d2,
+    0x30d3,0x30d4,0x30d5,0x30d6,0x30d7,0x30d8,0x30d9,0x30da,0x30db,0x30dc,
+    0x30dd,0x30de,0x30df,0x30e0,0x30e1,0x30e2,0x30e3,0x30e4,0x30e5,0x30e6,
+    0x30e7,0x30e8,0x30e9,0x30ea,0x30eb,0x30ec,0x30ed,0x30ee,0x30ef,0x30f0,
+    0x30f1,0x30f2,0x30f3,0x30f4,0x30f5,0x30f6,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 06 */
+    0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,0x0398,0x0399,0x039a,
+    0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0,0x03a1,0x03a3,0x03a4,0x03a5,
+    0x03a6,0x03a7,0x03a8,0x03a9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8,
+    0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,0x03c0,0x03c1,0x03c3,
+    0x03c4,0x03c5,0x03c6,0x03c7,0x03c8,0x03c9,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 07 */
+    0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0401,0x0416,0x0417,0x0418,
+    0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f,0x0420,0x0421,0x0422,
+    0x0423,0x0424,0x0425,0x0426,0x0427,0x0428,0x0429,0x042a,0x042b,0x042c,
+    0x042d,0x042e,0x042f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x0430,0x0431,
+    0x0432,0x0433,0x0434,0x0435,0x0451,0x0436,0x0437,0x0438,0x0439,0x043a,
+    0x043b,0x043c,0x043d,0x043e,0x043f,0x0440,0x0441,0x0442,0x0443,0x0444,
+    0x0445,0x0446,0x0447,0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,
+    0x044f,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 08 */
+    0x2500,0x2502,0x250c,0x2510,0x2518,0x2514,0x251c,0x252c,0x2524,0x2534,
+    0x253c,0x2501,0x2503,0x250f,0x2513,0x251b,0x2517,0x2523,0x2533,0x252b,
+    0x253b,0x254b,0x2520,0x252f,0x2528,0x2537,0x253f,0x251d,0x2530,0x2525,
+    0x2538,0x2542,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 09 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0a */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0b */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0d */
+#if 0
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+#else	/* additional mappings suggested by AOL */
+   0x2460,0x2461,0x2462,0x2463,0x2464,0x2465,0x2466,0x2467,0x2468,0x2469,
+   0x246a,0x246b,0x246c,0x246d,0x246e,0x246f,0x2470,0x2471,0x2472,0x2473,
+   0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,0x2169,
+   UBOGON,0x3349,0x3314,0x3322,0x334d,0x3318,0x3327,0x3303,0x3336,0x3351,
+   0x3357,0x330d,0x3326,0x3323,0x332b,0x334a,0x333b,0x339c,0x339d,0x339e,
+   0x338e,0x338f,0x33c4,0x33a1,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+   UBOGON,UBOGON,0x337b,0x301d,0x301f,0x2116,0x33cd,0x2121,0x32a4,0x32a5,
+   0x32a6,0x32a7,0x32a8,0x3231,0x3232,0x3239,0x337e,0x337d,0x337c,UBOGON,
+   UBOGON,UBOGON,0x222e,0x2211,UBOGON,UBOGON,UBOGON,0x221f,0x22bf,UBOGON,
+   UBOGON,UBOGON,UBOGON,UBOGON
+#endif
+  },
+  {				/* ku 0e */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0f */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 10 */
+    0x4e9c,0x5516,0x5a03,0x963f,0x54c0,0x611b,0x6328,0x59f6,0x9022,0x8475,
+    0x831c,0x7a50,0x60aa,0x63e1,0x6e25,0x65ed,0x8466,0x82a6,0x9bf5,0x6893,
+    0x5727,0x65a1,0x6271,0x5b9b,0x59d0,0x867b,0x98f4,0x7d62,0x7dbe,0x9b8e,
+    0x6216,0x7c9f,0x88b7,0x5b89,0x5eb5,0x6309,0x6697,0x6848,0x95c7,0x978d,
+    0x674f,0x4ee5,0x4f0a,0x4f4d,0x4f9d,0x5049,0x56f2,0x5937,0x59d4,0x5a01,
+    0x5c09,0x60df,0x610f,0x6170,0x6613,0x6905,0x70ba,0x754f,0x7570,0x79fb,
+    0x7dad,0x7def,0x80c3,0x840e,0x8863,0x8b02,0x9055,0x907a,0x533b,0x4e95,
+    0x4ea5,0x57df,0x80b2,0x90c1,0x78ef,0x4e00,0x58f1,0x6ea2,0x9038,0x7a32,
+    0x8328,0x828b,0x9c2f,0x5141,0x5370,0x54bd,0x54e1,0x56e0,0x59fb,0x5f15,
+    0x98f2,0x6deb,0x80e4,0x852d
+  },
+  {				/* ku 11 */
+    0x9662,0x9670,0x96a0,0x97fb,0x540b,0x53f3,0x5b87,0x70cf,0x7fbd,0x8fc2,
+    0x96e8,0x536f,0x9d5c,0x7aba,0x4e11,0x7893,0x81fc,0x6e26,0x5618,0x5504,
+    0x6b1d,0x851a,0x9c3b,0x59e5,0x53a9,0x6d66,0x74dc,0x958f,0x5642,0x4e91,
+    0x904b,0x96f2,0x834f,0x990c,0x53e1,0x55b6,0x5b30,0x5f71,0x6620,0x66f3,
+    0x6804,0x6c38,0x6cf3,0x6d29,0x745b,0x76c8,0x7a4e,0x9834,0x82f1,0x885b,
+    0x8a60,0x92ed,0x6db2,0x75ab,0x76ca,0x99c5,0x60a6,0x8b01,0x8d8a,0x95b2,
+    0x698e,0x53ad,0x5186,0x5712,0x5830,0x5944,0x5bb4,0x5ef6,0x6028,0x63a9,
+    0x63f4,0x6cbf,0x6f14,0x708e,0x7114,0x7159,0x71d5,0x733f,0x7e01,0x8276,
+    0x82d1,0x8597,0x9060,0x925b,0x9d1b,0x5869,0x65bc,0x6c5a,0x7525,0x51f9,
+    0x592e,0x5965,0x5f80,0x5fdc
+  },
+  {				/* ku 12 */
+    0x62bc,0x65fa,0x6a2a,0x6b27,0x6bb4,0x738b,0x7fc1,0x8956,0x9d2c,0x9d0e,
+    0x9ec4,0x5ca1,0x6c96,0x837b,0x5104,0x5c4b,0x61b6,0x81c6,0x6876,0x7261,
+    0x4e59,0x4ffa,0x5378,0x6069,0x6e29,0x7a4f,0x97f3,0x4e0b,0x5316,0x4eee,
+    0x4f55,0x4f3d,0x4fa1,0x4f73,0x52a0,0x53ef,0x5609,0x590f,0x5ac1,0x5bb6,
+    0x5be1,0x79d1,0x6687,0x679c,0x67b6,0x6b4c,0x6cb3,0x706b,0x73c2,0x798d,
+    0x79be,0x7a3c,0x7b87,0x82b1,0x82db,0x8304,0x8377,0x83ef,0x83d3,0x8766,
+    0x8ab2,0x5629,0x8ca8,0x8fe6,0x904e,0x971e,0x868a,0x4fc4,0x5ce8,0x6211,
+    0x7259,0x753b,0x81e5,0x82bd,0x86fe,0x8cc0,0x96c5,0x9913,0x99d5,0x4ecb,
+    0x4f1a,0x89e3,0x56de,0x584a,0x58ca,0x5efb,0x5feb,0x602a,0x6094,0x6062,
+    0x61d0,0x6212,0x62d0,0x6539
+  },
+  {				/* ku 13 */
+    0x9b41,0x6666,0x68b0,0x6d77,0x7070,0x754c,0x7686,0x7d75,0x82a5,0x87f9,
+    0x958b,0x968e,0x8c9d,0x51f1,0x52be,0x5916,0x54b3,0x5bb3,0x5d16,0x6168,
+    0x6982,0x6daf,0x788d,0x84cb,0x8857,0x8a72,0x93a7,0x9ab8,0x6d6c,0x99a8,
+    0x86d9,0x57a3,0x67ff,0x86ce,0x920e,0x5283,0x5687,0x5404,0x5ed3,0x62e1,
+    0x64b9,0x683c,0x6838,0x6bbb,0x7372,0x78ba,0x7a6b,0x899a,0x89d2,0x8d6b,
+    0x8f03,0x90ed,0x95a3,0x9694,0x9769,0x5b66,0x5cb3,0x697d,0x984d,0x984e,
+    0x639b,0x7b20,0x6a2b,0x6a7f,0x68b6,0x9c0d,0x6f5f,0x5272,0x559d,0x6070,
+    0x62ec,0x6d3b,0x6e07,0x6ed1,0x845b,0x8910,0x8f44,0x4e14,0x9c39,0x53f6,
+    0x691b,0x6a3a,0x9784,0x682a,0x515c,0x7ac3,0x84b2,0x91dc,0x938c,0x565b,
+    0x9d28,0x6822,0x8305,0x8431
+  },
+  {				/* ku 14 */
+    0x7ca5,0x5208,0x82c5,0x74e6,0x4e7e,0x4f83,0x51a0,0x5bd2,0x520a,0x52d8,
+    0x52e7,0x5dfb,0x559a,0x582a,0x59e6,0x5b8c,0x5b98,0x5bdb,0x5e72,0x5e79,
+    0x60a3,0x611f,0x6163,0x61be,0x63db,0x6562,0x67d1,0x6853,0x68fa,0x6b3e,
+    0x6b53,0x6c57,0x6f22,0x6f97,0x6f45,0x74b0,0x7518,0x76e3,0x770b,0x7aff,
+    0x7ba1,0x7c21,0x7de9,0x7f36,0x7ff0,0x809d,0x8266,0x839e,0x89b3,0x8acc,
+    0x8cab,0x9084,0x9451,0x9593,0x9591,0x95a2,0x9665,0x97d3,0x9928,0x8218,
+    0x4e38,0x542b,0x5cb8,0x5dcc,0x73a9,0x764c,0x773c,0x5ca9,0x7feb,0x8d0b,
+    0x96c1,0x9811,0x9854,0x9858,0x4f01,0x4f0e,0x5371,0x559c,0x5668,0x57fa,
+    0x5947,0x5b09,0x5bc4,0x5c90,0x5e0c,0x5e7e,0x5fcc,0x63ee,0x673a,0x65d7,
+    0x65e2,0x671f,0x68cb,0x68c4
+  },
+  {				/* ku 15 */
+    0x6a5f,0x5e30,0x6bc5,0x6c17,0x6c7d,0x757f,0x7948,0x5b63,0x7a00,0x7d00,
+    0x5fbd,0x898f,0x8a18,0x8cb4,0x8d77,0x8ecc,0x8f1d,0x98e2,0x9a0e,0x9b3c,
+    0x4e80,0x507d,0x5100,0x5993,0x5b9c,0x622f,0x6280,0x64ec,0x6b3a,0x72a0,
+    0x7591,0x7947,0x7fa9,0x87fb,0x8abc,0x8b70,0x63ac,0x83ca,0x97a0,0x5409,
+    0x5403,0x55ab,0x6854,0x6a58,0x8a70,0x7827,0x6775,0x9ecd,0x5374,0x5ba2,
+    0x811a,0x8650,0x9006,0x4e18,0x4e45,0x4ec7,0x4f11,0x53ca,0x5438,0x5bae,
+    0x5f13,0x6025,0x6551,0x673d,0x6c42,0x6c72,0x6ce3,0x7078,0x7403,0x7a76,
+    0x7aae,0x7b08,0x7d1a,0x7cfe,0x7d66,0x65e7,0x725b,0x53bb,0x5c45,0x5de8,
+    0x62d2,0x62e0,0x6319,0x6e20,0x865a,0x8a31,0x8ddd,0x92f8,0x6f01,0x79a6,
+    0x9b5a,0x4ea8,0x4eab,0x4eac
+  },
+  {				/* ku 16 */
+    0x4f9b,0x4fa0,0x50d1,0x5147,0x7af6,0x5171,0x51f6,0x5354,0x5321,0x537f,
+    0x53eb,0x55ac,0x5883,0x5ce1,0x5f37,0x5f4a,0x602f,0x6050,0x606d,0x631f,
+    0x6559,0x6a4b,0x6cc1,0x72c2,0x72ed,0x77ef,0x80f8,0x8105,0x8208,0x854e,
+    0x90f7,0x93e1,0x97ff,0x9957,0x9a5a,0x4ef0,0x51dd,0x5c2d,0x6681,0x696d,
+    0x5c40,0x66f2,0x6975,0x7389,0x6850,0x7c81,0x50c5,0x52e4,0x5747,0x5dfe,
+    0x9326,0x65a4,0x6b23,0x6b3d,0x7434,0x7981,0x79bd,0x7b4b,0x7dca,0x82b9,
+    0x83cc,0x887f,0x895f,0x8b39,0x8fd1,0x91d1,0x541f,0x9280,0x4e5d,0x5036,
+    0x53e5,0x533a,0x72d7,0x7396,0x77e9,0x82e6,0x8eaf,0x99c6,0x99c8,0x99d2,
+    0x5177,0x611a,0x865e,0x55b0,0x7a7a,0x5076,0x5bd3,0x9047,0x9685,0x4e32,
+    0x6adb,0x91e7,0x5c51,0x5c48
+  },
+  {				/* ku 17 */
+    0x6398,0x7a9f,0x6c93,0x9774,0x8f61,0x7aaa,0x718a,0x9688,0x7c82,0x6817,
+    0x7e70,0x6851,0x936c,0x52f2,0x541b,0x85ab,0x8a13,0x7fa4,0x8ecd,0x90e1,
+    0x5366,0x8888,0x7941,0x4fc2,0x50be,0x5211,0x5144,0x5553,0x572d,0x73ea,
+    0x578b,0x5951,0x5f62,0x5f84,0x6075,0x6176,0x6167,0x61a9,0x63b2,0x643a,
+    0x656c,0x666f,0x6842,0x6e13,0x7566,0x7a3d,0x7cfb,0x7d4c,0x7d99,0x7e4b,
+    0x7f6b,0x830e,0x834a,0x86cd,0x8a08,0x8a63,0x8b66,0x8efd,0x981a,0x9d8f,
+    0x82b8,0x8fce,0x9be8,0x5287,0x621f,0x6483,0x6fc0,0x9699,0x6841,0x5091,
+    0x6b20,0x6c7a,0x6f54,0x7a74,0x7d50,0x8840,0x8a23,0x6708,0x4ef6,0x5039,
+    0x5026,0x5065,0x517c,0x5238,0x5263,0x55a7,0x570f,0x5805,0x5acc,0x5efa,
+    0x61b2,0x61f8,0x62f3,0x6372
+  },
+  {				/* ku 18 */
+    0x691c,0x6a29,0x727d,0x72ac,0x732e,0x7814,0x786f,0x7d79,0x770c,0x80a9,
+    0x898b,0x8b19,0x8ce2,0x8ed2,0x9063,0x9375,0x967a,0x9855,0x9a13,0x9e78,
+    0x5143,0x539f,0x53b3,0x5e7b,0x5f26,0x6e1b,0x6e90,0x7384,0x73fe,0x7d43,
+    0x8237,0x8a00,0x8afa,0x9650,0x4e4e,0x500b,0x53e4,0x547c,0x56fa,0x59d1,
+    0x5b64,0x5df1,0x5eab,0x5f27,0x6238,0x6545,0x67af,0x6e56,0x72d0,0x7cca,
+    0x88b4,0x80a1,0x80e1,0x83f0,0x864e,0x8a87,0x8de8,0x9237,0x96c7,0x9867,
+    0x9f13,0x4e94,0x4e92,0x4f0d,0x5348,0x5449,0x543e,0x5a2f,0x5f8c,0x5fa1,
+    0x609f,0x68a7,0x6a8e,0x745a,0x7881,0x8a9e,0x8aa4,0x8b77,0x9190,0x4e5e,
+    0x9bc9,0x4ea4,0x4f7c,0x4faf,0x5019,0x5016,0x5149,0x516c,0x529f,0x52b9,
+    0x52fe,0x539a,0x53e3,0x5411
+  },
+  {				/* ku 19 */
+    0x540e,0x5589,0x5751,0x57a2,0x597d,0x5b54,0x5b5d,0x5b8f,0x5de5,0x5de7,
+    0x5df7,0x5e78,0x5e83,0x5e9a,0x5eb7,0x5f18,0x6052,0x614c,0x6297,0x62d8,
+    0x63a7,0x653b,0x6602,0x6643,0x66f4,0x676d,0x6821,0x6897,0x69cb,0x6c5f,
+    0x6d2a,0x6d69,0x6e2f,0x6e9d,0x7532,0x7687,0x786c,0x7a3f,0x7ce0,0x7d05,
+    0x7d18,0x7d5e,0x7db1,0x8015,0x8003,0x80af,0x80b1,0x8154,0x818f,0x822a,
+    0x8352,0x884c,0x8861,0x8b1b,0x8ca2,0x8cfc,0x90ca,0x9175,0x9271,0x783f,
+    0x92fc,0x95a4,0x964d,0x9805,0x9999,0x9ad8,0x9d3b,0x525b,0x52ab,0x53f7,
+    0x5408,0x58d5,0x62f7,0x6fe0,0x8c6a,0x8f5f,0x9eb9,0x514b,0x523b,0x544a,
+    0x56fd,0x7a40,0x9177,0x9d60,0x9ed2,0x7344,0x6f09,0x8170,0x7511,0x5ffd,
+    0x60da,0x9aa8,0x72db,0x8fbc
+  },
+  {				/* ku 1a */
+    0x6b64,0x9803,0x4eca,0x56f0,0x5764,0x58be,0x5a5a,0x6068,0x61c7,0x660f,
+    0x6606,0x6839,0x68b1,0x6df7,0x75d5,0x7d3a,0x826e,0x9b42,0x4e9b,0x4f50,
+    0x53c9,0x5506,0x5d6f,0x5de6,0x5dee,0x67fb,0x6c99,0x7473,0x7802,0x8a50,
+    0x9396,0x88df,0x5750,0x5ea7,0x632b,0x50b5,0x50ac,0x518d,0x6700,0x54c9,
+    0x585e,0x59bb,0x5bb0,0x5f69,0x624d,0x63a1,0x683d,0x6b73,0x6e08,0x707d,
+    0x91c7,0x7280,0x7815,0x7826,0x796d,0x658e,0x7d30,0x83dc,0x88c1,0x8f09,
+    0x969b,0x5264,0x5728,0x6750,0x7f6a,0x8ca1,0x51b4,0x5742,0x962a,0x583a,
+    0x698a,0x80b4,0x54b2,0x5d0e,0x57fc,0x7895,0x9dfa,0x4f5c,0x524a,0x548b,
+    0x643e,0x6628,0x6714,0x67f5,0x7a84,0x7b56,0x7d22,0x932f,0x685c,0x9bad,
+    0x7b39,0x5319,0x518a,0x5237
+  },
+  {				/* ku 1b */
+    0x5bdf,0x62f6,0x64ae,0x64e6,0x672d,0x6bba,0x85a9,0x96d1,0x7690,0x9bd6,
+    0x634c,0x9306,0x9bab,0x76bf,0x6652,0x4e09,0x5098,0x53c2,0x5c71,0x60e8,
+    0x6492,0x6563,0x685f,0x71e6,0x73ca,0x7523,0x7b97,0x7e82,0x8695,0x8b83,
+    0x8cdb,0x9178,0x9910,0x65ac,0x66ab,0x6b8b,0x4ed5,0x4ed4,0x4f3a,0x4f7f,
+    0x523a,0x53f8,0x53f2,0x55e3,0x56db,0x58eb,0x59cb,0x59c9,0x59ff,0x5b50,
+    0x5c4d,0x5e02,0x5e2b,0x5fd7,0x601d,0x6307,0x652f,0x5b5c,0x65af,0x65bd,
+    0x65e8,0x679d,0x6b62,0x6b7b,0x6c0f,0x7345,0x7949,0x79c1,0x7cf8,0x7d19,
+    0x7d2b,0x80a2,0x8102,0x81f3,0x8996,0x8a5e,0x8a69,0x8a66,0x8a8c,0x8aee,
+    0x8cc7,0x8cdc,0x96cc,0x98fc,0x6b6f,0x4e8b,0x4f3c,0x4f8d,0x5150,0x5b57,
+    0x5bfa,0x6148,0x6301,0x6642
+  },
+  {				/* ku 1c */
+    0x6b21,0x6ecb,0x6cbb,0x723e,0x74bd,0x75d4,0x78c1,0x793a,0x800c,0x8033,
+    0x81ea,0x8494,0x8f9e,0x6c50,0x9e7f,0x5f0f,0x8b58,0x9d2b,0x7afa,0x8ef8,
+    0x5b8d,0x96eb,0x4e03,0x53f1,0x57f7,0x5931,0x5ac9,0x5ba4,0x6089,0x6e7f,
+    0x6f06,0x75be,0x8cea,0x5b9f,0x8500,0x7be0,0x5072,0x67f4,0x829d,0x5c61,
+    0x854a,0x7e1e,0x820e,0x5199,0x5c04,0x6368,0x8d66,0x659c,0x716e,0x793e,
+    0x7d17,0x8005,0x8b1d,0x8eca,0x906e,0x86c7,0x90aa,0x501f,0x52fa,0x5c3a,
+    0x6753,0x707c,0x7235,0x914c,0x91c8,0x932b,0x82e5,0x5bc2,0x5f31,0x60f9,
+    0x4e3b,0x53d6,0x5b88,0x624b,0x6731,0x6b8a,0x72e9,0x73e0,0x7a2e,0x816b,
+    0x8da3,0x9152,0x9996,0x5112,0x53d7,0x546a,0x5bff,0x6388,0x6a39,0x7dac,
+    0x9700,0x56da,0x53ce,0x5468
+  },
+  {				/* ku 1d */
+    0x5b97,0x5c31,0x5dde,0x4fee,0x6101,0x62fe,0x6d32,0x79c0,0x79cb,0x7d42,
+    0x7e4d,0x7fd2,0x81ed,0x821f,0x8490,0x8846,0x8972,0x8b90,0x8e74,0x8f2f,
+    0x9031,0x914b,0x916c,0x96c6,0x919c,0x4ec0,0x4f4f,0x5145,0x5341,0x5f93,
+    0x620e,0x67d4,0x6c41,0x6e0b,0x7363,0x7e26,0x91cd,0x9283,0x53d4,0x5919,
+    0x5bbf,0x6dd1,0x795d,0x7e2e,0x7c9b,0x587e,0x719f,0x51fa,0x8853,0x8ff0,
+    0x4fca,0x5cfb,0x6625,0x77ac,0x7ae3,0x821c,0x99ff,0x51c6,0x5faa,0x65ec,
+    0x696f,0x6b89,0x6df3,0x6e96,0x6f64,0x76fe,0x7d14,0x5de1,0x9075,0x9187,
+    0x9806,0x51e6,0x521d,0x6240,0x6691,0x66d9,0x6e1a,0x5eb6,0x7dd2,0x7f72,
+    0x66f8,0x85af,0x85f7,0x8af8,0x52a9,0x53d9,0x5973,0x5e8f,0x5f90,0x6055,
+    0x92e4,0x9664,0x50b7,0x511f
+  },
+  {				/* ku 1e */
+    0x52dd,0x5320,0x5347,0x53ec,0x54e8,0x5546,0x5531,0x5617,0x5968,0x59be,
+    0x5a3c,0x5bb5,0x5c06,0x5c0f,0x5c11,0x5c1a,0x5e84,0x5e8a,0x5ee0,0x5f70,
+    0x627f,0x6284,0x62db,0x638c,0x6377,0x6607,0x660c,0x662d,0x6676,0x677e,
+    0x68a2,0x6a1f,0x6a35,0x6cbc,0x6d88,0x6e09,0x6e58,0x713c,0x7126,0x7167,
+    0x75c7,0x7701,0x785d,0x7901,0x7965,0x79f0,0x7ae0,0x7b11,0x7ca7,0x7d39,
+    0x8096,0x83d6,0x848b,0x8549,0x885d,0x88f3,0x8a1f,0x8a3c,0x8a54,0x8a73,
+    0x8c61,0x8cde,0x91a4,0x9266,0x937e,0x9418,0x969c,0x9798,0x4e0a,0x4e08,
+    0x4e1e,0x4e57,0x5197,0x5270,0x57ce,0x5834,0x58cc,0x5b22,0x5e38,0x60c5,
+    0x64fe,0x6761,0x6756,0x6d44,0x72b6,0x7573,0x7a63,0x84b8,0x8b72,0x91b8,
+    0x9320,0x5631,0x57f4,0x98fe
+  },
+  {				/* ku 1f */
+    0x62ed,0x690d,0x6b96,0x71ed,0x7e54,0x8077,0x8272,0x89e6,0x98df,0x8755,
+    0x8fb1,0x5c3b,0x4f38,0x4fe1,0x4fb5,0x5507,0x5a20,0x5bdd,0x5be9,0x5fc3,
+    0x614e,0x632f,0x65b0,0x664b,0x68ee,0x699b,0x6d78,0x6df1,0x7533,0x75b9,
+    0x771f,0x795e,0x79e6,0x7d33,0x81e3,0x82af,0x85aa,0x89aa,0x8a3a,0x8eab,
+    0x8f9b,0x9032,0x91dd,0x9707,0x4eba,0x4ec1,0x5203,0x5875,0x58ec,0x5c0b,
+    0x751a,0x5c3d,0x814e,0x8a0a,0x8fc5,0x9663,0x976d,0x7b25,0x8acf,0x9808,
+    0x9162,0x56f3,0x53a8,0x9017,0x5439,0x5782,0x5e25,0x63a8,0x6c34,0x708a,
+    0x7761,0x7c8b,0x7fe0,0x8870,0x9042,0x9154,0x9310,0x9318,0x968f,0x745e,
+    0x9ac4,0x5d07,0x5d69,0x6570,0x67a2,0x8da8,0x96db,0x636e,0x6749,0x6919,
+    0x83c5,0x9817,0x96c0,0x88fe
+  },
+  {				/* ku 20 */
+    0x6f84,0x647a,0x5bf8,0x4e16,0x702c,0x755d,0x662f,0x51c4,0x5236,0x52e2,
+    0x59d3,0x5f81,0x6027,0x6210,0x653f,0x6574,0x661f,0x6674,0x68f2,0x6816,
+    0x6b63,0x6e05,0x7272,0x751f,0x76db,0x7cbe,0x8056,0x58f0,0x88fd,0x897f,
+    0x8aa0,0x8a93,0x8acb,0x901d,0x9192,0x9752,0x9759,0x6589,0x7a0e,0x8106,
+    0x96bb,0x5e2d,0x60dc,0x621a,0x65a5,0x6614,0x6790,0x77f3,0x7a4d,0x7c4d,
+    0x7e3e,0x810a,0x8cac,0x8d64,0x8de1,0x8e5f,0x78a9,0x5207,0x62d9,0x63a5,
+    0x6442,0x6298,0x8a2d,0x7a83,0x7bc0,0x8aac,0x96ea,0x7d76,0x820c,0x8749,
+    0x4ed9,0x5148,0x5343,0x5360,0x5ba3,0x5c02,0x5c16,0x5ddd,0x6226,0x6247,
+    0x64b0,0x6813,0x6834,0x6cc9,0x6d45,0x6d17,0x67d3,0x6f5c,0x714e,0x717d,
+    0x65cb,0x7a7f,0x7bad,0x7dda
+  },
+  {				/* ku 21 */
+    0x7e4a,0x7fa8,0x817a,0x821b,0x8239,0x85a6,0x8a6e,0x8cce,0x8df5,0x9078,
+    0x9077,0x92ad,0x9291,0x9583,0x9bae,0x524d,0x5584,0x6f38,0x7136,0x5168,
+    0x7985,0x7e55,0x81b3,0x7cce,0x564c,0x5851,0x5ca8,0x63aa,0x66fe,0x66fd,
+    0x695a,0x72d9,0x758f,0x758e,0x790e,0x7956,0x79df,0x7c97,0x7d20,0x7d44,
+    0x8607,0x8a34,0x963b,0x9061,0x9f20,0x50e7,0x5275,0x53cc,0x53e2,0x5009,
+    0x55aa,0x58ee,0x594f,0x723d,0x5b8b,0x5c64,0x531d,0x60e3,0x60f3,0x635c,
+    0x6383,0x633f,0x63bb,0x64cd,0x65e9,0x66f9,0x5de3,0x69cd,0x69fd,0x6f15,
+    0x71e5,0x4e89,0x75e9,0x76f8,0x7a93,0x7cdf,0x7dcf,0x7d9c,0x8061,0x8349,
+    0x8358,0x846c,0x84bc,0x85fb,0x88c5,0x8d70,0x9001,0x906d,0x9397,0x971c,
+    0x9a12,0x50cf,0x5897,0x618e
+  },
+  {				/* ku 22 */
+    0x81d3,0x8535,0x8d08,0x9020,0x4fc3,0x5074,0x5247,0x5373,0x606f,0x6349,
+    0x675f,0x6e2c,0x8db3,0x901f,0x4fd7,0x5c5e,0x8cca,0x65cf,0x7d9a,0x5352,
+    0x8896,0x5176,0x63c3,0x5b58,0x5b6b,0x5c0a,0x640d,0x6751,0x905c,0x4ed6,
+    0x591a,0x592a,0x6c70,0x8a51,0x553e,0x5815,0x59a5,0x60f0,0x6253,0x67c1,
+    0x8235,0x6955,0x9640,0x99c4,0x9a28,0x4f53,0x5806,0x5bfe,0x8010,0x5cb1,
+    0x5e2f,0x5f85,0x6020,0x614b,0x6234,0x66ff,0x6cf0,0x6ede,0x80ce,0x817f,
+    0x82d4,0x888b,0x8cb8,0x9000,0x902e,0x968a,0x9edb,0x9bdb,0x4ee3,0x53f0,
+    0x5927,0x7b2c,0x918d,0x984c,0x9df9,0x6edd,0x7027,0x5353,0x5544,0x5b85,
+    0x6258,0x629e,0x62d3,0x6ca2,0x6fef,0x7422,0x8a17,0x9438,0x6fc1,0x8afe,
+    0x8338,0x51e7,0x86f8,0x53ea
+  },
+  {				/* ku 23 */
+    0x53e9,0x4f46,0x9054,0x8fb0,0x596a,0x8131,0x5dfd,0x7aea,0x8fbf,0x68da,
+    0x8c37,0x72f8,0x9c48,0x6a3d,0x8ab0,0x4e39,0x5358,0x5606,0x5766,0x62c5,
+    0x63a2,0x65e6,0x6b4e,0x6de1,0x6e5b,0x70ad,0x77ed,0x7aef,0x7baa,0x7dbb,
+    0x803d,0x80c6,0x86cb,0x8a95,0x935b,0x56e3,0x58c7,0x5f3e,0x65ad,0x6696,
+    0x6a80,0x6bb5,0x7537,0x8ac7,0x5024,0x77e5,0x5730,0x5f1b,0x6065,0x667a,
+    0x6c60,0x75f4,0x7a1a,0x7f6e,0x81f4,0x8718,0x9045,0x99b3,0x7bc9,0x755c,
+    0x7af9,0x7b51,0x84c4,0x9010,0x79e9,0x7a92,0x8336,0x5ae1,0x7740,0x4e2d,
+    0x4ef2,0x5b99,0x5fe0,0x62bd,0x663c,0x67f1,0x6ce8,0x866b,0x8877,0x8a3b,
+    0x914e,0x92f3,0x99d0,0x6a17,0x7026,0x732a,0x82e7,0x8457,0x8caf,0x4e01,
+    0x5146,0x51cb,0x558b,0x5bf5
+  },
+  {				/* ku 24 */
+    0x5e16,0x5e33,0x5e81,0x5f14,0x5f35,0x5f6b,0x5fb4,0x61f2,0x6311,0x66a2,
+    0x671d,0x6f6e,0x7252,0x753a,0x773a,0x8074,0x8139,0x8178,0x8776,0x8abf,
+    0x8adc,0x8d85,0x8df3,0x929a,0x9577,0x9802,0x9ce5,0x52c5,0x6357,0x76f4,
+    0x6715,0x6c88,0x73cd,0x8cc3,0x93ae,0x9673,0x6d25,0x589c,0x690e,0x69cc,
+    0x8ffd,0x939a,0x75db,0x901a,0x585a,0x6802,0x63b4,0x69fb,0x4f43,0x6f2c,
+    0x67d8,0x8fbb,0x8526,0x7db4,0x9354,0x693f,0x6f70,0x576a,0x58f7,0x5b2c,
+    0x7d2c,0x722a,0x540a,0x91e3,0x9db4,0x4ead,0x4f4e,0x505c,0x5075,0x5243,
+    0x8c9e,0x5448,0x5824,0x5b9a,0x5e1d,0x5e95,0x5ead,0x5ef7,0x5f1f,0x608c,
+    0x62b5,0x633a,0x63d0,0x68af,0x6c40,0x7887,0x798e,0x7a0b,0x7de0,0x8247,
+    0x8a02,0x8ae6,0x8e44,0x9013
+  },
+  {				/* ku 25 */
+    0x90b8,0x912d,0x91d8,0x9f0e,0x6ce5,0x6458,0x64e2,0x6575,0x6ef4,0x7684,
+    0x7b1b,0x9069,0x93d1,0x6eba,0x54f2,0x5fb9,0x64a4,0x8f4d,0x8fed,0x9244,
+    0x5178,0x586b,0x5929,0x5c55,0x5e97,0x6dfb,0x7e8f,0x751c,0x8cbc,0x8ee2,
+    0x985b,0x70b9,0x4f1d,0x6bbf,0x6fb1,0x7530,0x96fb,0x514e,0x5410,0x5835,
+    0x5857,0x59ac,0x5c60,0x5f92,0x6597,0x675c,0x6e21,0x767b,0x83df,0x8ced,
+    0x9014,0x90fd,0x934d,0x7825,0x783a,0x52aa,0x5ea6,0x571f,0x5974,0x6012,
+    0x5012,0x515a,0x51ac,0x51cd,0x5200,0x5510,0x5854,0x5858,0x5957,0x5b95,
+    0x5cf6,0x5d8b,0x60bc,0x6295,0x642d,0x6771,0x6843,0x68bc,0x68df,0x76d7,
+    0x6dd8,0x6e6f,0x6d9b,0x706f,0x71c8,0x5f53,0x75d8,0x7977,0x7b49,0x7b54,
+    0x7b52,0x7cd6,0x7d71,0x5230
+  },
+  {				/* ku 26 */
+    0x8463,0x8569,0x85e4,0x8a0e,0x8b04,0x8c46,0x8e0f,0x9003,0x900f,0x9419,
+    0x9676,0x982d,0x9a30,0x95d8,0x50cd,0x52d5,0x540c,0x5802,0x5c0e,0x61a7,
+    0x649e,0x6d1e,0x77b3,0x7ae5,0x80f4,0x8404,0x9053,0x9285,0x5ce0,0x9d07,
+    0x533f,0x5f97,0x5fb3,0x6d9c,0x7279,0x7763,0x79bf,0x7be4,0x6bd2,0x72ec,
+    0x8aad,0x6803,0x6a61,0x51f8,0x7a81,0x6934,0x5c4a,0x9cf6,0x82eb,0x5bc5,
+    0x9149,0x701e,0x5678,0x5c6f,0x60c7,0x6566,0x6c8c,0x8c5a,0x9041,0x9813,
+    0x5451,0x66c7,0x920d,0x5948,0x90a3,0x5185,0x4e4d,0x51ea,0x8599,0x8b0e,
+    0x7058,0x637a,0x934b,0x6962,0x99b4,0x7e04,0x7577,0x5357,0x6960,0x8edf,
+    0x96e3,0x6c5d,0x4e8c,0x5c3c,0x5f10,0x8fe9,0x5302,0x8cd1,0x8089,0x8679,
+    0x5eff,0x65e5,0x4e73,0x5165
+  },
+  {				/* ku 27 */
+    0x5982,0x5c3f,0x97ee,0x4efb,0x598a,0x5fcd,0x8a8d,0x6fe1,0x79b0,0x7962,
+    0x5be7,0x8471,0x732b,0x71b1,0x5e74,0x5ff5,0x637b,0x649a,0x71c3,0x7c98,
+    0x4e43,0x5efc,0x4e4b,0x57dc,0x56a2,0x60a9,0x6fc3,0x7d0d,0x80fd,0x8133,
+    0x81bf,0x8fb2,0x8997,0x86a4,0x5df4,0x628a,0x64ad,0x8987,0x6777,0x6ce2,
+    0x6d3e,0x7436,0x7834,0x5a46,0x7f75,0x82ad,0x99ac,0x4ff3,0x5ec3,0x62dd,
+    0x6392,0x6557,0x676f,0x76c3,0x724c,0x80cc,0x80ba,0x8f29,0x914d,0x500d,
+    0x57f9,0x5a92,0x6885,0x6973,0x7164,0x72fd,0x8cb7,0x58f2,0x8ce0,0x966a,
+    0x9019,0x877f,0x79e4,0x77e7,0x8429,0x4f2f,0x5265,0x535a,0x62cd,0x67cf,
+    0x6cca,0x767d,0x7b94,0x7c95,0x8236,0x8584,0x8feb,0x66dd,0x6f20,0x7206,
+    0x7e1b,0x83ab,0x99c1,0x9ea6
+  },
+  {				/* ku 28 */
+    0x51fd,0x7bb1,0x7872,0x7bb8,0x8087,0x7b48,0x6ae8,0x5e61,0x808c,0x7551,
+    0x7560,0x516b,0x9262,0x6e8c,0x767a,0x9197,0x9aea,0x4f10,0x7f70,0x629c,
+    0x7b4f,0x95a5,0x9ce9,0x567a,0x5859,0x86e4,0x96bc,0x4f34,0x5224,0x534a,
+    0x53cd,0x53db,0x5e06,0x642c,0x6591,0x677f,0x6c3e,0x6c4e,0x7248,0x72af,
+    0x73ed,0x7554,0x7e41,0x822c,0x85e9,0x8ca9,0x7bc4,0x91c6,0x7169,0x9812,
+    0x98ef,0x633d,0x6669,0x756a,0x76e4,0x78d0,0x8543,0x86ee,0x532a,0x5351,
+    0x5426,0x5983,0x5e87,0x5f7c,0x60b2,0x6249,0x6279,0x62ab,0x6590,0x6bd4,
+    0x6ccc,0x75b2,0x76ae,0x7891,0x79d8,0x7dcb,0x7f77,0x80a5,0x88ab,0x8ab9,
+    0x8cbb,0x907f,0x975e,0x98db,0x6a0b,0x7c38,0x5099,0x5c3e,0x5fae,0x6787,
+    0x6bd8,0x7435,0x7709,0x7f8e
+  },
+  {				/* ku 29 */
+    0x9f3b,0x67ca,0x7a17,0x5339,0x758b,0x9aed,0x5f66,0x819d,0x83f1,0x8098,
+    0x5f3c,0x5fc5,0x7562,0x7b46,0x903c,0x6867,0x59eb,0x5a9b,0x7d10,0x767e,
+    0x8b2c,0x4ff5,0x5f6a,0x6a19,0x6c37,0x6f02,0x74e2,0x7968,0x8868,0x8a55,
+    0x8c79,0x5edf,0x63cf,0x75c5,0x79d2,0x82d7,0x9328,0x92f2,0x849c,0x86ed,
+    0x9c2d,0x54c1,0x5f6c,0x658c,0x6d5c,0x7015,0x8ca7,0x8cd3,0x983b,0x654f,
+    0x74f6,0x4e0d,0x4ed8,0x57e0,0x592b,0x5a66,0x5bcc,0x51a8,0x5e03,0x5e9c,
+    0x6016,0x6276,0x6577,0x65a7,0x666e,0x6d6e,0x7236,0x7b26,0x8150,0x819a,
+    0x8299,0x8b5c,0x8ca0,0x8ce6,0x8d74,0x961c,0x9644,0x4fae,0x64ab,0x6b66,
+    0x821e,0x8461,0x856a,0x90e8,0x5c01,0x6953,0x98a8,0x847a,0x8557,0x4f0f,
+    0x526f,0x5fa9,0x5e45,0x670d
+  },
+  {				/* ku 2a */
+    0x798f,0x8179,0x8907,0x8986,0x6df5,0x5f17,0x6255,0x6cb8,0x4ecf,0x7269,
+    0x9b92,0x5206,0x543b,0x5674,0x58b3,0x61a4,0x626e,0x711a,0x596e,0x7c89,
+    0x7cde,0x7d1b,0x96f0,0x6587,0x805e,0x4e19,0x4f75,0x5175,0x5840,0x5e63,
+    0x5e73,0x5f0a,0x67c4,0x4e26,0x853d,0x9589,0x965b,0x7c73,0x9801,0x50fb,
+    0x58c1,0x7656,0x78a7,0x5225,0x77a5,0x8511,0x7b86,0x504f,0x5909,0x7247,
+    0x7bc7,0x7de8,0x8fba,0x8fd4,0x904d,0x4fbf,0x52c9,0x5a29,0x5f01,0x97ad,
+    0x4fdd,0x8217,0x92ea,0x5703,0x6355,0x6b69,0x752b,0x88dc,0x8f14,0x7a42,
+    0x52df,0x5893,0x6155,0x620a,0x66ae,0x6bcd,0x7c3f,0x83e9,0x5023,0x4ff8,
+    0x5305,0x5446,0x5831,0x5949,0x5b9d,0x5cf0,0x5cef,0x5d29,0x5e96,0x62b1,
+    0x6367,0x653e,0x65b9,0x670b
+  },
+  {				/* ku 2b */
+    0x6cd5,0x6ce1,0x70f9,0x7832,0x7e2b,0x80de,0x82b3,0x840c,0x84ec,0x8702,
+    0x8912,0x8a2a,0x8c4a,0x90a6,0x92d2,0x98fd,0x9cf3,0x9d6c,0x4e4f,0x4ea1,
+    0x508d,0x5256,0x574a,0x59a8,0x5e3d,0x5fd8,0x5fd9,0x623f,0x66b4,0x671b,
+    0x67d0,0x68d2,0x5192,0x7d21,0x80aa,0x81a8,0x8b00,0x8c8c,0x8cbf,0x927e,
+    0x9632,0x5420,0x982c,0x5317,0x50d5,0x535c,0x58a8,0x64b2,0x6734,0x7267,
+    0x7766,0x7a46,0x91e6,0x52c3,0x6ca1,0x6b86,0x5800,0x5e4c,0x5954,0x672c,
+    0x7ffb,0x51e1,0x76c6,0x6469,0x78e8,0x9b54,0x9ebb,0x57cb,0x59b9,0x6627,
+    0x679a,0x6bce,0x54e9,0x69d9,0x5e55,0x819c,0x6795,0x9baa,0x67fe,0x9c52,
+    0x685d,0x4ea6,0x4fe3,0x53c8,0x62b9,0x672b,0x6cab,0x8fc4,0x4fad,0x7e6d,
+    0x9ebf,0x4e07,0x6162,0x6e80
+  },
+  {				/* ku 2c */
+    0x6f2b,0x8513,0x5473,0x672a,0x9b45,0x5df3,0x7b95,0x5cac,0x5bc6,0x871c,
+    0x6e4a,0x84d1,0x7a14,0x8108,0x5999,0x7c8d,0x6c11,0x7720,0x52d9,0x5922,
+    0x7121,0x725f,0x77db,0x9727,0x9d61,0x690b,0x5a7f,0x5a18,0x51a5,0x540d,
+    0x547d,0x660e,0x76df,0x8ff7,0x9298,0x9cf4,0x59ea,0x725d,0x6ec5,0x514d,
+    0x68c9,0x7dbf,0x7dec,0x9762,0x9eba,0x6478,0x6a21,0x8302,0x5984,0x5b5f,
+    0x6bdb,0x731b,0x76f2,0x7db2,0x8017,0x8499,0x5132,0x6728,0x9ed9,0x76ee,
+    0x6762,0x52ff,0x9905,0x5c24,0x623b,0x7c7e,0x8cb0,0x554f,0x60b6,0x7d0b,
+    0x9580,0x5301,0x4e5f,0x51b6,0x591c,0x723a,0x8036,0x91ce,0x5f25,0x77e2,
+    0x5384,0x5f79,0x7d04,0x85ac,0x8a33,0x8e8d,0x9756,0x67f3,0x85ae,0x9453,
+    0x6109,0x6108,0x6cb9,0x7652
+  },
+  {				/* ku 2d */
+    0x8aed,0x8f38,0x552f,0x4f51,0x512a,0x52c7,0x53cb,0x5ba5,0x5e7d,0x60a0,
+    0x6182,0x63d6,0x6709,0x67da,0x6e67,0x6d8c,0x7336,0x7337,0x7531,0x7950,
+    0x88d5,0x8a98,0x904a,0x9091,0x90f5,0x96c4,0x878d,0x5915,0x4e88,0x4f59,
+    0x4e0e,0x8a89,0x8f3f,0x9810,0x50ad,0x5e7c,0x5996,0x5bb9,0x5eb8,0x63da,
+    0x63fa,0x64c1,0x66dc,0x694a,0x69d8,0x6d0b,0x6eb6,0x7194,0x7528,0x7aaf,
+    0x7f8a,0x8000,0x8449,0x84c9,0x8981,0x8b21,0x8e0a,0x9065,0x967d,0x990a,
+    0x617e,0x6291,0x6b32,0x6c83,0x6d74,0x7fcc,0x7ffc,0x6dc0,0x7f85,0x87ba,
+    0x88f8,0x6765,0x83b1,0x983c,0x96f7,0x6d1b,0x7d61,0x843d,0x916a,0x4e71,
+    0x5375,0x5d50,0x6b04,0x6feb,0x85cd,0x862d,0x89a7,0x5229,0x540f,0x5c65,
+    0x674e,0x68a8,0x7406,0x7483
+  },
+  {				/* ku 2e */
+    0x75e2,0x88cf,0x88e1,0x91cc,0x96e2,0x9678,0x5f8b,0x7387,0x7acb,0x844e,
+    0x63a0,0x7565,0x5289,0x6d41,0x6e9c,0x7409,0x7559,0x786b,0x7c92,0x9686,
+    0x7adc,0x9f8d,0x4fb6,0x616e,0x65c5,0x865c,0x4e86,0x4eae,0x50da,0x4e21,
+    0x51cc,0x5bee,0x6599,0x6881,0x6dbc,0x731f,0x7642,0x77ad,0x7a1c,0x7ce7,
+    0x826f,0x8ad2,0x907c,0x91cf,0x9675,0x9818,0x529b,0x7dd1,0x502b,0x5398,
+    0x6797,0x6dcb,0x71d0,0x7433,0x81e8,0x8f2a,0x96a3,0x9c57,0x9e9f,0x7460,
+    0x5841,0x6d99,0x7d2f,0x985e,0x4ee4,0x4f36,0x4f8b,0x51b7,0x52b1,0x5dba,
+    0x601c,0x73b2,0x793c,0x82d3,0x9234,0x96b7,0x96f6,0x970a,0x9e97,0x9f62,
+    0x66a6,0x6b74,0x5217,0x52a3,0x70c8,0x88c2,0x5ec9,0x604b,0x6190,0x6f23,
+    0x7149,0x7c3e,0x7df4,0x806f
+  },
+  {				/* ku 2f */
+    0x84ee,0x9023,0x932c,0x5442,0x9b6f,0x6ad3,0x7089,0x8cc2,0x8def,0x9732,
+    0x52b4,0x5a41,0x5eca,0x5f04,0x6717,0x697c,0x6994,0x6d6a,0x6f0f,0x7262,
+    0x72fc,0x7bed,0x8001,0x807e,0x874b,0x90ce,0x516d,0x9e93,0x7984,0x808b,
+    0x9332,0x8ad6,0x502d,0x548c,0x8a71,0x6b6a,0x8cc4,0x8107,0x60d1,0x67a0,
+    0x9df2,0x4e99,0x4e98,0x9c10,0x8a6b,0x85c1,0x8568,0x6900,0x6e7e,0x7897,
+    0x8155,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 30 */
+    0x5f0c,0x4e10,0x4e15,0x4e2a,0x4e31,0x4e36,0x4e3c,0x4e3f,0x4e42,0x4e56,
+    0x4e58,0x4e82,0x4e85,0x8c6b,0x4e8a,0x8212,0x5f0d,0x4e8e,0x4e9e,0x4e9f,
+    0x4ea0,0x4ea2,0x4eb0,0x4eb3,0x4eb6,0x4ece,0x4ecd,0x4ec4,0x4ec6,0x4ec2,
+    0x4ed7,0x4ede,0x4eed,0x4edf,0x4ef7,0x4f09,0x4f5a,0x4f30,0x4f5b,0x4f5d,
+    0x4f57,0x4f47,0x4f76,0x4f88,0x4f8f,0x4f98,0x4f7b,0x4f69,0x4f70,0x4f91,
+    0x4f6f,0x4f86,0x4f96,0x5118,0x4fd4,0x4fdf,0x4fce,0x4fd8,0x4fdb,0x4fd1,
+    0x4fda,0x4fd0,0x4fe4,0x4fe5,0x501a,0x5028,0x5014,0x502a,0x5025,0x5005,
+    0x4f1c,0x4ff6,0x5021,0x5029,0x502c,0x4ffe,0x4fef,0x5011,0x5006,0x5043,
+    0x5047,0x6703,0x5055,0x5050,0x5048,0x505a,0x5056,0x506c,0x5078,0x5080,
+    0x509a,0x5085,0x50b4,0x50b2
+  },
+  {				/* ku 31 */
+    0x50c9,0x50ca,0x50b3,0x50c2,0x50d6,0x50de,0x50e5,0x50ed,0x50e3,0x50ee,
+    0x50f9,0x50f5,0x5109,0x5101,0x5102,0x5116,0x5115,0x5114,0x511a,0x5121,
+    0x513a,0x5137,0x513c,0x513b,0x513f,0x5140,0x5152,0x514c,0x5154,0x5162,
+    0x7af8,0x5169,0x516a,0x516e,0x5180,0x5182,0x56d8,0x518c,0x5189,0x518f,
+    0x5191,0x5193,0x5195,0x5196,0x51a4,0x51a6,0x51a2,0x51a9,0x51aa,0x51ab,
+    0x51b3,0x51b1,0x51b2,0x51b0,0x51b5,0x51bd,0x51c5,0x51c9,0x51db,0x51e0,
+    0x8655,0x51e9,0x51ed,0x51f0,0x51f5,0x51fe,0x5204,0x520b,0x5214,0x520e,
+    0x5227,0x522a,0x522e,0x5233,0x5239,0x524f,0x5244,0x524b,0x524c,0x525e,
+    0x5254,0x526a,0x5274,0x5269,0x5273,0x527f,0x527d,0x528d,0x5294,0x5292,
+    0x5271,0x5288,0x5291,0x8fa8
+  },
+  {				/* ku 32 */
+    0x8fa7,0x52ac,0x52ad,0x52bc,0x52b5,0x52c1,0x52cd,0x52d7,0x52de,0x52e3,
+    0x52e6,0x98ed,0x52e0,0x52f3,0x52f5,0x52f8,0x52f9,0x5306,0x5308,0x7538,
+    0x530d,0x5310,0x530f,0x5315,0x531a,0x5323,0x532f,0x5331,0x5333,0x5338,
+    0x5340,0x5346,0x5345,0x4e17,0x5349,0x534d,0x51d6,0x535e,0x5369,0x536e,
+    0x5918,0x537b,0x5377,0x5382,0x5396,0x53a0,0x53a6,0x53a5,0x53ae,0x53b0,
+    0x53b6,0x53c3,0x7c12,0x96d9,0x53df,0x66fc,0x71ee,0x53ee,0x53e8,0x53ed,
+    0x53fa,0x5401,0x543d,0x5440,0x542c,0x542d,0x543c,0x542e,0x5436,0x5429,
+    0x541d,0x544e,0x548f,0x5475,0x548e,0x545f,0x5471,0x5477,0x5470,0x5492,
+    0x547b,0x5480,0x5476,0x5484,0x5490,0x5486,0x54c7,0x54a2,0x54b8,0x54a5,
+    0x54ac,0x54c4,0x54c8,0x54a8
+  },
+  {				/* ku 33 */
+    0x54ab,0x54c2,0x54a4,0x54be,0x54bc,0x54d8,0x54e5,0x54e6,0x550f,0x5514,
+    0x54fd,0x54ee,0x54ed,0x54fa,0x54e2,0x5539,0x5540,0x5563,0x554c,0x552e,
+    0x555c,0x5545,0x5556,0x5557,0x5538,0x5533,0x555d,0x5599,0x5580,0x54af,
+    0x558a,0x559f,0x557b,0x557e,0x5598,0x559e,0x55ae,0x557c,0x5583,0x55a9,
+    0x5587,0x55a8,0x55da,0x55c5,0x55df,0x55c4,0x55dc,0x55e4,0x55d4,0x5614,
+    0x55f7,0x5616,0x55fe,0x55fd,0x561b,0x55f9,0x564e,0x5650,0x71df,0x5634,
+    0x5636,0x5632,0x5638,0x566b,0x5664,0x562f,0x566c,0x566a,0x5686,0x5680,
+    0x568a,0x56a0,0x5694,0x568f,0x56a5,0x56ae,0x56b6,0x56b4,0x56c2,0x56bc,
+    0x56c1,0x56c3,0x56c0,0x56c8,0x56ce,0x56d1,0x56d3,0x56d7,0x56ee,0x56f9,
+    0x5700,0x56ff,0x5704,0x5709
+  },
+  {				/* ku 34 */
+    0x5708,0x570b,0x570d,0x5713,0x5718,0x5716,0x55c7,0x571c,0x5726,0x5737,
+    0x5738,0x574e,0x573b,0x5740,0x574f,0x5769,0x57c0,0x5788,0x5761,0x577f,
+    0x5789,0x5793,0x57a0,0x57b3,0x57a4,0x57aa,0x57b0,0x57c3,0x57c6,0x57d4,
+    0x57d2,0x57d3,0x580a,0x57d6,0x57e3,0x580b,0x5819,0x581d,0x5872,0x5821,
+    0x5862,0x584b,0x5870,0x6bc0,0x5852,0x583d,0x5879,0x5885,0x58b9,0x589f,
+    0x58ab,0x58ba,0x58de,0x58bb,0x58b8,0x58ae,0x58c5,0x58d3,0x58d1,0x58d7,
+    0x58d9,0x58d8,0x58e5,0x58dc,0x58e4,0x58df,0x58ef,0x58fa,0x58f9,0x58fb,
+    0x58fc,0x58fd,0x5902,0x590a,0x5910,0x591b,0x68a6,0x5925,0x592c,0x592d,
+    0x5932,0x5938,0x593e,0x7ad2,0x5955,0x5950,0x594e,0x595a,0x5958,0x5962,
+    0x5960,0x5967,0x596c,0x5969
+  },
+  {				/* ku 35 */
+    0x5978,0x5981,0x599d,0x4f5e,0x4fab,0x59a3,0x59b2,0x59c6,0x59e8,0x59dc,
+    0x598d,0x59d9,0x59da,0x5a25,0x5a1f,0x5a11,0x5a1c,0x5a09,0x5a1a,0x5a40,
+    0x5a6c,0x5a49,0x5a35,0x5a36,0x5a62,0x5a6a,0x5a9a,0x5abc,0x5abe,0x5acb,
+    0x5ac2,0x5abd,0x5ae3,0x5ad7,0x5ae6,0x5ae9,0x5ad6,0x5afa,0x5afb,0x5b0c,
+    0x5b0b,0x5b16,0x5b32,0x5ad0,0x5b2a,0x5b36,0x5b3e,0x5b43,0x5b45,0x5b40,
+    0x5b51,0x5b55,0x5b5a,0x5b5b,0x5b65,0x5b69,0x5b70,0x5b73,0x5b75,0x5b78,
+    0x6588,0x5b7a,0x5b80,0x5b83,0x5ba6,0x5bb8,0x5bc3,0x5bc7,0x5bc9,0x5bd4,
+    0x5bd0,0x5be4,0x5be6,0x5be2,0x5bde,0x5be5,0x5beb,0x5bf0,0x5bf6,0x5bf3,
+    0x5c05,0x5c07,0x5c08,0x5c0d,0x5c13,0x5c20,0x5c22,0x5c28,0x5c38,0x5c39,
+    0x5c41,0x5c46,0x5c4e,0x5c53
+  },
+  {				/* ku 36 */
+    0x5c50,0x5c4f,0x5b71,0x5c6c,0x5c6e,0x4e62,0x5c76,0x5c79,0x5c8c,0x5c91,
+    0x5c94,0x599b,0x5cab,0x5cbb,0x5cb6,0x5cbc,0x5cb7,0x5cc5,0x5cbe,0x5cc7,
+    0x5cd9,0x5ce9,0x5cfd,0x5cfa,0x5ced,0x5d8c,0x5cea,0x5d0b,0x5d15,0x5d17,
+    0x5d5c,0x5d1f,0x5d1b,0x5d11,0x5d14,0x5d22,0x5d1a,0x5d19,0x5d18,0x5d4c,
+    0x5d52,0x5d4e,0x5d4b,0x5d6c,0x5d73,0x5d76,0x5d87,0x5d84,0x5d82,0x5da2,
+    0x5d9d,0x5dac,0x5dae,0x5dbd,0x5d90,0x5db7,0x5dbc,0x5dc9,0x5dcd,0x5dd3,
+    0x5dd2,0x5dd6,0x5ddb,0x5deb,0x5df2,0x5df5,0x5e0b,0x5e1a,0x5e19,0x5e11,
+    0x5e1b,0x5e36,0x5e37,0x5e44,0x5e43,0x5e40,0x5e4e,0x5e57,0x5e54,0x5e5f,
+    0x5e62,0x5e64,0x5e47,0x5e75,0x5e76,0x5e7a,0x9ebc,0x5e7f,0x5ea0,0x5ec1,
+    0x5ec2,0x5ec8,0x5ed0,0x5ecf
+  },
+  {				/* ku 37 */
+    0x5ed6,0x5ee3,0x5edd,0x5eda,0x5edb,0x5ee2,0x5ee1,0x5ee8,0x5ee9,0x5eec,
+    0x5ef1,0x5ef3,0x5ef0,0x5ef4,0x5ef8,0x5efe,0x5f03,0x5f09,0x5f5d,0x5f5c,
+    0x5f0b,0x5f11,0x5f16,0x5f29,0x5f2d,0x5f38,0x5f41,0x5f48,0x5f4c,0x5f4e,
+    0x5f2f,0x5f51,0x5f56,0x5f57,0x5f59,0x5f61,0x5f6d,0x5f73,0x5f77,0x5f83,
+    0x5f82,0x5f7f,0x5f8a,0x5f88,0x5f91,0x5f87,0x5f9e,0x5f99,0x5f98,0x5fa0,
+    0x5fa8,0x5fad,0x5fbc,0x5fd6,0x5ffb,0x5fe4,0x5ff8,0x5ff1,0x5fdd,0x60b3,
+    0x5fff,0x6021,0x6060,0x6019,0x6010,0x6029,0x600e,0x6031,0x601b,0x6015,
+    0x602b,0x6026,0x600f,0x603a,0x605a,0x6041,0x606a,0x6077,0x605f,0x604a,
+    0x6046,0x604d,0x6063,0x6043,0x6064,0x6042,0x606c,0x606b,0x6059,0x6081,
+    0x608d,0x60e7,0x6083,0x609a
+  },
+  {				/* ku 38 */
+    0x6084,0x609b,0x6096,0x6097,0x6092,0x60a7,0x608b,0x60e1,0x60b8,0x60e0,
+    0x60d3,0x60b4,0x5ff0,0x60bd,0x60c6,0x60b5,0x60d8,0x614d,0x6115,0x6106,
+    0x60f6,0x60f7,0x6100,0x60f4,0x60fa,0x6103,0x6121,0x60fb,0x60f1,0x610d,
+    0x610e,0x6147,0x613e,0x6128,0x6127,0x614a,0x613f,0x613c,0x612c,0x6134,
+    0x613d,0x6142,0x6144,0x6173,0x6177,0x6158,0x6159,0x615a,0x616b,0x6174,
+    0x616f,0x6165,0x6171,0x615f,0x615d,0x6153,0x6175,0x6199,0x6196,0x6187,
+    0x61ac,0x6194,0x619a,0x618a,0x6191,0x61ab,0x61ae,0x61cc,0x61ca,0x61c9,
+    0x61f7,0x61c8,0x61c3,0x61c6,0x61ba,0x61cb,0x7f79,0x61cd,0x61e6,0x61e3,
+    0x61f6,0x61fa,0x61f4,0x61ff,0x61fd,0x61fc,0x61fe,0x6200,0x6208,0x6209,
+    0x620d,0x620c,0x6214,0x621b
+  },
+  {				/* ku 39 */
+    0x621e,0x6221,0x622a,0x622e,0x6230,0x6232,0x6233,0x6241,0x624e,0x625e,
+    0x6263,0x625b,0x6260,0x6268,0x627c,0x6282,0x6289,0x627e,0x6292,0x6293,
+    0x6296,0x62d4,0x6283,0x6294,0x62d7,0x62d1,0x62bb,0x62cf,0x62ff,0x62c6,
+    0x64d4,0x62c8,0x62dc,0x62cc,0x62ca,0x62c2,0x62c7,0x629b,0x62c9,0x630c,
+    0x62ee,0x62f1,0x6327,0x6302,0x6308,0x62ef,0x62f5,0x6350,0x633e,0x634d,
+    0x641c,0x634f,0x6396,0x638e,0x6380,0x63ab,0x6376,0x63a3,0x638f,0x6389,
+    0x639f,0x63b5,0x636b,0x6369,0x63be,0x63e9,0x63c0,0x63c6,0x63e3,0x63c9,
+    0x63d2,0x63f6,0x63c4,0x6416,0x6434,0x6406,0x6413,0x6426,0x6436,0x651d,
+    0x6417,0x6428,0x640f,0x6467,0x646f,0x6476,0x644e,0x652a,0x6495,0x6493,
+    0x64a5,0x64a9,0x6488,0x64bc
+  },
+  {				/* ku 3a */
+    0x64da,0x64d2,0x64c5,0x64c7,0x64bb,0x64d8,0x64c2,0x64f1,0x64e7,0x8209,
+    0x64e0,0x64e1,0x62ac,0x64e3,0x64ef,0x652c,0x64f6,0x64f4,0x64f2,0x64fa,
+    0x6500,0x64fd,0x6518,0x651c,0x6505,0x6524,0x6523,0x652b,0x6534,0x6535,
+    0x6537,0x6536,0x6538,0x754b,0x6548,0x6556,0x6555,0x654d,0x6558,0x655e,
+    0x655d,0x6572,0x6578,0x6582,0x6583,0x8b8a,0x659b,0x659f,0x65ab,0x65b7,
+    0x65c3,0x65c6,0x65c1,0x65c4,0x65cc,0x65d2,0x65db,0x65d9,0x65e0,0x65e1,
+    0x65f1,0x6772,0x660a,0x6603,0x65fb,0x6773,0x6635,0x6636,0x6634,0x661c,
+    0x664f,0x6644,0x6649,0x6641,0x665e,0x665d,0x6664,0x6667,0x6668,0x665f,
+    0x6662,0x6670,0x6683,0x6688,0x668e,0x6689,0x6684,0x6698,0x669d,0x66c1,
+    0x66b9,0x66c9,0x66be,0x66bc
+  },
+  {				/* ku 3b */
+    0x66c4,0x66b8,0x66d6,0x66da,0x66e0,0x663f,0x66e6,0x66e9,0x66f0,0x66f5,
+    0x66f7,0x670f,0x6716,0x671e,0x6726,0x6727,0x9738,0x672e,0x673f,0x6736,
+    0x6741,0x6738,0x6737,0x6746,0x675e,0x6760,0x6759,0x6763,0x6764,0x6789,
+    0x6770,0x67a9,0x677c,0x676a,0x678c,0x678b,0x67a6,0x67a1,0x6785,0x67b7,
+    0x67ef,0x67b4,0x67ec,0x67b3,0x67e9,0x67b8,0x67e4,0x67de,0x67dd,0x67e2,
+    0x67ee,0x67b9,0x67ce,0x67c6,0x67e7,0x6a9c,0x681e,0x6846,0x6829,0x6840,
+    0x684d,0x6832,0x684e,0x68b3,0x682b,0x6859,0x6863,0x6877,0x687f,0x689f,
+    0x688f,0x68ad,0x6894,0x689d,0x689b,0x6883,0x6aae,0x68b9,0x6874,0x68b5,
+    0x68a0,0x68ba,0x690f,0x688d,0x687e,0x6901,0x68ca,0x6908,0x68d8,0x6922,
+    0x6926,0x68e1,0x690c,0x68cd
+  },
+  {				/* ku 3c */
+    0x68d4,0x68e7,0x68d5,0x6936,0x6912,0x6904,0x68d7,0x68e3,0x6925,0x68f9,
+    0x68e0,0x68ef,0x6928,0x692a,0x691a,0x6923,0x6921,0x68c6,0x6979,0x6977,
+    0x695c,0x6978,0x696b,0x6954,0x697e,0x696e,0x6939,0x6974,0x693d,0x6959,
+    0x6930,0x6961,0x695e,0x695d,0x6981,0x696a,0x69b2,0x69ae,0x69d0,0x69bf,
+    0x69c1,0x69d3,0x69be,0x69ce,0x5be8,0x69ca,0x69dd,0x69bb,0x69c3,0x69a7,
+    0x6a2e,0x6991,0x69a0,0x699c,0x6995,0x69b4,0x69de,0x69e8,0x6a02,0x6a1b,
+    0x69ff,0x6b0a,0x69f9,0x69f2,0x69e7,0x6a05,0x69b1,0x6a1e,0x69ed,0x6a14,
+    0x69eb,0x6a0a,0x6a12,0x6ac1,0x6a23,0x6a13,0x6a44,0x6a0c,0x6a72,0x6a36,
+    0x6a78,0x6a47,0x6a62,0x6a59,0x6a66,0x6a48,0x6a38,0x6a22,0x6a90,0x6a8d,
+    0x6aa0,0x6a84,0x6aa2,0x6aa3
+  },
+  {				/* ku 3d */
+    0x6a97,0x8617,0x6abb,0x6ac3,0x6ac2,0x6ab8,0x6ab3,0x6aac,0x6ade,0x6ad1,
+    0x6adf,0x6aaa,0x6ada,0x6aea,0x6afb,0x6b05,0x8616,0x6afa,0x6b12,0x6b16,
+    0x9b31,0x6b1f,0x6b38,0x6b37,0x76dc,0x6b39,0x98ee,0x6b47,0x6b43,0x6b49,
+    0x6b50,0x6b59,0x6b54,0x6b5b,0x6b5f,0x6b61,0x6b78,0x6b79,0x6b7f,0x6b80,
+    0x6b84,0x6b83,0x6b8d,0x6b98,0x6b95,0x6b9e,0x6ba4,0x6baa,0x6bab,0x6baf,
+    0x6bb2,0x6bb1,0x6bb3,0x6bb7,0x6bbc,0x6bc6,0x6bcb,0x6bd3,0x6bdf,0x6bec,
+    0x6beb,0x6bf3,0x6bef,0x9ebe,0x6c08,0x6c13,0x6c14,0x6c1b,0x6c24,0x6c23,
+    0x6c5e,0x6c55,0x6c62,0x6c6a,0x6c82,0x6c8d,0x6c9a,0x6c81,0x6c9b,0x6c7e,
+    0x6c68,0x6c73,0x6c92,0x6c90,0x6cc4,0x6cf1,0x6cd3,0x6cbd,0x6cd7,0x6cc5,
+    0x6cdd,0x6cae,0x6cb1,0x6cbe
+  },
+  {				/* ku 3e */
+    0x6cba,0x6cdb,0x6cef,0x6cd9,0x6cea,0x6d1f,0x884d,0x6d36,0x6d2b,0x6d3d,
+    0x6d38,0x6d19,0x6d35,0x6d33,0x6d12,0x6d0c,0x6d63,0x6d93,0x6d64,0x6d5a,
+    0x6d79,0x6d59,0x6d8e,0x6d95,0x6fe4,0x6d85,0x6df9,0x6e15,0x6e0a,0x6db5,
+    0x6dc7,0x6de6,0x6db8,0x6dc6,0x6dec,0x6dde,0x6dcc,0x6de8,0x6dd2,0x6dc5,
+    0x6dfa,0x6dd9,0x6de4,0x6dd5,0x6dea,0x6dee,0x6e2d,0x6e6e,0x6e2e,0x6e19,
+    0x6e72,0x6e5f,0x6e3e,0x6e23,0x6e6b,0x6e2b,0x6e76,0x6e4d,0x6e1f,0x6e43,
+    0x6e3a,0x6e4e,0x6e24,0x6eff,0x6e1d,0x6e38,0x6e82,0x6eaa,0x6e98,0x6ec9,
+    0x6eb7,0x6ed3,0x6ebd,0x6eaf,0x6ec4,0x6eb2,0x6ed4,0x6ed5,0x6e8f,0x6ea5,
+    0x6ec2,0x6e9f,0x6f41,0x6f11,0x704c,0x6eec,0x6ef8,0x6efe,0x6f3f,0x6ef2,
+    0x6f31,0x6eef,0x6f32,0x6ecc
+  },
+  {				/* ku 3f */
+    0x6f3e,0x6f13,0x6ef7,0x6f86,0x6f7a,0x6f78,0x6f81,0x6f80,0x6f6f,0x6f5b,
+    0x6ff3,0x6f6d,0x6f82,0x6f7c,0x6f58,0x6f8e,0x6f91,0x6fc2,0x6f66,0x6fb3,
+    0x6fa3,0x6fa1,0x6fa4,0x6fb9,0x6fc6,0x6faa,0x6fdf,0x6fd5,0x6fec,0x6fd4,
+    0x6fd8,0x6ff1,0x6fee,0x6fdb,0x7009,0x700b,0x6ffa,0x7011,0x7001,0x700f,
+    0x6ffe,0x701b,0x701a,0x6f74,0x701d,0x7018,0x701f,0x7030,0x703e,0x7032,
+    0x7051,0x7063,0x7099,0x7092,0x70af,0x70f1,0x70ac,0x70b8,0x70b3,0x70ae,
+    0x70df,0x70cb,0x70dd,0x70d9,0x7109,0x70fd,0x711c,0x7119,0x7165,0x7155,
+    0x7188,0x7166,0x7162,0x714c,0x7156,0x716c,0x718f,0x71fb,0x7184,0x7195,
+    0x71a8,0x71ac,0x71d7,0x71b9,0x71be,0x71d2,0x71c9,0x71d4,0x71ce,0x71e0,
+    0x71ec,0x71e7,0x71f5,0x71fc
+  },
+  {				/* ku 40 */
+    0x71f9,0x71ff,0x720d,0x7210,0x721b,0x7228,0x722d,0x722c,0x7230,0x7232,
+    0x723b,0x723c,0x723f,0x7240,0x7246,0x724b,0x7258,0x7274,0x727e,0x7282,
+    0x7281,0x7287,0x7292,0x7296,0x72a2,0x72a7,0x72b9,0x72b2,0x72c3,0x72c6,
+    0x72c4,0x72ce,0x72d2,0x72e2,0x72e0,0x72e1,0x72f9,0x72f7,0x500f,0x7317,
+    0x730a,0x731c,0x7316,0x731d,0x7334,0x732f,0x7329,0x7325,0x733e,0x734e,
+    0x734f,0x9ed8,0x7357,0x736a,0x7368,0x7370,0x7378,0x7375,0x737b,0x737a,
+    0x73c8,0x73b3,0x73ce,0x73bb,0x73c0,0x73e5,0x73ee,0x73de,0x74a2,0x7405,
+    0x746f,0x7425,0x73f8,0x7432,0x743a,0x7455,0x743f,0x745f,0x7459,0x7441,
+    0x745c,0x7469,0x7470,0x7463,0x746a,0x7476,0x747e,0x748b,0x749e,0x74a7,
+    0x74ca,0x74cf,0x74d4,0x73f1
+  },
+  {				/* ku 41 */
+    0x74e0,0x74e3,0x74e7,0x74e9,0x74ee,0x74f2,0x74f0,0x74f1,0x74f8,0x74f7,
+    0x7504,0x7503,0x7505,0x750c,0x750e,0x750d,0x7515,0x7513,0x751e,0x7526,
+    0x752c,0x753c,0x7544,0x754d,0x754a,0x7549,0x755b,0x7546,0x755a,0x7569,
+    0x7564,0x7567,0x756b,0x756d,0x7578,0x7576,0x7586,0x7587,0x7574,0x758a,
+    0x7589,0x7582,0x7594,0x759a,0x759d,0x75a5,0x75a3,0x75c2,0x75b3,0x75c3,
+    0x75b5,0x75bd,0x75b8,0x75bc,0x75b1,0x75cd,0x75ca,0x75d2,0x75d9,0x75e3,
+    0x75de,0x75fe,0x75ff,0x75fc,0x7601,0x75f0,0x75fa,0x75f2,0x75f3,0x760b,
+    0x760d,0x7609,0x761f,0x7627,0x7620,0x7621,0x7622,0x7624,0x7634,0x7630,
+    0x763b,0x7647,0x7648,0x7646,0x765c,0x7658,0x7661,0x7662,0x7668,0x7669,
+    0x766a,0x7667,0x766c,0x7670
+  },
+  {				/* ku 42 */
+    0x7672,0x7676,0x7678,0x767c,0x7680,0x7683,0x7688,0x768b,0x768e,0x7696,
+    0x7693,0x7699,0x769a,0x76b0,0x76b4,0x76b8,0x76b9,0x76ba,0x76c2,0x76cd,
+    0x76d6,0x76d2,0x76de,0x76e1,0x76e5,0x76e7,0x76ea,0x862f,0x76fb,0x7708,
+    0x7707,0x7704,0x7729,0x7724,0x771e,0x7725,0x7726,0x771b,0x7737,0x7738,
+    0x7747,0x775a,0x7768,0x776b,0x775b,0x7765,0x777f,0x777e,0x7779,0x778e,
+    0x778b,0x7791,0x77a0,0x779e,0x77b0,0x77b6,0x77b9,0x77bf,0x77bc,0x77bd,
+    0x77bb,0x77c7,0x77cd,0x77d7,0x77da,0x77dc,0x77e3,0x77ee,0x77fc,0x780c,
+    0x7812,0x7926,0x7820,0x792a,0x7845,0x788e,0x7874,0x7886,0x787c,0x789a,
+    0x788c,0x78a3,0x78b5,0x78aa,0x78af,0x78d1,0x78c6,0x78cb,0x78d4,0x78be,
+    0x78bc,0x78c5,0x78ca,0x78ec
+  },
+  {				/* ku 43 */
+    0x78e7,0x78da,0x78fd,0x78f4,0x7907,0x7912,0x7911,0x7919,0x792c,0x792b,
+    0x7940,0x7960,0x7957,0x795f,0x795a,0x7955,0x7953,0x797a,0x797f,0x798a,
+    0x799d,0x79a7,0x9f4b,0x79aa,0x79ae,0x79b3,0x79b9,0x79ba,0x79c9,0x79d5,
+    0x79e7,0x79ec,0x79e1,0x79e3,0x7a08,0x7a0d,0x7a18,0x7a19,0x7a20,0x7a1f,
+    0x7980,0x7a31,0x7a3b,0x7a3e,0x7a37,0x7a43,0x7a57,0x7a49,0x7a61,0x7a62,
+    0x7a69,0x9f9d,0x7a70,0x7a79,0x7a7d,0x7a88,0x7a97,0x7a95,0x7a98,0x7a96,
+    0x7aa9,0x7ac8,0x7ab0,0x7ab6,0x7ac5,0x7ac4,0x7abf,0x9083,0x7ac7,0x7aca,
+    0x7acd,0x7acf,0x7ad5,0x7ad3,0x7ad9,0x7ada,0x7add,0x7ae1,0x7ae2,0x7ae6,
+    0x7aed,0x7af0,0x7b02,0x7b0f,0x7b0a,0x7b06,0x7b33,0x7b18,0x7b19,0x7b1e,
+    0x7b35,0x7b28,0x7b36,0x7b50
+  },
+  {				/* ku 44 */
+    0x7b7a,0x7b04,0x7b4d,0x7b0b,0x7b4c,0x7b45,0x7b75,0x7b65,0x7b74,0x7b67,
+    0x7b70,0x7b71,0x7b6c,0x7b6e,0x7b9d,0x7b98,0x7b9f,0x7b8d,0x7b9c,0x7b9a,
+    0x7b8b,0x7b92,0x7b8f,0x7b5d,0x7b99,0x7bcb,0x7bc1,0x7bcc,0x7bcf,0x7bb4,
+    0x7bc6,0x7bdd,0x7be9,0x7c11,0x7c14,0x7be6,0x7be5,0x7c60,0x7c00,0x7c07,
+    0x7c13,0x7bf3,0x7bf7,0x7c17,0x7c0d,0x7bf6,0x7c23,0x7c27,0x7c2a,0x7c1f,
+    0x7c37,0x7c2b,0x7c3d,0x7c4c,0x7c43,0x7c54,0x7c4f,0x7c40,0x7c50,0x7c58,
+    0x7c5f,0x7c64,0x7c56,0x7c65,0x7c6c,0x7c75,0x7c83,0x7c90,0x7ca4,0x7cad,
+    0x7ca2,0x7cab,0x7ca1,0x7ca8,0x7cb3,0x7cb2,0x7cb1,0x7cae,0x7cb9,0x7cbd,
+    0x7cc0,0x7cc5,0x7cc2,0x7cd8,0x7cd2,0x7cdc,0x7ce2,0x9b3b,0x7cef,0x7cf2,
+    0x7cf4,0x7cf6,0x7cfa,0x7d06
+  },
+  {				/* ku 45 */
+    0x7d02,0x7d1c,0x7d15,0x7d0a,0x7d45,0x7d4b,0x7d2e,0x7d32,0x7d3f,0x7d35,
+    0x7d46,0x7d73,0x7d56,0x7d4e,0x7d72,0x7d68,0x7d6e,0x7d4f,0x7d63,0x7d93,
+    0x7d89,0x7d5b,0x7d8f,0x7d7d,0x7d9b,0x7dba,0x7dae,0x7da3,0x7db5,0x7dc7,
+    0x7dbd,0x7dab,0x7e3d,0x7da2,0x7daf,0x7ddc,0x7db8,0x7d9f,0x7db0,0x7dd8,
+    0x7ddd,0x7de4,0x7dde,0x7dfb,0x7df2,0x7de1,0x7e05,0x7e0a,0x7e23,0x7e21,
+    0x7e12,0x7e31,0x7e1f,0x7e09,0x7e0b,0x7e22,0x7e46,0x7e66,0x7e3b,0x7e35,
+    0x7e39,0x7e43,0x7e37,0x7e32,0x7e3a,0x7e67,0x7e5d,0x7e56,0x7e5e,0x7e59,
+    0x7e5a,0x7e79,0x7e6a,0x7e69,0x7e7c,0x7e7b,0x7e83,0x7dd5,0x7e7d,0x8fae,
+    0x7e7f,0x7e88,0x7e89,0x7e8c,0x7e92,0x7e90,0x7e93,0x7e94,0x7e96,0x7e8e,
+    0x7e9b,0x7e9c,0x7f38,0x7f3a
+  },
+  {				/* ku 46 */
+    0x7f45,0x7f4c,0x7f4d,0x7f4e,0x7f50,0x7f51,0x7f55,0x7f54,0x7f58,0x7f5f,
+    0x7f60,0x7f68,0x7f69,0x7f67,0x7f78,0x7f82,0x7f86,0x7f83,0x7f88,0x7f87,
+    0x7f8c,0x7f94,0x7f9e,0x7f9d,0x7f9a,0x7fa3,0x7faf,0x7fb2,0x7fb9,0x7fae,
+    0x7fb6,0x7fb8,0x8b71,0x7fc5,0x7fc6,0x7fca,0x7fd5,0x7fd4,0x7fe1,0x7fe6,
+    0x7fe9,0x7ff3,0x7ff9,0x98dc,0x8006,0x8004,0x800b,0x8012,0x8018,0x8019,
+    0x801c,0x8021,0x8028,0x803f,0x803b,0x804a,0x8046,0x8052,0x8058,0x805a,
+    0x805f,0x8062,0x8068,0x8073,0x8072,0x8070,0x8076,0x8079,0x807d,0x807f,
+    0x8084,0x8086,0x8085,0x809b,0x8093,0x809a,0x80ad,0x5190,0x80ac,0x80db,
+    0x80e5,0x80d9,0x80dd,0x80c4,0x80da,0x80d6,0x8109,0x80ef,0x80f1,0x811b,
+    0x8129,0x8123,0x812f,0x814b
+  },
+  {				/* ku 47 */
+    0x968b,0x8146,0x813e,0x8153,0x8151,0x80fc,0x8171,0x816e,0x8165,0x8166,
+    0x8174,0x8183,0x8188,0x818a,0x8180,0x8182,0x81a0,0x8195,0x81a4,0x81a3,
+    0x815f,0x8193,0x81a9,0x81b0,0x81b5,0x81be,0x81b8,0x81bd,0x81c0,0x81c2,
+    0x81ba,0x81c9,0x81cd,0x81d1,0x81d9,0x81d8,0x81c8,0x81da,0x81df,0x81e0,
+    0x81e7,0x81fa,0x81fb,0x81fe,0x8201,0x8202,0x8205,0x8207,0x820a,0x820d,
+    0x8210,0x8216,0x8229,0x822b,0x8238,0x8233,0x8240,0x8259,0x8258,0x825d,
+    0x825a,0x825f,0x8264,0x8262,0x8268,0x826a,0x826b,0x822e,0x8271,0x8277,
+    0x8278,0x827e,0x828d,0x8292,0x82ab,0x829f,0x82bb,0x82ac,0x82e1,0x82e3,
+    0x82df,0x82d2,0x82f4,0x82f3,0x82fa,0x8393,0x8303,0x82fb,0x82f9,0x82de,
+    0x8306,0x82dc,0x8309,0x82d9
+  },
+  {				/* ku 48 */
+    0x8335,0x8334,0x8316,0x8332,0x8331,0x8340,0x8339,0x8350,0x8345,0x832f,
+    0x832b,0x8317,0x8318,0x8385,0x839a,0x83aa,0x839f,0x83a2,0x8396,0x8323,
+    0x838e,0x8387,0x838a,0x837c,0x83b5,0x8373,0x8375,0x83a0,0x8389,0x83a8,
+    0x83f4,0x8413,0x83eb,0x83ce,0x83fd,0x8403,0x83d8,0x840b,0x83c1,0x83f7,
+    0x8407,0x83e0,0x83f2,0x840d,0x8422,0x8420,0x83bd,0x8438,0x8506,0x83fb,
+    0x846d,0x842a,0x843c,0x855a,0x8484,0x8477,0x846b,0x84ad,0x846e,0x8482,
+    0x8469,0x8446,0x842c,0x846f,0x8479,0x8435,0x84ca,0x8462,0x84b9,0x84bf,
+    0x849f,0x84d9,0x84cd,0x84bb,0x84da,0x84d0,0x84c1,0x84c6,0x84d6,0x84a1,
+    0x8521,0x84ff,0x84f4,0x8517,0x8518,0x852c,0x851f,0x8515,0x8514,0x84fc,
+    0x8540,0x8563,0x8558,0x8548
+  },
+  {				/* ku 49 */
+    0x8541,0x8602,0x854b,0x8555,0x8580,0x85a4,0x8588,0x8591,0x858a,0x85a8,
+    0x856d,0x8594,0x859b,0x85ea,0x8587,0x859c,0x8577,0x857e,0x8590,0x85c9,
+    0x85ba,0x85cf,0x85b9,0x85d0,0x85d5,0x85dd,0x85e5,0x85dc,0x85f9,0x860a,
+    0x8613,0x860b,0x85fe,0x85fa,0x8606,0x8622,0x861a,0x8630,0x863f,0x864d,
+    0x4e55,0x8654,0x865f,0x8667,0x8671,0x8693,0x86a3,0x86a9,0x86aa,0x868b,
+    0x868c,0x86b6,0x86af,0x86c4,0x86c6,0x86b0,0x86c9,0x8823,0x86ab,0x86d4,
+    0x86de,0x86e9,0x86ec,0x86df,0x86db,0x86ef,0x8712,0x8706,0x8708,0x8700,
+    0x8703,0x86fb,0x8711,0x8709,0x870d,0x86f9,0x870a,0x8734,0x873f,0x8737,
+    0x873b,0x8725,0x8729,0x871a,0x8760,0x875f,0x8778,0x874c,0x874e,0x8774,
+    0x8757,0x8768,0x876e,0x8759
+  },
+  {				/* ku 4a */
+    0x8753,0x8763,0x876a,0x8805,0x87a2,0x879f,0x8782,0x87af,0x87cb,0x87bd,
+    0x87c0,0x87d0,0x96d6,0x87ab,0x87c4,0x87b3,0x87c7,0x87c6,0x87bb,0x87ef,
+    0x87f2,0x87e0,0x880f,0x880d,0x87fe,0x87f6,0x87f7,0x880e,0x87d2,0x8811,
+    0x8816,0x8815,0x8822,0x8821,0x8831,0x8836,0x8839,0x8827,0x883b,0x8844,
+    0x8842,0x8852,0x8859,0x885e,0x8862,0x886b,0x8881,0x887e,0x889e,0x8875,
+    0x887d,0x88b5,0x8872,0x8882,0x8897,0x8892,0x88ae,0x8899,0x88a2,0x888d,
+    0x88a4,0x88b0,0x88bf,0x88b1,0x88c3,0x88c4,0x88d4,0x88d8,0x88d9,0x88dd,
+    0x88f9,0x8902,0x88fc,0x88f4,0x88e8,0x88f2,0x8904,0x890c,0x890a,0x8913,
+    0x8943,0x891e,0x8925,0x892a,0x892b,0x8941,0x8944,0x893b,0x8936,0x8938,
+    0x894c,0x891d,0x8960,0x895e
+  },
+  {				/* ku 4b */
+    0x8966,0x8964,0x896d,0x896a,0x896f,0x8974,0x8977,0x897e,0x8983,0x8988,
+    0x898a,0x8993,0x8998,0x89a1,0x89a9,0x89a6,0x89ac,0x89af,0x89b2,0x89ba,
+    0x89bd,0x89bf,0x89c0,0x89da,0x89dc,0x89dd,0x89e7,0x89f4,0x89f8,0x8a03,
+    0x8a16,0x8a10,0x8a0c,0x8a1b,0x8a1d,0x8a25,0x8a36,0x8a41,0x8a5b,0x8a52,
+    0x8a46,0x8a48,0x8a7c,0x8a6d,0x8a6c,0x8a62,0x8a85,0x8a82,0x8a84,0x8aa8,
+    0x8aa1,0x8a91,0x8aa5,0x8aa6,0x8a9a,0x8aa3,0x8ac4,0x8acd,0x8ac2,0x8ada,
+    0x8aeb,0x8af3,0x8ae7,0x8ae4,0x8af1,0x8b14,0x8ae0,0x8ae2,0x8af7,0x8ade,
+    0x8adb,0x8b0c,0x8b07,0x8b1a,0x8ae1,0x8b16,0x8b10,0x8b17,0x8b20,0x8b33,
+    0x97ab,0x8b26,0x8b2b,0x8b3e,0x8b28,0x8b41,0x8b4c,0x8b4f,0x8b4e,0x8b49,
+    0x8b56,0x8b5b,0x8b5a,0x8b6b
+  },
+  {				/* ku 4c */
+    0x8b5f,0x8b6c,0x8b6f,0x8b74,0x8b7d,0x8b80,0x8b8c,0x8b8e,0x8b92,0x8b93,
+    0x8b96,0x8b99,0x8b9a,0x8c3a,0x8c41,0x8c3f,0x8c48,0x8c4c,0x8c4e,0x8c50,
+    0x8c55,0x8c62,0x8c6c,0x8c78,0x8c7a,0x8c82,0x8c89,0x8c85,0x8c8a,0x8c8d,
+    0x8c8e,0x8c94,0x8c7c,0x8c98,0x621d,0x8cad,0x8caa,0x8cbd,0x8cb2,0x8cb3,
+    0x8cae,0x8cb6,0x8cc8,0x8cc1,0x8ce4,0x8ce3,0x8cda,0x8cfd,0x8cfa,0x8cfb,
+    0x8d04,0x8d05,0x8d0a,0x8d07,0x8d0f,0x8d0d,0x8d10,0x9f4e,0x8d13,0x8ccd,
+    0x8d14,0x8d16,0x8d67,0x8d6d,0x8d71,0x8d73,0x8d81,0x8d99,0x8dc2,0x8dbe,
+    0x8dba,0x8dcf,0x8dda,0x8dd6,0x8dcc,0x8ddb,0x8dcb,0x8dea,0x8deb,0x8ddf,
+    0x8de3,0x8dfc,0x8e08,0x8e09,0x8dff,0x8e1d,0x8e1e,0x8e10,0x8e1f,0x8e42,
+    0x8e35,0x8e30,0x8e34,0x8e4a
+  },
+  {				/* ku 4d */
+    0x8e47,0x8e49,0x8e4c,0x8e50,0x8e48,0x8e59,0x8e64,0x8e60,0x8e2a,0x8e63,
+    0x8e55,0x8e76,0x8e72,0x8e7c,0x8e81,0x8e87,0x8e85,0x8e84,0x8e8b,0x8e8a,
+    0x8e93,0x8e91,0x8e94,0x8e99,0x8eaa,0x8ea1,0x8eac,0x8eb0,0x8ec6,0x8eb1,
+    0x8ebe,0x8ec5,0x8ec8,0x8ecb,0x8edb,0x8ee3,0x8efc,0x8efb,0x8eeb,0x8efe,
+    0x8f0a,0x8f05,0x8f15,0x8f12,0x8f19,0x8f13,0x8f1c,0x8f1f,0x8f1b,0x8f0c,
+    0x8f26,0x8f33,0x8f3b,0x8f39,0x8f45,0x8f42,0x8f3e,0x8f4c,0x8f49,0x8f46,
+    0x8f4e,0x8f57,0x8f5c,0x8f62,0x8f63,0x8f64,0x8f9c,0x8f9f,0x8fa3,0x8fad,
+    0x8faf,0x8fb7,0x8fda,0x8fe5,0x8fe2,0x8fea,0x8fef,0x9087,0x8ff4,0x9005,
+    0x8ff9,0x8ffa,0x9011,0x9015,0x9021,0x900d,0x901e,0x9016,0x900b,0x9027,
+    0x9036,0x9035,0x9039,0x8ff8
+  },
+  {				/* ku 4e */
+    0x904f,0x9050,0x9051,0x9052,0x900e,0x9049,0x903e,0x9056,0x9058,0x905e,
+    0x9068,0x906f,0x9076,0x96a8,0x9072,0x9082,0x907d,0x9081,0x9080,0x908a,
+    0x9089,0x908f,0x90a8,0x90af,0x90b1,0x90b5,0x90e2,0x90e4,0x6248,0x90db,
+    0x9102,0x9112,0x9119,0x9132,0x9130,0x914a,0x9156,0x9158,0x9163,0x9165,
+    0x9169,0x9173,0x9172,0x918b,0x9189,0x9182,0x91a2,0x91ab,0x91af,0x91aa,
+    0x91b5,0x91b4,0x91ba,0x91c0,0x91c1,0x91c9,0x91cb,0x91d0,0x91d6,0x91df,
+    0x91e1,0x91db,0x91fc,0x91f5,0x91f6,0x921e,0x91ff,0x9214,0x922c,0x9215,
+    0x9211,0x925e,0x9257,0x9245,0x9249,0x9264,0x9248,0x9295,0x923f,0x924b,
+    0x9250,0x929c,0x9296,0x9293,0x929b,0x925a,0x92cf,0x92b9,0x92b7,0x92e9,
+    0x930f,0x92fa,0x9344,0x932e
+  },
+  {				/* ku 4f */
+    0x9319,0x9322,0x931a,0x9323,0x933a,0x9335,0x933b,0x935c,0x9360,0x937c,
+    0x936e,0x9356,0x93b0,0x93ac,0x93ad,0x9394,0x93b9,0x93d6,0x93d7,0x93e8,
+    0x93e5,0x93d8,0x93c3,0x93dd,0x93d0,0x93c8,0x93e4,0x941a,0x9414,0x9413,
+    0x9403,0x9407,0x9410,0x9436,0x942b,0x9435,0x9421,0x943a,0x9441,0x9452,
+    0x9444,0x945b,0x9460,0x9462,0x945e,0x946a,0x9229,0x9470,0x9475,0x9477,
+    0x947d,0x945a,0x947c,0x947e,0x9481,0x947f,0x9582,0x9587,0x958a,0x9594,
+    0x9596,0x9598,0x9599,0x95a0,0x95a8,0x95a7,0x95ad,0x95bc,0x95bb,0x95b9,
+    0x95be,0x95ca,0x6ff6,0x95c3,0x95cd,0x95cc,0x95d5,0x95d4,0x95d6,0x95dc,
+    0x95e1,0x95e5,0x95e2,0x9621,0x9628,0x962e,0x962f,0x9642,0x964c,0x964f,
+    0x964b,0x9677,0x965c,0x965e
+  },
+  {				/* ku 50 */
+    0x965d,0x965f,0x9666,0x9672,0x966c,0x968d,0x9698,0x9695,0x9697,0x96aa,
+    0x96a7,0x96b1,0x96b2,0x96b0,0x96b4,0x96b6,0x96b8,0x96b9,0x96ce,0x96cb,
+    0x96c9,0x96cd,0x894d,0x96dc,0x970d,0x96d5,0x96f9,0x9704,0x9706,0x9708,
+    0x9713,0x970e,0x9711,0x970f,0x9716,0x9719,0x9724,0x972a,0x9730,0x9739,
+    0x973d,0x973e,0x9744,0x9746,0x9748,0x9742,0x9749,0x975c,0x9760,0x9764,
+    0x9766,0x9768,0x52d2,0x976b,0x9771,0x9779,0x9785,0x977c,0x9781,0x977a,
+    0x9786,0x978b,0x978f,0x9790,0x979c,0x97a8,0x97a6,0x97a3,0x97b3,0x97b4,
+    0x97c3,0x97c6,0x97c8,0x97cb,0x97dc,0x97ed,0x9f4f,0x97f2,0x7adf,0x97f6,
+    0x97f5,0x980f,0x980c,0x9838,0x9824,0x9821,0x9837,0x983d,0x9846,0x984f,
+    0x984b,0x986b,0x986f,0x9870
+  },
+  {				/* ku 51 */
+    0x9871,0x9874,0x9873,0x98aa,0x98af,0x98b1,0x98b6,0x98c4,0x98c3,0x98c6,
+    0x98e9,0x98eb,0x9903,0x9909,0x9912,0x9914,0x9918,0x9921,0x991d,0x991e,
+    0x9924,0x9920,0x992c,0x992e,0x993d,0x993e,0x9942,0x9949,0x9945,0x9950,
+    0x994b,0x9951,0x9952,0x994c,0x9955,0x9997,0x9998,0x99a5,0x99ad,0x99ae,
+    0x99bc,0x99df,0x99db,0x99dd,0x99d8,0x99d1,0x99ed,0x99ee,0x99f1,0x99f2,
+    0x99fb,0x99f8,0x9a01,0x9a0f,0x9a05,0x99e2,0x9a19,0x9a2b,0x9a37,0x9a45,
+    0x9a42,0x9a40,0x9a43,0x9a3e,0x9a55,0x9a4d,0x9a5b,0x9a57,0x9a5f,0x9a62,
+    0x9a65,0x9a64,0x9a69,0x9a6b,0x9a6a,0x9aad,0x9ab0,0x9abc,0x9ac0,0x9acf,
+    0x9ad1,0x9ad3,0x9ad4,0x9ade,0x9adf,0x9ae2,0x9ae3,0x9ae6,0x9aef,0x9aeb,
+    0x9aee,0x9af4,0x9af1,0x9af7
+  },
+  {				/* ku 52 */
+    0x9afb,0x9b06,0x9b18,0x9b1a,0x9b1f,0x9b22,0x9b23,0x9b25,0x9b27,0x9b28,
+    0x9b29,0x9b2a,0x9b2e,0x9b2f,0x9b32,0x9b44,0x9b43,0x9b4f,0x9b4d,0x9b4e,
+    0x9b51,0x9b58,0x9b74,0x9b93,0x9b83,0x9b91,0x9b96,0x9b97,0x9b9f,0x9ba0,
+    0x9ba8,0x9bb4,0x9bc0,0x9bca,0x9bb9,0x9bc6,0x9bcf,0x9bd1,0x9bd2,0x9be3,
+    0x9be2,0x9be4,0x9bd4,0x9be1,0x9c3a,0x9bf2,0x9bf1,0x9bf0,0x9c15,0x9c14,
+    0x9c09,0x9c13,0x9c0c,0x9c06,0x9c08,0x9c12,0x9c0a,0x9c04,0x9c2e,0x9c1b,
+    0x9c25,0x9c24,0x9c21,0x9c30,0x9c47,0x9c32,0x9c46,0x9c3e,0x9c5a,0x9c60,
+    0x9c67,0x9c76,0x9c78,0x9ce7,0x9cec,0x9cf0,0x9d09,0x9d08,0x9ceb,0x9d03,
+    0x9d06,0x9d2a,0x9d26,0x9daf,0x9d23,0x9d1f,0x9d44,0x9d15,0x9d12,0x9d41,
+    0x9d3f,0x9d3e,0x9d46,0x9d48
+  },
+  {				/* ku 53 */
+    0x9d5d,0x9d5e,0x9d64,0x9d51,0x9d50,0x9d59,0x9d72,0x9d89,0x9d87,0x9dab,
+    0x9d6f,0x9d7a,0x9d9a,0x9da4,0x9da9,0x9db2,0x9dc4,0x9dc1,0x9dbb,0x9db8,
+    0x9dba,0x9dc6,0x9dcf,0x9dc2,0x9dd9,0x9dd3,0x9df8,0x9de6,0x9ded,0x9def,
+    0x9dfd,0x9e1a,0x9e1b,0x9e1e,0x9e75,0x9e79,0x9e7d,0x9e81,0x9e88,0x9e8b,
+    0x9e8c,0x9e92,0x9e95,0x9e91,0x9e9d,0x9ea5,0x9ea9,0x9eb8,0x9eaa,0x9ead,
+    0x9761,0x9ecc,0x9ece,0x9ecf,0x9ed0,0x9ed4,0x9edc,0x9ede,0x9edd,0x9ee0,
+    0x9ee5,0x9ee8,0x9eef,0x9ef4,0x9ef6,0x9ef7,0x9ef9,0x9efb,0x9efc,0x9efd,
+    0x9f07,0x9f08,0x76b7,0x9f15,0x9f21,0x9f2c,0x9f3e,0x9f4a,0x9f52,0x9f54,
+    0x9f63,0x9f5f,0x9f60,0x9f61,0x9f66,0x9f67,0x9f6c,0x9f6a,0x9f77,0x9f72,
+    0x9f76,0x9f95,0x9f9c,0x9fa0
+  },
+  {				/* ku 54 */
+    0x582f,0x69c7,0x9059,0x7464,0x51dc,0x7199,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  }
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/charset/jis_0212.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,962 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	JIS X0212 conversion table
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	4 August 1997
+ * Last Edited:	30 August 2006
+ */
+
+/* JIS X0212 is the supplemental industrial standard of Japan. */
+
+#define BASE_JIS0212_KU 0x22
+#define BASE_JIS0212_TEN 0x21
+#define MAX_JIS0212_KU 76
+#define MAX_JIS0212_TEN 94
+
+
+#define JIS0212TOUNICODE(c,c1,ku,ten)					\
+  ((((ku = (c & 0x7f) - BASE_JIS0212_KU) < MAX_JIS0212_KU) &&		\
+    ((ten = (c1 & 0x7f) - BASE_JIS0212_TEN) < MAX_JIS0212_TEN)) ?	\
+   jis0212tab[ku][ten] : UBOGON)
+
+
+static const unsigned short jis0212tab[MAX_JIS0212_KU][MAX_JIS0212_TEN] = {
+  {				/* ku 02 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x02d8,0x02c7,0x00b8,0x02d9,0x02dd,0x00af,
+    0x02db,0x02da,0x007e,0x0384,0x0385,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x00a1,0x00a6,0x00bf,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x00ba,0x00aa,0x00a9,0x00ae,0x2122,0x00a4,
+    0x2116,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 03 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 04 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 05 */
+    /* Note: ku/ten codepoints 05/87 - 05/90 are proposed for addition to
+     * JIS X 0212; I don't know if they've been formally accepted yet.
+     * They represent katakana VA, VI, VE, and VO, and are in the BMP but
+     * not in Unicode's JIS conversion tables.  They're useful enough that
+     * I decided to put them here.
+     */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x30f7,0x30f8,0x30f9,0x30fa,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 06 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x0386,0x0388,0x0389,0x038a,0x03aa,UBOGON,
+    0x038c,UBOGON,0x038e,0x03ab,UBOGON,0x038f,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x03ac,0x03ad,0x03ae,0x03af,0x03ca,0x0390,0x03cc,0x03c2,0x03cd,0x03cb,
+    0x03b0,0x03ce,UBOGON,UBOGON
+  },
+  {				/* ku 07 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,0x0402,0x0403,0x0404,0x0405,0x0406,0x0407,0x0408,
+    0x0409,0x040a,0x040b,0x040c,0x040e,0x040f,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x0452,0x0453,0x0454,0x0455,0x0456,0x0457,0x0458,0x0459,0x045a,
+    0x045b,0x045c,0x045e,0x045f
+  },
+  {				/* ku 08 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 09 */
+    0x00c6,0x0110,UBOGON,0x0126,UBOGON,0x0132,UBOGON,0x0141,0x013f,UBOGON,
+    0x014a,0x00d8,0x0152,UBOGON,0x0166,0x00de,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0x00e6,0x0111,0x00f0,0x0127,0x0131,0x0133,0x0138,0x0142,
+    0x0140,0x0149,0x014b,0x00f8,0x0153,0x00df,0x0167,0x00fe,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0a */
+    0x00c1,0x00c0,0x00c4,0x00c2,0x0102,0x01cd,0x0100,0x0104,0x00c5,0x00c3,
+    0x0106,0x0108,0x010c,0x00c7,0x010a,0x010e,0x00c9,0x00c8,0x00cb,0x00ca,
+    0x011a,0x0116,0x0112,0x0118,UBOGON,0x011c,0x011e,0x0122,0x0120,0x0124,
+    0x00cd,0x00cc,0x00cf,0x00ce,0x01cf,0x0130,0x012a,0x012e,0x0128,0x0134,
+    0x0136,0x0139,0x013d,0x013b,0x0143,0x0147,0x0145,0x00d1,0x00d3,0x00d2,
+    0x00d6,0x00d4,0x01d1,0x0150,0x014c,0x00d5,0x0154,0x0158,0x0156,0x015a,
+    0x015c,0x0160,0x015e,0x0164,0x0162,0x00da,0x00d9,0x00dc,0x00db,0x016c,
+    0x01d3,0x0170,0x016a,0x0172,0x016e,0x0168,0x01d7,0x01db,0x01d9,0x01d5,
+    0x0174,0x00dd,0x0178,0x0176,0x0179,0x017d,0x017b,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0b */
+    0x00e1,0x00e0,0x00e4,0x00e2,0x0103,0x01ce,0x0101,0x0105,0x00e5,0x00e3,
+    0x0107,0x0109,0x010d,0x00e7,0x010b,0x010f,0x00e9,0x00e8,0x00eb,0x00ea,
+    0x011b,0x0117,0x0113,0x0119,0x01f5,0x011d,0x011f,UBOGON,0x0121,0x0125,
+    0x00ed,0x00ec,0x00ef,0x00ee,0x01d0,UBOGON,0x012b,0x012f,0x0129,0x0135,
+    0x0137,0x013a,0x013e,0x013c,0x0144,0x0148,0x0146,0x00f1,0x00f3,0x00f2,
+    0x00f6,0x00f4,0x01d2,0x0151,0x014d,0x00f5,0x0155,0x0159,0x0157,0x015b,
+    0x015d,0x0161,0x015f,0x0165,0x0163,0x00fa,0x00f9,0x00fc,0x00fb,0x016d,
+    0x01d4,0x0171,0x016b,0x0173,0x016f,0x0169,0x01d8,0x01dc,0x01da,0x01d6,
+    0x0175,0x00fd,0x00ff,0x0177,0x017a,0x017e,0x017c,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0d */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0e */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 0f */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 10 */
+    0x4e02,0x4e04,0x4e05,0x4e0c,0x4e12,0x4e1f,0x4e23,0x4e24,0x4e28,0x4e2b,
+    0x4e2e,0x4e2f,0x4e30,0x4e35,0x4e40,0x4e41,0x4e44,0x4e47,0x4e51,0x4e5a,
+    0x4e5c,0x4e63,0x4e68,0x4e69,0x4e74,0x4e75,0x4e79,0x4e7f,0x4e8d,0x4e96,
+    0x4e97,0x4e9d,0x4eaf,0x4eb9,0x4ec3,0x4ed0,0x4eda,0x4edb,0x4ee0,0x4ee1,
+    0x4ee2,0x4ee8,0x4eef,0x4ef1,0x4ef3,0x4ef5,0x4efd,0x4efe,0x4eff,0x4f00,
+    0x4f02,0x4f03,0x4f08,0x4f0b,0x4f0c,0x4f12,0x4f15,0x4f16,0x4f17,0x4f19,
+    0x4f2e,0x4f31,0x4f60,0x4f33,0x4f35,0x4f37,0x4f39,0x4f3b,0x4f3e,0x4f40,
+    0x4f42,0x4f48,0x4f49,0x4f4b,0x4f4c,0x4f52,0x4f54,0x4f56,0x4f58,0x4f5f,
+    0x4f63,0x4f6a,0x4f6c,0x4f6e,0x4f71,0x4f77,0x4f78,0x4f79,0x4f7a,0x4f7d,
+    0x4f7e,0x4f81,0x4f82,0x4f84
+  },
+  {				/* ku 11 */
+    0x4f85,0x4f89,0x4f8a,0x4f8c,0x4f8e,0x4f90,0x4f92,0x4f93,0x4f94,0x4f97,
+    0x4f99,0x4f9a,0x4f9e,0x4f9f,0x4fb2,0x4fb7,0x4fb9,0x4fbb,0x4fbc,0x4fbd,
+    0x4fbe,0x4fc0,0x4fc1,0x4fc5,0x4fc6,0x4fc8,0x4fc9,0x4fcb,0x4fcc,0x4fcd,
+    0x4fcf,0x4fd2,0x4fdc,0x4fe0,0x4fe2,0x4ff0,0x4ff2,0x4ffc,0x4ffd,0x4fff,
+    0x5000,0x5001,0x5004,0x5007,0x500a,0x500c,0x500e,0x5010,0x5013,0x5017,
+    0x5018,0x501b,0x501c,0x501d,0x501e,0x5022,0x5027,0x502e,0x5030,0x5032,
+    0x5033,0x5035,0x5040,0x5041,0x5042,0x5045,0x5046,0x504a,0x504c,0x504e,
+    0x5051,0x5052,0x5053,0x5057,0x5059,0x505f,0x5060,0x5062,0x5063,0x5066,
+    0x5067,0x506a,0x506d,0x5070,0x5071,0x503b,0x5081,0x5083,0x5084,0x5086,
+    0x508a,0x508e,0x508f,0x5090
+  },
+  {				/* ku 12 */
+    0x5092,0x5093,0x5094,0x5096,0x509b,0x509c,0x509e,0x509f,0x50a0,0x50a1,
+    0x50a2,0x50aa,0x50af,0x50b0,0x50b9,0x50ba,0x50bd,0x50c0,0x50c3,0x50c4,
+    0x50c7,0x50cc,0x50ce,0x50d0,0x50d3,0x50d4,0x50d8,0x50dc,0x50dd,0x50df,
+    0x50e2,0x50e4,0x50e6,0x50e8,0x50e9,0x50ef,0x50f1,0x50f6,0x50fa,0x50fe,
+    0x5103,0x5106,0x5107,0x5108,0x510b,0x510c,0x510d,0x510e,0x50f2,0x5110,
+    0x5117,0x5119,0x511b,0x511c,0x511d,0x511e,0x5123,0x5127,0x5128,0x512c,
+    0x512d,0x512f,0x5131,0x5133,0x5134,0x5135,0x5138,0x5139,0x5142,0x514a,
+    0x514f,0x5153,0x5155,0x5157,0x5158,0x515f,0x5164,0x5166,0x517e,0x5183,
+    0x5184,0x518b,0x518e,0x5198,0x519d,0x51a1,0x51a3,0x51ad,0x51b8,0x51ba,
+    0x51bc,0x51be,0x51bf,0x51c2
+  },
+  {				/* ku 13 */
+    0x51c8,0x51cf,0x51d1,0x51d2,0x51d3,0x51d5,0x51d8,0x51de,0x51e2,0x51e5,
+    0x51ee,0x51f2,0x51f3,0x51f4,0x51f7,0x5201,0x5202,0x5205,0x5212,0x5213,
+    0x5215,0x5216,0x5218,0x5222,0x5228,0x5231,0x5232,0x5235,0x523c,0x5245,
+    0x5249,0x5255,0x5257,0x5258,0x525a,0x525c,0x525f,0x5260,0x5261,0x5266,
+    0x526e,0x5277,0x5278,0x5279,0x5280,0x5282,0x5285,0x528a,0x528c,0x5293,
+    0x5295,0x5296,0x5297,0x5298,0x529a,0x529c,0x52a4,0x52a5,0x52a6,0x52a7,
+    0x52af,0x52b0,0x52b6,0x52b7,0x52b8,0x52ba,0x52bb,0x52bd,0x52c0,0x52c4,
+    0x52c6,0x52c8,0x52cc,0x52cf,0x52d1,0x52d4,0x52d6,0x52db,0x52dc,0x52e1,
+    0x52e5,0x52e8,0x52e9,0x52ea,0x52ec,0x52f0,0x52f1,0x52f4,0x52f6,0x52f7,
+    0x5300,0x5303,0x530a,0x530b
+  },
+  {				/* ku 14 */
+    0x530c,0x5311,0x5313,0x5318,0x531b,0x531c,0x531e,0x531f,0x5325,0x5327,
+    0x5328,0x5329,0x532b,0x532c,0x532d,0x5330,0x5332,0x5335,0x533c,0x533d,
+    0x533e,0x5342,0x534c,0x534b,0x5359,0x535b,0x5361,0x5363,0x5365,0x536c,
+    0x536d,0x5372,0x5379,0x537e,0x5383,0x5387,0x5388,0x538e,0x5393,0x5394,
+    0x5399,0x539d,0x53a1,0x53a4,0x53aa,0x53ab,0x53af,0x53b2,0x53b4,0x53b5,
+    0x53b7,0x53b8,0x53ba,0x53bd,0x53c0,0x53c5,0x53cf,0x53d2,0x53d3,0x53d5,
+    0x53da,0x53dd,0x53de,0x53e0,0x53e6,0x53e7,0x53f5,0x5402,0x5413,0x541a,
+    0x5421,0x5427,0x5428,0x542a,0x542f,0x5431,0x5434,0x5435,0x5443,0x5444,
+    0x5447,0x544d,0x544f,0x545e,0x5462,0x5464,0x5466,0x5467,0x5469,0x546b,
+    0x546d,0x546e,0x5474,0x547f
+  },
+  {				/* ku 15 */
+    0x5481,0x5483,0x5485,0x5488,0x5489,0x548d,0x5491,0x5495,0x5496,0x549c,
+    0x549f,0x54a1,0x54a6,0x54a7,0x54a9,0x54aa,0x54ad,0x54ae,0x54b1,0x54b7,
+    0x54b9,0x54ba,0x54bb,0x54bf,0x54c6,0x54ca,0x54cd,0x54ce,0x54e0,0x54ea,
+    0x54ec,0x54ef,0x54f6,0x54fc,0x54fe,0x54ff,0x5500,0x5501,0x5505,0x5508,
+    0x5509,0x550c,0x550d,0x550e,0x5515,0x552a,0x552b,0x5532,0x5535,0x5536,
+    0x553b,0x553c,0x553d,0x5541,0x5547,0x5549,0x554a,0x554d,0x5550,0x5551,
+    0x5558,0x555a,0x555b,0x555e,0x5560,0x5561,0x5564,0x5566,0x557f,0x5581,
+    0x5582,0x5586,0x5588,0x558e,0x558f,0x5591,0x5592,0x5593,0x5594,0x5597,
+    0x55a3,0x55a4,0x55ad,0x55b2,0x55bf,0x55c1,0x55c3,0x55c6,0x55c9,0x55cb,
+    0x55cc,0x55ce,0x55d1,0x55d2
+  },
+  {				/* ku 16 */
+    0x55d3,0x55d7,0x55d8,0x55db,0x55de,0x55e2,0x55e9,0x55f6,0x55ff,0x5605,
+    0x5608,0x560a,0x560d,0x560e,0x560f,0x5610,0x5611,0x5612,0x5619,0x562c,
+    0x5630,0x5633,0x5635,0x5637,0x5639,0x563b,0x563c,0x563d,0x563f,0x5640,
+    0x5641,0x5643,0x5644,0x5646,0x5649,0x564b,0x564d,0x564f,0x5654,0x565e,
+    0x5660,0x5661,0x5662,0x5663,0x5666,0x5669,0x566d,0x566f,0x5671,0x5672,
+    0x5675,0x5684,0x5685,0x5688,0x568b,0x568c,0x5695,0x5699,0x569a,0x569d,
+    0x569e,0x569f,0x56a6,0x56a7,0x56a8,0x56a9,0x56ab,0x56ac,0x56ad,0x56b1,
+    0x56b3,0x56b7,0x56be,0x56c5,0x56c9,0x56ca,0x56cb,0x56cf,0x56d0,0x56cc,
+    0x56cd,0x56d9,0x56dc,0x56dd,0x56df,0x56e1,0x56e4,0x56e5,0x56e6,0x56e7,
+    0x56e8,0x56f1,0x56eb,0x56ed
+  },
+  {				/* ku 17 */
+    0x56f6,0x56f7,0x5701,0x5702,0x5707,0x570a,0x570c,0x5711,0x5715,0x571a,
+    0x571b,0x571d,0x5720,0x5722,0x5723,0x5724,0x5725,0x5729,0x572a,0x572c,
+    0x572e,0x572f,0x5733,0x5734,0x573d,0x573e,0x573f,0x5745,0x5746,0x574c,
+    0x574d,0x5752,0x5762,0x5765,0x5767,0x5768,0x576b,0x576d,0x576e,0x576f,
+    0x5770,0x5771,0x5773,0x5774,0x5775,0x5777,0x5779,0x577a,0x577b,0x577c,
+    0x577e,0x5781,0x5783,0x578c,0x5794,0x5797,0x5799,0x579a,0x579c,0x579d,
+    0x579e,0x579f,0x57a1,0x5795,0x57a7,0x57a8,0x57a9,0x57ac,0x57b8,0x57bd,
+    0x57c7,0x57c8,0x57cc,0x57cf,0x57d5,0x57dd,0x57de,0x57e4,0x57e6,0x57e7,
+    0x57e9,0x57ed,0x57f0,0x57f5,0x57f6,0x57f8,0x57fd,0x57fe,0x57ff,0x5803,
+    0x5804,0x5808,0x5809,0x57e1
+  },
+  {				/* ku 18 */
+    0x580c,0x580d,0x581b,0x581e,0x581f,0x5820,0x5826,0x5827,0x582d,0x5832,
+    0x5839,0x583f,0x5849,0x584c,0x584d,0x584f,0x5850,0x5855,0x585f,0x5861,
+    0x5864,0x5867,0x5868,0x5878,0x587c,0x587f,0x5880,0x5881,0x5887,0x5888,
+    0x5889,0x588a,0x588c,0x588d,0x588f,0x5890,0x5894,0x5896,0x589d,0x58a0,
+    0x58a1,0x58a2,0x58a6,0x58a9,0x58b1,0x58b2,0x58c4,0x58bc,0x58c2,0x58c8,
+    0x58cd,0x58ce,0x58d0,0x58d2,0x58d4,0x58d6,0x58da,0x58dd,0x58e1,0x58e2,
+    0x58e9,0x58f3,0x5905,0x5906,0x590b,0x590c,0x5912,0x5913,0x5914,0x8641,
+    0x591d,0x5921,0x5923,0x5924,0x5928,0x592f,0x5930,0x5933,0x5935,0x5936,
+    0x593f,0x5943,0x5946,0x5952,0x5953,0x5959,0x595b,0x595d,0x595e,0x595f,
+    0x5961,0x5963,0x596b,0x596d
+  },
+  {				/* ku 19 */
+    0x596f,0x5972,0x5975,0x5976,0x5979,0x597b,0x597c,0x598b,0x598c,0x598e,
+    0x5992,0x5995,0x5997,0x599f,0x59a4,0x59a7,0x59ad,0x59ae,0x59af,0x59b0,
+    0x59b3,0x59b7,0x59ba,0x59bc,0x59c1,0x59c3,0x59c4,0x59c8,0x59ca,0x59cd,
+    0x59d2,0x59dd,0x59de,0x59df,0x59e3,0x59e4,0x59e7,0x59ee,0x59ef,0x59f1,
+    0x59f2,0x59f4,0x59f7,0x5a00,0x5a04,0x5a0c,0x5a0d,0x5a0e,0x5a12,0x5a13,
+    0x5a1e,0x5a23,0x5a24,0x5a27,0x5a28,0x5a2a,0x5a2d,0x5a30,0x5a44,0x5a45,
+    0x5a47,0x5a48,0x5a4c,0x5a50,0x5a55,0x5a5e,0x5a63,0x5a65,0x5a67,0x5a6d,
+    0x5a77,0x5a7a,0x5a7b,0x5a7e,0x5a8b,0x5a90,0x5a93,0x5a96,0x5a99,0x5a9c,
+    0x5a9e,0x5a9f,0x5aa0,0x5aa2,0x5aa7,0x5aac,0x5ab1,0x5ab2,0x5ab3,0x5ab5,
+    0x5ab8,0x5aba,0x5abb,0x5abf
+  },
+  {				/* ku 1a */
+    0x5ac4,0x5ac6,0x5ac8,0x5acf,0x5ada,0x5adc,0x5ae0,0x5ae5,0x5aea,0x5aee,
+    0x5af5,0x5af6,0x5afd,0x5b00,0x5b01,0x5b08,0x5b17,0x5b34,0x5b19,0x5b1b,
+    0x5b1d,0x5b21,0x5b25,0x5b2d,0x5b38,0x5b41,0x5b4b,0x5b4c,0x5b52,0x5b56,
+    0x5b5e,0x5b68,0x5b6e,0x5b6f,0x5b7c,0x5b7d,0x5b7e,0x5b7f,0x5b81,0x5b84,
+    0x5b86,0x5b8a,0x5b8e,0x5b90,0x5b91,0x5b93,0x5b94,0x5b96,0x5ba8,0x5ba9,
+    0x5bac,0x5bad,0x5baf,0x5bb1,0x5bb2,0x5bb7,0x5bba,0x5bbc,0x5bc0,0x5bc1,
+    0x5bcd,0x5bcf,0x5bd6,0x5bd7,0x5bd8,0x5bd9,0x5bda,0x5be0,0x5bef,0x5bf1,
+    0x5bf4,0x5bfd,0x5c0c,0x5c17,0x5c1e,0x5c1f,0x5c23,0x5c26,0x5c29,0x5c2b,
+    0x5c2c,0x5c2e,0x5c30,0x5c32,0x5c35,0x5c36,0x5c59,0x5c5a,0x5c5c,0x5c62,
+    0x5c63,0x5c67,0x5c68,0x5c69
+  },
+  {				/* ku 1b */
+    0x5c6d,0x5c70,0x5c74,0x5c75,0x5c7a,0x5c7b,0x5c7c,0x5c7d,0x5c87,0x5c88,
+    0x5c8a,0x5c8f,0x5c92,0x5c9d,0x5c9f,0x5ca0,0x5ca2,0x5ca3,0x5ca6,0x5caa,
+    0x5cb2,0x5cb4,0x5cb5,0x5cba,0x5cc9,0x5ccb,0x5cd2,0x5cdd,0x5cd7,0x5cee,
+    0x5cf1,0x5cf2,0x5cf4,0x5d01,0x5d06,0x5d0d,0x5d12,0x5d2b,0x5d23,0x5d24,
+    0x5d26,0x5d27,0x5d31,0x5d34,0x5d39,0x5d3d,0x5d3f,0x5d42,0x5d43,0x5d46,
+    0x5d48,0x5d55,0x5d51,0x5d59,0x5d4a,0x5d5f,0x5d60,0x5d61,0x5d62,0x5d64,
+    0x5d6a,0x5d6d,0x5d70,0x5d79,0x5d7a,0x5d7e,0x5d7f,0x5d81,0x5d83,0x5d88,
+    0x5d8a,0x5d92,0x5d93,0x5d94,0x5d95,0x5d99,0x5d9b,0x5d9f,0x5da0,0x5da7,
+    0x5dab,0x5db0,0x5db4,0x5db8,0x5db9,0x5dc3,0x5dc7,0x5dcb,0x5dd0,0x5dce,
+    0x5dd8,0x5dd9,0x5de0,0x5de4
+  },
+  {				/* ku 1c */
+    0x5de9,0x5df8,0x5df9,0x5e00,0x5e07,0x5e0d,0x5e12,0x5e14,0x5e15,0x5e18,
+    0x5e1f,0x5e20,0x5e2e,0x5e28,0x5e32,0x5e35,0x5e3e,0x5e4b,0x5e50,0x5e49,
+    0x5e51,0x5e56,0x5e58,0x5e5b,0x5e5c,0x5e5e,0x5e68,0x5e6a,0x5e6b,0x5e6c,
+    0x5e6d,0x5e6e,0x5e70,0x5e80,0x5e8b,0x5e8e,0x5ea2,0x5ea4,0x5ea5,0x5ea8,
+    0x5eaa,0x5eac,0x5eb1,0x5eb3,0x5ebd,0x5ebe,0x5ebf,0x5ec6,0x5ecc,0x5ecb,
+    0x5ece,0x5ed1,0x5ed2,0x5ed4,0x5ed5,0x5edc,0x5ede,0x5ee5,0x5eeb,0x5f02,
+    0x5f06,0x5f07,0x5f08,0x5f0e,0x5f19,0x5f1c,0x5f1d,0x5f21,0x5f22,0x5f23,
+    0x5f24,0x5f28,0x5f2b,0x5f2c,0x5f2e,0x5f30,0x5f34,0x5f36,0x5f3b,0x5f3d,
+    0x5f3f,0x5f40,0x5f44,0x5f45,0x5f47,0x5f4d,0x5f50,0x5f54,0x5f58,0x5f5b,
+    0x5f60,0x5f63,0x5f64,0x5f67
+  },
+  {				/* ku 1d */
+    0x5f6f,0x5f72,0x5f74,0x5f75,0x5f78,0x5f7a,0x5f7d,0x5f7e,0x5f89,0x5f8d,
+    0x5f8f,0x5f96,0x5f9c,0x5f9d,0x5fa2,0x5fa7,0x5fab,0x5fa4,0x5fac,0x5faf,
+    0x5fb0,0x5fb1,0x5fb8,0x5fc4,0x5fc7,0x5fc8,0x5fc9,0x5fcb,0x5fd0,0x5fd1,
+    0x5fd2,0x5fd3,0x5fd4,0x5fde,0x5fe1,0x5fe2,0x5fe8,0x5fe9,0x5fea,0x5fec,
+    0x5fed,0x5fee,0x5fef,0x5ff2,0x5ff3,0x5ff6,0x5ffa,0x5ffc,0x6007,0x600a,
+    0x600d,0x6013,0x6014,0x6017,0x6018,0x601a,0x601f,0x6024,0x602d,0x6033,
+    0x6035,0x6040,0x6047,0x6048,0x6049,0x604c,0x6051,0x6054,0x6056,0x6057,
+    0x605d,0x6061,0x6067,0x6071,0x607e,0x607f,0x6082,0x6086,0x6088,0x608a,
+    0x608e,0x6091,0x6093,0x6095,0x6098,0x609d,0x609e,0x60a2,0x60a4,0x60a5,
+    0x60a8,0x60b0,0x60b1,0x60b7
+  },
+  {				/* ku 1e */
+    0x60bb,0x60be,0x60c2,0x60c4,0x60c8,0x60c9,0x60ca,0x60cb,0x60ce,0x60cf,
+    0x60d4,0x60d5,0x60d9,0x60db,0x60dd,0x60de,0x60e2,0x60e5,0x60f2,0x60f5,
+    0x60f8,0x60fc,0x60fd,0x6102,0x6107,0x610a,0x610c,0x6110,0x6111,0x6112,
+    0x6113,0x6114,0x6116,0x6117,0x6119,0x611c,0x611e,0x6122,0x612a,0x612b,
+    0x6130,0x6131,0x6135,0x6136,0x6137,0x6139,0x6141,0x6145,0x6146,0x6149,
+    0x615e,0x6160,0x616c,0x6172,0x6178,0x617b,0x617c,0x617f,0x6180,0x6181,
+    0x6183,0x6184,0x618b,0x618d,0x6192,0x6193,0x6197,0x6198,0x619c,0x619d,
+    0x619f,0x61a0,0x61a5,0x61a8,0x61aa,0x61ad,0x61b8,0x61b9,0x61bc,0x61c0,
+    0x61c1,0x61c2,0x61ce,0x61cf,0x61d5,0x61dc,0x61dd,0x61de,0x61df,0x61e1,
+    0x61e2,0x61e7,0x61e9,0x61e5
+  },
+  {				/* ku 1f */
+    0x61ec,0x61ed,0x61ef,0x6201,0x6203,0x6204,0x6207,0x6213,0x6215,0x621c,
+    0x6220,0x6222,0x6223,0x6227,0x6229,0x622b,0x6239,0x623d,0x6242,0x6243,
+    0x6244,0x6246,0x624c,0x6250,0x6251,0x6252,0x6254,0x6256,0x625a,0x625c,
+    0x6264,0x626d,0x626f,0x6273,0x627a,0x627d,0x628d,0x628e,0x628f,0x6290,
+    0x62a6,0x62a8,0x62b3,0x62b6,0x62b7,0x62ba,0x62be,0x62bf,0x62c4,0x62ce,
+    0x62d5,0x62d6,0x62da,0x62ea,0x62f2,0x62f4,0x62fc,0x62fd,0x6303,0x6304,
+    0x630a,0x630b,0x630d,0x6310,0x6313,0x6316,0x6318,0x6329,0x632a,0x632d,
+    0x6335,0x6336,0x6339,0x633c,0x6341,0x6342,0x6343,0x6344,0x6346,0x634a,
+    0x634b,0x634e,0x6352,0x6353,0x6354,0x6358,0x635b,0x6365,0x6366,0x636c,
+    0x636d,0x6371,0x6374,0x6375
+  },
+  {				/* ku 20 */
+    0x6378,0x637c,0x637d,0x637f,0x6382,0x6384,0x6387,0x638a,0x6390,0x6394,
+    0x6395,0x6399,0x639a,0x639e,0x63a4,0x63a6,0x63ad,0x63ae,0x63af,0x63bd,
+    0x63c1,0x63c5,0x63c8,0x63ce,0x63d1,0x63d3,0x63d4,0x63d5,0x63dc,0x63e0,
+    0x63e5,0x63ea,0x63ec,0x63f2,0x63f3,0x63f5,0x63f8,0x63f9,0x6409,0x640a,
+    0x6410,0x6412,0x6414,0x6418,0x641e,0x6420,0x6422,0x6424,0x6425,0x6429,
+    0x642a,0x642f,0x6430,0x6435,0x643d,0x643f,0x644b,0x644f,0x6451,0x6452,
+    0x6453,0x6454,0x645a,0x645b,0x645c,0x645d,0x645f,0x6460,0x6461,0x6463,
+    0x646d,0x6473,0x6474,0x647b,0x647d,0x6485,0x6487,0x648f,0x6490,0x6491,
+    0x6498,0x6499,0x649b,0x649d,0x649f,0x64a1,0x64a3,0x64a6,0x64a8,0x64ac,
+    0x64b3,0x64bd,0x64be,0x64bf
+  },
+  {				/* ku 21 */
+    0x64c4,0x64c9,0x64ca,0x64cb,0x64cc,0x64ce,0x64d0,0x64d1,0x64d5,0x64d7,
+    0x64e4,0x64e5,0x64e9,0x64ea,0x64ed,0x64f0,0x64f5,0x64f7,0x64fb,0x64ff,
+    0x6501,0x6504,0x6508,0x6509,0x650a,0x650f,0x6513,0x6514,0x6516,0x6519,
+    0x651b,0x651e,0x651f,0x6522,0x6526,0x6529,0x652e,0x6531,0x653a,0x653c,
+    0x653d,0x6543,0x6547,0x6549,0x6550,0x6552,0x6554,0x655f,0x6560,0x6567,
+    0x656b,0x657a,0x657d,0x6581,0x6585,0x658a,0x6592,0x6595,0x6598,0x659d,
+    0x65a0,0x65a3,0x65a6,0x65ae,0x65b2,0x65b3,0x65b4,0x65bf,0x65c2,0x65c8,
+    0x65c9,0x65ce,0x65d0,0x65d4,0x65d6,0x65d8,0x65df,0x65f0,0x65f2,0x65f4,
+    0x65f5,0x65f9,0x65fe,0x65ff,0x6600,0x6604,0x6608,0x6609,0x660d,0x6611,
+    0x6612,0x6615,0x6616,0x661d
+  },
+  {				/* ku 22 */
+    0x661e,0x6621,0x6622,0x6623,0x6624,0x6626,0x6629,0x662a,0x662b,0x662c,
+    0x662e,0x6630,0x6631,0x6633,0x6639,0x6637,0x6640,0x6645,0x6646,0x664a,
+    0x664c,0x6651,0x664e,0x6657,0x6658,0x6659,0x665b,0x665c,0x6660,0x6661,
+    0x66fb,0x666a,0x666b,0x666c,0x667e,0x6673,0x6675,0x667f,0x6677,0x6678,
+    0x6679,0x667b,0x6680,0x667c,0x668b,0x668c,0x668d,0x6690,0x6692,0x6699,
+    0x669a,0x669b,0x669c,0x669f,0x66a0,0x66a4,0x66ad,0x66b1,0x66b2,0x66b5,
+    0x66bb,0x66bf,0x66c0,0x66c2,0x66c3,0x66c8,0x66cc,0x66ce,0x66cf,0x66d4,
+    0x66db,0x66df,0x66e8,0x66eb,0x66ec,0x66ee,0x66fa,0x6705,0x6707,0x670e,
+    0x6713,0x6719,0x671c,0x6720,0x6722,0x6733,0x673e,0x6745,0x6747,0x6748,
+    0x674c,0x6754,0x6755,0x675d
+  },
+  {				/* ku 23 */
+    0x6766,0x676c,0x676e,0x6774,0x6776,0x677b,0x6781,0x6784,0x678e,0x678f,
+    0x6791,0x6793,0x6796,0x6798,0x6799,0x679b,0x67b0,0x67b1,0x67b2,0x67b5,
+    0x67bb,0x67bc,0x67bd,0x67f9,0x67c0,0x67c2,0x67c3,0x67c5,0x67c8,0x67c9,
+    0x67d2,0x67d7,0x67d9,0x67dc,0x67e1,0x67e6,0x67f0,0x67f2,0x67f6,0x67f7,
+    0x6852,0x6814,0x6819,0x681d,0x681f,0x6828,0x6827,0x682c,0x682d,0x682f,
+    0x6830,0x6831,0x6833,0x683b,0x683f,0x6844,0x6845,0x684a,0x684c,0x6855,
+    0x6857,0x6858,0x685b,0x686b,0x686e,0x686f,0x6870,0x6871,0x6872,0x6875,
+    0x6879,0x687a,0x687b,0x687c,0x6882,0x6884,0x6886,0x6888,0x6896,0x6898,
+    0x689a,0x689c,0x68a1,0x68a3,0x68a5,0x68a9,0x68aa,0x68ae,0x68b2,0x68bb,
+    0x68c5,0x68c8,0x68cc,0x68cf
+  },
+  {				/* ku 24 */
+    0x68d0,0x68d1,0x68d3,0x68d6,0x68d9,0x68dc,0x68dd,0x68e5,0x68e8,0x68ea,
+    0x68eb,0x68ec,0x68ed,0x68f0,0x68f1,0x68f5,0x68f6,0x68fb,0x68fc,0x68fd,
+    0x6906,0x6909,0x690a,0x6910,0x6911,0x6913,0x6916,0x6917,0x6931,0x6933,
+    0x6935,0x6938,0x693b,0x6942,0x6945,0x6949,0x694e,0x6957,0x695b,0x6963,
+    0x6964,0x6965,0x6966,0x6968,0x6969,0x696c,0x6970,0x6971,0x6972,0x697a,
+    0x697b,0x697f,0x6980,0x698d,0x6992,0x6996,0x6998,0x69a1,0x69a5,0x69a6,
+    0x69a8,0x69ab,0x69ad,0x69af,0x69b7,0x69b8,0x69ba,0x69bc,0x69c5,0x69c8,
+    0x69d1,0x69d6,0x69d7,0x69e2,0x69e5,0x69ee,0x69ef,0x69f1,0x69f3,0x69f5,
+    0x69fe,0x6a00,0x6a01,0x6a03,0x6a0f,0x6a11,0x6a15,0x6a1a,0x6a1d,0x6a20,
+    0x6a24,0x6a28,0x6a30,0x6a32
+  },
+  {				/* ku 25 */
+    0x6a34,0x6a37,0x6a3b,0x6a3e,0x6a3f,0x6a45,0x6a46,0x6a49,0x6a4a,0x6a4e,
+    0x6a50,0x6a51,0x6a52,0x6a55,0x6a56,0x6a5b,0x6a64,0x6a67,0x6a6a,0x6a71,
+    0x6a73,0x6a7e,0x6a81,0x6a83,0x6a86,0x6a87,0x6a89,0x6a8b,0x6a91,0x6a9b,
+    0x6a9d,0x6a9e,0x6a9f,0x6aa5,0x6aab,0x6aaf,0x6ab0,0x6ab1,0x6ab4,0x6abd,
+    0x6abe,0x6abf,0x6ac6,0x6ac9,0x6ac8,0x6acc,0x6ad0,0x6ad4,0x6ad5,0x6ad6,
+    0x6adc,0x6add,0x6ae4,0x6ae7,0x6aec,0x6af0,0x6af1,0x6af2,0x6afc,0x6afd,
+    0x6b02,0x6b03,0x6b06,0x6b07,0x6b09,0x6b0f,0x6b10,0x6b11,0x6b17,0x6b1b,
+    0x6b1e,0x6b24,0x6b28,0x6b2b,0x6b2c,0x6b2f,0x6b35,0x6b36,0x6b3b,0x6b3f,
+    0x6b46,0x6b4a,0x6b4d,0x6b52,0x6b56,0x6b58,0x6b5d,0x6b60,0x6b67,0x6b6b,
+    0x6b6e,0x6b70,0x6b75,0x6b7d
+  },
+  {				/* ku 26 */
+    0x6b7e,0x6b82,0x6b85,0x6b97,0x6b9b,0x6b9f,0x6ba0,0x6ba2,0x6ba3,0x6ba8,
+    0x6ba9,0x6bac,0x6bad,0x6bae,0x6bb0,0x6bb8,0x6bb9,0x6bbd,0x6bbe,0x6bc3,
+    0x6bc4,0x6bc9,0x6bcc,0x6bd6,0x6bda,0x6be1,0x6be3,0x6be6,0x6be7,0x6bee,
+    0x6bf1,0x6bf7,0x6bf9,0x6bff,0x6c02,0x6c04,0x6c05,0x6c09,0x6c0d,0x6c0e,
+    0x6c10,0x6c12,0x6c19,0x6c1f,0x6c26,0x6c27,0x6c28,0x6c2c,0x6c2e,0x6c33,
+    0x6c35,0x6c36,0x6c3a,0x6c3b,0x6c3f,0x6c4a,0x6c4b,0x6c4d,0x6c4f,0x6c52,
+    0x6c54,0x6c59,0x6c5b,0x6c5c,0x6c6b,0x6c6d,0x6c6f,0x6c74,0x6c76,0x6c78,
+    0x6c79,0x6c7b,0x6c85,0x6c86,0x6c87,0x6c89,0x6c94,0x6c95,0x6c97,0x6c98,
+    0x6c9c,0x6c9f,0x6cb0,0x6cb2,0x6cb4,0x6cc2,0x6cc6,0x6ccd,0x6ccf,0x6cd0,
+    0x6cd1,0x6cd2,0x6cd4,0x6cd6
+  },
+  {				/* ku 27 */
+    0x6cda,0x6cdc,0x6ce0,0x6ce7,0x6ce9,0x6ceb,0x6cec,0x6cee,0x6cf2,0x6cf4,
+    0x6d04,0x6d07,0x6d0a,0x6d0e,0x6d0f,0x6d11,0x6d13,0x6d1a,0x6d26,0x6d27,
+    0x6d28,0x6c67,0x6d2e,0x6d2f,0x6d31,0x6d39,0x6d3c,0x6d3f,0x6d57,0x6d5e,
+    0x6d5f,0x6d61,0x6d65,0x6d67,0x6d6f,0x6d70,0x6d7c,0x6d82,0x6d87,0x6d91,
+    0x6d92,0x6d94,0x6d96,0x6d97,0x6d98,0x6daa,0x6dac,0x6db4,0x6db7,0x6db9,
+    0x6dbd,0x6dbf,0x6dc4,0x6dc8,0x6dca,0x6dce,0x6dcf,0x6dd6,0x6ddb,0x6ddd,
+    0x6ddf,0x6de0,0x6de2,0x6de5,0x6de9,0x6def,0x6df0,0x6df4,0x6df6,0x6dfc,
+    0x6e00,0x6e04,0x6e1e,0x6e22,0x6e27,0x6e32,0x6e36,0x6e39,0x6e3b,0x6e3c,
+    0x6e44,0x6e45,0x6e48,0x6e49,0x6e4b,0x6e4f,0x6e51,0x6e52,0x6e53,0x6e54,
+    0x6e57,0x6e5c,0x6e5d,0x6e5e
+  },
+  {				/* ku 28 */
+    0x6e62,0x6e63,0x6e68,0x6e73,0x6e7b,0x6e7d,0x6e8d,0x6e93,0x6e99,0x6ea0,
+    0x6ea7,0x6ead,0x6eae,0x6eb1,0x6eb3,0x6ebb,0x6ebf,0x6ec0,0x6ec1,0x6ec3,
+    0x6ec7,0x6ec8,0x6eca,0x6ecd,0x6ece,0x6ecf,0x6eeb,0x6eed,0x6eee,0x6ef9,
+    0x6efb,0x6efd,0x6f04,0x6f08,0x6f0a,0x6f0c,0x6f0d,0x6f16,0x6f18,0x6f1a,
+    0x6f1b,0x6f26,0x6f29,0x6f2a,0x6f2f,0x6f30,0x6f33,0x6f36,0x6f3b,0x6f3c,
+    0x6f2d,0x6f4f,0x6f51,0x6f52,0x6f53,0x6f57,0x6f59,0x6f5a,0x6f5d,0x6f5e,
+    0x6f61,0x6f62,0x6f68,0x6f6c,0x6f7d,0x6f7e,0x6f83,0x6f87,0x6f88,0x6f8b,
+    0x6f8c,0x6f8d,0x6f90,0x6f92,0x6f93,0x6f94,0x6f96,0x6f9a,0x6f9f,0x6fa0,
+    0x6fa5,0x6fa6,0x6fa7,0x6fa8,0x6fae,0x6faf,0x6fb0,0x6fb5,0x6fb6,0x6fbc,
+    0x6fc5,0x6fc7,0x6fc8,0x6fca
+  },
+  {				/* ku 29 */
+    0x6fda,0x6fde,0x6fe8,0x6fe9,0x6ff0,0x6ff5,0x6ff9,0x6ffc,0x6ffd,0x7000,
+    0x7005,0x7006,0x7007,0x700d,0x7017,0x7020,0x7023,0x702f,0x7034,0x7037,
+    0x7039,0x703c,0x7043,0x7044,0x7048,0x7049,0x704a,0x704b,0x7054,0x7055,
+    0x705d,0x705e,0x704e,0x7064,0x7065,0x706c,0x706e,0x7075,0x7076,0x707e,
+    0x7081,0x7085,0x7086,0x7094,0x7095,0x7096,0x7097,0x7098,0x709b,0x70a4,
+    0x70ab,0x70b0,0x70b1,0x70b4,0x70b7,0x70ca,0x70d1,0x70d3,0x70d4,0x70d5,
+    0x70d6,0x70d8,0x70dc,0x70e4,0x70fa,0x7103,0x7104,0x7105,0x7106,0x7107,
+    0x710b,0x710c,0x710f,0x711e,0x7120,0x712b,0x712d,0x712f,0x7130,0x7131,
+    0x7138,0x7141,0x7145,0x7146,0x7147,0x714a,0x714b,0x7150,0x7152,0x7157,
+    0x715a,0x715c,0x715e,0x7160
+  },
+  {				/* ku 2a */
+    0x7168,0x7179,0x7180,0x7185,0x7187,0x718c,0x7192,0x719a,0x719b,0x71a0,
+    0x71a2,0x71af,0x71b0,0x71b2,0x71b3,0x71ba,0x71bf,0x71c0,0x71c1,0x71c4,
+    0x71cb,0x71cc,0x71d3,0x71d6,0x71d9,0x71da,0x71dc,0x71f8,0x71fe,0x7200,
+    0x7207,0x7208,0x7209,0x7213,0x7217,0x721a,0x721d,0x721f,0x7224,0x722b,
+    0x722f,0x7234,0x7238,0x7239,0x7241,0x7242,0x7243,0x7245,0x724e,0x724f,
+    0x7250,0x7253,0x7255,0x7256,0x725a,0x725c,0x725e,0x7260,0x7263,0x7268,
+    0x726b,0x726e,0x726f,0x7271,0x7277,0x7278,0x727b,0x727c,0x727f,0x7284,
+    0x7289,0x728d,0x728e,0x7293,0x729b,0x72a8,0x72ad,0x72ae,0x72b1,0x72b4,
+    0x72be,0x72c1,0x72c7,0x72c9,0x72cc,0x72d5,0x72d6,0x72d8,0x72df,0x72e5,
+    0x72f3,0x72f4,0x72fa,0x72fb
+  },
+  {				/* ku 2b */
+    0x72fe,0x7302,0x7304,0x7305,0x7307,0x730b,0x730d,0x7312,0x7313,0x7318,
+    0x7319,0x731e,0x7322,0x7324,0x7327,0x7328,0x732c,0x7331,0x7332,0x7335,
+    0x733a,0x733b,0x733d,0x7343,0x734d,0x7350,0x7352,0x7356,0x7358,0x735d,
+    0x735e,0x735f,0x7360,0x7366,0x7367,0x7369,0x736b,0x736c,0x736e,0x736f,
+    0x7371,0x7377,0x7379,0x737c,0x7380,0x7381,0x7383,0x7385,0x7386,0x738e,
+    0x7390,0x7393,0x7395,0x7397,0x7398,0x739c,0x739e,0x739f,0x73a0,0x73a2,
+    0x73a5,0x73a6,0x73aa,0x73ab,0x73ad,0x73b5,0x73b7,0x73b9,0x73bc,0x73bd,
+    0x73bf,0x73c5,0x73c6,0x73c9,0x73cb,0x73cc,0x73cf,0x73d2,0x73d3,0x73d6,
+    0x73d9,0x73dd,0x73e1,0x73e3,0x73e6,0x73e7,0x73e9,0x73f4,0x73f5,0x73f7,
+    0x73f9,0x73fa,0x73fb,0x73fd
+  },
+  {				/* ku 2c */
+    0x73ff,0x7400,0x7401,0x7404,0x7407,0x740a,0x7411,0x741a,0x741b,0x7424,
+    0x7426,0x7428,0x7429,0x742a,0x742b,0x742c,0x742d,0x742e,0x742f,0x7430,
+    0x7431,0x7439,0x7440,0x7443,0x7444,0x7446,0x7447,0x744b,0x744d,0x7451,
+    0x7452,0x7457,0x745d,0x7462,0x7466,0x7467,0x7468,0x746b,0x746d,0x746e,
+    0x7471,0x7472,0x7480,0x7481,0x7485,0x7486,0x7487,0x7489,0x748f,0x7490,
+    0x7491,0x7492,0x7498,0x7499,0x749a,0x749c,0x749f,0x74a0,0x74a1,0x74a3,
+    0x74a6,0x74a8,0x74a9,0x74aa,0x74ab,0x74ae,0x74af,0x74b1,0x74b2,0x74b5,
+    0x74b9,0x74bb,0x74bf,0x74c8,0x74c9,0x74cc,0x74d0,0x74d3,0x74d8,0x74da,
+    0x74db,0x74de,0x74df,0x74e4,0x74e8,0x74ea,0x74eb,0x74ef,0x74f4,0x74fa,
+    0x74fb,0x74fc,0x74ff,0x7506
+  },
+  {				/* ku 2d */
+    0x7512,0x7516,0x7517,0x7520,0x7521,0x7524,0x7527,0x7529,0x752a,0x752f,
+    0x7536,0x7539,0x753d,0x753e,0x753f,0x7540,0x7543,0x7547,0x7548,0x754e,
+    0x7550,0x7552,0x7557,0x755e,0x755f,0x7561,0x756f,0x7571,0x7579,0x757a,
+    0x757b,0x757c,0x757d,0x757e,0x7581,0x7585,0x7590,0x7592,0x7593,0x7595,
+    0x7599,0x759c,0x75a2,0x75a4,0x75b4,0x75ba,0x75bf,0x75c0,0x75c1,0x75c4,
+    0x75c6,0x75cc,0x75ce,0x75cf,0x75d7,0x75dc,0x75df,0x75e0,0x75e1,0x75e4,
+    0x75e7,0x75ec,0x75ee,0x75ef,0x75f1,0x75f9,0x7600,0x7602,0x7603,0x7604,
+    0x7607,0x7608,0x760a,0x760c,0x760f,0x7612,0x7613,0x7615,0x7616,0x7619,
+    0x761b,0x761c,0x761d,0x761e,0x7623,0x7625,0x7626,0x7629,0x762d,0x7632,
+    0x7633,0x7635,0x7638,0x7639
+  },
+  {				/* ku 2e */
+    0x763a,0x763c,0x764a,0x7640,0x7641,0x7643,0x7644,0x7645,0x7649,0x764b,
+    0x7655,0x7659,0x765f,0x7664,0x7665,0x766d,0x766e,0x766f,0x7671,0x7674,
+    0x7681,0x7685,0x768c,0x768d,0x7695,0x769b,0x769c,0x769d,0x769f,0x76a0,
+    0x76a2,0x76a3,0x76a4,0x76a5,0x76a6,0x76a7,0x76a8,0x76aa,0x76ad,0x76bd,
+    0x76c1,0x76c5,0x76c9,0x76cb,0x76cc,0x76ce,0x76d4,0x76d9,0x76e0,0x76e6,
+    0x76e8,0x76ec,0x76f0,0x76f1,0x76f6,0x76f9,0x76fc,0x7700,0x7706,0x770a,
+    0x770e,0x7712,0x7714,0x7715,0x7717,0x7719,0x771a,0x771c,0x7722,0x7728,
+    0x772d,0x772e,0x772f,0x7734,0x7735,0x7736,0x7739,0x773d,0x773e,0x7742,
+    0x7745,0x7746,0x774a,0x774d,0x774e,0x774f,0x7752,0x7756,0x7757,0x775c,
+    0x775e,0x775f,0x7760,0x7762
+  },
+  {				/* ku 2f */
+    0x7764,0x7767,0x776a,0x776c,0x7770,0x7772,0x7773,0x7774,0x777a,0x777d,
+    0x7780,0x7784,0x778c,0x778d,0x7794,0x7795,0x7796,0x779a,0x779f,0x77a2,
+    0x77a7,0x77aa,0x77ae,0x77af,0x77b1,0x77b5,0x77be,0x77c3,0x77c9,0x77d1,
+    0x77d2,0x77d5,0x77d9,0x77de,0x77df,0x77e0,0x77e4,0x77e6,0x77ea,0x77ec,
+    0x77f0,0x77f1,0x77f4,0x77f8,0x77fb,0x7805,0x7806,0x7809,0x780d,0x780e,
+    0x7811,0x781d,0x7821,0x7822,0x7823,0x782d,0x782e,0x7830,0x7835,0x7837,
+    0x7843,0x7844,0x7847,0x7848,0x784c,0x784e,0x7852,0x785c,0x785e,0x7860,
+    0x7861,0x7863,0x7864,0x7868,0x786a,0x786e,0x787a,0x787e,0x788a,0x788f,
+    0x7894,0x7898,0x78a1,0x789d,0x789e,0x789f,0x78a4,0x78a8,0x78ac,0x78ad,
+    0x78b0,0x78b1,0x78b2,0x78b3
+  },
+  {				/* ku 30 */
+    0x78bb,0x78bd,0x78bf,0x78c7,0x78c8,0x78c9,0x78cc,0x78ce,0x78d2,0x78d3,
+    0x78d5,0x78d6,0x78e4,0x78db,0x78df,0x78e0,0x78e1,0x78e6,0x78ea,0x78f2,
+    0x78f3,0x7900,0x78f6,0x78f7,0x78fa,0x78fb,0x78ff,0x7906,0x790c,0x7910,
+    0x791a,0x791c,0x791e,0x791f,0x7920,0x7925,0x7927,0x7929,0x792d,0x7931,
+    0x7934,0x7935,0x793b,0x793d,0x793f,0x7944,0x7945,0x7946,0x794a,0x794b,
+    0x794f,0x7951,0x7954,0x7958,0x795b,0x795c,0x7967,0x7969,0x796b,0x7972,
+    0x7979,0x797b,0x797c,0x797e,0x798b,0x798c,0x7991,0x7993,0x7994,0x7995,
+    0x7996,0x7998,0x799b,0x799c,0x79a1,0x79a8,0x79a9,0x79ab,0x79af,0x79b1,
+    0x79b4,0x79b8,0x79bb,0x79c2,0x79c4,0x79c7,0x79c8,0x79ca,0x79cf,0x79d4,
+    0x79d6,0x79da,0x79dd,0x79de
+  },
+  {				/* ku 31 */
+    0x79e0,0x79e2,0x79e5,0x79ea,0x79eb,0x79ed,0x79f1,0x79f8,0x79fc,0x7a02,
+    0x7a03,0x7a07,0x7a09,0x7a0a,0x7a0c,0x7a11,0x7a15,0x7a1b,0x7a1e,0x7a21,
+    0x7a27,0x7a2b,0x7a2d,0x7a2f,0x7a30,0x7a34,0x7a35,0x7a38,0x7a39,0x7a3a,
+    0x7a44,0x7a45,0x7a47,0x7a48,0x7a4c,0x7a55,0x7a56,0x7a59,0x7a5c,0x7a5d,
+    0x7a5f,0x7a60,0x7a65,0x7a67,0x7a6a,0x7a6d,0x7a75,0x7a78,0x7a7e,0x7a80,
+    0x7a82,0x7a85,0x7a86,0x7a8a,0x7a8b,0x7a90,0x7a91,0x7a94,0x7a9e,0x7aa0,
+    0x7aa3,0x7aac,0x7ab3,0x7ab5,0x7ab9,0x7abb,0x7abc,0x7ac6,0x7ac9,0x7acc,
+    0x7ace,0x7ad1,0x7adb,0x7ae8,0x7ae9,0x7aeb,0x7aec,0x7af1,0x7af4,0x7afb,
+    0x7afd,0x7afe,0x7b07,0x7b14,0x7b1f,0x7b23,0x7b27,0x7b29,0x7b2a,0x7b2b,
+    0x7b2d,0x7b2e,0x7b2f,0x7b30
+  },
+  {				/* ku 32 */
+    0x7b31,0x7b34,0x7b3d,0x7b3f,0x7b40,0x7b41,0x7b47,0x7b4e,0x7b55,0x7b60,
+    0x7b64,0x7b66,0x7b69,0x7b6a,0x7b6d,0x7b6f,0x7b72,0x7b73,0x7b77,0x7b84,
+    0x7b89,0x7b8e,0x7b90,0x7b91,0x7b96,0x7b9b,0x7b9e,0x7ba0,0x7ba5,0x7bac,
+    0x7baf,0x7bb0,0x7bb2,0x7bb5,0x7bb6,0x7bba,0x7bbb,0x7bbc,0x7bbd,0x7bc2,
+    0x7bc5,0x7bc8,0x7bca,0x7bd4,0x7bd6,0x7bd7,0x7bd9,0x7bda,0x7bdb,0x7be8,
+    0x7bea,0x7bf2,0x7bf4,0x7bf5,0x7bf8,0x7bf9,0x7bfa,0x7bfc,0x7bfe,0x7c01,
+    0x7c02,0x7c03,0x7c04,0x7c06,0x7c09,0x7c0b,0x7c0c,0x7c0e,0x7c0f,0x7c19,
+    0x7c1b,0x7c20,0x7c25,0x7c26,0x7c28,0x7c2c,0x7c31,0x7c33,0x7c34,0x7c36,
+    0x7c39,0x7c3a,0x7c46,0x7c4a,0x7c55,0x7c51,0x7c52,0x7c53,0x7c59,0x7c5a,
+    0x7c5b,0x7c5c,0x7c5d,0x7c5e
+  },
+  {				/* ku 33 */
+    0x7c61,0x7c63,0x7c67,0x7c69,0x7c6d,0x7c6e,0x7c70,0x7c72,0x7c79,0x7c7c,
+    0x7c7d,0x7c86,0x7c87,0x7c8f,0x7c94,0x7c9e,0x7ca0,0x7ca6,0x7cb0,0x7cb6,
+    0x7cb7,0x7cba,0x7cbb,0x7cbc,0x7cbf,0x7cc4,0x7cc7,0x7cc8,0x7cc9,0x7ccd,
+    0x7ccf,0x7cd3,0x7cd4,0x7cd5,0x7cd7,0x7cd9,0x7cda,0x7cdd,0x7ce6,0x7ce9,
+    0x7ceb,0x7cf5,0x7d03,0x7d07,0x7d08,0x7d09,0x7d0f,0x7d11,0x7d12,0x7d13,
+    0x7d16,0x7d1d,0x7d1e,0x7d23,0x7d26,0x7d2a,0x7d2d,0x7d31,0x7d3c,0x7d3d,
+    0x7d3e,0x7d40,0x7d41,0x7d47,0x7d48,0x7d4d,0x7d51,0x7d53,0x7d57,0x7d59,
+    0x7d5a,0x7d5c,0x7d5d,0x7d65,0x7d67,0x7d6a,0x7d70,0x7d78,0x7d7a,0x7d7b,
+    0x7d7f,0x7d81,0x7d82,0x7d83,0x7d85,0x7d86,0x7d88,0x7d8b,0x7d8c,0x7d8d,
+    0x7d91,0x7d96,0x7d97,0x7d9d
+  },
+  {				/* ku 34 */
+    0x7d9e,0x7da6,0x7da7,0x7daa,0x7db3,0x7db6,0x7db7,0x7db9,0x7dc2,0x7dc3,
+    0x7dc4,0x7dc5,0x7dc6,0x7dcc,0x7dcd,0x7dce,0x7dd7,0x7dd9,0x7e00,0x7de2,
+    0x7de5,0x7de6,0x7dea,0x7deb,0x7ded,0x7df1,0x7df5,0x7df6,0x7df9,0x7dfa,
+    0x7e08,0x7e10,0x7e11,0x7e15,0x7e17,0x7e1c,0x7e1d,0x7e20,0x7e27,0x7e28,
+    0x7e2c,0x7e2d,0x7e2f,0x7e33,0x7e36,0x7e3f,0x7e44,0x7e45,0x7e47,0x7e4e,
+    0x7e50,0x7e52,0x7e58,0x7e5f,0x7e61,0x7e62,0x7e65,0x7e6b,0x7e6e,0x7e6f,
+    0x7e73,0x7e78,0x7e7e,0x7e81,0x7e86,0x7e87,0x7e8a,0x7e8d,0x7e91,0x7e95,
+    0x7e98,0x7e9a,0x7e9d,0x7e9e,0x7f3c,0x7f3b,0x7f3d,0x7f3e,0x7f3f,0x7f43,
+    0x7f44,0x7f47,0x7f4f,0x7f52,0x7f53,0x7f5b,0x7f5c,0x7f5d,0x7f61,0x7f63,
+    0x7f64,0x7f65,0x7f66,0x7f6d
+  },
+  {				/* ku 35 */
+    0x7f71,0x7f7d,0x7f7e,0x7f7f,0x7f80,0x7f8b,0x7f8d,0x7f8f,0x7f90,0x7f91,
+    0x7f96,0x7f97,0x7f9c,0x7fa1,0x7fa2,0x7fa6,0x7faa,0x7fad,0x7fb4,0x7fbc,
+    0x7fbf,0x7fc0,0x7fc3,0x7fc8,0x7fce,0x7fcf,0x7fdb,0x7fdf,0x7fe3,0x7fe5,
+    0x7fe8,0x7fec,0x7fee,0x7fef,0x7ff2,0x7ffa,0x7ffd,0x7ffe,0x7fff,0x8007,
+    0x8008,0x800a,0x800d,0x800e,0x800f,0x8011,0x8013,0x8014,0x8016,0x801d,
+    0x801e,0x801f,0x8020,0x8024,0x8026,0x802c,0x802e,0x8030,0x8034,0x8035,
+    0x8037,0x8039,0x803a,0x803c,0x803e,0x8040,0x8044,0x8060,0x8064,0x8066,
+    0x806d,0x8071,0x8075,0x8081,0x8088,0x808e,0x809c,0x809e,0x80a6,0x80a7,
+    0x80ab,0x80b8,0x80b9,0x80c8,0x80cd,0x80cf,0x80d2,0x80d4,0x80d5,0x80d7,
+    0x80d8,0x80e0,0x80ed,0x80ee
+  },
+  {				/* ku 36 */
+    0x80f0,0x80f2,0x80f3,0x80f6,0x80f9,0x80fa,0x80fe,0x8103,0x810b,0x8116,
+    0x8117,0x8118,0x811c,0x811e,0x8120,0x8124,0x8127,0x812c,0x8130,0x8135,
+    0x813a,0x813c,0x8145,0x8147,0x814a,0x814c,0x8152,0x8157,0x8160,0x8161,
+    0x8167,0x8168,0x8169,0x816d,0x816f,0x8177,0x8181,0x8190,0x8184,0x8185,
+    0x8186,0x818b,0x818e,0x8196,0x8198,0x819b,0x819e,0x81a2,0x81ae,0x81b2,
+    0x81b4,0x81bb,0x81cb,0x81c3,0x81c5,0x81ca,0x81ce,0x81cf,0x81d5,0x81d7,
+    0x81db,0x81dd,0x81de,0x81e1,0x81e4,0x81eb,0x81ec,0x81f0,0x81f1,0x81f2,
+    0x81f5,0x81f6,0x81f8,0x81f9,0x81fd,0x81ff,0x8200,0x8203,0x820f,0x8213,
+    0x8214,0x8219,0x821a,0x821d,0x8221,0x8222,0x8228,0x8232,0x8234,0x823a,
+    0x8243,0x8244,0x8245,0x8246
+  },
+  {				/* ku 37 */
+    0x824b,0x824e,0x824f,0x8251,0x8256,0x825c,0x8260,0x8263,0x8267,0x826d,
+    0x8274,0x827b,0x827d,0x827f,0x8280,0x8281,0x8283,0x8284,0x8287,0x8289,
+    0x828a,0x828e,0x8291,0x8294,0x8296,0x8298,0x829a,0x829b,0x82a0,0x82a1,
+    0x82a3,0x82a4,0x82a7,0x82a8,0x82a9,0x82aa,0x82ae,0x82b0,0x82b2,0x82b4,
+    0x82b7,0x82ba,0x82bc,0x82be,0x82bf,0x82c6,0x82d0,0x82d5,0x82da,0x82e0,
+    0x82e2,0x82e4,0x82e8,0x82ea,0x82ed,0x82ef,0x82f6,0x82f7,0x82fd,0x82fe,
+    0x8300,0x8301,0x8307,0x8308,0x830a,0x830b,0x8354,0x831b,0x831d,0x831e,
+    0x831f,0x8321,0x8322,0x832c,0x832d,0x832e,0x8330,0x8333,0x8337,0x833a,
+    0x833c,0x833d,0x8342,0x8343,0x8344,0x8347,0x834d,0x834e,0x8351,0x8355,
+    0x8356,0x8357,0x8370,0x8378
+  },
+  {				/* ku 38 */
+    0x837d,0x837f,0x8380,0x8382,0x8384,0x8386,0x838d,0x8392,0x8394,0x8395,
+    0x8398,0x8399,0x839b,0x839c,0x839d,0x83a6,0x83a7,0x83a9,0x83ac,0x83be,
+    0x83bf,0x83c0,0x83c7,0x83c9,0x83cf,0x83d0,0x83d1,0x83d4,0x83dd,0x8353,
+    0x83e8,0x83ea,0x83f6,0x83f8,0x83f9,0x83fc,0x8401,0x8406,0x840a,0x840f,
+    0x8411,0x8415,0x8419,0x83ad,0x842f,0x8439,0x8445,0x8447,0x8448,0x844a,
+    0x844d,0x844f,0x8451,0x8452,0x8456,0x8458,0x8459,0x845a,0x845c,0x8460,
+    0x8464,0x8465,0x8467,0x846a,0x8470,0x8473,0x8474,0x8476,0x8478,0x847c,
+    0x847d,0x8481,0x8485,0x8492,0x8493,0x8495,0x849e,0x84a6,0x84a8,0x84a9,
+    0x84aa,0x84af,0x84b1,0x84b4,0x84ba,0x84bd,0x84be,0x84c0,0x84c2,0x84c7,
+    0x84c8,0x84cc,0x84cf,0x84d3
+  },
+  {				/* ku 39 */
+    0x84dc,0x84e7,0x84ea,0x84ef,0x84f0,0x84f1,0x84f2,0x84f7,0x8532,0x84fa,
+    0x84fb,0x84fd,0x8502,0x8503,0x8507,0x850c,0x850e,0x8510,0x851c,0x851e,
+    0x8522,0x8523,0x8524,0x8525,0x8527,0x852a,0x852b,0x852f,0x8533,0x8534,
+    0x8536,0x853f,0x8546,0x854f,0x8550,0x8551,0x8552,0x8553,0x8556,0x8559,
+    0x855c,0x855d,0x855e,0x855f,0x8560,0x8561,0x8562,0x8564,0x856b,0x856f,
+    0x8579,0x857a,0x857b,0x857d,0x857f,0x8581,0x8585,0x8586,0x8589,0x858b,
+    0x858c,0x858f,0x8593,0x8598,0x859d,0x859f,0x85a0,0x85a2,0x85a5,0x85a7,
+    0x85b4,0x85b6,0x85b7,0x85b8,0x85bc,0x85bd,0x85be,0x85bf,0x85c2,0x85c7,
+    0x85ca,0x85cb,0x85ce,0x85ad,0x85d8,0x85da,0x85df,0x85e0,0x85e6,0x85e8,
+    0x85ed,0x85f3,0x85f6,0x85fc
+  },
+  {				/* ku 3a */
+    0x85ff,0x8600,0x8604,0x8605,0x860d,0x860e,0x8610,0x8611,0x8612,0x8618,
+    0x8619,0x861b,0x861e,0x8621,0x8627,0x8629,0x8636,0x8638,0x863a,0x863c,
+    0x863d,0x8640,0x8642,0x8646,0x8652,0x8653,0x8656,0x8657,0x8658,0x8659,
+    0x865d,0x8660,0x8661,0x8662,0x8663,0x8664,0x8669,0x866c,0x866f,0x8675,
+    0x8676,0x8677,0x867a,0x868d,0x8691,0x8696,0x8698,0x869a,0x869c,0x86a1,
+    0x86a6,0x86a7,0x86a8,0x86ad,0x86b1,0x86b3,0x86b4,0x86b5,0x86b7,0x86b8,
+    0x86b9,0x86bf,0x86c0,0x86c1,0x86c3,0x86c5,0x86d1,0x86d2,0x86d5,0x86d7,
+    0x86da,0x86dc,0x86e0,0x86e3,0x86e5,0x86e7,0x8688,0x86fa,0x86fc,0x86fd,
+    0x8704,0x8705,0x8707,0x870b,0x870e,0x870f,0x8710,0x8713,0x8714,0x8719,
+    0x871e,0x871f,0x8721,0x8723
+  },
+  {				/* ku 3b */
+    0x8728,0x872e,0x872f,0x8731,0x8732,0x8739,0x873a,0x873c,0x873d,0x873e,
+    0x8740,0x8743,0x8745,0x874d,0x8758,0x875d,0x8761,0x8764,0x8765,0x876f,
+    0x8771,0x8772,0x877b,0x8783,0x8784,0x8785,0x8786,0x8787,0x8788,0x8789,
+    0x878b,0x878c,0x8790,0x8793,0x8795,0x8797,0x8798,0x8799,0x879e,0x87a0,
+    0x87a3,0x87a7,0x87ac,0x87ad,0x87ae,0x87b1,0x87b5,0x87be,0x87bf,0x87c1,
+    0x87c8,0x87c9,0x87ca,0x87ce,0x87d5,0x87d6,0x87d9,0x87da,0x87dc,0x87df,
+    0x87e2,0x87e3,0x87e4,0x87ea,0x87eb,0x87ed,0x87f1,0x87f3,0x87f8,0x87fa,
+    0x87ff,0x8801,0x8803,0x8806,0x8809,0x880a,0x880b,0x8810,0x8819,0x8812,
+    0x8813,0x8814,0x8818,0x881a,0x881b,0x881c,0x881e,0x881f,0x8828,0x882d,
+    0x882e,0x8830,0x8832,0x8835
+  },
+  {				/* ku 3c */
+    0x883a,0x883c,0x8841,0x8843,0x8845,0x8848,0x8849,0x884a,0x884b,0x884e,
+    0x8851,0x8855,0x8856,0x8858,0x885a,0x885c,0x885f,0x8860,0x8864,0x8869,
+    0x8871,0x8879,0x887b,0x8880,0x8898,0x889a,0x889b,0x889c,0x889f,0x88a0,
+    0x88a8,0x88aa,0x88ba,0x88bd,0x88be,0x88c0,0x88ca,0x88cb,0x88cc,0x88cd,
+    0x88ce,0x88d1,0x88d2,0x88d3,0x88db,0x88de,0x88e7,0x88ef,0x88f0,0x88f1,
+    0x88f5,0x88f7,0x8901,0x8906,0x890d,0x890e,0x890f,0x8915,0x8916,0x8918,
+    0x8919,0x891a,0x891c,0x8920,0x8926,0x8927,0x8928,0x8930,0x8931,0x8932,
+    0x8935,0x8939,0x893a,0x893e,0x8940,0x8942,0x8945,0x8946,0x8949,0x894f,
+    0x8952,0x8957,0x895a,0x895b,0x895c,0x8961,0x8962,0x8963,0x896b,0x896e,
+    0x8970,0x8973,0x8975,0x897a
+  },
+  {				/* ku 3d */
+    0x897b,0x897c,0x897d,0x8989,0x898d,0x8990,0x8994,0x8995,0x899b,0x899c,
+    0x899f,0x89a0,0x89a5,0x89b0,0x89b4,0x89b5,0x89b6,0x89b7,0x89bc,0x89d4,
+    0x89d5,0x89d6,0x89d7,0x89d8,0x89e5,0x89e9,0x89eb,0x89ed,0x89f1,0x89f3,
+    0x89f6,0x89f9,0x89fd,0x89ff,0x8a04,0x8a05,0x8a07,0x8a0f,0x8a11,0x8a12,
+    0x8a14,0x8a15,0x8a1e,0x8a20,0x8a22,0x8a24,0x8a26,0x8a2b,0x8a2c,0x8a2f,
+    0x8a35,0x8a37,0x8a3d,0x8a3e,0x8a40,0x8a43,0x8a45,0x8a47,0x8a49,0x8a4d,
+    0x8a4e,0x8a53,0x8a56,0x8a57,0x8a58,0x8a5c,0x8a5d,0x8a61,0x8a65,0x8a67,
+    0x8a75,0x8a76,0x8a77,0x8a79,0x8a7a,0x8a7b,0x8a7e,0x8a7f,0x8a80,0x8a83,
+    0x8a86,0x8a8b,0x8a8f,0x8a90,0x8a92,0x8a96,0x8a97,0x8a99,0x8a9f,0x8aa7,
+    0x8aa9,0x8aae,0x8aaf,0x8ab3
+  },
+  {				/* ku 3e */
+    0x8ab6,0x8ab7,0x8abb,0x8abe,0x8ac3,0x8ac6,0x8ac8,0x8ac9,0x8aca,0x8ad1,
+    0x8ad3,0x8ad4,0x8ad5,0x8ad7,0x8add,0x8adf,0x8aec,0x8af0,0x8af4,0x8af5,
+    0x8af6,0x8afc,0x8aff,0x8b05,0x8b06,0x8b0b,0x8b11,0x8b1c,0x8b1e,0x8b1f,
+    0x8b0a,0x8b2d,0x8b30,0x8b37,0x8b3c,0x8b42,0x8b43,0x8b44,0x8b45,0x8b46,
+    0x8b48,0x8b52,0x8b53,0x8b54,0x8b59,0x8b4d,0x8b5e,0x8b63,0x8b6d,0x8b76,
+    0x8b78,0x8b79,0x8b7c,0x8b7e,0x8b81,0x8b84,0x8b85,0x8b8b,0x8b8d,0x8b8f,
+    0x8b94,0x8b95,0x8b9c,0x8b9e,0x8b9f,0x8c38,0x8c39,0x8c3d,0x8c3e,0x8c45,
+    0x8c47,0x8c49,0x8c4b,0x8c4f,0x8c51,0x8c53,0x8c54,0x8c57,0x8c58,0x8c5b,
+    0x8c5d,0x8c59,0x8c63,0x8c64,0x8c66,0x8c68,0x8c69,0x8c6d,0x8c73,0x8c75,
+    0x8c76,0x8c7b,0x8c7e,0x8c86
+  },
+  {				/* ku 3f */
+    0x8c87,0x8c8b,0x8c90,0x8c92,0x8c93,0x8c99,0x8c9b,0x8c9c,0x8ca4,0x8cb9,
+    0x8cba,0x8cc5,0x8cc6,0x8cc9,0x8ccb,0x8ccf,0x8cd6,0x8cd5,0x8cd9,0x8cdd,
+    0x8ce1,0x8ce8,0x8cec,0x8cef,0x8cf0,0x8cf2,0x8cf5,0x8cf7,0x8cf8,0x8cfe,
+    0x8cff,0x8d01,0x8d03,0x8d09,0x8d12,0x8d17,0x8d1b,0x8d65,0x8d69,0x8d6c,
+    0x8d6e,0x8d7f,0x8d82,0x8d84,0x8d88,0x8d8d,0x8d90,0x8d91,0x8d95,0x8d9e,
+    0x8d9f,0x8da0,0x8da6,0x8dab,0x8dac,0x8daf,0x8db2,0x8db5,0x8db7,0x8db9,
+    0x8dbb,0x8dc0,0x8dc5,0x8dc6,0x8dc7,0x8dc8,0x8dca,0x8dce,0x8dd1,0x8dd4,
+    0x8dd5,0x8dd7,0x8dd9,0x8de4,0x8de5,0x8de7,0x8dec,0x8df0,0x8dbc,0x8df1,
+    0x8df2,0x8df4,0x8dfd,0x8e01,0x8e04,0x8e05,0x8e06,0x8e0b,0x8e11,0x8e14,
+    0x8e16,0x8e20,0x8e21,0x8e22
+  },
+  {				/* ku 40 */
+    0x8e23,0x8e26,0x8e27,0x8e31,0x8e33,0x8e36,0x8e37,0x8e38,0x8e39,0x8e3d,
+    0x8e40,0x8e41,0x8e4b,0x8e4d,0x8e4e,0x8e4f,0x8e54,0x8e5b,0x8e5c,0x8e5d,
+    0x8e5e,0x8e61,0x8e62,0x8e69,0x8e6c,0x8e6d,0x8e6f,0x8e70,0x8e71,0x8e79,
+    0x8e7a,0x8e7b,0x8e82,0x8e83,0x8e89,0x8e90,0x8e92,0x8e95,0x8e9a,0x8e9b,
+    0x8e9d,0x8e9e,0x8ea2,0x8ea7,0x8ea9,0x8ead,0x8eae,0x8eb3,0x8eb5,0x8eba,
+    0x8ebb,0x8ec0,0x8ec1,0x8ec3,0x8ec4,0x8ec7,0x8ecf,0x8ed1,0x8ed4,0x8edc,
+    0x8ee8,0x8eee,0x8ef0,0x8ef1,0x8ef7,0x8ef9,0x8efa,0x8eed,0x8f00,0x8f02,
+    0x8f07,0x8f08,0x8f0f,0x8f10,0x8f16,0x8f17,0x8f18,0x8f1e,0x8f20,0x8f21,
+    0x8f23,0x8f25,0x8f27,0x8f28,0x8f2c,0x8f2d,0x8f2e,0x8f34,0x8f35,0x8f36,
+    0x8f37,0x8f3a,0x8f40,0x8f41
+  },
+  {				/* ku 41 */
+    0x8f43,0x8f47,0x8f4f,0x8f51,0x8f52,0x8f53,0x8f54,0x8f55,0x8f58,0x8f5d,
+    0x8f5e,0x8f65,0x8f9d,0x8fa0,0x8fa1,0x8fa4,0x8fa5,0x8fa6,0x8fb5,0x8fb6,
+    0x8fb8,0x8fbe,0x8fc0,0x8fc1,0x8fc6,0x8fca,0x8fcb,0x8fcd,0x8fd0,0x8fd2,
+    0x8fd3,0x8fd5,0x8fe0,0x8fe3,0x8fe4,0x8fe8,0x8fee,0x8ff1,0x8ff5,0x8ff6,
+    0x8ffb,0x8ffe,0x9002,0x9004,0x9008,0x900c,0x9018,0x901b,0x9028,0x9029,
+    0x902f,0x902a,0x902c,0x902d,0x9033,0x9034,0x9037,0x903f,0x9043,0x9044,
+    0x904c,0x905b,0x905d,0x9062,0x9066,0x9067,0x906c,0x9070,0x9074,0x9079,
+    0x9085,0x9088,0x908b,0x908c,0x908e,0x9090,0x9095,0x9097,0x9098,0x9099,
+    0x909b,0x90a0,0x90a1,0x90a2,0x90a5,0x90b0,0x90b2,0x90b3,0x90b4,0x90b6,
+    0x90bd,0x90cc,0x90be,0x90c3
+  },
+  {				/* ku 42 */
+    0x90c4,0x90c5,0x90c7,0x90c8,0x90d5,0x90d7,0x90d8,0x90d9,0x90dc,0x90dd,
+    0x90df,0x90e5,0x90d2,0x90f6,0x90eb,0x90ef,0x90f0,0x90f4,0x90fe,0x90ff,
+    0x9100,0x9104,0x9105,0x9106,0x9108,0x910d,0x9110,0x9114,0x9116,0x9117,
+    0x9118,0x911a,0x911c,0x911e,0x9120,0x9125,0x9122,0x9123,0x9127,0x9129,
+    0x912e,0x912f,0x9131,0x9134,0x9136,0x9137,0x9139,0x913a,0x913c,0x913d,
+    0x9143,0x9147,0x9148,0x914f,0x9153,0x9157,0x9159,0x915a,0x915b,0x9161,
+    0x9164,0x9167,0x916d,0x9174,0x9179,0x917a,0x917b,0x9181,0x9183,0x9185,
+    0x9186,0x918a,0x918e,0x9191,0x9193,0x9194,0x9195,0x9198,0x919e,0x91a1,
+    0x91a6,0x91a8,0x91ac,0x91ad,0x91ae,0x91b0,0x91b1,0x91b2,0x91b3,0x91b6,
+    0x91bb,0x91bc,0x91bd,0x91bf
+  },
+  {				/* ku 43 */
+    0x91c2,0x91c3,0x91c5,0x91d3,0x91d4,0x91d7,0x91d9,0x91da,0x91de,0x91e4,
+    0x91e5,0x91e9,0x91ea,0x91ec,0x91ed,0x91ee,0x91ef,0x91f0,0x91f1,0x91f7,
+    0x91f9,0x91fb,0x91fd,0x9200,0x9201,0x9204,0x9205,0x9206,0x9207,0x9209,
+    0x920a,0x920c,0x9210,0x9212,0x9213,0x9216,0x9218,0x921c,0x921d,0x9223,
+    0x9224,0x9225,0x9226,0x9228,0x922e,0x922f,0x9230,0x9233,0x9235,0x9236,
+    0x9238,0x9239,0x923a,0x923c,0x923e,0x9240,0x9242,0x9243,0x9246,0x9247,
+    0x924a,0x924d,0x924e,0x924f,0x9251,0x9258,0x9259,0x925c,0x925d,0x9260,
+    0x9261,0x9265,0x9267,0x9268,0x9269,0x926e,0x926f,0x9270,0x9275,0x9276,
+    0x9277,0x9278,0x9279,0x927b,0x927c,0x927d,0x927f,0x9288,0x9289,0x928a,
+    0x928d,0x928e,0x9292,0x9297
+  },
+  {				/* ku 44 */
+    0x9299,0x929f,0x92a0,0x92a4,0x92a5,0x92a7,0x92a8,0x92ab,0x92af,0x92b2,
+    0x92b6,0x92b8,0x92ba,0x92bb,0x92bc,0x92bd,0x92bf,0x92c0,0x92c1,0x92c2,
+    0x92c3,0x92c5,0x92c6,0x92c7,0x92c8,0x92cb,0x92cc,0x92cd,0x92ce,0x92d0,
+    0x92d3,0x92d5,0x92d7,0x92d8,0x92d9,0x92dc,0x92dd,0x92df,0x92e0,0x92e1,
+    0x92e3,0x92e5,0x92e7,0x92e8,0x92ec,0x92ee,0x92f0,0x92f9,0x92fb,0x92ff,
+    0x9300,0x9302,0x9308,0x930d,0x9311,0x9314,0x9315,0x931c,0x931d,0x931e,
+    0x931f,0x9321,0x9324,0x9325,0x9327,0x9329,0x932a,0x9333,0x9334,0x9336,
+    0x9337,0x9347,0x9348,0x9349,0x9350,0x9351,0x9352,0x9355,0x9357,0x9358,
+    0x935a,0x935e,0x9364,0x9365,0x9367,0x9369,0x936a,0x936d,0x936f,0x9370,
+    0x9371,0x9373,0x9374,0x9376
+  },
+  {				/* ku 45 */
+    0x937a,0x937d,0x937f,0x9380,0x9381,0x9382,0x9388,0x938a,0x938b,0x938d,
+    0x938f,0x9392,0x9395,0x9398,0x939b,0x939e,0x93a1,0x93a3,0x93a4,0x93a6,
+    0x93a8,0x93ab,0x93b4,0x93b5,0x93b6,0x93ba,0x93a9,0x93c1,0x93c4,0x93c5,
+    0x93c6,0x93c7,0x93c9,0x93ca,0x93cb,0x93cc,0x93cd,0x93d3,0x93d9,0x93dc,
+    0x93de,0x93df,0x93e2,0x93e6,0x93e7,0x93f9,0x93f7,0x93f8,0x93fa,0x93fb,
+    0x93fd,0x9401,0x9402,0x9404,0x9408,0x9409,0x940d,0x940e,0x940f,0x9415,
+    0x9416,0x9417,0x941f,0x942e,0x942f,0x9431,0x9432,0x9433,0x9434,0x943b,
+    0x943f,0x943d,0x9443,0x9445,0x9448,0x944a,0x944c,0x9455,0x9459,0x945c,
+    0x945f,0x9461,0x9463,0x9468,0x946b,0x946d,0x946e,0x946f,0x9471,0x9472,
+    0x9484,0x9483,0x9578,0x9579
+  },
+  {				/* ku 46 */
+    0x957e,0x9584,0x9588,0x958c,0x958d,0x958e,0x959d,0x959e,0x959f,0x95a1,
+    0x95a6,0x95a9,0x95ab,0x95ac,0x95b4,0x95b6,0x95ba,0x95bd,0x95bf,0x95c6,
+    0x95c8,0x95c9,0x95cb,0x95d0,0x95d1,0x95d2,0x95d3,0x95d9,0x95da,0x95dd,
+    0x95de,0x95df,0x95e0,0x95e4,0x95e6,0x961d,0x961e,0x9622,0x9624,0x9625,
+    0x9626,0x962c,0x9631,0x9633,0x9637,0x9638,0x9639,0x963a,0x963c,0x963d,
+    0x9641,0x9652,0x9654,0x9656,0x9657,0x9658,0x9661,0x966e,0x9674,0x967b,
+    0x967c,0x967e,0x967f,0x9681,0x9682,0x9683,0x9684,0x9689,0x9691,0x9696,
+    0x969a,0x969d,0x969f,0x96a4,0x96a5,0x96a6,0x96a9,0x96ae,0x96af,0x96b3,
+    0x96ba,0x96ca,0x96d2,0x5db2,0x96d8,0x96da,0x96dd,0x96de,0x96df,0x96e9,
+    0x96ef,0x96f1,0x96fa,0x9702
+  },
+  {				/* ku 47 */
+    0x9703,0x9705,0x9709,0x971a,0x971b,0x971d,0x9721,0x9722,0x9723,0x9728,
+    0x9731,0x9733,0x9741,0x9743,0x974a,0x974e,0x974f,0x9755,0x9757,0x9758,
+    0x975a,0x975b,0x9763,0x9767,0x976a,0x976e,0x9773,0x9776,0x9777,0x9778,
+    0x977b,0x977d,0x977f,0x9780,0x9789,0x9795,0x9796,0x9797,0x9799,0x979a,
+    0x979e,0x979f,0x97a2,0x97ac,0x97ae,0x97b1,0x97b2,0x97b5,0x97b6,0x97b8,
+    0x97b9,0x97ba,0x97bc,0x97be,0x97bf,0x97c1,0x97c4,0x97c5,0x97c7,0x97c9,
+    0x97ca,0x97cc,0x97cd,0x97ce,0x97d0,0x97d1,0x97d4,0x97d7,0x97d8,0x97d9,
+    0x97dd,0x97de,0x97e0,0x97db,0x97e1,0x97e4,0x97ef,0x97f1,0x97f4,0x97f7,
+    0x97f8,0x97fa,0x9807,0x980a,0x9819,0x980d,0x980e,0x9814,0x9816,0x981c,
+    0x981e,0x9820,0x9823,0x9826
+  },
+  {				/* ku 48 */
+    0x982b,0x982e,0x982f,0x9830,0x9832,0x9833,0x9835,0x9825,0x983e,0x9844,
+    0x9847,0x984a,0x9851,0x9852,0x9853,0x9856,0x9857,0x9859,0x985a,0x9862,
+    0x9863,0x9865,0x9866,0x986a,0x986c,0x98ab,0x98ad,0x98ae,0x98b0,0x98b4,
+    0x98b7,0x98b8,0x98ba,0x98bb,0x98bf,0x98c2,0x98c5,0x98c8,0x98cc,0x98e1,
+    0x98e3,0x98e5,0x98e6,0x98e7,0x98ea,0x98f3,0x98f6,0x9902,0x9907,0x9908,
+    0x9911,0x9915,0x9916,0x9917,0x991a,0x991b,0x991c,0x991f,0x9922,0x9926,
+    0x9927,0x992b,0x9931,0x9932,0x9933,0x9934,0x9935,0x9939,0x993a,0x993b,
+    0x993c,0x9940,0x9941,0x9946,0x9947,0x9948,0x994d,0x994e,0x9954,0x9958,
+    0x9959,0x995b,0x995c,0x995e,0x995f,0x9960,0x999b,0x999d,0x999f,0x99a6,
+    0x99b0,0x99b1,0x99b2,0x99b5
+  },
+  {				/* ku 49 */
+    0x99b9,0x99ba,0x99bd,0x99bf,0x99c3,0x99c9,0x99d3,0x99d4,0x99d9,0x99da,
+    0x99dc,0x99de,0x99e7,0x99ea,0x99eb,0x99ec,0x99f0,0x99f4,0x99f5,0x99f9,
+    0x99fd,0x99fe,0x9a02,0x9a03,0x9a04,0x9a0b,0x9a0c,0x9a10,0x9a11,0x9a16,
+    0x9a1e,0x9a20,0x9a22,0x9a23,0x9a24,0x9a27,0x9a2d,0x9a2e,0x9a33,0x9a35,
+    0x9a36,0x9a38,0x9a47,0x9a41,0x9a44,0x9a4a,0x9a4b,0x9a4c,0x9a4e,0x9a51,
+    0x9a54,0x9a56,0x9a5d,0x9aaa,0x9aac,0x9aae,0x9aaf,0x9ab2,0x9ab4,0x9ab5,
+    0x9ab6,0x9ab9,0x9abb,0x9abe,0x9abf,0x9ac1,0x9ac3,0x9ac6,0x9ac8,0x9ace,
+    0x9ad0,0x9ad2,0x9ad5,0x9ad6,0x9ad7,0x9adb,0x9adc,0x9ae0,0x9ae4,0x9ae5,
+    0x9ae7,0x9ae9,0x9aec,0x9af2,0x9af3,0x9af5,0x9af9,0x9afa,0x9afd,0x9aff,
+    0x9b00,0x9b01,0x9b02,0x9b03
+  },
+  {				/* ku 4a */
+    0x9b04,0x9b05,0x9b08,0x9b09,0x9b0b,0x9b0c,0x9b0d,0x9b0e,0x9b10,0x9b12,
+    0x9b16,0x9b19,0x9b1b,0x9b1c,0x9b20,0x9b26,0x9b2b,0x9b2d,0x9b33,0x9b34,
+    0x9b35,0x9b37,0x9b39,0x9b3a,0x9b3d,0x9b48,0x9b4b,0x9b4c,0x9b55,0x9b56,
+    0x9b57,0x9b5b,0x9b5e,0x9b61,0x9b63,0x9b65,0x9b66,0x9b68,0x9b6a,0x9b6b,
+    0x9b6c,0x9b6d,0x9b6e,0x9b73,0x9b75,0x9b77,0x9b78,0x9b79,0x9b7f,0x9b80,
+    0x9b84,0x9b85,0x9b86,0x9b87,0x9b89,0x9b8a,0x9b8b,0x9b8d,0x9b8f,0x9b90,
+    0x9b94,0x9b9a,0x9b9d,0x9b9e,0x9ba6,0x9ba7,0x9ba9,0x9bac,0x9bb0,0x9bb1,
+    0x9bb2,0x9bb7,0x9bb8,0x9bbb,0x9bbc,0x9bbe,0x9bbf,0x9bc1,0x9bc7,0x9bc8,
+    0x9bce,0x9bd0,0x9bd7,0x9bd8,0x9bdd,0x9bdf,0x9be5,0x9be7,0x9bea,0x9beb,
+    0x9bef,0x9bf3,0x9bf7,0x9bf8
+  },
+  {				/* ku 4b */
+    0x9bf9,0x9bfa,0x9bfd,0x9bff,0x9c00,0x9c02,0x9c0b,0x9c0f,0x9c11,0x9c16,
+    0x9c18,0x9c19,0x9c1a,0x9c1c,0x9c1e,0x9c22,0x9c23,0x9c26,0x9c27,0x9c28,
+    0x9c29,0x9c2a,0x9c31,0x9c35,0x9c36,0x9c37,0x9c3d,0x9c41,0x9c43,0x9c44,
+    0x9c45,0x9c49,0x9c4a,0x9c4e,0x9c4f,0x9c50,0x9c53,0x9c54,0x9c56,0x9c58,
+    0x9c5b,0x9c5d,0x9c5e,0x9c5f,0x9c63,0x9c69,0x9c6a,0x9c5c,0x9c6b,0x9c68,
+    0x9c6e,0x9c70,0x9c72,0x9c75,0x9c77,0x9c7b,0x9ce6,0x9cf2,0x9cf7,0x9cf9,
+    0x9d0b,0x9d02,0x9d11,0x9d17,0x9d18,0x9d1c,0x9d1d,0x9d1e,0x9d2f,0x9d30,
+    0x9d32,0x9d33,0x9d34,0x9d3a,0x9d3c,0x9d45,0x9d3d,0x9d42,0x9d43,0x9d47,
+    0x9d4a,0x9d53,0x9d54,0x9d5f,0x9d63,0x9d62,0x9d65,0x9d69,0x9d6a,0x9d6b,
+    0x9d70,0x9d76,0x9d77,0x9d7b
+  },
+  {				/* ku 4c */
+    0x9d7c,0x9d7e,0x9d83,0x9d84,0x9d86,0x9d8a,0x9d8d,0x9d8e,0x9d92,0x9d93,
+    0x9d95,0x9d96,0x9d97,0x9d98,0x9da1,0x9daa,0x9dac,0x9dae,0x9db1,0x9db5,
+    0x9db9,0x9dbc,0x9dbf,0x9dc3,0x9dc7,0x9dc9,0x9dca,0x9dd4,0x9dd5,0x9dd6,
+    0x9dd7,0x9dda,0x9dde,0x9ddf,0x9de0,0x9de5,0x9de7,0x9de9,0x9deb,0x9dee,
+    0x9df0,0x9df3,0x9df4,0x9dfe,0x9e0a,0x9e02,0x9e07,0x9e0e,0x9e10,0x9e11,
+    0x9e12,0x9e15,0x9e16,0x9e19,0x9e1c,0x9e1d,0x9e7a,0x9e7b,0x9e7c,0x9e80,
+    0x9e82,0x9e83,0x9e84,0x9e85,0x9e87,0x9e8e,0x9e8f,0x9e96,0x9e98,0x9e9b,
+    0x9e9e,0x9ea4,0x9ea8,0x9eac,0x9eae,0x9eaf,0x9eb0,0x9eb3,0x9eb4,0x9eb5,
+    0x9ec6,0x9ec8,0x9ecb,0x9ed5,0x9edf,0x9ee4,0x9ee7,0x9eec,0x9eed,0x9eee,
+    0x9ef0,0x9ef1,0x9ef2,0x9ef5
+  },
+  {				/* ku 4d */
+    0x9ef8,0x9eff,0x9f02,0x9f03,0x9f09,0x9f0f,0x9f10,0x9f11,0x9f12,0x9f14,
+    0x9f16,0x9f17,0x9f19,0x9f1a,0x9f1b,0x9f1f,0x9f22,0x9f26,0x9f2a,0x9f2b,
+    0x9f2f,0x9f31,0x9f32,0x9f34,0x9f37,0x9f39,0x9f3a,0x9f3c,0x9f3d,0x9f3f,
+    0x9f41,0x9f43,0x9f44,0x9f45,0x9f46,0x9f47,0x9f53,0x9f55,0x9f56,0x9f57,
+    0x9f58,0x9f5a,0x9f5d,0x9f5e,0x9f68,0x9f69,0x9f6d,0x9f6e,0x9f6f,0x9f70,
+    0x9f71,0x9f73,0x9f75,0x9f7a,0x9f7d,0x9f8f,0x9f90,0x9f91,0x9f92,0x9f94,
+    0x9f96,0x9f97,0x9f9e,0x9fa1,0x9fa2,0x9fa3,0x9fa5,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON
+  }
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/charset/koi8_r.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,48 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	KOI8-R conversion table
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	3 July 1997
+ * Last Edited:	30 August 2006
+ */
+
+/* KOI8-R is a de-facto standard of Russia */
+
+static const unsigned short koi8rtab[128] = {
+  0x2500,0x2502,0x250c,0x2510,0x2514,0x2518,0x251c,0x2524,
+  0x252c,0x2534,0x253c,0x2580,0x2584,0x2588,0x258c,0x2590,
+  0x2591,0x2592,0x2593,0x2320,0x25a0,0x2219,0x221a,0x2248,
+  0x2264,0x2265,0x00a0,0x2321,0x00b0,0x00b2,0x00b7,0x00f7,
+  0x2550,0x2551,0x2552,0x0451,0x2553,0x2554,0x2555,0x2556,
+  0x2557,0x2558,0x2559,0x255a,0x255b,0x255c,0x255d,0x255e,
+  0x255f,0x2560,0x2561,0x0401,0x2562,0x2563,0x2564,0x2565,
+  0x2566,0x2567,0x2568,0x2569,0x256a,0x256b,0x256c,0x00a9,
+  0x044e,0x0430,0x0431,0x0446,0x0434,0x0435,0x0444,0x0433,
+  0x0445,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,
+  0x043f,0x044f,0x0440,0x0441,0x0442,0x0443,0x0436,0x0432,
+  0x044c,0x044b,0x0437,0x0448,0x044d,0x0449,0x0447,0x044a,
+  0x042e,0x0410,0x0411,0x0426,0x0414,0x0415,0x0424,0x0413,
+  0x0425,0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,
+  0x041f,0x042f,0x0420,0x0421,0x0422,0x0423,0x0416,0x0412,
+  0x042c,0x042b,0x0417,0x0428,0x042d,0x0429,0x0427,0x042a
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/charset/koi8_u.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,48 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	KOI8-U conversion table
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	25 August 1997
+ * Last Edited:	30 August 2006
+ */
+
+/* KOI8-U is a de-facto standard of Ukraine */
+
+static const unsigned short koi8utab[128] = {
+  0x2500,0x2502,0x250c,0x2510,0x2514,0x2518,0x251c,0x2524,
+  0x252c,0x2534,0x253c,0x2580,0x2584,0x2588,0x258c,0x2590,
+  0x2591,0x2592,0x2593,0x2320,0x25a0,0x2219,0x221a,0x2248,
+  0x2264,0x2265,0x00a0,0x2321,0x00b0,0x00b2,0x00b7,0x00f7,
+  0x2550,0x2551,0x2552,0x0451,0x0454,0x2554,0x0456,0x0457,
+  0x2557,0x2558,0x2559,0x255a,0x255b,0x0491,0x255d,0x255e,
+  0x255f,0x2560,0x2561,0x0401,0x0403,0x2563,0x0406,0x0407,
+  0x2566,0x2567,0x2568,0x2569,0x256a,0x0490,0x256c,0x00a9,
+  0x044e,0x0430,0x0431,0x0446,0x0434,0x0435,0x0444,0x0433,
+  0x0445,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,
+  0x043f,0x044f,0x0440,0x0441,0x0442,0x0443,0x0436,0x0432,
+  0x044c,0x044b,0x0437,0x0448,0x044d,0x0449,0x0447,0x044a,
+  0x042e,0x0410,0x0411,0x0426,0x0414,0x0415,0x0424,0x0413,
+  0x0425,0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,
+  0x041f,0x042f,0x0420,0x0421,0x0422,0x0423,0x0416,0x0412,
+  0x042c,0x042b,0x0417,0x0428,0x042d,0x0429,0x0427,0x042a
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/charset/ksc_5601.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,2673 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	KSC 5601 conversion table
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	3 July 1997
+ * Last Edited:	30 August 2006
+ */
+
+/* KSC 5601 is the national standard of the Republic of Korea (South Korea).
+ * It is believed that it is also the de-facto standard of the Democratic
+ * People's Republic of Korea (North Korea), although North Korea has its
+ * own official national standard (KPS 9566-97).
+ */
+
+#define BASE_KSC5601_KU 0x81
+#define BASE_KSC5601_TEN 0x41
+#define MAX_KSC5601_KU 125
+#define MAX_KSC5601_TEN 190
+
+
+#define KSCTOUNICODE(c,c1,ku,ten)				\
+  ((((ku = c - BASE_KSC5601_KU) < MAX_KSC5601_KU) &&		\
+    ((ten = c1 - BASE_KSC5601_TEN) < MAX_KSC5601_TEN)) ?	\
+   ksc5601tab[ku][ten] : UBOGON)
+
+
+static const unsigned short ksc5601tab[MAX_KSC5601_KU][MAX_KSC5601_TEN] = {
+  {				/* ku 01 */
+    0xac02,0xac03,0xac05,0xac06,0xac0b,0xac0c,0xac0d,0xac0e,0xac0f,0xac18,
+    0xac1e,0xac1f,0xac21,0xac22,0xac23,0xac25,0xac26,0xac27,0xac28,0xac29,
+    0xac2a,0xac2b,0xac2e,0xac32,0xac33,0xac34,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xac35,0xac36,0xac37,0xac3a,0xac3b,0xac3d,0xac3e,0xac3f,
+    0xac41,0xac42,0xac43,0xac44,0xac45,0xac46,0xac47,0xac48,0xac49,0xac4a,
+    0xac4c,0xac4e,0xac4f,0xac50,0xac51,0xac52,0xac53,0xac55,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xac56,0xac57,0xac59,0xac5a,0xac5b,0xac5d,
+    0xac5e,0xac5f,0xac60,0xac61,0xac62,0xac63,0xac64,0xac65,0xac66,0xac67,
+    0xac68,0xac69,0xac6a,0xac6b,0xac6c,0xac6d,0xac6e,0xac6f,0xac72,0xac73,
+    0xac75,0xac76,0xac79,0xac7b,0xac7c,0xac7d,0xac7e,0xac7f,0xac82,0xac87,
+    0xac88,0xac8d,0xac8e,0xac8f,0xac91,0xac92,0xac93,0xac95,0xac96,0xac97,
+    0xac98,0xac99,0xac9a,0xac9b,0xac9e,0xaca2,0xaca3,0xaca4,0xaca5,0xaca6,
+    0xaca7,0xacab,0xacad,0xacae,0xacb1,0xacb2,0xacb3,0xacb4,0xacb5,0xacb6,
+    0xacb7,0xacba,0xacbe,0xacbf,0xacc0,0xacc2,0xacc3,0xacc5,0xacc6,0xacc7,
+    0xacc9,0xacca,0xaccb,0xaccd,0xacce,0xaccf,0xacd0,0xacd1,0xacd2,0xacd3,
+    0xacd4,0xacd6,0xacd8,0xacd9,0xacda,0xacdb,0xacdc,0xacdd,0xacde,0xacdf,
+    0xace2,0xace3,0xace5,0xace6,0xace9,0xaceb,0xaced,0xacee,0xacf2,0xacf4,
+    0xacf7,0xacf8,0xacf9,0xacfa,0xacfb,0xacfe,0xacff,0xad01,0xad02,0xad03,
+    0xad05,0xad07,0xad08,0xad09,0xad0a,0xad0b,0xad0e,0xad10,0xad12,0xad13
+  },
+  {				/* ku 02 */
+    0xad14,0xad15,0xad16,0xad17,0xad19,0xad1a,0xad1b,0xad1d,0xad1e,0xad1f,
+    0xad21,0xad22,0xad23,0xad24,0xad25,0xad26,0xad27,0xad28,0xad2a,0xad2b,
+    0xad2e,0xad2f,0xad30,0xad31,0xad32,0xad33,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xad36,0xad37,0xad39,0xad3a,0xad3b,0xad3d,0xad3e,0xad3f,
+    0xad40,0xad41,0xad42,0xad43,0xad46,0xad48,0xad4a,0xad4b,0xad4c,0xad4d,
+    0xad4e,0xad4f,0xad51,0xad52,0xad53,0xad55,0xad56,0xad57,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xad59,0xad5a,0xad5b,0xad5c,0xad5d,0xad5e,
+    0xad5f,0xad60,0xad62,0xad64,0xad65,0xad66,0xad67,0xad68,0xad69,0xad6a,
+    0xad6b,0xad6e,0xad6f,0xad71,0xad72,0xad77,0xad78,0xad79,0xad7a,0xad7e,
+    0xad80,0xad83,0xad84,0xad85,0xad86,0xad87,0xad8a,0xad8b,0xad8d,0xad8e,
+    0xad8f,0xad91,0xad92,0xad93,0xad94,0xad95,0xad96,0xad97,0xad98,0xad99,
+    0xad9a,0xad9b,0xad9e,0xad9f,0xada0,0xada1,0xada2,0xada3,0xada5,0xada6,
+    0xada7,0xada8,0xada9,0xadaa,0xadab,0xadac,0xadad,0xadae,0xadaf,0xadb0,
+    0xadb1,0xadb2,0xadb3,0xadb4,0xadb5,0xadb6,0xadb8,0xadb9,0xadba,0xadbb,
+    0xadbc,0xadbd,0xadbe,0xadbf,0xadc2,0xadc3,0xadc5,0xadc6,0xadc7,0xadc9,
+    0xadca,0xadcb,0xadcc,0xadcd,0xadce,0xadcf,0xadd2,0xadd4,0xadd5,0xadd6,
+    0xadd7,0xadd8,0xadd9,0xadda,0xaddb,0xaddd,0xadde,0xaddf,0xade1,0xade2,
+    0xade3,0xade5,0xade6,0xade7,0xade8,0xade9,0xadea,0xadeb,0xadec,0xaded,
+    0xadee,0xadef,0xadf0,0xadf1,0xadf2,0xadf3,0xadf4,0xadf5,0xadf6,0xadf7
+  },
+  {				/* ku 03 */
+    0xadfa,0xadfb,0xadfd,0xadfe,0xae02,0xae03,0xae04,0xae05,0xae06,0xae07,
+    0xae0a,0xae0c,0xae0e,0xae0f,0xae10,0xae11,0xae12,0xae13,0xae15,0xae16,
+    0xae17,0xae18,0xae19,0xae1a,0xae1b,0xae1c,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xae1d,0xae1e,0xae1f,0xae20,0xae21,0xae22,0xae23,0xae24,
+    0xae25,0xae26,0xae27,0xae28,0xae29,0xae2a,0xae2b,0xae2c,0xae2d,0xae2e,
+    0xae2f,0xae32,0xae33,0xae35,0xae36,0xae39,0xae3b,0xae3c,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xae3d,0xae3e,0xae3f,0xae42,0xae44,0xae47,
+    0xae48,0xae49,0xae4b,0xae4f,0xae51,0xae52,0xae53,0xae55,0xae57,0xae58,
+    0xae59,0xae5a,0xae5b,0xae5e,0xae62,0xae63,0xae64,0xae66,0xae67,0xae6a,
+    0xae6b,0xae6d,0xae6e,0xae6f,0xae71,0xae72,0xae73,0xae74,0xae75,0xae76,
+    0xae77,0xae7a,0xae7e,0xae7f,0xae80,0xae81,0xae82,0xae83,0xae86,0xae87,
+    0xae88,0xae89,0xae8a,0xae8b,0xae8d,0xae8e,0xae8f,0xae90,0xae91,0xae92,
+    0xae93,0xae94,0xae95,0xae96,0xae97,0xae98,0xae99,0xae9a,0xae9b,0xae9c,
+    0xae9d,0xae9e,0xae9f,0xaea0,0xaea1,0xaea2,0xaea3,0xaea4,0xaea5,0xaea6,
+    0xaea7,0xaea8,0xaea9,0xaeaa,0xaeab,0xaeac,0xaead,0xaeae,0xaeaf,0xaeb0,
+    0xaeb1,0xaeb2,0xaeb3,0xaeb4,0xaeb5,0xaeb6,0xaeb7,0xaeb8,0xaeb9,0xaeba,
+    0xaebb,0xaebf,0xaec1,0xaec2,0xaec3,0xaec5,0xaec6,0xaec7,0xaec8,0xaec9,
+    0xaeca,0xaecb,0xaece,0xaed2,0xaed3,0xaed4,0xaed5,0xaed6,0xaed7,0xaeda,
+    0xaedb,0xaedd,0xaede,0xaedf,0xaee0,0xaee1,0xaee2,0xaee3,0xaee4,0xaee5
+  },
+  {				/* ku 04 */
+    0xaee6,0xaee7,0xaee9,0xaeea,0xaeec,0xaeee,0xaeef,0xaef0,0xaef1,0xaef2,
+    0xaef3,0xaef5,0xaef6,0xaef7,0xaef9,0xaefa,0xaefb,0xaefd,0xaefe,0xaeff,
+    0xaf00,0xaf01,0xaf02,0xaf03,0xaf04,0xaf05,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xaf06,0xaf09,0xaf0a,0xaf0b,0xaf0c,0xaf0e,0xaf0f,0xaf11,
+    0xaf12,0xaf13,0xaf14,0xaf15,0xaf16,0xaf17,0xaf18,0xaf19,0xaf1a,0xaf1b,
+    0xaf1c,0xaf1d,0xaf1e,0xaf1f,0xaf20,0xaf21,0xaf22,0xaf23,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xaf24,0xaf25,0xaf26,0xaf27,0xaf28,0xaf29,
+    0xaf2a,0xaf2b,0xaf2e,0xaf2f,0xaf31,0xaf33,0xaf35,0xaf36,0xaf37,0xaf38,
+    0xaf39,0xaf3a,0xaf3b,0xaf3e,0xaf40,0xaf44,0xaf45,0xaf46,0xaf47,0xaf4a,
+    0xaf4b,0xaf4c,0xaf4d,0xaf4e,0xaf4f,0xaf51,0xaf52,0xaf53,0xaf54,0xaf55,
+    0xaf56,0xaf57,0xaf58,0xaf59,0xaf5a,0xaf5b,0xaf5e,0xaf5f,0xaf60,0xaf61,
+    0xaf62,0xaf63,0xaf66,0xaf67,0xaf68,0xaf69,0xaf6a,0xaf6b,0xaf6c,0xaf6d,
+    0xaf6e,0xaf6f,0xaf70,0xaf71,0xaf72,0xaf73,0xaf74,0xaf75,0xaf76,0xaf77,
+    0xaf78,0xaf7a,0xaf7b,0xaf7c,0xaf7d,0xaf7e,0xaf7f,0xaf81,0xaf82,0xaf83,
+    0xaf85,0xaf86,0xaf87,0xaf89,0xaf8a,0xaf8b,0xaf8c,0xaf8d,0xaf8e,0xaf8f,
+    0xaf92,0xaf93,0xaf94,0xaf96,0xaf97,0xaf98,0xaf99,0xaf9a,0xaf9b,0xaf9d,
+    0xaf9e,0xaf9f,0xafa0,0xafa1,0xafa2,0xafa3,0xafa4,0xafa5,0xafa6,0xafa7,
+    0xafa8,0xafa9,0xafaa,0xafab,0xafac,0xafad,0xafae,0xafaf,0xafb0,0xafb1,
+    0xafb2,0xafb3,0xafb4,0xafb5,0xafb6,0xafb7,0xafba,0xafbb,0xafbd,0xafbe
+  },
+  {				/* ku 05 */
+    0xafbf,0xafc1,0xafc2,0xafc3,0xafc4,0xafc5,0xafc6,0xafca,0xafcc,0xafcf,
+    0xafd0,0xafd1,0xafd2,0xafd3,0xafd5,0xafd6,0xafd7,0xafd8,0xafd9,0xafda,
+    0xafdb,0xafdd,0xafde,0xafdf,0xafe0,0xafe1,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xafe2,0xafe3,0xafe4,0xafe5,0xafe6,0xafe7,0xafea,0xafeb,
+    0xafec,0xafed,0xafee,0xafef,0xaff2,0xaff3,0xaff5,0xaff6,0xaff7,0xaff9,
+    0xaffa,0xaffb,0xaffc,0xaffd,0xaffe,0xafff,0xb002,0xb003,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xb005,0xb006,0xb007,0xb008,0xb009,0xb00a,
+    0xb00b,0xb00d,0xb00e,0xb00f,0xb011,0xb012,0xb013,0xb015,0xb016,0xb017,
+    0xb018,0xb019,0xb01a,0xb01b,0xb01e,0xb01f,0xb020,0xb021,0xb022,0xb023,
+    0xb024,0xb025,0xb026,0xb027,0xb029,0xb02a,0xb02b,0xb02c,0xb02d,0xb02e,
+    0xb02f,0xb030,0xb031,0xb032,0xb033,0xb034,0xb035,0xb036,0xb037,0xb038,
+    0xb039,0xb03a,0xb03b,0xb03c,0xb03d,0xb03e,0xb03f,0xb040,0xb041,0xb042,
+    0xb043,0xb046,0xb047,0xb049,0xb04b,0xb04d,0xb04f,0xb050,0xb051,0xb052,
+    0xb056,0xb058,0xb05a,0xb05b,0xb05c,0xb05e,0xb05f,0xb060,0xb061,0xb062,
+    0xb063,0xb064,0xb065,0xb066,0xb067,0xb068,0xb069,0xb06a,0xb06b,0xb06c,
+    0xb06d,0xb06e,0xb06f,0xb070,0xb071,0xb072,0xb073,0xb074,0xb075,0xb076,
+    0xb077,0xb078,0xb079,0xb07a,0xb07b,0xb07e,0xb07f,0xb081,0xb082,0xb083,
+    0xb085,0xb086,0xb087,0xb088,0xb089,0xb08a,0xb08b,0xb08e,0xb090,0xb092,
+    0xb093,0xb094,0xb095,0xb096,0xb097,0xb09b,0xb09d,0xb09e,0xb0a3,0xb0a4
+  },
+  {				/* ku 06 */
+    0xb0a5,0xb0a6,0xb0a7,0xb0aa,0xb0b0,0xb0b2,0xb0b6,0xb0b7,0xb0b9,0xb0ba,
+    0xb0bb,0xb0bd,0xb0be,0xb0bf,0xb0c0,0xb0c1,0xb0c2,0xb0c3,0xb0c6,0xb0ca,
+    0xb0cb,0xb0cc,0xb0cd,0xb0ce,0xb0cf,0xb0d2,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xb0d3,0xb0d5,0xb0d6,0xb0d7,0xb0d9,0xb0da,0xb0db,0xb0dc,
+    0xb0dd,0xb0de,0xb0df,0xb0e1,0xb0e2,0xb0e3,0xb0e4,0xb0e6,0xb0e7,0xb0e8,
+    0xb0e9,0xb0ea,0xb0eb,0xb0ec,0xb0ed,0xb0ee,0xb0ef,0xb0f0,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xb0f1,0xb0f2,0xb0f3,0xb0f4,0xb0f5,0xb0f6,
+    0xb0f7,0xb0f8,0xb0f9,0xb0fa,0xb0fb,0xb0fc,0xb0fd,0xb0fe,0xb0ff,0xb100,
+    0xb101,0xb102,0xb103,0xb104,0xb105,0xb106,0xb107,0xb10a,0xb10d,0xb10e,
+    0xb10f,0xb111,0xb114,0xb115,0xb116,0xb117,0xb11a,0xb11e,0xb11f,0xb120,
+    0xb121,0xb122,0xb126,0xb127,0xb129,0xb12a,0xb12b,0xb12d,0xb12e,0xb12f,
+    0xb130,0xb131,0xb132,0xb133,0xb136,0xb13a,0xb13b,0xb13c,0xb13d,0xb13e,
+    0xb13f,0xb142,0xb143,0xb145,0xb146,0xb147,0xb149,0xb14a,0xb14b,0xb14c,
+    0xb14d,0xb14e,0xb14f,0xb152,0xb153,0xb156,0xb157,0xb159,0xb15a,0xb15b,
+    0xb15d,0xb15e,0xb15f,0xb161,0xb162,0xb163,0xb164,0xb165,0xb166,0xb167,
+    0xb168,0xb169,0xb16a,0xb16b,0xb16c,0xb16d,0xb16e,0xb16f,0xb170,0xb171,
+    0xb172,0xb173,0xb174,0xb175,0xb176,0xb177,0xb17a,0xb17b,0xb17d,0xb17e,
+    0xb17f,0xb181,0xb183,0xb184,0xb185,0xb186,0xb187,0xb18a,0xb18c,0xb18e,
+    0xb18f,0xb190,0xb191,0xb195,0xb196,0xb197,0xb199,0xb19a,0xb19b,0xb19d
+  },
+  {				/* ku 07 */
+    0xb19e,0xb19f,0xb1a0,0xb1a1,0xb1a2,0xb1a3,0xb1a4,0xb1a5,0xb1a6,0xb1a7,
+    0xb1a9,0xb1aa,0xb1ab,0xb1ac,0xb1ad,0xb1ae,0xb1af,0xb1b0,0xb1b1,0xb1b2,
+    0xb1b3,0xb1b4,0xb1b5,0xb1b6,0xb1b7,0xb1b8,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xb1b9,0xb1ba,0xb1bb,0xb1bc,0xb1bd,0xb1be,0xb1bf,0xb1c0,
+    0xb1c1,0xb1c2,0xb1c3,0xb1c4,0xb1c5,0xb1c6,0xb1c7,0xb1c8,0xb1c9,0xb1ca,
+    0xb1cb,0xb1cd,0xb1ce,0xb1cf,0xb1d1,0xb1d2,0xb1d3,0xb1d5,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xb1d6,0xb1d7,0xb1d8,0xb1d9,0xb1da,0xb1db,
+    0xb1de,0xb1e0,0xb1e1,0xb1e2,0xb1e3,0xb1e4,0xb1e5,0xb1e6,0xb1e7,0xb1ea,
+    0xb1eb,0xb1ed,0xb1ee,0xb1ef,0xb1f1,0xb1f2,0xb1f3,0xb1f4,0xb1f5,0xb1f6,
+    0xb1f7,0xb1f8,0xb1fa,0xb1fc,0xb1fe,0xb1ff,0xb200,0xb201,0xb202,0xb203,
+    0xb206,0xb207,0xb209,0xb20a,0xb20d,0xb20e,0xb20f,0xb210,0xb211,0xb212,
+    0xb213,0xb216,0xb218,0xb21a,0xb21b,0xb21c,0xb21d,0xb21e,0xb21f,0xb221,
+    0xb222,0xb223,0xb224,0xb225,0xb226,0xb227,0xb228,0xb229,0xb22a,0xb22b,
+    0xb22c,0xb22d,0xb22e,0xb22f,0xb230,0xb231,0xb232,0xb233,0xb235,0xb236,
+    0xb237,0xb238,0xb239,0xb23a,0xb23b,0xb23d,0xb23e,0xb23f,0xb240,0xb241,
+    0xb242,0xb243,0xb244,0xb245,0xb246,0xb247,0xb248,0xb249,0xb24a,0xb24b,
+    0xb24c,0xb24d,0xb24e,0xb24f,0xb250,0xb251,0xb252,0xb253,0xb254,0xb255,
+    0xb256,0xb257,0xb259,0xb25a,0xb25b,0xb25d,0xb25e,0xb25f,0xb261,0xb262,
+    0xb263,0xb264,0xb265,0xb266,0xb267,0xb26a,0xb26b,0xb26c,0xb26d,0xb26e
+  },
+  {				/* ku 08 */
+    0xb26f,0xb270,0xb271,0xb272,0xb273,0xb276,0xb277,0xb278,0xb279,0xb27a,
+    0xb27b,0xb27d,0xb27e,0xb27f,0xb280,0xb281,0xb282,0xb283,0xb286,0xb287,
+    0xb288,0xb28a,0xb28b,0xb28c,0xb28d,0xb28e,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xb28f,0xb292,0xb293,0xb295,0xb296,0xb297,0xb29b,0xb29c,
+    0xb29d,0xb29e,0xb29f,0xb2a2,0xb2a4,0xb2a7,0xb2a8,0xb2a9,0xb2ab,0xb2ad,
+    0xb2ae,0xb2af,0xb2b1,0xb2b2,0xb2b3,0xb2b5,0xb2b6,0xb2b7,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xb2b8,0xb2b9,0xb2ba,0xb2bb,0xb2bc,0xb2bd,
+    0xb2be,0xb2bf,0xb2c0,0xb2c1,0xb2c2,0xb2c3,0xb2c4,0xb2c5,0xb2c6,0xb2c7,
+    0xb2ca,0xb2cb,0xb2cd,0xb2ce,0xb2cf,0xb2d1,0xb2d3,0xb2d4,0xb2d5,0xb2d6,
+    0xb2d7,0xb2da,0xb2dc,0xb2de,0xb2df,0xb2e0,0xb2e1,0xb2e3,0xb2e7,0xb2e9,
+    0xb2ea,0xb2f0,0xb2f1,0xb2f2,0xb2f6,0xb2fc,0xb2fd,0xb2fe,0xb302,0xb303,
+    0xb305,0xb306,0xb307,0xb309,0xb30a,0xb30b,0xb30c,0xb30d,0xb30e,0xb30f,
+    0xb312,0xb316,0xb317,0xb318,0xb319,0xb31a,0xb31b,0xb31d,0xb31e,0xb31f,
+    0xb320,0xb321,0xb322,0xb323,0xb324,0xb325,0xb326,0xb327,0xb328,0xb329,
+    0xb32a,0xb32b,0xb32c,0xb32d,0xb32e,0xb32f,0xb330,0xb331,0xb332,0xb333,
+    0xb334,0xb335,0xb336,0xb337,0xb338,0xb339,0xb33a,0xb33b,0xb33c,0xb33d,
+    0xb33e,0xb33f,0xb340,0xb341,0xb342,0xb343,0xb344,0xb345,0xb346,0xb347,
+    0xb348,0xb349,0xb34a,0xb34b,0xb34c,0xb34d,0xb34e,0xb34f,0xb350,0xb351,
+    0xb352,0xb353,0xb357,0xb359,0xb35a,0xb35d,0xb360,0xb361,0xb362,0xb363
+  },
+  {				/* ku 09 */
+    0xb366,0xb368,0xb36a,0xb36c,0xb36d,0xb36f,0xb372,0xb373,0xb375,0xb376,
+    0xb377,0xb379,0xb37a,0xb37b,0xb37c,0xb37d,0xb37e,0xb37f,0xb382,0xb386,
+    0xb387,0xb388,0xb389,0xb38a,0xb38b,0xb38d,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xb38e,0xb38f,0xb391,0xb392,0xb393,0xb395,0xb396,0xb397,
+    0xb398,0xb399,0xb39a,0xb39b,0xb39c,0xb39d,0xb39e,0xb39f,0xb3a2,0xb3a3,
+    0xb3a4,0xb3a5,0xb3a6,0xb3a7,0xb3a9,0xb3aa,0xb3ab,0xb3ad,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xb3ae,0xb3af,0xb3b0,0xb3b1,0xb3b2,0xb3b3,
+    0xb3b4,0xb3b5,0xb3b6,0xb3b7,0xb3b8,0xb3b9,0xb3ba,0xb3bb,0xb3bc,0xb3bd,
+    0xb3be,0xb3bf,0xb3c0,0xb3c1,0xb3c2,0xb3c3,0xb3c6,0xb3c7,0xb3c9,0xb3ca,
+    0xb3cd,0xb3cf,0xb3d1,0xb3d2,0xb3d3,0xb3d6,0xb3d8,0xb3da,0xb3dc,0xb3de,
+    0xb3df,0xb3e1,0xb3e2,0xb3e3,0xb3e5,0xb3e6,0xb3e7,0xb3e9,0xb3ea,0xb3eb,
+    0xb3ec,0xb3ed,0xb3ee,0xb3ef,0xb3f0,0xb3f1,0xb3f2,0xb3f3,0xb3f4,0xb3f5,
+    0xb3f6,0xb3f7,0xb3f8,0xb3f9,0xb3fa,0xb3fb,0xb3fd,0xb3fe,0xb3ff,0xb400,
+    0xb401,0xb402,0xb403,0xb404,0xb405,0xb406,0xb407,0xb408,0xb409,0xb40a,
+    0xb40b,0xb40c,0xb40d,0xb40e,0xb40f,0xb411,0xb412,0xb413,0xb414,0xb415,
+    0xb416,0xb417,0xb419,0xb41a,0xb41b,0xb41d,0xb41e,0xb41f,0xb421,0xb422,
+    0xb423,0xb424,0xb425,0xb426,0xb427,0xb42a,0xb42c,0xb42d,0xb42e,0xb42f,
+    0xb430,0xb431,0xb432,0xb433,0xb435,0xb436,0xb437,0xb438,0xb439,0xb43a,
+    0xb43b,0xb43c,0xb43d,0xb43e,0xb43f,0xb440,0xb441,0xb442,0xb443,0xb444
+  },
+  {				/* ku 0a */
+    0xb445,0xb446,0xb447,0xb448,0xb449,0xb44a,0xb44b,0xb44c,0xb44d,0xb44e,
+    0xb44f,0xb452,0xb453,0xb455,0xb456,0xb457,0xb459,0xb45a,0xb45b,0xb45c,
+    0xb45d,0xb45e,0xb45f,0xb462,0xb464,0xb466,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xb467,0xb468,0xb469,0xb46a,0xb46b,0xb46d,0xb46e,0xb46f,
+    0xb470,0xb471,0xb472,0xb473,0xb474,0xb475,0xb476,0xb477,0xb478,0xb479,
+    0xb47a,0xb47b,0xb47c,0xb47d,0xb47e,0xb47f,0xb481,0xb482,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xb483,0xb484,0xb485,0xb486,0xb487,0xb489,
+    0xb48a,0xb48b,0xb48c,0xb48d,0xb48e,0xb48f,0xb490,0xb491,0xb492,0xb493,
+    0xb494,0xb495,0xb496,0xb497,0xb498,0xb499,0xb49a,0xb49b,0xb49c,0xb49e,
+    0xb49f,0xb4a0,0xb4a1,0xb4a2,0xb4a3,0xb4a5,0xb4a6,0xb4a7,0xb4a9,0xb4aa,
+    0xb4ab,0xb4ad,0xb4ae,0xb4af,0xb4b0,0xb4b1,0xb4b2,0xb4b3,0xb4b4,0xb4b6,
+    0xb4b8,0xb4ba,0xb4bb,0xb4bc,0xb4bd,0xb4be,0xb4bf,0xb4c1,0xb4c2,0xb4c3,
+    0xb4c5,0xb4c6,0xb4c7,0xb4c9,0xb4ca,0xb4cb,0xb4cc,0xb4cd,0xb4ce,0xb4cf,
+    0xb4d1,0xb4d2,0xb4d3,0xb4d4,0xb4d6,0xb4d7,0xb4d8,0xb4d9,0xb4da,0xb4db,
+    0xb4de,0xb4df,0xb4e1,0xb4e2,0xb4e5,0xb4e7,0xb4e8,0xb4e9,0xb4ea,0xb4eb,
+    0xb4ee,0xb4f0,0xb4f2,0xb4f3,0xb4f4,0xb4f5,0xb4f6,0xb4f7,0xb4f9,0xb4fa,
+    0xb4fb,0xb4fc,0xb4fd,0xb4fe,0xb4ff,0xb500,0xb501,0xb502,0xb503,0xb504,
+    0xb505,0xb506,0xb507,0xb508,0xb509,0xb50a,0xb50b,0xb50c,0xb50d,0xb50e,
+    0xb50f,0xb510,0xb511,0xb512,0xb513,0xb516,0xb517,0xb519,0xb51a,0xb51d
+  },
+  {				/* ku 0b */
+    0xb51e,0xb51f,0xb520,0xb521,0xb522,0xb523,0xb526,0xb52b,0xb52c,0xb52d,
+    0xb52e,0xb52f,0xb532,0xb533,0xb535,0xb536,0xb537,0xb539,0xb53a,0xb53b,
+    0xb53c,0xb53d,0xb53e,0xb53f,0xb542,0xb546,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xb547,0xb548,0xb549,0xb54a,0xb54e,0xb54f,0xb551,0xb552,
+    0xb553,0xb555,0xb556,0xb557,0xb558,0xb559,0xb55a,0xb55b,0xb55e,0xb562,
+    0xb563,0xb564,0xb565,0xb566,0xb567,0xb568,0xb569,0xb56a,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xb56b,0xb56c,0xb56d,0xb56e,0xb56f,0xb570,
+    0xb571,0xb572,0xb573,0xb574,0xb575,0xb576,0xb577,0xb578,0xb579,0xb57a,
+    0xb57b,0xb57c,0xb57d,0xb57e,0xb57f,0xb580,0xb581,0xb582,0xb583,0xb584,
+    0xb585,0xb586,0xb587,0xb588,0xb589,0xb58a,0xb58b,0xb58c,0xb58d,0xb58e,
+    0xb58f,0xb590,0xb591,0xb592,0xb593,0xb594,0xb595,0xb596,0xb597,0xb598,
+    0xb599,0xb59a,0xb59b,0xb59c,0xb59d,0xb59e,0xb59f,0xb5a2,0xb5a3,0xb5a5,
+    0xb5a6,0xb5a7,0xb5a9,0xb5ac,0xb5ad,0xb5ae,0xb5af,0xb5b2,0xb5b6,0xb5b7,
+    0xb5b8,0xb5b9,0xb5ba,0xb5be,0xb5bf,0xb5c1,0xb5c2,0xb5c3,0xb5c5,0xb5c6,
+    0xb5c7,0xb5c8,0xb5c9,0xb5ca,0xb5cb,0xb5ce,0xb5d2,0xb5d3,0xb5d4,0xb5d5,
+    0xb5d6,0xb5d7,0xb5d9,0xb5da,0xb5db,0xb5dc,0xb5dd,0xb5de,0xb5df,0xb5e0,
+    0xb5e1,0xb5e2,0xb5e3,0xb5e4,0xb5e5,0xb5e6,0xb5e7,0xb5e8,0xb5e9,0xb5ea,
+    0xb5eb,0xb5ed,0xb5ee,0xb5ef,0xb5f0,0xb5f1,0xb5f2,0xb5f3,0xb5f4,0xb5f5,
+    0xb5f6,0xb5f7,0xb5f8,0xb5f9,0xb5fa,0xb5fb,0xb5fc,0xb5fd,0xb5fe,0xb5ff
+  },
+  {				/* ku 0c */
+    0xb600,0xb601,0xb602,0xb603,0xb604,0xb605,0xb606,0xb607,0xb608,0xb609,
+    0xb60a,0xb60b,0xb60c,0xb60d,0xb60e,0xb60f,0xb612,0xb613,0xb615,0xb616,
+    0xb617,0xb619,0xb61a,0xb61b,0xb61c,0xb61d,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xb61e,0xb61f,0xb620,0xb621,0xb622,0xb623,0xb624,0xb626,
+    0xb627,0xb628,0xb629,0xb62a,0xb62b,0xb62d,0xb62e,0xb62f,0xb630,0xb631,
+    0xb632,0xb633,0xb635,0xb636,0xb637,0xb638,0xb639,0xb63a,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xb63b,0xb63c,0xb63d,0xb63e,0xb63f,0xb640,
+    0xb641,0xb642,0xb643,0xb644,0xb645,0xb646,0xb647,0xb649,0xb64a,0xb64b,
+    0xb64c,0xb64d,0xb64e,0xb64f,0xb650,0xb651,0xb652,0xb653,0xb654,0xb655,
+    0xb656,0xb657,0xb658,0xb659,0xb65a,0xb65b,0xb65c,0xb65d,0xb65e,0xb65f,
+    0xb660,0xb661,0xb662,0xb663,0xb665,0xb666,0xb667,0xb669,0xb66a,0xb66b,
+    0xb66c,0xb66d,0xb66e,0xb66f,0xb670,0xb671,0xb672,0xb673,0xb674,0xb675,
+    0xb676,0xb677,0xb678,0xb679,0xb67a,0xb67b,0xb67c,0xb67d,0xb67e,0xb67f,
+    0xb680,0xb681,0xb682,0xb683,0xb684,0xb685,0xb686,0xb687,0xb688,0xb689,
+    0xb68a,0xb68b,0xb68c,0xb68d,0xb68e,0xb68f,0xb690,0xb691,0xb692,0xb693,
+    0xb694,0xb695,0xb696,0xb697,0xb698,0xb699,0xb69a,0xb69b,0xb69e,0xb69f,
+    0xb6a1,0xb6a2,0xb6a3,0xb6a5,0xb6a6,0xb6a7,0xb6a8,0xb6a9,0xb6aa,0xb6ad,
+    0xb6ae,0xb6af,0xb6b0,0xb6b2,0xb6b3,0xb6b4,0xb6b5,0xb6b6,0xb6b7,0xb6b8,
+    0xb6b9,0xb6ba,0xb6bb,0xb6bc,0xb6bd,0xb6be,0xb6bf,0xb6c0,0xb6c1,0xb6c2
+  },
+  {				/* ku 0d */
+    0xb6c3,0xb6c4,0xb6c5,0xb6c6,0xb6c7,0xb6c8,0xb6c9,0xb6ca,0xb6cb,0xb6cc,
+    0xb6cd,0xb6ce,0xb6cf,0xb6d0,0xb6d1,0xb6d2,0xb6d3,0xb6d5,0xb6d6,0xb6d7,
+    0xb6d8,0xb6d9,0xb6da,0xb6db,0xb6dc,0xb6dd,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xb6de,0xb6df,0xb6e0,0xb6e1,0xb6e2,0xb6e3,0xb6e4,0xb6e5,
+    0xb6e6,0xb6e7,0xb6e8,0xb6e9,0xb6ea,0xb6eb,0xb6ec,0xb6ed,0xb6ee,0xb6ef,
+    0xb6f1,0xb6f2,0xb6f3,0xb6f5,0xb6f6,0xb6f7,0xb6f9,0xb6fa,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xb6fb,0xb6fc,0xb6fd,0xb6fe,0xb6ff,0xb702,
+    0xb703,0xb704,0xb706,0xb707,0xb708,0xb709,0xb70a,0xb70b,0xb70c,0xb70d,
+    0xb70e,0xb70f,0xb710,0xb711,0xb712,0xb713,0xb714,0xb715,0xb716,0xb717,
+    0xb718,0xb719,0xb71a,0xb71b,0xb71c,0xb71d,0xb71e,0xb71f,0xb720,0xb721,
+    0xb722,0xb723,0xb724,0xb725,0xb726,0xb727,0xb72a,0xb72b,0xb72d,0xb72e,
+    0xb731,0xb732,0xb733,0xb734,0xb735,0xb736,0xb737,0xb73a,0xb73c,0xb73d,
+    0xb73e,0xb73f,0xb740,0xb741,0xb742,0xb743,0xb745,0xb746,0xb747,0xb749,
+    0xb74a,0xb74b,0xb74d,0xb74e,0xb74f,0xb750,0xb751,0xb752,0xb753,0xb756,
+    0xb757,0xb758,0xb759,0xb75a,0xb75b,0xb75c,0xb75d,0xb75e,0xb75f,0xb761,
+    0xb762,0xb763,0xb765,0xb766,0xb767,0xb769,0xb76a,0xb76b,0xb76c,0xb76d,
+    0xb76e,0xb76f,0xb772,0xb774,0xb776,0xb777,0xb778,0xb779,0xb77a,0xb77b,
+    0xb77e,0xb77f,0xb781,0xb782,0xb783,0xb785,0xb786,0xb787,0xb788,0xb789,
+    0xb78a,0xb78b,0xb78e,0xb793,0xb794,0xb795,0xb79a,0xb79b,0xb79d,0xb79e
+  },
+  {				/* ku 0e */
+    0xb79f,0xb7a1,0xb7a2,0xb7a3,0xb7a4,0xb7a5,0xb7a6,0xb7a7,0xb7aa,0xb7ae,
+    0xb7af,0xb7b0,0xb7b1,0xb7b2,0xb7b3,0xb7b6,0xb7b7,0xb7b9,0xb7ba,0xb7bb,
+    0xb7bc,0xb7bd,0xb7be,0xb7bf,0xb7c0,0xb7c1,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xb7c2,0xb7c3,0xb7c4,0xb7c5,0xb7c6,0xb7c8,0xb7ca,0xb7cb,
+    0xb7cc,0xb7cd,0xb7ce,0xb7cf,0xb7d0,0xb7d1,0xb7d2,0xb7d3,0xb7d4,0xb7d5,
+    0xb7d6,0xb7d7,0xb7d8,0xb7d9,0xb7da,0xb7db,0xb7dc,0xb7dd,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xb7de,0xb7df,0xb7e0,0xb7e1,0xb7e2,0xb7e3,
+    0xb7e4,0xb7e5,0xb7e6,0xb7e7,0xb7e8,0xb7e9,0xb7ea,0xb7eb,0xb7ee,0xb7ef,
+    0xb7f1,0xb7f2,0xb7f3,0xb7f5,0xb7f6,0xb7f7,0xb7f8,0xb7f9,0xb7fa,0xb7fb,
+    0xb7fe,0xb802,0xb803,0xb804,0xb805,0xb806,0xb80a,0xb80b,0xb80d,0xb80e,
+    0xb80f,0xb811,0xb812,0xb813,0xb814,0xb815,0xb816,0xb817,0xb81a,0xb81c,
+    0xb81e,0xb81f,0xb820,0xb821,0xb822,0xb823,0xb826,0xb827,0xb829,0xb82a,
+    0xb82b,0xb82d,0xb82e,0xb82f,0xb830,0xb831,0xb832,0xb833,0xb836,0xb83a,
+    0xb83b,0xb83c,0xb83d,0xb83e,0xb83f,0xb841,0xb842,0xb843,0xb845,0xb846,
+    0xb847,0xb848,0xb849,0xb84a,0xb84b,0xb84c,0xb84d,0xb84e,0xb84f,0xb850,
+    0xb852,0xb854,0xb855,0xb856,0xb857,0xb858,0xb859,0xb85a,0xb85b,0xb85e,
+    0xb85f,0xb861,0xb862,0xb863,0xb865,0xb866,0xb867,0xb868,0xb869,0xb86a,
+    0xb86b,0xb86e,0xb870,0xb872,0xb873,0xb874,0xb875,0xb876,0xb877,0xb879,
+    0xb87a,0xb87b,0xb87d,0xb87e,0xb87f,0xb880,0xb881,0xb882,0xb883,0xb884
+  },
+  {				/* ku 0f */
+    0xb885,0xb886,0xb887,0xb888,0xb889,0xb88a,0xb88b,0xb88c,0xb88e,0xb88f,
+    0xb890,0xb891,0xb892,0xb893,0xb894,0xb895,0xb896,0xb897,0xb898,0xb899,
+    0xb89a,0xb89b,0xb89c,0xb89d,0xb89e,0xb89f,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xb8a0,0xb8a1,0xb8a2,0xb8a3,0xb8a4,0xb8a5,0xb8a6,0xb8a7,
+    0xb8a9,0xb8aa,0xb8ab,0xb8ac,0xb8ad,0xb8ae,0xb8af,0xb8b1,0xb8b2,0xb8b3,
+    0xb8b5,0xb8b6,0xb8b7,0xb8b9,0xb8ba,0xb8bb,0xb8bc,0xb8bd,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xb8be,0xb8bf,0xb8c2,0xb8c4,0xb8c6,0xb8c7,
+    0xb8c8,0xb8c9,0xb8ca,0xb8cb,0xb8cd,0xb8ce,0xb8cf,0xb8d1,0xb8d2,0xb8d3,
+    0xb8d5,0xb8d6,0xb8d7,0xb8d8,0xb8d9,0xb8da,0xb8db,0xb8dc,0xb8de,0xb8e0,
+    0xb8e2,0xb8e3,0xb8e4,0xb8e5,0xb8e6,0xb8e7,0xb8ea,0xb8eb,0xb8ed,0xb8ee,
+    0xb8ef,0xb8f1,0xb8f2,0xb8f3,0xb8f4,0xb8f5,0xb8f6,0xb8f7,0xb8fa,0xb8fc,
+    0xb8fe,0xb8ff,0xb900,0xb901,0xb902,0xb903,0xb905,0xb906,0xb907,0xb908,
+    0xb909,0xb90a,0xb90b,0xb90c,0xb90d,0xb90e,0xb90f,0xb910,0xb911,0xb912,
+    0xb913,0xb914,0xb915,0xb916,0xb917,0xb919,0xb91a,0xb91b,0xb91c,0xb91d,
+    0xb91e,0xb91f,0xb921,0xb922,0xb923,0xb924,0xb925,0xb926,0xb927,0xb928,
+    0xb929,0xb92a,0xb92b,0xb92c,0xb92d,0xb92e,0xb92f,0xb930,0xb931,0xb932,
+    0xb933,0xb934,0xb935,0xb936,0xb937,0xb938,0xb939,0xb93a,0xb93b,0xb93e,
+    0xb93f,0xb941,0xb942,0xb943,0xb945,0xb946,0xb947,0xb948,0xb949,0xb94a,
+    0xb94b,0xb94d,0xb94e,0xb950,0xb952,0xb953,0xb954,0xb955,0xb956,0xb957
+  },
+  {				/* ku 10 */
+    0xb95a,0xb95b,0xb95d,0xb95e,0xb95f,0xb961,0xb962,0xb963,0xb964,0xb965,
+    0xb966,0xb967,0xb96a,0xb96c,0xb96e,0xb96f,0xb970,0xb971,0xb972,0xb973,
+    0xb976,0xb977,0xb979,0xb97a,0xb97b,0xb97d,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xb97e,0xb97f,0xb980,0xb981,0xb982,0xb983,0xb986,0xb988,
+    0xb98b,0xb98c,0xb98f,0xb990,0xb991,0xb992,0xb993,0xb994,0xb995,0xb996,
+    0xb997,0xb998,0xb999,0xb99a,0xb99b,0xb99c,0xb99d,0xb99e,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xb99f,0xb9a0,0xb9a1,0xb9a2,0xb9a3,0xb9a4,
+    0xb9a5,0xb9a6,0xb9a7,0xb9a8,0xb9a9,0xb9aa,0xb9ab,0xb9ae,0xb9af,0xb9b1,
+    0xb9b2,0xb9b3,0xb9b5,0xb9b6,0xb9b7,0xb9b8,0xb9b9,0xb9ba,0xb9bb,0xb9be,
+    0xb9c0,0xb9c2,0xb9c3,0xb9c4,0xb9c5,0xb9c6,0xb9c7,0xb9ca,0xb9cb,0xb9cd,
+    0xb9d3,0xb9d4,0xb9d5,0xb9d6,0xb9d7,0xb9da,0xb9dc,0xb9df,0xb9e0,0xb9e2,
+    0xb9e6,0xb9e7,0xb9e9,0xb9ea,0xb9eb,0xb9ed,0xb9ee,0xb9ef,0xb9f0,0xb9f1,
+    0xb9f2,0xb9f3,0xb9f6,0xb9fb,0xb9fc,0xb9fd,0xb9fe,0xb9ff,0xba02,0xba03,
+    0xba04,0xba05,0xba06,0xba07,0xba09,0xba0a,0xba0b,0xba0c,0xba0d,0xba0e,
+    0xba0f,0xba10,0xba11,0xba12,0xba13,0xba14,0xba16,0xba17,0xba18,0xba19,
+    0xba1a,0xba1b,0xba1c,0xba1d,0xba1e,0xba1f,0xba20,0xba21,0xba22,0xba23,
+    0xba24,0xba25,0xba26,0xba27,0xba28,0xba29,0xba2a,0xba2b,0xba2c,0xba2d,
+    0xba2e,0xba2f,0xba30,0xba31,0xba32,0xba33,0xba34,0xba35,0xba36,0xba37,
+    0xba3a,0xba3b,0xba3d,0xba3e,0xba3f,0xba41,0xba43,0xba44,0xba45,0xba46
+  },
+  {				/* ku 11 */
+    0xba47,0xba4a,0xba4c,0xba4f,0xba50,0xba51,0xba52,0xba56,0xba57,0xba59,
+    0xba5a,0xba5b,0xba5d,0xba5e,0xba5f,0xba60,0xba61,0xba62,0xba63,0xba66,
+    0xba6a,0xba6b,0xba6c,0xba6d,0xba6e,0xba6f,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xba72,0xba73,0xba75,0xba76,0xba77,0xba79,0xba7a,0xba7b,
+    0xba7c,0xba7d,0xba7e,0xba7f,0xba80,0xba81,0xba82,0xba86,0xba88,0xba89,
+    0xba8a,0xba8b,0xba8d,0xba8e,0xba8f,0xba90,0xba91,0xba92,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xba93,0xba94,0xba95,0xba96,0xba97,0xba98,
+    0xba99,0xba9a,0xba9b,0xba9c,0xba9d,0xba9e,0xba9f,0xbaa0,0xbaa1,0xbaa2,
+    0xbaa3,0xbaa4,0xbaa5,0xbaa6,0xbaa7,0xbaaa,0xbaad,0xbaae,0xbaaf,0xbab1,
+    0xbab3,0xbab4,0xbab5,0xbab6,0xbab7,0xbaba,0xbabc,0xbabe,0xbabf,0xbac0,
+    0xbac1,0xbac2,0xbac3,0xbac5,0xbac6,0xbac7,0xbac9,0xbaca,0xbacb,0xbacc,
+    0xbacd,0xbace,0xbacf,0xbad0,0xbad1,0xbad2,0xbad3,0xbad4,0xbad5,0xbad6,
+    0xbad7,0xbada,0xbadb,0xbadc,0xbadd,0xbade,0xbadf,0xbae0,0xbae1,0xbae2,
+    0xbae3,0xbae4,0xbae5,0xbae6,0xbae7,0xbae8,0xbae9,0xbaea,0xbaeb,0xbaec,
+    0xbaed,0xbaee,0xbaef,0xbaf0,0xbaf1,0xbaf2,0xbaf3,0xbaf4,0xbaf5,0xbaf6,
+    0xbaf7,0xbaf8,0xbaf9,0xbafa,0xbafb,0xbafd,0xbafe,0xbaff,0xbb01,0xbb02,
+    0xbb03,0xbb05,0xbb06,0xbb07,0xbb08,0xbb09,0xbb0a,0xbb0b,0xbb0c,0xbb0e,
+    0xbb10,0xbb12,0xbb13,0xbb14,0xbb15,0xbb16,0xbb17,0xbb19,0xbb1a,0xbb1b,
+    0xbb1d,0xbb1e,0xbb1f,0xbb21,0xbb22,0xbb23,0xbb24,0xbb25,0xbb26,0xbb27
+  },
+  {				/* ku 12 */
+    0xbb28,0xbb2a,0xbb2c,0xbb2d,0xbb2e,0xbb2f,0xbb30,0xbb31,0xbb32,0xbb33,
+    0xbb37,0xbb39,0xbb3a,0xbb3f,0xbb40,0xbb41,0xbb42,0xbb43,0xbb46,0xbb48,
+    0xbb4a,0xbb4b,0xbb4c,0xbb4e,0xbb51,0xbb52,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xbb53,0xbb55,0xbb56,0xbb57,0xbb59,0xbb5a,0xbb5b,0xbb5c,
+    0xbb5d,0xbb5e,0xbb5f,0xbb60,0xbb62,0xbb64,0xbb65,0xbb66,0xbb67,0xbb68,
+    0xbb69,0xbb6a,0xbb6b,0xbb6d,0xbb6e,0xbb6f,0xbb70,0xbb71,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xbb72,0xbb73,0xbb74,0xbb75,0xbb76,0xbb77,
+    0xbb78,0xbb79,0xbb7a,0xbb7b,0xbb7c,0xbb7d,0xbb7e,0xbb7f,0xbb80,0xbb81,
+    0xbb82,0xbb83,0xbb84,0xbb85,0xbb86,0xbb87,0xbb89,0xbb8a,0xbb8b,0xbb8d,
+    0xbb8e,0xbb8f,0xbb91,0xbb92,0xbb93,0xbb94,0xbb95,0xbb96,0xbb97,0xbb98,
+    0xbb99,0xbb9a,0xbb9b,0xbb9c,0xbb9d,0xbb9e,0xbb9f,0xbba0,0xbba1,0xbba2,
+    0xbba3,0xbba5,0xbba6,0xbba7,0xbba9,0xbbaa,0xbbab,0xbbad,0xbbae,0xbbaf,
+    0xbbb0,0xbbb1,0xbbb2,0xbbb3,0xbbb5,0xbbb6,0xbbb8,0xbbb9,0xbbba,0xbbbb,
+    0xbbbc,0xbbbd,0xbbbe,0xbbbf,0xbbc1,0xbbc2,0xbbc3,0xbbc5,0xbbc6,0xbbc7,
+    0xbbc9,0xbbca,0xbbcb,0xbbcc,0xbbcd,0xbbce,0xbbcf,0xbbd1,0xbbd2,0xbbd4,
+    0xbbd5,0xbbd6,0xbbd7,0xbbd8,0xbbd9,0xbbda,0xbbdb,0xbbdc,0xbbdd,0xbbde,
+    0xbbdf,0xbbe0,0xbbe1,0xbbe2,0xbbe3,0xbbe4,0xbbe5,0xbbe6,0xbbe7,0xbbe8,
+    0xbbe9,0xbbea,0xbbeb,0xbbec,0xbbed,0xbbee,0xbbef,0xbbf0,0xbbf1,0xbbf2,
+    0xbbf3,0xbbf4,0xbbf5,0xbbf6,0xbbf7,0xbbfa,0xbbfb,0xbbfd,0xbbfe,0xbc01
+  },
+  {				/* ku 13 */
+    0xbc03,0xbc04,0xbc05,0xbc06,0xbc07,0xbc0a,0xbc0e,0xbc10,0xbc12,0xbc13,
+    0xbc19,0xbc1a,0xbc20,0xbc21,0xbc22,0xbc23,0xbc26,0xbc28,0xbc2a,0xbc2b,
+    0xbc2c,0xbc2e,0xbc2f,0xbc32,0xbc33,0xbc35,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xbc36,0xbc37,0xbc39,0xbc3a,0xbc3b,0xbc3c,0xbc3d,0xbc3e,
+    0xbc3f,0xbc42,0xbc46,0xbc47,0xbc48,0xbc4a,0xbc4b,0xbc4e,0xbc4f,0xbc51,
+    0xbc52,0xbc53,0xbc54,0xbc55,0xbc56,0xbc57,0xbc58,0xbc59,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xbc5a,0xbc5b,0xbc5c,0xbc5e,0xbc5f,0xbc60,
+    0xbc61,0xbc62,0xbc63,0xbc64,0xbc65,0xbc66,0xbc67,0xbc68,0xbc69,0xbc6a,
+    0xbc6b,0xbc6c,0xbc6d,0xbc6e,0xbc6f,0xbc70,0xbc71,0xbc72,0xbc73,0xbc74,
+    0xbc75,0xbc76,0xbc77,0xbc78,0xbc79,0xbc7a,0xbc7b,0xbc7c,0xbc7d,0xbc7e,
+    0xbc7f,0xbc80,0xbc81,0xbc82,0xbc83,0xbc86,0xbc87,0xbc89,0xbc8a,0xbc8d,
+    0xbc8f,0xbc90,0xbc91,0xbc92,0xbc93,0xbc96,0xbc98,0xbc9b,0xbc9c,0xbc9d,
+    0xbc9e,0xbc9f,0xbca2,0xbca3,0xbca5,0xbca6,0xbca9,0xbcaa,0xbcab,0xbcac,
+    0xbcad,0xbcae,0xbcaf,0xbcb2,0xbcb6,0xbcb7,0xbcb8,0xbcb9,0xbcba,0xbcbb,
+    0xbcbe,0xbcbf,0xbcc1,0xbcc2,0xbcc3,0xbcc5,0xbcc6,0xbcc7,0xbcc8,0xbcc9,
+    0xbcca,0xbccb,0xbccc,0xbcce,0xbcd2,0xbcd3,0xbcd4,0xbcd6,0xbcd7,0xbcd9,
+    0xbcda,0xbcdb,0xbcdd,0xbcde,0xbcdf,0xbce0,0xbce1,0xbce2,0xbce3,0xbce4,
+    0xbce5,0xbce6,0xbce7,0xbce8,0xbce9,0xbcea,0xbceb,0xbcec,0xbced,0xbcee,
+    0xbcef,0xbcf0,0xbcf1,0xbcf2,0xbcf3,0xbcf7,0xbcf9,0xbcfa,0xbcfb,0xbcfd
+  },
+  {				/* ku 14 */
+    0xbcfe,0xbcff,0xbd00,0xbd01,0xbd02,0xbd03,0xbd06,0xbd08,0xbd0a,0xbd0b,
+    0xbd0c,0xbd0d,0xbd0e,0xbd0f,0xbd11,0xbd12,0xbd13,0xbd15,0xbd16,0xbd17,
+    0xbd18,0xbd19,0xbd1a,0xbd1b,0xbd1c,0xbd1d,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xbd1e,0xbd1f,0xbd20,0xbd21,0xbd22,0xbd23,0xbd25,0xbd26,
+    0xbd27,0xbd28,0xbd29,0xbd2a,0xbd2b,0xbd2d,0xbd2e,0xbd2f,0xbd30,0xbd31,
+    0xbd32,0xbd33,0xbd34,0xbd35,0xbd36,0xbd37,0xbd38,0xbd39,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xbd3a,0xbd3b,0xbd3c,0xbd3d,0xbd3e,0xbd3f,
+    0xbd41,0xbd42,0xbd43,0xbd44,0xbd45,0xbd46,0xbd47,0xbd4a,0xbd4b,0xbd4d,
+    0xbd4e,0xbd4f,0xbd51,0xbd52,0xbd53,0xbd54,0xbd55,0xbd56,0xbd57,0xbd5a,
+    0xbd5b,0xbd5c,0xbd5d,0xbd5e,0xbd5f,0xbd60,0xbd61,0xbd62,0xbd63,0xbd65,
+    0xbd66,0xbd67,0xbd69,0xbd6a,0xbd6b,0xbd6c,0xbd6d,0xbd6e,0xbd6f,0xbd70,
+    0xbd71,0xbd72,0xbd73,0xbd74,0xbd75,0xbd76,0xbd77,0xbd78,0xbd79,0xbd7a,
+    0xbd7b,0xbd7c,0xbd7d,0xbd7e,0xbd7f,0xbd82,0xbd83,0xbd85,0xbd86,0xbd8b,
+    0xbd8c,0xbd8d,0xbd8e,0xbd8f,0xbd92,0xbd94,0xbd96,0xbd97,0xbd98,0xbd9b,
+    0xbd9d,0xbd9e,0xbd9f,0xbda0,0xbda1,0xbda2,0xbda3,0xbda5,0xbda6,0xbda7,
+    0xbda8,0xbda9,0xbdaa,0xbdab,0xbdac,0xbdad,0xbdae,0xbdaf,0xbdb1,0xbdb2,
+    0xbdb3,0xbdb4,0xbdb5,0xbdb6,0xbdb7,0xbdb9,0xbdba,0xbdbb,0xbdbc,0xbdbd,
+    0xbdbe,0xbdbf,0xbdc0,0xbdc1,0xbdc2,0xbdc3,0xbdc4,0xbdc5,0xbdc6,0xbdc7,
+    0xbdc8,0xbdc9,0xbdca,0xbdcb,0xbdcc,0xbdcd,0xbdce,0xbdcf,0xbdd0,0xbdd1
+  },
+  {				/* ku 15 */
+    0xbdd2,0xbdd3,0xbdd6,0xbdd7,0xbdd9,0xbdda,0xbddb,0xbddd,0xbdde,0xbddf,
+    0xbde0,0xbde1,0xbde2,0xbde3,0xbde4,0xbde5,0xbde6,0xbde7,0xbde8,0xbdea,
+    0xbdeb,0xbdec,0xbded,0xbdee,0xbdef,0xbdf1,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xbdf2,0xbdf3,0xbdf5,0xbdf6,0xbdf7,0xbdf9,0xbdfa,0xbdfb,
+    0xbdfc,0xbdfd,0xbdfe,0xbdff,0xbe01,0xbe02,0xbe04,0xbe06,0xbe07,0xbe08,
+    0xbe09,0xbe0a,0xbe0b,0xbe0e,0xbe0f,0xbe11,0xbe12,0xbe13,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xbe15,0xbe16,0xbe17,0xbe18,0xbe19,0xbe1a,
+    0xbe1b,0xbe1e,0xbe20,0xbe21,0xbe22,0xbe23,0xbe24,0xbe25,0xbe26,0xbe27,
+    0xbe28,0xbe29,0xbe2a,0xbe2b,0xbe2c,0xbe2d,0xbe2e,0xbe2f,0xbe30,0xbe31,
+    0xbe32,0xbe33,0xbe34,0xbe35,0xbe36,0xbe37,0xbe38,0xbe39,0xbe3a,0xbe3b,
+    0xbe3c,0xbe3d,0xbe3e,0xbe3f,0xbe40,0xbe41,0xbe42,0xbe43,0xbe46,0xbe47,
+    0xbe49,0xbe4a,0xbe4b,0xbe4d,0xbe4f,0xbe50,0xbe51,0xbe52,0xbe53,0xbe56,
+    0xbe58,0xbe5c,0xbe5d,0xbe5e,0xbe5f,0xbe62,0xbe63,0xbe65,0xbe66,0xbe67,
+    0xbe69,0xbe6b,0xbe6c,0xbe6d,0xbe6e,0xbe6f,0xbe72,0xbe76,0xbe77,0xbe78,
+    0xbe79,0xbe7a,0xbe7e,0xbe7f,0xbe81,0xbe82,0xbe83,0xbe85,0xbe86,0xbe87,
+    0xbe88,0xbe89,0xbe8a,0xbe8b,0xbe8e,0xbe92,0xbe93,0xbe94,0xbe95,0xbe96,
+    0xbe97,0xbe9a,0xbe9b,0xbe9c,0xbe9d,0xbe9e,0xbe9f,0xbea0,0xbea1,0xbea2,
+    0xbea3,0xbea4,0xbea5,0xbea6,0xbea7,0xbea9,0xbeaa,0xbeab,0xbeac,0xbead,
+    0xbeae,0xbeaf,0xbeb0,0xbeb1,0xbeb2,0xbeb3,0xbeb4,0xbeb5,0xbeb6,0xbeb7
+  },
+  {				/* ku 16 */
+    0xbeb8,0xbeb9,0xbeba,0xbebb,0xbebc,0xbebd,0xbebe,0xbebf,0xbec0,0xbec1,
+    0xbec2,0xbec3,0xbec4,0xbec5,0xbec6,0xbec7,0xbec8,0xbec9,0xbeca,0xbecb,
+    0xbecc,0xbecd,0xbece,0xbecf,0xbed2,0xbed3,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xbed5,0xbed6,0xbed9,0xbeda,0xbedb,0xbedc,0xbedd,0xbede,
+    0xbedf,0xbee1,0xbee2,0xbee6,0xbee7,0xbee8,0xbee9,0xbeea,0xbeeb,0xbeed,
+    0xbeee,0xbeef,0xbef0,0xbef1,0xbef2,0xbef3,0xbef4,0xbef5,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xbef6,0xbef7,0xbef8,0xbef9,0xbefa,0xbefb,
+    0xbefc,0xbefd,0xbefe,0xbeff,0xbf00,0xbf02,0xbf03,0xbf04,0xbf05,0xbf06,
+    0xbf07,0xbf0a,0xbf0b,0xbf0c,0xbf0d,0xbf0e,0xbf0f,0xbf10,0xbf11,0xbf12,
+    0xbf13,0xbf14,0xbf15,0xbf16,0xbf17,0xbf1a,0xbf1e,0xbf1f,0xbf20,0xbf21,
+    0xbf22,0xbf23,0xbf24,0xbf25,0xbf26,0xbf27,0xbf28,0xbf29,0xbf2a,0xbf2b,
+    0xbf2c,0xbf2d,0xbf2e,0xbf2f,0xbf30,0xbf31,0xbf32,0xbf33,0xbf34,0xbf35,
+    0xbf36,0xbf37,0xbf38,0xbf39,0xbf3a,0xbf3b,0xbf3c,0xbf3d,0xbf3e,0xbf3f,
+    0xbf42,0xbf43,0xbf45,0xbf46,0xbf47,0xbf49,0xbf4a,0xbf4b,0xbf4c,0xbf4d,
+    0xbf4e,0xbf4f,0xbf52,0xbf53,0xbf54,0xbf56,0xbf57,0xbf58,0xbf59,0xbf5a,
+    0xbf5b,0xbf5c,0xbf5d,0xbf5e,0xbf5f,0xbf60,0xbf61,0xbf62,0xbf63,0xbf64,
+    0xbf65,0xbf66,0xbf67,0xbf68,0xbf69,0xbf6a,0xbf6b,0xbf6c,0xbf6d,0xbf6e,
+    0xbf6f,0xbf70,0xbf71,0xbf72,0xbf73,0xbf74,0xbf75,0xbf76,0xbf77,0xbf78,
+    0xbf79,0xbf7a,0xbf7b,0xbf7c,0xbf7d,0xbf7e,0xbf7f,0xbf80,0xbf81,0xbf82
+  },
+  {				/* ku 17 */
+    0xbf83,0xbf84,0xbf85,0xbf86,0xbf87,0xbf88,0xbf89,0xbf8a,0xbf8b,0xbf8c,
+    0xbf8d,0xbf8e,0xbf8f,0xbf90,0xbf91,0xbf92,0xbf93,0xbf95,0xbf96,0xbf97,
+    0xbf98,0xbf99,0xbf9a,0xbf9b,0xbf9c,0xbf9d,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xbf9e,0xbf9f,0xbfa0,0xbfa1,0xbfa2,0xbfa3,0xbfa4,0xbfa5,
+    0xbfa6,0xbfa7,0xbfa8,0xbfa9,0xbfaa,0xbfab,0xbfac,0xbfad,0xbfae,0xbfaf,
+    0xbfb1,0xbfb2,0xbfb3,0xbfb4,0xbfb5,0xbfb6,0xbfb7,0xbfb8,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xbfb9,0xbfba,0xbfbb,0xbfbc,0xbfbd,0xbfbe,
+    0xbfbf,0xbfc0,0xbfc1,0xbfc2,0xbfc3,0xbfc4,0xbfc6,0xbfc7,0xbfc8,0xbfc9,
+    0xbfca,0xbfcb,0xbfce,0xbfcf,0xbfd1,0xbfd2,0xbfd3,0xbfd5,0xbfd6,0xbfd7,
+    0xbfd8,0xbfd9,0xbfda,0xbfdb,0xbfdd,0xbfde,0xbfe0,0xbfe2,0xbfe3,0xbfe4,
+    0xbfe5,0xbfe6,0xbfe7,0xbfe8,0xbfe9,0xbfea,0xbfeb,0xbfec,0xbfed,0xbfee,
+    0xbfef,0xbff0,0xbff1,0xbff2,0xbff3,0xbff4,0xbff5,0xbff6,0xbff7,0xbff8,
+    0xbff9,0xbffa,0xbffb,0xbffc,0xbffd,0xbffe,0xbfff,0xc000,0xc001,0xc002,
+    0xc003,0xc004,0xc005,0xc006,0xc007,0xc008,0xc009,0xc00a,0xc00b,0xc00c,
+    0xc00d,0xc00e,0xc00f,0xc010,0xc011,0xc012,0xc013,0xc014,0xc015,0xc016,
+    0xc017,0xc018,0xc019,0xc01a,0xc01b,0xc01c,0xc01d,0xc01e,0xc01f,0xc020,
+    0xc021,0xc022,0xc023,0xc024,0xc025,0xc026,0xc027,0xc028,0xc029,0xc02a,
+    0xc02b,0xc02c,0xc02d,0xc02e,0xc02f,0xc030,0xc031,0xc032,0xc033,0xc034,
+    0xc035,0xc036,0xc037,0xc038,0xc039,0xc03a,0xc03b,0xc03d,0xc03e,0xc03f
+  },
+  {				/* ku 18 */
+    0xc040,0xc041,0xc042,0xc043,0xc044,0xc045,0xc046,0xc047,0xc048,0xc049,
+    0xc04a,0xc04b,0xc04c,0xc04d,0xc04e,0xc04f,0xc050,0xc052,0xc053,0xc054,
+    0xc055,0xc056,0xc057,0xc059,0xc05a,0xc05b,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xc05d,0xc05e,0xc05f,0xc061,0xc062,0xc063,0xc064,0xc065,
+    0xc066,0xc067,0xc06a,0xc06b,0xc06c,0xc06d,0xc06e,0xc06f,0xc070,0xc071,
+    0xc072,0xc073,0xc074,0xc075,0xc076,0xc077,0xc078,0xc079,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xc07a,0xc07b,0xc07c,0xc07d,0xc07e,0xc07f,
+    0xc080,0xc081,0xc082,0xc083,0xc084,0xc085,0xc086,0xc087,0xc088,0xc089,
+    0xc08a,0xc08b,0xc08c,0xc08d,0xc08e,0xc08f,0xc092,0xc093,0xc095,0xc096,
+    0xc097,0xc099,0xc09a,0xc09b,0xc09c,0xc09d,0xc09e,0xc09f,0xc0a2,0xc0a4,
+    0xc0a6,0xc0a7,0xc0a8,0xc0a9,0xc0aa,0xc0ab,0xc0ae,0xc0b1,0xc0b2,0xc0b7,
+    0xc0b8,0xc0b9,0xc0ba,0xc0bb,0xc0be,0xc0c2,0xc0c3,0xc0c4,0xc0c6,0xc0c7,
+    0xc0ca,0xc0cb,0xc0cd,0xc0ce,0xc0cf,0xc0d1,0xc0d2,0xc0d3,0xc0d4,0xc0d5,
+    0xc0d6,0xc0d7,0xc0da,0xc0de,0xc0df,0xc0e0,0xc0e1,0xc0e2,0xc0e3,0xc0e6,
+    0xc0e7,0xc0e9,0xc0ea,0xc0eb,0xc0ed,0xc0ee,0xc0ef,0xc0f0,0xc0f1,0xc0f2,
+    0xc0f3,0xc0f6,0xc0f8,0xc0fa,0xc0fb,0xc0fc,0xc0fd,0xc0fe,0xc0ff,0xc101,
+    0xc102,0xc103,0xc105,0xc106,0xc107,0xc109,0xc10a,0xc10b,0xc10c,0xc10d,
+    0xc10e,0xc10f,0xc111,0xc112,0xc113,0xc114,0xc116,0xc117,0xc118,0xc119,
+    0xc11a,0xc11b,0xc121,0xc122,0xc125,0xc128,0xc129,0xc12a,0xc12b,0xc12e
+  },
+  {				/* ku 19 */
+    0xc132,0xc133,0xc134,0xc135,0xc137,0xc13a,0xc13b,0xc13d,0xc13e,0xc13f,
+    0xc141,0xc142,0xc143,0xc144,0xc145,0xc146,0xc147,0xc14a,0xc14e,0xc14f,
+    0xc150,0xc151,0xc152,0xc153,0xc156,0xc157,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xc159,0xc15a,0xc15b,0xc15d,0xc15e,0xc15f,0xc160,0xc161,
+    0xc162,0xc163,0xc166,0xc16a,0xc16b,0xc16c,0xc16d,0xc16e,0xc16f,0xc171,
+    0xc172,0xc173,0xc175,0xc176,0xc177,0xc179,0xc17a,0xc17b,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xc17c,0xc17d,0xc17e,0xc17f,0xc180,0xc181,
+    0xc182,0xc183,0xc184,0xc186,0xc187,0xc188,0xc189,0xc18a,0xc18b,0xc18f,
+    0xc191,0xc192,0xc193,0xc195,0xc197,0xc198,0xc199,0xc19a,0xc19b,0xc19e,
+    0xc1a0,0xc1a2,0xc1a3,0xc1a4,0xc1a6,0xc1a7,0xc1aa,0xc1ab,0xc1ad,0xc1ae,
+    0xc1af,0xc1b1,0xc1b2,0xc1b3,0xc1b4,0xc1b5,0xc1b6,0xc1b7,0xc1b8,0xc1b9,
+    0xc1ba,0xc1bb,0xc1bc,0xc1be,0xc1bf,0xc1c0,0xc1c1,0xc1c2,0xc1c3,0xc1c5,
+    0xc1c6,0xc1c7,0xc1c9,0xc1ca,0xc1cb,0xc1cd,0xc1ce,0xc1cf,0xc1d0,0xc1d1,
+    0xc1d2,0xc1d3,0xc1d5,0xc1d6,0xc1d9,0xc1da,0xc1db,0xc1dc,0xc1dd,0xc1de,
+    0xc1df,0xc1e1,0xc1e2,0xc1e3,0xc1e5,0xc1e6,0xc1e7,0xc1e9,0xc1ea,0xc1eb,
+    0xc1ec,0xc1ed,0xc1ee,0xc1ef,0xc1f2,0xc1f4,0xc1f5,0xc1f6,0xc1f7,0xc1f8,
+    0xc1f9,0xc1fa,0xc1fb,0xc1fe,0xc1ff,0xc201,0xc202,0xc203,0xc205,0xc206,
+    0xc207,0xc208,0xc209,0xc20a,0xc20b,0xc20e,0xc210,0xc212,0xc213,0xc214,
+    0xc215,0xc216,0xc217,0xc21a,0xc21b,0xc21d,0xc21e,0xc221,0xc222,0xc223
+  },
+  {				/* ku 1a */
+    0xc224,0xc225,0xc226,0xc227,0xc22a,0xc22c,0xc22e,0xc230,0xc233,0xc235,
+    0xc236,0xc237,0xc238,0xc239,0xc23a,0xc23b,0xc23c,0xc23d,0xc23e,0xc23f,
+    0xc240,0xc241,0xc242,0xc243,0xc244,0xc245,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xc246,0xc247,0xc249,0xc24a,0xc24b,0xc24c,0xc24d,0xc24e,
+    0xc24f,0xc252,0xc253,0xc255,0xc256,0xc257,0xc259,0xc25a,0xc25b,0xc25c,
+    0xc25d,0xc25e,0xc25f,0xc261,0xc262,0xc263,0xc264,0xc266,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xc267,0xc268,0xc269,0xc26a,0xc26b,0xc26e,
+    0xc26f,0xc271,0xc272,0xc273,0xc275,0xc276,0xc277,0xc278,0xc279,0xc27a,
+    0xc27b,0xc27e,0xc280,0xc282,0xc283,0xc284,0xc285,0xc286,0xc287,0xc28a,
+    0xc28b,0xc28c,0xc28d,0xc28e,0xc28f,0xc291,0xc292,0xc293,0xc294,0xc295,
+    0xc296,0xc297,0xc299,0xc29a,0xc29c,0xc29e,0xc29f,0xc2a0,0xc2a1,0xc2a2,
+    0xc2a3,0xc2a6,0xc2a7,0xc2a9,0xc2aa,0xc2ab,0xc2ae,0xc2af,0xc2b0,0xc2b1,
+    0xc2b2,0xc2b3,0xc2b6,0xc2b8,0xc2ba,0xc2bb,0xc2bc,0xc2bd,0xc2be,0xc2bf,
+    0xc2c0,0xc2c1,0xc2c2,0xc2c3,0xc2c4,0xc2c5,0xc2c6,0xc2c7,0xc2c8,0xc2c9,
+    0xc2ca,0xc2cb,0xc2cc,0xc2cd,0xc2ce,0xc2cf,0xc2d0,0xc2d1,0xc2d2,0xc2d3,
+    0xc2d4,0xc2d5,0xc2d6,0xc2d7,0xc2d8,0xc2d9,0xc2da,0xc2db,0xc2de,0xc2df,
+    0xc2e1,0xc2e2,0xc2e5,0xc2e6,0xc2e7,0xc2e8,0xc2e9,0xc2ea,0xc2ee,0xc2f0,
+    0xc2f2,0xc2f3,0xc2f4,0xc2f5,0xc2f7,0xc2fa,0xc2fd,0xc2fe,0xc2ff,0xc301,
+    0xc302,0xc303,0xc304,0xc305,0xc306,0xc307,0xc30a,0xc30b,0xc30e,0xc30f
+  },
+  {				/* ku 1b */
+    0xc310,0xc311,0xc312,0xc316,0xc317,0xc319,0xc31a,0xc31b,0xc31d,0xc31e,
+    0xc31f,0xc320,0xc321,0xc322,0xc323,0xc326,0xc327,0xc32a,0xc32b,0xc32c,
+    0xc32d,0xc32e,0xc32f,0xc330,0xc331,0xc332,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xc333,0xc334,0xc335,0xc336,0xc337,0xc338,0xc339,0xc33a,
+    0xc33b,0xc33c,0xc33d,0xc33e,0xc33f,0xc340,0xc341,0xc342,0xc343,0xc344,
+    0xc346,0xc347,0xc348,0xc349,0xc34a,0xc34b,0xc34c,0xc34d,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xc34e,0xc34f,0xc350,0xc351,0xc352,0xc353,
+    0xc354,0xc355,0xc356,0xc357,0xc358,0xc359,0xc35a,0xc35b,0xc35c,0xc35d,
+    0xc35e,0xc35f,0xc360,0xc361,0xc362,0xc363,0xc364,0xc365,0xc366,0xc367,
+    0xc36a,0xc36b,0xc36d,0xc36e,0xc36f,0xc371,0xc373,0xc374,0xc375,0xc376,
+    0xc377,0xc37a,0xc37b,0xc37e,0xc37f,0xc380,0xc381,0xc382,0xc383,0xc385,
+    0xc386,0xc387,0xc389,0xc38a,0xc38b,0xc38d,0xc38e,0xc38f,0xc390,0xc391,
+    0xc392,0xc393,0xc394,0xc395,0xc396,0xc397,0xc398,0xc399,0xc39a,0xc39b,
+    0xc39c,0xc39d,0xc39e,0xc39f,0xc3a0,0xc3a1,0xc3a2,0xc3a3,0xc3a4,0xc3a5,
+    0xc3a6,0xc3a7,0xc3a8,0xc3a9,0xc3aa,0xc3ab,0xc3ac,0xc3ad,0xc3ae,0xc3af,
+    0xc3b0,0xc3b1,0xc3b2,0xc3b3,0xc3b4,0xc3b5,0xc3b6,0xc3b7,0xc3b8,0xc3b9,
+    0xc3ba,0xc3bb,0xc3bc,0xc3bd,0xc3be,0xc3bf,0xc3c1,0xc3c2,0xc3c3,0xc3c4,
+    0xc3c5,0xc3c6,0xc3c7,0xc3c8,0xc3c9,0xc3ca,0xc3cb,0xc3cc,0xc3cd,0xc3ce,
+    0xc3cf,0xc3d0,0xc3d1,0xc3d2,0xc3d3,0xc3d4,0xc3d5,0xc3d6,0xc3d7,0xc3da
+  },
+  {				/* ku 1c */
+    0xc3db,0xc3dd,0xc3de,0xc3e1,0xc3e3,0xc3e4,0xc3e5,0xc3e6,0xc3e7,0xc3ea,
+    0xc3eb,0xc3ec,0xc3ee,0xc3ef,0xc3f0,0xc3f1,0xc3f2,0xc3f3,0xc3f6,0xc3f7,
+    0xc3f9,0xc3fa,0xc3fb,0xc3fc,0xc3fd,0xc3fe,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xc3ff,0xc400,0xc401,0xc402,0xc403,0xc404,0xc405,0xc406,
+    0xc407,0xc409,0xc40a,0xc40b,0xc40c,0xc40d,0xc40e,0xc40f,0xc411,0xc412,
+    0xc413,0xc414,0xc415,0xc416,0xc417,0xc418,0xc419,0xc41a,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xc41b,0xc41c,0xc41d,0xc41e,0xc41f,0xc420,
+    0xc421,0xc422,0xc423,0xc425,0xc426,0xc427,0xc428,0xc429,0xc42a,0xc42b,
+    0xc42d,0xc42e,0xc42f,0xc431,0xc432,0xc433,0xc435,0xc436,0xc437,0xc438,
+    0xc439,0xc43a,0xc43b,0xc43e,0xc43f,0xc440,0xc441,0xc442,0xc443,0xc444,
+    0xc445,0xc446,0xc447,0xc449,0xc44a,0xc44b,0xc44c,0xc44d,0xc44e,0xc44f,
+    0xc450,0xc451,0xc452,0xc453,0xc454,0xc455,0xc456,0xc457,0xc458,0xc459,
+    0xc45a,0xc45b,0xc45c,0xc45d,0xc45e,0xc45f,0xc460,0xc461,0xc462,0xc463,
+    0xc466,0xc467,0xc469,0xc46a,0xc46b,0xc46d,0xc46e,0xc46f,0xc470,0xc471,
+    0xc472,0xc473,0xc476,0xc477,0xc478,0xc47a,0xc47b,0xc47c,0xc47d,0xc47e,
+    0xc47f,0xc481,0xc482,0xc483,0xc484,0xc485,0xc486,0xc487,0xc488,0xc489,
+    0xc48a,0xc48b,0xc48c,0xc48d,0xc48e,0xc48f,0xc490,0xc491,0xc492,0xc493,
+    0xc495,0xc496,0xc497,0xc498,0xc499,0xc49a,0xc49b,0xc49d,0xc49e,0xc49f,
+    0xc4a0,0xc4a1,0xc4a2,0xc4a3,0xc4a4,0xc4a5,0xc4a6,0xc4a7,0xc4a8,0xc4a9
+  },
+  {				/* ku 1d */
+    0xc4aa,0xc4ab,0xc4ac,0xc4ad,0xc4ae,0xc4af,0xc4b0,0xc4b1,0xc4b2,0xc4b3,
+    0xc4b4,0xc4b5,0xc4b6,0xc4b7,0xc4b9,0xc4ba,0xc4bb,0xc4bd,0xc4be,0xc4bf,
+    0xc4c0,0xc4c1,0xc4c2,0xc4c3,0xc4c4,0xc4c5,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xc4c6,0xc4c7,0xc4c8,0xc4c9,0xc4ca,0xc4cb,0xc4cc,0xc4cd,
+    0xc4ce,0xc4cf,0xc4d0,0xc4d1,0xc4d2,0xc4d3,0xc4d4,0xc4d5,0xc4d6,0xc4d7,
+    0xc4d8,0xc4d9,0xc4da,0xc4db,0xc4dc,0xc4dd,0xc4de,0xc4df,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xc4e0,0xc4e1,0xc4e2,0xc4e3,0xc4e4,0xc4e5,
+    0xc4e6,0xc4e7,0xc4e8,0xc4ea,0xc4eb,0xc4ec,0xc4ed,0xc4ee,0xc4ef,0xc4f2,
+    0xc4f3,0xc4f5,0xc4f6,0xc4f7,0xc4f9,0xc4fb,0xc4fc,0xc4fd,0xc4fe,0xc502,
+    0xc503,0xc504,0xc505,0xc506,0xc507,0xc508,0xc509,0xc50a,0xc50b,0xc50d,
+    0xc50e,0xc50f,0xc511,0xc512,0xc513,0xc515,0xc516,0xc517,0xc518,0xc519,
+    0xc51a,0xc51b,0xc51d,0xc51e,0xc51f,0xc520,0xc521,0xc522,0xc523,0xc524,
+    0xc525,0xc526,0xc527,0xc52a,0xc52b,0xc52d,0xc52e,0xc52f,0xc531,0xc532,
+    0xc533,0xc534,0xc535,0xc536,0xc537,0xc53a,0xc53c,0xc53e,0xc53f,0xc540,
+    0xc541,0xc542,0xc543,0xc546,0xc547,0xc54b,0xc54f,0xc550,0xc551,0xc552,
+    0xc556,0xc55a,0xc55b,0xc55c,0xc55f,0xc562,0xc563,0xc565,0xc566,0xc567,
+    0xc569,0xc56a,0xc56b,0xc56c,0xc56d,0xc56e,0xc56f,0xc572,0xc576,0xc577,
+    0xc578,0xc579,0xc57a,0xc57b,0xc57e,0xc57f,0xc581,0xc582,0xc583,0xc585,
+    0xc586,0xc588,0xc589,0xc58a,0xc58b,0xc58e,0xc590,0xc592,0xc593,0xc594
+  },
+  {				/* ku 1e */
+    0xc596,0xc599,0xc59a,0xc59b,0xc59d,0xc59e,0xc59f,0xc5a1,0xc5a2,0xc5a3,
+    0xc5a4,0xc5a5,0xc5a6,0xc5a7,0xc5a8,0xc5aa,0xc5ab,0xc5ac,0xc5ad,0xc5ae,
+    0xc5af,0xc5b0,0xc5b1,0xc5b2,0xc5b3,0xc5b6,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xc5b7,0xc5ba,0xc5bf,0xc5c0,0xc5c1,0xc5c2,0xc5c3,0xc5cb,
+    0xc5cd,0xc5cf,0xc5d2,0xc5d3,0xc5d5,0xc5d6,0xc5d7,0xc5d9,0xc5da,0xc5db,
+    0xc5dc,0xc5dd,0xc5de,0xc5df,0xc5e2,0xc5e4,0xc5e6,0xc5e7,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xc5e8,0xc5e9,0xc5ea,0xc5eb,0xc5ef,0xc5f1,
+    0xc5f2,0xc5f3,0xc5f5,0xc5f8,0xc5f9,0xc5fa,0xc5fb,0xc602,0xc603,0xc604,
+    0xc609,0xc60a,0xc60b,0xc60d,0xc60e,0xc60f,0xc611,0xc612,0xc613,0xc614,
+    0xc615,0xc616,0xc617,0xc61a,0xc61d,0xc61e,0xc61f,0xc620,0xc621,0xc622,
+    0xc623,0xc626,0xc627,0xc629,0xc62a,0xc62b,0xc62f,0xc631,0xc632,0xc636,
+    0xc638,0xc63a,0xc63c,0xc63d,0xc63e,0xc63f,0xc642,0xc643,0xc645,0xc646,
+    0xc647,0xc649,0xc64a,0xc64b,0xc64c,0xc64d,0xc64e,0xc64f,0xc652,0xc656,
+    0xc657,0xc658,0xc659,0xc65a,0xc65b,0xc65e,0xc65f,0xc661,0xc662,0xc663,
+    0xc664,0xc665,0xc666,0xc667,0xc668,0xc669,0xc66a,0xc66b,0xc66d,0xc66e,
+    0xc670,0xc672,0xc673,0xc674,0xc675,0xc676,0xc677,0xc67a,0xc67b,0xc67d,
+    0xc67e,0xc67f,0xc681,0xc682,0xc683,0xc684,0xc685,0xc686,0xc687,0xc68a,
+    0xc68c,0xc68e,0xc68f,0xc690,0xc691,0xc692,0xc693,0xc696,0xc697,0xc699,
+    0xc69a,0xc69b,0xc69d,0xc69e,0xc69f,0xc6a0,0xc6a1,0xc6a2,0xc6a3,0xc6a6
+  },
+  {				/* ku 1f */
+    0xc6a8,0xc6aa,0xc6ab,0xc6ac,0xc6ad,0xc6ae,0xc6af,0xc6b2,0xc6b3,0xc6b5,
+    0xc6b6,0xc6b7,0xc6bb,0xc6bc,0xc6bd,0xc6be,0xc6bf,0xc6c2,0xc6c4,0xc6c6,
+    0xc6c7,0xc6c8,0xc6c9,0xc6ca,0xc6cb,0xc6ce,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xc6cf,0xc6d1,0xc6d2,0xc6d3,0xc6d5,0xc6d6,0xc6d7,0xc6d8,
+    0xc6d9,0xc6da,0xc6db,0xc6de,0xc6df,0xc6e2,0xc6e3,0xc6e4,0xc6e5,0xc6e6,
+    0xc6e7,0xc6ea,0xc6eb,0xc6ed,0xc6ee,0xc6ef,0xc6f1,0xc6f2,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xc6f3,0xc6f4,0xc6f5,0xc6f6,0xc6f7,0xc6fa,
+    0xc6fb,0xc6fc,0xc6fe,0xc6ff,0xc700,0xc701,0xc702,0xc703,0xc706,0xc707,
+    0xc709,0xc70a,0xc70b,0xc70d,0xc70e,0xc70f,0xc710,0xc711,0xc712,0xc713,
+    0xc716,0xc718,0xc71a,0xc71b,0xc71c,0xc71d,0xc71e,0xc71f,0xc722,0xc723,
+    0xc725,0xc726,0xc727,0xc729,0xc72a,0xc72b,0xc72c,0xc72d,0xc72e,0xc72f,
+    0xc732,0xc734,0xc736,0xc738,0xc739,0xc73a,0xc73b,0xc73e,0xc73f,0xc741,
+    0xc742,0xc743,0xc745,0xc746,0xc747,0xc748,0xc749,0xc74b,0xc74e,0xc750,
+    0xc759,0xc75a,0xc75b,0xc75d,0xc75e,0xc75f,0xc761,0xc762,0xc763,0xc764,
+    0xc765,0xc766,0xc767,0xc769,0xc76a,0xc76c,0xc76d,0xc76e,0xc76f,0xc770,
+    0xc771,0xc772,0xc773,0xc776,0xc777,0xc779,0xc77a,0xc77b,0xc77f,0xc780,
+    0xc781,0xc782,0xc786,0xc78b,0xc78c,0xc78d,0xc78f,0xc792,0xc793,0xc795,
+    0xc799,0xc79b,0xc79c,0xc79d,0xc79e,0xc79f,0xc7a2,0xc7a7,0xc7a8,0xc7a9,
+    0xc7aa,0xc7ab,0xc7ae,0xc7af,0xc7b1,0xc7b2,0xc7b3,0xc7b5,0xc7b6,0xc7b7
+  },
+  {				/* ku 20 */
+    0xc7b8,0xc7b9,0xc7ba,0xc7bb,0xc7be,0xc7c2,0xc7c3,0xc7c4,0xc7c5,0xc7c6,
+    0xc7c7,0xc7ca,0xc7cb,0xc7cd,0xc7cf,0xc7d1,0xc7d2,0xc7d3,0xc7d4,0xc7d5,
+    0xc7d6,0xc7d7,0xc7d9,0xc7da,0xc7db,0xc7dc,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xc7de,0xc7df,0xc7e0,0xc7e1,0xc7e2,0xc7e3,0xc7e5,0xc7e6,
+    0xc7e7,0xc7e9,0xc7ea,0xc7eb,0xc7ed,0xc7ee,0xc7ef,0xc7f0,0xc7f1,0xc7f2,
+    0xc7f3,0xc7f4,0xc7f5,0xc7f6,0xc7f7,0xc7f8,0xc7f9,0xc7fa,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xc7fb,0xc7fc,0xc7fd,0xc7fe,0xc7ff,0xc802,
+    0xc803,0xc805,0xc806,0xc807,0xc809,0xc80b,0xc80c,0xc80d,0xc80e,0xc80f,
+    0xc812,0xc814,0xc817,0xc818,0xc819,0xc81a,0xc81b,0xc81e,0xc81f,0xc821,
+    0xc822,0xc823,0xc825,0xc826,0xc827,0xc828,0xc829,0xc82a,0xc82b,0xc82e,
+    0xc830,0xc832,0xc833,0xc834,0xc835,0xc836,0xc837,0xc839,0xc83a,0xc83b,
+    0xc83d,0xc83e,0xc83f,0xc841,0xc842,0xc843,0xc844,0xc845,0xc846,0xc847,
+    0xc84a,0xc84b,0xc84e,0xc84f,0xc850,0xc851,0xc852,0xc853,0xc855,0xc856,
+    0xc857,0xc858,0xc859,0xc85a,0xc85b,0xc85c,0xc85d,0xc85e,0xc85f,0xc860,
+    0xc861,0xc862,0xc863,0xc864,0xc865,0xc866,0xc867,0xc868,0xc869,0xc86a,
+    0xc86b,0xc86c,0xc86d,0xc86e,0xc86f,0xc872,0xc873,0xc875,0xc876,0xc877,
+    0xc879,0xc87b,0xc87c,0xc87d,0xc87e,0xc87f,0xc882,0xc884,0xc888,0xc889,
+    0xc88a,0xc88e,0xc88f,0xc890,0xc891,0xc892,0xc893,0xc895,0xc896,0xc897,
+    0xc898,0xc899,0xc89a,0xc89b,0xc89c,0xc89e,0xc8a0,0xc8a2,0xc8a3,0xc8a4
+  },
+  {				/* ku 21 */
+    0xc8a5,0xc8a6,0xc8a7,0xc8a9,0xc8aa,0xc8ab,0xc8ac,0xc8ad,0xc8ae,0xc8af,
+    0xc8b0,0xc8b1,0xc8b2,0xc8b3,0xc8b4,0xc8b5,0xc8b6,0xc8b7,0xc8b8,0xc8b9,
+    0xc8ba,0xc8bb,0xc8be,0xc8bf,0xc8c0,0xc8c1,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xc8c2,0xc8c3,0xc8c5,0xc8c6,0xc8c7,0xc8c9,0xc8ca,0xc8cb,
+    0xc8cd,0xc8ce,0xc8cf,0xc8d0,0xc8d1,0xc8d2,0xc8d3,0xc8d6,0xc8d8,0xc8da,
+    0xc8db,0xc8dc,0xc8dd,0xc8de,0xc8df,0xc8e2,0xc8e3,0xc8e5,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xc8e6,0xc8e7,0xc8e8,0xc8e9,0xc8ea,0xc8eb,
+    0xc8ec,0xc8ed,0xc8ee,0xc8ef,0xc8f0,0xc8f1,0xc8f2,0xc8f3,0xc8f4,0xc8f6,
+    0xc8f7,0xc8f8,0xc8f9,0xc8fa,0xc8fb,0xc8fe,0xc8ff,0xc901,0xc902,0xc903,
+    0xc907,0xc908,0xc909,0xc90a,0xc90b,0xc90e,0x3000,0x3001,0x3002,0x00b7,
+    0x2025,0x2026,0x00a8,0x3003,0x00ad,0x2015,0x2225,0xff3c,0x223c,0x2018,
+    0x2019,0x201c,0x201d,0x3014,0x3015,0x3008,0x3009,0x300a,0x300b,0x300c,
+    0x300d,0x300e,0x300f,0x3010,0x3011,0x00b1,0x00d7,0x00f7,0x2260,0x2264,
+    0x2265,0x221e,0x2234,0x00b0,0x2032,0x2033,0x2103,0x212b,0xffe0,0xffe1,
+    0xffe5,0x2642,0x2640,0x2220,0x22a5,0x2312,0x2202,0x2207,0x2261,0x2252,
+    0x00a7,0x203b,0x2606,0x2605,0x25cb,0x25cf,0x25ce,0x25c7,0x25c6,0x25a1,
+    0x25a0,0x25b3,0x25b2,0x25bd,0x25bc,0x2192,0x2190,0x2191,0x2193,0x2194,
+    0x3013,0x226a,0x226b,0x221a,0x223d,0x221d,0x2235,0x222b,0x222c,0x2208,
+    0x220b,0x2286,0x2287,0x2282,0x2283,0x222a,0x2229,0x2227,0x2228,0xffe2
+  },
+  {				/* ku 22 */
+    0xc910,0xc912,0xc913,0xc914,0xc915,0xc916,0xc917,0xc919,0xc91a,0xc91b,
+    0xc91c,0xc91d,0xc91e,0xc91f,0xc920,0xc921,0xc922,0xc923,0xc924,0xc925,
+    0xc926,0xc927,0xc928,0xc929,0xc92a,0xc92b,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xc92d,0xc92e,0xc92f,0xc930,0xc931,0xc932,0xc933,0xc935,
+    0xc936,0xc937,0xc938,0xc939,0xc93a,0xc93b,0xc93c,0xc93d,0xc93e,0xc93f,
+    0xc940,0xc941,0xc942,0xc943,0xc944,0xc945,0xc946,0xc947,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xc948,0xc949,0xc94a,0xc94b,0xc94c,0xc94d,
+    0xc94e,0xc94f,0xc952,0xc953,0xc955,0xc956,0xc957,0xc959,0xc95a,0xc95b,
+    0xc95c,0xc95d,0xc95e,0xc95f,0xc962,0xc964,0xc965,0xc966,0xc967,0xc968,
+    0xc969,0xc96a,0xc96b,0xc96d,0xc96e,0xc96f,0x21d2,0x21d4,0x2200,0x2203,
+    0x00b4,0xff5e,0x02c7,0x02d8,0x02dd,0x02da,0x02d9,0x00b8,0x02db,0x00a1,
+    0x00bf,0x02d0,0x222e,0x2211,0x220f,0x00a4,0x2109,0x2030,0x25c1,0x25c0,
+    0x25b7,0x25b6,0x2664,0x2660,0x2661,0x2665,0x2667,0x2663,0x2299,0x25c8,
+    0x25a3,0x25d0,0x25d1,0x2592,0x25a4,0x25a5,0x25a8,0x25a7,0x25a6,0x25a9,
+    0x2668,0x260f,0x260e,0x261c,0x261e,0x00b6,0x2020,0x2021,0x2195,0x2197,
+    0x2199,0x2196,0x2198,0x266d,0x2669,0x266a,0x266c,0x327f,0x321c,0x2116,
+    0x33c7,0x2122,0x33c2,0x33d8,0x2121,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 23 */
+    0xc971,0xc972,0xc973,0xc975,0xc976,0xc977,0xc978,0xc979,0xc97a,0xc97b,
+    0xc97d,0xc97e,0xc97f,0xc980,0xc981,0xc982,0xc983,0xc984,0xc985,0xc986,
+    0xc987,0xc98a,0xc98b,0xc98d,0xc98e,0xc98f,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xc991,0xc992,0xc993,0xc994,0xc995,0xc996,0xc997,0xc99a,
+    0xc99c,0xc99e,0xc99f,0xc9a0,0xc9a1,0xc9a2,0xc9a3,0xc9a4,0xc9a5,0xc9a6,
+    0xc9a7,0xc9a8,0xc9a9,0xc9aa,0xc9ab,0xc9ac,0xc9ad,0xc9ae,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xc9af,0xc9b0,0xc9b1,0xc9b2,0xc9b3,0xc9b4,
+    0xc9b5,0xc9b6,0xc9b7,0xc9b8,0xc9b9,0xc9ba,0xc9bb,0xc9bc,0xc9bd,0xc9be,
+    0xc9bf,0xc9c2,0xc9c3,0xc9c5,0xc9c6,0xc9c9,0xc9cb,0xc9cc,0xc9cd,0xc9ce,
+    0xc9cf,0xc9d2,0xc9d4,0xc9d7,0xc9d8,0xc9db,0xff01,0xff02,0xff03,0xff04,
+    0xff05,0xff06,0xff07,0xff08,0xff09,0xff0a,0xff0b,0xff0c,0xff0d,0xff0e,
+    0xff0f,0xff10,0xff11,0xff12,0xff13,0xff14,0xff15,0xff16,0xff17,0xff18,
+    0xff19,0xff1a,0xff1b,0xff1c,0xff1d,0xff1e,0xff1f,0xff20,0xff21,0xff22,
+    0xff23,0xff24,0xff25,0xff26,0xff27,0xff28,0xff29,0xff2a,0xff2b,0xff2c,
+    0xff2d,0xff2e,0xff2f,0xff30,0xff31,0xff32,0xff33,0xff34,0xff35,0xff36,
+    0xff37,0xff38,0xff39,0xff3a,0xff3b,0xffe6,0xff3d,0xff3e,0xff3f,0xff40,
+    0xff41,0xff42,0xff43,0xff44,0xff45,0xff46,0xff47,0xff48,0xff49,0xff4a,
+    0xff4b,0xff4c,0xff4d,0xff4e,0xff4f,0xff50,0xff51,0xff52,0xff53,0xff54,
+    0xff55,0xff56,0xff57,0xff58,0xff59,0xff5a,0xff5b,0xff5c,0xff5d,0xffe3
+  },
+  {				/* ku 24 */
+    0xc9de,0xc9df,0xc9e1,0xc9e3,0xc9e5,0xc9e6,0xc9e8,0xc9e9,0xc9ea,0xc9eb,
+    0xc9ee,0xc9f2,0xc9f3,0xc9f4,0xc9f5,0xc9f6,0xc9f7,0xc9fa,0xc9fb,0xc9fd,
+    0xc9fe,0xc9ff,0xca01,0xca02,0xca03,0xca04,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xca05,0xca06,0xca07,0xca0a,0xca0e,0xca0f,0xca10,0xca11,
+    0xca12,0xca13,0xca15,0xca16,0xca17,0xca19,0xca1a,0xca1b,0xca1c,0xca1d,
+    0xca1e,0xca1f,0xca20,0xca21,0xca22,0xca23,0xca24,0xca25,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xca26,0xca27,0xca28,0xca2a,0xca2b,0xca2c,
+    0xca2d,0xca2e,0xca2f,0xca30,0xca31,0xca32,0xca33,0xca34,0xca35,0xca36,
+    0xca37,0xca38,0xca39,0xca3a,0xca3b,0xca3c,0xca3d,0xca3e,0xca3f,0xca40,
+    0xca41,0xca42,0xca43,0xca44,0xca45,0xca46,0x3131,0x3132,0x3133,0x3134,
+    0x3135,0x3136,0x3137,0x3138,0x3139,0x313a,0x313b,0x313c,0x313d,0x313e,
+    0x313f,0x3140,0x3141,0x3142,0x3143,0x3144,0x3145,0x3146,0x3147,0x3148,
+    0x3149,0x314a,0x314b,0x314c,0x314d,0x314e,0x314f,0x3150,0x3151,0x3152,
+    0x3153,0x3154,0x3155,0x3156,0x3157,0x3158,0x3159,0x315a,0x315b,0x315c,
+    0x315d,0x315e,0x315f,0x3160,0x3161,0x3162,0x3163,0x3164,0x3165,0x3166,
+    0x3167,0x3168,0x3169,0x316a,0x316b,0x316c,0x316d,0x316e,0x316f,0x3170,
+    0x3171,0x3172,0x3173,0x3174,0x3175,0x3176,0x3177,0x3178,0x3179,0x317a,
+    0x317b,0x317c,0x317d,0x317e,0x317f,0x3180,0x3181,0x3182,0x3183,0x3184,
+    0x3185,0x3186,0x3187,0x3188,0x3189,0x318a,0x318b,0x318c,0x318d,0x318e
+  },
+  {				/* ku 25 */
+    0xca47,0xca48,0xca49,0xca4a,0xca4b,0xca4e,0xca4f,0xca51,0xca52,0xca53,
+    0xca55,0xca56,0xca57,0xca58,0xca59,0xca5a,0xca5b,0xca5e,0xca62,0xca63,
+    0xca64,0xca65,0xca66,0xca67,0xca69,0xca6a,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xca6b,0xca6c,0xca6d,0xca6e,0xca6f,0xca70,0xca71,0xca72,
+    0xca73,0xca74,0xca75,0xca76,0xca77,0xca78,0xca79,0xca7a,0xca7b,0xca7c,
+    0xca7e,0xca7f,0xca80,0xca81,0xca82,0xca83,0xca85,0xca86,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xca87,0xca88,0xca89,0xca8a,0xca8b,0xca8c,
+    0xca8d,0xca8e,0xca8f,0xca90,0xca91,0xca92,0xca93,0xca94,0xca95,0xca96,
+    0xca97,0xca99,0xca9a,0xca9b,0xca9c,0xca9d,0xca9e,0xca9f,0xcaa0,0xcaa1,
+    0xcaa2,0xcaa3,0xcaa4,0xcaa5,0xcaa6,0xcaa7,0x2170,0x2171,0x2172,0x2173,
+    0x2174,0x2175,0x2176,0x2177,0x2178,0x2179,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,
+    0x2169,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x0391,0x0392,
+    0x0393,0x0394,0x0395,0x0396,0x0397,0x0398,0x0399,0x039a,0x039b,0x039c,
+    0x039d,0x039e,0x039f,0x03a0,0x03a1,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,
+    0x03a8,0x03a9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8,0x03b9,0x03ba,
+    0x03bb,0x03bc,0x03bd,0x03be,0x03bf,0x03c0,0x03c1,0x03c3,0x03c4,0x03c5,
+    0x03c6,0x03c7,0x03c8,0x03c9,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 26 */
+    0xcaa8,0xcaa9,0xcaaa,0xcaab,0xcaac,0xcaad,0xcaae,0xcaaf,0xcab0,0xcab1,
+    0xcab2,0xcab3,0xcab4,0xcab5,0xcab6,0xcab7,0xcab8,0xcab9,0xcaba,0xcabb,
+    0xcabe,0xcabf,0xcac1,0xcac2,0xcac3,0xcac5,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xcac6,0xcac7,0xcac8,0xcac9,0xcaca,0xcacb,0xcace,0xcad0,
+    0xcad2,0xcad4,0xcad5,0xcad6,0xcad7,0xcada,0xcadb,0xcadc,0xcadd,0xcade,
+    0xcadf,0xcae1,0xcae2,0xcae3,0xcae4,0xcae5,0xcae6,0xcae7,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xcae8,0xcae9,0xcaea,0xcaeb,0xcaed,0xcaee,
+    0xcaef,0xcaf0,0xcaf1,0xcaf2,0xcaf3,0xcaf5,0xcaf6,0xcaf7,0xcaf8,0xcaf9,
+    0xcafa,0xcafb,0xcafc,0xcafd,0xcafe,0xcaff,0xcb00,0xcb01,0xcb02,0xcb03,
+    0xcb04,0xcb05,0xcb06,0xcb07,0xcb09,0xcb0a,0x2500,0x2502,0x250c,0x2510,
+    0x2518,0x2514,0x251c,0x252c,0x2524,0x2534,0x253c,0x2501,0x2503,0x250f,
+    0x2513,0x251b,0x2517,0x2523,0x2533,0x252b,0x253b,0x254b,0x2520,0x252f,
+    0x2528,0x2537,0x253f,0x251d,0x2530,0x2525,0x2538,0x2542,0x2512,0x2511,
+    0x251a,0x2519,0x2516,0x2515,0x250e,0x250d,0x251e,0x251f,0x2521,0x2522,
+    0x2526,0x2527,0x2529,0x252a,0x252d,0x252e,0x2531,0x2532,0x2535,0x2536,
+    0x2539,0x253a,0x253d,0x253e,0x2540,0x2541,0x2543,0x2544,0x2545,0x2546,
+    0x2547,0x2548,0x2549,0x254a,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 27 */
+    0xcb0b,0xcb0c,0xcb0d,0xcb0e,0xcb0f,0xcb11,0xcb12,0xcb13,0xcb15,0xcb16,
+    0xcb17,0xcb19,0xcb1a,0xcb1b,0xcb1c,0xcb1d,0xcb1e,0xcb1f,0xcb22,0xcb23,
+    0xcb24,0xcb25,0xcb26,0xcb27,0xcb28,0xcb29,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xcb2a,0xcb2b,0xcb2c,0xcb2d,0xcb2e,0xcb2f,0xcb30,0xcb31,
+    0xcb32,0xcb33,0xcb34,0xcb35,0xcb36,0xcb37,0xcb38,0xcb39,0xcb3a,0xcb3b,
+    0xcb3c,0xcb3d,0xcb3e,0xcb3f,0xcb40,0xcb42,0xcb43,0xcb44,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xcb45,0xcb46,0xcb47,0xcb4a,0xcb4b,0xcb4d,
+    0xcb4e,0xcb4f,0xcb51,0xcb52,0xcb53,0xcb54,0xcb55,0xcb56,0xcb57,0xcb5a,
+    0xcb5b,0xcb5c,0xcb5e,0xcb5f,0xcb60,0xcb61,0xcb62,0xcb63,0xcb65,0xcb66,
+    0xcb67,0xcb68,0xcb69,0xcb6a,0xcb6b,0xcb6c,0x3395,0x3396,0x3397,0x2113,
+    0x3398,0x33c4,0x33a3,0x33a4,0x33a5,0x33a6,0x3399,0x339a,0x339b,0x339c,
+    0x339d,0x339e,0x339f,0x33a0,0x33a1,0x33a2,0x33ca,0x338d,0x338e,0x338f,
+    0x33cf,0x3388,0x3389,0x33c8,0x33a7,0x33a8,0x33b0,0x33b1,0x33b2,0x33b3,
+    0x33b4,0x33b5,0x33b6,0x33b7,0x33b8,0x33b9,0x3380,0x3381,0x3382,0x3383,
+    0x3384,0x33ba,0x33bb,0x33bc,0x33bd,0x33be,0x33bf,0x3390,0x3391,0x3392,
+    0x3393,0x3394,0x2126,0x33c0,0x33c1,0x338a,0x338b,0x338c,0x33d6,0x33c5,
+    0x33ad,0x33ae,0x33af,0x33db,0x33a9,0x33aa,0x33ab,0x33ac,0x33dd,0x33d0,
+    0x33d3,0x33c3,0x33c9,0x33dc,0x33c6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 28 */
+    0xcb6d,0xcb6e,0xcb6f,0xcb70,0xcb71,0xcb72,0xcb73,0xcb74,0xcb75,0xcb76,
+    0xcb77,0xcb7a,0xcb7b,0xcb7c,0xcb7d,0xcb7e,0xcb7f,0xcb80,0xcb81,0xcb82,
+    0xcb83,0xcb84,0xcb85,0xcb86,0xcb87,0xcb88,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xcb89,0xcb8a,0xcb8b,0xcb8c,0xcb8d,0xcb8e,0xcb8f,0xcb90,
+    0xcb91,0xcb92,0xcb93,0xcb94,0xcb95,0xcb96,0xcb97,0xcb98,0xcb99,0xcb9a,
+    0xcb9b,0xcb9d,0xcb9e,0xcb9f,0xcba0,0xcba1,0xcba2,0xcba3,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xcba4,0xcba5,0xcba6,0xcba7,0xcba8,0xcba9,
+    0xcbaa,0xcbab,0xcbac,0xcbad,0xcbae,0xcbaf,0xcbb0,0xcbb1,0xcbb2,0xcbb3,
+    0xcbb4,0xcbb5,0xcbb6,0xcbb7,0xcbb9,0xcbba,0xcbbb,0xcbbc,0xcbbd,0xcbbe,
+    0xcbbf,0xcbc0,0xcbc1,0xcbc2,0xcbc3,0xcbc4,0x00c6,0x00d0,0x00aa,0x0126,
+    UBOGON,0x0132,UBOGON,0x013f,0x0141,0x00d8,0x0152,0x00ba,0x00de,0x0166,
+    0x014a,UBOGON,0x3260,0x3261,0x3262,0x3263,0x3264,0x3265,0x3266,0x3267,
+    0x3268,0x3269,0x326a,0x326b,0x326c,0x326d,0x326e,0x326f,0x3270,0x3271,
+    0x3272,0x3273,0x3274,0x3275,0x3276,0x3277,0x3278,0x3279,0x327a,0x327b,
+    0x24d0,0x24d1,0x24d2,0x24d3,0x24d4,0x24d5,0x24d6,0x24d7,0x24d8,0x24d9,
+    0x24da,0x24db,0x24dc,0x24dd,0x24de,0x24df,0x24e0,0x24e1,0x24e2,0x24e3,
+    0x24e4,0x24e5,0x24e6,0x24e7,0x24e8,0x24e9,0x2460,0x2461,0x2462,0x2463,
+    0x2464,0x2465,0x2466,0x2467,0x2468,0x2469,0x246a,0x246b,0x246c,0x246d,
+    0x246e,0x00bd,0x2153,0x2154,0x00bc,0x00be,0x215b,0x215c,0x215d,0x215e
+  },
+  {				/* ku 29 */
+    0xcbc5,0xcbc6,0xcbc7,0xcbc8,0xcbc9,0xcbca,0xcbcb,0xcbcc,0xcbcd,0xcbce,
+    0xcbcf,0xcbd0,0xcbd1,0xcbd2,0xcbd3,0xcbd5,0xcbd6,0xcbd7,0xcbd8,0xcbd9,
+    0xcbda,0xcbdb,0xcbdc,0xcbdd,0xcbde,0xcbdf,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xcbe0,0xcbe1,0xcbe2,0xcbe3,0xcbe5,0xcbe6,0xcbe8,0xcbea,
+    0xcbeb,0xcbec,0xcbed,0xcbee,0xcbef,0xcbf0,0xcbf1,0xcbf2,0xcbf3,0xcbf4,
+    0xcbf5,0xcbf6,0xcbf7,0xcbf8,0xcbf9,0xcbfa,0xcbfb,0xcbfc,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xcbfd,0xcbfe,0xcbff,0xcc00,0xcc01,0xcc02,
+    0xcc03,0xcc04,0xcc05,0xcc06,0xcc07,0xcc08,0xcc09,0xcc0a,0xcc0b,0xcc0e,
+    0xcc0f,0xcc11,0xcc12,0xcc13,0xcc15,0xcc16,0xcc17,0xcc18,0xcc19,0xcc1a,
+    0xcc1b,0xcc1e,0xcc1f,0xcc20,0xcc23,0xcc24,0x00e6,0x0111,0x00f0,0x0127,
+    0x0131,0x0133,0x0138,0x0140,0x0142,0x00f8,0x0153,0x00df,0x00fe,0x0167,
+    0x014b,0x0149,0x3200,0x3201,0x3202,0x3203,0x3204,0x3205,0x3206,0x3207,
+    0x3208,0x3209,0x320a,0x320b,0x320c,0x320d,0x320e,0x320f,0x3210,0x3211,
+    0x3212,0x3213,0x3214,0x3215,0x3216,0x3217,0x3218,0x3219,0x321a,0x321b,
+    0x249c,0x249d,0x249e,0x249f,0x24a0,0x24a1,0x24a2,0x24a3,0x24a4,0x24a5,
+    0x24a6,0x24a7,0x24a8,0x24a9,0x24aa,0x24ab,0x24ac,0x24ad,0x24ae,0x24af,
+    0x24b0,0x24b1,0x24b2,0x24b3,0x24b4,0x24b5,0x2474,0x2475,0x2476,0x2477,
+    0x2478,0x2479,0x247a,0x247b,0x247c,0x247d,0x247e,0x247f,0x2480,0x2481,
+    0x2482,0x00b9,0x00b2,0x00b3,0x2074,0x207f,0x2081,0x2082,0x2083,0x2084
+  },
+  {				/* ku 2a */
+    0xcc25,0xcc26,0xcc2a,0xcc2b,0xcc2d,0xcc2f,0xcc31,0xcc32,0xcc33,0xcc34,
+    0xcc35,0xcc36,0xcc37,0xcc3a,0xcc3f,0xcc40,0xcc41,0xcc42,0xcc43,0xcc46,
+    0xcc47,0xcc49,0xcc4a,0xcc4b,0xcc4d,0xcc4e,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xcc4f,0xcc50,0xcc51,0xcc52,0xcc53,0xcc56,0xcc5a,0xcc5b,
+    0xcc5c,0xcc5d,0xcc5e,0xcc5f,0xcc61,0xcc62,0xcc63,0xcc65,0xcc67,0xcc69,
+    0xcc6a,0xcc6b,0xcc6c,0xcc6d,0xcc6e,0xcc6f,0xcc71,0xcc72,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xcc73,0xcc74,0xcc76,0xcc77,0xcc78,0xcc79,
+    0xcc7a,0xcc7b,0xcc7c,0xcc7d,0xcc7e,0xcc7f,0xcc80,0xcc81,0xcc82,0xcc83,
+    0xcc84,0xcc85,0xcc86,0xcc87,0xcc88,0xcc89,0xcc8a,0xcc8b,0xcc8c,0xcc8d,
+    0xcc8e,0xcc8f,0xcc90,0xcc91,0xcc92,0xcc93,0x3041,0x3042,0x3043,0x3044,
+    0x3045,0x3046,0x3047,0x3048,0x3049,0x304a,0x304b,0x304c,0x304d,0x304e,
+    0x304f,0x3050,0x3051,0x3052,0x3053,0x3054,0x3055,0x3056,0x3057,0x3058,
+    0x3059,0x305a,0x305b,0x305c,0x305d,0x305e,0x305f,0x3060,0x3061,0x3062,
+    0x3063,0x3064,0x3065,0x3066,0x3067,0x3068,0x3069,0x306a,0x306b,0x306c,
+    0x306d,0x306e,0x306f,0x3070,0x3071,0x3072,0x3073,0x3074,0x3075,0x3076,
+    0x3077,0x3078,0x3079,0x307a,0x307b,0x307c,0x307d,0x307e,0x307f,0x3080,
+    0x3081,0x3082,0x3083,0x3084,0x3085,0x3086,0x3087,0x3088,0x3089,0x308a,
+    0x308b,0x308c,0x308d,0x308e,0x308f,0x3090,0x3091,0x3092,0x3093,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2b */
+    0xcc94,0xcc95,0xcc96,0xcc97,0xcc9a,0xcc9b,0xcc9d,0xcc9e,0xcc9f,0xcca1,
+    0xcca2,0xcca3,0xcca4,0xcca5,0xcca6,0xcca7,0xccaa,0xccae,0xccaf,0xccb0,
+    0xccb1,0xccb2,0xccb3,0xccb6,0xccb7,0xccb9,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xccba,0xccbb,0xccbd,0xccbe,0xccbf,0xccc0,0xccc1,0xccc2,
+    0xccc3,0xccc6,0xccc8,0xccca,0xcccb,0xcccc,0xcccd,0xccce,0xcccf,0xccd1,
+    0xccd2,0xccd3,0xccd5,0xccd6,0xccd7,0xccd8,0xccd9,0xccda,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xccdb,0xccdc,0xccdd,0xccde,0xccdf,0xcce0,
+    0xcce1,0xcce2,0xcce3,0xcce5,0xcce6,0xcce7,0xcce8,0xcce9,0xccea,0xcceb,
+    0xcced,0xccee,0xccef,0xccf1,0xccf2,0xccf3,0xccf4,0xccf5,0xccf6,0xccf7,
+    0xccf8,0xccf9,0xccfa,0xccfb,0xccfc,0xccfd,0x30a1,0x30a2,0x30a3,0x30a4,
+    0x30a5,0x30a6,0x30a7,0x30a8,0x30a9,0x30aa,0x30ab,0x30ac,0x30ad,0x30ae,
+    0x30af,0x30b0,0x30b1,0x30b2,0x30b3,0x30b4,0x30b5,0x30b6,0x30b7,0x30b8,
+    0x30b9,0x30ba,0x30bb,0x30bc,0x30bd,0x30be,0x30bf,0x30c0,0x30c1,0x30c2,
+    0x30c3,0x30c4,0x30c5,0x30c6,0x30c7,0x30c8,0x30c9,0x30ca,0x30cb,0x30cc,
+    0x30cd,0x30ce,0x30cf,0x30d0,0x30d1,0x30d2,0x30d3,0x30d4,0x30d5,0x30d6,
+    0x30d7,0x30d8,0x30d9,0x30da,0x30db,0x30dc,0x30dd,0x30de,0x30df,0x30e0,
+    0x30e1,0x30e2,0x30e3,0x30e4,0x30e5,0x30e6,0x30e7,0x30e8,0x30e9,0x30ea,
+    0x30eb,0x30ec,0x30ed,0x30ee,0x30ef,0x30f0,0x30f1,0x30f2,0x30f3,0x30f4,
+    0x30f5,0x30f6,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2c */
+    0xccfe,0xccff,0xcd00,0xcd02,0xcd03,0xcd04,0xcd05,0xcd06,0xcd07,0xcd0a,
+    0xcd0b,0xcd0d,0xcd0e,0xcd0f,0xcd11,0xcd12,0xcd13,0xcd14,0xcd15,0xcd16,
+    0xcd17,0xcd1a,0xcd1c,0xcd1e,0xcd1f,0xcd20,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xcd21,0xcd22,0xcd23,0xcd25,0xcd26,0xcd27,0xcd29,0xcd2a,
+    0xcd2b,0xcd2d,0xcd2e,0xcd2f,0xcd30,0xcd31,0xcd32,0xcd33,0xcd34,0xcd35,
+    0xcd36,0xcd37,0xcd38,0xcd3a,0xcd3b,0xcd3c,0xcd3d,0xcd3e,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xcd3f,0xcd40,0xcd41,0xcd42,0xcd43,0xcd44,
+    0xcd45,0xcd46,0xcd47,0xcd48,0xcd49,0xcd4a,0xcd4b,0xcd4c,0xcd4d,0xcd4e,
+    0xcd4f,0xcd50,0xcd51,0xcd52,0xcd53,0xcd54,0xcd55,0xcd56,0xcd57,0xcd58,
+    0xcd59,0xcd5a,0xcd5b,0xcd5d,0xcd5e,0xcd5f,0x0410,0x0411,0x0412,0x0413,
+    0x0414,0x0415,0x0401,0x0416,0x0417,0x0418,0x0419,0x041a,0x041b,0x041c,
+    0x041d,0x041e,0x041f,0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,
+    0x0427,0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,
+    0x0451,0x0436,0x0437,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,
+    0x043f,0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,0x0447,0x0448,
+    0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,0x044f,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2d */
+    0xcd61,0xcd62,0xcd63,0xcd65,0xcd66,0xcd67,0xcd68,0xcd69,0xcd6a,0xcd6b,
+    0xcd6e,0xcd70,0xcd72,0xcd73,0xcd74,0xcd75,0xcd76,0xcd77,0xcd79,0xcd7a,
+    0xcd7b,0xcd7c,0xcd7d,0xcd7e,0xcd7f,0xcd80,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xcd81,0xcd82,0xcd83,0xcd84,0xcd85,0xcd86,0xcd87,0xcd89,
+    0xcd8a,0xcd8b,0xcd8c,0xcd8d,0xcd8e,0xcd8f,0xcd90,0xcd91,0xcd92,0xcd93,
+    0xcd96,0xcd97,0xcd99,0xcd9a,0xcd9b,0xcd9d,0xcd9e,0xcd9f,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xcda0,0xcda1,0xcda2,0xcda3,0xcda6,0xcda8,
+    0xcdaa,0xcdab,0xcdac,0xcdad,0xcdae,0xcdaf,0xcdb1,0xcdb2,0xcdb3,0xcdb4,
+    0xcdb5,0xcdb6,0xcdb7,0xcdb8,0xcdb9,0xcdba,0xcdbb,0xcdbc,0xcdbd,0xcdbe,
+    0xcdbf,0xcdc0,0xcdc1,0xcdc2,0xcdc3,0xcdc5,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2e */
+    0xcdc6,0xcdc7,0xcdc8,0xcdc9,0xcdca,0xcdcb,0xcdcd,0xcdce,0xcdcf,0xcdd1,
+    0xcdd2,0xcdd3,0xcdd4,0xcdd5,0xcdd6,0xcdd7,0xcdd8,0xcdd9,0xcdda,0xcddb,
+    0xcddc,0xcddd,0xcdde,0xcddf,0xcde0,0xcde1,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xcde2,0xcde3,0xcde4,0xcde5,0xcde6,0xcde7,0xcde9,0xcdea,
+    0xcdeb,0xcded,0xcdee,0xcdef,0xcdf1,0xcdf2,0xcdf3,0xcdf4,0xcdf5,0xcdf6,
+    0xcdf7,0xcdfa,0xcdfc,0xcdfe,0xcdff,0xce00,0xce01,0xce02,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xce03,0xce05,0xce06,0xce07,0xce09,0xce0a,
+    0xce0b,0xce0d,0xce0e,0xce0f,0xce10,0xce11,0xce12,0xce13,0xce15,0xce16,
+    0xce17,0xce18,0xce1a,0xce1b,0xce1c,0xce1d,0xce1e,0xce1f,0xce22,0xce23,
+    0xce25,0xce26,0xce27,0xce29,0xce2a,0xce2b,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 2f */
+    0xce2c,0xce2d,0xce2e,0xce2f,0xce32,0xce34,0xce36,0xce37,0xce38,0xce39,
+    0xce3a,0xce3b,0xce3c,0xce3d,0xce3e,0xce3f,0xce40,0xce41,0xce42,0xce43,
+    0xce44,0xce45,0xce46,0xce47,0xce48,0xce49,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xce4a,0xce4b,0xce4c,0xce4d,0xce4e,0xce4f,0xce50,0xce51,
+    0xce52,0xce53,0xce54,0xce55,0xce56,0xce57,0xce5a,0xce5b,0xce5d,0xce5e,
+    0xce62,0xce63,0xce64,0xce65,0xce66,0xce67,0xce6a,0xce6c,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xce6e,0xce6f,0xce70,0xce71,0xce72,0xce73,
+    0xce76,0xce77,0xce79,0xce7a,0xce7b,0xce7d,0xce7e,0xce7f,0xce80,0xce81,
+    0xce82,0xce83,0xce86,0xce88,0xce8a,0xce8b,0xce8c,0xce8d,0xce8e,0xce8f,
+    0xce92,0xce93,0xce95,0xce96,0xce97,0xce99,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 30 */
+    0xce9a,0xce9b,0xce9c,0xce9d,0xce9e,0xce9f,0xcea2,0xcea6,0xcea7,0xcea8,
+    0xcea9,0xceaa,0xceab,0xceae,0xceaf,0xceb0,0xceb1,0xceb2,0xceb3,0xceb4,
+    0xceb5,0xceb6,0xceb7,0xceb8,0xceb9,0xceba,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xcebb,0xcebc,0xcebd,0xcebe,0xcebf,0xcec0,0xcec2,0xcec3,
+    0xcec4,0xcec5,0xcec6,0xcec7,0xcec8,0xcec9,0xceca,0xcecb,0xcecc,0xcecd,
+    0xcece,0xcecf,0xced0,0xced1,0xced2,0xced3,0xced4,0xced5,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xced6,0xced7,0xced8,0xced9,0xceda,0xcedb,
+    0xcedc,0xcedd,0xcede,0xcedf,0xcee0,0xcee1,0xcee2,0xcee3,0xcee6,0xcee7,
+    0xcee9,0xceea,0xceed,0xceee,0xceef,0xcef0,0xcef1,0xcef2,0xcef3,0xcef6,
+    0xcefa,0xcefb,0xcefc,0xcefd,0xcefe,0xceff,0xac00,0xac01,0xac04,0xac07,
+    0xac08,0xac09,0xac0a,0xac10,0xac11,0xac12,0xac13,0xac14,0xac15,0xac16,
+    0xac17,0xac19,0xac1a,0xac1b,0xac1c,0xac1d,0xac20,0xac24,0xac2c,0xac2d,
+    0xac2f,0xac30,0xac31,0xac38,0xac39,0xac3c,0xac40,0xac4b,0xac4d,0xac54,
+    0xac58,0xac5c,0xac70,0xac71,0xac74,0xac77,0xac78,0xac7a,0xac80,0xac81,
+    0xac83,0xac84,0xac85,0xac86,0xac89,0xac8a,0xac8b,0xac8c,0xac90,0xac94,
+    0xac9c,0xac9d,0xac9f,0xaca0,0xaca1,0xaca8,0xaca9,0xacaa,0xacac,0xacaf,
+    0xacb0,0xacb8,0xacb9,0xacbb,0xacbc,0xacbd,0xacc1,0xacc4,0xacc8,0xaccc,
+    0xacd5,0xacd7,0xace0,0xace1,0xace4,0xace7,0xace8,0xacea,0xacec,0xacef,
+    0xacf0,0xacf1,0xacf3,0xacf5,0xacf6,0xacfc,0xacfd,0xad00,0xad04,0xad06
+  },
+  {				/* ku 31 */
+    0xcf02,0xcf03,0xcf05,0xcf06,0xcf07,0xcf09,0xcf0a,0xcf0b,0xcf0c,0xcf0d,
+    0xcf0e,0xcf0f,0xcf12,0xcf14,0xcf16,0xcf17,0xcf18,0xcf19,0xcf1a,0xcf1b,
+    0xcf1d,0xcf1e,0xcf1f,0xcf21,0xcf22,0xcf23,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xcf25,0xcf26,0xcf27,0xcf28,0xcf29,0xcf2a,0xcf2b,0xcf2e,
+    0xcf32,0xcf33,0xcf34,0xcf35,0xcf36,0xcf37,0xcf39,0xcf3a,0xcf3b,0xcf3c,
+    0xcf3d,0xcf3e,0xcf3f,0xcf40,0xcf41,0xcf42,0xcf43,0xcf44,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xcf45,0xcf46,0xcf47,0xcf48,0xcf49,0xcf4a,
+    0xcf4b,0xcf4c,0xcf4d,0xcf4e,0xcf4f,0xcf50,0xcf51,0xcf52,0xcf53,0xcf56,
+    0xcf57,0xcf59,0xcf5a,0xcf5b,0xcf5d,0xcf5e,0xcf5f,0xcf60,0xcf61,0xcf62,
+    0xcf63,0xcf66,0xcf68,0xcf6a,0xcf6b,0xcf6c,0xad0c,0xad0d,0xad0f,0xad11,
+    0xad18,0xad1c,0xad20,0xad29,0xad2c,0xad2d,0xad34,0xad35,0xad38,0xad3c,
+    0xad44,0xad45,0xad47,0xad49,0xad50,0xad54,0xad58,0xad61,0xad63,0xad6c,
+    0xad6d,0xad70,0xad73,0xad74,0xad75,0xad76,0xad7b,0xad7c,0xad7d,0xad7f,
+    0xad81,0xad82,0xad88,0xad89,0xad8c,0xad90,0xad9c,0xad9d,0xada4,0xadb7,
+    0xadc0,0xadc1,0xadc4,0xadc8,0xadd0,0xadd1,0xadd3,0xaddc,0xade0,0xade4,
+    0xadf8,0xadf9,0xadfc,0xadff,0xae00,0xae01,0xae08,0xae09,0xae0b,0xae0d,
+    0xae14,0xae30,0xae31,0xae34,0xae37,0xae38,0xae3a,0xae40,0xae41,0xae43,
+    0xae45,0xae46,0xae4a,0xae4c,0xae4d,0xae4e,0xae50,0xae54,0xae56,0xae5c,
+    0xae5d,0xae5f,0xae60,0xae61,0xae65,0xae68,0xae69,0xae6c,0xae70,0xae78
+  },
+  {				/* ku 32 */
+    0xcf6d,0xcf6e,0xcf6f,0xcf72,0xcf73,0xcf75,0xcf76,0xcf77,0xcf79,0xcf7a,
+    0xcf7b,0xcf7c,0xcf7d,0xcf7e,0xcf7f,0xcf81,0xcf82,0xcf83,0xcf84,0xcf86,
+    0xcf87,0xcf88,0xcf89,0xcf8a,0xcf8b,0xcf8d,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xcf8e,0xcf8f,0xcf90,0xcf91,0xcf92,0xcf93,0xcf94,0xcf95,
+    0xcf96,0xcf97,0xcf98,0xcf99,0xcf9a,0xcf9b,0xcf9c,0xcf9d,0xcf9e,0xcf9f,
+    0xcfa0,0xcfa2,0xcfa3,0xcfa4,0xcfa5,0xcfa6,0xcfa7,0xcfa9,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xcfaa,0xcfab,0xcfac,0xcfad,0xcfae,0xcfaf,
+    0xcfb1,0xcfb2,0xcfb3,0xcfb4,0xcfb5,0xcfb6,0xcfb7,0xcfb8,0xcfb9,0xcfba,
+    0xcfbb,0xcfbc,0xcfbd,0xcfbe,0xcfbf,0xcfc0,0xcfc1,0xcfc2,0xcfc3,0xcfc5,
+    0xcfc6,0xcfc7,0xcfc8,0xcfc9,0xcfca,0xcfcb,0xae79,0xae7b,0xae7c,0xae7d,
+    0xae84,0xae85,0xae8c,0xaebc,0xaebd,0xaebe,0xaec0,0xaec4,0xaecc,0xaecd,
+    0xaecf,0xaed0,0xaed1,0xaed8,0xaed9,0xaedc,0xaee8,0xaeeb,0xaeed,0xaef4,
+    0xaef8,0xaefc,0xaf07,0xaf08,0xaf0d,0xaf10,0xaf2c,0xaf2d,0xaf30,0xaf32,
+    0xaf34,0xaf3c,0xaf3d,0xaf3f,0xaf41,0xaf42,0xaf43,0xaf48,0xaf49,0xaf50,
+    0xaf5c,0xaf5d,0xaf64,0xaf65,0xaf79,0xaf80,0xaf84,0xaf88,0xaf90,0xaf91,
+    0xaf95,0xaf9c,0xafb8,0xafb9,0xafbc,0xafc0,0xafc7,0xafc8,0xafc9,0xafcb,
+    0xafcd,0xafce,0xafd4,0xafdc,0xafe8,0xafe9,0xaff0,0xaff1,0xaff4,0xaff8,
+    0xb000,0xb001,0xb004,0xb00c,0xb010,0xb014,0xb01c,0xb01d,0xb028,0xb044,
+    0xb045,0xb048,0xb04a,0xb04c,0xb04e,0xb053,0xb054,0xb055,0xb057,0xb059
+  },
+  {				/* ku 33 */
+    0xcfcc,0xcfcd,0xcfce,0xcfcf,0xcfd0,0xcfd1,0xcfd2,0xcfd3,0xcfd4,0xcfd5,
+    0xcfd6,0xcfd7,0xcfd8,0xcfd9,0xcfda,0xcfdb,0xcfdc,0xcfdd,0xcfde,0xcfdf,
+    0xcfe2,0xcfe3,0xcfe5,0xcfe6,0xcfe7,0xcfe9,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xcfea,0xcfeb,0xcfec,0xcfed,0xcfee,0xcfef,0xcff2,0xcff4,
+    0xcff6,0xcff7,0xcff8,0xcff9,0xcffa,0xcffb,0xcffd,0xcffe,0xcfff,0xd001,
+    0xd002,0xd003,0xd005,0xd006,0xd007,0xd008,0xd009,0xd00a,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xd00b,0xd00c,0xd00d,0xd00e,0xd00f,0xd010,
+    0xd012,0xd013,0xd014,0xd015,0xd016,0xd017,0xd019,0xd01a,0xd01b,0xd01c,
+    0xd01d,0xd01e,0xd01f,0xd020,0xd021,0xd022,0xd023,0xd024,0xd025,0xd026,
+    0xd027,0xd028,0xd029,0xd02a,0xd02b,0xd02c,0xb05d,0xb07c,0xb07d,0xb080,
+    0xb084,0xb08c,0xb08d,0xb08f,0xb091,0xb098,0xb099,0xb09a,0xb09c,0xb09f,
+    0xb0a0,0xb0a1,0xb0a2,0xb0a8,0xb0a9,0xb0ab,0xb0ac,0xb0ad,0xb0ae,0xb0af,
+    0xb0b1,0xb0b3,0xb0b4,0xb0b5,0xb0b8,0xb0bc,0xb0c4,0xb0c5,0xb0c7,0xb0c8,
+    0xb0c9,0xb0d0,0xb0d1,0xb0d4,0xb0d8,0xb0e0,0xb0e5,0xb108,0xb109,0xb10b,
+    0xb10c,0xb110,0xb112,0xb113,0xb118,0xb119,0xb11b,0xb11c,0xb11d,0xb123,
+    0xb124,0xb125,0xb128,0xb12c,0xb134,0xb135,0xb137,0xb138,0xb139,0xb140,
+    0xb141,0xb144,0xb148,0xb150,0xb151,0xb154,0xb155,0xb158,0xb15c,0xb160,
+    0xb178,0xb179,0xb17c,0xb180,0xb182,0xb188,0xb189,0xb18b,0xb18d,0xb192,
+    0xb193,0xb194,0xb198,0xb19c,0xb1a8,0xb1cc,0xb1d0,0xb1d4,0xb1dc,0xb1dd
+  },
+  {				/* ku 34 */
+    0xd02e,0xd02f,0xd030,0xd031,0xd032,0xd033,0xd036,0xd037,0xd039,0xd03a,
+    0xd03b,0xd03d,0xd03e,0xd03f,0xd040,0xd041,0xd042,0xd043,0xd046,0xd048,
+    0xd04a,0xd04b,0xd04c,0xd04d,0xd04e,0xd04f,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xd051,0xd052,0xd053,0xd055,0xd056,0xd057,0xd059,0xd05a,
+    0xd05b,0xd05c,0xd05d,0xd05e,0xd05f,0xd061,0xd062,0xd063,0xd064,0xd065,
+    0xd066,0xd067,0xd068,0xd069,0xd06a,0xd06b,0xd06e,0xd06f,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xd071,0xd072,0xd073,0xd075,0xd076,0xd077,
+    0xd078,0xd079,0xd07a,0xd07b,0xd07e,0xd07f,0xd080,0xd082,0xd083,0xd084,
+    0xd085,0xd086,0xd087,0xd088,0xd089,0xd08a,0xd08b,0xd08c,0xd08d,0xd08e,
+    0xd08f,0xd090,0xd091,0xd092,0xd093,0xd094,0xb1df,0xb1e8,0xb1e9,0xb1ec,
+    0xb1f0,0xb1f9,0xb1fb,0xb1fd,0xb204,0xb205,0xb208,0xb20b,0xb20c,0xb214,
+    0xb215,0xb217,0xb219,0xb220,0xb234,0xb23c,0xb258,0xb25c,0xb260,0xb268,
+    0xb269,0xb274,0xb275,0xb27c,0xb284,0xb285,0xb289,0xb290,0xb291,0xb294,
+    0xb298,0xb299,0xb29a,0xb2a0,0xb2a1,0xb2a3,0xb2a5,0xb2a6,0xb2aa,0xb2ac,
+    0xb2b0,0xb2b4,0xb2c8,0xb2c9,0xb2cc,0xb2d0,0xb2d2,0xb2d8,0xb2d9,0xb2db,
+    0xb2dd,0xb2e2,0xb2e4,0xb2e5,0xb2e6,0xb2e8,0xb2eb,0xb2ec,0xb2ed,0xb2ee,
+    0xb2ef,0xb2f3,0xb2f4,0xb2f5,0xb2f7,0xb2f8,0xb2f9,0xb2fa,0xb2fb,0xb2ff,
+    0xb300,0xb301,0xb304,0xb308,0xb310,0xb311,0xb313,0xb314,0xb315,0xb31c,
+    0xb354,0xb355,0xb356,0xb358,0xb35b,0xb35c,0xb35e,0xb35f,0xb364,0xb365
+  },
+  {				/* ku 35 */
+    0xd095,0xd096,0xd097,0xd098,0xd099,0xd09a,0xd09b,0xd09c,0xd09d,0xd09e,
+    0xd09f,0xd0a0,0xd0a1,0xd0a2,0xd0a3,0xd0a6,0xd0a7,0xd0a9,0xd0aa,0xd0ab,
+    0xd0ad,0xd0ae,0xd0af,0xd0b0,0xd0b1,0xd0b2,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xd0b3,0xd0b6,0xd0b8,0xd0ba,0xd0bb,0xd0bc,0xd0bd,0xd0be,
+    0xd0bf,0xd0c2,0xd0c3,0xd0c5,0xd0c6,0xd0c7,0xd0ca,0xd0cb,0xd0cc,0xd0cd,
+    0xd0ce,0xd0cf,0xd0d2,0xd0d6,0xd0d7,0xd0d8,0xd0d9,0xd0da,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xd0db,0xd0de,0xd0df,0xd0e1,0xd0e2,0xd0e3,
+    0xd0e5,0xd0e6,0xd0e7,0xd0e8,0xd0e9,0xd0ea,0xd0eb,0xd0ee,0xd0f2,0xd0f3,
+    0xd0f4,0xd0f5,0xd0f6,0xd0f7,0xd0f9,0xd0fa,0xd0fb,0xd0fc,0xd0fd,0xd0fe,
+    0xd0ff,0xd100,0xd101,0xd102,0xd103,0xd104,0xb367,0xb369,0xb36b,0xb36e,
+    0xb370,0xb371,0xb374,0xb378,0xb380,0xb381,0xb383,0xb384,0xb385,0xb38c,
+    0xb390,0xb394,0xb3a0,0xb3a1,0xb3a8,0xb3ac,0xb3c4,0xb3c5,0xb3c8,0xb3cb,
+    0xb3cc,0xb3ce,0xb3d0,0xb3d4,0xb3d5,0xb3d7,0xb3d9,0xb3db,0xb3dd,0xb3e0,
+    0xb3e4,0xb3e8,0xb3fc,0xb410,0xb418,0xb41c,0xb420,0xb428,0xb429,0xb42b,
+    0xb434,0xb450,0xb451,0xb454,0xb458,0xb460,0xb461,0xb463,0xb465,0xb46c,
+    0xb480,0xb488,0xb49d,0xb4a4,0xb4a8,0xb4ac,0xb4b5,0xb4b7,0xb4b9,0xb4c0,
+    0xb4c4,0xb4c8,0xb4d0,0xb4d5,0xb4dc,0xb4dd,0xb4e0,0xb4e3,0xb4e4,0xb4e6,
+    0xb4ec,0xb4ed,0xb4ef,0xb4f1,0xb4f8,0xb514,0xb515,0xb518,0xb51b,0xb51c,
+    0xb524,0xb525,0xb527,0xb528,0xb529,0xb52a,0xb530,0xb531,0xb534,0xb538
+  },
+  {				/* ku 36 */
+    0xd105,0xd106,0xd107,0xd108,0xd109,0xd10a,0xd10b,0xd10c,0xd10e,0xd10f,
+    0xd110,0xd111,0xd112,0xd113,0xd114,0xd115,0xd116,0xd117,0xd118,0xd119,
+    0xd11a,0xd11b,0xd11c,0xd11d,0xd11e,0xd11f,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xd120,0xd121,0xd122,0xd123,0xd124,0xd125,0xd126,0xd127,
+    0xd128,0xd129,0xd12a,0xd12b,0xd12c,0xd12d,0xd12e,0xd12f,0xd132,0xd133,
+    0xd135,0xd136,0xd137,0xd139,0xd13b,0xd13c,0xd13d,0xd13e,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xd13f,0xd142,0xd146,0xd147,0xd148,0xd149,
+    0xd14a,0xd14b,0xd14e,0xd14f,0xd151,0xd152,0xd153,0xd155,0xd156,0xd157,
+    0xd158,0xd159,0xd15a,0xd15b,0xd15e,0xd160,0xd162,0xd163,0xd164,0xd165,
+    0xd166,0xd167,0xd169,0xd16a,0xd16b,0xd16d,0xb540,0xb541,0xb543,0xb544,
+    0xb545,0xb54b,0xb54c,0xb54d,0xb550,0xb554,0xb55c,0xb55d,0xb55f,0xb560,
+    0xb561,0xb5a0,0xb5a1,0xb5a4,0xb5a8,0xb5aa,0xb5ab,0xb5b0,0xb5b1,0xb5b3,
+    0xb5b4,0xb5b5,0xb5bb,0xb5bc,0xb5bd,0xb5c0,0xb5c4,0xb5cc,0xb5cd,0xb5cf,
+    0xb5d0,0xb5d1,0xb5d8,0xb5ec,0xb610,0xb611,0xb614,0xb618,0xb625,0xb62c,
+    0xb634,0xb648,0xb664,0xb668,0xb69c,0xb69d,0xb6a0,0xb6a4,0xb6ab,0xb6ac,
+    0xb6b1,0xb6d4,0xb6f0,0xb6f4,0xb6f8,0xb700,0xb701,0xb705,0xb728,0xb729,
+    0xb72c,0xb72f,0xb730,0xb738,0xb739,0xb73b,0xb744,0xb748,0xb74c,0xb754,
+    0xb755,0xb760,0xb764,0xb768,0xb770,0xb771,0xb773,0xb775,0xb77c,0xb77d,
+    0xb780,0xb784,0xb78c,0xb78d,0xb78f,0xb790,0xb791,0xb792,0xb796,0xb797
+  },
+  {				/* ku 37 */
+    0xd16e,0xd16f,0xd170,0xd171,0xd172,0xd173,0xd174,0xd175,0xd176,0xd177,
+    0xd178,0xd179,0xd17a,0xd17b,0xd17d,0xd17e,0xd17f,0xd180,0xd181,0xd182,
+    0xd183,0xd185,0xd186,0xd187,0xd189,0xd18a,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xd18b,0xd18c,0xd18d,0xd18e,0xd18f,0xd190,0xd191,0xd192,
+    0xd193,0xd194,0xd195,0xd196,0xd197,0xd198,0xd199,0xd19a,0xd19b,0xd19c,
+    0xd19d,0xd19e,0xd19f,0xd1a2,0xd1a3,0xd1a5,0xd1a6,0xd1a7,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xd1a9,0xd1aa,0xd1ab,0xd1ac,0xd1ad,0xd1ae,
+    0xd1af,0xd1b2,0xd1b4,0xd1b6,0xd1b7,0xd1b8,0xd1b9,0xd1bb,0xd1bd,0xd1be,
+    0xd1bf,0xd1c1,0xd1c2,0xd1c3,0xd1c4,0xd1c5,0xd1c6,0xd1c7,0xd1c8,0xd1c9,
+    0xd1ca,0xd1cb,0xd1cc,0xd1cd,0xd1ce,0xd1cf,0xb798,0xb799,0xb79c,0xb7a0,
+    0xb7a8,0xb7a9,0xb7ab,0xb7ac,0xb7ad,0xb7b4,0xb7b5,0xb7b8,0xb7c7,0xb7c9,
+    0xb7ec,0xb7ed,0xb7f0,0xb7f4,0xb7fc,0xb7fd,0xb7ff,0xb800,0xb801,0xb807,
+    0xb808,0xb809,0xb80c,0xb810,0xb818,0xb819,0xb81b,0xb81d,0xb824,0xb825,
+    0xb828,0xb82c,0xb834,0xb835,0xb837,0xb838,0xb839,0xb840,0xb844,0xb851,
+    0xb853,0xb85c,0xb85d,0xb860,0xb864,0xb86c,0xb86d,0xb86f,0xb871,0xb878,
+    0xb87c,0xb88d,0xb8a8,0xb8b0,0xb8b4,0xb8b8,0xb8c0,0xb8c1,0xb8c3,0xb8c5,
+    0xb8cc,0xb8d0,0xb8d4,0xb8dd,0xb8df,0xb8e1,0xb8e8,0xb8e9,0xb8ec,0xb8f0,
+    0xb8f8,0xb8f9,0xb8fb,0xb8fd,0xb904,0xb918,0xb920,0xb93c,0xb93d,0xb940,
+    0xb944,0xb94c,0xb94f,0xb951,0xb958,0xb959,0xb95c,0xb960,0xb968,0xb969
+  },
+  {				/* ku 38 */
+    0xd1d0,0xd1d1,0xd1d2,0xd1d3,0xd1d4,0xd1d5,0xd1d6,0xd1d7,0xd1d9,0xd1da,
+    0xd1db,0xd1dc,0xd1dd,0xd1de,0xd1df,0xd1e0,0xd1e1,0xd1e2,0xd1e3,0xd1e4,
+    0xd1e5,0xd1e6,0xd1e7,0xd1e8,0xd1e9,0xd1ea,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xd1eb,0xd1ec,0xd1ed,0xd1ee,0xd1ef,0xd1f0,0xd1f1,0xd1f2,
+    0xd1f3,0xd1f5,0xd1f6,0xd1f7,0xd1f9,0xd1fa,0xd1fb,0xd1fc,0xd1fd,0xd1fe,
+    0xd1ff,0xd200,0xd201,0xd202,0xd203,0xd204,0xd205,0xd206,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xd208,0xd20a,0xd20b,0xd20c,0xd20d,0xd20e,
+    0xd20f,0xd211,0xd212,0xd213,0xd214,0xd215,0xd216,0xd217,0xd218,0xd219,
+    0xd21a,0xd21b,0xd21c,0xd21d,0xd21e,0xd21f,0xd220,0xd221,0xd222,0xd223,
+    0xd224,0xd225,0xd226,0xd227,0xd228,0xd229,0xb96b,0xb96d,0xb974,0xb975,
+    0xb978,0xb97c,0xb984,0xb985,0xb987,0xb989,0xb98a,0xb98d,0xb98e,0xb9ac,
+    0xb9ad,0xb9b0,0xb9b4,0xb9bc,0xb9bd,0xb9bf,0xb9c1,0xb9c8,0xb9c9,0xb9cc,
+    0xb9ce,0xb9cf,0xb9d0,0xb9d1,0xb9d2,0xb9d8,0xb9d9,0xb9db,0xb9dd,0xb9de,
+    0xb9e1,0xb9e3,0xb9e4,0xb9e5,0xb9e8,0xb9ec,0xb9f4,0xb9f5,0xb9f7,0xb9f8,
+    0xb9f9,0xb9fa,0xba00,0xba01,0xba08,0xba15,0xba38,0xba39,0xba3c,0xba40,
+    0xba42,0xba48,0xba49,0xba4b,0xba4d,0xba4e,0xba53,0xba54,0xba55,0xba58,
+    0xba5c,0xba64,0xba65,0xba67,0xba68,0xba69,0xba70,0xba71,0xba74,0xba78,
+    0xba83,0xba84,0xba85,0xba87,0xba8c,0xbaa8,0xbaa9,0xbaab,0xbaac,0xbab0,
+    0xbab2,0xbab8,0xbab9,0xbabb,0xbabd,0xbac4,0xbac8,0xbad8,0xbad9,0xbafc
+  },
+  {				/* ku 39 */
+    0xd22a,0xd22b,0xd22e,0xd22f,0xd231,0xd232,0xd233,0xd235,0xd236,0xd237,
+    0xd238,0xd239,0xd23a,0xd23b,0xd23e,0xd240,0xd242,0xd243,0xd244,0xd245,
+    0xd246,0xd247,0xd249,0xd24a,0xd24b,0xd24c,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xd24d,0xd24e,0xd24f,0xd250,0xd251,0xd252,0xd253,0xd254,
+    0xd255,0xd256,0xd257,0xd258,0xd259,0xd25a,0xd25b,0xd25d,0xd25e,0xd25f,
+    0xd260,0xd261,0xd262,0xd263,0xd265,0xd266,0xd267,0xd268,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xd269,0xd26a,0xd26b,0xd26c,0xd26d,0xd26e,
+    0xd26f,0xd270,0xd271,0xd272,0xd273,0xd274,0xd275,0xd276,0xd277,0xd278,
+    0xd279,0xd27a,0xd27b,0xd27c,0xd27d,0xd27e,0xd27f,0xd282,0xd283,0xd285,
+    0xd286,0xd287,0xd289,0xd28a,0xd28b,0xd28c,0xbb00,0xbb04,0xbb0d,0xbb0f,
+    0xbb11,0xbb18,0xbb1c,0xbb20,0xbb29,0xbb2b,0xbb34,0xbb35,0xbb36,0xbb38,
+    0xbb3b,0xbb3c,0xbb3d,0xbb3e,0xbb44,0xbb45,0xbb47,0xbb49,0xbb4d,0xbb4f,
+    0xbb50,0xbb54,0xbb58,0xbb61,0xbb63,0xbb6c,0xbb88,0xbb8c,0xbb90,0xbba4,
+    0xbba8,0xbbac,0xbbb4,0xbbb7,0xbbc0,0xbbc4,0xbbc8,0xbbd0,0xbbd3,0xbbf8,
+    0xbbf9,0xbbfc,0xbbff,0xbc00,0xbc02,0xbc08,0xbc09,0xbc0b,0xbc0c,0xbc0d,
+    0xbc0f,0xbc11,0xbc14,0xbc15,0xbc16,0xbc17,0xbc18,0xbc1b,0xbc1c,0xbc1d,
+    0xbc1e,0xbc1f,0xbc24,0xbc25,0xbc27,0xbc29,0xbc2d,0xbc30,0xbc31,0xbc34,
+    0xbc38,0xbc40,0xbc41,0xbc43,0xbc44,0xbc45,0xbc49,0xbc4c,0xbc4d,0xbc50,
+    0xbc5d,0xbc84,0xbc85,0xbc88,0xbc8b,0xbc8c,0xbc8e,0xbc94,0xbc95,0xbc97
+  },
+  {				/* ku 3a */
+    0xd28d,0xd28e,0xd28f,0xd292,0xd293,0xd294,0xd296,0xd297,0xd298,0xd299,
+    0xd29a,0xd29b,0xd29d,0xd29e,0xd29f,0xd2a1,0xd2a2,0xd2a3,0xd2a5,0xd2a6,
+    0xd2a7,0xd2a8,0xd2a9,0xd2aa,0xd2ab,0xd2ad,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xd2ae,0xd2af,0xd2b0,0xd2b2,0xd2b3,0xd2b4,0xd2b5,0xd2b6,
+    0xd2b7,0xd2ba,0xd2bb,0xd2bd,0xd2be,0xd2c1,0xd2c3,0xd2c4,0xd2c5,0xd2c6,
+    0xd2c7,0xd2ca,0xd2cc,0xd2cd,0xd2ce,0xd2cf,0xd2d0,0xd2d1,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xd2d2,0xd2d3,0xd2d5,0xd2d6,0xd2d7,0xd2d9,
+    0xd2da,0xd2db,0xd2dd,0xd2de,0xd2df,0xd2e0,0xd2e1,0xd2e2,0xd2e3,0xd2e6,
+    0xd2e7,0xd2e8,0xd2e9,0xd2ea,0xd2eb,0xd2ec,0xd2ed,0xd2ee,0xd2ef,0xd2f2,
+    0xd2f3,0xd2f5,0xd2f6,0xd2f7,0xd2f9,0xd2fa,0xbc99,0xbc9a,0xbca0,0xbca1,
+    0xbca4,0xbca7,0xbca8,0xbcb0,0xbcb1,0xbcb3,0xbcb4,0xbcb5,0xbcbc,0xbcbd,
+    0xbcc0,0xbcc4,0xbccd,0xbccf,0xbcd0,0xbcd1,0xbcd5,0xbcd8,0xbcdc,0xbcf4,
+    0xbcf5,0xbcf6,0xbcf8,0xbcfc,0xbd04,0xbd05,0xbd07,0xbd09,0xbd10,0xbd14,
+    0xbd24,0xbd2c,0xbd40,0xbd48,0xbd49,0xbd4c,0xbd50,0xbd58,0xbd59,0xbd64,
+    0xbd68,0xbd80,0xbd81,0xbd84,0xbd87,0xbd88,0xbd89,0xbd8a,0xbd90,0xbd91,
+    0xbd93,0xbd95,0xbd99,0xbd9a,0xbd9c,0xbda4,0xbdb0,0xbdb8,0xbdd4,0xbdd5,
+    0xbdd8,0xbddc,0xbde9,0xbdf0,0xbdf4,0xbdf8,0xbe00,0xbe03,0xbe05,0xbe0c,
+    0xbe0d,0xbe10,0xbe14,0xbe1c,0xbe1d,0xbe1f,0xbe44,0xbe45,0xbe48,0xbe4c,
+    0xbe4e,0xbe54,0xbe55,0xbe57,0xbe59,0xbe5a,0xbe5b,0xbe60,0xbe61,0xbe64
+  },
+  {				/* ku 3b */
+    0xd2fb,0xd2fc,0xd2fd,0xd2fe,0xd2ff,0xd302,0xd304,0xd306,0xd307,0xd308,
+    0xd309,0xd30a,0xd30b,0xd30f,0xd311,0xd312,0xd313,0xd315,0xd317,0xd318,
+    0xd319,0xd31a,0xd31b,0xd31e,0xd322,0xd323,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xd324,0xd326,0xd327,0xd32a,0xd32b,0xd32d,0xd32e,0xd32f,
+    0xd331,0xd332,0xd333,0xd334,0xd335,0xd336,0xd337,0xd33a,0xd33e,0xd33f,
+    0xd340,0xd341,0xd342,0xd343,0xd346,0xd347,0xd348,0xd349,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xd34a,0xd34b,0xd34c,0xd34d,0xd34e,0xd34f,
+    0xd350,0xd351,0xd352,0xd353,0xd354,0xd355,0xd356,0xd357,0xd358,0xd359,
+    0xd35a,0xd35b,0xd35c,0xd35d,0xd35e,0xd35f,0xd360,0xd361,0xd362,0xd363,
+    0xd364,0xd365,0xd366,0xd367,0xd368,0xd369,0xbe68,0xbe6a,0xbe70,0xbe71,
+    0xbe73,0xbe74,0xbe75,0xbe7b,0xbe7c,0xbe7d,0xbe80,0xbe84,0xbe8c,0xbe8d,
+    0xbe8f,0xbe90,0xbe91,0xbe98,0xbe99,0xbea8,0xbed0,0xbed1,0xbed4,0xbed7,
+    0xbed8,0xbee0,0xbee3,0xbee4,0xbee5,0xbeec,0xbf01,0xbf08,0xbf09,0xbf18,
+    0xbf19,0xbf1b,0xbf1c,0xbf1d,0xbf40,0xbf41,0xbf44,0xbf48,0xbf50,0xbf51,
+    0xbf55,0xbf94,0xbfb0,0xbfc5,0xbfcc,0xbfcd,0xbfd0,0xbfd4,0xbfdc,0xbfdf,
+    0xbfe1,0xc03c,0xc051,0xc058,0xc05c,0xc060,0xc068,0xc069,0xc090,0xc091,
+    0xc094,0xc098,0xc0a0,0xc0a1,0xc0a3,0xc0a5,0xc0ac,0xc0ad,0xc0af,0xc0b0,
+    0xc0b3,0xc0b4,0xc0b5,0xc0b6,0xc0bc,0xc0bd,0xc0bf,0xc0c0,0xc0c1,0xc0c5,
+    0xc0c8,0xc0c9,0xc0cc,0xc0d0,0xc0d8,0xc0d9,0xc0db,0xc0dc,0xc0dd,0xc0e4
+  },
+  {				/* ku 3c */
+    0xd36a,0xd36b,0xd36c,0xd36d,0xd36e,0xd36f,0xd370,0xd371,0xd372,0xd373,
+    0xd374,0xd375,0xd376,0xd377,0xd378,0xd379,0xd37a,0xd37b,0xd37e,0xd37f,
+    0xd381,0xd382,0xd383,0xd385,0xd386,0xd387,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xd388,0xd389,0xd38a,0xd38b,0xd38e,0xd392,0xd393,0xd394,
+    0xd395,0xd396,0xd397,0xd39a,0xd39b,0xd39d,0xd39e,0xd39f,0xd3a1,0xd3a2,
+    0xd3a3,0xd3a4,0xd3a5,0xd3a6,0xd3a7,0xd3aa,0xd3ac,0xd3ae,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xd3af,0xd3b0,0xd3b1,0xd3b2,0xd3b3,0xd3b5,
+    0xd3b6,0xd3b7,0xd3b9,0xd3ba,0xd3bb,0xd3bd,0xd3be,0xd3bf,0xd3c0,0xd3c1,
+    0xd3c2,0xd3c3,0xd3c6,0xd3c7,0xd3ca,0xd3cb,0xd3cc,0xd3cd,0xd3ce,0xd3cf,
+    0xd3d1,0xd3d2,0xd3d3,0xd3d4,0xd3d5,0xd3d6,0xc0e5,0xc0e8,0xc0ec,0xc0f4,
+    0xc0f5,0xc0f7,0xc0f9,0xc100,0xc104,0xc108,0xc110,0xc115,0xc11c,0xc11d,
+    0xc11e,0xc11f,0xc120,0xc123,0xc124,0xc126,0xc127,0xc12c,0xc12d,0xc12f,
+    0xc130,0xc131,0xc136,0xc138,0xc139,0xc13c,0xc140,0xc148,0xc149,0xc14b,
+    0xc14c,0xc14d,0xc154,0xc155,0xc158,0xc15c,0xc164,0xc165,0xc167,0xc168,
+    0xc169,0xc170,0xc174,0xc178,0xc185,0xc18c,0xc18d,0xc18e,0xc190,0xc194,
+    0xc196,0xc19c,0xc19d,0xc19f,0xc1a1,0xc1a5,0xc1a8,0xc1a9,0xc1ac,0xc1b0,
+    0xc1bd,0xc1c4,0xc1c8,0xc1cc,0xc1d4,0xc1d7,0xc1d8,0xc1e0,0xc1e4,0xc1e8,
+    0xc1f0,0xc1f1,0xc1f3,0xc1fc,0xc1fd,0xc200,0xc204,0xc20c,0xc20d,0xc20f,
+    0xc211,0xc218,0xc219,0xc21c,0xc21f,0xc220,0xc228,0xc229,0xc22b,0xc22d
+  },
+  {				/* ku 3d */
+    0xd3d7,0xd3d9,0xd3da,0xd3db,0xd3dc,0xd3dd,0xd3de,0xd3df,0xd3e0,0xd3e2,
+    0xd3e4,0xd3e5,0xd3e6,0xd3e7,0xd3e8,0xd3e9,0xd3ea,0xd3eb,0xd3ee,0xd3ef,
+    0xd3f1,0xd3f2,0xd3f3,0xd3f5,0xd3f6,0xd3f7,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xd3f8,0xd3f9,0xd3fa,0xd3fb,0xd3fe,0xd400,0xd402,0xd403,
+    0xd404,0xd405,0xd406,0xd407,0xd409,0xd40a,0xd40b,0xd40c,0xd40d,0xd40e,
+    0xd40f,0xd410,0xd411,0xd412,0xd413,0xd414,0xd415,0xd416,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xd417,0xd418,0xd419,0xd41a,0xd41b,0xd41c,
+    0xd41e,0xd41f,0xd420,0xd421,0xd422,0xd423,0xd424,0xd425,0xd426,0xd427,
+    0xd428,0xd429,0xd42a,0xd42b,0xd42c,0xd42d,0xd42e,0xd42f,0xd430,0xd431,
+    0xd432,0xd433,0xd434,0xd435,0xd436,0xd437,0xc22f,0xc231,0xc232,0xc234,
+    0xc248,0xc250,0xc251,0xc254,0xc258,0xc260,0xc265,0xc26c,0xc26d,0xc270,
+    0xc274,0xc27c,0xc27d,0xc27f,0xc281,0xc288,0xc289,0xc290,0xc298,0xc29b,
+    0xc29d,0xc2a4,0xc2a5,0xc2a8,0xc2ac,0xc2ad,0xc2b4,0xc2b5,0xc2b7,0xc2b9,
+    0xc2dc,0xc2dd,0xc2e0,0xc2e3,0xc2e4,0xc2eb,0xc2ec,0xc2ed,0xc2ef,0xc2f1,
+    0xc2f6,0xc2f8,0xc2f9,0xc2fb,0xc2fc,0xc300,0xc308,0xc309,0xc30c,0xc30d,
+    0xc313,0xc314,0xc315,0xc318,0xc31c,0xc324,0xc325,0xc328,0xc329,0xc345,
+    0xc368,0xc369,0xc36c,0xc370,0xc372,0xc378,0xc379,0xc37c,0xc37d,0xc384,
+    0xc388,0xc38c,0xc3c0,0xc3d8,0xc3d9,0xc3dc,0xc3df,0xc3e0,0xc3e2,0xc3e8,
+    0xc3e9,0xc3ed,0xc3f4,0xc3f5,0xc3f8,0xc408,0xc410,0xc424,0xc42c,0xc430
+  },
+  {				/* ku 3e */
+    0xd438,0xd439,0xd43a,0xd43b,0xd43c,0xd43d,0xd43e,0xd43f,0xd441,0xd442,
+    0xd443,0xd445,0xd446,0xd447,0xd448,0xd449,0xd44a,0xd44b,0xd44c,0xd44d,
+    0xd44e,0xd44f,0xd450,0xd451,0xd452,0xd453,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xd454,0xd455,0xd456,0xd457,0xd458,0xd459,0xd45a,0xd45b,
+    0xd45d,0xd45e,0xd45f,0xd461,0xd462,0xd463,0xd465,0xd466,0xd467,0xd468,
+    0xd469,0xd46a,0xd46b,0xd46c,0xd46e,0xd470,0xd471,0xd472,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xd473,0xd474,0xd475,0xd476,0xd477,0xd47a,
+    0xd47b,0xd47d,0xd47e,0xd481,0xd483,0xd484,0xd485,0xd486,0xd487,0xd48a,
+    0xd48c,0xd48e,0xd48f,0xd490,0xd491,0xd492,0xd493,0xd495,0xd496,0xd497,
+    0xd498,0xd499,0xd49a,0xd49b,0xd49c,0xd49d,0xc434,0xc43c,0xc43d,0xc448,
+    0xc464,0xc465,0xc468,0xc46c,0xc474,0xc475,0xc479,0xc480,0xc494,0xc49c,
+    0xc4b8,0xc4bc,0xc4e9,0xc4f0,0xc4f1,0xc4f4,0xc4f8,0xc4fa,0xc4ff,0xc500,
+    0xc501,0xc50c,0xc510,0xc514,0xc51c,0xc528,0xc529,0xc52c,0xc530,0xc538,
+    0xc539,0xc53b,0xc53d,0xc544,0xc545,0xc548,0xc549,0xc54a,0xc54c,0xc54d,
+    0xc54e,0xc553,0xc554,0xc555,0xc557,0xc558,0xc559,0xc55d,0xc55e,0xc560,
+    0xc561,0xc564,0xc568,0xc570,0xc571,0xc573,0xc574,0xc575,0xc57c,0xc57d,
+    0xc580,0xc584,0xc587,0xc58c,0xc58d,0xc58f,0xc591,0xc595,0xc597,0xc598,
+    0xc59c,0xc5a0,0xc5a9,0xc5b4,0xc5b5,0xc5b8,0xc5b9,0xc5bb,0xc5bc,0xc5bd,
+    0xc5be,0xc5c4,0xc5c5,0xc5c6,0xc5c7,0xc5c8,0xc5c9,0xc5ca,0xc5cc,0xc5ce
+  },
+  {				/* ku 3f */
+    0xd49e,0xd49f,0xd4a0,0xd4a1,0xd4a2,0xd4a3,0xd4a4,0xd4a5,0xd4a6,0xd4a7,
+    0xd4a8,0xd4aa,0xd4ab,0xd4ac,0xd4ad,0xd4ae,0xd4af,0xd4b0,0xd4b1,0xd4b2,
+    0xd4b3,0xd4b4,0xd4b5,0xd4b6,0xd4b7,0xd4b8,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xd4b9,0xd4ba,0xd4bb,0xd4bc,0xd4bd,0xd4be,0xd4bf,0xd4c0,
+    0xd4c1,0xd4c2,0xd4c3,0xd4c4,0xd4c5,0xd4c6,0xd4c7,0xd4c8,0xd4c9,0xd4ca,
+    0xd4cb,0xd4cd,0xd4ce,0xd4cf,0xd4d1,0xd4d2,0xd4d3,0xd4d5,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xd4d6,0xd4d7,0xd4d8,0xd4d9,0xd4da,0xd4db,
+    0xd4dd,0xd4de,0xd4e0,0xd4e1,0xd4e2,0xd4e3,0xd4e4,0xd4e5,0xd4e6,0xd4e7,
+    0xd4e9,0xd4ea,0xd4eb,0xd4ed,0xd4ee,0xd4ef,0xd4f1,0xd4f2,0xd4f3,0xd4f4,
+    0xd4f5,0xd4f6,0xd4f7,0xd4f9,0xd4fa,0xd4fc,0xc5d0,0xc5d1,0xc5d4,0xc5d8,
+    0xc5e0,0xc5e1,0xc5e3,0xc5e5,0xc5ec,0xc5ed,0xc5ee,0xc5f0,0xc5f4,0xc5f6,
+    0xc5f7,0xc5fc,0xc5fd,0xc5fe,0xc5ff,0xc600,0xc601,0xc605,0xc606,0xc607,
+    0xc608,0xc60c,0xc610,0xc618,0xc619,0xc61b,0xc61c,0xc624,0xc625,0xc628,
+    0xc62c,0xc62d,0xc62e,0xc630,0xc633,0xc634,0xc635,0xc637,0xc639,0xc63b,
+    0xc640,0xc641,0xc644,0xc648,0xc650,0xc651,0xc653,0xc654,0xc655,0xc65c,
+    0xc65d,0xc660,0xc66c,0xc66f,0xc671,0xc678,0xc679,0xc67c,0xc680,0xc688,
+    0xc689,0xc68b,0xc68d,0xc694,0xc695,0xc698,0xc69c,0xc6a4,0xc6a5,0xc6a7,
+    0xc6a9,0xc6b0,0xc6b1,0xc6b4,0xc6b8,0xc6b9,0xc6ba,0xc6c0,0xc6c1,0xc6c3,
+    0xc6c5,0xc6cc,0xc6cd,0xc6d0,0xc6d4,0xc6dc,0xc6dd,0xc6e0,0xc6e1,0xc6e8
+  },
+  {				/* ku 40 */
+    0xd4fe,0xd4ff,0xd500,0xd501,0xd502,0xd503,0xd505,0xd506,0xd507,0xd509,
+    0xd50a,0xd50b,0xd50d,0xd50e,0xd50f,0xd510,0xd511,0xd512,0xd513,0xd516,
+    0xd518,0xd519,0xd51a,0xd51b,0xd51c,0xd51d,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xd51e,0xd51f,0xd520,0xd521,0xd522,0xd523,0xd524,0xd525,
+    0xd526,0xd527,0xd528,0xd529,0xd52a,0xd52b,0xd52c,0xd52d,0xd52e,0xd52f,
+    0xd530,0xd531,0xd532,0xd533,0xd534,0xd535,0xd536,0xd537,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xd538,0xd539,0xd53a,0xd53b,0xd53e,0xd53f,
+    0xd541,0xd542,0xd543,0xd545,0xd546,0xd547,0xd548,0xd549,0xd54a,0xd54b,
+    0xd54e,0xd550,0xd552,0xd553,0xd554,0xd555,0xd556,0xd557,0xd55a,0xd55b,
+    0xd55d,0xd55e,0xd55f,0xd561,0xd562,0xd563,0xc6e9,0xc6ec,0xc6f0,0xc6f8,
+    0xc6f9,0xc6fd,0xc704,0xc705,0xc708,0xc70c,0xc714,0xc715,0xc717,0xc719,
+    0xc720,0xc721,0xc724,0xc728,0xc730,0xc731,0xc733,0xc735,0xc737,0xc73c,
+    0xc73d,0xc740,0xc744,0xc74a,0xc74c,0xc74d,0xc74f,0xc751,0xc752,0xc753,
+    0xc754,0xc755,0xc756,0xc757,0xc758,0xc75c,0xc760,0xc768,0xc76b,0xc774,
+    0xc775,0xc778,0xc77c,0xc77d,0xc77e,0xc783,0xc784,0xc785,0xc787,0xc788,
+    0xc789,0xc78a,0xc78e,0xc790,0xc791,0xc794,0xc796,0xc797,0xc798,0xc79a,
+    0xc7a0,0xc7a1,0xc7a3,0xc7a4,0xc7a5,0xc7a6,0xc7ac,0xc7ad,0xc7b0,0xc7b4,
+    0xc7bc,0xc7bd,0xc7bf,0xc7c0,0xc7c1,0xc7c8,0xc7c9,0xc7cc,0xc7ce,0xc7d0,
+    0xc7d8,0xc7dd,0xc7e4,0xc7e8,0xc7ec,0xc800,0xc801,0xc804,0xc808,0xc80a
+  },
+  {				/* ku 41 */
+    0xd564,0xd566,0xd567,0xd56a,0xd56c,0xd56e,0xd56f,0xd570,0xd571,0xd572,
+    0xd573,0xd576,0xd577,0xd579,0xd57a,0xd57b,0xd57d,0xd57e,0xd57f,0xd580,
+    0xd581,0xd582,0xd583,0xd586,0xd58a,0xd58b,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xd58c,0xd58d,0xd58e,0xd58f,0xd591,0xd592,0xd593,0xd594,
+    0xd595,0xd596,0xd597,0xd598,0xd599,0xd59a,0xd59b,0xd59c,0xd59d,0xd59e,
+    0xd59f,0xd5a0,0xd5a1,0xd5a2,0xd5a3,0xd5a4,0xd5a6,0xd5a7,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xd5a8,0xd5a9,0xd5aa,0xd5ab,0xd5ac,0xd5ad,
+    0xd5ae,0xd5af,0xd5b0,0xd5b1,0xd5b2,0xd5b3,0xd5b4,0xd5b5,0xd5b6,0xd5b7,
+    0xd5b8,0xd5b9,0xd5ba,0xd5bb,0xd5bc,0xd5bd,0xd5be,0xd5bf,0xd5c0,0xd5c1,
+    0xd5c2,0xd5c3,0xd5c4,0xd5c5,0xd5c6,0xd5c7,0xc810,0xc811,0xc813,0xc815,
+    0xc816,0xc81c,0xc81d,0xc820,0xc824,0xc82c,0xc82d,0xc82f,0xc831,0xc838,
+    0xc83c,0xc840,0xc848,0xc849,0xc84c,0xc84d,0xc854,0xc870,0xc871,0xc874,
+    0xc878,0xc87a,0xc880,0xc881,0xc883,0xc885,0xc886,0xc887,0xc88b,0xc88c,
+    0xc88d,0xc894,0xc89d,0xc89f,0xc8a1,0xc8a8,0xc8bc,0xc8bd,0xc8c4,0xc8c8,
+    0xc8cc,0xc8d4,0xc8d5,0xc8d7,0xc8d9,0xc8e0,0xc8e1,0xc8e4,0xc8f5,0xc8fc,
+    0xc8fd,0xc900,0xc904,0xc905,0xc906,0xc90c,0xc90d,0xc90f,0xc911,0xc918,
+    0xc92c,0xc934,0xc950,0xc951,0xc954,0xc958,0xc960,0xc961,0xc963,0xc96c,
+    0xc970,0xc974,0xc97c,0xc988,0xc989,0xc98c,0xc990,0xc998,0xc999,0xc99b,
+    0xc99d,0xc9c0,0xc9c1,0xc9c4,0xc9c7,0xc9c8,0xc9ca,0xc9d0,0xc9d1,0xc9d3
+  },
+  {				/* ku 42 */
+    0xd5ca,0xd5cb,0xd5cd,0xd5ce,0xd5cf,0xd5d1,0xd5d3,0xd5d4,0xd5d5,0xd5d6,
+    0xd5d7,0xd5da,0xd5dc,0xd5de,0xd5df,0xd5e0,0xd5e1,0xd5e2,0xd5e3,0xd5e6,
+    0xd5e7,0xd5e9,0xd5ea,0xd5eb,0xd5ed,0xd5ee,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xd5ef,0xd5f0,0xd5f1,0xd5f2,0xd5f3,0xd5f6,0xd5f8,0xd5fa,
+    0xd5fb,0xd5fc,0xd5fd,0xd5fe,0xd5ff,0xd602,0xd603,0xd605,0xd606,0xd607,
+    0xd609,0xd60a,0xd60b,0xd60c,0xd60d,0xd60e,0xd60f,0xd612,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xd616,0xd617,0xd618,0xd619,0xd61a,0xd61b,
+    0xd61d,0xd61e,0xd61f,0xd621,0xd622,0xd623,0xd625,0xd626,0xd627,0xd628,
+    0xd629,0xd62a,0xd62b,0xd62c,0xd62e,0xd62f,0xd630,0xd631,0xd632,0xd633,
+    0xd634,0xd635,0xd636,0xd637,0xd63a,0xd63b,0xc9d5,0xc9d6,0xc9d9,0xc9da,
+    0xc9dc,0xc9dd,0xc9e0,0xc9e2,0xc9e4,0xc9e7,0xc9ec,0xc9ed,0xc9ef,0xc9f0,
+    0xc9f1,0xc9f8,0xc9f9,0xc9fc,0xca00,0xca08,0xca09,0xca0b,0xca0c,0xca0d,
+    0xca14,0xca18,0xca29,0xca4c,0xca4d,0xca50,0xca54,0xca5c,0xca5d,0xca5f,
+    0xca60,0xca61,0xca68,0xca7d,0xca84,0xca98,0xcabc,0xcabd,0xcac0,0xcac4,
+    0xcacc,0xcacd,0xcacf,0xcad1,0xcad3,0xcad8,0xcad9,0xcae0,0xcaec,0xcaf4,
+    0xcb08,0xcb10,0xcb14,0xcb18,0xcb20,0xcb21,0xcb41,0xcb48,0xcb49,0xcb4c,
+    0xcb50,0xcb58,0xcb59,0xcb5d,0xcb64,0xcb78,0xcb79,0xcb9c,0xcbb8,0xcbd4,
+    0xcbe4,0xcbe7,0xcbe9,0xcc0c,0xcc0d,0xcc10,0xcc14,0xcc1c,0xcc1d,0xcc21,
+    0xcc22,0xcc27,0xcc28,0xcc29,0xcc2c,0xcc2e,0xcc30,0xcc38,0xcc39,0xcc3b
+  },
+  {				/* ku 43 */
+    0xd63d,0xd63e,0xd63f,0xd641,0xd642,0xd643,0xd644,0xd646,0xd647,0xd64a,
+    0xd64c,0xd64e,0xd64f,0xd650,0xd652,0xd653,0xd656,0xd657,0xd659,0xd65a,
+    0xd65b,0xd65d,0xd65e,0xd65f,0xd660,0xd661,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xd662,0xd663,0xd664,0xd665,0xd666,0xd668,0xd66a,0xd66b,
+    0xd66c,0xd66d,0xd66e,0xd66f,0xd672,0xd673,0xd675,0xd676,0xd677,0xd678,
+    0xd679,0xd67a,0xd67b,0xd67c,0xd67d,0xd67e,0xd67f,0xd680,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xd681,0xd682,0xd684,0xd686,0xd687,0xd688,
+    0xd689,0xd68a,0xd68b,0xd68e,0xd68f,0xd691,0xd692,0xd693,0xd695,0xd696,
+    0xd697,0xd698,0xd699,0xd69a,0xd69b,0xd69c,0xd69e,0xd6a0,0xd6a2,0xd6a3,
+    0xd6a4,0xd6a5,0xd6a6,0xd6a7,0xd6a9,0xd6aa,0xcc3c,0xcc3d,0xcc3e,0xcc44,
+    0xcc45,0xcc48,0xcc4c,0xcc54,0xcc55,0xcc57,0xcc58,0xcc59,0xcc60,0xcc64,
+    0xcc66,0xcc68,0xcc70,0xcc75,0xcc98,0xcc99,0xcc9c,0xcca0,0xcca8,0xcca9,
+    0xccab,0xccac,0xccad,0xccb4,0xccb5,0xccb8,0xccbc,0xccc4,0xccc5,0xccc7,
+    0xccc9,0xccd0,0xccd4,0xcce4,0xccec,0xccf0,0xcd01,0xcd08,0xcd09,0xcd0c,
+    0xcd10,0xcd18,0xcd19,0xcd1b,0xcd1d,0xcd24,0xcd28,0xcd2c,0xcd39,0xcd5c,
+    0xcd60,0xcd64,0xcd6c,0xcd6d,0xcd6f,0xcd71,0xcd78,0xcd88,0xcd94,0xcd95,
+    0xcd98,0xcd9c,0xcda4,0xcda5,0xcda7,0xcda9,0xcdb0,0xcdc4,0xcdcc,0xcdd0,
+    0xcde8,0xcdec,0xcdf0,0xcdf8,0xcdf9,0xcdfb,0xcdfd,0xce04,0xce08,0xce0c,
+    0xce14,0xce19,0xce20,0xce21,0xce24,0xce28,0xce30,0xce31,0xce33,0xce35
+  },
+  {				/* ku 44 */
+    0xd6ab,0xd6ad,0xd6ae,0xd6af,0xd6b1,0xd6b2,0xd6b3,0xd6b4,0xd6b5,0xd6b6,
+    0xd6b7,0xd6b8,0xd6ba,0xd6bc,0xd6bd,0xd6be,0xd6bf,0xd6c0,0xd6c1,0xd6c2,
+    0xd6c3,0xd6c6,0xd6c7,0xd6c9,0xd6ca,0xd6cb,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xd6cd,0xd6ce,0xd6cf,0xd6d0,0xd6d2,0xd6d3,0xd6d5,0xd6d6,
+    0xd6d8,0xd6da,0xd6db,0xd6dc,0xd6dd,0xd6de,0xd6df,0xd6e1,0xd6e2,0xd6e3,
+    0xd6e5,0xd6e6,0xd6e7,0xd6e9,0xd6ea,0xd6eb,0xd6ec,0xd6ed,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xd6ee,0xd6ef,0xd6f1,0xd6f2,0xd6f3,0xd6f4,
+    0xd6f6,0xd6f7,0xd6f8,0xd6f9,0xd6fa,0xd6fb,0xd6fe,0xd6ff,0xd701,0xd702,
+    0xd703,0xd705,0xd706,0xd707,0xd708,0xd709,0xd70a,0xd70b,0xd70c,0xd70d,
+    0xd70e,0xd70f,0xd710,0xd712,0xd713,0xd714,0xce58,0xce59,0xce5c,0xce5f,
+    0xce60,0xce61,0xce68,0xce69,0xce6b,0xce6d,0xce74,0xce75,0xce78,0xce7c,
+    0xce84,0xce85,0xce87,0xce89,0xce90,0xce91,0xce94,0xce98,0xcea0,0xcea1,
+    0xcea3,0xcea4,0xcea5,0xceac,0xcead,0xcec1,0xcee4,0xcee5,0xcee8,0xceeb,
+    0xceec,0xcef4,0xcef5,0xcef7,0xcef8,0xcef9,0xcf00,0xcf01,0xcf04,0xcf08,
+    0xcf10,0xcf11,0xcf13,0xcf15,0xcf1c,0xcf20,0xcf24,0xcf2c,0xcf2d,0xcf2f,
+    0xcf30,0xcf31,0xcf38,0xcf54,0xcf55,0xcf58,0xcf5c,0xcf64,0xcf65,0xcf67,
+    0xcf69,0xcf70,0xcf71,0xcf74,0xcf78,0xcf80,0xcf85,0xcf8c,0xcfa1,0xcfa8,
+    0xcfb0,0xcfc4,0xcfe0,0xcfe1,0xcfe4,0xcfe8,0xcff0,0xcff1,0xcff3,0xcff5,
+    0xcffc,0xd000,0xd004,0xd011,0xd018,0xd02d,0xd034,0xd035,0xd038,0xd03c
+  },
+  {				/* ku 45 */
+    0xd715,0xd716,0xd717,0xd71a,0xd71b,0xd71d,0xd71e,0xd71f,0xd721,0xd722,
+    0xd723,0xd724,0xd725,0xd726,0xd727,0xd72a,0xd72c,0xd72e,0xd72f,0xd730,
+    0xd731,0xd732,0xd733,0xd736,0xd737,0xd739,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,0xd73a,0xd73b,0xd73d,0xd73e,0xd73f,0xd740,0xd741,0xd742,
+    0xd743,0xd745,0xd746,0xd748,0xd74a,0xd74b,0xd74c,0xd74d,0xd74e,0xd74f,
+    0xd752,0xd753,0xd755,0xd75a,0xd75b,0xd75c,0xd75d,0xd75e,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,0xd75f,0xd762,0xd764,0xd766,0xd767,0xd768,
+    0xd76a,0xd76b,0xd76d,0xd76e,0xd76f,0xd771,0xd772,0xd773,0xd775,0xd776,
+    0xd777,0xd778,0xd779,0xd77a,0xd77b,0xd77e,0xd77f,0xd780,0xd782,0xd783,
+    0xd784,0xd785,0xd786,0xd787,0xd78a,0xd78b,0xd044,0xd045,0xd047,0xd049,
+    0xd050,0xd054,0xd058,0xd060,0xd06c,0xd06d,0xd070,0xd074,0xd07c,0xd07d,
+    0xd081,0xd0a4,0xd0a5,0xd0a8,0xd0ac,0xd0b4,0xd0b5,0xd0b7,0xd0b9,0xd0c0,
+    0xd0c1,0xd0c4,0xd0c8,0xd0c9,0xd0d0,0xd0d1,0xd0d3,0xd0d4,0xd0d5,0xd0dc,
+    0xd0dd,0xd0e0,0xd0e4,0xd0ec,0xd0ed,0xd0ef,0xd0f0,0xd0f1,0xd0f8,0xd10d,
+    0xd130,0xd131,0xd134,0xd138,0xd13a,0xd140,0xd141,0xd143,0xd144,0xd145,
+    0xd14c,0xd14d,0xd150,0xd154,0xd15c,0xd15d,0xd15f,0xd161,0xd168,0xd16c,
+    0xd17c,0xd184,0xd188,0xd1a0,0xd1a1,0xd1a4,0xd1a8,0xd1b0,0xd1b1,0xd1b3,
+    0xd1b5,0xd1ba,0xd1bc,0xd1c0,0xd1d8,0xd1f4,0xd1f8,0xd207,0xd209,0xd210,
+    0xd22c,0xd22d,0xd230,0xd234,0xd23c,0xd23d,0xd23f,0xd241,0xd248,0xd25c
+  },
+  {				/* ku 46 */
+    0xd78d,0xd78e,0xd78f,0xd791,0xd792,0xd793,0xd794,0xd795,0xd796,0xd797,
+    0xd79a,0xd79c,0xd79e,0xd79f,0xd7a0,0xd7a1,0xd7a2,0xd7a3,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xd264,0xd280,0xd281,0xd284,
+    0xd288,0xd290,0xd291,0xd295,0xd29c,0xd2a0,0xd2a4,0xd2ac,0xd2b1,0xd2b8,
+    0xd2b9,0xd2bc,0xd2bf,0xd2c0,0xd2c2,0xd2c8,0xd2c9,0xd2cb,0xd2d4,0xd2d8,
+    0xd2dc,0xd2e4,0xd2e5,0xd2f0,0xd2f1,0xd2f4,0xd2f8,0xd300,0xd301,0xd303,
+    0xd305,0xd30c,0xd30d,0xd30e,0xd310,0xd314,0xd316,0xd31c,0xd31d,0xd31f,
+    0xd320,0xd321,0xd325,0xd328,0xd329,0xd32c,0xd330,0xd338,0xd339,0xd33b,
+    0xd33c,0xd33d,0xd344,0xd345,0xd37c,0xd37d,0xd380,0xd384,0xd38c,0xd38d,
+    0xd38f,0xd390,0xd391,0xd398,0xd399,0xd39c,0xd3a0,0xd3a8,0xd3a9,0xd3ab,
+    0xd3ad,0xd3b4,0xd3b8,0xd3bc,0xd3c4,0xd3c5,0xd3c8,0xd3c9,0xd3d0,0xd3d8,
+    0xd3e1,0xd3e3,0xd3ec,0xd3ed,0xd3f0,0xd3f4,0xd3fc,0xd3fd,0xd3ff,0xd401
+  },
+  {				/* ku 47 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xd408,0xd41d,0xd440,0xd444,
+    0xd45c,0xd460,0xd464,0xd46d,0xd46f,0xd478,0xd479,0xd47c,0xd47f,0xd480,
+    0xd482,0xd488,0xd489,0xd48b,0xd48d,0xd494,0xd4a9,0xd4cc,0xd4d0,0xd4d4,
+    0xd4dc,0xd4df,0xd4e8,0xd4ec,0xd4f0,0xd4f8,0xd4fb,0xd4fd,0xd504,0xd508,
+    0xd50c,0xd514,0xd515,0xd517,0xd53c,0xd53d,0xd540,0xd544,0xd54c,0xd54d,
+    0xd54f,0xd551,0xd558,0xd559,0xd55c,0xd560,0xd565,0xd568,0xd569,0xd56b,
+    0xd56d,0xd574,0xd575,0xd578,0xd57c,0xd584,0xd585,0xd587,0xd588,0xd589,
+    0xd590,0xd5a5,0xd5c8,0xd5c9,0xd5cc,0xd5d0,0xd5d2,0xd5d8,0xd5d9,0xd5db,
+    0xd5dd,0xd5e4,0xd5e5,0xd5e8,0xd5ec,0xd5f4,0xd5f5,0xd5f7,0xd5f9,0xd600,
+    0xd601,0xd604,0xd608,0xd610,0xd611,0xd613,0xd614,0xd615,0xd61c,0xd620
+  },
+  {				/* ku 48 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xd624,0xd62d,0xd638,0xd639,
+    0xd63c,0xd640,0xd645,0xd648,0xd649,0xd64b,0xd64d,0xd651,0xd654,0xd655,
+    0xd658,0xd65c,0xd667,0xd669,0xd670,0xd671,0xd674,0xd683,0xd685,0xd68c,
+    0xd68d,0xd690,0xd694,0xd69d,0xd69f,0xd6a1,0xd6a8,0xd6ac,0xd6b0,0xd6b9,
+    0xd6bb,0xd6c4,0xd6c5,0xd6c8,0xd6cc,0xd6d1,0xd6d4,0xd6d7,0xd6d9,0xd6e0,
+    0xd6e4,0xd6e8,0xd6f0,0xd6f5,0xd6fc,0xd6fd,0xd700,0xd704,0xd711,0xd718,
+    0xd719,0xd71c,0xd720,0xd728,0xd729,0xd72b,0xd72d,0xd734,0xd735,0xd738,
+    0xd73c,0xd744,0xd747,0xd749,0xd750,0xd751,0xd754,0xd756,0xd757,0xd758,
+    0xd759,0xd760,0xd761,0xd763,0xd765,0xd769,0xd76c,0xd770,0xd774,0xd77c,
+    0xd77d,0xd781,0xd788,0xd789,0xd78c,0xd790,0xd798,0xd799,0xd79b,0xd79d
+  },
+  {				/* ku 49 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON
+  },
+  {				/* ku 4a */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4f3d,0x4f73,0x5047,0x50f9,
+    0x52a0,0x53ef,0x5475,0x54e5,0x5609,0x5ac1,0x5bb6,0x6687,0x67b6,0x67b7,
+    0x67ef,0x6b4c,0x73c2,0x75c2,0x7a3c,0x82db,0x8304,0x8857,0x8888,0x8a36,
+    0x8cc8,0x8dcf,0x8efb,0x8fe6,0x99d5,0x523b,0x5374,0x5404,0x606a,0x6164,
+    0x6bbc,0x73cf,0x811a,0x89ba,0x89d2,0x95a3,0x4f83,0x520a,0x58be,0x5978,
+    0x59e6,0x5e72,0x5e79,0x61c7,0x63c0,0x6746,0x67ec,0x687f,0x6f97,0x764e,
+    0x770b,0x78f5,0x7a08,0x7aff,0x7c21,0x809d,0x826e,0x8271,0x8aeb,0x9593,
+    0x4e6b,0x559d,0x66f7,0x6e34,0x78a3,0x7aed,0x845b,0x8910,0x874e,0x97a8,
+    0x52d8,0x574e,0x582a,0x5d4c,0x611f,0x61be,0x6221,0x6562,0x67d1,0x6a44,
+    0x6e1b,0x7518,0x75b3,0x76e3,0x77b0,0x7d3a,0x90af,0x9451,0x9452,0x9f95
+  },
+  {				/* ku 4b */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5323,0x5cac,0x7532,0x80db,
+    0x9240,0x9598,0x525b,0x5808,0x59dc,0x5ca1,0x5d17,0x5eb7,0x5f3a,0x5f4a,
+    0x6177,0x6c5f,0x757a,0x7586,0x7ce0,0x7d73,0x7db1,0x7f8c,0x8154,0x8221,
+    0x8591,0x8941,0x8b1b,0x92fc,0x964d,0x9c47,0x4ecb,0x4ef7,0x500b,0x51f1,
+    0x584f,0x6137,0x613e,0x6168,0x6539,0x69ea,0x6f11,0x75a5,0x7686,0x76d6,
+    0x7b87,0x82a5,0x84cb,0xf900,0x93a7,0x958b,0x5580,0x5ba2,0x5751,0xf901,
+    0x7cb3,0x7fb9,0x91b5,0x5028,0x53bb,0x5c45,0x5de8,0x62d2,0x636e,0x64da,
+    0x64e7,0x6e20,0x70ac,0x795b,0x8ddd,0x8e1e,0xf902,0x907d,0x9245,0x92f8,
+    0x4e7e,0x4ef6,0x5065,0x5dfe,0x5efa,0x6106,0x6957,0x8171,0x8654,0x8e47,
+    0x9375,0x9a2b,0x4e5e,0x5091,0x6770,0x6840,0x5109,0x528d,0x5292,0x6aa2
+  },
+  {				/* ku 4c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x77bc,0x9210,0x9ed4,0x52ab,
+    0x602f,0x8ff2,0x5048,0x61a9,0x63ed,0x64ca,0x683c,0x6a84,0x6fc0,0x8188,
+    0x89a1,0x9694,0x5805,0x727d,0x72ac,0x7504,0x7d79,0x7e6d,0x80a9,0x898b,
+    0x8b74,0x9063,0x9d51,0x6289,0x6c7a,0x6f54,0x7d50,0x7f3a,0x8a23,0x517c,
+    0x614a,0x7b9d,0x8b19,0x9257,0x938c,0x4eac,0x4fd3,0x501e,0x50be,0x5106,
+    0x52c1,0x52cd,0x537f,0x5770,0x5883,0x5e9a,0x5f91,0x6176,0x61ac,0x64ce,
+    0x656c,0x666f,0x66bb,0x66f4,0x6897,0x6d87,0x7085,0x70f1,0x749f,0x74a5,
+    0x74ca,0x75d9,0x786c,0x78ec,0x7adf,0x7af6,0x7d45,0x7d93,0x8015,0x803f,
+    0x811b,0x8396,0x8b66,0x8f15,0x9015,0x93e1,0x9803,0x9838,0x9a5a,0x9be8,
+    0x4fc2,0x5553,0x583a,0x5951,0x5b63,0x5c46,0x60b8,0x6212,0x6842,0x68b0
+  },
+  {				/* ku 4d */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x68e8,0x6eaa,0x754c,0x7678,
+    0x78ce,0x7a3d,0x7cfb,0x7e6b,0x7e7c,0x8a08,0x8aa1,0x8c3f,0x968e,0x9dc4,
+    0x53e4,0x53e9,0x544a,0x5471,0x56fa,0x59d1,0x5b64,0x5c3b,0x5eab,0x62f7,
+    0x6537,0x6545,0x6572,0x66a0,0x67af,0x69c1,0x6cbd,0x75fc,0x7690,0x777e,
+    0x7a3f,0x7f94,0x8003,0x80a1,0x818f,0x82e6,0x82fd,0x83f0,0x85c1,0x8831,
+    0x88b4,0x8aa5,0xf903,0x8f9c,0x932e,0x96c7,0x9867,0x9ad8,0x9f13,0x54ed,
+    0x659b,0x66f2,0x688f,0x7a40,0x8c37,0x9d60,0x56f0,0x5764,0x5d11,0x6606,
+    0x68b1,0x68cd,0x6efe,0x7428,0x889e,0x9be4,0x6c68,0xf904,0x9aa8,0x4f9b,
+    0x516c,0x5171,0x529f,0x5b54,0x5de5,0x6050,0x606d,0x62f1,0x63a7,0x653b,
+    0x73d9,0x7a7a,0x86a3,0x8ca2,0x978f,0x4e32,0x5be1,0x6208,0x679c,0x74dc
+  },
+  {				/* ku 4e */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x79d1,0x83d3,0x8a87,0x8ab2,
+    0x8de8,0x904e,0x934b,0x9846,0x5ed3,0x69e8,0x85ff,0x90ed,0xf905,0x51a0,
+    0x5b98,0x5bec,0x6163,0x68fa,0x6b3e,0x704c,0x742f,0x74d8,0x7ba1,0x7f50,
+    0x83c5,0x89c0,0x8cab,0x95dc,0x9928,0x522e,0x605d,0x62ec,0x9002,0x4f8a,
+    0x5149,0x5321,0x58d9,0x5ee3,0x66e0,0x6d38,0x709a,0x72c2,0x73d6,0x7b50,
+    0x80f1,0x945b,0x5366,0x639b,0x7f6b,0x4e56,0x5080,0x584a,0x58de,0x602a,
+    0x6127,0x62d0,0x69d0,0x9b41,0x5b8f,0x7d18,0x80b1,0x8f5f,0x4ea4,0x50d1,
+    0x54ac,0x55ac,0x5b0c,0x5da0,0x5de7,0x652a,0x654e,0x6821,0x6a4b,0x72e1,
+    0x768e,0x77ef,0x7d5e,0x7ff9,0x81a0,0x854e,0x86df,0x8f03,0x8f4e,0x90ca,
+    0x9903,0x9a55,0x9bab,0x4e18,0x4e45,0x4e5d,0x4ec7,0x4ff1,0x5177,0x52fe
+  },
+  {				/* ku 4f */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5340,0x53e3,0x53e5,0x548e,
+    0x5614,0x5775,0x57a2,0x5bc7,0x5d87,0x5ed0,0x61fc,0x62d8,0x6551,0x67b8,
+    0x67e9,0x69cb,0x6b50,0x6bc6,0x6bec,0x6c42,0x6e9d,0x7078,0x72d7,0x7396,
+    0x7403,0x77bf,0x77e9,0x7a76,0x7d7f,0x8009,0x81fc,0x8205,0x820a,0x82df,
+    0x8862,0x8b33,0x8cfc,0x8ec0,0x9011,0x90b1,0x9264,0x92b6,0x99d2,0x9a45,
+    0x9ce9,0x9dd7,0x9f9c,0x570b,0x5c40,0x83ca,0x97a0,0x97ab,0x9eb4,0x541b,
+    0x7a98,0x7fa4,0x88d9,0x8ecd,0x90e1,0x5800,0x5c48,0x6398,0x7a9f,0x5bae,
+    0x5f13,0x7a79,0x7aae,0x828e,0x8eac,0x5026,0x5238,0x52f8,0x5377,0x5708,
+    0x62f3,0x6372,0x6b0a,0x6dc3,0x7737,0x53a5,0x7357,0x8568,0x8e76,0x95d5,
+    0x673a,0x6ac3,0x6f70,0x8a6d,0x8ecc,0x994b,0xf906,0x6677,0x6b78,0x8cb4
+  },
+  {				/* ku 50 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9b3c,0xf907,0x53eb,0x572d,
+    0x594e,0x63c6,0x69fb,0x73ea,0x7845,0x7aba,0x7ac5,0x7cfe,0x8475,0x898f,
+    0x8d73,0x9035,0x95a8,0x52fb,0x5747,0x7547,0x7b60,0x83cc,0x921e,0xf908,
+    0x6a58,0x514b,0x524b,0x5287,0x621f,0x68d8,0x6975,0x9699,0x50c5,0x52a4,
+    0x52e4,0x61c3,0x65a4,0x6839,0x69ff,0x747e,0x7b4b,0x82b9,0x83eb,0x89b2,
+    0x8b39,0x8fd1,0x9949,0xf909,0x4eca,0x5997,0x64d2,0x6611,0x6a8e,0x7434,
+    0x7981,0x79bd,0x82a9,0x887e,0x887f,0x895f,0xf90a,0x9326,0x4f0b,0x53ca,
+    0x6025,0x6271,0x6c72,0x7d1a,0x7d66,0x4e98,0x5162,0x77dc,0x80af,0x4f01,
+    0x4f0e,0x5176,0x5180,0x55dc,0x5668,0x573b,0x57fa,0x57fc,0x5914,0x5947,
+    0x5993,0x5bc4,0x5c90,0x5d0e,0x5df1,0x5e7e,0x5fcc,0x6280,0x65d7,0x65e3
+  },
+  {				/* ku 51 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x671e,0x671f,0x675e,0x68cb,
+    0x68c4,0x6a5f,0x6b3a,0x6c23,0x6c7d,0x6c82,0x6dc7,0x7398,0x7426,0x742a,
+    0x7482,0x74a3,0x7578,0x757f,0x7881,0x78ef,0x7941,0x7947,0x7948,0x797a,
+    0x7b95,0x7d00,0x7dba,0x7f88,0x8006,0x802d,0x808c,0x8a18,0x8b4f,0x8c48,
+    0x8d77,0x9321,0x9324,0x98e2,0x9951,0x9a0e,0x9a0f,0x9a65,0x9e92,0x7dca,
+    0x4f76,0x5409,0x62ee,0x6854,0x91d1,0x55ab,0x513a,0xf90b,0xf90c,0x5a1c,
+    0x61e6,0xf90d,0x62cf,0x62ff,0xf90e,0xf90f,0xf910,0xf911,0xf912,0xf913,
+    0x90a3,0xf914,0xf915,0xf916,0xf917,0xf918,0x8afe,0xf919,0xf91a,0xf91b,
+    0xf91c,0x6696,0xf91d,0x7156,0xf91e,0xf91f,0x96e3,0xf920,0x634f,0x637a,
+    0x5357,0xf921,0x678f,0x6960,0x6e73,0xf922,0x7537,0xf923,0xf924,0xf925
+  },
+  {				/* ku 52 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7d0d,0xf926,0xf927,0x8872,
+    0x56ca,0x5a18,0xf928,0xf929,0xf92a,0xf92b,0xf92c,0x4e43,0xf92d,0x5167,
+    0x5948,0x67f0,0x8010,0xf92e,0x5973,0x5e74,0x649a,0x79ca,0x5ff5,0x606c,
+    0x62c8,0x637b,0x5be7,0x5bd7,0x52aa,0xf92f,0x5974,0x5f29,0x6012,0xf930,
+    0xf931,0xf932,0x7459,0xf933,0xf934,0xf935,0xf936,0xf937,0xf938,0x99d1,
+    0xf939,0xf93a,0xf93b,0xf93c,0xf93d,0xf93e,0xf93f,0xf940,0xf941,0xf942,
+    0xf943,0x6fc3,0xf944,0xf945,0x81bf,0x8fb2,0x60f1,0xf946,0xf947,0x8166,
+    0xf948,0xf949,0x5c3f,0xf94a,0xf94b,0xf94c,0xf94d,0xf94e,0xf94f,0xf950,
+    0xf951,0x5ae9,0x8a25,0x677b,0x7d10,0xf952,0xf953,0xf954,0xf955,0xf956,
+    0xf957,0x80fd,0xf958,0xf959,0x5c3c,0x6ce5,0x533f,0x6eba,0x591a,0x8336
+  },
+  {				/* ku 53 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x4e39,0x4eb6,0x4f46,0x55ae,
+    0x5718,0x58c7,0x5f56,0x65b7,0x65e6,0x6a80,0x6bb5,0x6e4d,0x77ed,0x7aef,
+    0x7c1e,0x7dde,0x86cb,0x8892,0x9132,0x935b,0x64bb,0x6fbe,0x737a,0x75b8,
+    0x9054,0x5556,0x574d,0x61ba,0x64d4,0x66c7,0x6de1,0x6e5b,0x6f6d,0x6fb9,
+    0x75f0,0x8043,0x81bd,0x8541,0x8983,0x8ac7,0x8b5a,0x931f,0x6c93,0x7553,
+    0x7b54,0x8e0f,0x905d,0x5510,0x5802,0x5858,0x5e62,0x6207,0x649e,0x68e0,
+    0x7576,0x7cd6,0x87b3,0x9ee8,0x4ee3,0x5788,0x576e,0x5927,0x5c0d,0x5cb1,
+    0x5e36,0x5f85,0x6234,0x64e1,0x73b3,0x81fa,0x888b,0x8cb8,0x968a,0x9edb,
+    0x5b85,0x5fb7,0x60b3,0x5012,0x5200,0x5230,0x5716,0x5835,0x5857,0x5c0e,
+    0x5c60,0x5cf6,0x5d8b,0x5ea6,0x5f92,0x60bc,0x6311,0x6389,0x6417,0x6843
+  },
+  {				/* ku 54 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x68f9,0x6ac2,0x6dd8,0x6e21,
+    0x6ed4,0x6fe4,0x71fe,0x76dc,0x7779,0x79b1,0x7a3b,0x8404,0x89a9,0x8ced,
+    0x8df3,0x8e48,0x9003,0x9014,0x9053,0x90fd,0x934d,0x9676,0x97dc,0x6bd2,
+    0x7006,0x7258,0x72a2,0x7368,0x7763,0x79bf,0x7be4,0x7e9b,0x8b80,0x58a9,
+    0x60c7,0x6566,0x65fd,0x66be,0x6c8c,0x711e,0x71c9,0x8c5a,0x9813,0x4e6d,
+    0x7a81,0x4edd,0x51ac,0x51cd,0x52d5,0x540c,0x61a7,0x6771,0x6850,0x68df,
+    0x6d1e,0x6f7c,0x75bc,0x77b3,0x7ae5,0x80f4,0x8463,0x9285,0x515c,0x6597,
+    0x675c,0x6793,0x75d8,0x7ac7,0x8373,0xf95a,0x8c46,0x9017,0x982d,0x5c6f,
+    0x81c0,0x829a,0x9041,0x906f,0x920d,0x5f97,0x5d9d,0x6a59,0x71c8,0x767b,
+    0x7b49,0x85e4,0x8b04,0x9127,0x9a30,0x5587,0x61f6,0xf95b,0x7669,0x7f85
+  },
+  {				/* ku 55 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x863f,0x87ba,0x88f8,0x908f,
+    0xf95c,0x6d1b,0x70d9,0x73de,0x7d61,0x843d,0xf95d,0x916a,0x99f1,0xf95e,
+    0x4e82,0x5375,0x6b04,0x6b12,0x703e,0x721b,0x862d,0x9e1e,0x524c,0x8fa3,
+    0x5d50,0x64e5,0x652c,0x6b16,0x6feb,0x7c43,0x7e9c,0x85cd,0x8964,0x89bd,
+    0x62c9,0x81d8,0x881f,0x5eca,0x6717,0x6d6a,0x72fc,0x7405,0x746f,0x8782,
+    0x90de,0x4f86,0x5d0d,0x5fa0,0x840a,0x51b7,0x63a0,0x7565,0x4eae,0x5006,
+    0x5169,0x51c9,0x6881,0x6a11,0x7cae,0x7cb1,0x7ce7,0x826f,0x8ad2,0x8f1b,
+    0x91cf,0x4fb6,0x5137,0x52f5,0x5442,0x5eec,0x616e,0x623e,0x65c5,0x6ada,
+    0x6ffe,0x792a,0x85dc,0x8823,0x95ad,0x9a62,0x9a6a,0x9e97,0x9ece,0x529b,
+    0x66c6,0x6b77,0x701d,0x792b,0x8f62,0x9742,0x6190,0x6200,0x6523,0x6f23
+  },
+  {				/* ku 56 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7149,0x7489,0x7df4,0x806f,
+    0x84ee,0x8f26,0x9023,0x934a,0x51bd,0x5217,0x52a3,0x6d0c,0x70c8,0x88c2,
+    0x5ec9,0x6582,0x6bae,0x6fc2,0x7c3e,0x7375,0x4ee4,0x4f36,0x56f9,0xf95f,
+    0x5cba,0x5dba,0x601c,0x73b2,0x7b2d,0x7f9a,0x7fce,0x8046,0x901e,0x9234,
+    0x96f6,0x9748,0x9818,0x9f61,0x4f8b,0x6fa7,0x79ae,0x91b4,0x96b7,0x52de,
+    0xf960,0x6488,0x64c4,0x6ad3,0x6f5e,0x7018,0x7210,0x76e7,0x8001,0x8606,
+    0x865c,0x8def,0x8f05,0x9732,0x9b6f,0x9dfa,0x9e75,0x788c,0x797f,0x7da0,
+    0x83c9,0x9304,0x9e7f,0x9e93,0x8ad6,0x58df,0x5f04,0x6727,0x7027,0x74cf,
+    0x7c60,0x807e,0x5121,0x7028,0x7262,0x78ca,0x8cc2,0x8cda,0x8cf4,0x96f7,
+    0x4e86,0x50da,0x5bee,0x5ed6,0x6599,0x71ce,0x7642,0x77ad,0x804a,0x84fc
+  },
+  {				/* ku 57 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x907c,0x9b27,0x9f8d,0x58d8,
+    0x5a41,0x5c62,0x6a13,0x6dda,0x6f0f,0x763b,0x7d2f,0x7e37,0x851e,0x8938,
+    0x93e4,0x964b,0x5289,0x65d2,0x67f3,0x69b4,0x6d41,0x6e9c,0x700f,0x7409,
+    0x7460,0x7559,0x7624,0x786b,0x8b2c,0x985e,0x516d,0x622e,0x9678,0x4f96,
+    0x502b,0x5d19,0x6dea,0x7db8,0x8f2a,0x5f8b,0x6144,0x6817,0xf961,0x9686,
+    0x52d2,0x808b,0x51dc,0x51cc,0x695e,0x7a1c,0x7dbe,0x83f1,0x9675,0x4fda,
+    0x5229,0x5398,0x540f,0x550e,0x5c65,0x60a7,0x674e,0x68a8,0x6d6c,0x7281,
+    0x72f8,0x7406,0x7483,0xf962,0x75e2,0x7c6c,0x7f79,0x7fb8,0x8389,0x88cf,
+    0x88e1,0x91cc,0x91d0,0x96e2,0x9bc9,0x541d,0x6f7e,0x71d0,0x7498,0x85fa,
+    0x8eaa,0x96a3,0x9c57,0x9e9f,0x6797,0x6dcb,0x7433,0x81e8,0x9716,0x782c
+  },
+  {				/* ku 58 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7acb,0x7b20,0x7c92,0x6469,
+    0x746a,0x75f2,0x78bc,0x78e8,0x99ac,0x9b54,0x9ebb,0x5bde,0x5e55,0x6f20,
+    0x819c,0x83ab,0x9088,0x4e07,0x534d,0x5a29,0x5dd2,0x5f4e,0x6162,0x633d,
+    0x6669,0x66fc,0x6eff,0x6f2b,0x7063,0x779e,0x842c,0x8513,0x883b,0x8f13,
+    0x9945,0x9c3b,0x551c,0x62b9,0x672b,0x6cab,0x8309,0x896a,0x977a,0x4ea1,
+    0x5984,0x5fd8,0x5fd9,0x671b,0x7db2,0x7f54,0x8292,0x832b,0x83bd,0x8f1e,
+    0x9099,0x57cb,0x59b9,0x5a92,0x5bd0,0x6627,0x679a,0x6885,0x6bcf,0x7164,
+    0x7f75,0x8cb7,0x8ce3,0x9081,0x9b45,0x8108,0x8c8a,0x964c,0x9a40,0x9ea5,
+    0x5b5f,0x6c13,0x731b,0x76f2,0x76df,0x840c,0x51aa,0x8993,0x514d,0x5195,
+    0x52c9,0x68c9,0x6c94,0x7704,0x7720,0x7dbf,0x7dec,0x9762,0x9eb5,0x6ec5
+  },
+  {				/* ku 59 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8511,0x51a5,0x540d,0x547d,
+    0x660e,0x669d,0x6927,0x6e9f,0x76bf,0x7791,0x8317,0x84c2,0x879f,0x9169,
+    0x9298,0x9cf4,0x8882,0x4fae,0x5192,0x52df,0x59c6,0x5e3d,0x6155,0x6478,
+    0x6479,0x66ae,0x67d0,0x6a21,0x6bcd,0x6bdb,0x725f,0x7261,0x7441,0x7738,
+    0x77db,0x8017,0x82bc,0x8305,0x8b00,0x8b28,0x8c8c,0x6728,0x6c90,0x7267,
+    0x76ee,0x7766,0x7a46,0x9da9,0x6b7f,0x6c92,0x5922,0x6726,0x8499,0x536f,
+    0x5893,0x5999,0x5edf,0x63cf,0x6634,0x6773,0x6e3a,0x732b,0x7ad7,0x82d7,
+    0x9328,0x52d9,0x5deb,0x61ae,0x61cb,0x620a,0x62c7,0x64ab,0x65e0,0x6959,
+    0x6b66,0x6bcb,0x7121,0x73f7,0x755d,0x7e46,0x821e,0x8302,0x856a,0x8aa3,
+    0x8cbf,0x9727,0x9d61,0x58a8,0x9ed8,0x5011,0x520e,0x543b,0x554f,0x6587
+  },
+  {				/* ku 5a */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6c76,0x7d0a,0x7d0b,0x805e,
+    0x868a,0x9580,0x96ef,0x52ff,0x6c95,0x7269,0x5473,0x5a9a,0x5c3e,0x5d4b,
+    0x5f4c,0x5fae,0x672a,0x68b6,0x6963,0x6e3c,0x6e44,0x7709,0x7c73,0x7f8e,
+    0x8587,0x8b0e,0x8ff7,0x9761,0x9ef4,0x5cb7,0x60b6,0x610d,0x61ab,0x654f,
+    0x65fb,0x65fc,0x6c11,0x6cef,0x739f,0x73c9,0x7de1,0x9594,0x5bc6,0x871c,
+    0x8b10,0x525d,0x535a,0x62cd,0x640f,0x64b2,0x6734,0x6a38,0x6cca,0x73c0,
+    0x749e,0x7b94,0x7c95,0x7e1b,0x818a,0x8236,0x8584,0x8feb,0x96f9,0x99c1,
+    0x4f34,0x534a,0x53cd,0x53db,0x62cc,0x642c,0x6500,0x6591,0x69c3,0x6cee,
+    0x6f58,0x73ed,0x7554,0x7622,0x76e4,0x76fc,0x78d0,0x78fb,0x792c,0x7d46,
+    0x822c,0x87e0,0x8fd4,0x9812,0x98ef,0x52c3,0x62d4,0x64a5,0x6e24,0x6f51
+  },
+  {				/* ku 5b */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x767c,0x8dcb,0x91b1,0x9262,
+    0x9aee,0x9b43,0x5023,0x508d,0x574a,0x59a8,0x5c28,0x5e47,0x5f77,0x623f,
+    0x653e,0x65b9,0x65c1,0x6609,0x678b,0x699c,0x6ec2,0x78c5,0x7d21,0x80aa,
+    0x8180,0x822b,0x82b3,0x84a1,0x868c,0x8a2a,0x8b17,0x90a6,0x9632,0x9f90,
+    0x500d,0x4ff3,0xf963,0x57f9,0x5f98,0x62dc,0x6392,0x676f,0x6e43,0x7119,
+    0x76c3,0x80cc,0x80da,0x88f4,0x88f5,0x8919,0x8ce0,0x8f29,0x914d,0x966a,
+    0x4f2f,0x4f70,0x5e1b,0x67cf,0x6822,0x767d,0x767e,0x9b44,0x5e61,0x6a0a,
+    0x7169,0x71d4,0x756a,0xf964,0x7e41,0x8543,0x85e9,0x98dc,0x4f10,0x7b4f,
+    0x7f70,0x95a5,0x51e1,0x5e06,0x68b5,0x6c3e,0x6c4e,0x6cdb,0x72af,0x7bc4,
+    0x8303,0x6cd5,0x743a,0x50fb,0x5288,0x58c1,0x64d8,0x6a97,0x74a7,0x7656
+  },
+  {				/* ku 5c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x78a7,0x8617,0x95e2,0x9739,
+    0xf965,0x535e,0x5f01,0x8b8a,0x8fa8,0x8faf,0x908a,0x5225,0x77a5,0x9c49,
+    0x9f08,0x4e19,0x5002,0x5175,0x5c5b,0x5e77,0x661e,0x663a,0x67c4,0x68c5,
+    0x70b3,0x7501,0x75c5,0x79c9,0x7add,0x8f27,0x9920,0x9a08,0x4fdd,0x5821,
+    0x5831,0x5bf6,0x666e,0x6b65,0x6d11,0x6e7a,0x6f7d,0x73e4,0x752b,0x83e9,
+    0x88dc,0x8913,0x8b5c,0x8f14,0x4f0f,0x50d5,0x5310,0x535c,0x5b93,0x5fa9,
+    0x670d,0x798f,0x8179,0x832f,0x8514,0x8907,0x8986,0x8f39,0x8f3b,0x99a5,
+    0x9c12,0x672c,0x4e76,0x4ff8,0x5949,0x5c01,0x5cef,0x5cf0,0x6367,0x68d2,
+    0x70fd,0x71a2,0x742b,0x7e2b,0x84ec,0x8702,0x9022,0x92d2,0x9cf3,0x4e0d,
+    0x4ed8,0x4fef,0x5085,0x5256,0x526f,0x5426,0x5490,0x57e0,0x592b,0x5a66
+  },
+  {				/* ku 5d */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5b5a,0x5b75,0x5bcc,0x5e9c,
+    0xf966,0x6276,0x6577,0x65a7,0x6d6e,0x6ea5,0x7236,0x7b26,0x7c3f,0x7f36,
+    0x8150,0x8151,0x819a,0x8240,0x8299,0x83a9,0x8a03,0x8ca0,0x8ce6,0x8cfb,
+    0x8d74,0x8dba,0x90e8,0x91dc,0x961c,0x9644,0x99d9,0x9ce7,0x5317,0x5206,
+    0x5429,0x5674,0x58b3,0x5954,0x596e,0x5fff,0x61a4,0x626e,0x6610,0x6c7e,
+    0x711a,0x76c6,0x7c89,0x7cde,0x7d1b,0x82ac,0x8cc1,0x96f0,0xf967,0x4f5b,
+    0x5f17,0x5f7f,0x62c2,0x5d29,0x670b,0x68da,0x787c,0x7e43,0x9d6c,0x4e15,
+    0x5099,0x5315,0x532a,0x5351,0x5983,0x5a62,0x5e87,0x60b2,0x618a,0x6249,
+    0x6279,0x6590,0x6787,0x69a7,0x6bd4,0x6bd6,0x6bd7,0x6bd8,0x6cb8,0xf968,
+    0x7435,0x75fa,0x7812,0x7891,0x79d5,0x79d8,0x7c83,0x7dcb,0x7fe1,0x80a5
+  },
+  {				/* ku 5e */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x813e,0x81c2,0x83f2,0x871a,
+    0x88e8,0x8ab9,0x8b6c,0x8cbb,0x9119,0x975e,0x98db,0x9f3b,0x56ac,0x5b2a,
+    0x5f6c,0x658c,0x6ab3,0x6baf,0x6d5c,0x6ff1,0x7015,0x725d,0x73ad,0x8ca7,
+    0x8cd3,0x983b,0x6191,0x6c37,0x8058,0x9a01,0x4e4d,0x4e8b,0x4e9b,0x4ed5,
+    0x4f3a,0x4f3c,0x4f7f,0x4fdf,0x50ff,0x53f2,0x53f8,0x5506,0x55e3,0x56db,
+    0x58eb,0x5962,0x5a11,0x5beb,0x5bfa,0x5c04,0x5df3,0x5e2b,0x5f99,0x601d,
+    0x6368,0x659c,0x65af,0x67f6,0x67fb,0x68ad,0x6b7b,0x6c99,0x6cd7,0x6e23,
+    0x7009,0x7345,0x7802,0x793e,0x7940,0x7960,0x79c1,0x7be9,0x7d17,0x7d72,
+    0x8086,0x820d,0x838e,0x84d1,0x86c7,0x88df,0x8a50,0x8a5e,0x8b1d,0x8cdc,
+    0x8d66,0x8fad,0x90aa,0x98fc,0x99df,0x9e9d,0x524a,0xf969,0x6714,0xf96a
+  },
+  {				/* ku 5f */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5098,0x522a,0x5c71,0x6563,
+    0x6c55,0x73ca,0x7523,0x759d,0x7b97,0x849c,0x9178,0x9730,0x4e77,0x6492,
+    0x6bba,0x715e,0x85a9,0x4e09,0xf96b,0x6749,0x68ee,0x6e17,0x829f,0x8518,
+    0x886b,0x63f7,0x6f81,0x9212,0x98af,0x4e0a,0x50b7,0x50cf,0x511f,0x5546,
+    0x55aa,0x5617,0x5b40,0x5c19,0x5ce0,0x5e38,0x5e8a,0x5ea0,0x5ec2,0x60f3,
+    0x6851,0x6a61,0x6e58,0x723d,0x7240,0x72c0,0x76f8,0x7965,0x7bb1,0x7fd4,
+    0x88f3,0x89f4,0x8a73,0x8c61,0x8cde,0x971c,0x585e,0x74bd,0x8cfd,0x55c7,
+    0xf96c,0x7a61,0x7d22,0x8272,0x7272,0x751f,0x7525,0xf96d,0x7b19,0x5885,
+    0x58fb,0x5dbc,0x5e8f,0x5eb6,0x5f90,0x6055,0x6292,0x637f,0x654d,0x6691,
+    0x66d9,0x66f8,0x6816,0x68f2,0x7280,0x745e,0x7b6e,0x7d6e,0x7dd6,0x7f72
+  },
+  {				/* ku 60 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x80e5,0x8212,0x85af,0x897f,
+    0x8a93,0x901d,0x92e4,0x9ecd,0x9f20,0x5915,0x596d,0x5e2d,0x60dc,0x6614,
+    0x6673,0x6790,0x6c50,0x6dc5,0x6f5f,0x77f3,0x78a9,0x84c6,0x91cb,0x932b,
+    0x4ed9,0x50ca,0x5148,0x5584,0x5b0b,0x5ba3,0x6247,0x657e,0x65cb,0x6e32,
+    0x717d,0x7401,0x7444,0x7487,0x74bf,0x766c,0x79aa,0x7dda,0x7e55,0x7fa8,
+    0x817a,0x81b3,0x8239,0x861a,0x87ec,0x8a75,0x8de3,0x9078,0x9291,0x9425,
+    0x994d,0x9bae,0x5368,0x5c51,0x6954,0x6cc4,0x6d29,0x6e2b,0x820c,0x859b,
+    0x893b,0x8a2d,0x8aaa,0x96ea,0x9f67,0x5261,0x66b9,0x6bb2,0x7e96,0x87fe,
+    0x8d0d,0x9583,0x965d,0x651d,0x6d89,0x71ee,0xf96e,0x57ce,0x59d3,0x5bac,
+    0x6027,0x60fa,0x6210,0x661f,0x665f,0x7329,0x73f9,0x76db,0x7701,0x7b6c
+  },
+  {				/* ku 61 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8056,0x8072,0x8165,0x8aa0,
+    0x9192,0x4e16,0x52e2,0x6b72,0x6d17,0x7a05,0x7b39,0x7d30,0xf96f,0x8cb0,
+    0x53ec,0x562f,0x5851,0x5bb5,0x5c0f,0x5c11,0x5de2,0x6240,0x6383,0x6414,
+    0x662d,0x68b3,0x6cbc,0x6d88,0x6eaf,0x701f,0x70a4,0x71d2,0x7526,0x758f,
+    0x758e,0x7619,0x7b11,0x7be0,0x7c2b,0x7d20,0x7d39,0x852c,0x856d,0x8607,
+    0x8a34,0x900d,0x9061,0x90b5,0x92b7,0x97f6,0x9a37,0x4fd7,0x5c6c,0x675f,
+    0x6d91,0x7c9f,0x7e8c,0x8b16,0x8d16,0x901f,0x5b6b,0x5dfd,0x640d,0x84c0,
+    0x905c,0x98e1,0x7387,0x5b8b,0x609a,0x677e,0x6dde,0x8a1f,0x8aa6,0x9001,
+    0x980c,0x5237,0xf970,0x7051,0x788e,0x9396,0x8870,0x91d7,0x4fee,0x53d7,
+    0x55fd,0x56da,0x5782,0x58fd,0x5ac2,0x5b88,0x5cab,0x5cc0,0x5e25,0x6101
+  },
+  {				/* ku 62 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x620d,0x624b,0x6388,0x641c,
+    0x6536,0x6578,0x6a39,0x6b8a,0x6c34,0x6d19,0x6f31,0x71e7,0x72e9,0x7378,
+    0x7407,0x74b2,0x7626,0x7761,0x79c0,0x7a57,0x7aea,0x7cb9,0x7d8f,0x7dac,
+    0x7e61,0x7f9e,0x8129,0x8331,0x8490,0x84da,0x85ea,0x8896,0x8ab0,0x8b90,
+    0x8f38,0x9042,0x9083,0x916c,0x9296,0x92b9,0x968b,0x96a7,0x96a8,0x96d6,
+    0x9700,0x9808,0x9996,0x9ad3,0x9b1a,0x53d4,0x587e,0x5919,0x5b70,0x5bbf,
+    0x6dd1,0x6f5a,0x719f,0x7421,0x74b9,0x8085,0x83fd,0x5de1,0x5f87,0x5faa,
+    0x6042,0x65ec,0x6812,0x696f,0x6a53,0x6b89,0x6d35,0x6df3,0x73e3,0x76fe,
+    0x77ac,0x7b4d,0x7d14,0x8123,0x821c,0x8340,0x84f4,0x8563,0x8a62,0x8ac4,
+    0x9187,0x931e,0x9806,0x99b4,0x620c,0x8853,0x8ff0,0x9265,0x5d07,0x5d27
+  },
+  {				/* ku 63 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5d69,0x745f,0x819d,0x8768,
+    0x6fd5,0x62fe,0x7fd2,0x8936,0x8972,0x4e1e,0x4e58,0x50e7,0x52dd,0x5347,
+    0x627f,0x6607,0x7e69,0x8805,0x965e,0x4f8d,0x5319,0x5636,0x59cb,0x5aa4,
+    0x5c38,0x5c4e,0x5c4d,0x5e02,0x5f11,0x6043,0x65bd,0x662f,0x6642,0x67be,
+    0x67f4,0x731c,0x77e2,0x793a,0x7fc5,0x8494,0x84cd,0x8996,0x8a66,0x8a69,
+    0x8ae1,0x8c55,0x8c7a,0x57f4,0x5bd4,0x5f0f,0x606f,0x62ed,0x690d,0x6b96,
+    0x6e5c,0x7184,0x7bd2,0x8755,0x8b58,0x8efe,0x98df,0x98fe,0x4f38,0x4f81,
+    0x4fe1,0x547b,0x5a20,0x5bb8,0x613c,0x65b0,0x6668,0x71fc,0x7533,0x795e,
+    0x7d33,0x814e,0x81e3,0x8398,0x85aa,0x85ce,0x8703,0x8a0a,0x8eab,0x8f9b,
+    0xf971,0x8fc5,0x5931,0x5ba4,0x5be6,0x6089,0x5be9,0x5c0b,0x5fc3,0x6c81
+  },
+  {				/* ku 64 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xf972,0x6df1,0x700b,0x751a,
+    0x82af,0x8af6,0x4ec0,0x5341,0xf973,0x96d9,0x6c0f,0x4e9e,0x4fc4,0x5152,
+    0x555e,0x5a25,0x5ce8,0x6211,0x7259,0x82bd,0x83aa,0x86fe,0x8859,0x8a1d,
+    0x963f,0x96c5,0x9913,0x9d09,0x9d5d,0x580a,0x5cb3,0x5dbd,0x5e44,0x60e1,
+    0x6115,0x63e1,0x6a02,0x6e25,0x9102,0x9354,0x984e,0x9c10,0x9f77,0x5b89,
+    0x5cb8,0x6309,0x664f,0x6848,0x773c,0x96c1,0x978d,0x9854,0x9b9f,0x65a1,
+    0x8b01,0x8ecb,0x95bc,0x5535,0x5ca9,0x5dd6,0x5eb5,0x6697,0x764c,0x83f4,
+    0x95c7,0x58d3,0x62bc,0x72ce,0x9d28,0x4ef0,0x592e,0x600f,0x663b,0x6b83,
+    0x79e7,0x9d26,0x5393,0x54c0,0x57c3,0x5d16,0x611b,0x66d6,0x6daf,0x788d,
+    0x827e,0x9698,0x9744,0x5384,0x627c,0x6396,0x6db2,0x7e0a,0x814b,0x984d
+  },
+  {				/* ku 65 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6afb,0x7f4c,0x9daf,0x9e1a,
+    0x4e5f,0x503b,0x51b6,0x591c,0x60f9,0x63f6,0x6930,0x723a,0x8036,0xf974,
+    0x91ce,0x5f31,0xf975,0xf976,0x7d04,0x82e5,0x846f,0x84bb,0x85e5,0x8e8d,
+    0xf977,0x4f6f,0xf978,0xf979,0x58e4,0x5b43,0x6059,0x63da,0x6518,0x656d,
+    0x6698,0xf97a,0x694a,0x6a23,0x6d0b,0x7001,0x716c,0x75d2,0x760d,0x79b3,
+    0x7a70,0xf97b,0x7f8a,0xf97c,0x8944,0xf97d,0x8b93,0x91c0,0x967d,0xf97e,
+    0x990a,0x5704,0x5fa1,0x65bc,0x6f01,0x7600,0x79a6,0x8a9e,0x99ad,0x9b5a,
+    0x9f6c,0x5104,0x61b6,0x6291,0x6a8d,0x81c6,0x5043,0x5830,0x5f66,0x7109,
+    0x8a00,0x8afa,0x5b7c,0x8616,0x4ffa,0x513c,0x56b4,0x5944,0x63a9,0x6df9,
+    0x5daa,0x696d,0x5186,0x4e88,0x4f59,0xf97f,0xf980,0xf981,0x5982,0xf982
+  },
+  {				/* ku 66 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xf983,0x6b5f,0x6c5d,0xf984,
+    0x74b5,0x7916,0xf985,0x8207,0x8245,0x8339,0x8f3f,0x8f5d,0xf986,0x9918,
+    0xf987,0xf988,0xf989,0x4ea6,0xf98a,0x57df,0x5f79,0x6613,0xf98b,0xf98c,
+    0x75ab,0x7e79,0x8b6f,0xf98d,0x9006,0x9a5b,0x56a5,0x5827,0x59f8,0x5a1f,
+    0x5bb4,0xf98e,0x5ef6,0xf98f,0xf990,0x6350,0x633b,0xf991,0x693d,0x6c87,
+    0x6cbf,0x6d8e,0x6d93,0x6df5,0x6f14,0xf992,0x70df,0x7136,0x7159,0xf993,
+    0x71c3,0x71d5,0xf994,0x784f,0x786f,0xf995,0x7b75,0x7de3,0xf996,0x7e2f,
+    0xf997,0x884d,0x8edf,0xf998,0xf999,0xf99a,0x925b,0xf99b,0x9cf6,0xf99c,
+    0xf99d,0xf99e,0x6085,0x6d85,0xf99f,0x71b1,0xf9a0,0xf9a1,0x95b1,0x53ad,
+    0xf9a2,0xf9a3,0xf9a4,0x67d3,0xf9a5,0x708e,0x7130,0x7430,0x8276,0x82d2
+  },
+  {				/* ku 67 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xf9a6,0x95bb,0x9ae5,0x9e7d,
+    0x66c4,0xf9a7,0x71c1,0x8449,0xf9a8,0xf9a9,0x584b,0xf9aa,0xf9ab,0x5db8,
+    0x5f71,0xf9ac,0x6620,0x668e,0x6979,0x69ae,0x6c38,0x6cf3,0x6e36,0x6f41,
+    0x6fda,0x701b,0x702f,0x7150,0x71df,0x7370,0xf9ad,0x745b,0xf9ae,0x74d4,
+    0x76c8,0x7a4e,0x7e93,0xf9af,0xf9b0,0x82f1,0x8a60,0x8fce,0xf9b1,0x9348,
+    0xf9b2,0x9719,0xf9b3,0xf9b4,0x4e42,0x502a,0xf9b5,0x5208,0x53e1,0x66f3,
+    0x6c6d,0x6fca,0x730a,0x777f,0x7a62,0x82ae,0x85dd,0x8602,0xf9b6,0x88d4,
+    0x8a63,0x8b7d,0x8c6b,0xf9b7,0x92b3,0xf9b8,0x9713,0x9810,0x4e94,0x4f0d,
+    0x4fc9,0x50b2,0x5348,0x543e,0x5433,0x55da,0x5862,0x58ba,0x5967,0x5a1b,
+    0x5be4,0x609f,0xf9b9,0x61ca,0x6556,0x65ff,0x6664,0x68a7,0x6c5a,0x6fb3
+  },
+  {				/* ku 68 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x70cf,0x71ac,0x7352,0x7b7d,
+    0x8708,0x8aa4,0x9c32,0x9f07,0x5c4b,0x6c83,0x7344,0x7389,0x923a,0x6eab,
+    0x7465,0x761f,0x7a69,0x7e15,0x860a,0x5140,0x58c5,0x64c1,0x74ee,0x7515,
+    0x7670,0x7fc1,0x9095,0x96cd,0x9954,0x6e26,0x74e6,0x7aa9,0x7aaa,0x81e5,
+    0x86d9,0x8778,0x8a1b,0x5a49,0x5b8c,0x5b9b,0x68a1,0x6900,0x6d63,0x73a9,
+    0x7413,0x742c,0x7897,0x7de9,0x7feb,0x8118,0x8155,0x839e,0x8c4c,0x962e,
+    0x9811,0x66f0,0x5f80,0x65fa,0x6789,0x6c6a,0x738b,0x502d,0x5a03,0x6b6a,
+    0x77ee,0x5916,0x5d6c,0x5dcd,0x7325,0x754f,0xf9ba,0xf9bb,0x50e5,0x51f9,
+    0x582f,0x592d,0x5996,0x59da,0x5be5,0xf9bc,0xf9bd,0x5da2,0x62d7,0x6416,
+    0x6493,0x64fe,0xf9be,0x66dc,0xf9bf,0x6a48,0xf9c0,0x71ff,0x7464,0xf9c1
+  },
+  {				/* ku 69 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x7a88,0x7aaf,0x7e47,0x7e5e,
+    0x8000,0x8170,0xf9c2,0x87ef,0x8981,0x8b20,0x9059,0xf9c3,0x9080,0x9952,
+    0x617e,0x6b32,0x6d74,0x7e1f,0x8925,0x8fb1,0x4fd1,0x50ad,0x5197,0x52c7,
+    0x57c7,0x5889,0x5bb9,0x5eb8,0x6142,0x6995,0x6d8c,0x6e67,0x6eb6,0x7194,
+    0x7462,0x7528,0x752c,0x8073,0x8338,0x84c9,0x8e0a,0x9394,0x93de,0xf9c4,
+    0x4e8e,0x4f51,0x5076,0x512a,0x53c8,0x53cb,0x53f3,0x5b87,0x5bd3,0x5c24,
+    0x611a,0x6182,0x65f4,0x725b,0x7397,0x7440,0x76c2,0x7950,0x7991,0x79b9,
+    0x7d06,0x7fbd,0x828b,0x85d5,0x865e,0x8fc2,0x9047,0x90f5,0x91ea,0x9685,
+    0x96e8,0x96e9,0x52d6,0x5f67,0x65ed,0x6631,0x682f,0x715c,0x7a36,0x90c1,
+    0x980a,0x4e91,0xf9c5,0x6a52,0x6b9e,0x6f90,0x7189,0x8018,0x82b8,0x8553
+  },
+  {				/* ku 6a */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x904b,0x9695,0x96f2,0x97fb,
+    0x851a,0x9b31,0x4e90,0x718a,0x96c4,0x5143,0x539f,0x54e1,0x5713,0x5712,
+    0x57a3,0x5a9b,0x5ac4,0x5bc3,0x6028,0x613f,0x63f4,0x6c85,0x6d39,0x6e72,
+    0x6e90,0x7230,0x733f,0x7457,0x82d1,0x8881,0x8f45,0x9060,0xf9c6,0x9662,
+    0x9858,0x9d1b,0x6708,0x8d8a,0x925e,0x4f4d,0x5049,0x50de,0x5371,0x570d,
+    0x59d4,0x5a01,0x5c09,0x6170,0x6690,0x6e2d,0x7232,0x744b,0x7def,0x80c3,
+    0x840e,0x8466,0x853f,0x875f,0x885b,0x8918,0x8b02,0x9055,0x97cb,0x9b4f,
+    0x4e73,0x4f91,0x5112,0x516a,0xf9c7,0x552f,0x55a9,0x5b7a,0x5ba5,0x5e7c,
+    0x5e7d,0x5ebe,0x60a0,0x60df,0x6108,0x6109,0x63c4,0x6538,0x6709,0xf9c8,
+    0x67d4,0x67da,0xf9c9,0x6961,0x6962,0x6cb9,0x6d27,0xf9ca,0x6e38,0xf9cb
+  },
+  {				/* ku 6b */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6fe1,0x7336,0x7337,0xf9cc,
+    0x745c,0x7531,0xf9cd,0x7652,0xf9ce,0xf9cf,0x7dad,0x81fe,0x8438,0x88d5,
+    0x8a98,0x8adb,0x8aed,0x8e30,0x8e42,0x904a,0x903e,0x907a,0x9149,0x91c9,
+    0x936e,0xf9d0,0xf9d1,0x5809,0xf9d2,0x6bd3,0x8089,0x80b2,0xf9d3,0xf9d4,
+    0x5141,0x596b,0x5c39,0xf9d5,0xf9d6,0x6f64,0x73a7,0x80e4,0x8d07,0xf9d7,
+    0x9217,0x958f,0xf9d8,0xf9d9,0xf9da,0xf9db,0x807f,0x620e,0x701c,0x7d68,
+    0x878d,0xf9dc,0x57a0,0x6069,0x6147,0x6bb7,0x8abe,0x9280,0x96b1,0x4e59,
+    0x541f,0x6deb,0x852d,0x9670,0x97f3,0x98ee,0x63d6,0x6ce3,0x9091,0x51dd,
+    0x61c9,0x81ba,0x9df9,0x4f9d,0x501a,0x5100,0x5b9c,0x610f,0x61ff,0x64ec,
+    0x6905,0x6bc5,0x7591,0x77e3,0x7fa9,0x8264,0x858f,0x87fb,0x8863,0x8abc
+  },
+  {				/* ku 6c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8b70,0x91ab,0x4e8c,0x4ee5,
+    0x4f0a,0xf9dd,0xf9de,0x5937,0x59e8,0xf9df,0x5df2,0x5f1b,0x5f5b,0x6021,
+    0xf9e0,0xf9e1,0xf9e2,0xf9e3,0x723e,0x73e5,0xf9e4,0x7570,0x75cd,0xf9e5,
+    0x79fb,0xf9e6,0x800c,0x8033,0x8084,0x82e1,0x8351,0xf9e7,0xf9e8,0x8cbd,
+    0x8cb3,0x9087,0xf9e9,0xf9ea,0x98f4,0x990c,0xf9eb,0xf9ec,0x7037,0x76ca,
+    0x7fca,0x7fcc,0x7ffc,0x8b1a,0x4eba,0x4ec1,0x5203,0x5370,0xf9ed,0x54bd,
+    0x56e0,0x59fb,0x5bc5,0x5f15,0x5fcd,0x6e6e,0xf9ee,0xf9ef,0x7d6a,0x8335,
+    0xf9f0,0x8693,0x8a8d,0xf9f1,0x976d,0x9777,0xf9f2,0xf9f3,0x4e00,0x4f5a,
+    0x4f7e,0x58f9,0x65e5,0x6ea2,0x9038,0x93b0,0x99b9,0x4efb,0x58ec,0x598a,
+    0x59d9,0x6041,0xf9f4,0xf9f5,0x7a14,0xf9f6,0x834f,0x8cc3,0x5165,0x5344
+  },
+  {				/* ku 6d */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xf9f7,0xf9f8,0xf9f9,0x4ecd,
+    0x5269,0x5b55,0x82bf,0x4ed4,0x523a,0x54a8,0x59c9,0x59ff,0x5b50,0x5b57,
+    0x5b5c,0x6063,0x6148,0x6ecb,0x7099,0x716e,0x7386,0x74f7,0x75b5,0x78c1,
+    0x7d2b,0x8005,0x81ea,0x8328,0x8517,0x85c9,0x8aee,0x8cc7,0x96cc,0x4f5c,
+    0x52fa,0x56bc,0x65ab,0x6628,0x707c,0x70b8,0x7235,0x7dbd,0x828d,0x914c,
+    0x96c0,0x9d72,0x5b71,0x68e7,0x6b98,0x6f7a,0x76de,0x5c91,0x66ab,0x6f5b,
+    0x7bb4,0x7c2a,0x8836,0x96dc,0x4e08,0x4ed7,0x5320,0x5834,0x58bb,0x58ef,
+    0x596c,0x5c07,0x5e33,0x5e84,0x5f35,0x638c,0x66b2,0x6756,0x6a1f,0x6aa3,
+    0x6b0c,0x6f3f,0x7246,0xf9fa,0x7350,0x748b,0x7ae0,0x7ca7,0x8178,0x81df,
+    0x81e7,0x838a,0x846c,0x8523,0x8594,0x85cf,0x88dd,0x8d13,0x91ac,0x9577
+  },
+  {				/* ku 6e */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x969c,0x518d,0x54c9,0x5728,
+    0x5bb0,0x624d,0x6750,0x683d,0x6893,0x6e3d,0x6ed3,0x707d,0x7e21,0x88c1,
+    0x8ca1,0x8f09,0x9f4b,0x9f4e,0x722d,0x7b8f,0x8acd,0x931a,0x4f47,0x4f4e,
+    0x5132,0x5480,0x59d0,0x5e95,0x62b5,0x6775,0x696e,0x6a17,0x6cae,0x6e1a,
+    0x72d9,0x732a,0x75bd,0x7bb8,0x7d35,0x82e7,0x83f9,0x8457,0x85f7,0x8a5b,
+    0x8caf,0x8e87,0x9019,0x90b8,0x96ce,0x9f5f,0x52e3,0x540a,0x5ae1,0x5bc2,
+    0x6458,0x6575,0x6ef4,0x72c4,0xf9fb,0x7684,0x7a4d,0x7b1b,0x7c4d,0x7e3e,
+    0x7fdf,0x837b,0x8b2b,0x8cca,0x8d64,0x8de1,0x8e5f,0x8fea,0x8ff9,0x9069,
+    0x93d1,0x4f43,0x4f7a,0x50b3,0x5168,0x5178,0x524d,0x526a,0x5861,0x587c,
+    0x5960,0x5c08,0x5c55,0x5edb,0x609b,0x6230,0x6813,0x6bbf,0x6c08,0x6fb1
+  },
+  {				/* ku 6f */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x714e,0x7420,0x7530,0x7538,
+    0x7551,0x7672,0x7b4c,0x7b8b,0x7bad,0x7bc6,0x7e8f,0x8a6e,0x8f3e,0x8f49,
+    0x923f,0x9293,0x9322,0x942b,0x96fb,0x985a,0x986b,0x991e,0x5207,0x622a,
+    0x6298,0x6d59,0x7664,0x7aca,0x7bc0,0x7d76,0x5360,0x5cbe,0x5e97,0x6f38,
+    0x70b9,0x7c98,0x9711,0x9b8e,0x9ede,0x63a5,0x647a,0x8776,0x4e01,0x4e95,
+    0x4ead,0x505c,0x5075,0x5448,0x59c3,0x5b9a,0x5e40,0x5ead,0x5ef7,0x5f81,
+    0x60c5,0x633a,0x653f,0x6574,0x65cc,0x6676,0x6678,0x67fe,0x6968,0x6a89,
+    0x6b63,0x6c40,0x6dc0,0x6de8,0x6e1f,0x6e5e,0x701e,0x70a1,0x738e,0x73fd,
+    0x753a,0x775b,0x7887,0x798e,0x7a0b,0x7a7d,0x7cbe,0x7d8e,0x8247,0x8a02,
+    0x8aea,0x8c9e,0x912d,0x914a,0x91d8,0x9266,0x92cc,0x9320,0x9706,0x9756
+  },
+  {				/* ku 70 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x975c,0x9802,0x9f0e,0x5236,
+    0x5291,0x557c,0x5824,0x5e1d,0x5f1f,0x608c,0x63d0,0x68af,0x6fdf,0x796d,
+    0x7b2c,0x81cd,0x85ba,0x88fd,0x8af8,0x8e44,0x918d,0x9664,0x969b,0x973d,
+    0x984c,0x9f4a,0x4fce,0x5146,0x51cb,0x52a9,0x5632,0x5f14,0x5f6b,0x63aa,
+    0x64cd,0x65e9,0x6641,0x66fa,0x66f9,0x671d,0x689d,0x68d7,0x69fd,0x6f15,
+    0x6f6e,0x7167,0x71e5,0x722a,0x74aa,0x773a,0x7956,0x795a,0x79df,0x7a20,
+    0x7a95,0x7c97,0x7cdf,0x7d44,0x7e70,0x8087,0x85fb,0x86a4,0x8a54,0x8abf,
+    0x8d99,0x8e81,0x9020,0x906d,0x91e3,0x963b,0x96d5,0x9ce5,0x65cf,0x7c07,
+    0x8db3,0x93c3,0x5b58,0x5c0a,0x5352,0x62d9,0x731d,0x5027,0x5b97,0x5f9e,
+    0x60b0,0x616b,0x68d5,0x6dd9,0x742e,0x7a2e,0x7d42,0x7d9c,0x7e31,0x816b
+  },
+  {				/* ku 71 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8e2a,0x8e35,0x937e,0x9418,
+    0x4f50,0x5750,0x5de6,0x5ea7,0x632b,0x7f6a,0x4e3b,0x4f4f,0x4f8f,0x505a,
+    0x59dd,0x80c4,0x546a,0x5468,0x55fe,0x594f,0x5b99,0x5dde,0x5eda,0x665d,
+    0x6731,0x67f1,0x682a,0x6ce8,0x6d32,0x6e4a,0x6f8d,0x70b7,0x73e0,0x7587,
+    0x7c4c,0x7d02,0x7d2c,0x7da2,0x821f,0x86db,0x8a3b,0x8a85,0x8d70,0x8e8a,
+    0x8f33,0x9031,0x914e,0x9152,0x9444,0x99d0,0x7af9,0x7ca5,0x4fca,0x5101,
+    0x51c6,0x57c8,0x5bef,0x5cfb,0x6659,0x6a3d,0x6d5a,0x6e96,0x6fec,0x710c,
+    0x756f,0x7ae3,0x8822,0x9021,0x9075,0x96cb,0x99ff,0x8301,0x4e2d,0x4ef2,
+    0x8846,0x91cd,0x537d,0x6adb,0x696b,0x6c41,0x847a,0x589e,0x618e,0x66fe,
+    0x62ef,0x70dd,0x7511,0x75c7,0x7e52,0x84b8,0x8b49,0x8d08,0x4e4b,0x53ea
+  },
+  {				/* ku 72 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x54ab,0x5730,0x5740,0x5fd7,
+    0x6301,0x6307,0x646f,0x652f,0x65e8,0x667a,0x679d,0x67b3,0x6b62,0x6c60,
+    0x6c9a,0x6f2c,0x77e5,0x7825,0x7949,0x7957,0x7d19,0x80a2,0x8102,0x81f3,
+    0x829d,0x82b7,0x8718,0x8a8c,0xf9fc,0x8d04,0x8dbe,0x9072,0x76f4,0x7a19,
+    0x7a37,0x7e54,0x8077,0x5507,0x55d4,0x5875,0x632f,0x6422,0x6649,0x664b,
+    0x686d,0x699b,0x6b84,0x6d25,0x6eb1,0x73cd,0x7468,0x74a1,0x755b,0x75b9,
+    0x76e1,0x771e,0x778b,0x79e6,0x7e09,0x7e1d,0x81fb,0x852f,0x8897,0x8a3a,
+    0x8cd1,0x8eeb,0x8fb0,0x9032,0x93ad,0x9663,0x9673,0x9707,0x4f84,0x53f1,
+    0x59ea,0x5ac9,0x5e19,0x684e,0x74c6,0x75be,0x79e9,0x7a92,0x81a3,0x86ed,
+    0x8cea,0x8dcc,0x8fed,0x659f,0x6715,0xf9fd,0x57f7,0x6f57,0x7ddd,0x8f2f
+  },
+  {				/* ku 73 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x93f6,0x96c6,0x5fb5,0x61f2,
+    0x6f84,0x4e14,0x4f98,0x501f,0x53c9,0x55df,0x5d6f,0x5dee,0x6b21,0x6b64,
+    0x78cb,0x7b9a,0xf9fe,0x8e49,0x8eca,0x906e,0x6349,0x643e,0x7740,0x7a84,
+    0x932f,0x947f,0x9f6a,0x64b0,0x6faf,0x71e6,0x74a8,0x74da,0x7ac4,0x7c12,
+    0x7e82,0x7cb2,0x7e98,0x8b9a,0x8d0a,0x947d,0x9910,0x994c,0x5239,0x5bdf,
+    0x64e6,0x672d,0x7d2e,0x50ed,0x53c3,0x5879,0x6158,0x6159,0x61fa,0x65ac,
+    0x7ad9,0x8b92,0x8b96,0x5009,0x5021,0x5275,0x5531,0x5a3c,0x5ee0,0x5f70,
+    0x6134,0x655e,0x660c,0x6636,0x66a2,0x69cd,0x6ec4,0x6f32,0x7316,0x7621,
+    0x7a93,0x8139,0x8259,0x83d6,0x84bc,0x50b5,0x57f0,0x5bc0,0x5be8,0x5f69,
+    0x63a1,0x7826,0x7db5,0x83dc,0x8521,0x91c7,0x91f5,0x518a,0x67f5,0x7b56
+  },
+  {				/* ku 74 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8cac,0x51c4,0x59bb,0x60bd,
+    0x8655,0x501c,0xf9ff,0x5254,0x5c3a,0x617d,0x621a,0x62d3,0x64f2,0x65a5,
+    0x6ecc,0x7620,0x810a,0x8e60,0x965f,0x96bb,0x4edf,0x5343,0x5598,0x5929,
+    0x5ddd,0x64c5,0x6cc9,0x6dfa,0x7394,0x7a7f,0x821b,0x85a6,0x8ce4,0x8e10,
+    0x9077,0x91e7,0x95e1,0x9621,0x97c6,0x51f8,0x54f2,0x5586,0x5fb9,0x64a4,
+    0x6f88,0x7db4,0x8f1f,0x8f4d,0x9435,0x50c9,0x5c16,0x6cbe,0x6dfb,0x751b,
+    0x77bb,0x7c3d,0x7c64,0x8a79,0x8ac2,0x581e,0x59be,0x5e16,0x6377,0x7252,
+    0x758a,0x776b,0x8adc,0x8cbc,0x8f12,0x5ef3,0x6674,0x6df8,0x807d,0x83c1,
+    0x8acb,0x9751,0x9bd6,0xfa00,0x5243,0x66ff,0x6d95,0x6eef,0x7de0,0x8ae6,
+    0x902e,0x905e,0x9ad4,0x521d,0x527f,0x54e8,0x6194,0x6284,0x62db,0x68a2
+  },
+  {				/* ku 75 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x6912,0x695a,0x6a35,0x7092,
+    0x7126,0x785d,0x7901,0x790e,0x79d2,0x7a0d,0x8096,0x8278,0x82d5,0x8349,
+    0x8549,0x8c82,0x8d85,0x9162,0x918b,0x91ae,0x4fc3,0x56d1,0x71ed,0x77d7,
+    0x8700,0x89f8,0x5bf8,0x5fd6,0x6751,0x90a8,0x53e2,0x585a,0x5bf5,0x60a4,
+    0x6181,0x6460,0x7e3d,0x8070,0x8525,0x9283,0x64ae,0x50ac,0x5d14,0x6700,
+    0x589c,0x62bd,0x63a8,0x690e,0x6978,0x6a1e,0x6e6b,0x76ba,0x79cb,0x82bb,
+    0x8429,0x8acf,0x8da8,0x8ffd,0x9112,0x914b,0x919c,0x9310,0x9318,0x939a,
+    0x96db,0x9a36,0x9c0d,0x4e11,0x755c,0x795d,0x7afa,0x7b51,0x7bc9,0x7e2e,
+    0x84c4,0x8e59,0x8e74,0x8ef8,0x9010,0x6625,0x693f,0x7443,0x51fa,0x672e,
+    0x9edc,0x5145,0x5fe0,0x6c96,0x87f2,0x885d,0x8877,0x60b4,0x81b5,0x8403
+  },
+  {				/* ku 76 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x8d05,0x53d6,0x5439,0x5634,
+    0x5a36,0x5c31,0x708a,0x7fe0,0x805a,0x8106,0x81ed,0x8da3,0x9189,0x9a5f,
+    0x9df2,0x5074,0x4ec4,0x53a0,0x60fb,0x6e2c,0x5c64,0x4f88,0x5024,0x55e4,
+    0x5cd9,0x5e5f,0x6065,0x6894,0x6cbb,0x6dc4,0x71be,0x75d4,0x75f4,0x7661,
+    0x7a1a,0x7a49,0x7dc7,0x7dfb,0x7f6e,0x81f4,0x86a9,0x8f1c,0x96c9,0x99b3,
+    0x9f52,0x5247,0x52c5,0x98ed,0x89aa,0x4e03,0x67d2,0x6f06,0x4fb5,0x5be2,
+    0x6795,0x6c88,0x6d78,0x741b,0x7827,0x91dd,0x937c,0x87c4,0x79e4,0x7a31,
+    0x5feb,0x4ed6,0x54a4,0x553e,0x58ae,0x59a5,0x60f0,0x6253,0x62d6,0x6736,
+    0x6955,0x8235,0x9640,0x99b1,0x99dd,0x502c,0x5353,0x5544,0x577c,0xfa01,
+    0x6258,0xfa02,0x64e2,0x666b,0x67dd,0x6fc1,0x6fef,0x7422,0x7438,0x8a17
+  },
+  {				/* ku 77 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x9438,0x5451,0x5606,0x5766,
+    0x5f48,0x619a,0x6b4e,0x7058,0x70ad,0x7dbb,0x8a95,0x596a,0x812b,0x63a2,
+    0x7708,0x803d,0x8caa,0x5854,0x642d,0x69bb,0x5b95,0x5e11,0x6e6f,0xfa03,
+    0x8569,0x514c,0x53f0,0x592a,0x6020,0x614b,0x6b86,0x6c70,0x6cf0,0x7b1e,
+    0x80ce,0x82d4,0x8dc6,0x90b0,0x98b1,0xfa04,0x64c7,0x6fa4,0x6491,0x6504,
+    0x514e,0x5410,0x571f,0x8a0e,0x615f,0x6876,0xfa05,0x75db,0x7b52,0x7d71,
+    0x901a,0x5806,0x69cc,0x817f,0x892a,0x9000,0x9839,0x5078,0x5957,0x59ac,
+    0x6295,0x900f,0x9b2a,0x615d,0x7279,0x95d6,0x5761,0x5a46,0x5df4,0x628a,
+    0x64ad,0x64fa,0x6777,0x6ce2,0x6d3e,0x722c,0x7436,0x7834,0x7f77,0x82ad,
+    0x8ddb,0x9817,0x5224,0x5742,0x677f,0x7248,0x74e3,0x8ca9,0x8fa6,0x9211
+  },
+  {				/* ku 78 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x962a,0x516b,0x53ed,0x634c,
+    0x4f69,0x5504,0x6096,0x6557,0x6c9b,0x6d7f,0x724c,0x72fd,0x7a17,0x8987,
+    0x8c9d,0x5f6d,0x6f8e,0x70f9,0x81a8,0x610e,0x4fbf,0x504f,0x6241,0x7247,
+    0x7bc7,0x7de8,0x7fe9,0x904d,0x97ad,0x9a19,0x8cb6,0x576a,0x5e73,0x67b0,
+    0x840d,0x8a55,0x5420,0x5b16,0x5e63,0x5ee2,0x5f0a,0x6583,0x80ba,0x853d,
+    0x9589,0x965b,0x4f48,0x5305,0x530d,0x530f,0x5486,0x54fa,0x5703,0x5e03,
+    0x6016,0x629b,0x62b1,0x6355,0xfa06,0x6ce1,0x6d66,0x75b1,0x7832,0x80de,
+    0x812f,0x82de,0x8461,0x84b2,0x888d,0x8912,0x900b,0x92ea,0x98fd,0x9b91,
+    0x5e45,0x66b4,0x66dd,0x7011,0x7206,0xfa07,0x4ff5,0x527d,0x5f6a,0x6153,
+    0x6753,0x6a19,0x6f02,0x74e2,0x7968,0x8868,0x8c79,0x98c7,0x98c4,0x9a43
+  },
+  {				/* ku 79 */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x54c1,0x7a1f,0x6953,0x8af7,
+    0x8c4a,0x98a8,0x99ae,0x5f7c,0x62ab,0x75b2,0x76ae,0x88ab,0x907f,0x9642,
+    0x5339,0x5f3c,0x5fc5,0x6ccc,0x73cc,0x7562,0x758b,0x7b46,0x82fe,0x999d,
+    0x4e4f,0x903c,0x4e0b,0x4f55,0x53a6,0x590f,0x5ec8,0x6630,0x6cb3,0x7455,
+    0x8377,0x8766,0x8cc0,0x9050,0x971e,0x9c15,0x58d1,0x5b78,0x8650,0x8b14,
+    0x9db4,0x5bd2,0x6068,0x608d,0x65f1,0x6c57,0x6f22,0x6fa3,0x701a,0x7f55,
+    0x7ff0,0x9591,0x9592,0x9650,0x97d3,0x5272,0x8f44,0x51fd,0x542b,0x54b8,
+    0x5563,0x558a,0x6abb,0x6db5,0x7dd8,0x8266,0x929c,0x9677,0x9e79,0x5408,
+    0x54c8,0x76d2,0x86e4,0x95a4,0x95d4,0x965c,0x4ea2,0x4f09,0x59ee,0x5ae6,
+    0x5df7,0x6052,0x6297,0x676d,0x6841,0x6c86,0x6e2f,0x7f38,0x809b,0x822a
+  },
+  {				/* ku 7a */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0xfa08,0xfa09,0x9805,0x4ea5,
+    0x5055,0x54b3,0x5793,0x595a,0x5b69,0x5bb3,0x61c8,0x6977,0x6d77,0x7023,
+    0x87f9,0x89e3,0x8a72,0x8ae7,0x9082,0x99ed,0x9ab8,0x52be,0x6838,0x5016,
+    0x5e78,0x674f,0x8347,0x884c,0x4eab,0x5411,0x56ae,0x73e6,0x9115,0x97ff,
+    0x9909,0x9957,0x9999,0x5653,0x589f,0x865b,0x8a31,0x61b2,0x6af6,0x737b,
+    0x8ed2,0x6b47,0x96aa,0x9a57,0x5955,0x7200,0x8d6b,0x9769,0x4fd4,0x5cf4,
+    0x5f26,0x61f8,0x665b,0x6ceb,0x70ab,0x7384,0x73b9,0x73fe,0x7729,0x774d,
+    0x7d43,0x7d62,0x7e23,0x8237,0x8852,0xfa0a,0x8ce2,0x9249,0x986f,0x5b51,
+    0x7a74,0x8840,0x9801,0x5acc,0x4fe0,0x5354,0x593e,0x5cfd,0x633e,0x6d79,
+    0x72f9,0x8105,0x8107,0x83a2,0x92cf,0x9830,0x4ea8,0x5144,0x5211,0x578b
+  },
+  {				/* ku 7b */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x5f62,0x6cc2,0x6ece,0x7005,
+    0x7050,0x70af,0x7192,0x73e9,0x7469,0x834a,0x87a2,0x8861,0x9008,0x90a2,
+    0x93a3,0x99a8,0x516e,0x5f57,0x60e0,0x6167,0x66b3,0x8559,0x8e4a,0x91af,
+    0x978b,0x4e4e,0x4e92,0x547c,0x58d5,0x58fa,0x597d,0x5cb5,0x5f27,0x6236,
+    0x6248,0x660a,0x6667,0x6beb,0x6d69,0x6dcf,0x6e56,0x6ef8,0x6f94,0x6fe0,
+    0x6fe9,0x705d,0x72d0,0x7425,0x745a,0x74e0,0x7693,0x795c,0x7cca,0x7e1e,
+    0x80e1,0x82a6,0x846b,0x84bf,0x864e,0x865f,0x8774,0x8b77,0x8c6a,0x93ac,
+    0x9800,0x9865,0x60d1,0x6216,0x9177,0x5a5a,0x660f,0x6df7,0x6e3e,0x743f,
+    0x9b42,0x5ffd,0x60da,0x7b0f,0x54c4,0x5f18,0x6c5e,0x6cd3,0x6d2a,0x70d8,
+    0x7d05,0x8679,0x8a0c,0x9d3b,0x5316,0x548c,0x5b05,0x6a3a,0x706b,0x7575
+  },
+  {				/* ku 7c */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x798d,0x79be,0x82b1,0x83ef,
+    0x8a71,0x8b41,0x8ca8,0x9774,0xfa0b,0x64f4,0x652b,0x78ba,0x78bb,0x7a6b,
+    0x4e38,0x559a,0x5950,0x5ba6,0x5e7b,0x60a3,0x63db,0x6b61,0x6665,0x6853,
+    0x6e19,0x7165,0x74b0,0x7d08,0x9084,0x9a69,0x9c25,0x6d3b,0x6ed1,0x733e,
+    0x8c41,0x95ca,0x51f0,0x5e4c,0x5fa8,0x604d,0x60f6,0x6130,0x614c,0x6643,
+    0x6644,0x69a5,0x6cc1,0x6e5f,0x6ec9,0x6f62,0x714c,0x749c,0x7687,0x7bc1,
+    0x7c27,0x8352,0x8757,0x9051,0x968d,0x9ec3,0x532f,0x56de,0x5efb,0x5f8a,
+    0x6062,0x6094,0x61f7,0x6666,0x6703,0x6a9c,0x6dee,0x6fae,0x7070,0x736a,
+    0x7e6a,0x81be,0x8334,0x86d4,0x8aa8,0x8cc4,0x5283,0x7372,0x5b96,0x6a6b,
+    0x9404,0x54ee,0x5686,0x5b5d,0x6548,0x6585,0x66c9,0x689f,0x6d8d,0x6dc6
+  },
+  {				/* ku 7d */
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+    UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,0x723b,0x80b4,0x9175,0x9a4d,
+    0x4faf,0x5019,0x539a,0x540e,0x543c,0x5589,0x55c5,0x5e3f,0x5f8c,0x673d,
+    0x7166,0x73dd,0x9005,0x52db,0x52f3,0x5864,0x58ce,0x7104,0x718f,0x71fb,
+    0x85b0,0x8a13,0x6688,0x85a8,0x55a7,0x6684,0x714a,0x8431,0x5349,0x5599,
+    0x6bc1,0x5f59,0x5fbd,0x63ee,0x6689,0x7147,0x8af1,0x8f1d,0x9ebe,0x4f11,
+    0x643a,0x70cb,0x7566,0x8667,0x6064,0x8b4e,0x9df8,0x5147,0x51f6,0x5308,
+    0x6d36,0x80f8,0x9ed1,0x6615,0x6b23,0x7098,0x75d5,0x5403,0x5c79,0x7d07,
+    0x8a16,0x6b20,0x6b3d,0x6b46,0x5438,0x6070,0x6d3d,0x7fd5,0x8208,0x50d6,
+    0x51de,0x559c,0x566b,0x56cd,0x59ec,0x5b09,0x5e0c,0x6199,0x6198,0x6231,
+    0x665e,0x66e6,0x7199,0x71b9,0x71ba,0x72a7,0x79a7,0x7a00,0x7fb2,0x8a70
+  }
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/charset/tis_620.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,51 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	TIS 620-2529 conversion table
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	24 October 1997
+ * Last Edited:	30 August 2006
+ */
+
+/* TIS 620-2529 is the "Thai Industrial Standard for Thai Character Code
+ * for Computer", published by the Thai Industrial Standards Institute,
+ * Ministry of Industry of Thailand.
+ */
+
+static const unsigned short tis620tab[128] = {
+  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
+  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
+  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
+  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
+  UBOGON,0x0e01,0x0e02,0x0e03,0x0e04,0x0e05,0x0e06,0x0e07,
+  0x0e08,0x0e09,0x0e0a,0x0e0b,0x0e0c,0x0e0d,0x0e0e,0x0e0f,
+  0x0e10,0x0e11,0x0e12,0x0e13,0x0e14,0x0e15,0x0e16,0x0e17,
+  0x0e18,0x0e19,0x0e1a,0x0e1b,0x0e1c,0x0e1d,0x0e1e,0x0e1f,
+  0x0e20,0x0e21,0x0e22,0x0e23,0x0e24,0x0e25,0x0e26,0x0e27,
+  0x0e28,0x0e29,0x0e2a,0x0e2b,0x0e2c,0x0e2d,0x0e2e,0x0e2f,
+  0x0e30,0x0e31,0x0e32,0x0e33,0x0e34,0x0e35,0x0e36,0x0e37,
+  0x0e38,0x0e39,0x0e3a,UBOGON,UBOGON,UBOGON,UBOGON,0x0e3f,
+  0x0e40,0x0e41,0x0e42,0x0e43,0x0e44,0x0e45,0x0e46,0x0e47,
+  0x0e48,0x0e49,0x0e4a,0x0e4b,0x0e4c,0x0e4d,0x0e4e,0x0e4f,
+  0x0e50,0x0e51,0x0e52,0x0e53,0x0e54,0x0e55,0x0e56,0x0e57,
+  0x0e58,0x0e59,0x0e5a,0x0e5b,UBOGON,UBOGON,UBOGON,UBOGON
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/charset/tmap.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1487 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Unicode title case mapping table (current as of Unicode 5.0)
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	7 April 2006
+ * Last Edited:	6 December 2006
+ */
+
+			
+#define UCS4_TMAPMAX 0x2d25	/* size of mapping table */
+
+#define UCS4_TMAPHIMIN 0xff41	/* high mapping minimum */
+#define UCS4_TMAPHIMAX 0xff5a	/* high mapping maximum */
+#define UCS4_TMAPHIMAP 0x20	/* high mapping offset */
+
+				/* Values for Deseret */
+#define UCS4_TMAPDESERETMIN 0x10428
+#define UCS4_TMAPDESERETMAX 0x1044f
+#define UCS4_TMAPDESERETMAP 0x28
+
+static const unsigned short ucs4_tmaptab[UCS4_TMAPMAX+1] = {
+  0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007,
+  0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f,
+  0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017,
+  0x0018,0x0019,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f,
+  0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,
+  0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f,
+  0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,
+  0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f,
+  0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,
+  0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,
+  0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,
+  0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f,
+  0x0060,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,
+  0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,
+  0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,
+  0x0058,0x0059,0x005a,0x007b,0x007c,0x007d,0x007e,0x007f,
+  0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
+  0x0088,0x0089,0x008a,0x008b,0x008c,0x008d,0x008e,0x008f,
+  0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
+  0x0098,0x0099,0x009a,0x009b,0x009c,0x009d,0x009e,0x009f,
+  0x00a0,0x00a1,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,
+  0x00a8,0x00a9,0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
+  0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x039c,0x00b6,0x00b7,
+  0x00b8,0x00b9,0x00ba,0x00bb,0x00bc,0x00bd,0x00be,0x00bf,
+  0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7,
+  0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
+  0x00d0,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00d7,
+  0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x00dd,0x00de,0x00df,
+  0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7,
+  0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
+  0x00d0,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00f7,
+  0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x00dd,0x00de,0x0178,
+  0x0100,0x0100,0x0102,0x0102,0x0104,0x0104,0x0106,0x0106,
+  0x0108,0x0108,0x010a,0x010a,0x010c,0x010c,0x010e,0x010e,
+  0x0110,0x0110,0x0112,0x0112,0x0114,0x0114,0x0116,0x0116,
+  0x0118,0x0118,0x011a,0x011a,0x011c,0x011c,0x011e,0x011e,
+  0x0120,0x0120,0x0122,0x0122,0x0124,0x0124,0x0126,0x0126,
+  0x0128,0x0128,0x012a,0x012a,0x012c,0x012c,0x012e,0x012e,
+  0x0130,0x0049,0x0132,0x0132,0x0134,0x0134,0x0136,0x0136,
+  0x0138,0x0139,0x0139,0x013b,0x013b,0x013d,0x013d,0x013f,
+  0x013f,0x0141,0x0141,0x0143,0x0143,0x0145,0x0145,0x0147,
+  0x0147,0x0149,0x014a,0x014a,0x014c,0x014c,0x014e,0x014e,
+  0x0150,0x0150,0x0152,0x0152,0x0154,0x0154,0x0156,0x0156,
+  0x0158,0x0158,0x015a,0x015a,0x015c,0x015c,0x015e,0x015e,
+  0x0160,0x0160,0x0162,0x0162,0x0164,0x0164,0x0166,0x0166,
+  0x0168,0x0168,0x016a,0x016a,0x016c,0x016c,0x016e,0x016e,
+  0x0170,0x0170,0x0172,0x0172,0x0174,0x0174,0x0176,0x0176,
+  0x0178,0x0179,0x0179,0x017b,0x017b,0x017d,0x017d,0x0053,
+  0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,
+  0x0187,0x0189,0x018a,0x018b,0x018b,0x018d,0x018e,0x018f,
+  0x0190,0x0191,0x0191,0x0193,0x0194,0x01f6,0x0196,0x0197,
+  0x0198,0x0198,0x023d,0x019b,0x019c,0x019d,0x0220,0x019f,
+  0x01a0,0x01a0,0x01a2,0x01a2,0x01a4,0x01a4,0x01a6,0x01a7,
+  0x01a7,0x01a9,0x01aa,0x01ab,0x01ac,0x01ac,0x01ae,0x01af,
+  0x01af,0x01b1,0x01b2,0x01b3,0x01b3,0x01b5,0x01b5,0x01b7,
+  0x01b8,0x01b8,0x01ba,0x01bb,0x01bc,0x01bc,0x01be,0x01f7,
+  0x01c0,0x01c1,0x01c2,0x01c3,0x01c5,0x01c5,0x01c5,0x01c8,
+  0x01c8,0x01c8,0x01cb,0x01cb,0x01cb,0x01cd,0x01cd,0x01cf,
+  0x01cf,0x01d1,0x01d1,0x01d3,0x01d3,0x01d5,0x01d5,0x01d7,
+  0x01d7,0x01d9,0x01d9,0x01db,0x01db,0x018e,0x01de,0x01de,
+  0x01e0,0x01e0,0x01e2,0x01e2,0x01e4,0x01e4,0x01e6,0x01e6,
+  0x01e8,0x01e8,0x01ea,0x01ea,0x01ec,0x01ec,0x01ee,0x01ee,
+  0x01f0,0x01f2,0x01f2,0x01f2,0x01f4,0x01f4,0x01f6,0x01f7,
+  0x01f8,0x01f8,0x01fa,0x01fa,0x01fc,0x01fc,0x01fe,0x01fe,
+  0x0200,0x0200,0x0202,0x0202,0x0204,0x0204,0x0206,0x0206,
+  0x0208,0x0208,0x020a,0x020a,0x020c,0x020c,0x020e,0x020e,
+  0x0210,0x0210,0x0212,0x0212,0x0214,0x0214,0x0216,0x0216,
+  0x0218,0x0218,0x021a,0x021a,0x021c,0x021c,0x021e,0x021e,
+  0x0220,0x0221,0x0222,0x0222,0x0224,0x0224,0x0226,0x0226,
+  0x0228,0x0228,0x022a,0x022a,0x022c,0x022c,0x022e,0x022e,
+  0x0230,0x0230,0x0232,0x0232,0x0234,0x0235,0x0236,0x0237,
+  0x0238,0x0239,0x023a,0x023b,0x023b,0x023d,0x023e,0x023f,
+  0x0240,0x0241,0x0241,0x0243,0x0244,0x0245,0x0246,0x0246,
+  0x0248,0x0248,0x024a,0x024a,0x024c,0x024c,0x024e,0x024e,
+  0x0250,0x0251,0x0252,0x0181,0x0186,0x0255,0x0189,0x018a,
+  0x0258,0x018f,0x025a,0x0190,0x025c,0x025d,0x025e,0x025f,
+  0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,
+  0x0197,0x0196,0x026a,0x2c62,0x026c,0x026d,0x026e,0x019c,
+  0x0270,0x0271,0x019d,0x0273,0x0274,0x019f,0x0276,0x0277,
+  0x0278,0x0279,0x027a,0x027b,0x027c,0x2c64,0x027e,0x027f,
+  0x01a6,0x0281,0x0282,0x01a9,0x0284,0x0285,0x0286,0x0287,
+  0x01ae,0x0244,0x01b1,0x01b2,0x0245,0x028d,0x028e,0x028f,
+  0x0290,0x0291,0x01b7,0x0293,0x0294,0x0295,0x0296,0x0297,
+  0x0298,0x0299,0x029a,0x029b,0x029c,0x029d,0x029e,0x029f,
+  0x02a0,0x02a1,0x02a2,0x02a3,0x02a4,0x02a5,0x02a6,0x02a7,
+  0x02a8,0x02a9,0x02aa,0x02ab,0x02ac,0x02ad,0x02ae,0x02af,
+  0x02b0,0x02b1,0x02b2,0x02b3,0x02b4,0x02b5,0x02b6,0x02b7,
+  0x02b8,0x02b9,0x02ba,0x02bb,0x02bc,0x02bd,0x02be,0x02bf,
+  0x02c0,0x02c1,0x02c2,0x02c3,0x02c4,0x02c5,0x02c6,0x02c7,
+  0x02c8,0x02c9,0x02ca,0x02cb,0x02cc,0x02cd,0x02ce,0x02cf,
+  0x02d0,0x02d1,0x02d2,0x02d3,0x02d4,0x02d5,0x02d6,0x02d7,
+  0x02d8,0x02d9,0x02da,0x02db,0x02dc,0x02dd,0x02de,0x02df,
+  0x02e0,0x02e1,0x02e2,0x02e3,0x02e4,0x02e5,0x02e6,0x02e7,
+  0x02e8,0x02e9,0x02ea,0x02eb,0x02ec,0x02ed,0x02ee,0x02ef,
+  0x02f0,0x02f1,0x02f2,0x02f3,0x02f4,0x02f5,0x02f6,0x02f7,
+  0x02f8,0x02f9,0x02fa,0x02fb,0x02fc,0x02fd,0x02fe,0x02ff,
+  0x0300,0x0301,0x0302,0x0303,0x0304,0x0305,0x0306,0x0307,
+  0x0308,0x0309,0x030a,0x030b,0x030c,0x030d,0x030e,0x030f,
+  0x0310,0x0311,0x0312,0x0313,0x0314,0x0315,0x0316,0x0317,
+  0x0318,0x0319,0x031a,0x031b,0x031c,0x031d,0x031e,0x031f,
+  0x0320,0x0321,0x0322,0x0323,0x0324,0x0325,0x0326,0x0327,
+  0x0328,0x0329,0x032a,0x032b,0x032c,0x032d,0x032e,0x032f,
+  0x0330,0x0331,0x0332,0x0333,0x0334,0x0335,0x0336,0x0337,
+  0x0338,0x0339,0x033a,0x033b,0x033c,0x033d,0x033e,0x033f,
+  0x0340,0x0341,0x0342,0x0343,0x0344,0x0399,0x0346,0x0347,
+  0x0348,0x0349,0x034a,0x034b,0x034c,0x034d,0x034e,0x034f,
+  0x0350,0x0351,0x0352,0x0353,0x0354,0x0355,0x0356,0x0357,
+  0x0358,0x0359,0x035a,0x035b,0x035c,0x035d,0x035e,0x035f,
+  0x0360,0x0361,0x0362,0x0363,0x0364,0x0365,0x0366,0x0367,
+  0x0368,0x0369,0x036a,0x036b,0x036c,0x036d,0x036e,0x036f,
+  0x0370,0x0371,0x0372,0x0373,0x0374,0x0375,0x0376,0x0377,
+  0x0378,0x0379,0x037a,0x03fd,0x03fe,0x03ff,0x037e,0x037f,
+  0x0380,0x0381,0x0382,0x0383,0x0384,0x0385,0x0386,0x0387,
+  0x0388,0x0389,0x038a,0x038b,0x038c,0x038d,0x038e,0x038f,
+  0x0390,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,
+  0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,
+  0x03a0,0x03a1,0x03a2,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,
+  0x03a8,0x03a9,0x03aa,0x03ab,0x0386,0x0388,0x0389,0x038a,
+  0x03b0,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,
+  0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,
+  0x03a0,0x03a1,0x03a3,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,
+  0x03a8,0x03a9,0x03aa,0x03ab,0x038c,0x038e,0x038f,0x03cf,
+  0x0392,0x0398,0x03d2,0x03d3,0x03d4,0x03a6,0x03a0,0x03d7,
+  0x03d8,0x03d8,0x03da,0x03da,0x03dc,0x03dc,0x03de,0x03de,
+  0x03e0,0x03e0,0x03e2,0x03e2,0x03e4,0x03e4,0x03e6,0x03e6,
+  0x03e8,0x03e8,0x03ea,0x03ea,0x03ec,0x03ec,0x03ee,0x03ee,
+  0x039a,0x03a1,0x03f9,0x03f3,0x03f4,0x0395,0x03f6,0x03f7,
+  0x03f7,0x03f9,0x03fa,0x03fa,0x03fc,0x03fd,0x03fe,0x03ff,
+  0x0400,0x0401,0x0402,0x0403,0x0404,0x0405,0x0406,0x0407,
+  0x0408,0x0409,0x040a,0x040b,0x040c,0x040d,0x040e,0x040f,
+  0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0416,0x0417,
+  0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f,
+  0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,0x0427,
+  0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f,
+  0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0416,0x0417,
+  0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f,
+  0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,0x0427,
+  0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f,
+  0x0400,0x0401,0x0402,0x0403,0x0404,0x0405,0x0406,0x0407,
+  0x0408,0x0409,0x040a,0x040b,0x040c,0x040d,0x040e,0x040f,
+  0x0460,0x0460,0x0462,0x0462,0x0464,0x0464,0x0466,0x0466,
+  0x0468,0x0468,0x046a,0x046a,0x046c,0x046c,0x046e,0x046e,
+  0x0470,0x0470,0x0472,0x0472,0x0474,0x0474,0x0476,0x0476,
+  0x0478,0x0478,0x047a,0x047a,0x047c,0x047c,0x047e,0x047e,
+  0x0480,0x0480,0x0482,0x0483,0x0484,0x0485,0x0486,0x0487,
+  0x0488,0x0489,0x048a,0x048a,0x048c,0x048c,0x048e,0x048e,
+  0x0490,0x0490,0x0492,0x0492,0x0494,0x0494,0x0496,0x0496,
+  0x0498,0x0498,0x049a,0x049a,0x049c,0x049c,0x049e,0x049e,
+  0x04a0,0x04a0,0x04a2,0x04a2,0x04a4,0x04a4,0x04a6,0x04a6,
+  0x04a8,0x04a8,0x04aa,0x04aa,0x04ac,0x04ac,0x04ae,0x04ae,
+  0x04b0,0x04b0,0x04b2,0x04b2,0x04b4,0x04b4,0x04b6,0x04b6,
+  0x04b8,0x04b8,0x04ba,0x04ba,0x04bc,0x04bc,0x04be,0x04be,
+  0x04c0,0x04c1,0x04c1,0x04c3,0x04c3,0x04c5,0x04c5,0x04c7,
+  0x04c7,0x04c9,0x04c9,0x04cb,0x04cb,0x04cd,0x04cd,0x04c0,
+  0x04d0,0x04d0,0x04d2,0x04d2,0x04d4,0x04d4,0x04d6,0x04d6,
+  0x04d8,0x04d8,0x04da,0x04da,0x04dc,0x04dc,0x04de,0x04de,
+  0x04e0,0x04e0,0x04e2,0x04e2,0x04e4,0x04e4,0x04e6,0x04e6,
+  0x04e8,0x04e8,0x04ea,0x04ea,0x04ec,0x04ec,0x04ee,0x04ee,
+  0x04f0,0x04f0,0x04f2,0x04f2,0x04f4,0x04f4,0x04f6,0x04f6,
+  0x04f8,0x04f8,0x04fa,0x04fa,0x04fc,0x04fc,0x04fe,0x04fe,
+  0x0500,0x0500,0x0502,0x0502,0x0504,0x0504,0x0506,0x0506,
+  0x0508,0x0508,0x050a,0x050a,0x050c,0x050c,0x050e,0x050e,
+  0x0510,0x0510,0x0512,0x0512,0x0514,0x0515,0x0516,0x0517,
+  0x0518,0x0519,0x051a,0x051b,0x051c,0x051d,0x051e,0x051f,
+  0x0520,0x0521,0x0522,0x0523,0x0524,0x0525,0x0526,0x0527,
+  0x0528,0x0529,0x052a,0x052b,0x052c,0x052d,0x052e,0x052f,
+  0x0530,0x0531,0x0532,0x0533,0x0534,0x0535,0x0536,0x0537,
+  0x0538,0x0539,0x053a,0x053b,0x053c,0x053d,0x053e,0x053f,
+  0x0540,0x0541,0x0542,0x0543,0x0544,0x0545,0x0546,0x0547,
+  0x0548,0x0549,0x054a,0x054b,0x054c,0x054d,0x054e,0x054f,
+  0x0550,0x0551,0x0552,0x0553,0x0554,0x0555,0x0556,0x0557,
+  0x0558,0x0559,0x055a,0x055b,0x055c,0x055d,0x055e,0x055f,
+  0x0560,0x0531,0x0532,0x0533,0x0534,0x0535,0x0536,0x0537,
+  0x0538,0x0539,0x053a,0x053b,0x053c,0x053d,0x053e,0x053f,
+  0x0540,0x0541,0x0542,0x0543,0x0544,0x0545,0x0546,0x0547,
+  0x0548,0x0549,0x054a,0x054b,0x054c,0x054d,0x054e,0x054f,
+  0x0550,0x0551,0x0552,0x0553,0x0554,0x0555,0x0556,0x0587,
+  0x0588,0x0589,0x058a,0x058b,0x058c,0x058d,0x058e,0x058f,
+  0x0590,0x0591,0x0592,0x0593,0x0594,0x0595,0x0596,0x0597,
+  0x0598,0x0599,0x059a,0x059b,0x059c,0x059d,0x059e,0x059f,
+  0x05a0,0x05a1,0x05a2,0x05a3,0x05a4,0x05a5,0x05a6,0x05a7,
+  0x05a8,0x05a9,0x05aa,0x05ab,0x05ac,0x05ad,0x05ae,0x05af,
+  0x05b0,0x05b1,0x05b2,0x05b3,0x05b4,0x05b5,0x05b6,0x05b7,
+  0x05b8,0x05b9,0x05ba,0x05bb,0x05bc,0x05bd,0x05be,0x05bf,
+  0x05c0,0x05c1,0x05c2,0x05c3,0x05c4,0x05c5,0x05c6,0x05c7,
+  0x05c8,0x05c9,0x05ca,0x05cb,0x05cc,0x05cd,0x05ce,0x05cf,
+  0x05d0,0x05d1,0x05d2,0x05d3,0x05d4,0x05d5,0x05d6,0x05d7,
+  0x05d8,0x05d9,0x05da,0x05db,0x05dc,0x05dd,0x05de,0x05df,
+  0x05e0,0x05e1,0x05e2,0x05e3,0x05e4,0x05e5,0x05e6,0x05e7,
+  0x05e8,0x05e9,0x05ea,0x05eb,0x05ec,0x05ed,0x05ee,0x05ef,
+  0x05f0,0x05f1,0x05f2,0x05f3,0x05f4,0x05f5,0x05f6,0x05f7,
+  0x05f8,0x05f9,0x05fa,0x05fb,0x05fc,0x05fd,0x05fe,0x05ff,
+  0x0600,0x0601,0x0602,0x0603,0x0604,0x0605,0x0606,0x0607,
+  0x0608,0x0609,0x060a,0x060b,0x060c,0x060d,0x060e,0x060f,
+  0x0610,0x0611,0x0612,0x0613,0x0614,0x0615,0x0616,0x0617,
+  0x0618,0x0619,0x061a,0x061b,0x061c,0x061d,0x061e,0x061f,
+  0x0620,0x0621,0x0622,0x0623,0x0624,0x0625,0x0626,0x0627,
+  0x0628,0x0629,0x062a,0x062b,0x062c,0x062d,0x062e,0x062f,
+  0x0630,0x0631,0x0632,0x0633,0x0634,0x0635,0x0636,0x0637,
+  0x0638,0x0639,0x063a,0x063b,0x063c,0x063d,0x063e,0x063f,
+  0x0640,0x0641,0x0642,0x0643,0x0644,0x0645,0x0646,0x0647,
+  0x0648,0x0649,0x064a,0x064b,0x064c,0x064d,0x064e,0x064f,
+  0x0650,0x0651,0x0652,0x0653,0x0654,0x0655,0x0656,0x0657,
+  0x0658,0x0659,0x065a,0x065b,0x065c,0x065d,0x065e,0x065f,
+  0x0660,0x0661,0x0662,0x0663,0x0664,0x0665,0x0666,0x0667,
+  0x0668,0x0669,0x066a,0x066b,0x066c,0x066d,0x066e,0x066f,
+  0x0670,0x0671,0x0672,0x0673,0x0674,0x0675,0x0676,0x0677,
+  0x0678,0x0679,0x067a,0x067b,0x067c,0x067d,0x067e,0x067f,
+  0x0680,0x0681,0x0682,0x0683,0x0684,0x0685,0x0686,0x0687,
+  0x0688,0x0689,0x068a,0x068b,0x068c,0x068d,0x068e,0x068f,
+  0x0690,0x0691,0x0692,0x0693,0x0694,0x0695,0x0696,0x0697,
+  0x0698,0x0699,0x069a,0x069b,0x069c,0x069d,0x069e,0x069f,
+  0x06a0,0x06a1,0x06a2,0x06a3,0x06a4,0x06a5,0x06a6,0x06a7,
+  0x06a8,0x06a9,0x06aa,0x06ab,0x06ac,0x06ad,0x06ae,0x06af,
+  0x06b0,0x06b1,0x06b2,0x06b3,0x06b4,0x06b5,0x06b6,0x06b7,
+  0x06b8,0x06b9,0x06ba,0x06bb,0x06bc,0x06bd,0x06be,0x06bf,
+  0x06c0,0x06c1,0x06c2,0x06c3,0x06c4,0x06c5,0x06c6,0x06c7,
+  0x06c8,0x06c9,0x06ca,0x06cb,0x06cc,0x06cd,0x06ce,0x06cf,
+  0x06d0,0x06d1,0x06d2,0x06d3,0x06d4,0x06d5,0x06d6,0x06d7,
+  0x06d8,0x06d9,0x06da,0x06db,0x06dc,0x06dd,0x06de,0x06df,
+  0x06e0,0x06e1,0x06e2,0x06e3,0x06e4,0x06e5,0x06e6,0x06e7,
+  0x06e8,0x06e9,0x06ea,0x06eb,0x06ec,0x06ed,0x06ee,0x06ef,
+  0x06f0,0x06f1,0x06f2,0x06f3,0x06f4,0x06f5,0x06f6,0x06f7,
+  0x06f8,0x06f9,0x06fa,0x06fb,0x06fc,0x06fd,0x06fe,0x06ff,
+  0x0700,0x0701,0x0702,0x0703,0x0704,0x0705,0x0706,0x0707,
+  0x0708,0x0709,0x070a,0x070b,0x070c,0x070d,0x070e,0x070f,
+  0x0710,0x0711,0x0712,0x0713,0x0714,0x0715,0x0716,0x0717,
+  0x0718,0x0719,0x071a,0x071b,0x071c,0x071d,0x071e,0x071f,
+  0x0720,0x0721,0x0722,0x0723,0x0724,0x0725,0x0726,0x0727,
+  0x0728,0x0729,0x072a,0x072b,0x072c,0x072d,0x072e,0x072f,
+  0x0730,0x0731,0x0732,0x0733,0x0734,0x0735,0x0736,0x0737,
+  0x0738,0x0739,0x073a,0x073b,0x073c,0x073d,0x073e,0x073f,
+  0x0740,0x0741,0x0742,0x0743,0x0744,0x0745,0x0746,0x0747,
+  0x0748,0x0749,0x074a,0x074b,0x074c,0x074d,0x074e,0x074f,
+  0x0750,0x0751,0x0752,0x0753,0x0754,0x0755,0x0756,0x0757,
+  0x0758,0x0759,0x075a,0x075b,0x075c,0x075d,0x075e,0x075f,
+  0x0760,0x0761,0x0762,0x0763,0x0764,0x0765,0x0766,0x0767,
+  0x0768,0x0769,0x076a,0x076b,0x076c,0x076d,0x076e,0x076f,
+  0x0770,0x0771,0x0772,0x0773,0x0774,0x0775,0x0776,0x0777,
+  0x0778,0x0779,0x077a,0x077b,0x077c,0x077d,0x077e,0x077f,
+  0x0780,0x0781,0x0782,0x0783,0x0784,0x0785,0x0786,0x0787,
+  0x0788,0x0789,0x078a,0x078b,0x078c,0x078d,0x078e,0x078f,
+  0x0790,0x0791,0x0792,0x0793,0x0794,0x0795,0x0796,0x0797,
+  0x0798,0x0799,0x079a,0x079b,0x079c,0x079d,0x079e,0x079f,
+  0x07a0,0x07a1,0x07a2,0x07a3,0x07a4,0x07a5,0x07a6,0x07a7,
+  0x07a8,0x07a9,0x07aa,0x07ab,0x07ac,0x07ad,0x07ae,0x07af,
+  0x07b0,0x07b1,0x07b2,0x07b3,0x07b4,0x07b5,0x07b6,0x07b7,
+  0x07b8,0x07b9,0x07ba,0x07bb,0x07bc,0x07bd,0x07be,0x07bf,
+  0x07c0,0x07c1,0x07c2,0x07c3,0x07c4,0x07c5,0x07c6,0x07c7,
+  0x07c8,0x07c9,0x07ca,0x07cb,0x07cc,0x07cd,0x07ce,0x07cf,
+  0x07d0,0x07d1,0x07d2,0x07d3,0x07d4,0x07d5,0x07d6,0x07d7,
+  0x07d8,0x07d9,0x07da,0x07db,0x07dc,0x07dd,0x07de,0x07df,
+  0x07e0,0x07e1,0x07e2,0x07e3,0x07e4,0x07e5,0x07e6,0x07e7,
+  0x07e8,0x07e9,0x07ea,0x07eb,0x07ec,0x07ed,0x07ee,0x07ef,
+  0x07f0,0x07f1,0x07f2,0x07f3,0x07f4,0x07f5,0x07f6,0x07f7,
+  0x07f8,0x07f9,0x07fa,0x07fb,0x07fc,0x07fd,0x07fe,0x07ff,
+  0x0800,0x0801,0x0802,0x0803,0x0804,0x0805,0x0806,0x0807,
+  0x0808,0x0809,0x080a,0x080b,0x080c,0x080d,0x080e,0x080f,
+  0x0810,0x0811,0x0812,0x0813,0x0814,0x0815,0x0816,0x0817,
+  0x0818,0x0819,0x081a,0x081b,0x081c,0x081d,0x081e,0x081f,
+  0x0820,0x0821,0x0822,0x0823,0x0824,0x0825,0x0826,0x0827,
+  0x0828,0x0829,0x082a,0x082b,0x082c,0x082d,0x082e,0x082f,
+  0x0830,0x0831,0x0832,0x0833,0x0834,0x0835,0x0836,0x0837,
+  0x0838,0x0839,0x083a,0x083b,0x083c,0x083d,0x083e,0x083f,
+  0x0840,0x0841,0x0842,0x0843,0x0844,0x0845,0x0846,0x0847,
+  0x0848,0x0849,0x084a,0x084b,0x084c,0x084d,0x084e,0x084f,
+  0x0850,0x0851,0x0852,0x0853,0x0854,0x0855,0x0856,0x0857,
+  0x0858,0x0859,0x085a,0x085b,0x085c,0x085d,0x085e,0x085f,
+  0x0860,0x0861,0x0862,0x0863,0x0864,0x0865,0x0866,0x0867,
+  0x0868,0x0869,0x086a,0x086b,0x086c,0x086d,0x086e,0x086f,
+  0x0870,0x0871,0x0872,0x0873,0x0874,0x0875,0x0876,0x0877,
+  0x0878,0x0879,0x087a,0x087b,0x087c,0x087d,0x087e,0x087f,
+  0x0880,0x0881,0x0882,0x0883,0x0884,0x0885,0x0886,0x0887,
+  0x0888,0x0889,0x088a,0x088b,0x088c,0x088d,0x088e,0x088f,
+  0x0890,0x0891,0x0892,0x0893,0x0894,0x0895,0x0896,0x0897,
+  0x0898,0x0899,0x089a,0x089b,0x089c,0x089d,0x089e,0x089f,
+  0x08a0,0x08a1,0x08a2,0x08a3,0x08a4,0x08a5,0x08a6,0x08a7,
+  0x08a8,0x08a9,0x08aa,0x08ab,0x08ac,0x08ad,0x08ae,0x08af,
+  0x08b0,0x08b1,0x08b2,0x08b3,0x08b4,0x08b5,0x08b6,0x08b7,
+  0x08b8,0x08b9,0x08ba,0x08bb,0x08bc,0x08bd,0x08be,0x08bf,
+  0x08c0,0x08c1,0x08c2,0x08c3,0x08c4,0x08c5,0x08c6,0x08c7,
+  0x08c8,0x08c9,0x08ca,0x08cb,0x08cc,0x08cd,0x08ce,0x08cf,
+  0x08d0,0x08d1,0x08d2,0x08d3,0x08d4,0x08d5,0x08d6,0x08d7,
+  0x08d8,0x08d9,0x08da,0x08db,0x08dc,0x08dd,0x08de,0x08df,
+  0x08e0,0x08e1,0x08e2,0x08e3,0x08e4,0x08e5,0x08e6,0x08e7,
+  0x08e8,0x08e9,0x08ea,0x08eb,0x08ec,0x08ed,0x08ee,0x08ef,
+  0x08f0,0x08f1,0x08f2,0x08f3,0x08f4,0x08f5,0x08f6,0x08f7,
+  0x08f8,0x08f9,0x08fa,0x08fb,0x08fc,0x08fd,0x08fe,0x08ff,
+  0x0900,0x0901,0x0902,0x0903,0x0904,0x0905,0x0906,0x0907,
+  0x0908,0x0909,0x090a,0x090b,0x090c,0x090d,0x090e,0x090f,
+  0x0910,0x0911,0x0912,0x0913,0x0914,0x0915,0x0916,0x0917,
+  0x0918,0x0919,0x091a,0x091b,0x091c,0x091d,0x091e,0x091f,
+  0x0920,0x0921,0x0922,0x0923,0x0924,0x0925,0x0926,0x0927,
+  0x0928,0x0929,0x092a,0x092b,0x092c,0x092d,0x092e,0x092f,
+  0x0930,0x0931,0x0932,0x0933,0x0934,0x0935,0x0936,0x0937,
+  0x0938,0x0939,0x093a,0x093b,0x093c,0x093d,0x093e,0x093f,
+  0x0940,0x0941,0x0942,0x0943,0x0944,0x0945,0x0946,0x0947,
+  0x0948,0x0949,0x094a,0x094b,0x094c,0x094d,0x094e,0x094f,
+  0x0950,0x0951,0x0952,0x0953,0x0954,0x0955,0x0956,0x0957,
+  0x0958,0x0959,0x095a,0x095b,0x095c,0x095d,0x095e,0x095f,
+  0x0960,0x0961,0x0962,0x0963,0x0964,0x0965,0x0966,0x0967,
+  0x0968,0x0969,0x096a,0x096b,0x096c,0x096d,0x096e,0x096f,
+  0x0970,0x0971,0x0972,0x0973,0x0974,0x0975,0x0976,0x0977,
+  0x0978,0x0979,0x097a,0x097b,0x097c,0x097d,0x097e,0x097f,
+  0x0980,0x0981,0x0982,0x0983,0x0984,0x0985,0x0986,0x0987,
+  0x0988,0x0989,0x098a,0x098b,0x098c,0x098d,0x098e,0x098f,
+  0x0990,0x0991,0x0992,0x0993,0x0994,0x0995,0x0996,0x0997,
+  0x0998,0x0999,0x099a,0x099b,0x099c,0x099d,0x099e,0x099f,
+  0x09a0,0x09a1,0x09a2,0x09a3,0x09a4,0x09a5,0x09a6,0x09a7,
+  0x09a8,0x09a9,0x09aa,0x09ab,0x09ac,0x09ad,0x09ae,0x09af,
+  0x09b0,0x09b1,0x09b2,0x09b3,0x09b4,0x09b5,0x09b6,0x09b7,
+  0x09b8,0x09b9,0x09ba,0x09bb,0x09bc,0x09bd,0x09be,0x09bf,
+  0x09c0,0x09c1,0x09c2,0x09c3,0x09c4,0x09c5,0x09c6,0x09c7,
+  0x09c8,0x09c9,0x09ca,0x09cb,0x09cc,0x09cd,0x09ce,0x09cf,
+  0x09d0,0x09d1,0x09d2,0x09d3,0x09d4,0x09d5,0x09d6,0x09d7,
+  0x09d8,0x09d9,0x09da,0x09db,0x09dc,0x09dd,0x09de,0x09df,
+  0x09e0,0x09e1,0x09e2,0x09e3,0x09e4,0x09e5,0x09e6,0x09e7,
+  0x09e8,0x09e9,0x09ea,0x09eb,0x09ec,0x09ed,0x09ee,0x09ef,
+  0x09f0,0x09f1,0x09f2,0x09f3,0x09f4,0x09f5,0x09f6,0x09f7,
+  0x09f8,0x09f9,0x09fa,0x09fb,0x09fc,0x09fd,0x09fe,0x09ff,
+  0x0a00,0x0a01,0x0a02,0x0a03,0x0a04,0x0a05,0x0a06,0x0a07,
+  0x0a08,0x0a09,0x0a0a,0x0a0b,0x0a0c,0x0a0d,0x0a0e,0x0a0f,
+  0x0a10,0x0a11,0x0a12,0x0a13,0x0a14,0x0a15,0x0a16,0x0a17,
+  0x0a18,0x0a19,0x0a1a,0x0a1b,0x0a1c,0x0a1d,0x0a1e,0x0a1f,
+  0x0a20,0x0a21,0x0a22,0x0a23,0x0a24,0x0a25,0x0a26,0x0a27,
+  0x0a28,0x0a29,0x0a2a,0x0a2b,0x0a2c,0x0a2d,0x0a2e,0x0a2f,
+  0x0a30,0x0a31,0x0a32,0x0a33,0x0a34,0x0a35,0x0a36,0x0a37,
+  0x0a38,0x0a39,0x0a3a,0x0a3b,0x0a3c,0x0a3d,0x0a3e,0x0a3f,
+  0x0a40,0x0a41,0x0a42,0x0a43,0x0a44,0x0a45,0x0a46,0x0a47,
+  0x0a48,0x0a49,0x0a4a,0x0a4b,0x0a4c,0x0a4d,0x0a4e,0x0a4f,
+  0x0a50,0x0a51,0x0a52,0x0a53,0x0a54,0x0a55,0x0a56,0x0a57,
+  0x0a58,0x0a59,0x0a5a,0x0a5b,0x0a5c,0x0a5d,0x0a5e,0x0a5f,
+  0x0a60,0x0a61,0x0a62,0x0a63,0x0a64,0x0a65,0x0a66,0x0a67,
+  0x0a68,0x0a69,0x0a6a,0x0a6b,0x0a6c,0x0a6d,0x0a6e,0x0a6f,
+  0x0a70,0x0a71,0x0a72,0x0a73,0x0a74,0x0a75,0x0a76,0x0a77,
+  0x0a78,0x0a79,0x0a7a,0x0a7b,0x0a7c,0x0a7d,0x0a7e,0x0a7f,
+  0x0a80,0x0a81,0x0a82,0x0a83,0x0a84,0x0a85,0x0a86,0x0a87,
+  0x0a88,0x0a89,0x0a8a,0x0a8b,0x0a8c,0x0a8d,0x0a8e,0x0a8f,
+  0x0a90,0x0a91,0x0a92,0x0a93,0x0a94,0x0a95,0x0a96,0x0a97,
+  0x0a98,0x0a99,0x0a9a,0x0a9b,0x0a9c,0x0a9d,0x0a9e,0x0a9f,
+  0x0aa0,0x0aa1,0x0aa2,0x0aa3,0x0aa4,0x0aa5,0x0aa6,0x0aa7,
+  0x0aa8,0x0aa9,0x0aaa,0x0aab,0x0aac,0x0aad,0x0aae,0x0aaf,
+  0x0ab0,0x0ab1,0x0ab2,0x0ab3,0x0ab4,0x0ab5,0x0ab6,0x0ab7,
+  0x0ab8,0x0ab9,0x0aba,0x0abb,0x0abc,0x0abd,0x0abe,0x0abf,
+  0x0ac0,0x0ac1,0x0ac2,0x0ac3,0x0ac4,0x0ac5,0x0ac6,0x0ac7,
+  0x0ac8,0x0ac9,0x0aca,0x0acb,0x0acc,0x0acd,0x0ace,0x0acf,
+  0x0ad0,0x0ad1,0x0ad2,0x0ad3,0x0ad4,0x0ad5,0x0ad6,0x0ad7,
+  0x0ad8,0x0ad9,0x0ada,0x0adb,0x0adc,0x0add,0x0ade,0x0adf,
+  0x0ae0,0x0ae1,0x0ae2,0x0ae3,0x0ae4,0x0ae5,0x0ae6,0x0ae7,
+  0x0ae8,0x0ae9,0x0aea,0x0aeb,0x0aec,0x0aed,0x0aee,0x0aef,
+  0x0af0,0x0af1,0x0af2,0x0af3,0x0af4,0x0af5,0x0af6,0x0af7,
+  0x0af8,0x0af9,0x0afa,0x0afb,0x0afc,0x0afd,0x0afe,0x0aff,
+  0x0b00,0x0b01,0x0b02,0x0b03,0x0b04,0x0b05,0x0b06,0x0b07,
+  0x0b08,0x0b09,0x0b0a,0x0b0b,0x0b0c,0x0b0d,0x0b0e,0x0b0f,
+  0x0b10,0x0b11,0x0b12,0x0b13,0x0b14,0x0b15,0x0b16,0x0b17,
+  0x0b18,0x0b19,0x0b1a,0x0b1b,0x0b1c,0x0b1d,0x0b1e,0x0b1f,
+  0x0b20,0x0b21,0x0b22,0x0b23,0x0b24,0x0b25,0x0b26,0x0b27,
+  0x0b28,0x0b29,0x0b2a,0x0b2b,0x0b2c,0x0b2d,0x0b2e,0x0b2f,
+  0x0b30,0x0b31,0x0b32,0x0b33,0x0b34,0x0b35,0x0b36,0x0b37,
+  0x0b38,0x0b39,0x0b3a,0x0b3b,0x0b3c,0x0b3d,0x0b3e,0x0b3f,
+  0x0b40,0x0b41,0x0b42,0x0b43,0x0b44,0x0b45,0x0b46,0x0b47,
+  0x0b48,0x0b49,0x0b4a,0x0b4b,0x0b4c,0x0b4d,0x0b4e,0x0b4f,
+  0x0b50,0x0b51,0x0b52,0x0b53,0x0b54,0x0b55,0x0b56,0x0b57,
+  0x0b58,0x0b59,0x0b5a,0x0b5b,0x0b5c,0x0b5d,0x0b5e,0x0b5f,
+  0x0b60,0x0b61,0x0b62,0x0b63,0x0b64,0x0b65,0x0b66,0x0b67,
+  0x0b68,0x0b69,0x0b6a,0x0b6b,0x0b6c,0x0b6d,0x0b6e,0x0b6f,
+  0x0b70,0x0b71,0x0b72,0x0b73,0x0b74,0x0b75,0x0b76,0x0b77,
+  0x0b78,0x0b79,0x0b7a,0x0b7b,0x0b7c,0x0b7d,0x0b7e,0x0b7f,
+  0x0b80,0x0b81,0x0b82,0x0b83,0x0b84,0x0b85,0x0b86,0x0b87,
+  0x0b88,0x0b89,0x0b8a,0x0b8b,0x0b8c,0x0b8d,0x0b8e,0x0b8f,
+  0x0b90,0x0b91,0x0b92,0x0b93,0x0b94,0x0b95,0x0b96,0x0b97,
+  0x0b98,0x0b99,0x0b9a,0x0b9b,0x0b9c,0x0b9d,0x0b9e,0x0b9f,
+  0x0ba0,0x0ba1,0x0ba2,0x0ba3,0x0ba4,0x0ba5,0x0ba6,0x0ba7,
+  0x0ba8,0x0ba9,0x0baa,0x0bab,0x0bac,0x0bad,0x0bae,0x0baf,
+  0x0bb0,0x0bb1,0x0bb2,0x0bb3,0x0bb4,0x0bb5,0x0bb6,0x0bb7,
+  0x0bb8,0x0bb9,0x0bba,0x0bbb,0x0bbc,0x0bbd,0x0bbe,0x0bbf,
+  0x0bc0,0x0bc1,0x0bc2,0x0bc3,0x0bc4,0x0bc5,0x0bc6,0x0bc7,
+  0x0bc8,0x0bc9,0x0bca,0x0bcb,0x0bcc,0x0bcd,0x0bce,0x0bcf,
+  0x0bd0,0x0bd1,0x0bd2,0x0bd3,0x0bd4,0x0bd5,0x0bd6,0x0bd7,
+  0x0bd8,0x0bd9,0x0bda,0x0bdb,0x0bdc,0x0bdd,0x0bde,0x0bdf,
+  0x0be0,0x0be1,0x0be2,0x0be3,0x0be4,0x0be5,0x0be6,0x0be7,
+  0x0be8,0x0be9,0x0bea,0x0beb,0x0bec,0x0bed,0x0bee,0x0bef,
+  0x0bf0,0x0bf1,0x0bf2,0x0bf3,0x0bf4,0x0bf5,0x0bf6,0x0bf7,
+  0x0bf8,0x0bf9,0x0bfa,0x0bfb,0x0bfc,0x0bfd,0x0bfe,0x0bff,
+  0x0c00,0x0c01,0x0c02,0x0c03,0x0c04,0x0c05,0x0c06,0x0c07,
+  0x0c08,0x0c09,0x0c0a,0x0c0b,0x0c0c,0x0c0d,0x0c0e,0x0c0f,
+  0x0c10,0x0c11,0x0c12,0x0c13,0x0c14,0x0c15,0x0c16,0x0c17,
+  0x0c18,0x0c19,0x0c1a,0x0c1b,0x0c1c,0x0c1d,0x0c1e,0x0c1f,
+  0x0c20,0x0c21,0x0c22,0x0c23,0x0c24,0x0c25,0x0c26,0x0c27,
+  0x0c28,0x0c29,0x0c2a,0x0c2b,0x0c2c,0x0c2d,0x0c2e,0x0c2f,
+  0x0c30,0x0c31,0x0c32,0x0c33,0x0c34,0x0c35,0x0c36,0x0c37,
+  0x0c38,0x0c39,0x0c3a,0x0c3b,0x0c3c,0x0c3d,0x0c3e,0x0c3f,
+  0x0c40,0x0c41,0x0c42,0x0c43,0x0c44,0x0c45,0x0c46,0x0c47,
+  0x0c48,0x0c49,0x0c4a,0x0c4b,0x0c4c,0x0c4d,0x0c4e,0x0c4f,
+  0x0c50,0x0c51,0x0c52,0x0c53,0x0c54,0x0c55,0x0c56,0x0c57,
+  0x0c58,0x0c59,0x0c5a,0x0c5b,0x0c5c,0x0c5d,0x0c5e,0x0c5f,
+  0x0c60,0x0c61,0x0c62,0x0c63,0x0c64,0x0c65,0x0c66,0x0c67,
+  0x0c68,0x0c69,0x0c6a,0x0c6b,0x0c6c,0x0c6d,0x0c6e,0x0c6f,
+  0x0c70,0x0c71,0x0c72,0x0c73,0x0c74,0x0c75,0x0c76,0x0c77,
+  0x0c78,0x0c79,0x0c7a,0x0c7b,0x0c7c,0x0c7d,0x0c7e,0x0c7f,
+  0x0c80,0x0c81,0x0c82,0x0c83,0x0c84,0x0c85,0x0c86,0x0c87,
+  0x0c88,0x0c89,0x0c8a,0x0c8b,0x0c8c,0x0c8d,0x0c8e,0x0c8f,
+  0x0c90,0x0c91,0x0c92,0x0c93,0x0c94,0x0c95,0x0c96,0x0c97,
+  0x0c98,0x0c99,0x0c9a,0x0c9b,0x0c9c,0x0c9d,0x0c9e,0x0c9f,
+  0x0ca0,0x0ca1,0x0ca2,0x0ca3,0x0ca4,0x0ca5,0x0ca6,0x0ca7,
+  0x0ca8,0x0ca9,0x0caa,0x0cab,0x0cac,0x0cad,0x0cae,0x0caf,
+  0x0cb0,0x0cb1,0x0cb2,0x0cb3,0x0cb4,0x0cb5,0x0cb6,0x0cb7,
+  0x0cb8,0x0cb9,0x0cba,0x0cbb,0x0cbc,0x0cbd,0x0cbe,0x0cbf,
+  0x0cc0,0x0cc1,0x0cc2,0x0cc3,0x0cc4,0x0cc5,0x0cc6,0x0cc7,
+  0x0cc8,0x0cc9,0x0cca,0x0ccb,0x0ccc,0x0ccd,0x0cce,0x0ccf,
+  0x0cd0,0x0cd1,0x0cd2,0x0cd3,0x0cd4,0x0cd5,0x0cd6,0x0cd7,
+  0x0cd8,0x0cd9,0x0cda,0x0cdb,0x0cdc,0x0cdd,0x0cde,0x0cdf,
+  0x0ce0,0x0ce1,0x0ce2,0x0ce3,0x0ce4,0x0ce5,0x0ce6,0x0ce7,
+  0x0ce8,0x0ce9,0x0cea,0x0ceb,0x0cec,0x0ced,0x0cee,0x0cef,
+  0x0cf0,0x0cf1,0x0cf2,0x0cf3,0x0cf4,0x0cf5,0x0cf6,0x0cf7,
+  0x0cf8,0x0cf9,0x0cfa,0x0cfb,0x0cfc,0x0cfd,0x0cfe,0x0cff,
+  0x0d00,0x0d01,0x0d02,0x0d03,0x0d04,0x0d05,0x0d06,0x0d07,
+  0x0d08,0x0d09,0x0d0a,0x0d0b,0x0d0c,0x0d0d,0x0d0e,0x0d0f,
+  0x0d10,0x0d11,0x0d12,0x0d13,0x0d14,0x0d15,0x0d16,0x0d17,
+  0x0d18,0x0d19,0x0d1a,0x0d1b,0x0d1c,0x0d1d,0x0d1e,0x0d1f,
+  0x0d20,0x0d21,0x0d22,0x0d23,0x0d24,0x0d25,0x0d26,0x0d27,
+  0x0d28,0x0d29,0x0d2a,0x0d2b,0x0d2c,0x0d2d,0x0d2e,0x0d2f,
+  0x0d30,0x0d31,0x0d32,0x0d33,0x0d34,0x0d35,0x0d36,0x0d37,
+  0x0d38,0x0d39,0x0d3a,0x0d3b,0x0d3c,0x0d3d,0x0d3e,0x0d3f,
+  0x0d40,0x0d41,0x0d42,0x0d43,0x0d44,0x0d45,0x0d46,0x0d47,
+  0x0d48,0x0d49,0x0d4a,0x0d4b,0x0d4c,0x0d4d,0x0d4e,0x0d4f,
+  0x0d50,0x0d51,0x0d52,0x0d53,0x0d54,0x0d55,0x0d56,0x0d57,
+  0x0d58,0x0d59,0x0d5a,0x0d5b,0x0d5c,0x0d5d,0x0d5e,0x0d5f,
+  0x0d60,0x0d61,0x0d62,0x0d63,0x0d64,0x0d65,0x0d66,0x0d67,
+  0x0d68,0x0d69,0x0d6a,0x0d6b,0x0d6c,0x0d6d,0x0d6e,0x0d6f,
+  0x0d70,0x0d71,0x0d72,0x0d73,0x0d74,0x0d75,0x0d76,0x0d77,
+  0x0d78,0x0d79,0x0d7a,0x0d7b,0x0d7c,0x0d7d,0x0d7e,0x0d7f,
+  0x0d80,0x0d81,0x0d82,0x0d83,0x0d84,0x0d85,0x0d86,0x0d87,
+  0x0d88,0x0d89,0x0d8a,0x0d8b,0x0d8c,0x0d8d,0x0d8e,0x0d8f,
+  0x0d90,0x0d91,0x0d92,0x0d93,0x0d94,0x0d95,0x0d96,0x0d97,
+  0x0d98,0x0d99,0x0d9a,0x0d9b,0x0d9c,0x0d9d,0x0d9e,0x0d9f,
+  0x0da0,0x0da1,0x0da2,0x0da3,0x0da4,0x0da5,0x0da6,0x0da7,
+  0x0da8,0x0da9,0x0daa,0x0dab,0x0dac,0x0dad,0x0dae,0x0daf,
+  0x0db0,0x0db1,0x0db2,0x0db3,0x0db4,0x0db5,0x0db6,0x0db7,
+  0x0db8,0x0db9,0x0dba,0x0dbb,0x0dbc,0x0dbd,0x0dbe,0x0dbf,
+  0x0dc0,0x0dc1,0x0dc2,0x0dc3,0x0dc4,0x0dc5,0x0dc6,0x0dc7,
+  0x0dc8,0x0dc9,0x0dca,0x0dcb,0x0dcc,0x0dcd,0x0dce,0x0dcf,
+  0x0dd0,0x0dd1,0x0dd2,0x0dd3,0x0dd4,0x0dd5,0x0dd6,0x0dd7,
+  0x0dd8,0x0dd9,0x0dda,0x0ddb,0x0ddc,0x0ddd,0x0dde,0x0ddf,
+  0x0de0,0x0de1,0x0de2,0x0de3,0x0de4,0x0de5,0x0de6,0x0de7,
+  0x0de8,0x0de9,0x0dea,0x0deb,0x0dec,0x0ded,0x0dee,0x0def,
+  0x0df0,0x0df1,0x0df2,0x0df3,0x0df4,0x0df5,0x0df6,0x0df7,
+  0x0df8,0x0df9,0x0dfa,0x0dfb,0x0dfc,0x0dfd,0x0dfe,0x0dff,
+  0x0e00,0x0e01,0x0e02,0x0e03,0x0e04,0x0e05,0x0e06,0x0e07,
+  0x0e08,0x0e09,0x0e0a,0x0e0b,0x0e0c,0x0e0d,0x0e0e,0x0e0f,
+  0x0e10,0x0e11,0x0e12,0x0e13,0x0e14,0x0e15,0x0e16,0x0e17,
+  0x0e18,0x0e19,0x0e1a,0x0e1b,0x0e1c,0x0e1d,0x0e1e,0x0e1f,
+  0x0e20,0x0e21,0x0e22,0x0e23,0x0e24,0x0e25,0x0e26,0x0e27,
+  0x0e28,0x0e29,0x0e2a,0x0e2b,0x0e2c,0x0e2d,0x0e2e,0x0e2f,
+  0x0e30,0x0e31,0x0e32,0x0e33,0x0e34,0x0e35,0x0e36,0x0e37,
+  0x0e38,0x0e39,0x0e3a,0x0e3b,0x0e3c,0x0e3d,0x0e3e,0x0e3f,
+  0x0e40,0x0e41,0x0e42,0x0e43,0x0e44,0x0e45,0x0e46,0x0e47,
+  0x0e48,0x0e49,0x0e4a,0x0e4b,0x0e4c,0x0e4d,0x0e4e,0x0e4f,
+  0x0e50,0x0e51,0x0e52,0x0e53,0x0e54,0x0e55,0x0e56,0x0e57,
+  0x0e58,0x0e59,0x0e5a,0x0e5b,0x0e5c,0x0e5d,0x0e5e,0x0e5f,
+  0x0e60,0x0e61,0x0e62,0x0e63,0x0e64,0x0e65,0x0e66,0x0e67,
+  0x0e68,0x0e69,0x0e6a,0x0e6b,0x0e6c,0x0e6d,0x0e6e,0x0e6f,
+  0x0e70,0x0e71,0x0e72,0x0e73,0x0e74,0x0e75,0x0e76,0x0e77,
+  0x0e78,0x0e79,0x0e7a,0x0e7b,0x0e7c,0x0e7d,0x0e7e,0x0e7f,
+  0x0e80,0x0e81,0x0e82,0x0e83,0x0e84,0x0e85,0x0e86,0x0e87,
+  0x0e88,0x0e89,0x0e8a,0x0e8b,0x0e8c,0x0e8d,0x0e8e,0x0e8f,
+  0x0e90,0x0e91,0x0e92,0x0e93,0x0e94,0x0e95,0x0e96,0x0e97,
+  0x0e98,0x0e99,0x0e9a,0x0e9b,0x0e9c,0x0e9d,0x0e9e,0x0e9f,
+  0x0ea0,0x0ea1,0x0ea2,0x0ea3,0x0ea4,0x0ea5,0x0ea6,0x0ea7,
+  0x0ea8,0x0ea9,0x0eaa,0x0eab,0x0eac,0x0ead,0x0eae,0x0eaf,
+  0x0eb0,0x0eb1,0x0eb2,0x0eb3,0x0eb4,0x0eb5,0x0eb6,0x0eb7,
+  0x0eb8,0x0eb9,0x0eba,0x0ebb,0x0ebc,0x0ebd,0x0ebe,0x0ebf,
+  0x0ec0,0x0ec1,0x0ec2,0x0ec3,0x0ec4,0x0ec5,0x0ec6,0x0ec7,
+  0x0ec8,0x0ec9,0x0eca,0x0ecb,0x0ecc,0x0ecd,0x0ece,0x0ecf,
+  0x0ed0,0x0ed1,0x0ed2,0x0ed3,0x0ed4,0x0ed5,0x0ed6,0x0ed7,
+  0x0ed8,0x0ed9,0x0eda,0x0edb,0x0edc,0x0edd,0x0ede,0x0edf,
+  0x0ee0,0x0ee1,0x0ee2,0x0ee3,0x0ee4,0x0ee5,0x0ee6,0x0ee7,
+  0x0ee8,0x0ee9,0x0eea,0x0eeb,0x0eec,0x0eed,0x0eee,0x0eef,
+  0x0ef0,0x0ef1,0x0ef2,0x0ef3,0x0ef4,0x0ef5,0x0ef6,0x0ef7,
+  0x0ef8,0x0ef9,0x0efa,0x0efb,0x0efc,0x0efd,0x0efe,0x0eff,
+  0x0f00,0x0f01,0x0f02,0x0f03,0x0f04,0x0f05,0x0f06,0x0f07,
+  0x0f08,0x0f09,0x0f0a,0x0f0b,0x0f0c,0x0f0d,0x0f0e,0x0f0f,
+  0x0f10,0x0f11,0x0f12,0x0f13,0x0f14,0x0f15,0x0f16,0x0f17,
+  0x0f18,0x0f19,0x0f1a,0x0f1b,0x0f1c,0x0f1d,0x0f1e,0x0f1f,
+  0x0f20,0x0f21,0x0f22,0x0f23,0x0f24,0x0f25,0x0f26,0x0f27,
+  0x0f28,0x0f29,0x0f2a,0x0f2b,0x0f2c,0x0f2d,0x0f2e,0x0f2f,
+  0x0f30,0x0f31,0x0f32,0x0f33,0x0f34,0x0f35,0x0f36,0x0f37,
+  0x0f38,0x0f39,0x0f3a,0x0f3b,0x0f3c,0x0f3d,0x0f3e,0x0f3f,
+  0x0f40,0x0f41,0x0f42,0x0f43,0x0f44,0x0f45,0x0f46,0x0f47,
+  0x0f48,0x0f49,0x0f4a,0x0f4b,0x0f4c,0x0f4d,0x0f4e,0x0f4f,
+  0x0f50,0x0f51,0x0f52,0x0f53,0x0f54,0x0f55,0x0f56,0x0f57,
+  0x0f58,0x0f59,0x0f5a,0x0f5b,0x0f5c,0x0f5d,0x0f5e,0x0f5f,
+  0x0f60,0x0f61,0x0f62,0x0f63,0x0f64,0x0f65,0x0f66,0x0f67,
+  0x0f68,0x0f69,0x0f6a,0x0f6b,0x0f6c,0x0f6d,0x0f6e,0x0f6f,
+  0x0f70,0x0f71,0x0f72,0x0f73,0x0f74,0x0f75,0x0f76,0x0f77,
+  0x0f78,0x0f79,0x0f7a,0x0f7b,0x0f7c,0x0f7d,0x0f7e,0x0f7f,
+  0x0f80,0x0f81,0x0f82,0x0f83,0x0f84,0x0f85,0x0f86,0x0f87,
+  0x0f88,0x0f89,0x0f8a,0x0f8b,0x0f8c,0x0f8d,0x0f8e,0x0f8f,
+  0x0f90,0x0f91,0x0f92,0x0f93,0x0f94,0x0f95,0x0f96,0x0f97,
+  0x0f98,0x0f99,0x0f9a,0x0f9b,0x0f9c,0x0f9d,0x0f9e,0x0f9f,
+  0x0fa0,0x0fa1,0x0fa2,0x0fa3,0x0fa4,0x0fa5,0x0fa6,0x0fa7,
+  0x0fa8,0x0fa9,0x0faa,0x0fab,0x0fac,0x0fad,0x0fae,0x0faf,
+  0x0fb0,0x0fb1,0x0fb2,0x0fb3,0x0fb4,0x0fb5,0x0fb6,0x0fb7,
+  0x0fb8,0x0fb9,0x0fba,0x0fbb,0x0fbc,0x0fbd,0x0fbe,0x0fbf,
+  0x0fc0,0x0fc1,0x0fc2,0x0fc3,0x0fc4,0x0fc5,0x0fc6,0x0fc7,
+  0x0fc8,0x0fc9,0x0fca,0x0fcb,0x0fcc,0x0fcd,0x0fce,0x0fcf,
+  0x0fd0,0x0fd1,0x0fd2,0x0fd3,0x0fd4,0x0fd5,0x0fd6,0x0fd7,
+  0x0fd8,0x0fd9,0x0fda,0x0fdb,0x0fdc,0x0fdd,0x0fde,0x0fdf,
+  0x0fe0,0x0fe1,0x0fe2,0x0fe3,0x0fe4,0x0fe5,0x0fe6,0x0fe7,
+  0x0fe8,0x0fe9,0x0fea,0x0feb,0x0fec,0x0fed,0x0fee,0x0fef,
+  0x0ff0,0x0ff1,0x0ff2,0x0ff3,0x0ff4,0x0ff5,0x0ff6,0x0ff7,
+  0x0ff8,0x0ff9,0x0ffa,0x0ffb,0x0ffc,0x0ffd,0x0ffe,0x0fff,
+  0x1000,0x1001,0x1002,0x1003,0x1004,0x1005,0x1006,0x1007,
+  0x1008,0x1009,0x100a,0x100b,0x100c,0x100d,0x100e,0x100f,
+  0x1010,0x1011,0x1012,0x1013,0x1014,0x1015,0x1016,0x1017,
+  0x1018,0x1019,0x101a,0x101b,0x101c,0x101d,0x101e,0x101f,
+  0x1020,0x1021,0x1022,0x1023,0x1024,0x1025,0x1026,0x1027,
+  0x1028,0x1029,0x102a,0x102b,0x102c,0x102d,0x102e,0x102f,
+  0x1030,0x1031,0x1032,0x1033,0x1034,0x1035,0x1036,0x1037,
+  0x1038,0x1039,0x103a,0x103b,0x103c,0x103d,0x103e,0x103f,
+  0x1040,0x1041,0x1042,0x1043,0x1044,0x1045,0x1046,0x1047,
+  0x1048,0x1049,0x104a,0x104b,0x104c,0x104d,0x104e,0x104f,
+  0x1050,0x1051,0x1052,0x1053,0x1054,0x1055,0x1056,0x1057,
+  0x1058,0x1059,0x105a,0x105b,0x105c,0x105d,0x105e,0x105f,
+  0x1060,0x1061,0x1062,0x1063,0x1064,0x1065,0x1066,0x1067,
+  0x1068,0x1069,0x106a,0x106b,0x106c,0x106d,0x106e,0x106f,
+  0x1070,0x1071,0x1072,0x1073,0x1074,0x1075,0x1076,0x1077,
+  0x1078,0x1079,0x107a,0x107b,0x107c,0x107d,0x107e,0x107f,
+  0x1080,0x1081,0x1082,0x1083,0x1084,0x1085,0x1086,0x1087,
+  0x1088,0x1089,0x108a,0x108b,0x108c,0x108d,0x108e,0x108f,
+  0x1090,0x1091,0x1092,0x1093,0x1094,0x1095,0x1096,0x1097,
+  0x1098,0x1099,0x109a,0x109b,0x109c,0x109d,0x109e,0x109f,
+  0x10a0,0x10a1,0x10a2,0x10a3,0x10a4,0x10a5,0x10a6,0x10a7,
+  0x10a8,0x10a9,0x10aa,0x10ab,0x10ac,0x10ad,0x10ae,0x10af,
+  0x10b0,0x10b1,0x10b2,0x10b3,0x10b4,0x10b5,0x10b6,0x10b7,
+  0x10b8,0x10b9,0x10ba,0x10bb,0x10bc,0x10bd,0x10be,0x10bf,
+  0x10c0,0x10c1,0x10c2,0x10c3,0x10c4,0x10c5,0x10c6,0x10c7,
+  0x10c8,0x10c9,0x10ca,0x10cb,0x10cc,0x10cd,0x10ce,0x10cf,
+  0x10d0,0x10d1,0x10d2,0x10d3,0x10d4,0x10d5,0x10d6,0x10d7,
+  0x10d8,0x10d9,0x10da,0x10db,0x10dc,0x10dd,0x10de,0x10df,
+  0x10e0,0x10e1,0x10e2,0x10e3,0x10e4,0x10e5,0x10e6,0x10e7,
+  0x10e8,0x10e9,0x10ea,0x10eb,0x10ec,0x10ed,0x10ee,0x10ef,
+  0x10f0,0x10f1,0x10f2,0x10f3,0x10f4,0x10f5,0x10f6,0x10f7,
+  0x10f8,0x10f9,0x10fa,0x10fb,0x10fc,0x10fd,0x10fe,0x10ff,
+  0x1100,0x1101,0x1102,0x1103,0x1104,0x1105,0x1106,0x1107,
+  0x1108,0x1109,0x110a,0x110b,0x110c,0x110d,0x110e,0x110f,
+  0x1110,0x1111,0x1112,0x1113,0x1114,0x1115,0x1116,0x1117,
+  0x1118,0x1119,0x111a,0x111b,0x111c,0x111d,0x111e,0x111f,
+  0x1120,0x1121,0x1122,0x1123,0x1124,0x1125,0x1126,0x1127,
+  0x1128,0x1129,0x112a,0x112b,0x112c,0x112d,0x112e,0x112f,
+  0x1130,0x1131,0x1132,0x1133,0x1134,0x1135,0x1136,0x1137,
+  0x1138,0x1139,0x113a,0x113b,0x113c,0x113d,0x113e,0x113f,
+  0x1140,0x1141,0x1142,0x1143,0x1144,0x1145,0x1146,0x1147,
+  0x1148,0x1149,0x114a,0x114b,0x114c,0x114d,0x114e,0x114f,
+  0x1150,0x1151,0x1152,0x1153,0x1154,0x1155,0x1156,0x1157,
+  0x1158,0x1159,0x115a,0x115b,0x115c,0x115d,0x115e,0x115f,
+  0x1160,0x1161,0x1162,0x1163,0x1164,0x1165,0x1166,0x1167,
+  0x1168,0x1169,0x116a,0x116b,0x116c,0x116d,0x116e,0x116f,
+  0x1170,0x1171,0x1172,0x1173,0x1174,0x1175,0x1176,0x1177,
+  0x1178,0x1179,0x117a,0x117b,0x117c,0x117d,0x117e,0x117f,
+  0x1180,0x1181,0x1182,0x1183,0x1184,0x1185,0x1186,0x1187,
+  0x1188,0x1189,0x118a,0x118b,0x118c,0x118d,0x118e,0x118f,
+  0x1190,0x1191,0x1192,0x1193,0x1194,0x1195,0x1196,0x1197,
+  0x1198,0x1199,0x119a,0x119b,0x119c,0x119d,0x119e,0x119f,
+  0x11a0,0x11a1,0x11a2,0x11a3,0x11a4,0x11a5,0x11a6,0x11a7,
+  0x11a8,0x11a9,0x11aa,0x11ab,0x11ac,0x11ad,0x11ae,0x11af,
+  0x11b0,0x11b1,0x11b2,0x11b3,0x11b4,0x11b5,0x11b6,0x11b7,
+  0x11b8,0x11b9,0x11ba,0x11bb,0x11bc,0x11bd,0x11be,0x11bf,
+  0x11c0,0x11c1,0x11c2,0x11c3,0x11c4,0x11c5,0x11c6,0x11c7,
+  0x11c8,0x11c9,0x11ca,0x11cb,0x11cc,0x11cd,0x11ce,0x11cf,
+  0x11d0,0x11d1,0x11d2,0x11d3,0x11d4,0x11d5,0x11d6,0x11d7,
+  0x11d8,0x11d9,0x11da,0x11db,0x11dc,0x11dd,0x11de,0x11df,
+  0x11e0,0x11e1,0x11e2,0x11e3,0x11e4,0x11e5,0x11e6,0x11e7,
+  0x11e8,0x11e9,0x11ea,0x11eb,0x11ec,0x11ed,0x11ee,0x11ef,
+  0x11f0,0x11f1,0x11f2,0x11f3,0x11f4,0x11f5,0x11f6,0x11f7,
+  0x11f8,0x11f9,0x11fa,0x11fb,0x11fc,0x11fd,0x11fe,0x11ff,
+  0x1200,0x1201,0x1202,0x1203,0x1204,0x1205,0x1206,0x1207,
+  0x1208,0x1209,0x120a,0x120b,0x120c,0x120d,0x120e,0x120f,
+  0x1210,0x1211,0x1212,0x1213,0x1214,0x1215,0x1216,0x1217,
+  0x1218,0x1219,0x121a,0x121b,0x121c,0x121d,0x121e,0x121f,
+  0x1220,0x1221,0x1222,0x1223,0x1224,0x1225,0x1226,0x1227,
+  0x1228,0x1229,0x122a,0x122b,0x122c,0x122d,0x122e,0x122f,
+  0x1230,0x1231,0x1232,0x1233,0x1234,0x1235,0x1236,0x1237,
+  0x1238,0x1239,0x123a,0x123b,0x123c,0x123d,0x123e,0x123f,
+  0x1240,0x1241,0x1242,0x1243,0x1244,0x1245,0x1246,0x1247,
+  0x1248,0x1249,0x124a,0x124b,0x124c,0x124d,0x124e,0x124f,
+  0x1250,0x1251,0x1252,0x1253,0x1254,0x1255,0x1256,0x1257,
+  0x1258,0x1259,0x125a,0x125b,0x125c,0x125d,0x125e,0x125f,
+  0x1260,0x1261,0x1262,0x1263,0x1264,0x1265,0x1266,0x1267,
+  0x1268,0x1269,0x126a,0x126b,0x126c,0x126d,0x126e,0x126f,
+  0x1270,0x1271,0x1272,0x1273,0x1274,0x1275,0x1276,0x1277,
+  0x1278,0x1279,0x127a,0x127b,0x127c,0x127d,0x127e,0x127f,
+  0x1280,0x1281,0x1282,0x1283,0x1284,0x1285,0x1286,0x1287,
+  0x1288,0x1289,0x128a,0x128b,0x128c,0x128d,0x128e,0x128f,
+  0x1290,0x1291,0x1292,0x1293,0x1294,0x1295,0x1296,0x1297,
+  0x1298,0x1299,0x129a,0x129b,0x129c,0x129d,0x129e,0x129f,
+  0x12a0,0x12a1,0x12a2,0x12a3,0x12a4,0x12a5,0x12a6,0x12a7,
+  0x12a8,0x12a9,0x12aa,0x12ab,0x12ac,0x12ad,0x12ae,0x12af,
+  0x12b0,0x12b1,0x12b2,0x12b3,0x12b4,0x12b5,0x12b6,0x12b7,
+  0x12b8,0x12b9,0x12ba,0x12bb,0x12bc,0x12bd,0x12be,0x12bf,
+  0x12c0,0x12c1,0x12c2,0x12c3,0x12c4,0x12c5,0x12c6,0x12c7,
+  0x12c8,0x12c9,0x12ca,0x12cb,0x12cc,0x12cd,0x12ce,0x12cf,
+  0x12d0,0x12d1,0x12d2,0x12d3,0x12d4,0x12d5,0x12d6,0x12d7,
+  0x12d8,0x12d9,0x12da,0x12db,0x12dc,0x12dd,0x12de,0x12df,
+  0x12e0,0x12e1,0x12e2,0x12e3,0x12e4,0x12e5,0x12e6,0x12e7,
+  0x12e8,0x12e9,0x12ea,0x12eb,0x12ec,0x12ed,0x12ee,0x12ef,
+  0x12f0,0x12f1,0x12f2,0x12f3,0x12f4,0x12f5,0x12f6,0x12f7,
+  0x12f8,0x12f9,0x12fa,0x12fb,0x12fc,0x12fd,0x12fe,0x12ff,
+  0x1300,0x1301,0x1302,0x1303,0x1304,0x1305,0x1306,0x1307,
+  0x1308,0x1309,0x130a,0x130b,0x130c,0x130d,0x130e,0x130f,
+  0x1310,0x1311,0x1312,0x1313,0x1314,0x1315,0x1316,0x1317,
+  0x1318,0x1319,0x131a,0x131b,0x131c,0x131d,0x131e,0x131f,
+  0x1320,0x1321,0x1322,0x1323,0x1324,0x1325,0x1326,0x1327,
+  0x1328,0x1329,0x132a,0x132b,0x132c,0x132d,0x132e,0x132f,
+  0x1330,0x1331,0x1332,0x1333,0x1334,0x1335,0x1336,0x1337,
+  0x1338,0x1339,0x133a,0x133b,0x133c,0x133d,0x133e,0x133f,
+  0x1340,0x1341,0x1342,0x1343,0x1344,0x1345,0x1346,0x1347,
+  0x1348,0x1349,0x134a,0x134b,0x134c,0x134d,0x134e,0x134f,
+  0x1350,0x1351,0x1352,0x1353,0x1354,0x1355,0x1356,0x1357,
+  0x1358,0x1359,0x135a,0x135b,0x135c,0x135d,0x135e,0x135f,
+  0x1360,0x1361,0x1362,0x1363,0x1364,0x1365,0x1366,0x1367,
+  0x1368,0x1369,0x136a,0x136b,0x136c,0x136d,0x136e,0x136f,
+  0x1370,0x1371,0x1372,0x1373,0x1374,0x1375,0x1376,0x1377,
+  0x1378,0x1379,0x137a,0x137b,0x137c,0x137d,0x137e,0x137f,
+  0x1380,0x1381,0x1382,0x1383,0x1384,0x1385,0x1386,0x1387,
+  0x1388,0x1389,0x138a,0x138b,0x138c,0x138d,0x138e,0x138f,
+  0x1390,0x1391,0x1392,0x1393,0x1394,0x1395,0x1396,0x1397,
+  0x1398,0x1399,0x139a,0x139b,0x139c,0x139d,0x139e,0x139f,
+  0x13a0,0x13a1,0x13a2,0x13a3,0x13a4,0x13a5,0x13a6,0x13a7,
+  0x13a8,0x13a9,0x13aa,0x13ab,0x13ac,0x13ad,0x13ae,0x13af,
+  0x13b0,0x13b1,0x13b2,0x13b3,0x13b4,0x13b5,0x13b6,0x13b7,
+  0x13b8,0x13b9,0x13ba,0x13bb,0x13bc,0x13bd,0x13be,0x13bf,
+  0x13c0,0x13c1,0x13c2,0x13c3,0x13c4,0x13c5,0x13c6,0x13c7,
+  0x13c8,0x13c9,0x13ca,0x13cb,0x13cc,0x13cd,0x13ce,0x13cf,
+  0x13d0,0x13d1,0x13d2,0x13d3,0x13d4,0x13d5,0x13d6,0x13d7,
+  0x13d8,0x13d9,0x13da,0x13db,0x13dc,0x13dd,0x13de,0x13df,
+  0x13e0,0x13e1,0x13e2,0x13e3,0x13e4,0x13e5,0x13e6,0x13e7,
+  0x13e8,0x13e9,0x13ea,0x13eb,0x13ec,0x13ed,0x13ee,0x13ef,
+  0x13f0,0x13f1,0x13f2,0x13f3,0x13f4,0x13f5,0x13f6,0x13f7,
+  0x13f8,0x13f9,0x13fa,0x13fb,0x13fc,0x13fd,0x13fe,0x13ff,
+  0x1400,0x1401,0x1402,0x1403,0x1404,0x1405,0x1406,0x1407,
+  0x1408,0x1409,0x140a,0x140b,0x140c,0x140d,0x140e,0x140f,
+  0x1410,0x1411,0x1412,0x1413,0x1414,0x1415,0x1416,0x1417,
+  0x1418,0x1419,0x141a,0x141b,0x141c,0x141d,0x141e,0x141f,
+  0x1420,0x1421,0x1422,0x1423,0x1424,0x1425,0x1426,0x1427,
+  0x1428,0x1429,0x142a,0x142b,0x142c,0x142d,0x142e,0x142f,
+  0x1430,0x1431,0x1432,0x1433,0x1434,0x1435,0x1436,0x1437,
+  0x1438,0x1439,0x143a,0x143b,0x143c,0x143d,0x143e,0x143f,
+  0x1440,0x1441,0x1442,0x1443,0x1444,0x1445,0x1446,0x1447,
+  0x1448,0x1449,0x144a,0x144b,0x144c,0x144d,0x144e,0x144f,
+  0x1450,0x1451,0x1452,0x1453,0x1454,0x1455,0x1456,0x1457,
+  0x1458,0x1459,0x145a,0x145b,0x145c,0x145d,0x145e,0x145f,
+  0x1460,0x1461,0x1462,0x1463,0x1464,0x1465,0x1466,0x1467,
+  0x1468,0x1469,0x146a,0x146b,0x146c,0x146d,0x146e,0x146f,
+  0x1470,0x1471,0x1472,0x1473,0x1474,0x1475,0x1476,0x1477,
+  0x1478,0x1479,0x147a,0x147b,0x147c,0x147d,0x147e,0x147f,
+  0x1480,0x1481,0x1482,0x1483,0x1484,0x1485,0x1486,0x1487,
+  0x1488,0x1489,0x148a,0x148b,0x148c,0x148d,0x148e,0x148f,
+  0x1490,0x1491,0x1492,0x1493,0x1494,0x1495,0x1496,0x1497,
+  0x1498,0x1499,0x149a,0x149b,0x149c,0x149d,0x149e,0x149f,
+  0x14a0,0x14a1,0x14a2,0x14a3,0x14a4,0x14a5,0x14a6,0x14a7,
+  0x14a8,0x14a9,0x14aa,0x14ab,0x14ac,0x14ad,0x14ae,0x14af,
+  0x14b0,0x14b1,0x14b2,0x14b3,0x14b4,0x14b5,0x14b6,0x14b7,
+  0x14b8,0x14b9,0x14ba,0x14bb,0x14bc,0x14bd,0x14be,0x14bf,
+  0x14c0,0x14c1,0x14c2,0x14c3,0x14c4,0x14c5,0x14c6,0x14c7,
+  0x14c8,0x14c9,0x14ca,0x14cb,0x14cc,0x14cd,0x14ce,0x14cf,
+  0x14d0,0x14d1,0x14d2,0x14d3,0x14d4,0x14d5,0x14d6,0x14d7,
+  0x14d8,0x14d9,0x14da,0x14db,0x14dc,0x14dd,0x14de,0x14df,
+  0x14e0,0x14e1,0x14e2,0x14e3,0x14e4,0x14e5,0x14e6,0x14e7,
+  0x14e8,0x14e9,0x14ea,0x14eb,0x14ec,0x14ed,0x14ee,0x14ef,
+  0x14f0,0x14f1,0x14f2,0x14f3,0x14f4,0x14f5,0x14f6,0x14f7,
+  0x14f8,0x14f9,0x14fa,0x14fb,0x14fc,0x14fd,0x14fe,0x14ff,
+  0x1500,0x1501,0x1502,0x1503,0x1504,0x1505,0x1506,0x1507,
+  0x1508,0x1509,0x150a,0x150b,0x150c,0x150d,0x150e,0x150f,
+  0x1510,0x1511,0x1512,0x1513,0x1514,0x1515,0x1516,0x1517,
+  0x1518,0x1519,0x151a,0x151b,0x151c,0x151d,0x151e,0x151f,
+  0x1520,0x1521,0x1522,0x1523,0x1524,0x1525,0x1526,0x1527,
+  0x1528,0x1529,0x152a,0x152b,0x152c,0x152d,0x152e,0x152f,
+  0x1530,0x1531,0x1532,0x1533,0x1534,0x1535,0x1536,0x1537,
+  0x1538,0x1539,0x153a,0x153b,0x153c,0x153d,0x153e,0x153f,
+  0x1540,0x1541,0x1542,0x1543,0x1544,0x1545,0x1546,0x1547,
+  0x1548,0x1549,0x154a,0x154b,0x154c,0x154d,0x154e,0x154f,
+  0x1550,0x1551,0x1552,0x1553,0x1554,0x1555,0x1556,0x1557,
+  0x1558,0x1559,0x155a,0x155b,0x155c,0x155d,0x155e,0x155f,
+  0x1560,0x1561,0x1562,0x1563,0x1564,0x1565,0x1566,0x1567,
+  0x1568,0x1569,0x156a,0x156b,0x156c,0x156d,0x156e,0x156f,
+  0x1570,0x1571,0x1572,0x1573,0x1574,0x1575,0x1576,0x1577,
+  0x1578,0x1579,0x157a,0x157b,0x157c,0x157d,0x157e,0x157f,
+  0x1580,0x1581,0x1582,0x1583,0x1584,0x1585,0x1586,0x1587,
+  0x1588,0x1589,0x158a,0x158b,0x158c,0x158d,0x158e,0x158f,
+  0x1590,0x1591,0x1592,0x1593,0x1594,0x1595,0x1596,0x1597,
+  0x1598,0x1599,0x159a,0x159b,0x159c,0x159d,0x159e,0x159f,
+  0x15a0,0x15a1,0x15a2,0x15a3,0x15a4,0x15a5,0x15a6,0x15a7,
+  0x15a8,0x15a9,0x15aa,0x15ab,0x15ac,0x15ad,0x15ae,0x15af,
+  0x15b0,0x15b1,0x15b2,0x15b3,0x15b4,0x15b5,0x15b6,0x15b7,
+  0x15b8,0x15b9,0x15ba,0x15bb,0x15bc,0x15bd,0x15be,0x15bf,
+  0x15c0,0x15c1,0x15c2,0x15c3,0x15c4,0x15c5,0x15c6,0x15c7,
+  0x15c8,0x15c9,0x15ca,0x15cb,0x15cc,0x15cd,0x15ce,0x15cf,
+  0x15d0,0x15d1,0x15d2,0x15d3,0x15d4,0x15d5,0x15d6,0x15d7,
+  0x15d8,0x15d9,0x15da,0x15db,0x15dc,0x15dd,0x15de,0x15df,
+  0x15e0,0x15e1,0x15e2,0x15e3,0x15e4,0x15e5,0x15e6,0x15e7,
+  0x15e8,0x15e9,0x15ea,0x15eb,0x15ec,0x15ed,0x15ee,0x15ef,
+  0x15f0,0x15f1,0x15f2,0x15f3,0x15f4,0x15f5,0x15f6,0x15f7,
+  0x15f8,0x15f9,0x15fa,0x15fb,0x15fc,0x15fd,0x15fe,0x15ff,
+  0x1600,0x1601,0x1602,0x1603,0x1604,0x1605,0x1606,0x1607,
+  0x1608,0x1609,0x160a,0x160b,0x160c,0x160d,0x160e,0x160f,
+  0x1610,0x1611,0x1612,0x1613,0x1614,0x1615,0x1616,0x1617,
+  0x1618,0x1619,0x161a,0x161b,0x161c,0x161d,0x161e,0x161f,
+  0x1620,0x1621,0x1622,0x1623,0x1624,0x1625,0x1626,0x1627,
+  0x1628,0x1629,0x162a,0x162b,0x162c,0x162d,0x162e,0x162f,
+  0x1630,0x1631,0x1632,0x1633,0x1634,0x1635,0x1636,0x1637,
+  0x1638,0x1639,0x163a,0x163b,0x163c,0x163d,0x163e,0x163f,
+  0x1640,0x1641,0x1642,0x1643,0x1644,0x1645,0x1646,0x1647,
+  0x1648,0x1649,0x164a,0x164b,0x164c,0x164d,0x164e,0x164f,
+  0x1650,0x1651,0x1652,0x1653,0x1654,0x1655,0x1656,0x1657,
+  0x1658,0x1659,0x165a,0x165b,0x165c,0x165d,0x165e,0x165f,
+  0x1660,0x1661,0x1662,0x1663,0x1664,0x1665,0x1666,0x1667,
+  0x1668,0x1669,0x166a,0x166b,0x166c,0x166d,0x166e,0x166f,
+  0x1670,0x1671,0x1672,0x1673,0x1674,0x1675,0x1676,0x1677,
+  0x1678,0x1679,0x167a,0x167b,0x167c,0x167d,0x167e,0x167f,
+  0x1680,0x1681,0x1682,0x1683,0x1684,0x1685,0x1686,0x1687,
+  0x1688,0x1689,0x168a,0x168b,0x168c,0x168d,0x168e,0x168f,
+  0x1690,0x1691,0x1692,0x1693,0x1694,0x1695,0x1696,0x1697,
+  0x1698,0x1699,0x169a,0x169b,0x169c,0x169d,0x169e,0x169f,
+  0x16a0,0x16a1,0x16a2,0x16a3,0x16a4,0x16a5,0x16a6,0x16a7,
+  0x16a8,0x16a9,0x16aa,0x16ab,0x16ac,0x16ad,0x16ae,0x16af,
+  0x16b0,0x16b1,0x16b2,0x16b3,0x16b4,0x16b5,0x16b6,0x16b7,
+  0x16b8,0x16b9,0x16ba,0x16bb,0x16bc,0x16bd,0x16be,0x16bf,
+  0x16c0,0x16c1,0x16c2,0x16c3,0x16c4,0x16c5,0x16c6,0x16c7,
+  0x16c8,0x16c9,0x16ca,0x16cb,0x16cc,0x16cd,0x16ce,0x16cf,
+  0x16d0,0x16d1,0x16d2,0x16d3,0x16d4,0x16d5,0x16d6,0x16d7,
+  0x16d8,0x16d9,0x16da,0x16db,0x16dc,0x16dd,0x16de,0x16df,
+  0x16e0,0x16e1,0x16e2,0x16e3,0x16e4,0x16e5,0x16e6,0x16e7,
+  0x16e8,0x16e9,0x16ea,0x16eb,0x16ec,0x16ed,0x16ee,0x16ef,
+  0x16f0,0x16f1,0x16f2,0x16f3,0x16f4,0x16f5,0x16f6,0x16f7,
+  0x16f8,0x16f9,0x16fa,0x16fb,0x16fc,0x16fd,0x16fe,0x16ff,
+  0x1700,0x1701,0x1702,0x1703,0x1704,0x1705,0x1706,0x1707,
+  0x1708,0x1709,0x170a,0x170b,0x170c,0x170d,0x170e,0x170f,
+  0x1710,0x1711,0x1712,0x1713,0x1714,0x1715,0x1716,0x1717,
+  0x1718,0x1719,0x171a,0x171b,0x171c,0x171d,0x171e,0x171f,
+  0x1720,0x1721,0x1722,0x1723,0x1724,0x1725,0x1726,0x1727,
+  0x1728,0x1729,0x172a,0x172b,0x172c,0x172d,0x172e,0x172f,
+  0x1730,0x1731,0x1732,0x1733,0x1734,0x1735,0x1736,0x1737,
+  0x1738,0x1739,0x173a,0x173b,0x173c,0x173d,0x173e,0x173f,
+  0x1740,0x1741,0x1742,0x1743,0x1744,0x1745,0x1746,0x1747,
+  0x1748,0x1749,0x174a,0x174b,0x174c,0x174d,0x174e,0x174f,
+  0x1750,0x1751,0x1752,0x1753,0x1754,0x1755,0x1756,0x1757,
+  0x1758,0x1759,0x175a,0x175b,0x175c,0x175d,0x175e,0x175f,
+  0x1760,0x1761,0x1762,0x1763,0x1764,0x1765,0x1766,0x1767,
+  0x1768,0x1769,0x176a,0x176b,0x176c,0x176d,0x176e,0x176f,
+  0x1770,0x1771,0x1772,0x1773,0x1774,0x1775,0x1776,0x1777,
+  0x1778,0x1779,0x177a,0x177b,0x177c,0x177d,0x177e,0x177f,
+  0x1780,0x1781,0x1782,0x1783,0x1784,0x1785,0x1786,0x1787,
+  0x1788,0x1789,0x178a,0x178b,0x178c,0x178d,0x178e,0x178f,
+  0x1790,0x1791,0x1792,0x1793,0x1794,0x1795,0x1796,0x1797,
+  0x1798,0x1799,0x179a,0x179b,0x179c,0x179d,0x179e,0x179f,
+  0x17a0,0x17a1,0x17a2,0x17a3,0x17a4,0x17a5,0x17a6,0x17a7,
+  0x17a8,0x17a9,0x17aa,0x17ab,0x17ac,0x17ad,0x17ae,0x17af,
+  0x17b0,0x17b1,0x17b2,0x17b3,0x17b4,0x17b5,0x17b6,0x17b7,
+  0x17b8,0x17b9,0x17ba,0x17bb,0x17bc,0x17bd,0x17be,0x17bf,
+  0x17c0,0x17c1,0x17c2,0x17c3,0x17c4,0x17c5,0x17c6,0x17c7,
+  0x17c8,0x17c9,0x17ca,0x17cb,0x17cc,0x17cd,0x17ce,0x17cf,
+  0x17d0,0x17d1,0x17d2,0x17d3,0x17d4,0x17d5,0x17d6,0x17d7,
+  0x17d8,0x17d9,0x17da,0x17db,0x17dc,0x17dd,0x17de,0x17df,
+  0x17e0,0x17e1,0x17e2,0x17e3,0x17e4,0x17e5,0x17e6,0x17e7,
+  0x17e8,0x17e9,0x17ea,0x17eb,0x17ec,0x17ed,0x17ee,0x17ef,
+  0x17f0,0x17f1,0x17f2,0x17f3,0x17f4,0x17f5,0x17f6,0x17f7,
+  0x17f8,0x17f9,0x17fa,0x17fb,0x17fc,0x17fd,0x17fe,0x17ff,
+  0x1800,0x1801,0x1802,0x1803,0x1804,0x1805,0x1806,0x1807,
+  0x1808,0x1809,0x180a,0x180b,0x180c,0x180d,0x180e,0x180f,
+  0x1810,0x1811,0x1812,0x1813,0x1814,0x1815,0x1816,0x1817,
+  0x1818,0x1819,0x181a,0x181b,0x181c,0x181d,0x181e,0x181f,
+  0x1820,0x1821,0x1822,0x1823,0x1824,0x1825,0x1826,0x1827,
+  0x1828,0x1829,0x182a,0x182b,0x182c,0x182d,0x182e,0x182f,
+  0x1830,0x1831,0x1832,0x1833,0x1834,0x1835,0x1836,0x1837,
+  0x1838,0x1839,0x183a,0x183b,0x183c,0x183d,0x183e,0x183f,
+  0x1840,0x1841,0x1842,0x1843,0x1844,0x1845,0x1846,0x1847,
+  0x1848,0x1849,0x184a,0x184b,0x184c,0x184d,0x184e,0x184f,
+  0x1850,0x1851,0x1852,0x1853,0x1854,0x1855,0x1856,0x1857,
+  0x1858,0x1859,0x185a,0x185b,0x185c,0x185d,0x185e,0x185f,
+  0x1860,0x1861,0x1862,0x1863,0x1864,0x1865,0x1866,0x1867,
+  0x1868,0x1869,0x186a,0x186b,0x186c,0x186d,0x186e,0x186f,
+  0x1870,0x1871,0x1872,0x1873,0x1874,0x1875,0x1876,0x1877,
+  0x1878,0x1879,0x187a,0x187b,0x187c,0x187d,0x187e,0x187f,
+  0x1880,0x1881,0x1882,0x1883,0x1884,0x1885,0x1886,0x1887,
+  0x1888,0x1889,0x188a,0x188b,0x188c,0x188d,0x188e,0x188f,
+  0x1890,0x1891,0x1892,0x1893,0x1894,0x1895,0x1896,0x1897,
+  0x1898,0x1899,0x189a,0x189b,0x189c,0x189d,0x189e,0x189f,
+  0x18a0,0x18a1,0x18a2,0x18a3,0x18a4,0x18a5,0x18a6,0x18a7,
+  0x18a8,0x18a9,0x18aa,0x18ab,0x18ac,0x18ad,0x18ae,0x18af,
+  0x18b0,0x18b1,0x18b2,0x18b3,0x18b4,0x18b5,0x18b6,0x18b7,
+  0x18b8,0x18b9,0x18ba,0x18bb,0x18bc,0x18bd,0x18be,0x18bf,
+  0x18c0,0x18c1,0x18c2,0x18c3,0x18c4,0x18c5,0x18c6,0x18c7,
+  0x18c8,0x18c9,0x18ca,0x18cb,0x18cc,0x18cd,0x18ce,0x18cf,
+  0x18d0,0x18d1,0x18d2,0x18d3,0x18d4,0x18d5,0x18d6,0x18d7,
+  0x18d8,0x18d9,0x18da,0x18db,0x18dc,0x18dd,0x18de,0x18df,
+  0x18e0,0x18e1,0x18e2,0x18e3,0x18e4,0x18e5,0x18e6,0x18e7,
+  0x18e8,0x18e9,0x18ea,0x18eb,0x18ec,0x18ed,0x18ee,0x18ef,
+  0x18f0,0x18f1,0x18f2,0x18f3,0x18f4,0x18f5,0x18f6,0x18f7,
+  0x18f8,0x18f9,0x18fa,0x18fb,0x18fc,0x18fd,0x18fe,0x18ff,
+  0x1900,0x1901,0x1902,0x1903,0x1904,0x1905,0x1906,0x1907,
+  0x1908,0x1909,0x190a,0x190b,0x190c,0x190d,0x190e,0x190f,
+  0x1910,0x1911,0x1912,0x1913,0x1914,0x1915,0x1916,0x1917,
+  0x1918,0x1919,0x191a,0x191b,0x191c,0x191d,0x191e,0x191f,
+  0x1920,0x1921,0x1922,0x1923,0x1924,0x1925,0x1926,0x1927,
+  0x1928,0x1929,0x192a,0x192b,0x192c,0x192d,0x192e,0x192f,
+  0x1930,0x1931,0x1932,0x1933,0x1934,0x1935,0x1936,0x1937,
+  0x1938,0x1939,0x193a,0x193b,0x193c,0x193d,0x193e,0x193f,
+  0x1940,0x1941,0x1942,0x1943,0x1944,0x1945,0x1946,0x1947,
+  0x1948,0x1949,0x194a,0x194b,0x194c,0x194d,0x194e,0x194f,
+  0x1950,0x1951,0x1952,0x1953,0x1954,0x1955,0x1956,0x1957,
+  0x1958,0x1959,0x195a,0x195b,0x195c,0x195d,0x195e,0x195f,
+  0x1960,0x1961,0x1962,0x1963,0x1964,0x1965,0x1966,0x1967,
+  0x1968,0x1969,0x196a,0x196b,0x196c,0x196d,0x196e,0x196f,
+  0x1970,0x1971,0x1972,0x1973,0x1974,0x1975,0x1976,0x1977,
+  0x1978,0x1979,0x197a,0x197b,0x197c,0x197d,0x197e,0x197f,
+  0x1980,0x1981,0x1982,0x1983,0x1984,0x1985,0x1986,0x1987,
+  0x1988,0x1989,0x198a,0x198b,0x198c,0x198d,0x198e,0x198f,
+  0x1990,0x1991,0x1992,0x1993,0x1994,0x1995,0x1996,0x1997,
+  0x1998,0x1999,0x199a,0x199b,0x199c,0x199d,0x199e,0x199f,
+  0x19a0,0x19a1,0x19a2,0x19a3,0x19a4,0x19a5,0x19a6,0x19a7,
+  0x19a8,0x19a9,0x19aa,0x19ab,0x19ac,0x19ad,0x19ae,0x19af,
+  0x19b0,0x19b1,0x19b2,0x19b3,0x19b4,0x19b5,0x19b6,0x19b7,
+  0x19b8,0x19b9,0x19ba,0x19bb,0x19bc,0x19bd,0x19be,0x19bf,
+  0x19c0,0x19c1,0x19c2,0x19c3,0x19c4,0x19c5,0x19c6,0x19c7,
+  0x19c8,0x19c9,0x19ca,0x19cb,0x19cc,0x19cd,0x19ce,0x19cf,
+  0x19d0,0x19d1,0x19d2,0x19d3,0x19d4,0x19d5,0x19d6,0x19d7,
+  0x19d8,0x19d9,0x19da,0x19db,0x19dc,0x19dd,0x19de,0x19df,
+  0x19e0,0x19e1,0x19e2,0x19e3,0x19e4,0x19e5,0x19e6,0x19e7,
+  0x19e8,0x19e9,0x19ea,0x19eb,0x19ec,0x19ed,0x19ee,0x19ef,
+  0x19f0,0x19f1,0x19f2,0x19f3,0x19f4,0x19f5,0x19f6,0x19f7,
+  0x19f8,0x19f9,0x19fa,0x19fb,0x19fc,0x19fd,0x19fe,0x19ff,
+  0x1a00,0x1a01,0x1a02,0x1a03,0x1a04,0x1a05,0x1a06,0x1a07,
+  0x1a08,0x1a09,0x1a0a,0x1a0b,0x1a0c,0x1a0d,0x1a0e,0x1a0f,
+  0x1a10,0x1a11,0x1a12,0x1a13,0x1a14,0x1a15,0x1a16,0x1a17,
+  0x1a18,0x1a19,0x1a1a,0x1a1b,0x1a1c,0x1a1d,0x1a1e,0x1a1f,
+  0x1a20,0x1a21,0x1a22,0x1a23,0x1a24,0x1a25,0x1a26,0x1a27,
+  0x1a28,0x1a29,0x1a2a,0x1a2b,0x1a2c,0x1a2d,0x1a2e,0x1a2f,
+  0x1a30,0x1a31,0x1a32,0x1a33,0x1a34,0x1a35,0x1a36,0x1a37,
+  0x1a38,0x1a39,0x1a3a,0x1a3b,0x1a3c,0x1a3d,0x1a3e,0x1a3f,
+  0x1a40,0x1a41,0x1a42,0x1a43,0x1a44,0x1a45,0x1a46,0x1a47,
+  0x1a48,0x1a49,0x1a4a,0x1a4b,0x1a4c,0x1a4d,0x1a4e,0x1a4f,
+  0x1a50,0x1a51,0x1a52,0x1a53,0x1a54,0x1a55,0x1a56,0x1a57,
+  0x1a58,0x1a59,0x1a5a,0x1a5b,0x1a5c,0x1a5d,0x1a5e,0x1a5f,
+  0x1a60,0x1a61,0x1a62,0x1a63,0x1a64,0x1a65,0x1a66,0x1a67,
+  0x1a68,0x1a69,0x1a6a,0x1a6b,0x1a6c,0x1a6d,0x1a6e,0x1a6f,
+  0x1a70,0x1a71,0x1a72,0x1a73,0x1a74,0x1a75,0x1a76,0x1a77,
+  0x1a78,0x1a79,0x1a7a,0x1a7b,0x1a7c,0x1a7d,0x1a7e,0x1a7f,
+  0x1a80,0x1a81,0x1a82,0x1a83,0x1a84,0x1a85,0x1a86,0x1a87,
+  0x1a88,0x1a89,0x1a8a,0x1a8b,0x1a8c,0x1a8d,0x1a8e,0x1a8f,
+  0x1a90,0x1a91,0x1a92,0x1a93,0x1a94,0x1a95,0x1a96,0x1a97,
+  0x1a98,0x1a99,0x1a9a,0x1a9b,0x1a9c,0x1a9d,0x1a9e,0x1a9f,
+  0x1aa0,0x1aa1,0x1aa2,0x1aa3,0x1aa4,0x1aa5,0x1aa6,0x1aa7,
+  0x1aa8,0x1aa9,0x1aaa,0x1aab,0x1aac,0x1aad,0x1aae,0x1aaf,
+  0x1ab0,0x1ab1,0x1ab2,0x1ab3,0x1ab4,0x1ab5,0x1ab6,0x1ab7,
+  0x1ab8,0x1ab9,0x1aba,0x1abb,0x1abc,0x1abd,0x1abe,0x1abf,
+  0x1ac0,0x1ac1,0x1ac2,0x1ac3,0x1ac4,0x1ac5,0x1ac6,0x1ac7,
+  0x1ac8,0x1ac9,0x1aca,0x1acb,0x1acc,0x1acd,0x1ace,0x1acf,
+  0x1ad0,0x1ad1,0x1ad2,0x1ad3,0x1ad4,0x1ad5,0x1ad6,0x1ad7,
+  0x1ad8,0x1ad9,0x1ada,0x1adb,0x1adc,0x1add,0x1ade,0x1adf,
+  0x1ae0,0x1ae1,0x1ae2,0x1ae3,0x1ae4,0x1ae5,0x1ae6,0x1ae7,
+  0x1ae8,0x1ae9,0x1aea,0x1aeb,0x1aec,0x1aed,0x1aee,0x1aef,
+  0x1af0,0x1af1,0x1af2,0x1af3,0x1af4,0x1af5,0x1af6,0x1af7,
+  0x1af8,0x1af9,0x1afa,0x1afb,0x1afc,0x1afd,0x1afe,0x1aff,
+  0x1b00,0x1b01,0x1b02,0x1b03,0x1b04,0x1b05,0x1b06,0x1b07,
+  0x1b08,0x1b09,0x1b0a,0x1b0b,0x1b0c,0x1b0d,0x1b0e,0x1b0f,
+  0x1b10,0x1b11,0x1b12,0x1b13,0x1b14,0x1b15,0x1b16,0x1b17,
+  0x1b18,0x1b19,0x1b1a,0x1b1b,0x1b1c,0x1b1d,0x1b1e,0x1b1f,
+  0x1b20,0x1b21,0x1b22,0x1b23,0x1b24,0x1b25,0x1b26,0x1b27,
+  0x1b28,0x1b29,0x1b2a,0x1b2b,0x1b2c,0x1b2d,0x1b2e,0x1b2f,
+  0x1b30,0x1b31,0x1b32,0x1b33,0x1b34,0x1b35,0x1b36,0x1b37,
+  0x1b38,0x1b39,0x1b3a,0x1b3b,0x1b3c,0x1b3d,0x1b3e,0x1b3f,
+  0x1b40,0x1b41,0x1b42,0x1b43,0x1b44,0x1b45,0x1b46,0x1b47,
+  0x1b48,0x1b49,0x1b4a,0x1b4b,0x1b4c,0x1b4d,0x1b4e,0x1b4f,
+  0x1b50,0x1b51,0x1b52,0x1b53,0x1b54,0x1b55,0x1b56,0x1b57,
+  0x1b58,0x1b59,0x1b5a,0x1b5b,0x1b5c,0x1b5d,0x1b5e,0x1b5f,
+  0x1b60,0x1b61,0x1b62,0x1b63,0x1b64,0x1b65,0x1b66,0x1b67,
+  0x1b68,0x1b69,0x1b6a,0x1b6b,0x1b6c,0x1b6d,0x1b6e,0x1b6f,
+  0x1b70,0x1b71,0x1b72,0x1b73,0x1b74,0x1b75,0x1b76,0x1b77,
+  0x1b78,0x1b79,0x1b7a,0x1b7b,0x1b7c,0x1b7d,0x1b7e,0x1b7f,
+  0x1b80,0x1b81,0x1b82,0x1b83,0x1b84,0x1b85,0x1b86,0x1b87,
+  0x1b88,0x1b89,0x1b8a,0x1b8b,0x1b8c,0x1b8d,0x1b8e,0x1b8f,
+  0x1b90,0x1b91,0x1b92,0x1b93,0x1b94,0x1b95,0x1b96,0x1b97,
+  0x1b98,0x1b99,0x1b9a,0x1b9b,0x1b9c,0x1b9d,0x1b9e,0x1b9f,
+  0x1ba0,0x1ba1,0x1ba2,0x1ba3,0x1ba4,0x1ba5,0x1ba6,0x1ba7,
+  0x1ba8,0x1ba9,0x1baa,0x1bab,0x1bac,0x1bad,0x1bae,0x1baf,
+  0x1bb0,0x1bb1,0x1bb2,0x1bb3,0x1bb4,0x1bb5,0x1bb6,0x1bb7,
+  0x1bb8,0x1bb9,0x1bba,0x1bbb,0x1bbc,0x1bbd,0x1bbe,0x1bbf,
+  0x1bc0,0x1bc1,0x1bc2,0x1bc3,0x1bc4,0x1bc5,0x1bc6,0x1bc7,
+  0x1bc8,0x1bc9,0x1bca,0x1bcb,0x1bcc,0x1bcd,0x1bce,0x1bcf,
+  0x1bd0,0x1bd1,0x1bd2,0x1bd3,0x1bd4,0x1bd5,0x1bd6,0x1bd7,
+  0x1bd8,0x1bd9,0x1bda,0x1bdb,0x1bdc,0x1bdd,0x1bde,0x1bdf,
+  0x1be0,0x1be1,0x1be2,0x1be3,0x1be4,0x1be5,0x1be6,0x1be7,
+  0x1be8,0x1be9,0x1bea,0x1beb,0x1bec,0x1bed,0x1bee,0x1bef,
+  0x1bf0,0x1bf1,0x1bf2,0x1bf3,0x1bf4,0x1bf5,0x1bf6,0x1bf7,
+  0x1bf8,0x1bf9,0x1bfa,0x1bfb,0x1bfc,0x1bfd,0x1bfe,0x1bff,
+  0x1c00,0x1c01,0x1c02,0x1c03,0x1c04,0x1c05,0x1c06,0x1c07,
+  0x1c08,0x1c09,0x1c0a,0x1c0b,0x1c0c,0x1c0d,0x1c0e,0x1c0f,
+  0x1c10,0x1c11,0x1c12,0x1c13,0x1c14,0x1c15,0x1c16,0x1c17,
+  0x1c18,0x1c19,0x1c1a,0x1c1b,0x1c1c,0x1c1d,0x1c1e,0x1c1f,
+  0x1c20,0x1c21,0x1c22,0x1c23,0x1c24,0x1c25,0x1c26,0x1c27,
+  0x1c28,0x1c29,0x1c2a,0x1c2b,0x1c2c,0x1c2d,0x1c2e,0x1c2f,
+  0x1c30,0x1c31,0x1c32,0x1c33,0x1c34,0x1c35,0x1c36,0x1c37,
+  0x1c38,0x1c39,0x1c3a,0x1c3b,0x1c3c,0x1c3d,0x1c3e,0x1c3f,
+  0x1c40,0x1c41,0x1c42,0x1c43,0x1c44,0x1c45,0x1c46,0x1c47,
+  0x1c48,0x1c49,0x1c4a,0x1c4b,0x1c4c,0x1c4d,0x1c4e,0x1c4f,
+  0x1c50,0x1c51,0x1c52,0x1c53,0x1c54,0x1c55,0x1c56,0x1c57,
+  0x1c58,0x1c59,0x1c5a,0x1c5b,0x1c5c,0x1c5d,0x1c5e,0x1c5f,
+  0x1c60,0x1c61,0x1c62,0x1c63,0x1c64,0x1c65,0x1c66,0x1c67,
+  0x1c68,0x1c69,0x1c6a,0x1c6b,0x1c6c,0x1c6d,0x1c6e,0x1c6f,
+  0x1c70,0x1c71,0x1c72,0x1c73,0x1c74,0x1c75,0x1c76,0x1c77,
+  0x1c78,0x1c79,0x1c7a,0x1c7b,0x1c7c,0x1c7d,0x1c7e,0x1c7f,
+  0x1c80,0x1c81,0x1c82,0x1c83,0x1c84,0x1c85,0x1c86,0x1c87,
+  0x1c88,0x1c89,0x1c8a,0x1c8b,0x1c8c,0x1c8d,0x1c8e,0x1c8f,
+  0x1c90,0x1c91,0x1c92,0x1c93,0x1c94,0x1c95,0x1c96,0x1c97,
+  0x1c98,0x1c99,0x1c9a,0x1c9b,0x1c9c,0x1c9d,0x1c9e,0x1c9f,
+  0x1ca0,0x1ca1,0x1ca2,0x1ca3,0x1ca4,0x1ca5,0x1ca6,0x1ca7,
+  0x1ca8,0x1ca9,0x1caa,0x1cab,0x1cac,0x1cad,0x1cae,0x1caf,
+  0x1cb0,0x1cb1,0x1cb2,0x1cb3,0x1cb4,0x1cb5,0x1cb6,0x1cb7,
+  0x1cb8,0x1cb9,0x1cba,0x1cbb,0x1cbc,0x1cbd,0x1cbe,0x1cbf,
+  0x1cc0,0x1cc1,0x1cc2,0x1cc3,0x1cc4,0x1cc5,0x1cc6,0x1cc7,
+  0x1cc8,0x1cc9,0x1cca,0x1ccb,0x1ccc,0x1ccd,0x1cce,0x1ccf,
+  0x1cd0,0x1cd1,0x1cd2,0x1cd3,0x1cd4,0x1cd5,0x1cd6,0x1cd7,
+  0x1cd8,0x1cd9,0x1cda,0x1cdb,0x1cdc,0x1cdd,0x1cde,0x1cdf,
+  0x1ce0,0x1ce1,0x1ce2,0x1ce3,0x1ce4,0x1ce5,0x1ce6,0x1ce7,
+  0x1ce8,0x1ce9,0x1cea,0x1ceb,0x1cec,0x1ced,0x1cee,0x1cef,
+  0x1cf0,0x1cf1,0x1cf2,0x1cf3,0x1cf4,0x1cf5,0x1cf6,0x1cf7,
+  0x1cf8,0x1cf9,0x1cfa,0x1cfb,0x1cfc,0x1cfd,0x1cfe,0x1cff,
+  0x1d00,0x1d01,0x1d02,0x1d03,0x1d04,0x1d05,0x1d06,0x1d07,
+  0x1d08,0x1d09,0x1d0a,0x1d0b,0x1d0c,0x1d0d,0x1d0e,0x1d0f,
+  0x1d10,0x1d11,0x1d12,0x1d13,0x1d14,0x1d15,0x1d16,0x1d17,
+  0x1d18,0x1d19,0x1d1a,0x1d1b,0x1d1c,0x1d1d,0x1d1e,0x1d1f,
+  0x1d20,0x1d21,0x1d22,0x1d23,0x1d24,0x1d25,0x1d26,0x1d27,
+  0x1d28,0x1d29,0x1d2a,0x1d2b,0x1d2c,0x1d2d,0x1d2e,0x1d2f,
+  0x1d30,0x1d31,0x1d32,0x1d33,0x1d34,0x1d35,0x1d36,0x1d37,
+  0x1d38,0x1d39,0x1d3a,0x1d3b,0x1d3c,0x1d3d,0x1d3e,0x1d3f,
+  0x1d40,0x1d41,0x1d42,0x1d43,0x1d44,0x1d45,0x1d46,0x1d47,
+  0x1d48,0x1d49,0x1d4a,0x1d4b,0x1d4c,0x1d4d,0x1d4e,0x1d4f,
+  0x1d50,0x1d51,0x1d52,0x1d53,0x1d54,0x1d55,0x1d56,0x1d57,
+  0x1d58,0x1d59,0x1d5a,0x1d5b,0x1d5c,0x1d5d,0x1d5e,0x1d5f,
+  0x1d60,0x1d61,0x1d62,0x1d63,0x1d64,0x1d65,0x1d66,0x1d67,
+  0x1d68,0x1d69,0x1d6a,0x1d6b,0x1d6c,0x1d6d,0x1d6e,0x1d6f,
+  0x1d70,0x1d71,0x1d72,0x1d73,0x1d74,0x1d75,0x1d76,0x1d77,
+  0x1d78,0x1d79,0x1d7a,0x1d7b,0x1d7c,0x2c63,0x1d7e,0x1d7f,
+  0x1d80,0x1d81,0x1d82,0x1d83,0x1d84,0x1d85,0x1d86,0x1d87,
+  0x1d88,0x1d89,0x1d8a,0x1d8b,0x1d8c,0x1d8d,0x1d8e,0x1d8f,
+  0x1d90,0x1d91,0x1d92,0x1d93,0x1d94,0x1d95,0x1d96,0x1d97,
+  0x1d98,0x1d99,0x1d9a,0x1d9b,0x1d9c,0x1d9d,0x1d9e,0x1d9f,
+  0x1da0,0x1da1,0x1da2,0x1da3,0x1da4,0x1da5,0x1da6,0x1da7,
+  0x1da8,0x1da9,0x1daa,0x1dab,0x1dac,0x1dad,0x1dae,0x1daf,
+  0x1db0,0x1db1,0x1db2,0x1db3,0x1db4,0x1db5,0x1db6,0x1db7,
+  0x1db8,0x1db9,0x1dba,0x1dbb,0x1dbc,0x1dbd,0x1dbe,0x1dbf,
+  0x1dc0,0x1dc1,0x1dc2,0x1dc3,0x1dc4,0x1dc5,0x1dc6,0x1dc7,
+  0x1dc8,0x1dc9,0x1dca,0x1dcb,0x1dcc,0x1dcd,0x1dce,0x1dcf,
+  0x1dd0,0x1dd1,0x1dd2,0x1dd3,0x1dd4,0x1dd5,0x1dd6,0x1dd7,
+  0x1dd8,0x1dd9,0x1dda,0x1ddb,0x1ddc,0x1ddd,0x1dde,0x1ddf,
+  0x1de0,0x1de1,0x1de2,0x1de3,0x1de4,0x1de5,0x1de6,0x1de7,
+  0x1de8,0x1de9,0x1dea,0x1deb,0x1dec,0x1ded,0x1dee,0x1def,
+  0x1df0,0x1df1,0x1df2,0x1df3,0x1df4,0x1df5,0x1df6,0x1df7,
+  0x1df8,0x1df9,0x1dfa,0x1dfb,0x1dfc,0x1dfd,0x1dfe,0x1dff,
+  0x1e00,0x1e00,0x1e02,0x1e02,0x1e04,0x1e04,0x1e06,0x1e06,
+  0x1e08,0x1e08,0x1e0a,0x1e0a,0x1e0c,0x1e0c,0x1e0e,0x1e0e,
+  0x1e10,0x1e10,0x1e12,0x1e12,0x1e14,0x1e14,0x1e16,0x1e16,
+  0x1e18,0x1e18,0x1e1a,0x1e1a,0x1e1c,0x1e1c,0x1e1e,0x1e1e,
+  0x1e20,0x1e20,0x1e22,0x1e22,0x1e24,0x1e24,0x1e26,0x1e26,
+  0x1e28,0x1e28,0x1e2a,0x1e2a,0x1e2c,0x1e2c,0x1e2e,0x1e2e,
+  0x1e30,0x1e30,0x1e32,0x1e32,0x1e34,0x1e34,0x1e36,0x1e36,
+  0x1e38,0x1e38,0x1e3a,0x1e3a,0x1e3c,0x1e3c,0x1e3e,0x1e3e,
+  0x1e40,0x1e40,0x1e42,0x1e42,0x1e44,0x1e44,0x1e46,0x1e46,
+  0x1e48,0x1e48,0x1e4a,0x1e4a,0x1e4c,0x1e4c,0x1e4e,0x1e4e,
+  0x1e50,0x1e50,0x1e52,0x1e52,0x1e54,0x1e54,0x1e56,0x1e56,
+  0x1e58,0x1e58,0x1e5a,0x1e5a,0x1e5c,0x1e5c,0x1e5e,0x1e5e,
+  0x1e60,0x1e60,0x1e62,0x1e62,0x1e64,0x1e64,0x1e66,0x1e66,
+  0x1e68,0x1e68,0x1e6a,0x1e6a,0x1e6c,0x1e6c,0x1e6e,0x1e6e,
+  0x1e70,0x1e70,0x1e72,0x1e72,0x1e74,0x1e74,0x1e76,0x1e76,
+  0x1e78,0x1e78,0x1e7a,0x1e7a,0x1e7c,0x1e7c,0x1e7e,0x1e7e,
+  0x1e80,0x1e80,0x1e82,0x1e82,0x1e84,0x1e84,0x1e86,0x1e86,
+  0x1e88,0x1e88,0x1e8a,0x1e8a,0x1e8c,0x1e8c,0x1e8e,0x1e8e,
+  0x1e90,0x1e90,0x1e92,0x1e92,0x1e94,0x1e94,0x1e96,0x1e97,
+  0x1e98,0x1e99,0x1e9a,0x1e60,0x1e9c,0x1e9d,0x1e9e,0x1e9f,
+  0x1ea0,0x1ea0,0x1ea2,0x1ea2,0x1ea4,0x1ea4,0x1ea6,0x1ea6,
+  0x1ea8,0x1ea8,0x1eaa,0x1eaa,0x1eac,0x1eac,0x1eae,0x1eae,
+  0x1eb0,0x1eb0,0x1eb2,0x1eb2,0x1eb4,0x1eb4,0x1eb6,0x1eb6,
+  0x1eb8,0x1eb8,0x1eba,0x1eba,0x1ebc,0x1ebc,0x1ebe,0x1ebe,
+  0x1ec0,0x1ec0,0x1ec2,0x1ec2,0x1ec4,0x1ec4,0x1ec6,0x1ec6,
+  0x1ec8,0x1ec8,0x1eca,0x1eca,0x1ecc,0x1ecc,0x1ece,0x1ece,
+  0x1ed0,0x1ed0,0x1ed2,0x1ed2,0x1ed4,0x1ed4,0x1ed6,0x1ed6,
+  0x1ed8,0x1ed8,0x1eda,0x1eda,0x1edc,0x1edc,0x1ede,0x1ede,
+  0x1ee0,0x1ee0,0x1ee2,0x1ee2,0x1ee4,0x1ee4,0x1ee6,0x1ee6,
+  0x1ee8,0x1ee8,0x1eea,0x1eea,0x1eec,0x1eec,0x1eee,0x1eee,
+  0x1ef0,0x1ef0,0x1ef2,0x1ef2,0x1ef4,0x1ef4,0x1ef6,0x1ef6,
+  0x1ef8,0x1ef8,0x1efa,0x1efb,0x1efc,0x1efd,0x1efe,0x1eff,
+  0x1f08,0x1f09,0x1f0a,0x1f0b,0x1f0c,0x1f0d,0x1f0e,0x1f0f,
+  0x1f08,0x1f09,0x1f0a,0x1f0b,0x1f0c,0x1f0d,0x1f0e,0x1f0f,
+  0x1f18,0x1f19,0x1f1a,0x1f1b,0x1f1c,0x1f1d,0x1f16,0x1f17,
+  0x1f18,0x1f19,0x1f1a,0x1f1b,0x1f1c,0x1f1d,0x1f1e,0x1f1f,
+  0x1f28,0x1f29,0x1f2a,0x1f2b,0x1f2c,0x1f2d,0x1f2e,0x1f2f,
+  0x1f28,0x1f29,0x1f2a,0x1f2b,0x1f2c,0x1f2d,0x1f2e,0x1f2f,
+  0x1f38,0x1f39,0x1f3a,0x1f3b,0x1f3c,0x1f3d,0x1f3e,0x1f3f,
+  0x1f38,0x1f39,0x1f3a,0x1f3b,0x1f3c,0x1f3d,0x1f3e,0x1f3f,
+  0x1f48,0x1f49,0x1f4a,0x1f4b,0x1f4c,0x1f4d,0x1f46,0x1f47,
+  0x1f48,0x1f49,0x1f4a,0x1f4b,0x1f4c,0x1f4d,0x1f4e,0x1f4f,
+  0x1f50,0x1f59,0x1f52,0x1f5b,0x1f54,0x1f5d,0x1f56,0x1f5f,
+  0x1f58,0x1f59,0x1f5a,0x1f5b,0x1f5c,0x1f5d,0x1f5e,0x1f5f,
+  0x1f68,0x1f69,0x1f6a,0x1f6b,0x1f6c,0x1f6d,0x1f6e,0x1f6f,
+  0x1f68,0x1f69,0x1f6a,0x1f6b,0x1f6c,0x1f6d,0x1f6e,0x1f6f,
+  0x1fba,0x1fbb,0x1fc8,0x1fc9,0x1fca,0x1fcb,0x1fda,0x1fdb,
+  0x1ff8,0x1ff9,0x1fea,0x1feb,0x1ffa,0x1ffb,0x1f7e,0x1f7f,
+  0x1f88,0x1f89,0x1f8a,0x1f8b,0x1f8c,0x1f8d,0x1f8e,0x1f8f,
+  0x1f88,0x1f89,0x1f8a,0x1f8b,0x1f8c,0x1f8d,0x1f8e,0x1f8f,
+  0x1f98,0x1f99,0x1f9a,0x1f9b,0x1f9c,0x1f9d,0x1f9e,0x1f9f,
+  0x1f98,0x1f99,0x1f9a,0x1f9b,0x1f9c,0x1f9d,0x1f9e,0x1f9f,
+  0x1fa8,0x1fa9,0x1faa,0x1fab,0x1fac,0x1fad,0x1fae,0x1faf,
+  0x1fa8,0x1fa9,0x1faa,0x1fab,0x1fac,0x1fad,0x1fae,0x1faf,
+  0x1fb8,0x1fb9,0x1fb2,0x1fbc,0x1fb4,0x1fb5,0x1fb6,0x1fb7,
+  0x1fb8,0x1fb9,0x1fba,0x1fbb,0x1fbc,0x1fbd,0x0399,0x1fbf,
+  0x1fc0,0x1fc1,0x1fc2,0x1fcc,0x1fc4,0x1fc5,0x1fc6,0x1fc7,
+  0x1fc8,0x1fc9,0x1fca,0x1fcb,0x1fcc,0x1fcd,0x1fce,0x1fcf,
+  0x1fd8,0x1fd9,0x1fd2,0x1fd3,0x1fd4,0x1fd5,0x1fd6,0x1fd7,
+  0x1fd8,0x1fd9,0x1fda,0x1fdb,0x1fdc,0x1fdd,0x1fde,0x1fdf,
+  0x1fe8,0x1fe9,0x1fe2,0x1fe3,0x1fe4,0x1fec,0x1fe6,0x1fe7,
+  0x1fe8,0x1fe9,0x1fea,0x1feb,0x1fec,0x1fed,0x1fee,0x1fef,
+  0x1ff0,0x1ff1,0x1ff2,0x1ffc,0x1ff4,0x1ff5,0x1ff6,0x1ff7,
+  0x1ff8,0x1ff9,0x1ffa,0x1ffb,0x1ffc,0x1ffd,0x1ffe,0x1fff,
+  0x2000,0x2001,0x2002,0x2003,0x2004,0x2005,0x2006,0x2007,
+  0x2008,0x2009,0x200a,0x200b,0x200c,0x200d,0x200e,0x200f,
+  0x2010,0x2011,0x2012,0x2013,0x2014,0x2015,0x2016,0x2017,
+  0x2018,0x2019,0x201a,0x201b,0x201c,0x201d,0x201e,0x201f,
+  0x2020,0x2021,0x2022,0x2023,0x2024,0x2025,0x2026,0x2027,
+  0x2028,0x2029,0x202a,0x202b,0x202c,0x202d,0x202e,0x202f,
+  0x2030,0x2031,0x2032,0x2033,0x2034,0x2035,0x2036,0x2037,
+  0x2038,0x2039,0x203a,0x203b,0x203c,0x203d,0x203e,0x203f,
+  0x2040,0x2041,0x2042,0x2043,0x2044,0x2045,0x2046,0x2047,
+  0x2048,0x2049,0x204a,0x204b,0x204c,0x204d,0x204e,0x204f,
+  0x2050,0x2051,0x2052,0x2053,0x2054,0x2055,0x2056,0x2057,
+  0x2058,0x2059,0x205a,0x205b,0x205c,0x205d,0x205e,0x205f,
+  0x2060,0x2061,0x2062,0x2063,0x2064,0x2065,0x2066,0x2067,
+  0x2068,0x2069,0x206a,0x206b,0x206c,0x206d,0x206e,0x206f,
+  0x2070,0x2071,0x2072,0x2073,0x2074,0x2075,0x2076,0x2077,
+  0x2078,0x2079,0x207a,0x207b,0x207c,0x207d,0x207e,0x207f,
+  0x2080,0x2081,0x2082,0x2083,0x2084,0x2085,0x2086,0x2087,
+  0x2088,0x2089,0x208a,0x208b,0x208c,0x208d,0x208e,0x208f,
+  0x2090,0x2091,0x2092,0x2093,0x2094,0x2095,0x2096,0x2097,
+  0x2098,0x2099,0x209a,0x209b,0x209c,0x209d,0x209e,0x209f,
+  0x20a0,0x20a1,0x20a2,0x20a3,0x20a4,0x20a5,0x20a6,0x20a7,
+  0x20a8,0x20a9,0x20aa,0x20ab,0x20ac,0x20ad,0x20ae,0x20af,
+  0x20b0,0x20b1,0x20b2,0x20b3,0x20b4,0x20b5,0x20b6,0x20b7,
+  0x20b8,0x20b9,0x20ba,0x20bb,0x20bc,0x20bd,0x20be,0x20bf,
+  0x20c0,0x20c1,0x20c2,0x20c3,0x20c4,0x20c5,0x20c6,0x20c7,
+  0x20c8,0x20c9,0x20ca,0x20cb,0x20cc,0x20cd,0x20ce,0x20cf,
+  0x20d0,0x20d1,0x20d2,0x20d3,0x20d4,0x20d5,0x20d6,0x20d7,
+  0x20d8,0x20d9,0x20da,0x20db,0x20dc,0x20dd,0x20de,0x20df,
+  0x20e0,0x20e1,0x20e2,0x20e3,0x20e4,0x20e5,0x20e6,0x20e7,
+  0x20e8,0x20e9,0x20ea,0x20eb,0x20ec,0x20ed,0x20ee,0x20ef,
+  0x20f0,0x20f1,0x20f2,0x20f3,0x20f4,0x20f5,0x20f6,0x20f7,
+  0x20f8,0x20f9,0x20fa,0x20fb,0x20fc,0x20fd,0x20fe,0x20ff,
+  0x2100,0x2101,0x2102,0x2103,0x2104,0x2105,0x2106,0x2107,
+  0x2108,0x2109,0x210a,0x210b,0x210c,0x210d,0x210e,0x210f,
+  0x2110,0x2111,0x2112,0x2113,0x2114,0x2115,0x2116,0x2117,
+  0x2118,0x2119,0x211a,0x211b,0x211c,0x211d,0x211e,0x211f,
+  0x2120,0x2121,0x2122,0x2123,0x2124,0x2125,0x2126,0x2127,
+  0x2128,0x2129,0x212a,0x212b,0x212c,0x212d,0x212e,0x212f,
+  0x2130,0x2131,0x2132,0x2133,0x2134,0x2135,0x2136,0x2137,
+  0x2138,0x2139,0x213a,0x213b,0x213c,0x213d,0x213e,0x213f,
+  0x2140,0x2141,0x2142,0x2143,0x2144,0x2145,0x2146,0x2147,
+  0x2148,0x2149,0x214a,0x214b,0x214c,0x214d,0x2132,0x214f,
+  0x2150,0x2151,0x2152,0x2153,0x2154,0x2155,0x2156,0x2157,
+  0x2158,0x2159,0x215a,0x215b,0x215c,0x215d,0x215e,0x215f,
+  0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,
+  0x2168,0x2169,0x216a,0x216b,0x216c,0x216d,0x216e,0x216f,
+  0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,
+  0x2168,0x2169,0x216a,0x216b,0x216c,0x216d,0x216e,0x216f,
+  0x2180,0x2181,0x2182,0x2183,0x2183,0x2185,0x2186,0x2187,
+  0x2188,0x2189,0x218a,0x218b,0x218c,0x218d,0x218e,0x218f,
+  0x2190,0x2191,0x2192,0x2193,0x2194,0x2195,0x2196,0x2197,
+  0x2198,0x2199,0x219a,0x219b,0x219c,0x219d,0x219e,0x219f,
+  0x21a0,0x21a1,0x21a2,0x21a3,0x21a4,0x21a5,0x21a6,0x21a7,
+  0x21a8,0x21a9,0x21aa,0x21ab,0x21ac,0x21ad,0x21ae,0x21af,
+  0x21b0,0x21b1,0x21b2,0x21b3,0x21b4,0x21b5,0x21b6,0x21b7,
+  0x21b8,0x21b9,0x21ba,0x21bb,0x21bc,0x21bd,0x21be,0x21bf,
+  0x21c0,0x21c1,0x21c2,0x21c3,0x21c4,0x21c5,0x21c6,0x21c7,
+  0x21c8,0x21c9,0x21ca,0x21cb,0x21cc,0x21cd,0x21ce,0x21cf,
+  0x21d0,0x21d1,0x21d2,0x21d3,0x21d4,0x21d5,0x21d6,0x21d7,
+  0x21d8,0x21d9,0x21da,0x21db,0x21dc,0x21dd,0x21de,0x21df,
+  0x21e0,0x21e1,0x21e2,0x21e3,0x21e4,0x21e5,0x21e6,0x21e7,
+  0x21e8,0x21e9,0x21ea,0x21eb,0x21ec,0x21ed,0x21ee,0x21ef,
+  0x21f0,0x21f1,0x21f2,0x21f3,0x21f4,0x21f5,0x21f6,0x21f7,
+  0x21f8,0x21f9,0x21fa,0x21fb,0x21fc,0x21fd,0x21fe,0x21ff,
+  0x2200,0x2201,0x2202,0x2203,0x2204,0x2205,0x2206,0x2207,
+  0x2208,0x2209,0x220a,0x220b,0x220c,0x220d,0x220e,0x220f,
+  0x2210,0x2211,0x2212,0x2213,0x2214,0x2215,0x2216,0x2217,
+  0x2218,0x2219,0x221a,0x221b,0x221c,0x221d,0x221e,0x221f,
+  0x2220,0x2221,0x2222,0x2223,0x2224,0x2225,0x2226,0x2227,
+  0x2228,0x2229,0x222a,0x222b,0x222c,0x222d,0x222e,0x222f,
+  0x2230,0x2231,0x2232,0x2233,0x2234,0x2235,0x2236,0x2237,
+  0x2238,0x2239,0x223a,0x223b,0x223c,0x223d,0x223e,0x223f,
+  0x2240,0x2241,0x2242,0x2243,0x2244,0x2245,0x2246,0x2247,
+  0x2248,0x2249,0x224a,0x224b,0x224c,0x224d,0x224e,0x224f,
+  0x2250,0x2251,0x2252,0x2253,0x2254,0x2255,0x2256,0x2257,
+  0x2258,0x2259,0x225a,0x225b,0x225c,0x225d,0x225e,0x225f,
+  0x2260,0x2261,0x2262,0x2263,0x2264,0x2265,0x2266,0x2267,
+  0x2268,0x2269,0x226a,0x226b,0x226c,0x226d,0x226e,0x226f,
+  0x2270,0x2271,0x2272,0x2273,0x2274,0x2275,0x2276,0x2277,
+  0x2278,0x2279,0x227a,0x227b,0x227c,0x227d,0x227e,0x227f,
+  0x2280,0x2281,0x2282,0x2283,0x2284,0x2285,0x2286,0x2287,
+  0x2288,0x2289,0x228a,0x228b,0x228c,0x228d,0x228e,0x228f,
+  0x2290,0x2291,0x2292,0x2293,0x2294,0x2295,0x2296,0x2297,
+  0x2298,0x2299,0x229a,0x229b,0x229c,0x229d,0x229e,0x229f,
+  0x22a0,0x22a1,0x22a2,0x22a3,0x22a4,0x22a5,0x22a6,0x22a7,
+  0x22a8,0x22a9,0x22aa,0x22ab,0x22ac,0x22ad,0x22ae,0x22af,
+  0x22b0,0x22b1,0x22b2,0x22b3,0x22b4,0x22b5,0x22b6,0x22b7,
+  0x22b8,0x22b9,0x22ba,0x22bb,0x22bc,0x22bd,0x22be,0x22bf,
+  0x22c0,0x22c1,0x22c2,0x22c3,0x22c4,0x22c5,0x22c6,0x22c7,
+  0x22c8,0x22c9,0x22ca,0x22cb,0x22cc,0x22cd,0x22ce,0x22cf,
+  0x22d0,0x22d1,0x22d2,0x22d3,0x22d4,0x22d5,0x22d6,0x22d7,
+  0x22d8,0x22d9,0x22da,0x22db,0x22dc,0x22dd,0x22de,0x22df,
+  0x22e0,0x22e1,0x22e2,0x22e3,0x22e4,0x22e5,0x22e6,0x22e7,
+  0x22e8,0x22e9,0x22ea,0x22eb,0x22ec,0x22ed,0x22ee,0x22ef,
+  0x22f0,0x22f1,0x22f2,0x22f3,0x22f4,0x22f5,0x22f6,0x22f7,
+  0x22f8,0x22f9,0x22fa,0x22fb,0x22fc,0x22fd,0x22fe,0x22ff,
+  0x2300,0x2301,0x2302,0x2303,0x2304,0x2305,0x2306,0x2307,
+  0x2308,0x2309,0x230a,0x230b,0x230c,0x230d,0x230e,0x230f,
+  0x2310,0x2311,0x2312,0x2313,0x2314,0x2315,0x2316,0x2317,
+  0x2318,0x2319,0x231a,0x231b,0x231c,0x231d,0x231e,0x231f,
+  0x2320,0x2321,0x2322,0x2323,0x2324,0x2325,0x2326,0x2327,
+  0x2328,0x2329,0x232a,0x232b,0x232c,0x232d,0x232e,0x232f,
+  0x2330,0x2331,0x2332,0x2333,0x2334,0x2335,0x2336,0x2337,
+  0x2338,0x2339,0x233a,0x233b,0x233c,0x233d,0x233e,0x233f,
+  0x2340,0x2341,0x2342,0x2343,0x2344,0x2345,0x2346,0x2347,
+  0x2348,0x2349,0x234a,0x234b,0x234c,0x234d,0x234e,0x234f,
+  0x2350,0x2351,0x2352,0x2353,0x2354,0x2355,0x2356,0x2357,
+  0x2358,0x2359,0x235a,0x235b,0x235c,0x235d,0x235e,0x235f,
+  0x2360,0x2361,0x2362,0x2363,0x2364,0x2365,0x2366,0x2367,
+  0x2368,0x2369,0x236a,0x236b,0x236c,0x236d,0x236e,0x236f,
+  0x2370,0x2371,0x2372,0x2373,0x2374,0x2375,0x2376,0x2377,
+  0x2378,0x2379,0x237a,0x237b,0x237c,0x237d,0x237e,0x237f,
+  0x2380,0x2381,0x2382,0x2383,0x2384,0x2385,0x2386,0x2387,
+  0x2388,0x2389,0x238a,0x238b,0x238c,0x238d,0x238e,0x238f,
+  0x2390,0x2391,0x2392,0x2393,0x2394,0x2395,0x2396,0x2397,
+  0x2398,0x2399,0x239a,0x239b,0x239c,0x239d,0x239e,0x239f,
+  0x23a0,0x23a1,0x23a2,0x23a3,0x23a4,0x23a5,0x23a6,0x23a7,
+  0x23a8,0x23a9,0x23aa,0x23ab,0x23ac,0x23ad,0x23ae,0x23af,
+  0x23b0,0x23b1,0x23b2,0x23b3,0x23b4,0x23b5,0x23b6,0x23b7,
+  0x23b8,0x23b9,0x23ba,0x23bb,0x23bc,0x23bd,0x23be,0x23bf,
+  0x23c0,0x23c1,0x23c2,0x23c3,0x23c4,0x23c5,0x23c6,0x23c7,
+  0x23c8,0x23c9,0x23ca,0x23cb,0x23cc,0x23cd,0x23ce,0x23cf,
+  0x23d0,0x23d1,0x23d2,0x23d3,0x23d4,0x23d5,0x23d6,0x23d7,
+  0x23d8,0x23d9,0x23da,0x23db,0x23dc,0x23dd,0x23de,0x23df,
+  0x23e0,0x23e1,0x23e2,0x23e3,0x23e4,0x23e5,0x23e6,0x23e7,
+  0x23e8,0x23e9,0x23ea,0x23eb,0x23ec,0x23ed,0x23ee,0x23ef,
+  0x23f0,0x23f1,0x23f2,0x23f3,0x23f4,0x23f5,0x23f6,0x23f7,
+  0x23f8,0x23f9,0x23fa,0x23fb,0x23fc,0x23fd,0x23fe,0x23ff,
+  0x2400,0x2401,0x2402,0x2403,0x2404,0x2405,0x2406,0x2407,
+  0x2408,0x2409,0x240a,0x240b,0x240c,0x240d,0x240e,0x240f,
+  0x2410,0x2411,0x2412,0x2413,0x2414,0x2415,0x2416,0x2417,
+  0x2418,0x2419,0x241a,0x241b,0x241c,0x241d,0x241e,0x241f,
+  0x2420,0x2421,0x2422,0x2423,0x2424,0x2425,0x2426,0x2427,
+  0x2428,0x2429,0x242a,0x242b,0x242c,0x242d,0x242e,0x242f,
+  0x2430,0x2431,0x2432,0x2433,0x2434,0x2435,0x2436,0x2437,
+  0x2438,0x2439,0x243a,0x243b,0x243c,0x243d,0x243e,0x243f,
+  0x2440,0x2441,0x2442,0x2443,0x2444,0x2445,0x2446,0x2447,
+  0x2448,0x2449,0x244a,0x244b,0x244c,0x244d,0x244e,0x244f,
+  0x2450,0x2451,0x2452,0x2453,0x2454,0x2455,0x2456,0x2457,
+  0x2458,0x2459,0x245a,0x245b,0x245c,0x245d,0x245e,0x245f,
+  0x2460,0x2461,0x2462,0x2463,0x2464,0x2465,0x2466,0x2467,
+  0x2468,0x2469,0x246a,0x246b,0x246c,0x246d,0x246e,0x246f,
+  0x2470,0x2471,0x2472,0x2473,0x2474,0x2475,0x2476,0x2477,
+  0x2478,0x2479,0x247a,0x247b,0x247c,0x247d,0x247e,0x247f,
+  0x2480,0x2481,0x2482,0x2483,0x2484,0x2485,0x2486,0x2487,
+  0x2488,0x2489,0x248a,0x248b,0x248c,0x248d,0x248e,0x248f,
+  0x2490,0x2491,0x2492,0x2493,0x2494,0x2495,0x2496,0x2497,
+  0x2498,0x2499,0x249a,0x249b,0x249c,0x249d,0x249e,0x249f,
+  0x24a0,0x24a1,0x24a2,0x24a3,0x24a4,0x24a5,0x24a6,0x24a7,
+  0x24a8,0x24a9,0x24aa,0x24ab,0x24ac,0x24ad,0x24ae,0x24af,
+  0x24b0,0x24b1,0x24b2,0x24b3,0x24b4,0x24b5,0x24b6,0x24b7,
+  0x24b8,0x24b9,0x24ba,0x24bb,0x24bc,0x24bd,0x24be,0x24bf,
+  0x24c0,0x24c1,0x24c2,0x24c3,0x24c4,0x24c5,0x24c6,0x24c7,
+  0x24c8,0x24c9,0x24ca,0x24cb,0x24cc,0x24cd,0x24ce,0x24cf,
+  0x24b6,0x24b7,0x24b8,0x24b9,0x24ba,0x24bb,0x24bc,0x24bd,
+  0x24be,0x24bf,0x24c0,0x24c1,0x24c2,0x24c3,0x24c4,0x24c5,
+  0x24c6,0x24c7,0x24c8,0x24c9,0x24ca,0x24cb,0x24cc,0x24cd,
+  0x24ce,0x24cf,0x24ea,0x24eb,0x24ec,0x24ed,0x24ee,0x24ef,
+  0x24f0,0x24f1,0x24f2,0x24f3,0x24f4,0x24f5,0x24f6,0x24f7,
+  0x24f8,0x24f9,0x24fa,0x24fb,0x24fc,0x24fd,0x24fe,0x24ff,
+  0x2500,0x2501,0x2502,0x2503,0x2504,0x2505,0x2506,0x2507,
+  0x2508,0x2509,0x250a,0x250b,0x250c,0x250d,0x250e,0x250f,
+  0x2510,0x2511,0x2512,0x2513,0x2514,0x2515,0x2516,0x2517,
+  0x2518,0x2519,0x251a,0x251b,0x251c,0x251d,0x251e,0x251f,
+  0x2520,0x2521,0x2522,0x2523,0x2524,0x2525,0x2526,0x2527,
+  0x2528,0x2529,0x252a,0x252b,0x252c,0x252d,0x252e,0x252f,
+  0x2530,0x2531,0x2532,0x2533,0x2534,0x2535,0x2536,0x2537,
+  0x2538,0x2539,0x253a,0x253b,0x253c,0x253d,0x253e,0x253f,
+  0x2540,0x2541,0x2542,0x2543,0x2544,0x2545,0x2546,0x2547,
+  0x2548,0x2549,0x254a,0x254b,0x254c,0x254d,0x254e,0x254f,
+  0x2550,0x2551,0x2552,0x2553,0x2554,0x2555,0x2556,0x2557,
+  0x2558,0x2559,0x255a,0x255b,0x255c,0x255d,0x255e,0x255f,
+  0x2560,0x2561,0x2562,0x2563,0x2564,0x2565,0x2566,0x2567,
+  0x2568,0x2569,0x256a,0x256b,0x256c,0x256d,0x256e,0x256f,
+  0x2570,0x2571,0x2572,0x2573,0x2574,0x2575,0x2576,0x2577,
+  0x2578,0x2579,0x257a,0x257b,0x257c,0x257d,0x257e,0x257f,
+  0x2580,0x2581,0x2582,0x2583,0x2584,0x2585,0x2586,0x2587,
+  0x2588,0x2589,0x258a,0x258b,0x258c,0x258d,0x258e,0x258f,
+  0x2590,0x2591,0x2592,0x2593,0x2594,0x2595,0x2596,0x2597,
+  0x2598,0x2599,0x259a,0x259b,0x259c,0x259d,0x259e,0x259f,
+  0x25a0,0x25a1,0x25a2,0x25a3,0x25a4,0x25a5,0x25a6,0x25a7,
+  0x25a8,0x25a9,0x25aa,0x25ab,0x25ac,0x25ad,0x25ae,0x25af,
+  0x25b0,0x25b1,0x25b2,0x25b3,0x25b4,0x25b5,0x25b6,0x25b7,
+  0x25b8,0x25b9,0x25ba,0x25bb,0x25bc,0x25bd,0x25be,0x25bf,
+  0x25c0,0x25c1,0x25c2,0x25c3,0x25c4,0x25c5,0x25c6,0x25c7,
+  0x25c8,0x25c9,0x25ca,0x25cb,0x25cc,0x25cd,0x25ce,0x25cf,
+  0x25d0,0x25d1,0x25d2,0x25d3,0x25d4,0x25d5,0x25d6,0x25d7,
+  0x25d8,0x25d9,0x25da,0x25db,0x25dc,0x25dd,0x25de,0x25df,
+  0x25e0,0x25e1,0x25e2,0x25e3,0x25e4,0x25e5,0x25e6,0x25e7,
+  0x25e8,0x25e9,0x25ea,0x25eb,0x25ec,0x25ed,0x25ee,0x25ef,
+  0x25f0,0x25f1,0x25f2,0x25f3,0x25f4,0x25f5,0x25f6,0x25f7,
+  0x25f8,0x25f9,0x25fa,0x25fb,0x25fc,0x25fd,0x25fe,0x25ff,
+  0x2600,0x2601,0x2602,0x2603,0x2604,0x2605,0x2606,0x2607,
+  0x2608,0x2609,0x260a,0x260b,0x260c,0x260d,0x260e,0x260f,
+  0x2610,0x2611,0x2612,0x2613,0x2614,0x2615,0x2616,0x2617,
+  0x2618,0x2619,0x261a,0x261b,0x261c,0x261d,0x261e,0x261f,
+  0x2620,0x2621,0x2622,0x2623,0x2624,0x2625,0x2626,0x2627,
+  0x2628,0x2629,0x262a,0x262b,0x262c,0x262d,0x262e,0x262f,
+  0x2630,0x2631,0x2632,0x2633,0x2634,0x2635,0x2636,0x2637,
+  0x2638,0x2639,0x263a,0x263b,0x263c,0x263d,0x263e,0x263f,
+  0x2640,0x2641,0x2642,0x2643,0x2644,0x2645,0x2646,0x2647,
+  0x2648,0x2649,0x264a,0x264b,0x264c,0x264d,0x264e,0x264f,
+  0x2650,0x2651,0x2652,0x2653,0x2654,0x2655,0x2656,0x2657,
+  0x2658,0x2659,0x265a,0x265b,0x265c,0x265d,0x265e,0x265f,
+  0x2660,0x2661,0x2662,0x2663,0x2664,0x2665,0x2666,0x2667,
+  0x2668,0x2669,0x266a,0x266b,0x266c,0x266d,0x266e,0x266f,
+  0x2670,0x2671,0x2672,0x2673,0x2674,0x2675,0x2676,0x2677,
+  0x2678,0x2679,0x267a,0x267b,0x267c,0x267d,0x267e,0x267f,
+  0x2680,0x2681,0x2682,0x2683,0x2684,0x2685,0x2686,0x2687,
+  0x2688,0x2689,0x268a,0x268b,0x268c,0x268d,0x268e,0x268f,
+  0x2690,0x2691,0x2692,0x2693,0x2694,0x2695,0x2696,0x2697,
+  0x2698,0x2699,0x269a,0x269b,0x269c,0x269d,0x269e,0x269f,
+  0x26a0,0x26a1,0x26a2,0x26a3,0x26a4,0x26a5,0x26a6,0x26a7,
+  0x26a8,0x26a9,0x26aa,0x26ab,0x26ac,0x26ad,0x26ae,0x26af,
+  0x26b0,0x26b1,0x26b2,0x26b3,0x26b4,0x26b5,0x26b6,0x26b7,
+  0x26b8,0x26b9,0x26ba,0x26bb,0x26bc,0x26bd,0x26be,0x26bf,
+  0x26c0,0x26c1,0x26c2,0x26c3,0x26c4,0x26c5,0x26c6,0x26c7,
+  0x26c8,0x26c9,0x26ca,0x26cb,0x26cc,0x26cd,0x26ce,0x26cf,
+  0x26d0,0x26d1,0x26d2,0x26d3,0x26d4,0x26d5,0x26d6,0x26d7,
+  0x26d8,0x26d9,0x26da,0x26db,0x26dc,0x26dd,0x26de,0x26df,
+  0x26e0,0x26e1,0x26e2,0x26e3,0x26e4,0x26e5,0x26e6,0x26e7,
+  0x26e8,0x26e9,0x26ea,0x26eb,0x26ec,0x26ed,0x26ee,0x26ef,
+  0x26f0,0x26f1,0x26f2,0x26f3,0x26f4,0x26f5,0x26f6,0x26f7,
+  0x26f8,0x26f9,0x26fa,0x26fb,0x26fc,0x26fd,0x26fe,0x26ff,
+  0x2700,0x2701,0x2702,0x2703,0x2704,0x2705,0x2706,0x2707,
+  0x2708,0x2709,0x270a,0x270b,0x270c,0x270d,0x270e,0x270f,
+  0x2710,0x2711,0x2712,0x2713,0x2714,0x2715,0x2716,0x2717,
+  0x2718,0x2719,0x271a,0x271b,0x271c,0x271d,0x271e,0x271f,
+  0x2720,0x2721,0x2722,0x2723,0x2724,0x2725,0x2726,0x2727,
+  0x2728,0x2729,0x272a,0x272b,0x272c,0x272d,0x272e,0x272f,
+  0x2730,0x2731,0x2732,0x2733,0x2734,0x2735,0x2736,0x2737,
+  0x2738,0x2739,0x273a,0x273b,0x273c,0x273d,0x273e,0x273f,
+  0x2740,0x2741,0x2742,0x2743,0x2744,0x2745,0x2746,0x2747,
+  0x2748,0x2749,0x274a,0x274b,0x274c,0x274d,0x274e,0x274f,
+  0x2750,0x2751,0x2752,0x2753,0x2754,0x2755,0x2756,0x2757,
+  0x2758,0x2759,0x275a,0x275b,0x275c,0x275d,0x275e,0x275f,
+  0x2760,0x2761,0x2762,0x2763,0x2764,0x2765,0x2766,0x2767,
+  0x2768,0x2769,0x276a,0x276b,0x276c,0x276d,0x276e,0x276f,
+  0x2770,0x2771,0x2772,0x2773,0x2774,0x2775,0x2776,0x2777,
+  0x2778,0x2779,0x277a,0x277b,0x277c,0x277d,0x277e,0x277f,
+  0x2780,0x2781,0x2782,0x2783,0x2784,0x2785,0x2786,0x2787,
+  0x2788,0x2789,0x278a,0x278b,0x278c,0x278d,0x278e,0x278f,
+  0x2790,0x2791,0x2792,0x2793,0x2794,0x2795,0x2796,0x2797,
+  0x2798,0x2799,0x279a,0x279b,0x279c,0x279d,0x279e,0x279f,
+  0x27a0,0x27a1,0x27a2,0x27a3,0x27a4,0x27a5,0x27a6,0x27a7,
+  0x27a8,0x27a9,0x27aa,0x27ab,0x27ac,0x27ad,0x27ae,0x27af,
+  0x27b0,0x27b1,0x27b2,0x27b3,0x27b4,0x27b5,0x27b6,0x27b7,
+  0x27b8,0x27b9,0x27ba,0x27bb,0x27bc,0x27bd,0x27be,0x27bf,
+  0x27c0,0x27c1,0x27c2,0x27c3,0x27c4,0x27c5,0x27c6,0x27c7,
+  0x27c8,0x27c9,0x27ca,0x27cb,0x27cc,0x27cd,0x27ce,0x27cf,
+  0x27d0,0x27d1,0x27d2,0x27d3,0x27d4,0x27d5,0x27d6,0x27d7,
+  0x27d8,0x27d9,0x27da,0x27db,0x27dc,0x27dd,0x27de,0x27df,
+  0x27e0,0x27e1,0x27e2,0x27e3,0x27e4,0x27e5,0x27e6,0x27e7,
+  0x27e8,0x27e9,0x27ea,0x27eb,0x27ec,0x27ed,0x27ee,0x27ef,
+  0x27f0,0x27f1,0x27f2,0x27f3,0x27f4,0x27f5,0x27f6,0x27f7,
+  0x27f8,0x27f9,0x27fa,0x27fb,0x27fc,0x27fd,0x27fe,0x27ff,
+  0x2800,0x2801,0x2802,0x2803,0x2804,0x2805,0x2806,0x2807,
+  0x2808,0x2809,0x280a,0x280b,0x280c,0x280d,0x280e,0x280f,
+  0x2810,0x2811,0x2812,0x2813,0x2814,0x2815,0x2816,0x2817,
+  0x2818,0x2819,0x281a,0x281b,0x281c,0x281d,0x281e,0x281f,
+  0x2820,0x2821,0x2822,0x2823,0x2824,0x2825,0x2826,0x2827,
+  0x2828,0x2829,0x282a,0x282b,0x282c,0x282d,0x282e,0x282f,
+  0x2830,0x2831,0x2832,0x2833,0x2834,0x2835,0x2836,0x2837,
+  0x2838,0x2839,0x283a,0x283b,0x283c,0x283d,0x283e,0x283f,
+  0x2840,0x2841,0x2842,0x2843,0x2844,0x2845,0x2846,0x2847,
+  0x2848,0x2849,0x284a,0x284b,0x284c,0x284d,0x284e,0x284f,
+  0x2850,0x2851,0x2852,0x2853,0x2854,0x2855,0x2856,0x2857,
+  0x2858,0x2859,0x285a,0x285b,0x285c,0x285d,0x285e,0x285f,
+  0x2860,0x2861,0x2862,0x2863,0x2864,0x2865,0x2866,0x2867,
+  0x2868,0x2869,0x286a,0x286b,0x286c,0x286d,0x286e,0x286f,
+  0x2870,0x2871,0x2872,0x2873,0x2874,0x2875,0x2876,0x2877,
+  0x2878,0x2879,0x287a,0x287b,0x287c,0x287d,0x287e,0x287f,
+  0x2880,0x2881,0x2882,0x2883,0x2884,0x2885,0x2886,0x2887,
+  0x2888,0x2889,0x288a,0x288b,0x288c,0x288d,0x288e,0x288f,
+  0x2890,0x2891,0x2892,0x2893,0x2894,0x2895,0x2896,0x2897,
+  0x2898,0x2899,0x289a,0x289b,0x289c,0x289d,0x289e,0x289f,
+  0x28a0,0x28a1,0x28a2,0x28a3,0x28a4,0x28a5,0x28a6,0x28a7,
+  0x28a8,0x28a9,0x28aa,0x28ab,0x28ac,0x28ad,0x28ae,0x28af,
+  0x28b0,0x28b1,0x28b2,0x28b3,0x28b4,0x28b5,0x28b6,0x28b7,
+  0x28b8,0x28b9,0x28ba,0x28bb,0x28bc,0x28bd,0x28be,0x28bf,
+  0x28c0,0x28c1,0x28c2,0x28c3,0x28c4,0x28c5,0x28c6,0x28c7,
+  0x28c8,0x28c9,0x28ca,0x28cb,0x28cc,0x28cd,0x28ce,0x28cf,
+  0x28d0,0x28d1,0x28d2,0x28d3,0x28d4,0x28d5,0x28d6,0x28d7,
+  0x28d8,0x28d9,0x28da,0x28db,0x28dc,0x28dd,0x28de,0x28df,
+  0x28e0,0x28e1,0x28e2,0x28e3,0x28e4,0x28e5,0x28e6,0x28e7,
+  0x28e8,0x28e9,0x28ea,0x28eb,0x28ec,0x28ed,0x28ee,0x28ef,
+  0x28f0,0x28f1,0x28f2,0x28f3,0x28f4,0x28f5,0x28f6,0x28f7,
+  0x28f8,0x28f9,0x28fa,0x28fb,0x28fc,0x28fd,0x28fe,0x28ff,
+  0x2900,0x2901,0x2902,0x2903,0x2904,0x2905,0x2906,0x2907,
+  0x2908,0x2909,0x290a,0x290b,0x290c,0x290d,0x290e,0x290f,
+  0x2910,0x2911,0x2912,0x2913,0x2914,0x2915,0x2916,0x2917,
+  0x2918,0x2919,0x291a,0x291b,0x291c,0x291d,0x291e,0x291f,
+  0x2920,0x2921,0x2922,0x2923,0x2924,0x2925,0x2926,0x2927,
+  0x2928,0x2929,0x292a,0x292b,0x292c,0x292d,0x292e,0x292f,
+  0x2930,0x2931,0x2932,0x2933,0x2934,0x2935,0x2936,0x2937,
+  0x2938,0x2939,0x293a,0x293b,0x293c,0x293d,0x293e,0x293f,
+  0x2940,0x2941,0x2942,0x2943,0x2944,0x2945,0x2946,0x2947,
+  0x2948,0x2949,0x294a,0x294b,0x294c,0x294d,0x294e,0x294f,
+  0x2950,0x2951,0x2952,0x2953,0x2954,0x2955,0x2956,0x2957,
+  0x2958,0x2959,0x295a,0x295b,0x295c,0x295d,0x295e,0x295f,
+  0x2960,0x2961,0x2962,0x2963,0x2964,0x2965,0x2966,0x2967,
+  0x2968,0x2969,0x296a,0x296b,0x296c,0x296d,0x296e,0x296f,
+  0x2970,0x2971,0x2972,0x2973,0x2974,0x2975,0x2976,0x2977,
+  0x2978,0x2979,0x297a,0x297b,0x297c,0x297d,0x297e,0x297f,
+  0x2980,0x2981,0x2982,0x2983,0x2984,0x2985,0x2986,0x2987,
+  0x2988,0x2989,0x298a,0x298b,0x298c,0x298d,0x298e,0x298f,
+  0x2990,0x2991,0x2992,0x2993,0x2994,0x2995,0x2996,0x2997,
+  0x2998,0x2999,0x299a,0x299b,0x299c,0x299d,0x299e,0x299f,
+  0x29a0,0x29a1,0x29a2,0x29a3,0x29a4,0x29a5,0x29a6,0x29a7,
+  0x29a8,0x29a9,0x29aa,0x29ab,0x29ac,0x29ad,0x29ae,0x29af,
+  0x29b0,0x29b1,0x29b2,0x29b3,0x29b4,0x29b5,0x29b6,0x29b7,
+  0x29b8,0x29b9,0x29ba,0x29bb,0x29bc,0x29bd,0x29be,0x29bf,
+  0x29c0,0x29c1,0x29c2,0x29c3,0x29c4,0x29c5,0x29c6,0x29c7,
+  0x29c8,0x29c9,0x29ca,0x29cb,0x29cc,0x29cd,0x29ce,0x29cf,
+  0x29d0,0x29d1,0x29d2,0x29d3,0x29d4,0x29d5,0x29d6,0x29d7,
+  0x29d8,0x29d9,0x29da,0x29db,0x29dc,0x29dd,0x29de,0x29df,
+  0x29e0,0x29e1,0x29e2,0x29e3,0x29e4,0x29e5,0x29e6,0x29e7,
+  0x29e8,0x29e9,0x29ea,0x29eb,0x29ec,0x29ed,0x29ee,0x29ef,
+  0x29f0,0x29f1,0x29f2,0x29f3,0x29f4,0x29f5,0x29f6,0x29f7,
+  0x29f8,0x29f9,0x29fa,0x29fb,0x29fc,0x29fd,0x29fe,0x29ff,
+  0x2a00,0x2a01,0x2a02,0x2a03,0x2a04,0x2a05,0x2a06,0x2a07,
+  0x2a08,0x2a09,0x2a0a,0x2a0b,0x2a0c,0x2a0d,0x2a0e,0x2a0f,
+  0x2a10,0x2a11,0x2a12,0x2a13,0x2a14,0x2a15,0x2a16,0x2a17,
+  0x2a18,0x2a19,0x2a1a,0x2a1b,0x2a1c,0x2a1d,0x2a1e,0x2a1f,
+  0x2a20,0x2a21,0x2a22,0x2a23,0x2a24,0x2a25,0x2a26,0x2a27,
+  0x2a28,0x2a29,0x2a2a,0x2a2b,0x2a2c,0x2a2d,0x2a2e,0x2a2f,
+  0x2a30,0x2a31,0x2a32,0x2a33,0x2a34,0x2a35,0x2a36,0x2a37,
+  0x2a38,0x2a39,0x2a3a,0x2a3b,0x2a3c,0x2a3d,0x2a3e,0x2a3f,
+  0x2a40,0x2a41,0x2a42,0x2a43,0x2a44,0x2a45,0x2a46,0x2a47,
+  0x2a48,0x2a49,0x2a4a,0x2a4b,0x2a4c,0x2a4d,0x2a4e,0x2a4f,
+  0x2a50,0x2a51,0x2a52,0x2a53,0x2a54,0x2a55,0x2a56,0x2a57,
+  0x2a58,0x2a59,0x2a5a,0x2a5b,0x2a5c,0x2a5d,0x2a5e,0x2a5f,
+  0x2a60,0x2a61,0x2a62,0x2a63,0x2a64,0x2a65,0x2a66,0x2a67,
+  0x2a68,0x2a69,0x2a6a,0x2a6b,0x2a6c,0x2a6d,0x2a6e,0x2a6f,
+  0x2a70,0x2a71,0x2a72,0x2a73,0x2a74,0x2a75,0x2a76,0x2a77,
+  0x2a78,0x2a79,0x2a7a,0x2a7b,0x2a7c,0x2a7d,0x2a7e,0x2a7f,
+  0x2a80,0x2a81,0x2a82,0x2a83,0x2a84,0x2a85,0x2a86,0x2a87,
+  0x2a88,0x2a89,0x2a8a,0x2a8b,0x2a8c,0x2a8d,0x2a8e,0x2a8f,
+  0x2a90,0x2a91,0x2a92,0x2a93,0x2a94,0x2a95,0x2a96,0x2a97,
+  0x2a98,0x2a99,0x2a9a,0x2a9b,0x2a9c,0x2a9d,0x2a9e,0x2a9f,
+  0x2aa0,0x2aa1,0x2aa2,0x2aa3,0x2aa4,0x2aa5,0x2aa6,0x2aa7,
+  0x2aa8,0x2aa9,0x2aaa,0x2aab,0x2aac,0x2aad,0x2aae,0x2aaf,
+  0x2ab0,0x2ab1,0x2ab2,0x2ab3,0x2ab4,0x2ab5,0x2ab6,0x2ab7,
+  0x2ab8,0x2ab9,0x2aba,0x2abb,0x2abc,0x2abd,0x2abe,0x2abf,
+  0x2ac0,0x2ac1,0x2ac2,0x2ac3,0x2ac4,0x2ac5,0x2ac6,0x2ac7,
+  0x2ac8,0x2ac9,0x2aca,0x2acb,0x2acc,0x2acd,0x2ace,0x2acf,
+  0x2ad0,0x2ad1,0x2ad2,0x2ad3,0x2ad4,0x2ad5,0x2ad6,0x2ad7,
+  0x2ad8,0x2ad9,0x2ada,0x2adb,0x2adc,0x2add,0x2ade,0x2adf,
+  0x2ae0,0x2ae1,0x2ae2,0x2ae3,0x2ae4,0x2ae5,0x2ae6,0x2ae7,
+  0x2ae8,0x2ae9,0x2aea,0x2aeb,0x2aec,0x2aed,0x2aee,0x2aef,
+  0x2af0,0x2af1,0x2af2,0x2af3,0x2af4,0x2af5,0x2af6,0x2af7,
+  0x2af8,0x2af9,0x2afa,0x2afb,0x2afc,0x2afd,0x2afe,0x2aff,
+  0x2b00,0x2b01,0x2b02,0x2b03,0x2b04,0x2b05,0x2b06,0x2b07,
+  0x2b08,0x2b09,0x2b0a,0x2b0b,0x2b0c,0x2b0d,0x2b0e,0x2b0f,
+  0x2b10,0x2b11,0x2b12,0x2b13,0x2b14,0x2b15,0x2b16,0x2b17,
+  0x2b18,0x2b19,0x2b1a,0x2b1b,0x2b1c,0x2b1d,0x2b1e,0x2b1f,
+  0x2b20,0x2b21,0x2b22,0x2b23,0x2b24,0x2b25,0x2b26,0x2b27,
+  0x2b28,0x2b29,0x2b2a,0x2b2b,0x2b2c,0x2b2d,0x2b2e,0x2b2f,
+  0x2b30,0x2b31,0x2b32,0x2b33,0x2b34,0x2b35,0x2b36,0x2b37,
+  0x2b38,0x2b39,0x2b3a,0x2b3b,0x2b3c,0x2b3d,0x2b3e,0x2b3f,
+  0x2b40,0x2b41,0x2b42,0x2b43,0x2b44,0x2b45,0x2b46,0x2b47,
+  0x2b48,0x2b49,0x2b4a,0x2b4b,0x2b4c,0x2b4d,0x2b4e,0x2b4f,
+  0x2b50,0x2b51,0x2b52,0x2b53,0x2b54,0x2b55,0x2b56,0x2b57,
+  0x2b58,0x2b59,0x2b5a,0x2b5b,0x2b5c,0x2b5d,0x2b5e,0x2b5f,
+  0x2b60,0x2b61,0x2b62,0x2b63,0x2b64,0x2b65,0x2b66,0x2b67,
+  0x2b68,0x2b69,0x2b6a,0x2b6b,0x2b6c,0x2b6d,0x2b6e,0x2b6f,
+  0x2b70,0x2b71,0x2b72,0x2b73,0x2b74,0x2b75,0x2b76,0x2b77,
+  0x2b78,0x2b79,0x2b7a,0x2b7b,0x2b7c,0x2b7d,0x2b7e,0x2b7f,
+  0x2b80,0x2b81,0x2b82,0x2b83,0x2b84,0x2b85,0x2b86,0x2b87,
+  0x2b88,0x2b89,0x2b8a,0x2b8b,0x2b8c,0x2b8d,0x2b8e,0x2b8f,
+  0x2b90,0x2b91,0x2b92,0x2b93,0x2b94,0x2b95,0x2b96,0x2b97,
+  0x2b98,0x2b99,0x2b9a,0x2b9b,0x2b9c,0x2b9d,0x2b9e,0x2b9f,
+  0x2ba0,0x2ba1,0x2ba2,0x2ba3,0x2ba4,0x2ba5,0x2ba6,0x2ba7,
+  0x2ba8,0x2ba9,0x2baa,0x2bab,0x2bac,0x2bad,0x2bae,0x2baf,
+  0x2bb0,0x2bb1,0x2bb2,0x2bb3,0x2bb4,0x2bb5,0x2bb6,0x2bb7,
+  0x2bb8,0x2bb9,0x2bba,0x2bbb,0x2bbc,0x2bbd,0x2bbe,0x2bbf,
+  0x2bc0,0x2bc1,0x2bc2,0x2bc3,0x2bc4,0x2bc5,0x2bc6,0x2bc7,
+  0x2bc8,0x2bc9,0x2bca,0x2bcb,0x2bcc,0x2bcd,0x2bce,0x2bcf,
+  0x2bd0,0x2bd1,0x2bd2,0x2bd3,0x2bd4,0x2bd5,0x2bd6,0x2bd7,
+  0x2bd8,0x2bd9,0x2bda,0x2bdb,0x2bdc,0x2bdd,0x2bde,0x2bdf,
+  0x2be0,0x2be1,0x2be2,0x2be3,0x2be4,0x2be5,0x2be6,0x2be7,
+  0x2be8,0x2be9,0x2bea,0x2beb,0x2bec,0x2bed,0x2bee,0x2bef,
+  0x2bf0,0x2bf1,0x2bf2,0x2bf3,0x2bf4,0x2bf5,0x2bf6,0x2bf7,
+  0x2bf8,0x2bf9,0x2bfa,0x2bfb,0x2bfc,0x2bfd,0x2bfe,0x2bff,
+  0x2c00,0x2c01,0x2c02,0x2c03,0x2c04,0x2c05,0x2c06,0x2c07,
+  0x2c08,0x2c09,0x2c0a,0x2c0b,0x2c0c,0x2c0d,0x2c0e,0x2c0f,
+  0x2c10,0x2c11,0x2c12,0x2c13,0x2c14,0x2c15,0x2c16,0x2c17,
+  0x2c18,0x2c19,0x2c1a,0x2c1b,0x2c1c,0x2c1d,0x2c1e,0x2c1f,
+  0x2c20,0x2c21,0x2c22,0x2c23,0x2c24,0x2c25,0x2c26,0x2c27,
+  0x2c28,0x2c29,0x2c2a,0x2c2b,0x2c2c,0x2c2d,0x2c2e,0x2c2f,
+  0x2c00,0x2c01,0x2c02,0x2c03,0x2c04,0x2c05,0x2c06,0x2c07,
+  0x2c08,0x2c09,0x2c0a,0x2c0b,0x2c0c,0x2c0d,0x2c0e,0x2c0f,
+  0x2c10,0x2c11,0x2c12,0x2c13,0x2c14,0x2c15,0x2c16,0x2c17,
+  0x2c18,0x2c19,0x2c1a,0x2c1b,0x2c1c,0x2c1d,0x2c1e,0x2c1f,
+  0x2c20,0x2c21,0x2c22,0x2c23,0x2c24,0x2c25,0x2c26,0x2c27,
+  0x2c28,0x2c29,0x2c2a,0x2c2b,0x2c2c,0x2c2d,0x2c2e,0x2c5f,
+  0x2c60,0x2c60,0x2c62,0x2c63,0x2c64,0x023a,0x023e,0x2c67,
+  0x2c67,0x2c69,0x2c69,0x2c6b,0x2c6b,0x2c6d,0x2c6e,0x2c6f,
+  0x2c70,0x2c71,0x2c72,0x2c73,0x2c74,0x2c75,0x2c75,0x2c77,
+  0x2c78,0x2c79,0x2c7a,0x2c7b,0x2c7c,0x2c7d,0x2c7e,0x2c7f,
+  0x2c80,0x2c80,0x2c82,0x2c82,0x2c84,0x2c84,0x2c86,0x2c86,
+  0x2c88,0x2c88,0x2c8a,0x2c8a,0x2c8c,0x2c8c,0x2c8e,0x2c8e,
+  0x2c90,0x2c90,0x2c92,0x2c92,0x2c94,0x2c94,0x2c96,0x2c96,
+  0x2c98,0x2c98,0x2c9a,0x2c9a,0x2c9c,0x2c9c,0x2c9e,0x2c9e,
+  0x2ca0,0x2ca0,0x2ca2,0x2ca2,0x2ca4,0x2ca4,0x2ca6,0x2ca6,
+  0x2ca8,0x2ca8,0x2caa,0x2caa,0x2cac,0x2cac,0x2cae,0x2cae,
+  0x2cb0,0x2cb0,0x2cb2,0x2cb2,0x2cb4,0x2cb4,0x2cb6,0x2cb6,
+  0x2cb8,0x2cb8,0x2cba,0x2cba,0x2cbc,0x2cbc,0x2cbe,0x2cbe,
+  0x2cc0,0x2cc0,0x2cc2,0x2cc2,0x2cc4,0x2cc4,0x2cc6,0x2cc6,
+  0x2cc8,0x2cc8,0x2cca,0x2cca,0x2ccc,0x2ccc,0x2cce,0x2cce,
+  0x2cd0,0x2cd0,0x2cd2,0x2cd2,0x2cd4,0x2cd4,0x2cd6,0x2cd6,
+  0x2cd8,0x2cd8,0x2cda,0x2cda,0x2cdc,0x2cdc,0x2cde,0x2cde,
+  0x2ce0,0x2ce0,0x2ce2,0x2ce2,0x2ce4,0x2ce5,0x2ce6,0x2ce7,
+  0x2ce8,0x2ce9,0x2cea,0x2ceb,0x2cec,0x2ced,0x2cee,0x2cef,
+  0x2cf0,0x2cf1,0x2cf2,0x2cf3,0x2cf4,0x2cf5,0x2cf6,0x2cf7,
+  0x2cf8,0x2cf9,0x2cfa,0x2cfb,0x2cfc,0x2cfd,0x2cfe,0x2cff,
+  0x10a0,0x10a1,0x10a2,0x10a3,0x10a4,0x10a5,0x10a6,0x10a7,
+  0x10a8,0x10a9,0x10aa,0x10ab,0x10ac,0x10ad,0x10ae,0x10af,
+  0x10b0,0x10b1,0x10b2,0x10b3,0x10b4,0x10b5,0x10b6,0x10b7,
+  0x10b8,0x10b9,0x10ba,0x10bb,0x10bc,0x10bd,0x10be,0x10bf,
+  0x10c0,0x10c1,0x10c2,0x10c3,0x10c4,0x10c5
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/charset/viscii.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,67 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	VISCII conversion table
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	2 June 1998
+ * Last Edited:	30 August 2006
+ */
+
+/* VISCII is the VIetnamese Standard Code for Information Interchange,
+ * defined by the Vietnamese Standardization Working Group, RFC-1456,
+ * May 1993.
+ */
+
+static const unsigned short visciitab[256] = {
+  0x0000,0x0001,0x1eb2,0x0003,0x0004,0x1eb4,0x1eaa,0x0007,
+  0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x000e,0x000f,
+  0x0010,0x0011,0x0012,0x0013,0x1ef6,0x0015,0x0016,0x0017,
+  0x0018,0x1ef8,0x001a,0x001b,0x001c,0x001d,0x1ef4,0x001f,
+  0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,
+  0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f,
+  0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,
+  0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f,
+  0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,
+  0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,
+  0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,
+  0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f,
+  0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,
+  0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f,
+  0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,
+  0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x007f,
+  0x1ea0,0x1eae,0x1eb0,0x1eb6,0x1ea4,0x1ea6,0x1ea8,0x1eac,
+  0x1ebc,0x1eb8,0x1ebe,0x1ec0,0x1ec2,0x1ec4,0x1ec6,0x1ed0,
+  0x1ed2,0x1ed4,0x1ed6,0x1ed8,0x1ee2,0x1eda,0x1edc,0x1ede,
+  0x1eca,0x1ece,0x1ecc,0x1ec8,0x1ee6,0x0168,0x1ee4,0x1ef2,
+  0x00d5,0x1eaf,0x1eb1,0x1eb7,0x1ea5,0x1ea7,0x1ea9,0x1ead,
+  0x1ebd,0x1eb9,0x1ebf,0x1ec1,0x1ec3,0x1ec5,0x1ec7,0x1ed1,
+  0x1ed3,0x1ed5,0x1ed7,0x1ee0,0x01a0,0x1ed9,0x1edd,0x1edf,
+  0x1ecb,0x1ef0,0x1ee8,0x1eea,0x1eec,0x01a1,0x1edb,0x01af,
+  0x00c0,0x00c1,0x00c2,0x00c3,0x1ea2,0x0102,0x1eb3,0x1eb5,
+  0x00c8,0x00c9,0x00ca,0x1eba,0x00cc,0x00cd,0x0128,0x1ef3,
+  0x0110,0x1ee9,0x00d2,0x00d3,0x00d4,0x1ea1,0x1ef7,0x1eeb,
+  0x1eed,0x00d9,0x00da,0x1ef9,0x1ef5,0x00dd,0x1ee1,0x01b0,
+  0x00e0,0x00e1,0x00e2,0x00e3,0x1ea3,0x0103,0x1eef,0x1eab,
+  0x00e8,0x00e9,0x00ea,0x1ebb,0x00ec,0x00ed,0x0129,0x1ec9,
+  0x0111,0x1ef1,0x00f2,0x00f3,0x00f4,0x00f5,0x1ecf,0x1ecd,
+  0x1ee5,0x00f9,0x00fa,0x0169,0x1ee7,0x00fd,0x1ee3,0x1eee
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/charset/widths.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,4136 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Unicode width table (current as of Unicode 5.0)
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	20 March 2006
+ * Last Edited:	1 March 2007
+ */
+
+/* Table of 2-bit character widths, indexed by Unicode codepoint and
+ * big-endian within bytes:
+ *  0	zero-width
+ *  1	single-width (half-width)
+ *  2	double-width (full-width)
+ *  3	ambiguous
+ */
+
+#define UCS4_WIDLEN 131072
+
+static const unsigned char ucs4_widthtab[32768] = {
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	/* U+0000 - U+001f */
+  0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,	/* U+0020 - U+003f */
+  0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,	/* U+0040 - U+005f */
+  0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x54,	/* U+0060 - U+007f */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	/* U+0080 - U+009f */
+  0xf5,0xd7,0xff,0x4d,0xff,0xff,0xff,0xff,	/* U+00a0 - U+00bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+00c0 - U+00df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+00e0 - U+00ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0100 - U+011f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0120 - U+013f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0140 - U+015f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0160 - U+017f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0180 - U+019f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+01a0 - U+01bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+01c0 - U+01df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+01e0 - U+01ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0200 - U+021f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0220 - U+023f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0240 - U+025f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0260 - U+027f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0280 - U+029f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+02a0 - U+02bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+02c0 - U+02df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+02e0 - U+02ff */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	/* U+0300 - U+031f */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	/* U+0320 - U+033f */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,	/* U+0340 - U+035f */
+  0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,	/* U+0360 - U+037f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0380 - U+039f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+03a0 - U+03bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+03c0 - U+03df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+03e0 - U+03ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0400 - U+041f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0420 - U+043f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0440 - U+045f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0460 - U+047f */
+  0xfc,0x03,0x0f,0xff,0xff,0xff,0xff,0xff,	/* U+0480 - U+049f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+04a0 - U+04bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+04c0 - U+04df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+04e0 - U+04ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0500 - U+051f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0520 - U+053f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0540 - U+055f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0560 - U+057f */
+  0xff,0xff,0xff,0xff,0xc0,0x00,0x00,0x00,	/* U+0580 - U+059f */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,	/* U+05a0 - U+05bf */
+  0xc3,0x0c,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+05c0 - U+05df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+05e0 - U+05ff */
+  0x00,0xff,0xff,0xff,0x00,0x0f,0xff,0xff,	/* U+0600 - U+061f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0620 - U+063f */
+  0xff,0xff,0xfc,0x00,0x00,0x00,0x00,0x03,	/* U+0640 - U+065f */
+  0xff,0xff,0xff,0xff,0x3f,0xff,0xff,0xff,	/* U+0660 - U+067f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0680 - U+069f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+06a0 - U+06bf */
+  0xff,0xff,0xff,0xff,0xff,0xf0,0x00,0x00,	/* U+06c0 - U+06df */
+  0x00,0x3c,0x30,0x0f,0xff,0xff,0xff,0xff,	/* U+06e0 - U+06ff */
+  0xff,0xff,0xff,0xfc,0xcf,0xff,0xff,0xff,	/* U+0700 - U+071f */
+  0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,	/* U+0720 - U+073f */
+  0x00,0x00,0x03,0xff,0xff,0xff,0xff,0xff,	/* U+0740 - U+075f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0760 - U+077f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0780 - U+079f */
+  0xff,0xf0,0x00,0x00,0x3f,0xff,0xff,0xff,	/* U+07a0 - U+07bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+07c0 - U+07df */
+  0xff,0xff,0xfc,0x00,0x00,0xff,0xff,0xff,	/* U+07e0 - U+07ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0800 - U+081f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0820 - U+083f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0840 - U+085f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0860 - U+087f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0880 - U+089f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+08a0 - U+08bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+08c0 - U+08df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+08e0 - U+08ff */
+  0xc3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0900 - U+091f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,	/* U+0920 - U+093f */
+  0xc0,0x00,0x3f,0xcf,0xc0,0x3f,0xff,0xff,	/* U+0940 - U+095f */
+  0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0960 - U+097f */
+  0xcf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0980 - U+099f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,	/* U+09a0 - U+09bf */
+  0xc0,0x3f,0xff,0xcf,0xff,0xff,0xff,0xff,	/* U+09c0 - U+09df */
+  0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+09e0 - U+09ff */
+  0xc3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0a00 - U+0a1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,	/* U+0a20 - U+0a3f */
+  0xc3,0xfc,0x3c,0x0f,0xff,0xff,0xff,0xff,	/* U+0a40 - U+0a5f */
+  0xff,0xff,0xff,0xff,0x0f,0xff,0xff,0xff,	/* U+0a60 - U+0a7f */
+  0xc3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0a80 - U+0a9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,	/* U+0aa0 - U+0abf */
+  0xc0,0x0c,0x3f,0xcf,0xff,0xff,0xff,0xff,	/* U+0ac0 - U+0adf */
+  0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0ae0 - U+0aff */
+  0xcf,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0b00 - U+0b1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3c,	/* U+0b20 - U+0b3f */
+  0xc0,0xff,0xff,0xcf,0xff,0xf3,0xff,0xff,	/* U+0b40 - U+0b5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0b60 - U+0b7f */
+  0xf3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0b80 - U+0b9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0ba0 - U+0bbf */
+  0x3f,0xff,0xff,0xcf,0xff,0xff,0xff,0xff,	/* U+0bc0 - U+0bdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0be0 - U+0bff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0c00 - U+0c1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,	/* U+0c20 - U+0c3f */
+  0x3f,0xf0,0x30,0x0f,0xff,0xc3,0xff,0xff,	/* U+0c40 - U+0c5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0c60 - U+0c7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0c80 - U+0c9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,	/* U+0ca0 - U+0cbf */
+  0xff,0xff,0xff,0x0f,0xff,0xff,0xff,0xff,	/* U+0cc0 - U+0cdf */
+  0xf0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0ce0 - U+0cff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0d00 - U+0d1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0d20 - U+0d3f */
+  0xc0,0xff,0xff,0xcf,0xff,0xff,0xff,0xff,	/* U+0d40 - U+0d5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0d60 - U+0d7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0d80 - U+0d9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0da0 - U+0dbf */
+  0xff,0xff,0xf3,0xff,0xf0,0x33,0xff,0xff,	/* U+0dc0 - U+0ddf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0de0 - U+0dff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0e00 - U+0e1f */
+  0xff,0xff,0xff,0xff,0xcf,0x00,0x03,0xff,	/* U+0e20 - U+0e3f */
+  0xff,0xfc,0x00,0x03,0xff,0xff,0xff,0xff,	/* U+0e40 - U+0e5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0e60 - U+0e7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0e80 - U+0e9f */
+  0xff,0xff,0xff,0xff,0xcf,0x00,0x0c,0x3f,	/* U+0ea0 - U+0ebf */
+  0xff,0xff,0x00,0x0f,0xff,0xff,0xff,0xff,	/* U+0ec0 - U+0edf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0ee0 - U+0eff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xff,	/* U+0f00 - U+0f1f */
+  0xff,0xff,0xff,0xff,0xff,0xcc,0xcf,0xff,	/* U+0f20 - U+0f3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0f40 - U+0f5f */
+  0xff,0xff,0xff,0xff,0xc0,0x00,0x00,0x03,	/* U+0f60 - U+0f7f */
+  0x00,0x30,0xff,0xff,0x00,0x00,0xc0,0x00,	/* U+0f80 - U+0f9f */
+  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,	/* U+0fa0 - U+0fbf */
+  0xff,0xf3,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0fc0 - U+0fdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+0fe0 - U+0fff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1000 - U+101f */
+  0xff,0xff,0xff,0xc0,0x33,0xf0,0xcf,0xff,	/* U+1020 - U+103f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0xff,	/* U+1040 - U+105f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1060 - U+107f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1080 - U+109f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10a0 - U+10bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10c0 - U+10df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10e0 - U+10ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+1100 - U+111f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+1120 - U+113f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaf,0xfe,	/* U+1140 - U+115f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1160 - U+117f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1180 - U+119f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11a0 - U+11bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11c0 - U+11df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11e0 - U+11ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1200 - U+121f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1220 - U+123f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1240 - U+125f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1260 - U+127f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1280 - U+129f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12a0 - U+12bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12c0 - U+12df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12e0 - U+12ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1300 - U+131f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1320 - U+133f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,	/* U+1340 - U+135f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1360 - U+137f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1380 - U+139f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13a0 - U+13bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13c0 - U+13df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13e0 - U+13ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1400 - U+141f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1420 - U+143f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1440 - U+145f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1460 - U+147f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1480 - U+149f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14a0 - U+14bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14c0 - U+14df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14e0 - U+14ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1500 - U+151f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1520 - U+153f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1540 - U+155f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1560 - U+157f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1580 - U+159f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15a0 - U+15bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15c0 - U+15df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15e0 - U+15ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1600 - U+161f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1620 - U+163f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1640 - U+165f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1660 - U+167f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1680 - U+169f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16a0 - U+16bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16c0 - U+16df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16e0 - U+16ff */
+  0xff,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,	/* U+1700 - U+171f */
+  0xff,0xff,0xff,0xff,0xf0,0x3f,0xff,0xff,	/* U+1720 - U+173f */
+  0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,	/* U+1740 - U+175f */
+  0xff,0xff,0xff,0xff,0xf0,0xff,0xff,0xff,	/* U+1760 - U+177f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1780 - U+179f */
+  0xff,0xff,0xff,0xff,0xff,0x0c,0x00,0x0f,	/* U+17a0 - U+17bf */
+  0xff,0xf3,0xc0,0x00,0x00,0xff,0xff,0xcf,	/* U+17c0 - U+17df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17e0 - U+17ff */
+  0xff,0xff,0xfc,0x0f,0xff,0xff,0xff,0xff,	/* U+1800 - U+181f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1820 - U+183f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1840 - U+185f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1860 - U+187f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1880 - U+189f */
+  0xff,0xff,0xcf,0xff,0xff,0xff,0xff,0xff,	/* U+18a0 - U+18bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18c0 - U+18df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18e0 - U+18ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1900 - U+191f */
+  0x03,0xfc,0x00,0xff,0xf3,0xff,0xc0,0xff,	/* U+1920 - U+193f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1940 - U+195f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1960 - U+197f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1980 - U+199f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19a0 - U+19bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19c0 - U+19df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19e0 - U+19ff */
+  0xff,0xff,0xff,0xff,0xff,0xfc,0x3f,0xff,	/* U+1a00 - U+1a1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a20 - U+1a3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a40 - U+1a5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a60 - U+1a7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a80 - U+1a9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aa0 - U+1abf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ac0 - U+1adf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ae0 - U+1aff */
+  0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b00 - U+1b1f */
+  0xff,0xff,0xff,0xff,0xff,0x30,0x03,0x3f,	/* U+1b20 - U+1b3f */
+  0xf3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b40 - U+1b5f */
+  0xff,0xff,0xfc,0x00,0x00,0xff,0xff,0xff,	/* U+1b60 - U+1b7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b80 - U+1b9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ba0 - U+1bbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bc0 - U+1bdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1be0 - U+1bff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c00 - U+1c1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c20 - U+1c3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c40 - U+1c5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c60 - U+1c7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c80 - U+1c9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ca0 - U+1cbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cc0 - U+1cdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ce0 - U+1cff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d00 - U+1d1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d20 - U+1d3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d40 - U+1d5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d60 - U+1d7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d80 - U+1d9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1da0 - U+1dbf */
+  0x00,0x00,0x03,0xff,0xff,0xff,0xff,0xff,	/* U+1dc0 - U+1ddf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf0,	/* U+1de0 - U+1dff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e00 - U+1e1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e20 - U+1e3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e40 - U+1e5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e60 - U+1e7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e80 - U+1e9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ea0 - U+1ebf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ec0 - U+1edf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ee0 - U+1eff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f00 - U+1f1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f20 - U+1f3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f40 - U+1f5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f60 - U+1f7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f80 - U+1f9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fa0 - U+1fbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fc0 - U+1fdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fe0 - U+1fff */
+  0xff,0xff,0xfc,0x00,0xff,0xff,0xff,0xff,	/* U+2000 - U+201f */
+  0xff,0xff,0xf0,0x03,0xff,0xff,0xff,0xff,	/* U+2020 - U+203f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2040 - U+205f */
+  0x00,0xff,0xf0,0x00,0xff,0xff,0xff,0xff,	/* U+2060 - U+207f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2080 - U+209f */
+  0xff,0xff,0xdf,0xff,0xff,0xff,0xff,0xff,	/* U+20a0 - U+20bf */
+  0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,	/* U+20c0 - U+20df */
+  0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,	/* U+20e0 - U+20ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2100 - U+211f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2120 - U+213f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2140 - U+215f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2160 - U+217f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2180 - U+219f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+21a0 - U+21bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+21c0 - U+21df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+21e0 - U+21ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2200 - U+221f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2220 - U+223f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2240 - U+225f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2260 - U+227f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2280 - U+229f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+22a0 - U+22bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+22c0 - U+22df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+22e0 - U+22ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2300 - U+231f */
+  0xff,0xff,0xeb,0xff,0xff,0xff,0xff,0xff,	/* U+2320 - U+233f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2340 - U+235f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2360 - U+237f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2380 - U+239f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+23a0 - U+23bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+23c0 - U+23df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+23e0 - U+23ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2400 - U+241f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2420 - U+243f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2440 - U+245f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2460 - U+247f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2480 - U+249f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+24a0 - U+24bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+24c0 - U+24df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+24e0 - U+24ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2500 - U+251f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2520 - U+253f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2540 - U+255f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2560 - U+257f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2580 - U+259f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+25a0 - U+25bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+25c0 - U+25df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+25e0 - U+25ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2600 - U+261f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2620 - U+263f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2640 - U+265f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2660 - U+267f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2680 - U+269f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+26a0 - U+26bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+26c0 - U+26df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+26e0 - U+26ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2700 - U+271f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2720 - U+273f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2740 - U+275f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2760 - U+277f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2780 - U+279f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+27a0 - U+27bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+27c0 - U+27df */
+  0xff,0xf5,0x55,0xff,0xff,0xff,0xff,0xff,	/* U+27e0 - U+27ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2800 - U+281f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2820 - U+283f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2840 - U+285f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2860 - U+287f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2880 - U+289f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+28a0 - U+28bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+28c0 - U+28df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+28e0 - U+28ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2900 - U+291f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2920 - U+293f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2940 - U+295f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2960 - U+297f */
+  0xff,0xd7,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2980 - U+299f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+29a0 - U+29bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+29c0 - U+29df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+29e0 - U+29ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2a00 - U+2a1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2a20 - U+2a3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2a40 - U+2a5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2a60 - U+2a7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2a80 - U+2a9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2aa0 - U+2abf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2ac0 - U+2adf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2ae0 - U+2aff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2b00 - U+2b1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2b20 - U+2b3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2b40 - U+2b5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2b60 - U+2b7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2b80 - U+2b9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2ba0 - U+2bbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2bc0 - U+2bdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2be0 - U+2bff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2c00 - U+2c1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2c20 - U+2c3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2c40 - U+2c5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2c60 - U+2c7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2c80 - U+2c9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2ca0 - U+2cbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2cc0 - U+2cdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2ce0 - U+2cff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2d00 - U+2d1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2d20 - U+2d3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2d40 - U+2d5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2d60 - U+2d7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2d80 - U+2d9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2da0 - U+2dbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2dc0 - U+2ddf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2de0 - U+2dff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2e00 - U+2e1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2e20 - U+2e3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2e40 - U+2e5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+2e60 - U+2e7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xae,0xaa,	/* U+2e80 - U+2e9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+2ea0 - U+2ebf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+2ec0 - U+2edf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,	/* U+2ee0 - U+2eff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+2f00 - U+2f1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+2f20 - U+2f3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+2f40 - U+2f5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+2f60 - U+2f7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+2f80 - U+2f9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+2fa0 - U+2fbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaf,0xff,0xff,	/* U+2fc0 - U+2fdf */
+  0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xff,	/* U+2fe0 - U+2fff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3000 - U+301f */
+  0xaa,0xaa,0xa0,0x00,0xaa,0xaa,0xaa,0xab,	/* U+3020 - U+303f */
+  0xea,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3040 - U+305f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3060 - U+307f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xab,0xc2,0xaa,	/* U+3080 - U+309f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+30a0 - U+30bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+30c0 - U+30df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+30e0 - U+30ff */
+  0xff,0xea,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3100 - U+311f */
+  0xaa,0xaa,0xaa,0xbf,0xea,0xaa,0xaa,0xaa,	/* U+3120 - U+313f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3140 - U+315f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3160 - U+317f */
+  0xaa,0xaa,0xaa,0xab,0xaa,0xaa,0xaa,0xaa,	/* U+3180 - U+319f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xff,0xff,	/* U+31a0 - U+31bf */
+  0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,	/* U+31c0 - U+31df */
+  0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,	/* U+31e0 - U+31ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xab,	/* U+3200 - U+321f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3220 - U+323f */
+  0xaa,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,	/* U+3240 - U+325f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3260 - U+327f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3280 - U+329f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+32a0 - U+32bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+32c0 - U+32df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xab,	/* U+32e0 - U+32ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3300 - U+331f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3320 - U+333f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3340 - U+335f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3360 - U+337f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3380 - U+339f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+33a0 - U+33bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+33c0 - U+33df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+33e0 - U+33ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3400 - U+341f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3420 - U+343f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3440 - U+345f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3460 - U+347f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3480 - U+349f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+34a0 - U+34bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+34c0 - U+34df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+34e0 - U+34ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3500 - U+351f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3520 - U+353f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3540 - U+355f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3560 - U+357f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3580 - U+359f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+35a0 - U+35bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+35c0 - U+35df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+35e0 - U+35ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3600 - U+361f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3620 - U+363f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3640 - U+365f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3660 - U+367f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3680 - U+369f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+36a0 - U+36bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+36c0 - U+36df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+36e0 - U+36ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3700 - U+371f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3720 - U+373f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3740 - U+375f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3760 - U+377f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3780 - U+379f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+37a0 - U+37bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+37c0 - U+37df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+37e0 - U+37ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3800 - U+381f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3820 - U+383f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3840 - U+385f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3860 - U+387f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3880 - U+389f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+38a0 - U+38bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+38c0 - U+38df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+38e0 - U+38ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3900 - U+391f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3920 - U+393f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3940 - U+395f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3960 - U+397f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3980 - U+399f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+39a0 - U+39bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+39c0 - U+39df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+39e0 - U+39ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3a00 - U+3a1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3a20 - U+3a3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3a40 - U+3a5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3a60 - U+3a7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3a80 - U+3a9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3aa0 - U+3abf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3ac0 - U+3adf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3ae0 - U+3aff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3b00 - U+3b1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3b20 - U+3b3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3b40 - U+3b5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3b60 - U+3b7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3b80 - U+3b9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3ba0 - U+3bbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3bc0 - U+3bdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3be0 - U+3bff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3c00 - U+3c1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3c20 - U+3c3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3c40 - U+3c5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3c60 - U+3c7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3c80 - U+3c9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3ca0 - U+3cbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3cc0 - U+3cdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3ce0 - U+3cff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3d00 - U+3d1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3d20 - U+3d3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3d40 - U+3d5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3d60 - U+3d7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3d80 - U+3d9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3da0 - U+3dbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3dc0 - U+3ddf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3de0 - U+3dff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3e00 - U+3e1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3e20 - U+3e3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3e40 - U+3e5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3e60 - U+3e7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3e80 - U+3e9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3ea0 - U+3ebf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3ec0 - U+3edf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3ee0 - U+3eff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3f00 - U+3f1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3f20 - U+3f3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3f40 - U+3f5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3f60 - U+3f7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3f80 - U+3f9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3fa0 - U+3fbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3fc0 - U+3fdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+3fe0 - U+3fff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4000 - U+401f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4020 - U+403f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4040 - U+405f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4060 - U+407f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4080 - U+409f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+40a0 - U+40bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+40c0 - U+40df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+40e0 - U+40ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4100 - U+411f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4120 - U+413f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4140 - U+415f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4160 - U+417f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4180 - U+419f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+41a0 - U+41bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+41c0 - U+41df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+41e0 - U+41ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4200 - U+421f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4220 - U+423f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4240 - U+425f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4260 - U+427f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4280 - U+429f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+42a0 - U+42bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+42c0 - U+42df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+42e0 - U+42ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4300 - U+431f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4320 - U+433f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4340 - U+435f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4360 - U+437f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4380 - U+439f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+43a0 - U+43bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+43c0 - U+43df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+43e0 - U+43ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4400 - U+441f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4420 - U+443f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4440 - U+445f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4460 - U+447f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4480 - U+449f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+44a0 - U+44bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+44c0 - U+44df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+44e0 - U+44ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4500 - U+451f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4520 - U+453f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4540 - U+455f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4560 - U+457f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4580 - U+459f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+45a0 - U+45bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+45c0 - U+45df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+45e0 - U+45ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4600 - U+461f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4620 - U+463f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4640 - U+465f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4660 - U+467f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4680 - U+469f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+46a0 - U+46bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+46c0 - U+46df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+46e0 - U+46ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4700 - U+471f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4720 - U+473f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4740 - U+475f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4760 - U+477f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4780 - U+479f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+47a0 - U+47bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+47c0 - U+47df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+47e0 - U+47ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4800 - U+481f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4820 - U+483f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4840 - U+485f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4860 - U+487f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4880 - U+489f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+48a0 - U+48bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+48c0 - U+48df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+48e0 - U+48ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4900 - U+491f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4920 - U+493f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4940 - U+495f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4960 - U+497f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4980 - U+499f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+49a0 - U+49bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+49c0 - U+49df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+49e0 - U+49ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4a00 - U+4a1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4a20 - U+4a3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4a40 - U+4a5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4a60 - U+4a7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4a80 - U+4a9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4aa0 - U+4abf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4ac0 - U+4adf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4ae0 - U+4aff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4b00 - U+4b1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4b20 - U+4b3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4b40 - U+4b5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4b60 - U+4b7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4b80 - U+4b9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4ba0 - U+4bbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4bc0 - U+4bdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4be0 - U+4bff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4c00 - U+4c1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4c20 - U+4c3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4c40 - U+4c5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4c60 - U+4c7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4c80 - U+4c9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4ca0 - U+4cbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4cc0 - U+4cdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4ce0 - U+4cff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4d00 - U+4d1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4d20 - U+4d3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4d40 - U+4d5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4d60 - U+4d7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4d80 - U+4d9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaf,0xff,0xff,	/* U+4da0 - U+4dbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+4dc0 - U+4ddf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+4de0 - U+4dff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4e00 - U+4e1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4e20 - U+4e3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4e40 - U+4e5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4e60 - U+4e7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4e80 - U+4e9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4ea0 - U+4ebf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4ec0 - U+4edf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4ee0 - U+4eff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4f00 - U+4f1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4f20 - U+4f3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4f40 - U+4f5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4f60 - U+4f7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4f80 - U+4f9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4fa0 - U+4fbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4fc0 - U+4fdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+4fe0 - U+4fff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5000 - U+501f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5020 - U+503f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5040 - U+505f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5060 - U+507f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5080 - U+509f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+50a0 - U+50bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+50c0 - U+50df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+50e0 - U+50ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5100 - U+511f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5120 - U+513f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5140 - U+515f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5160 - U+517f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5180 - U+519f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+51a0 - U+51bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+51c0 - U+51df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+51e0 - U+51ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5200 - U+521f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5220 - U+523f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5240 - U+525f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5260 - U+527f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5280 - U+529f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+52a0 - U+52bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+52c0 - U+52df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+52e0 - U+52ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5300 - U+531f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5320 - U+533f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5340 - U+535f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5360 - U+537f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5380 - U+539f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+53a0 - U+53bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+53c0 - U+53df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+53e0 - U+53ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5400 - U+541f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5420 - U+543f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5440 - U+545f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5460 - U+547f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5480 - U+549f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+54a0 - U+54bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+54c0 - U+54df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+54e0 - U+54ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5500 - U+551f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5520 - U+553f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5540 - U+555f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5560 - U+557f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5580 - U+559f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+55a0 - U+55bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+55c0 - U+55df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+55e0 - U+55ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5600 - U+561f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5620 - U+563f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5640 - U+565f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5660 - U+567f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5680 - U+569f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+56a0 - U+56bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+56c0 - U+56df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+56e0 - U+56ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5700 - U+571f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5720 - U+573f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5740 - U+575f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5760 - U+577f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5780 - U+579f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+57a0 - U+57bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+57c0 - U+57df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+57e0 - U+57ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5800 - U+581f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5820 - U+583f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5840 - U+585f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5860 - U+587f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5880 - U+589f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+58a0 - U+58bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+58c0 - U+58df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+58e0 - U+58ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5900 - U+591f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5920 - U+593f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5940 - U+595f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5960 - U+597f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5980 - U+599f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+59a0 - U+59bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+59c0 - U+59df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+59e0 - U+59ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5a00 - U+5a1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5a20 - U+5a3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5a40 - U+5a5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5a60 - U+5a7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5a80 - U+5a9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5aa0 - U+5abf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5ac0 - U+5adf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5ae0 - U+5aff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5b00 - U+5b1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5b20 - U+5b3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5b40 - U+5b5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5b60 - U+5b7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5b80 - U+5b9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5ba0 - U+5bbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5bc0 - U+5bdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5be0 - U+5bff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5c00 - U+5c1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5c20 - U+5c3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5c40 - U+5c5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5c60 - U+5c7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5c80 - U+5c9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5ca0 - U+5cbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5cc0 - U+5cdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5ce0 - U+5cff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5d00 - U+5d1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5d20 - U+5d3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5d40 - U+5d5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5d60 - U+5d7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5d80 - U+5d9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5da0 - U+5dbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5dc0 - U+5ddf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5de0 - U+5dff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5e00 - U+5e1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5e20 - U+5e3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5e40 - U+5e5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5e60 - U+5e7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5e80 - U+5e9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5ea0 - U+5ebf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5ec0 - U+5edf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5ee0 - U+5eff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5f00 - U+5f1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5f20 - U+5f3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5f40 - U+5f5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5f60 - U+5f7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5f80 - U+5f9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5fa0 - U+5fbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5fc0 - U+5fdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+5fe0 - U+5fff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6000 - U+601f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6020 - U+603f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6040 - U+605f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6060 - U+607f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6080 - U+609f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+60a0 - U+60bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+60c0 - U+60df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+60e0 - U+60ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6100 - U+611f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6120 - U+613f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6140 - U+615f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6160 - U+617f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6180 - U+619f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+61a0 - U+61bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+61c0 - U+61df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+61e0 - U+61ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6200 - U+621f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6220 - U+623f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6240 - U+625f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6260 - U+627f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6280 - U+629f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+62a0 - U+62bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+62c0 - U+62df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+62e0 - U+62ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6300 - U+631f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6320 - U+633f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6340 - U+635f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6360 - U+637f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6380 - U+639f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+63a0 - U+63bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+63c0 - U+63df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+63e0 - U+63ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6400 - U+641f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6420 - U+643f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6440 - U+645f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6460 - U+647f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6480 - U+649f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+64a0 - U+64bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+64c0 - U+64df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+64e0 - U+64ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6500 - U+651f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6520 - U+653f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6540 - U+655f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6560 - U+657f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6580 - U+659f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+65a0 - U+65bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+65c0 - U+65df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+65e0 - U+65ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6600 - U+661f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6620 - U+663f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6640 - U+665f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6660 - U+667f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6680 - U+669f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+66a0 - U+66bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+66c0 - U+66df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+66e0 - U+66ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6700 - U+671f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6720 - U+673f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6740 - U+675f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6760 - U+677f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6780 - U+679f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+67a0 - U+67bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+67c0 - U+67df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+67e0 - U+67ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6800 - U+681f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6820 - U+683f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6840 - U+685f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6860 - U+687f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6880 - U+689f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+68a0 - U+68bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+68c0 - U+68df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+68e0 - U+68ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6900 - U+691f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6920 - U+693f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6940 - U+695f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6960 - U+697f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6980 - U+699f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+69a0 - U+69bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+69c0 - U+69df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+69e0 - U+69ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6a00 - U+6a1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6a20 - U+6a3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6a40 - U+6a5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6a60 - U+6a7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6a80 - U+6a9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6aa0 - U+6abf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6ac0 - U+6adf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6ae0 - U+6aff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6b00 - U+6b1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6b20 - U+6b3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6b40 - U+6b5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6b60 - U+6b7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6b80 - U+6b9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6ba0 - U+6bbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6bc0 - U+6bdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6be0 - U+6bff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6c00 - U+6c1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6c20 - U+6c3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6c40 - U+6c5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6c60 - U+6c7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6c80 - U+6c9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6ca0 - U+6cbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6cc0 - U+6cdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6ce0 - U+6cff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6d00 - U+6d1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6d20 - U+6d3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6d40 - U+6d5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6d60 - U+6d7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6d80 - U+6d9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6da0 - U+6dbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6dc0 - U+6ddf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6de0 - U+6dff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6e00 - U+6e1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6e20 - U+6e3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6e40 - U+6e5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6e60 - U+6e7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6e80 - U+6e9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6ea0 - U+6ebf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6ec0 - U+6edf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6ee0 - U+6eff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6f00 - U+6f1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6f20 - U+6f3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6f40 - U+6f5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6f60 - U+6f7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6f80 - U+6f9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6fa0 - U+6fbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6fc0 - U+6fdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+6fe0 - U+6fff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7000 - U+701f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7020 - U+703f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7040 - U+705f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7060 - U+707f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7080 - U+709f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+70a0 - U+70bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+70c0 - U+70df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+70e0 - U+70ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7100 - U+711f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7120 - U+713f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7140 - U+715f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7160 - U+717f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7180 - U+719f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+71a0 - U+71bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+71c0 - U+71df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+71e0 - U+71ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7200 - U+721f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7220 - U+723f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7240 - U+725f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7260 - U+727f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7280 - U+729f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+72a0 - U+72bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+72c0 - U+72df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+72e0 - U+72ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7300 - U+731f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7320 - U+733f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7340 - U+735f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7360 - U+737f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7380 - U+739f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+73a0 - U+73bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+73c0 - U+73df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+73e0 - U+73ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7400 - U+741f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7420 - U+743f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7440 - U+745f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7460 - U+747f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7480 - U+749f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+74a0 - U+74bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+74c0 - U+74df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+74e0 - U+74ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7500 - U+751f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7520 - U+753f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7540 - U+755f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7560 - U+757f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7580 - U+759f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+75a0 - U+75bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+75c0 - U+75df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+75e0 - U+75ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7600 - U+761f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7620 - U+763f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7640 - U+765f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7660 - U+767f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7680 - U+769f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+76a0 - U+76bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+76c0 - U+76df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+76e0 - U+76ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7700 - U+771f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7720 - U+773f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7740 - U+775f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7760 - U+777f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7780 - U+779f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+77a0 - U+77bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+77c0 - U+77df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+77e0 - U+77ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7800 - U+781f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7820 - U+783f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7840 - U+785f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7860 - U+787f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7880 - U+789f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+78a0 - U+78bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+78c0 - U+78df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+78e0 - U+78ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7900 - U+791f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7920 - U+793f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7940 - U+795f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7960 - U+797f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7980 - U+799f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+79a0 - U+79bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+79c0 - U+79df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+79e0 - U+79ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7a00 - U+7a1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7a20 - U+7a3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7a40 - U+7a5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7a60 - U+7a7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7a80 - U+7a9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7aa0 - U+7abf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7ac0 - U+7adf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7ae0 - U+7aff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7b00 - U+7b1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7b20 - U+7b3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7b40 - U+7b5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7b60 - U+7b7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7b80 - U+7b9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7ba0 - U+7bbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7bc0 - U+7bdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7be0 - U+7bff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7c00 - U+7c1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7c20 - U+7c3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7c40 - U+7c5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7c60 - U+7c7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7c80 - U+7c9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7ca0 - U+7cbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7cc0 - U+7cdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7ce0 - U+7cff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7d00 - U+7d1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7d20 - U+7d3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7d40 - U+7d5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7d60 - U+7d7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7d80 - U+7d9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7da0 - U+7dbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7dc0 - U+7ddf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7de0 - U+7dff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7e00 - U+7e1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7e20 - U+7e3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7e40 - U+7e5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7e60 - U+7e7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7e80 - U+7e9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7ea0 - U+7ebf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7ec0 - U+7edf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7ee0 - U+7eff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7f00 - U+7f1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7f20 - U+7f3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7f40 - U+7f5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7f60 - U+7f7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7f80 - U+7f9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7fa0 - U+7fbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7fc0 - U+7fdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+7fe0 - U+7fff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8000 - U+801f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8020 - U+803f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8040 - U+805f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8060 - U+807f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8080 - U+809f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+80a0 - U+80bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+80c0 - U+80df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+80e0 - U+80ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8100 - U+811f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8120 - U+813f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8140 - U+815f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8160 - U+817f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8180 - U+819f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+81a0 - U+81bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+81c0 - U+81df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+81e0 - U+81ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8200 - U+821f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8220 - U+823f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8240 - U+825f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8260 - U+827f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8280 - U+829f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+82a0 - U+82bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+82c0 - U+82df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+82e0 - U+82ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8300 - U+831f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8320 - U+833f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8340 - U+835f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8360 - U+837f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8380 - U+839f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+83a0 - U+83bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+83c0 - U+83df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+83e0 - U+83ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8400 - U+841f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8420 - U+843f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8440 - U+845f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8460 - U+847f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8480 - U+849f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+84a0 - U+84bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+84c0 - U+84df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+84e0 - U+84ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8500 - U+851f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8520 - U+853f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8540 - U+855f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8560 - U+857f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8580 - U+859f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+85a0 - U+85bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+85c0 - U+85df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+85e0 - U+85ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8600 - U+861f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8620 - U+863f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8640 - U+865f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8660 - U+867f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8680 - U+869f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+86a0 - U+86bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+86c0 - U+86df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+86e0 - U+86ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8700 - U+871f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8720 - U+873f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8740 - U+875f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8760 - U+877f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8780 - U+879f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+87a0 - U+87bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+87c0 - U+87df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+87e0 - U+87ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8800 - U+881f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8820 - U+883f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8840 - U+885f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8860 - U+887f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8880 - U+889f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+88a0 - U+88bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+88c0 - U+88df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+88e0 - U+88ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8900 - U+891f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8920 - U+893f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8940 - U+895f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8960 - U+897f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8980 - U+899f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+89a0 - U+89bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+89c0 - U+89df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+89e0 - U+89ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8a00 - U+8a1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8a20 - U+8a3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8a40 - U+8a5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8a60 - U+8a7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8a80 - U+8a9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8aa0 - U+8abf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8ac0 - U+8adf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8ae0 - U+8aff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8b00 - U+8b1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8b20 - U+8b3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8b40 - U+8b5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8b60 - U+8b7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8b80 - U+8b9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8ba0 - U+8bbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8bc0 - U+8bdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8be0 - U+8bff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8c00 - U+8c1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8c20 - U+8c3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8c40 - U+8c5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8c60 - U+8c7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8c80 - U+8c9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8ca0 - U+8cbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8cc0 - U+8cdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8ce0 - U+8cff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8d00 - U+8d1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8d20 - U+8d3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8d40 - U+8d5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8d60 - U+8d7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8d80 - U+8d9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8da0 - U+8dbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8dc0 - U+8ddf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8de0 - U+8dff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8e00 - U+8e1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8e20 - U+8e3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8e40 - U+8e5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8e60 - U+8e7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8e80 - U+8e9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8ea0 - U+8ebf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8ec0 - U+8edf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8ee0 - U+8eff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8f00 - U+8f1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8f20 - U+8f3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8f40 - U+8f5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8f60 - U+8f7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8f80 - U+8f9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8fa0 - U+8fbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8fc0 - U+8fdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+8fe0 - U+8fff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9000 - U+901f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9020 - U+903f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9040 - U+905f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9060 - U+907f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9080 - U+909f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+90a0 - U+90bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+90c0 - U+90df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+90e0 - U+90ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9100 - U+911f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9120 - U+913f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9140 - U+915f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9160 - U+917f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9180 - U+919f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+91a0 - U+91bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+91c0 - U+91df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+91e0 - U+91ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9200 - U+921f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9220 - U+923f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9240 - U+925f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9260 - U+927f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9280 - U+929f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+92a0 - U+92bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+92c0 - U+92df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+92e0 - U+92ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9300 - U+931f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9320 - U+933f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9340 - U+935f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9360 - U+937f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9380 - U+939f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+93a0 - U+93bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+93c0 - U+93df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+93e0 - U+93ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9400 - U+941f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9420 - U+943f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9440 - U+945f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9460 - U+947f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9480 - U+949f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+94a0 - U+94bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+94c0 - U+94df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+94e0 - U+94ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9500 - U+951f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9520 - U+953f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9540 - U+955f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9560 - U+957f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9580 - U+959f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+95a0 - U+95bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+95c0 - U+95df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+95e0 - U+95ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9600 - U+961f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9620 - U+963f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9640 - U+965f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9660 - U+967f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9680 - U+969f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+96a0 - U+96bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+96c0 - U+96df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+96e0 - U+96ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9700 - U+971f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9720 - U+973f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9740 - U+975f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9760 - U+977f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9780 - U+979f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+97a0 - U+97bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+97c0 - U+97df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+97e0 - U+97ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9800 - U+981f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9820 - U+983f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9840 - U+985f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9860 - U+987f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9880 - U+989f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+98a0 - U+98bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+98c0 - U+98df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+98e0 - U+98ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9900 - U+991f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9920 - U+993f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9940 - U+995f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9960 - U+997f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9980 - U+999f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+99a0 - U+99bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+99c0 - U+99df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+99e0 - U+99ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9a00 - U+9a1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9a20 - U+9a3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9a40 - U+9a5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9a60 - U+9a7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9a80 - U+9a9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9aa0 - U+9abf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9ac0 - U+9adf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9ae0 - U+9aff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9b00 - U+9b1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9b20 - U+9b3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9b40 - U+9b5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9b60 - U+9b7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9b80 - U+9b9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9ba0 - U+9bbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9bc0 - U+9bdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9be0 - U+9bff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9c00 - U+9c1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9c20 - U+9c3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9c40 - U+9c5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9c60 - U+9c7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9c80 - U+9c9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9ca0 - U+9cbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9cc0 - U+9cdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9ce0 - U+9cff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9d00 - U+9d1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9d20 - U+9d3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9d40 - U+9d5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9d60 - U+9d7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9d80 - U+9d9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9da0 - U+9dbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9dc0 - U+9ddf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9de0 - U+9dff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9e00 - U+9e1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9e20 - U+9e3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9e40 - U+9e5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9e60 - U+9e7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9e80 - U+9e9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9ea0 - U+9ebf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9ec0 - U+9edf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9ee0 - U+9eff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9f00 - U+9f1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9f20 - U+9f3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9f40 - U+9f5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9f60 - U+9f7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+9f80 - U+9f9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xff,	/* U+9fa0 - U+9fbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+9fc0 - U+9fdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+9fe0 - U+9fff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a000 - U+a01f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a020 - U+a03f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a040 - U+a05f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a060 - U+a07f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a080 - U+a09f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a0a0 - U+a0bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a0c0 - U+a0df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a0e0 - U+a0ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a100 - U+a11f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a120 - U+a13f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a140 - U+a15f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a160 - U+a17f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a180 - U+a19f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a1a0 - U+a1bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a1c0 - U+a1df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a1e0 - U+a1ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a200 - U+a21f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a220 - U+a23f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a240 - U+a25f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a260 - U+a27f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a280 - U+a29f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a2a0 - U+a2bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a2c0 - U+a2df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a2e0 - U+a2ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a300 - U+a31f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a320 - U+a33f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a340 - U+a35f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a360 - U+a37f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a380 - U+a39f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a3a0 - U+a3bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a3c0 - U+a3df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a3e0 - U+a3ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a400 - U+a41f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a420 - U+a43f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a440 - U+a45f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a460 - U+a47f */
+  0xaa,0xaa,0xaa,0xbf,0xaa,0xaa,0xaa,0xaa,	/* U+a480 - U+a49f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+a4a0 - U+a4bf */
+  0xaa,0xab,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a4c0 - U+a4df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a4e0 - U+a4ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a500 - U+a51f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a520 - U+a53f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a540 - U+a55f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a560 - U+a57f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a580 - U+a59f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a5a0 - U+a5bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a5c0 - U+a5df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a5e0 - U+a5ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a600 - U+a61f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a620 - U+a63f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a640 - U+a65f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a660 - U+a67f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a680 - U+a69f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a6a0 - U+a6bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a6c0 - U+a6df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a6e0 - U+a6ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a700 - U+a71f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a720 - U+a73f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a740 - U+a75f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a760 - U+a77f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a780 - U+a79f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a7a0 - U+a7bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a7c0 - U+a7df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a7e0 - U+a7ff */
+  0xf3,0xf3,0xfc,0xff,0xff,0xff,0xff,0xff,	/* U+a800 - U+a81f */
+  0xff,0xc3,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a820 - U+a83f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a840 - U+a85f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a860 - U+a87f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a880 - U+a89f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a8a0 - U+a8bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a8c0 - U+a8df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a8e0 - U+a8ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a900 - U+a91f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a920 - U+a93f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a940 - U+a95f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a960 - U+a97f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a980 - U+a99f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a9a0 - U+a9bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a9c0 - U+a9df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+a9e0 - U+a9ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+aa00 - U+aa1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+aa20 - U+aa3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+aa40 - U+aa5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+aa60 - U+aa7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+aa80 - U+aa9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+aaa0 - U+aabf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+aac0 - U+aadf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+aae0 - U+aaff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ab00 - U+ab1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ab20 - U+ab3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ab40 - U+ab5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ab60 - U+ab7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ab80 - U+ab9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+aba0 - U+abbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+abc0 - U+abdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+abe0 - U+abff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ac00 - U+ac1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ac20 - U+ac3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ac40 - U+ac5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ac60 - U+ac7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ac80 - U+ac9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+aca0 - U+acbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+acc0 - U+acdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ace0 - U+acff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ad00 - U+ad1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ad20 - U+ad3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ad40 - U+ad5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ad60 - U+ad7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ad80 - U+ad9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ada0 - U+adbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+adc0 - U+addf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ade0 - U+adff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ae00 - U+ae1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ae20 - U+ae3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ae40 - U+ae5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ae60 - U+ae7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ae80 - U+ae9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+aea0 - U+aebf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+aec0 - U+aedf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+aee0 - U+aeff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+af00 - U+af1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+af20 - U+af3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+af40 - U+af5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+af60 - U+af7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+af80 - U+af9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+afa0 - U+afbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+afc0 - U+afdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+afe0 - U+afff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b000 - U+b01f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b020 - U+b03f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b040 - U+b05f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b060 - U+b07f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b080 - U+b09f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b0a0 - U+b0bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b0c0 - U+b0df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b0e0 - U+b0ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b100 - U+b11f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b120 - U+b13f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b140 - U+b15f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b160 - U+b17f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b180 - U+b19f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b1a0 - U+b1bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b1c0 - U+b1df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b1e0 - U+b1ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b200 - U+b21f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b220 - U+b23f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b240 - U+b25f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b260 - U+b27f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b280 - U+b29f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b2a0 - U+b2bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b2c0 - U+b2df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b2e0 - U+b2ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b300 - U+b31f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b320 - U+b33f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b340 - U+b35f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b360 - U+b37f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b380 - U+b39f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b3a0 - U+b3bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b3c0 - U+b3df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b3e0 - U+b3ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b400 - U+b41f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b420 - U+b43f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b440 - U+b45f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b460 - U+b47f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b480 - U+b49f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b4a0 - U+b4bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b4c0 - U+b4df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b4e0 - U+b4ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b500 - U+b51f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b520 - U+b53f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b540 - U+b55f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b560 - U+b57f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b580 - U+b59f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b5a0 - U+b5bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b5c0 - U+b5df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b5e0 - U+b5ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b600 - U+b61f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b620 - U+b63f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b640 - U+b65f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b660 - U+b67f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b680 - U+b69f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b6a0 - U+b6bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b6c0 - U+b6df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b6e0 - U+b6ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b700 - U+b71f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b720 - U+b73f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b740 - U+b75f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b760 - U+b77f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b780 - U+b79f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b7a0 - U+b7bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b7c0 - U+b7df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b7e0 - U+b7ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b800 - U+b81f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b820 - U+b83f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b840 - U+b85f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b860 - U+b87f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b880 - U+b89f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b8a0 - U+b8bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b8c0 - U+b8df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b8e0 - U+b8ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b900 - U+b91f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b920 - U+b93f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b940 - U+b95f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b960 - U+b97f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b980 - U+b99f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b9a0 - U+b9bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b9c0 - U+b9df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+b9e0 - U+b9ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ba00 - U+ba1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ba20 - U+ba3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ba40 - U+ba5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ba60 - U+ba7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ba80 - U+ba9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+baa0 - U+babf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bac0 - U+badf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bae0 - U+baff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bb00 - U+bb1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bb20 - U+bb3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bb40 - U+bb5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bb60 - U+bb7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bb80 - U+bb9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bba0 - U+bbbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bbc0 - U+bbdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bbe0 - U+bbff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bc00 - U+bc1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bc20 - U+bc3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bc40 - U+bc5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bc60 - U+bc7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bc80 - U+bc9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bca0 - U+bcbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bcc0 - U+bcdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bce0 - U+bcff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bd00 - U+bd1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bd20 - U+bd3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bd40 - U+bd5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bd60 - U+bd7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bd80 - U+bd9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bda0 - U+bdbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bdc0 - U+bddf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bde0 - U+bdff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+be00 - U+be1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+be20 - U+be3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+be40 - U+be5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+be60 - U+be7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+be80 - U+be9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bea0 - U+bebf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bec0 - U+bedf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bee0 - U+beff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bf00 - U+bf1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bf20 - U+bf3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bf40 - U+bf5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bf60 - U+bf7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bf80 - U+bf9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bfa0 - U+bfbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bfc0 - U+bfdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+bfe0 - U+bfff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c000 - U+c01f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c020 - U+c03f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c040 - U+c05f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c060 - U+c07f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c080 - U+c09f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c0a0 - U+c0bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c0c0 - U+c0df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c0e0 - U+c0ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c100 - U+c11f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c120 - U+c13f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c140 - U+c15f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c160 - U+c17f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c180 - U+c19f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c1a0 - U+c1bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c1c0 - U+c1df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c1e0 - U+c1ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c200 - U+c21f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c220 - U+c23f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c240 - U+c25f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c260 - U+c27f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c280 - U+c29f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c2a0 - U+c2bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c2c0 - U+c2df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c2e0 - U+c2ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c300 - U+c31f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c320 - U+c33f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c340 - U+c35f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c360 - U+c37f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c380 - U+c39f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c3a0 - U+c3bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c3c0 - U+c3df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c3e0 - U+c3ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c400 - U+c41f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c420 - U+c43f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c440 - U+c45f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c460 - U+c47f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c480 - U+c49f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c4a0 - U+c4bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c4c0 - U+c4df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c4e0 - U+c4ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c500 - U+c51f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c520 - U+c53f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c540 - U+c55f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c560 - U+c57f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c580 - U+c59f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c5a0 - U+c5bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c5c0 - U+c5df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c5e0 - U+c5ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c600 - U+c61f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c620 - U+c63f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c640 - U+c65f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c660 - U+c67f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c680 - U+c69f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c6a0 - U+c6bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c6c0 - U+c6df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c6e0 - U+c6ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c700 - U+c71f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c720 - U+c73f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c740 - U+c75f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c760 - U+c77f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c780 - U+c79f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c7a0 - U+c7bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c7c0 - U+c7df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c7e0 - U+c7ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c800 - U+c81f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c820 - U+c83f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c840 - U+c85f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c860 - U+c87f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c880 - U+c89f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c8a0 - U+c8bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c8c0 - U+c8df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c8e0 - U+c8ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c900 - U+c91f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c920 - U+c93f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c940 - U+c95f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c960 - U+c97f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c980 - U+c99f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c9a0 - U+c9bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c9c0 - U+c9df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+c9e0 - U+c9ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ca00 - U+ca1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ca20 - U+ca3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ca40 - U+ca5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ca60 - U+ca7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ca80 - U+ca9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+caa0 - U+cabf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cac0 - U+cadf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cae0 - U+caff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cb00 - U+cb1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cb20 - U+cb3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cb40 - U+cb5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cb60 - U+cb7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cb80 - U+cb9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cba0 - U+cbbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cbc0 - U+cbdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cbe0 - U+cbff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cc00 - U+cc1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cc20 - U+cc3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cc40 - U+cc5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cc60 - U+cc7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cc80 - U+cc9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cca0 - U+ccbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ccc0 - U+ccdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cce0 - U+ccff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cd00 - U+cd1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cd20 - U+cd3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cd40 - U+cd5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cd60 - U+cd7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cd80 - U+cd9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cda0 - U+cdbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cdc0 - U+cddf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cde0 - U+cdff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ce00 - U+ce1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ce20 - U+ce3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ce40 - U+ce5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ce60 - U+ce7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ce80 - U+ce9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cea0 - U+cebf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cec0 - U+cedf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cee0 - U+ceff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cf00 - U+cf1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cf20 - U+cf3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cf40 - U+cf5f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cf60 - U+cf7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cf80 - U+cf9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cfa0 - U+cfbf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cfc0 - U+cfdf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+cfe0 - U+cfff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d000 - U+d01f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d020 - U+d03f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d040 - U+d05f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d060 - U+d07f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d080 - U+d09f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d0a0 - U+d0bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d0c0 - U+d0df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d0e0 - U+d0ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d100 - U+d11f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d120 - U+d13f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d140 - U+d15f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d160 - U+d17f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d180 - U+d19f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d1a0 - U+d1bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d1c0 - U+d1df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d1e0 - U+d1ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d200 - U+d21f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d220 - U+d23f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d240 - U+d25f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d260 - U+d27f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d280 - U+d29f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d2a0 - U+d2bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d2c0 - U+d2df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d2e0 - U+d2ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d300 - U+d31f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d320 - U+d33f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d340 - U+d35f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d360 - U+d37f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d380 - U+d39f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d3a0 - U+d3bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d3c0 - U+d3df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d3e0 - U+d3ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d400 - U+d41f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d420 - U+d43f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d440 - U+d45f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d460 - U+d47f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d480 - U+d49f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d4a0 - U+d4bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d4c0 - U+d4df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d4e0 - U+d4ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d500 - U+d51f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d520 - U+d53f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d540 - U+d55f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d560 - U+d57f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d580 - U+d59f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d5a0 - U+d5bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d5c0 - U+d5df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d5e0 - U+d5ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d600 - U+d61f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d620 - U+d63f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d640 - U+d65f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d660 - U+d67f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d680 - U+d69f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d6a0 - U+d6bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d6c0 - U+d6df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d6e0 - U+d6ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d700 - U+d71f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d720 - U+d73f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d740 - U+d75f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d760 - U+d77f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+d780 - U+d79f */
+  0xaa,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d7a0 - U+d7bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d7c0 - U+d7df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d7e0 - U+d7ff */
+  0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d800 - U+d81f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d820 - U+d83f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d840 - U+d85f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d860 - U+d87f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d880 - U+d89f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d8a0 - U+d8bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d8c0 - U+d8df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d8e0 - U+d8ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d900 - U+d91f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d920 - U+d93f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d940 - U+d95f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d960 - U+d97f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d980 - U+d99f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d9a0 - U+d9bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d9c0 - U+d9df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+d9e0 - U+d9ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+da00 - U+da1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+da20 - U+da3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+da40 - U+da5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+da60 - U+da7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+da80 - U+da9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+daa0 - U+dabf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dac0 - U+dadf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dae0 - U+daff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+db00 - U+db1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+db20 - U+db3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+db40 - U+db5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,	/* U+db60 - U+db7f */
+  0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+db80 - U+db9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dba0 - U+dbbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dbc0 - U+dbdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,	/* U+dbe0 - U+dbff */
+  0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dc00 - U+dc1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dc20 - U+dc3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dc40 - U+dc5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dc60 - U+dc7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dc80 - U+dc9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dca0 - U+dcbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dcc0 - U+dcdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dce0 - U+dcff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dd00 - U+dd1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dd20 - U+dd3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dd40 - U+dd5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dd60 - U+dd7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dd80 - U+dd9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dda0 - U+ddbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ddc0 - U+dddf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dde0 - U+ddff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+de00 - U+de1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+de20 - U+de3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+de40 - U+de5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+de60 - U+de7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+de80 - U+de9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dea0 - U+debf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dec0 - U+dedf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dee0 - U+deff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+df00 - U+df1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+df20 - U+df3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+df40 - U+df5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+df60 - U+df7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+df80 - U+df9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dfa0 - U+dfbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+dfc0 - U+dfdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,	/* U+dfe0 - U+dfff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e000 - U+e01f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e020 - U+e03f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e040 - U+e05f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e060 - U+e07f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e080 - U+e09f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e0a0 - U+e0bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e0c0 - U+e0df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e0e0 - U+e0ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e100 - U+e11f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e120 - U+e13f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e140 - U+e15f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e160 - U+e17f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e180 - U+e19f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e1a0 - U+e1bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e1c0 - U+e1df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e1e0 - U+e1ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e200 - U+e21f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e220 - U+e23f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e240 - U+e25f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e260 - U+e27f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e280 - U+e29f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e2a0 - U+e2bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e2c0 - U+e2df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e2e0 - U+e2ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e300 - U+e31f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e320 - U+e33f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e340 - U+e35f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e360 - U+e37f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e380 - U+e39f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e3a0 - U+e3bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e3c0 - U+e3df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e3e0 - U+e3ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e400 - U+e41f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e420 - U+e43f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e440 - U+e45f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e460 - U+e47f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e480 - U+e49f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e4a0 - U+e4bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e4c0 - U+e4df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e4e0 - U+e4ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e500 - U+e51f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e520 - U+e53f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e540 - U+e55f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e560 - U+e57f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e580 - U+e59f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e5a0 - U+e5bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e5c0 - U+e5df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e5e0 - U+e5ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e600 - U+e61f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e620 - U+e63f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e640 - U+e65f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e660 - U+e67f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e680 - U+e69f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e6a0 - U+e6bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e6c0 - U+e6df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e6e0 - U+e6ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e700 - U+e71f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e720 - U+e73f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e740 - U+e75f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e760 - U+e77f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e780 - U+e79f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e7a0 - U+e7bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e7c0 - U+e7df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e7e0 - U+e7ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e800 - U+e81f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e820 - U+e83f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e840 - U+e85f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e860 - U+e87f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e880 - U+e89f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e8a0 - U+e8bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e8c0 - U+e8df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e8e0 - U+e8ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e900 - U+e91f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e920 - U+e93f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e940 - U+e95f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e960 - U+e97f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e980 - U+e99f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e9a0 - U+e9bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e9c0 - U+e9df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+e9e0 - U+e9ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ea00 - U+ea1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ea20 - U+ea3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ea40 - U+ea5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ea60 - U+ea7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ea80 - U+ea9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eaa0 - U+eabf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eac0 - U+eadf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eae0 - U+eaff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eb00 - U+eb1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eb20 - U+eb3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eb40 - U+eb5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eb60 - U+eb7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eb80 - U+eb9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eba0 - U+ebbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ebc0 - U+ebdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ebe0 - U+ebff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ec00 - U+ec1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ec20 - U+ec3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ec40 - U+ec5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ec60 - U+ec7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ec80 - U+ec9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eca0 - U+ecbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ecc0 - U+ecdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ece0 - U+ecff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ed00 - U+ed1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ed20 - U+ed3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ed40 - U+ed5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ed60 - U+ed7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ed80 - U+ed9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eda0 - U+edbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+edc0 - U+eddf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ede0 - U+edff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ee00 - U+ee1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ee20 - U+ee3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ee40 - U+ee5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ee60 - U+ee7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ee80 - U+ee9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eea0 - U+eebf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eec0 - U+eedf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+eee0 - U+eeff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ef00 - U+ef1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ef20 - U+ef3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ef40 - U+ef5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ef60 - U+ef7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+ef80 - U+ef9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+efa0 - U+efbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+efc0 - U+efdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+efe0 - U+efff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f000 - U+f01f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f020 - U+f03f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f040 - U+f05f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f060 - U+f07f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f080 - U+f09f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f0a0 - U+f0bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f0c0 - U+f0df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f0e0 - U+f0ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f100 - U+f11f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f120 - U+f13f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f140 - U+f15f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f160 - U+f17f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f180 - U+f19f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f1a0 - U+f1bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f1c0 - U+f1df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f1e0 - U+f1ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f200 - U+f21f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f220 - U+f23f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f240 - U+f25f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f260 - U+f27f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f280 - U+f29f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f2a0 - U+f2bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f2c0 - U+f2df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f2e0 - U+f2ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f300 - U+f31f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f320 - U+f33f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f340 - U+f35f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f360 - U+f37f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f380 - U+f39f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f3a0 - U+f3bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f3c0 - U+f3df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f3e0 - U+f3ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f400 - U+f41f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f420 - U+f43f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f440 - U+f45f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f460 - U+f47f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f480 - U+f49f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f4a0 - U+f4bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f4c0 - U+f4df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f4e0 - U+f4ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f500 - U+f51f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f520 - U+f53f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f540 - U+f55f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f560 - U+f57f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f580 - U+f59f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f5a0 - U+f5bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f5c0 - U+f5df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f5e0 - U+f5ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f600 - U+f61f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f620 - U+f63f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f640 - U+f65f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f660 - U+f67f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f680 - U+f69f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f6a0 - U+f6bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f6c0 - U+f6df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f6e0 - U+f6ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f700 - U+f71f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f720 - U+f73f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f740 - U+f75f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f760 - U+f77f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f780 - U+f79f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f7a0 - U+f7bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f7c0 - U+f7df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f7e0 - U+f7ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f800 - U+f81f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f820 - U+f83f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f840 - U+f85f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f860 - U+f87f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f880 - U+f89f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f8a0 - U+f8bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f8c0 - U+f8df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+f8e0 - U+f8ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+f900 - U+f91f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+f920 - U+f93f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+f940 - U+f95f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+f960 - U+f97f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+f980 - U+f99f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+f9a0 - U+f9bf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+f9c0 - U+f9df */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+f9e0 - U+f9ff */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+fa00 - U+fa1f */
+  0xaa,0xaa,0xaa,0xaf,0xaa,0xaa,0xaa,0xaa,	/* U+fa20 - U+fa3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+fa40 - U+fa5f */
+  0xaa,0xaa,0xab,0xff,0xaa,0xaa,0xaa,0xaa,	/* U+fa60 - U+fa7f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+fa80 - U+fa9f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+faa0 - U+fabf */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaf,0xff,	/* U+fac0 - U+fadf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fae0 - U+faff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf3,	/* U+fb00 - U+fb1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fb20 - U+fb3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fb40 - U+fb5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fb60 - U+fb7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fb80 - U+fb9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fba0 - U+fbbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fbc0 - U+fbdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fbe0 - U+fbff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fc00 - U+fc1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fc20 - U+fc3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fc40 - U+fc5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fc60 - U+fc7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fc80 - U+fc9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fca0 - U+fcbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fcc0 - U+fcdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fce0 - U+fcff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fd00 - U+fd1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fd20 - U+fd3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fd40 - U+fd5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fd60 - U+fd7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fd80 - U+fd9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fda0 - U+fdbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fdc0 - U+fddf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fde0 - U+fdff */
+  0x00,0x00,0x00,0x00,0xaa,0xaa,0xaf,0xff,	/* U+fe00 - U+fe1f */
+  0x00,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,	/* U+fe20 - U+fe3f */
+  0xaa,0xaa,0xaa,0xaa,0xab,0xaa,0xaa,0xaa,	/* U+fe40 - U+fe5f */
+  0xaa,0xab,0xaa,0xff,0xff,0xff,0xff,0xff,	/* U+fe60 - U+fe7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fe80 - U+fe9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fea0 - U+febf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+fec0 - U+fedf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,	/* U+fee0 - U+feff */
+  0xea,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ff00 - U+ff1f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ff20 - U+ff3f */
+  0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,	/* U+ff40 - U+ff5f */
+  0x95,0x55,0x55,0x55,0x55,0x55,0x55,0x55,	/* U+ff60 - U+ff7f */
+  0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,	/* U+ff80 - U+ff9f */
+  0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x57,	/* U+ffa0 - U+ffbf */
+  0xf5,0x55,0xf5,0x55,0xf5,0x55,0xf5,0x7f,	/* U+ffc0 - U+ffdf */
+  0xaa,0xab,0x55,0x57,0xff,0xff,0xc0,0xff,	/* U+ffe0 - U+ffff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10000 - U+1001f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10020 - U+1003f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10040 - U+1005f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10060 - U+1007f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10080 - U+1009f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+100a0 - U+100bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+100c0 - U+100df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+100e0 - U+100ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10100 - U+1011f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10120 - U+1013f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10140 - U+1015f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10160 - U+1017f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10180 - U+1019f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+101a0 - U+101bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+101c0 - U+101df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+101e0 - U+101ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10200 - U+1021f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10220 - U+1023f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10240 - U+1025f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10260 - U+1027f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10280 - U+1029f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+102a0 - U+102bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+102c0 - U+102df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+102e0 - U+102ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10300 - U+1031f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10320 - U+1033f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10340 - U+1035f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10360 - U+1037f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10380 - U+1039f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+103a0 - U+103bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+103c0 - U+103df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+103e0 - U+103ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10400 - U+1041f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10420 - U+1043f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10440 - U+1045f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10460 - U+1047f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10480 - U+1049f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+104a0 - U+104bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+104c0 - U+104df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+104e0 - U+104ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10500 - U+1051f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10520 - U+1053f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10540 - U+1055f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10560 - U+1057f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10580 - U+1059f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+105a0 - U+105bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+105c0 - U+105df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+105e0 - U+105ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10600 - U+1061f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10620 - U+1063f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10640 - U+1065f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10660 - U+1067f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10680 - U+1069f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+106a0 - U+106bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+106c0 - U+106df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+106e0 - U+106ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10700 - U+1071f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10720 - U+1073f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10740 - U+1075f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10760 - U+1077f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10780 - U+1079f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+107a0 - U+107bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+107c0 - U+107df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+107e0 - U+107ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10800 - U+1081f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10820 - U+1083f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10840 - U+1085f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10860 - U+1087f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10880 - U+1089f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+108a0 - U+108bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+108c0 - U+108df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+108e0 - U+108ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10900 - U+1091f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10920 - U+1093f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10940 - U+1095f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10960 - U+1097f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10980 - U+1099f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+109a0 - U+109bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+109c0 - U+109df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+109e0 - U+109ff */
+  0xc0,0xc3,0xff,0x00,0xff,0xff,0xff,0xff,	/* U+10a00 - U+10a1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0x03,0xfc,	/* U+10a20 - U+10a3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10a40 - U+10a5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10a60 - U+10a7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10a80 - U+10a9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10aa0 - U+10abf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10ac0 - U+10adf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10ae0 - U+10aff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10b00 - U+10b1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10b20 - U+10b3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10b40 - U+10b5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10b60 - U+10b7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10b80 - U+10b9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10ba0 - U+10bbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10bc0 - U+10bdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10be0 - U+10bff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10c00 - U+10c1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10c20 - U+10c3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10c40 - U+10c5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10c60 - U+10c7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10c80 - U+10c9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10ca0 - U+10cbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10cc0 - U+10cdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10ce0 - U+10cff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10d00 - U+10d1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10d20 - U+10d3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10d40 - U+10d5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10d60 - U+10d7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10d80 - U+10d9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10da0 - U+10dbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10dc0 - U+10ddf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10de0 - U+10dff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10e00 - U+10e1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10e20 - U+10e3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10e40 - U+10e5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10e60 - U+10e7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10e80 - U+10e9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10ea0 - U+10ebf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10ec0 - U+10edf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10ee0 - U+10eff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10f00 - U+10f1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10f20 - U+10f3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10f40 - U+10f5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10f60 - U+10f7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10f80 - U+10f9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10fa0 - U+10fbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10fc0 - U+10fdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+10fe0 - U+10fff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11000 - U+1101f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11020 - U+1103f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11040 - U+1105f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11060 - U+1107f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11080 - U+1109f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+110a0 - U+110bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+110c0 - U+110df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+110e0 - U+110ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11100 - U+1111f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11120 - U+1113f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11140 - U+1115f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11160 - U+1117f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11180 - U+1119f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+111a0 - U+111bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+111c0 - U+111df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+111e0 - U+111ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11200 - U+1121f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11220 - U+1123f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11240 - U+1125f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11260 - U+1127f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11280 - U+1129f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+112a0 - U+112bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+112c0 - U+112df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+112e0 - U+112ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11300 - U+1131f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11320 - U+1133f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11340 - U+1135f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11360 - U+1137f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11380 - U+1139f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+113a0 - U+113bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+113c0 - U+113df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+113e0 - U+113ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11400 - U+1141f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11420 - U+1143f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11440 - U+1145f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11460 - U+1147f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11480 - U+1149f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+114a0 - U+114bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+114c0 - U+114df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+114e0 - U+114ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11500 - U+1151f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11520 - U+1153f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11540 - U+1155f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11560 - U+1157f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11580 - U+1159f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+115a0 - U+115bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+115c0 - U+115df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+115e0 - U+115ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11600 - U+1161f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11620 - U+1163f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11640 - U+1165f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11660 - U+1167f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11680 - U+1169f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+116a0 - U+116bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+116c0 - U+116df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+116e0 - U+116ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11700 - U+1171f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11720 - U+1173f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11740 - U+1175f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11760 - U+1177f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11780 - U+1179f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+117a0 - U+117bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+117c0 - U+117df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+117e0 - U+117ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11800 - U+1181f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11820 - U+1183f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11840 - U+1185f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11860 - U+1187f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11880 - U+1189f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+118a0 - U+118bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+118c0 - U+118df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+118e0 - U+118ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11900 - U+1191f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11920 - U+1193f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11940 - U+1195f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11960 - U+1197f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11980 - U+1199f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+119a0 - U+119bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+119c0 - U+119df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+119e0 - U+119ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11a00 - U+11a1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11a20 - U+11a3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11a40 - U+11a5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11a60 - U+11a7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11a80 - U+11a9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11aa0 - U+11abf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11ac0 - U+11adf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11ae0 - U+11aff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11b00 - U+11b1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11b20 - U+11b3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11b40 - U+11b5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11b60 - U+11b7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11b80 - U+11b9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11ba0 - U+11bbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11bc0 - U+11bdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11be0 - U+11bff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11c00 - U+11c1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11c20 - U+11c3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11c40 - U+11c5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11c60 - U+11c7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11c80 - U+11c9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11ca0 - U+11cbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11cc0 - U+11cdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11ce0 - U+11cff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11d00 - U+11d1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11d20 - U+11d3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11d40 - U+11d5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11d60 - U+11d7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11d80 - U+11d9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11da0 - U+11dbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11dc0 - U+11ddf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11de0 - U+11dff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11e00 - U+11e1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11e20 - U+11e3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11e40 - U+11e5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11e60 - U+11e7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11e80 - U+11e9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11ea0 - U+11ebf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11ec0 - U+11edf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11ee0 - U+11eff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11f00 - U+11f1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11f20 - U+11f3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11f40 - U+11f5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11f60 - U+11f7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11f80 - U+11f9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11fa0 - U+11fbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11fc0 - U+11fdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+11fe0 - U+11fff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12000 - U+1201f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12020 - U+1203f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12040 - U+1205f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12060 - U+1207f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12080 - U+1209f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+120a0 - U+120bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+120c0 - U+120df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+120e0 - U+120ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12100 - U+1211f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12120 - U+1213f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12140 - U+1215f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12160 - U+1217f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12180 - U+1219f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+121a0 - U+121bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+121c0 - U+121df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+121e0 - U+121ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12200 - U+1221f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12220 - U+1223f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12240 - U+1225f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12260 - U+1227f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12280 - U+1229f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+122a0 - U+122bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+122c0 - U+122df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+122e0 - U+122ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12300 - U+1231f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12320 - U+1233f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12340 - U+1235f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12360 - U+1237f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12380 - U+1239f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+123a0 - U+123bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+123c0 - U+123df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+123e0 - U+123ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12400 - U+1241f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12420 - U+1243f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12440 - U+1245f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12460 - U+1247f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12480 - U+1249f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+124a0 - U+124bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+124c0 - U+124df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+124e0 - U+124ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12500 - U+1251f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12520 - U+1253f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12540 - U+1255f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12560 - U+1257f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12580 - U+1259f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+125a0 - U+125bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+125c0 - U+125df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+125e0 - U+125ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12600 - U+1261f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12620 - U+1263f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12640 - U+1265f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12660 - U+1267f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12680 - U+1269f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+126a0 - U+126bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+126c0 - U+126df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+126e0 - U+126ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12700 - U+1271f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12720 - U+1273f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12740 - U+1275f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12760 - U+1277f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12780 - U+1279f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+127a0 - U+127bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+127c0 - U+127df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+127e0 - U+127ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12800 - U+1281f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12820 - U+1283f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12840 - U+1285f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12860 - U+1287f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12880 - U+1289f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+128a0 - U+128bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+128c0 - U+128df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+128e0 - U+128ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12900 - U+1291f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12920 - U+1293f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12940 - U+1295f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12960 - U+1297f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12980 - U+1299f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+129a0 - U+129bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+129c0 - U+129df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+129e0 - U+129ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12a00 - U+12a1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12a20 - U+12a3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12a40 - U+12a5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12a60 - U+12a7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12a80 - U+12a9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12aa0 - U+12abf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12ac0 - U+12adf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12ae0 - U+12aff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12b00 - U+12b1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12b20 - U+12b3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12b40 - U+12b5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12b60 - U+12b7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12b80 - U+12b9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12ba0 - U+12bbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12bc0 - U+12bdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12be0 - U+12bff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12c00 - U+12c1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12c20 - U+12c3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12c40 - U+12c5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12c60 - U+12c7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12c80 - U+12c9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12ca0 - U+12cbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12cc0 - U+12cdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12ce0 - U+12cff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12d00 - U+12d1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12d20 - U+12d3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12d40 - U+12d5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12d60 - U+12d7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12d80 - U+12d9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12da0 - U+12dbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12dc0 - U+12ddf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12de0 - U+12dff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12e00 - U+12e1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12e20 - U+12e3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12e40 - U+12e5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12e60 - U+12e7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12e80 - U+12e9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12ea0 - U+12ebf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12ec0 - U+12edf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12ee0 - U+12eff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12f00 - U+12f1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12f20 - U+12f3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12f40 - U+12f5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12f60 - U+12f7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12f80 - U+12f9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12fa0 - U+12fbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12fc0 - U+12fdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+12fe0 - U+12fff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13000 - U+1301f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13020 - U+1303f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13040 - U+1305f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13060 - U+1307f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13080 - U+1309f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+130a0 - U+130bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+130c0 - U+130df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+130e0 - U+130ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13100 - U+1311f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13120 - U+1313f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13140 - U+1315f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13160 - U+1317f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13180 - U+1319f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+131a0 - U+131bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+131c0 - U+131df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+131e0 - U+131ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13200 - U+1321f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13220 - U+1323f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13240 - U+1325f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13260 - U+1327f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13280 - U+1329f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+132a0 - U+132bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+132c0 - U+132df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+132e0 - U+132ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13300 - U+1331f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13320 - U+1333f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13340 - U+1335f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13360 - U+1337f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13380 - U+1339f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+133a0 - U+133bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+133c0 - U+133df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+133e0 - U+133ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13400 - U+1341f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13420 - U+1343f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13440 - U+1345f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13460 - U+1347f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13480 - U+1349f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+134a0 - U+134bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+134c0 - U+134df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+134e0 - U+134ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13500 - U+1351f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13520 - U+1353f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13540 - U+1355f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13560 - U+1357f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13580 - U+1359f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+135a0 - U+135bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+135c0 - U+135df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+135e0 - U+135ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13600 - U+1361f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13620 - U+1363f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13640 - U+1365f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13660 - U+1367f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13680 - U+1369f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+136a0 - U+136bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+136c0 - U+136df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+136e0 - U+136ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13700 - U+1371f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13720 - U+1373f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13740 - U+1375f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13760 - U+1377f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13780 - U+1379f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+137a0 - U+137bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+137c0 - U+137df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+137e0 - U+137ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13800 - U+1381f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13820 - U+1383f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13840 - U+1385f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13860 - U+1387f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13880 - U+1389f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+138a0 - U+138bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+138c0 - U+138df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+138e0 - U+138ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13900 - U+1391f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13920 - U+1393f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13940 - U+1395f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13960 - U+1397f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13980 - U+1399f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+139a0 - U+139bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+139c0 - U+139df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+139e0 - U+139ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13a00 - U+13a1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13a20 - U+13a3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13a40 - U+13a5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13a60 - U+13a7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13a80 - U+13a9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13aa0 - U+13abf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13ac0 - U+13adf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13ae0 - U+13aff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13b00 - U+13b1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13b20 - U+13b3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13b40 - U+13b5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13b60 - U+13b7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13b80 - U+13b9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13ba0 - U+13bbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13bc0 - U+13bdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13be0 - U+13bff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13c00 - U+13c1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13c20 - U+13c3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13c40 - U+13c5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13c60 - U+13c7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13c80 - U+13c9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13ca0 - U+13cbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13cc0 - U+13cdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13ce0 - U+13cff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13d00 - U+13d1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13d20 - U+13d3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13d40 - U+13d5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13d60 - U+13d7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13d80 - U+13d9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13da0 - U+13dbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13dc0 - U+13ddf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13de0 - U+13dff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13e00 - U+13e1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13e20 - U+13e3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13e40 - U+13e5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13e60 - U+13e7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13e80 - U+13e9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13ea0 - U+13ebf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13ec0 - U+13edf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13ee0 - U+13eff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13f00 - U+13f1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13f20 - U+13f3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13f40 - U+13f5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13f60 - U+13f7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13f80 - U+13f9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13fa0 - U+13fbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13fc0 - U+13fdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+13fe0 - U+13fff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14000 - U+1401f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14020 - U+1403f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14040 - U+1405f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14060 - U+1407f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14080 - U+1409f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+140a0 - U+140bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+140c0 - U+140df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+140e0 - U+140ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14100 - U+1411f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14120 - U+1413f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14140 - U+1415f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14160 - U+1417f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14180 - U+1419f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+141a0 - U+141bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+141c0 - U+141df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+141e0 - U+141ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14200 - U+1421f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14220 - U+1423f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14240 - U+1425f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14260 - U+1427f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14280 - U+1429f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+142a0 - U+142bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+142c0 - U+142df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+142e0 - U+142ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14300 - U+1431f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14320 - U+1433f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14340 - U+1435f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14360 - U+1437f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14380 - U+1439f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+143a0 - U+143bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+143c0 - U+143df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+143e0 - U+143ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14400 - U+1441f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14420 - U+1443f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14440 - U+1445f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14460 - U+1447f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14480 - U+1449f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+144a0 - U+144bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+144c0 - U+144df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+144e0 - U+144ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14500 - U+1451f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14520 - U+1453f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14540 - U+1455f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14560 - U+1457f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14580 - U+1459f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+145a0 - U+145bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+145c0 - U+145df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+145e0 - U+145ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14600 - U+1461f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14620 - U+1463f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14640 - U+1465f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14660 - U+1467f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14680 - U+1469f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+146a0 - U+146bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+146c0 - U+146df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+146e0 - U+146ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14700 - U+1471f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14720 - U+1473f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14740 - U+1475f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14760 - U+1477f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14780 - U+1479f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+147a0 - U+147bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+147c0 - U+147df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+147e0 - U+147ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14800 - U+1481f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14820 - U+1483f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14840 - U+1485f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14860 - U+1487f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14880 - U+1489f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+148a0 - U+148bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+148c0 - U+148df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+148e0 - U+148ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14900 - U+1491f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14920 - U+1493f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14940 - U+1495f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14960 - U+1497f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14980 - U+1499f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+149a0 - U+149bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+149c0 - U+149df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+149e0 - U+149ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14a00 - U+14a1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14a20 - U+14a3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14a40 - U+14a5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14a60 - U+14a7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14a80 - U+14a9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14aa0 - U+14abf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14ac0 - U+14adf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14ae0 - U+14aff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14b00 - U+14b1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14b20 - U+14b3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14b40 - U+14b5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14b60 - U+14b7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14b80 - U+14b9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14ba0 - U+14bbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14bc0 - U+14bdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14be0 - U+14bff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14c00 - U+14c1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14c20 - U+14c3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14c40 - U+14c5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14c60 - U+14c7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14c80 - U+14c9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14ca0 - U+14cbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14cc0 - U+14cdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14ce0 - U+14cff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14d00 - U+14d1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14d20 - U+14d3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14d40 - U+14d5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14d60 - U+14d7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14d80 - U+14d9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14da0 - U+14dbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14dc0 - U+14ddf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14de0 - U+14dff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14e00 - U+14e1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14e20 - U+14e3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14e40 - U+14e5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14e60 - U+14e7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14e80 - U+14e9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14ea0 - U+14ebf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14ec0 - U+14edf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14ee0 - U+14eff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14f00 - U+14f1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14f20 - U+14f3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14f40 - U+14f5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14f60 - U+14f7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14f80 - U+14f9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14fa0 - U+14fbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14fc0 - U+14fdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+14fe0 - U+14fff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15000 - U+1501f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15020 - U+1503f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15040 - U+1505f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15060 - U+1507f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15080 - U+1509f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+150a0 - U+150bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+150c0 - U+150df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+150e0 - U+150ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15100 - U+1511f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15120 - U+1513f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15140 - U+1515f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15160 - U+1517f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15180 - U+1519f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+151a0 - U+151bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+151c0 - U+151df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+151e0 - U+151ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15200 - U+1521f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15220 - U+1523f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15240 - U+1525f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15260 - U+1527f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15280 - U+1529f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+152a0 - U+152bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+152c0 - U+152df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+152e0 - U+152ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15300 - U+1531f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15320 - U+1533f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15340 - U+1535f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15360 - U+1537f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15380 - U+1539f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+153a0 - U+153bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+153c0 - U+153df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+153e0 - U+153ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15400 - U+1541f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15420 - U+1543f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15440 - U+1545f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15460 - U+1547f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15480 - U+1549f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+154a0 - U+154bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+154c0 - U+154df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+154e0 - U+154ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15500 - U+1551f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15520 - U+1553f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15540 - U+1555f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15560 - U+1557f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15580 - U+1559f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+155a0 - U+155bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+155c0 - U+155df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+155e0 - U+155ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15600 - U+1561f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15620 - U+1563f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15640 - U+1565f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15660 - U+1567f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15680 - U+1569f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+156a0 - U+156bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+156c0 - U+156df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+156e0 - U+156ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15700 - U+1571f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15720 - U+1573f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15740 - U+1575f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15760 - U+1577f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15780 - U+1579f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+157a0 - U+157bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+157c0 - U+157df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+157e0 - U+157ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15800 - U+1581f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15820 - U+1583f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15840 - U+1585f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15860 - U+1587f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15880 - U+1589f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+158a0 - U+158bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+158c0 - U+158df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+158e0 - U+158ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15900 - U+1591f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15920 - U+1593f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15940 - U+1595f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15960 - U+1597f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15980 - U+1599f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+159a0 - U+159bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+159c0 - U+159df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+159e0 - U+159ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15a00 - U+15a1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15a20 - U+15a3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15a40 - U+15a5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15a60 - U+15a7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15a80 - U+15a9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15aa0 - U+15abf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15ac0 - U+15adf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15ae0 - U+15aff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15b00 - U+15b1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15b20 - U+15b3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15b40 - U+15b5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15b60 - U+15b7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15b80 - U+15b9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15ba0 - U+15bbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15bc0 - U+15bdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15be0 - U+15bff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15c00 - U+15c1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15c20 - U+15c3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15c40 - U+15c5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15c60 - U+15c7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15c80 - U+15c9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15ca0 - U+15cbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15cc0 - U+15cdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15ce0 - U+15cff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15d00 - U+15d1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15d20 - U+15d3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15d40 - U+15d5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15d60 - U+15d7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15d80 - U+15d9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15da0 - U+15dbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15dc0 - U+15ddf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15de0 - U+15dff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15e00 - U+15e1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15e20 - U+15e3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15e40 - U+15e5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15e60 - U+15e7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15e80 - U+15e9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15ea0 - U+15ebf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15ec0 - U+15edf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15ee0 - U+15eff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15f00 - U+15f1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15f20 - U+15f3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15f40 - U+15f5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15f60 - U+15f7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15f80 - U+15f9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15fa0 - U+15fbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15fc0 - U+15fdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+15fe0 - U+15fff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16000 - U+1601f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16020 - U+1603f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16040 - U+1605f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16060 - U+1607f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16080 - U+1609f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+160a0 - U+160bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+160c0 - U+160df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+160e0 - U+160ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16100 - U+1611f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16120 - U+1613f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16140 - U+1615f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16160 - U+1617f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16180 - U+1619f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+161a0 - U+161bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+161c0 - U+161df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+161e0 - U+161ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16200 - U+1621f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16220 - U+1623f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16240 - U+1625f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16260 - U+1627f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16280 - U+1629f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+162a0 - U+162bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+162c0 - U+162df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+162e0 - U+162ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16300 - U+1631f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16320 - U+1633f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16340 - U+1635f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16360 - U+1637f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16380 - U+1639f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+163a0 - U+163bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+163c0 - U+163df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+163e0 - U+163ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16400 - U+1641f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16420 - U+1643f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16440 - U+1645f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16460 - U+1647f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16480 - U+1649f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+164a0 - U+164bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+164c0 - U+164df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+164e0 - U+164ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16500 - U+1651f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16520 - U+1653f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16540 - U+1655f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16560 - U+1657f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16580 - U+1659f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+165a0 - U+165bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+165c0 - U+165df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+165e0 - U+165ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16600 - U+1661f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16620 - U+1663f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16640 - U+1665f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16660 - U+1667f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16680 - U+1669f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+166a0 - U+166bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+166c0 - U+166df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+166e0 - U+166ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16700 - U+1671f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16720 - U+1673f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16740 - U+1675f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16760 - U+1677f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16780 - U+1679f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+167a0 - U+167bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+167c0 - U+167df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+167e0 - U+167ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16800 - U+1681f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16820 - U+1683f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16840 - U+1685f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16860 - U+1687f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16880 - U+1689f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+168a0 - U+168bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+168c0 - U+168df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+168e0 - U+168ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16900 - U+1691f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16920 - U+1693f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16940 - U+1695f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16960 - U+1697f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16980 - U+1699f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+169a0 - U+169bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+169c0 - U+169df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+169e0 - U+169ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16a00 - U+16a1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16a20 - U+16a3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16a40 - U+16a5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16a60 - U+16a7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16a80 - U+16a9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16aa0 - U+16abf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16ac0 - U+16adf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16ae0 - U+16aff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16b00 - U+16b1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16b20 - U+16b3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16b40 - U+16b5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16b60 - U+16b7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16b80 - U+16b9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16ba0 - U+16bbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16bc0 - U+16bdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16be0 - U+16bff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16c00 - U+16c1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16c20 - U+16c3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16c40 - U+16c5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16c60 - U+16c7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16c80 - U+16c9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16ca0 - U+16cbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16cc0 - U+16cdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16ce0 - U+16cff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16d00 - U+16d1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16d20 - U+16d3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16d40 - U+16d5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16d60 - U+16d7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16d80 - U+16d9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16da0 - U+16dbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16dc0 - U+16ddf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16de0 - U+16dff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16e00 - U+16e1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16e20 - U+16e3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16e40 - U+16e5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16e60 - U+16e7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16e80 - U+16e9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16ea0 - U+16ebf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16ec0 - U+16edf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16ee0 - U+16eff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16f00 - U+16f1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16f20 - U+16f3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16f40 - U+16f5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16f60 - U+16f7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16f80 - U+16f9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16fa0 - U+16fbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16fc0 - U+16fdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+16fe0 - U+16fff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17000 - U+1701f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17020 - U+1703f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17040 - U+1705f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17060 - U+1707f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17080 - U+1709f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+170a0 - U+170bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+170c0 - U+170df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+170e0 - U+170ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17100 - U+1711f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17120 - U+1713f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17140 - U+1715f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17160 - U+1717f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17180 - U+1719f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+171a0 - U+171bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+171c0 - U+171df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+171e0 - U+171ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17200 - U+1721f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17220 - U+1723f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17240 - U+1725f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17260 - U+1727f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17280 - U+1729f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+172a0 - U+172bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+172c0 - U+172df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+172e0 - U+172ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17300 - U+1731f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17320 - U+1733f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17340 - U+1735f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17360 - U+1737f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17380 - U+1739f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+173a0 - U+173bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+173c0 - U+173df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+173e0 - U+173ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17400 - U+1741f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17420 - U+1743f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17440 - U+1745f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17460 - U+1747f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17480 - U+1749f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+174a0 - U+174bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+174c0 - U+174df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+174e0 - U+174ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17500 - U+1751f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17520 - U+1753f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17540 - U+1755f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17560 - U+1757f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17580 - U+1759f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+175a0 - U+175bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+175c0 - U+175df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+175e0 - U+175ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17600 - U+1761f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17620 - U+1763f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17640 - U+1765f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17660 - U+1767f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17680 - U+1769f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+176a0 - U+176bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+176c0 - U+176df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+176e0 - U+176ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17700 - U+1771f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17720 - U+1773f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17740 - U+1775f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17760 - U+1777f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17780 - U+1779f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+177a0 - U+177bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+177c0 - U+177df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+177e0 - U+177ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17800 - U+1781f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17820 - U+1783f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17840 - U+1785f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17860 - U+1787f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17880 - U+1789f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+178a0 - U+178bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+178c0 - U+178df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+178e0 - U+178ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17900 - U+1791f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17920 - U+1793f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17940 - U+1795f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17960 - U+1797f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17980 - U+1799f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+179a0 - U+179bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+179c0 - U+179df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+179e0 - U+179ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17a00 - U+17a1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17a20 - U+17a3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17a40 - U+17a5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17a60 - U+17a7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17a80 - U+17a9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17aa0 - U+17abf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17ac0 - U+17adf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17ae0 - U+17aff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17b00 - U+17b1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17b20 - U+17b3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17b40 - U+17b5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17b60 - U+17b7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17b80 - U+17b9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17ba0 - U+17bbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17bc0 - U+17bdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17be0 - U+17bff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17c00 - U+17c1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17c20 - U+17c3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17c40 - U+17c5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17c60 - U+17c7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17c80 - U+17c9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17ca0 - U+17cbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17cc0 - U+17cdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17ce0 - U+17cff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17d00 - U+17d1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17d20 - U+17d3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17d40 - U+17d5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17d60 - U+17d7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17d80 - U+17d9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17da0 - U+17dbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17dc0 - U+17ddf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17de0 - U+17dff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17e00 - U+17e1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17e20 - U+17e3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17e40 - U+17e5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17e60 - U+17e7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17e80 - U+17e9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17ea0 - U+17ebf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17ec0 - U+17edf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17ee0 - U+17eff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17f00 - U+17f1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17f20 - U+17f3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17f40 - U+17f5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17f60 - U+17f7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17f80 - U+17f9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17fa0 - U+17fbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17fc0 - U+17fdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+17fe0 - U+17fff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18000 - U+1801f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18020 - U+1803f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18040 - U+1805f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18060 - U+1807f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18080 - U+1809f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+180a0 - U+180bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+180c0 - U+180df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+180e0 - U+180ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18100 - U+1811f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18120 - U+1813f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18140 - U+1815f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18160 - U+1817f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18180 - U+1819f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+181a0 - U+181bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+181c0 - U+181df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+181e0 - U+181ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18200 - U+1821f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18220 - U+1823f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18240 - U+1825f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18260 - U+1827f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18280 - U+1829f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+182a0 - U+182bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+182c0 - U+182df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+182e0 - U+182ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18300 - U+1831f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18320 - U+1833f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18340 - U+1835f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18360 - U+1837f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18380 - U+1839f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+183a0 - U+183bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+183c0 - U+183df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+183e0 - U+183ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18400 - U+1841f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18420 - U+1843f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18440 - U+1845f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18460 - U+1847f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18480 - U+1849f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+184a0 - U+184bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+184c0 - U+184df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+184e0 - U+184ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18500 - U+1851f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18520 - U+1853f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18540 - U+1855f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18560 - U+1857f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18580 - U+1859f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+185a0 - U+185bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+185c0 - U+185df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+185e0 - U+185ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18600 - U+1861f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18620 - U+1863f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18640 - U+1865f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18660 - U+1867f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18680 - U+1869f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+186a0 - U+186bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+186c0 - U+186df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+186e0 - U+186ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18700 - U+1871f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18720 - U+1873f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18740 - U+1875f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18760 - U+1877f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18780 - U+1879f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+187a0 - U+187bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+187c0 - U+187df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+187e0 - U+187ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18800 - U+1881f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18820 - U+1883f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18840 - U+1885f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18860 - U+1887f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18880 - U+1889f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+188a0 - U+188bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+188c0 - U+188df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+188e0 - U+188ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18900 - U+1891f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18920 - U+1893f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18940 - U+1895f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18960 - U+1897f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18980 - U+1899f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+189a0 - U+189bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+189c0 - U+189df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+189e0 - U+189ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18a00 - U+18a1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18a20 - U+18a3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18a40 - U+18a5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18a60 - U+18a7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18a80 - U+18a9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18aa0 - U+18abf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18ac0 - U+18adf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18ae0 - U+18aff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18b00 - U+18b1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18b20 - U+18b3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18b40 - U+18b5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18b60 - U+18b7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18b80 - U+18b9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18ba0 - U+18bbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18bc0 - U+18bdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18be0 - U+18bff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18c00 - U+18c1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18c20 - U+18c3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18c40 - U+18c5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18c60 - U+18c7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18c80 - U+18c9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18ca0 - U+18cbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18cc0 - U+18cdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18ce0 - U+18cff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18d00 - U+18d1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18d20 - U+18d3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18d40 - U+18d5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18d60 - U+18d7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18d80 - U+18d9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18da0 - U+18dbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18dc0 - U+18ddf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18de0 - U+18dff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18e00 - U+18e1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18e20 - U+18e3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18e40 - U+18e5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18e60 - U+18e7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18e80 - U+18e9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18ea0 - U+18ebf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18ec0 - U+18edf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18ee0 - U+18eff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18f00 - U+18f1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18f20 - U+18f3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18f40 - U+18f5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18f60 - U+18f7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18f80 - U+18f9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18fa0 - U+18fbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18fc0 - U+18fdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+18fe0 - U+18fff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19000 - U+1901f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19020 - U+1903f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19040 - U+1905f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19060 - U+1907f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19080 - U+1909f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+190a0 - U+190bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+190c0 - U+190df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+190e0 - U+190ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19100 - U+1911f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19120 - U+1913f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19140 - U+1915f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19160 - U+1917f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19180 - U+1919f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+191a0 - U+191bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+191c0 - U+191df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+191e0 - U+191ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19200 - U+1921f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19220 - U+1923f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19240 - U+1925f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19260 - U+1927f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19280 - U+1929f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+192a0 - U+192bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+192c0 - U+192df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+192e0 - U+192ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19300 - U+1931f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19320 - U+1933f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19340 - U+1935f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19360 - U+1937f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19380 - U+1939f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+193a0 - U+193bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+193c0 - U+193df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+193e0 - U+193ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19400 - U+1941f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19420 - U+1943f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19440 - U+1945f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19460 - U+1947f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19480 - U+1949f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+194a0 - U+194bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+194c0 - U+194df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+194e0 - U+194ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19500 - U+1951f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19520 - U+1953f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19540 - U+1955f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19560 - U+1957f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19580 - U+1959f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+195a0 - U+195bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+195c0 - U+195df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+195e0 - U+195ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19600 - U+1961f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19620 - U+1963f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19640 - U+1965f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19660 - U+1967f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19680 - U+1969f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+196a0 - U+196bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+196c0 - U+196df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+196e0 - U+196ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19700 - U+1971f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19720 - U+1973f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19740 - U+1975f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19760 - U+1977f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19780 - U+1979f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+197a0 - U+197bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+197c0 - U+197df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+197e0 - U+197ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19800 - U+1981f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19820 - U+1983f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19840 - U+1985f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19860 - U+1987f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19880 - U+1989f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+198a0 - U+198bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+198c0 - U+198df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+198e0 - U+198ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19900 - U+1991f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19920 - U+1993f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19940 - U+1995f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19960 - U+1997f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19980 - U+1999f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+199a0 - U+199bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+199c0 - U+199df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+199e0 - U+199ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19a00 - U+19a1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19a20 - U+19a3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19a40 - U+19a5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19a60 - U+19a7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19a80 - U+19a9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19aa0 - U+19abf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19ac0 - U+19adf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19ae0 - U+19aff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19b00 - U+19b1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19b20 - U+19b3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19b40 - U+19b5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19b60 - U+19b7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19b80 - U+19b9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19ba0 - U+19bbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19bc0 - U+19bdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19be0 - U+19bff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19c00 - U+19c1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19c20 - U+19c3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19c40 - U+19c5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19c60 - U+19c7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19c80 - U+19c9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19ca0 - U+19cbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19cc0 - U+19cdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19ce0 - U+19cff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19d00 - U+19d1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19d20 - U+19d3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19d40 - U+19d5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19d60 - U+19d7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19d80 - U+19d9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19da0 - U+19dbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19dc0 - U+19ddf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19de0 - U+19dff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19e00 - U+19e1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19e20 - U+19e3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19e40 - U+19e5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19e60 - U+19e7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19e80 - U+19e9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19ea0 - U+19ebf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19ec0 - U+19edf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19ee0 - U+19eff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19f00 - U+19f1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19f20 - U+19f3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19f40 - U+19f5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19f60 - U+19f7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19f80 - U+19f9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19fa0 - U+19fbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19fc0 - U+19fdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+19fe0 - U+19fff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a000 - U+1a01f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a020 - U+1a03f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a040 - U+1a05f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a060 - U+1a07f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a080 - U+1a09f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a0a0 - U+1a0bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a0c0 - U+1a0df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a0e0 - U+1a0ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a100 - U+1a11f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a120 - U+1a13f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a140 - U+1a15f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a160 - U+1a17f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a180 - U+1a19f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a1a0 - U+1a1bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a1c0 - U+1a1df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a1e0 - U+1a1ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a200 - U+1a21f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a220 - U+1a23f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a240 - U+1a25f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a260 - U+1a27f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a280 - U+1a29f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a2a0 - U+1a2bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a2c0 - U+1a2df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a2e0 - U+1a2ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a300 - U+1a31f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a320 - U+1a33f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a340 - U+1a35f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a360 - U+1a37f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a380 - U+1a39f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a3a0 - U+1a3bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a3c0 - U+1a3df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a3e0 - U+1a3ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a400 - U+1a41f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a420 - U+1a43f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a440 - U+1a45f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a460 - U+1a47f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a480 - U+1a49f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a4a0 - U+1a4bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a4c0 - U+1a4df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a4e0 - U+1a4ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a500 - U+1a51f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a520 - U+1a53f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a540 - U+1a55f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a560 - U+1a57f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a580 - U+1a59f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a5a0 - U+1a5bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a5c0 - U+1a5df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a5e0 - U+1a5ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a600 - U+1a61f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a620 - U+1a63f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a640 - U+1a65f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a660 - U+1a67f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a680 - U+1a69f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a6a0 - U+1a6bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a6c0 - U+1a6df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a6e0 - U+1a6ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a700 - U+1a71f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a720 - U+1a73f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a740 - U+1a75f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a760 - U+1a77f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a780 - U+1a79f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a7a0 - U+1a7bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a7c0 - U+1a7df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a7e0 - U+1a7ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a800 - U+1a81f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a820 - U+1a83f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a840 - U+1a85f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a860 - U+1a87f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a880 - U+1a89f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a8a0 - U+1a8bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a8c0 - U+1a8df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a8e0 - U+1a8ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a900 - U+1a91f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a920 - U+1a93f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a940 - U+1a95f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a960 - U+1a97f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a980 - U+1a99f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a9a0 - U+1a9bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a9c0 - U+1a9df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1a9e0 - U+1a9ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aa00 - U+1aa1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aa20 - U+1aa3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aa40 - U+1aa5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aa60 - U+1aa7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aa80 - U+1aa9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aaa0 - U+1aabf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aac0 - U+1aadf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aae0 - U+1aaff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ab00 - U+1ab1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ab20 - U+1ab3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ab40 - U+1ab5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ab60 - U+1ab7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ab80 - U+1ab9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aba0 - U+1abbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1abc0 - U+1abdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1abe0 - U+1abff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ac00 - U+1ac1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ac20 - U+1ac3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ac40 - U+1ac5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ac60 - U+1ac7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ac80 - U+1ac9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aca0 - U+1acbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1acc0 - U+1acdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ace0 - U+1acff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ad00 - U+1ad1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ad20 - U+1ad3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ad40 - U+1ad5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ad60 - U+1ad7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ad80 - U+1ad9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ada0 - U+1adbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1adc0 - U+1addf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ade0 - U+1adff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ae00 - U+1ae1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ae20 - U+1ae3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ae40 - U+1ae5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ae60 - U+1ae7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ae80 - U+1ae9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aea0 - U+1aebf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aec0 - U+1aedf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1aee0 - U+1aeff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1af00 - U+1af1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1af20 - U+1af3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1af40 - U+1af5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1af60 - U+1af7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1af80 - U+1af9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1afa0 - U+1afbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1afc0 - U+1afdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1afe0 - U+1afff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b000 - U+1b01f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b020 - U+1b03f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b040 - U+1b05f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b060 - U+1b07f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b080 - U+1b09f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b0a0 - U+1b0bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b0c0 - U+1b0df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b0e0 - U+1b0ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b100 - U+1b11f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b120 - U+1b13f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b140 - U+1b15f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b160 - U+1b17f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b180 - U+1b19f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b1a0 - U+1b1bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b1c0 - U+1b1df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b1e0 - U+1b1ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b200 - U+1b21f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b220 - U+1b23f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b240 - U+1b25f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b260 - U+1b27f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b280 - U+1b29f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b2a0 - U+1b2bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b2c0 - U+1b2df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b2e0 - U+1b2ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b300 - U+1b31f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b320 - U+1b33f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b340 - U+1b35f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b360 - U+1b37f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b380 - U+1b39f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b3a0 - U+1b3bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b3c0 - U+1b3df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b3e0 - U+1b3ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b400 - U+1b41f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b420 - U+1b43f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b440 - U+1b45f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b460 - U+1b47f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b480 - U+1b49f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b4a0 - U+1b4bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b4c0 - U+1b4df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b4e0 - U+1b4ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b500 - U+1b51f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b520 - U+1b53f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b540 - U+1b55f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b560 - U+1b57f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b580 - U+1b59f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b5a0 - U+1b5bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b5c0 - U+1b5df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b5e0 - U+1b5ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b600 - U+1b61f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b620 - U+1b63f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b640 - U+1b65f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b660 - U+1b67f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b680 - U+1b69f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b6a0 - U+1b6bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b6c0 - U+1b6df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b6e0 - U+1b6ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b700 - U+1b71f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b720 - U+1b73f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b740 - U+1b75f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b760 - U+1b77f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b780 - U+1b79f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b7a0 - U+1b7bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b7c0 - U+1b7df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b7e0 - U+1b7ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b800 - U+1b81f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b820 - U+1b83f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b840 - U+1b85f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b860 - U+1b87f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b880 - U+1b89f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b8a0 - U+1b8bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b8c0 - U+1b8df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b8e0 - U+1b8ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b900 - U+1b91f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b920 - U+1b93f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b940 - U+1b95f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b960 - U+1b97f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b980 - U+1b99f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b9a0 - U+1b9bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b9c0 - U+1b9df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1b9e0 - U+1b9ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ba00 - U+1ba1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ba20 - U+1ba3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ba40 - U+1ba5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ba60 - U+1ba7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ba80 - U+1ba9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1baa0 - U+1babf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bac0 - U+1badf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bae0 - U+1baff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bb00 - U+1bb1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bb20 - U+1bb3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bb40 - U+1bb5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bb60 - U+1bb7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bb80 - U+1bb9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bba0 - U+1bbbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bbc0 - U+1bbdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bbe0 - U+1bbff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bc00 - U+1bc1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bc20 - U+1bc3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bc40 - U+1bc5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bc60 - U+1bc7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bc80 - U+1bc9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bca0 - U+1bcbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bcc0 - U+1bcdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bce0 - U+1bcff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bd00 - U+1bd1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bd20 - U+1bd3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bd40 - U+1bd5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bd60 - U+1bd7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bd80 - U+1bd9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bda0 - U+1bdbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bdc0 - U+1bddf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bde0 - U+1bdff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1be00 - U+1be1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1be20 - U+1be3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1be40 - U+1be5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1be60 - U+1be7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1be80 - U+1be9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bea0 - U+1bebf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bec0 - U+1bedf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bee0 - U+1beff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bf00 - U+1bf1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bf20 - U+1bf3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bf40 - U+1bf5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bf60 - U+1bf7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bf80 - U+1bf9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bfa0 - U+1bfbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bfc0 - U+1bfdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1bfe0 - U+1bfff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c000 - U+1c01f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c020 - U+1c03f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c040 - U+1c05f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c060 - U+1c07f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c080 - U+1c09f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c0a0 - U+1c0bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c0c0 - U+1c0df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c0e0 - U+1c0ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c100 - U+1c11f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c120 - U+1c13f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c140 - U+1c15f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c160 - U+1c17f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c180 - U+1c19f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c1a0 - U+1c1bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c1c0 - U+1c1df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c1e0 - U+1c1ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c200 - U+1c21f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c220 - U+1c23f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c240 - U+1c25f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c260 - U+1c27f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c280 - U+1c29f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c2a0 - U+1c2bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c2c0 - U+1c2df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c2e0 - U+1c2ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c300 - U+1c31f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c320 - U+1c33f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c340 - U+1c35f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c360 - U+1c37f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c380 - U+1c39f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c3a0 - U+1c3bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c3c0 - U+1c3df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c3e0 - U+1c3ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c400 - U+1c41f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c420 - U+1c43f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c440 - U+1c45f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c460 - U+1c47f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c480 - U+1c49f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c4a0 - U+1c4bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c4c0 - U+1c4df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c4e0 - U+1c4ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c500 - U+1c51f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c520 - U+1c53f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c540 - U+1c55f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c560 - U+1c57f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c580 - U+1c59f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c5a0 - U+1c5bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c5c0 - U+1c5df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c5e0 - U+1c5ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c600 - U+1c61f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c620 - U+1c63f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c640 - U+1c65f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c660 - U+1c67f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c680 - U+1c69f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c6a0 - U+1c6bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c6c0 - U+1c6df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c6e0 - U+1c6ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c700 - U+1c71f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c720 - U+1c73f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c740 - U+1c75f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c760 - U+1c77f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c780 - U+1c79f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c7a0 - U+1c7bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c7c0 - U+1c7df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c7e0 - U+1c7ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c800 - U+1c81f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c820 - U+1c83f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c840 - U+1c85f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c860 - U+1c87f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c880 - U+1c89f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c8a0 - U+1c8bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c8c0 - U+1c8df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c8e0 - U+1c8ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c900 - U+1c91f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c920 - U+1c93f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c940 - U+1c95f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c960 - U+1c97f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c980 - U+1c99f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c9a0 - U+1c9bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c9c0 - U+1c9df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1c9e0 - U+1c9ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ca00 - U+1ca1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ca20 - U+1ca3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ca40 - U+1ca5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ca60 - U+1ca7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ca80 - U+1ca9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1caa0 - U+1cabf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cac0 - U+1cadf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cae0 - U+1caff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cb00 - U+1cb1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cb20 - U+1cb3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cb40 - U+1cb5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cb60 - U+1cb7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cb80 - U+1cb9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cba0 - U+1cbbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cbc0 - U+1cbdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cbe0 - U+1cbff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cc00 - U+1cc1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cc20 - U+1cc3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cc40 - U+1cc5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cc60 - U+1cc7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cc80 - U+1cc9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cca0 - U+1ccbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ccc0 - U+1ccdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cce0 - U+1ccff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cd00 - U+1cd1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cd20 - U+1cd3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cd40 - U+1cd5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cd60 - U+1cd7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cd80 - U+1cd9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cda0 - U+1cdbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cdc0 - U+1cddf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cde0 - U+1cdff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ce00 - U+1ce1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ce20 - U+1ce3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ce40 - U+1ce5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ce60 - U+1ce7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ce80 - U+1ce9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cea0 - U+1cebf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cec0 - U+1cedf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cee0 - U+1ceff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cf00 - U+1cf1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cf20 - U+1cf3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cf40 - U+1cf5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cf60 - U+1cf7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cf80 - U+1cf9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cfa0 - U+1cfbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cfc0 - U+1cfdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1cfe0 - U+1cfff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d000 - U+1d01f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d020 - U+1d03f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d040 - U+1d05f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d060 - U+1d07f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d080 - U+1d09f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d0a0 - U+1d0bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d0c0 - U+1d0df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d0e0 - U+1d0ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d100 - U+1d11f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d120 - U+1d13f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d140 - U+1d15f */
+  0xff,0xfc,0x0f,0xff,0xfc,0x00,0x00,0x00,	/* U+1d160 - U+1d17f */
+  0x03,0xc0,0x00,0xff,0xff,0xff,0xff,0xff,	/* U+1d180 - U+1d19f */
+  0xff,0xff,0xf0,0x0f,0xff,0xff,0xff,0xff,	/* U+1d1a0 - U+1d1bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d1c0 - U+1d1df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d1e0 - U+1d1ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d200 - U+1d21f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d220 - U+1d23f */
+  0xf0,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d240 - U+1d25f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d260 - U+1d27f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d280 - U+1d29f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d2a0 - U+1d2bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d2c0 - U+1d2df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d2e0 - U+1d2ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d300 - U+1d31f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d320 - U+1d33f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d340 - U+1d35f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d360 - U+1d37f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d380 - U+1d39f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d3a0 - U+1d3bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d3c0 - U+1d3df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d3e0 - U+1d3ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d400 - U+1d41f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d420 - U+1d43f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d440 - U+1d45f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d460 - U+1d47f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d480 - U+1d49f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d4a0 - U+1d4bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d4c0 - U+1d4df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d4e0 - U+1d4ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d500 - U+1d51f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d520 - U+1d53f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d540 - U+1d55f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d560 - U+1d57f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d580 - U+1d59f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d5a0 - U+1d5bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d5c0 - U+1d5df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d5e0 - U+1d5ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d600 - U+1d61f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d620 - U+1d63f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d640 - U+1d65f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d660 - U+1d67f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d680 - U+1d69f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d6a0 - U+1d6bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d6c0 - U+1d6df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d6e0 - U+1d6ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d700 - U+1d71f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d720 - U+1d73f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d740 - U+1d75f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d760 - U+1d77f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d780 - U+1d79f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d7a0 - U+1d7bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d7c0 - U+1d7df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d7e0 - U+1d7ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d800 - U+1d81f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d820 - U+1d83f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d840 - U+1d85f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d860 - U+1d87f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d880 - U+1d89f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d8a0 - U+1d8bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d8c0 - U+1d8df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d8e0 - U+1d8ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d900 - U+1d91f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d920 - U+1d93f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d940 - U+1d95f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d960 - U+1d97f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d980 - U+1d99f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d9a0 - U+1d9bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d9c0 - U+1d9df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1d9e0 - U+1d9ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1da00 - U+1da1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1da20 - U+1da3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1da40 - U+1da5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1da60 - U+1da7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1da80 - U+1da9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1daa0 - U+1dabf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dac0 - U+1dadf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dae0 - U+1daff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1db00 - U+1db1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1db20 - U+1db3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1db40 - U+1db5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1db60 - U+1db7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1db80 - U+1db9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dba0 - U+1dbbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dbc0 - U+1dbdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dbe0 - U+1dbff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dc00 - U+1dc1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dc20 - U+1dc3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dc40 - U+1dc5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dc60 - U+1dc7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dc80 - U+1dc9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dca0 - U+1dcbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dcc0 - U+1dcdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dce0 - U+1dcff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dd00 - U+1dd1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dd20 - U+1dd3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dd40 - U+1dd5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dd60 - U+1dd7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dd80 - U+1dd9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dda0 - U+1ddbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ddc0 - U+1dddf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dde0 - U+1ddff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1de00 - U+1de1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1de20 - U+1de3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1de40 - U+1de5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1de60 - U+1de7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1de80 - U+1de9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dea0 - U+1debf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dec0 - U+1dedf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dee0 - U+1deff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1df00 - U+1df1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1df20 - U+1df3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1df40 - U+1df5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1df60 - U+1df7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1df80 - U+1df9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dfa0 - U+1dfbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dfc0 - U+1dfdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1dfe0 - U+1dfff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e000 - U+1e01f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e020 - U+1e03f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e040 - U+1e05f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e060 - U+1e07f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e080 - U+1e09f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e0a0 - U+1e0bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e0c0 - U+1e0df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e0e0 - U+1e0ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e100 - U+1e11f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e120 - U+1e13f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e140 - U+1e15f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e160 - U+1e17f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e180 - U+1e19f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e1a0 - U+1e1bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e1c0 - U+1e1df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e1e0 - U+1e1ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e200 - U+1e21f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e220 - U+1e23f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e240 - U+1e25f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e260 - U+1e27f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e280 - U+1e29f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e2a0 - U+1e2bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e2c0 - U+1e2df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e2e0 - U+1e2ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e300 - U+1e31f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e320 - U+1e33f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e340 - U+1e35f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e360 - U+1e37f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e380 - U+1e39f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e3a0 - U+1e3bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e3c0 - U+1e3df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e3e0 - U+1e3ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e400 - U+1e41f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e420 - U+1e43f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e440 - U+1e45f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e460 - U+1e47f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e480 - U+1e49f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e4a0 - U+1e4bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e4c0 - U+1e4df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e4e0 - U+1e4ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e500 - U+1e51f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e520 - U+1e53f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e540 - U+1e55f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e560 - U+1e57f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e580 - U+1e59f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e5a0 - U+1e5bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e5c0 - U+1e5df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e5e0 - U+1e5ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e600 - U+1e61f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e620 - U+1e63f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e640 - U+1e65f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e660 - U+1e67f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e680 - U+1e69f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e6a0 - U+1e6bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e6c0 - U+1e6df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e6e0 - U+1e6ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e700 - U+1e71f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e720 - U+1e73f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e740 - U+1e75f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e760 - U+1e77f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e780 - U+1e79f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e7a0 - U+1e7bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e7c0 - U+1e7df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e7e0 - U+1e7ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e800 - U+1e81f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e820 - U+1e83f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e840 - U+1e85f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e860 - U+1e87f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e880 - U+1e89f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e8a0 - U+1e8bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e8c0 - U+1e8df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e8e0 - U+1e8ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e900 - U+1e91f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e920 - U+1e93f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e940 - U+1e95f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e960 - U+1e97f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e980 - U+1e99f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e9a0 - U+1e9bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e9c0 - U+1e9df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1e9e0 - U+1e9ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ea00 - U+1ea1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ea20 - U+1ea3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ea40 - U+1ea5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ea60 - U+1ea7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ea80 - U+1ea9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eaa0 - U+1eabf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eac0 - U+1eadf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eae0 - U+1eaff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eb00 - U+1eb1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eb20 - U+1eb3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eb40 - U+1eb5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eb60 - U+1eb7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eb80 - U+1eb9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eba0 - U+1ebbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ebc0 - U+1ebdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ebe0 - U+1ebff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ec00 - U+1ec1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ec20 - U+1ec3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ec40 - U+1ec5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ec60 - U+1ec7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ec80 - U+1ec9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eca0 - U+1ecbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ecc0 - U+1ecdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ece0 - U+1ecff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ed00 - U+1ed1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ed20 - U+1ed3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ed40 - U+1ed5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ed60 - U+1ed7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ed80 - U+1ed9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eda0 - U+1edbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1edc0 - U+1eddf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ede0 - U+1edff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ee00 - U+1ee1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ee20 - U+1ee3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ee40 - U+1ee5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ee60 - U+1ee7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ee80 - U+1ee9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eea0 - U+1eebf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eec0 - U+1eedf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1eee0 - U+1eeff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ef00 - U+1ef1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ef20 - U+1ef3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ef40 - U+1ef5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ef60 - U+1ef7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ef80 - U+1ef9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1efa0 - U+1efbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1efc0 - U+1efdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1efe0 - U+1efff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f000 - U+1f01f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f020 - U+1f03f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f040 - U+1f05f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f060 - U+1f07f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f080 - U+1f09f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f0a0 - U+1f0bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f0c0 - U+1f0df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f0e0 - U+1f0ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f100 - U+1f11f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f120 - U+1f13f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f140 - U+1f15f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f160 - U+1f17f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f180 - U+1f19f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f1a0 - U+1f1bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f1c0 - U+1f1df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f1e0 - U+1f1ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f200 - U+1f21f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f220 - U+1f23f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f240 - U+1f25f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f260 - U+1f27f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f280 - U+1f29f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f2a0 - U+1f2bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f2c0 - U+1f2df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f2e0 - U+1f2ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f300 - U+1f31f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f320 - U+1f33f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f340 - U+1f35f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f360 - U+1f37f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f380 - U+1f39f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f3a0 - U+1f3bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f3c0 - U+1f3df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f3e0 - U+1f3ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f400 - U+1f41f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f420 - U+1f43f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f440 - U+1f45f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f460 - U+1f47f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f480 - U+1f49f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f4a0 - U+1f4bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f4c0 - U+1f4df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f4e0 - U+1f4ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f500 - U+1f51f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f520 - U+1f53f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f540 - U+1f55f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f560 - U+1f57f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f580 - U+1f59f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f5a0 - U+1f5bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f5c0 - U+1f5df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f5e0 - U+1f5ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f600 - U+1f61f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f620 - U+1f63f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f640 - U+1f65f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f660 - U+1f67f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f680 - U+1f69f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f6a0 - U+1f6bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f6c0 - U+1f6df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f6e0 - U+1f6ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f700 - U+1f71f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f720 - U+1f73f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f740 - U+1f75f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f760 - U+1f77f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f780 - U+1f79f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f7a0 - U+1f7bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f7c0 - U+1f7df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f7e0 - U+1f7ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f800 - U+1f81f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f820 - U+1f83f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f840 - U+1f85f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f860 - U+1f87f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f880 - U+1f89f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f8a0 - U+1f8bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f8c0 - U+1f8df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f8e0 - U+1f8ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f900 - U+1f91f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f920 - U+1f93f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f940 - U+1f95f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f960 - U+1f97f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f980 - U+1f99f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f9a0 - U+1f9bf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f9c0 - U+1f9df */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1f9e0 - U+1f9ff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fa00 - U+1fa1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fa20 - U+1fa3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fa40 - U+1fa5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fa60 - U+1fa7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fa80 - U+1fa9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1faa0 - U+1fabf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fac0 - U+1fadf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fae0 - U+1faff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fb00 - U+1fb1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fb20 - U+1fb3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fb40 - U+1fb5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fb60 - U+1fb7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fb80 - U+1fb9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fba0 - U+1fbbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fbc0 - U+1fbdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fbe0 - U+1fbff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fc00 - U+1fc1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fc20 - U+1fc3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fc40 - U+1fc5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fc60 - U+1fc7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fc80 - U+1fc9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fca0 - U+1fcbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fcc0 - U+1fcdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fce0 - U+1fcff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fd00 - U+1fd1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fd20 - U+1fd3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fd40 - U+1fd5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fd60 - U+1fd7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fd80 - U+1fd9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fda0 - U+1fdbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fdc0 - U+1fddf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fde0 - U+1fdff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fe00 - U+1fe1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fe20 - U+1fe3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fe40 - U+1fe5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fe60 - U+1fe7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fe80 - U+1fe9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fea0 - U+1febf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fec0 - U+1fedf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1fee0 - U+1feff */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ff00 - U+1ff1f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ff20 - U+1ff3f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ff40 - U+1ff5f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ff60 - U+1ff7f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ff80 - U+1ff9f */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ffa0 - U+1ffbf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,	/* U+1ffc0 - U+1ffdf */
+  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff	/* U+1ffe0 - U+1ffff */
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/charset/windows.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,228 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Windows conversion tables
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	16 October 2000
+ * Last Edited:	30 August 2006
+ */
+
+				/* Windows Thai */
+static const unsigned short windows_874tab[128] = {
+  0x20ac,UBOGON,UBOGON,UBOGON,UBOGON,0x2026,UBOGON,UBOGON,
+  UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+  UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
+  UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+  0x00a0,0x0e01,0x0e02,0x0e03,0x0e04,0x0e05,0x0e06,0x0e07,
+  0x0e08,0x0e09,0x0e0a,0x0e0b,0x0e0c,0x0e0d,0x0e0e,0x0e0f,
+  0x0e10,0x0e11,0x0e12,0x0e13,0x0e14,0x0e15,0x0e16,0x0e17,
+  0x0e18,0x0e19,0x0e1a,0x0e1b,0x0e1c,0x0e1d,0x0e1e,0x0e1f,
+  0x0e20,0x0e21,0x0e22,0x0e23,0x0e24,0x0e25,0x0e26,0x0e27,
+  0x0e28,0x0e29,0x0e2a,0x0e2b,0x0e2c,0x0e2d,0x0e2e,0x0e2f,
+  0x0e30,0x0e31,0x0e32,0x0e33,0x0e34,0x0e35,0x0e36,0x0e37,
+  0x0e38,0x0e39,0x0e3a,UBOGON,UBOGON,UBOGON,UBOGON,0x0e3f,
+  0x0e40,0x0e41,0x0e42,0x0e43,0x0e44,0x0e45,0x0e46,0x0e47,
+  0x0e48,0x0e49,0x0e4a,0x0e4b,0x0e4c,0x0e4d,0x0e4e,0x0e4f,
+  0x0e50,0x0e51,0x0e52,0x0e53,0x0e54,0x0e55,0x0e56,0x0e57,
+  0x0e58,0x0e59,0x0e5a,0x0e5b,UBOGON,UBOGON,UBOGON,UBOGON
+};
+
+				/* Windows Latin-2 */
+static const unsigned short windows_1250tab[128] = {
+  0x20ac,UBOGON,0x201a,UBOGON,0x201e,0x2026,0x2020,0x2021,
+  UBOGON,0x2030,0x0160,0x2039,0x015a,0x0164,0x017d,0x0179,
+  UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
+  UBOGON,0x2122,0x0161,0x203a,0x015b,0x0165,0x017e,0x017a,
+  0x00a0,0x02c7,0x02d8,0x0141,0x00a4,0x0104,0x00a6,0x00a7,
+  0x00a8,0x00a9,0x015e,0x00ab,0x00ac,0x00ad,0x00ae,0x017b,
+  0x00b0,0x00b1,0x02db,0x0142,0x00b4,0x00b5,0x00b6,0x00b7,
+  0x00b8,0x0105,0x015f,0x00bb,0x013d,0x02dd,0x013e,0x017c,
+  0x0154,0x00c1,0x00c2,0x0102,0x00c4,0x0139,0x0106,0x00c7,
+  0x010c,0x00c9,0x0118,0x00cb,0x011a,0x00cd,0x00ce,0x010e,
+  0x0110,0x0143,0x0147,0x00d3,0x00d4,0x0150,0x00d6,0x00d7,
+  0x0158,0x016e,0x00da,0x0170,0x00dc,0x00dd,0x0162,0x00df,
+  0x0155,0x00e1,0x00e2,0x0103,0x00e4,0x013a,0x0107,0x00e7,
+  0x010d,0x00e9,0x0119,0x00eb,0x011b,0x00ed,0x00ee,0x010f,
+  0x0111,0x0144,0x0148,0x00f3,0x00f4,0x0151,0x00f6,0x00f7,
+  0x0159,0x016f,0x00fa,0x0171,0x00fc,0x00fd,0x0163,0x02d9
+};
+
+				/* Windows Cyrillic */
+static const unsigned short windows_1251tab[128] = {
+  0x0402,0x0403,0x201a,0x0453,0x201e,0x2026,0x2020,0x2021,
+  0x20ac,0x2030,0x0409,0x2039,0x040a,0x040c,0x040b,0x040f,
+  0x0452,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
+  UBOGON,0x2122,0x0459,0x203a,0x045a,0x045c,0x045b,0x045f,
+  0x00a0,0x040e,0x045e,0x0408,0x00a4,0x0490,0x00a6,0x00a7,
+  0x0401,0x00a9,0x0404,0x00ab,0x00ac,0x00ad,0x00ae,0x0407,
+  0x00b0,0x00b1,0x0406,0x0456,0x0491,0x00b5,0x00b6,0x00b7,
+  0x0451,0x2116,0x0454,0x00bb,0x0458,0x0405,0x0455,0x0457,
+  0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0416,0x0417,
+  0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f,
+  0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,0x0427,
+  0x0428,0x0429,0x042a,0x042b,0x042c,0x042d,0x042e,0x042f,
+  0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,0x0436,0x0437,
+  0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,0x043f,
+  0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,0x0447,
+  0x0448,0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,0x044f
+};
+
+				/* Windows Latin-1 */
+static const unsigned short windows_1252tab[128] = {
+  0x20ac,UBOGON,0x201a,0x0192,0x201e,0x2026,0x2020,0x2021,
+  0x02c6,0x2030,0x0160,0x2039,0x0152,UBOGON,0x017d,UBOGON,
+  UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
+  0x02dc,0x2122,0x0161,0x203a,0x0153,UBOGON,0x017e,0x0178,
+  0x00a0,0x00a1,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,
+  0x00a8,0x00a9,0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
+  0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,
+  0x00b8,0x00b9,0x00ba,0x00bb,0x00bc,0x00bd,0x00be,0x00bf,
+  0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7,
+  0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
+  0x00d0,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00d7,
+  0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x00dd,0x00de,0x00df,
+  0x00e0,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x00e7,
+  0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef,
+  0x00f0,0x00f1,0x00f2,0x00f3,0x00f4,0x00f5,0x00f6,0x00f7,
+  0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x00fd,0x00fe,0x00ff
+};
+
+
+				/* Windows Greek */
+static const unsigned short windows_1253tab[128] = {
+  0x20ac,UBOGON,0x201a,0x0192,0x201e,0x2026,0x2020,0x2021,
+  UBOGON,0x2030,UBOGON,0x2039,UBOGON,UBOGON,UBOGON,UBOGON,
+  UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
+  UBOGON,0x2122,UBOGON,0x203a,UBOGON,UBOGON,UBOGON,UBOGON,
+  0x00a0,0x0385,0x0386,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,
+  0x00a8,0x00a9,UBOGON,0x00ab,0x00ac,0x00ad,0x00ae,0x2015,
+  0x00b0,0x00b1,0x00b2,0x00b3,0x0384,0x00b5,0x00b6,0x00b7,
+  0x0388,0x0389,0x038a,0x00bb,0x038c,0x00bd,0x038e,0x038f,
+  0x0390,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,
+  0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,
+  0x03a0,0x03a1,UBOGON,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,
+  0x03a8,0x03a9,0x03aa,0x03ab,0x03ac,0x03ad,0x03ae,0x03af,
+  0x03b0,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,
+  0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,
+  0x03c0,0x03c1,0x03c2,0x03c3,0x03c4,0x03c5,0x03c6,0x03c7,
+  0x03c8,0x03c9,0x03ca,0x03cb,0x03cc,0x03cd,0x03ce,UBOGON
+};
+
+				/* Windows Turkish */
+static const unsigned short windows_1254tab[128] = {
+  0x20ac,UBOGON,0x201a,0x0192,0x201e,0x2026,0x2020,0x2021,
+  0x02c6,0x2030,0x0160,0x2039,0x0152,UBOGON,UBOGON,UBOGON,
+  UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
+  0x02dc,0x2122,0x0161,0x203a,0x0153,UBOGON,UBOGON,0x0178,
+  0x00a0,0x00a1,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,
+  0x00a8,0x00a9,0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
+  0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,
+  0x00b8,0x00b9,0x00ba,0x00bb,0x00bc,0x00bd,0x00be,0x00bf,
+  0x00c0,0x00c1,0x00c2,0x00c3,0x00c4,0x00c5,0x00c6,0x00c7,
+  0x00c8,0x00c9,0x00ca,0x00cb,0x00cc,0x00cd,0x00ce,0x00cf,
+  0x011e,0x00d1,0x00d2,0x00d3,0x00d4,0x00d5,0x00d6,0x00d7,
+  0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x0130,0x015e,0x00df,
+  0x00e0,0x00e1,0x00e2,0x00e3,0x00e4,0x00e5,0x00e6,0x00e7,
+  0x00e8,0x00e9,0x00ea,0x00eb,0x00ec,0x00ed,0x00ee,0x00ef,
+  0x011f,0x00f1,0x00f2,0x00f3,0x00f4,0x00f5,0x00f6,0x00f7,
+  0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x0131,0x015f,0x00ff
+};
+
+				/* Windows Hebrew */
+static const unsigned short windows_1255tab[128] = {
+  0x20ac,UBOGON,0x201a,0x0192,0x201e,0x2026,0x2020,0x2021,
+  0x02c6,0x2030,UBOGON,0x2039,UBOGON,UBOGON,UBOGON,UBOGON,
+  UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
+  0x02dc,0x2122,UBOGON,0x203a,UBOGON,UBOGON,UBOGON,UBOGON,
+  0x00a0,0x00a1,0x00a2,0x00a3,0x20aa,0x00a5,0x00a6,0x00a7,
+  0x00a8,0x00a9,0x00d7,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
+  0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,
+  0x00b8,0x00b9,0x00f7,0x00bb,0x00bc,0x00bd,0x00be,0x00bf,
+  0x05b0,0x05b1,0x05b2,0x05b3,0x05b4,0x05b5,0x05b6,0x05b7,
+  0x05b8,0x05b9,UBOGON,0x05bb,0x05bc,0x05bd,0x05be,0x05bf,
+  0x05c0,0x05c1,0x05c2,0x05c3,0x05f0,0x05f1,0x05f2,0x05f3,
+  0x05f4,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,UBOGON,
+  0x05d0,0x05d1,0x05d2,0x05d3,0x05d4,0x05d5,0x05d6,0x05d7,
+  0x05d8,0x05d9,0x05da,0x05db,0x05dc,0x05dd,0x05de,0x05df,
+  0x05e0,0x05e1,0x05e2,0x05e3,0x05e4,0x05e5,0x05e6,0x05e7,
+  0x05e8,0x05e9,0x05ea,UBOGON,UBOGON,0x200e,0x200f,UBOGON
+};
+
+				/* Windows Arabic */
+static const unsigned short windows_1256tab[128] = {
+  0x20ac,0x067e,0x201a,0x0192,0x201e,0x2026,0x2020,0x2021,
+  0x02c6,0x2030,0x0679,0x2039,0x0152,0x0686,0x0698,0x0688,
+  0x06af,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
+  0x06a9,0x2122,0x0691,0x203a,0x0153,0x200c,0x200d,0x06ba,
+  0x00a0,0x060c,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,
+  0x00a8,0x00a9,0x06be,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
+  0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,
+  0x00b8,0x00b9,0x061b,0x00bb,0x00bc,0x00bd,0x00be,0x061f,
+  0x06c1,0x0621,0x0622,0x0623,0x0624,0x0625,0x0626,0x0627,
+  0x0628,0x0629,0x062a,0x062b,0x062c,0x062d,0x062e,0x062f,
+  0x0630,0x0631,0x0632,0x0633,0x0634,0x0635,0x0636,0x00d7,
+  0x0637,0x0638,0x0639,0x063a,0x0640,0x0641,0x0642,0x0643,
+  0x00e0,0x0644,0x00e2,0x0645,0x0646,0x0647,0x0648,0x00e7,
+  0x00e8,0x00e9,0x00ea,0x00eb,0x0649,0x064a,0x00ee,0x00ef,
+  0x064b,0x064c,0x064d,0x064e,0x00f4,0x064f,0x0650,0x00f7,
+  0x0651,0x00f9,0x0652,0x00fb,0x00fc,0x200e,0x200f,0x06d2
+};
+
+				/* Windows Baltic */
+static const unsigned short windows_1257tab[128] = {
+  0x20ac,UBOGON,0x201a,UBOGON,0x201e,0x2026,0x2020,0x2021,
+  UBOGON,0x2030,UBOGON,0x2039,UBOGON,0x00a8,0x02c7,0x00b8,
+  UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
+  UBOGON,0x2122,UBOGON,0x203a,UBOGON,0x00af,0x02db,UBOGON,
+  0x00a0,UBOGON,0x00a2,0x00a3,0x00a4,UBOGON,0x00a6,0x00a7,
+  0x00d8,0x00a9,0x0156,0x00ab,0x00ac,0x00ad,0x00ae,0x00c6,
+  0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,
+  0x00f8,0x00b9,0x0157,0x00bb,0x00bc,0x00bd,0x00be,0x00e6,
+  0x0104,0x012e,0x0100,0x0106,0x00c4,0x00c5,0x0118,0x0112,
+  0x010c,0x00c9,0x0179,0x0116,0x0122,0x0136,0x012a,0x013b,
+  0x0160,0x0143,0x0145,0x00d3,0x014c,0x00d5,0x00d6,0x00d7,
+  0x0172,0x0141,0x015a,0x016a,0x00dc,0x017b,0x017d,0x00df,
+  0x0105,0x012f,0x0101,0x0107,0x00e4,0x00e5,0x0119,0x0113,
+  0x010d,0x00e9,0x017a,0x0117,0x0123,0x0137,0x012b,0x013c,
+  0x0161,0x0144,0x0146,0x00f3,0x014d,0x00f5,0x00f6,0x00f7,
+  0x0173,0x0142,0x015b,0x016b,0x00fc,0x017c,0x017e,0x02d9
+};
+
+				/* Windows Vietnamese */
+static const unsigned short windows_1258tab[128] = {
+  0x20ac,UBOGON,0x201a,0x0192,0x201e,0x2026,0x2020,0x2021,
+  0x02c6,0x2030,UBOGON,0x2039,0x0152,UBOGON,UBOGON,UBOGON,
+  UBOGON,0x2018,0x2019,0x201c,0x201d,0x2022,0x2013,0x2014,
+  0x02dc,0x2122,UBOGON,0x203a,0x0153,UBOGON,UBOGON,0x0178,
+  0x00a0,0x00a1,0x00a2,0x00a3,0x00a4,0x00a5,0x00a6,0x00a7,
+  0x00a8,0x00a9,0x00aa,0x00ab,0x00ac,0x00ad,0x00ae,0x00af,
+  0x00b0,0x00b1,0x00b2,0x00b3,0x00b4,0x00b5,0x00b6,0x00b7,
+  0x00b8,0x00b9,0x00ba,0x00bb,0x00bc,0x00bd,0x00be,0x00bf,
+  0x00c0,0x00c1,0x00c2,0x0102,0x00c4,0x00c5,0x00c6,0x00c7,
+  0x00c8,0x00c9,0x00ca,0x00cb,0x0300,0x00cd,0x00ce,0x00cf,
+  0x0110,0x00d1,0x0309,0x00d3,0x00d4,0x01a0,0x00d6,0x00d7,
+  0x00d8,0x00d9,0x00da,0x00db,0x00dc,0x01af,0x0303,0x00df,
+  0x00e0,0x00e1,0x00e2,0x0103,0x00e4,0x00e5,0x00e6,0x00e7,
+  0x00e8,0x00e9,0x00ea,0x00eb,0x0301,0x00ed,0x00ee,0x00ef,
+  0x0111,0x00f1,0x0323,0x00f3,0x00f4,0x01a1,0x00f6,0x00f7,
+  0x00f8,0x00f9,0x00fa,0x00fb,0x00fc,0x01b0,0x20ab,0x00ff
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmail/Makefile	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,53 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+
+# Program:	dmail Makefile
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		5 April 1993
+# Last Edited:	10 September 2007
+
+
+C = ../c-client
+CCLIENTLIB = $C/c-client.a
+SHELL = /bin/sh
+
+# Get local definitions from c-client directory
+
+CC = `cat $C/CCTYPE`
+CFLAGS = -I$C `cat $C/CFLAGS`
+LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS`
+
+dmail: $(CCLIENTLIB) dmail.o dquota.o
+	$(CC) $(CFLAGS) -o dmail dmail.o dquota.o $(LDFLAGS)
+
+dmail.o: $C/mail.h $C/misc.h $C/osdep.h dquota.h
+
+dquota.o: dquota.h
+
+$(CCLIENTLIB):
+	cd $C;make
+
+clean:
+	rm -f *.o dmail
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo 'not war?'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmail/dmail.1	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,121 @@
+.ig
+ * ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+..
+.TH DMAIL 1 "June 18, 2007"
+.SH NAME
+dmail \- procmail Mail Delivery Module
+.nh
+.SH SYNOPSIS
+.B dmail
+.I [\-D] [\-f from_name] [-s] [-k keyword_list] [user][+folder]
+.SH DESCRIPTION
+.I dmail
+delivers mail to a user's INBOX or a designated folder.
+.I dmail
+may be configured as a drop-in replacement for
+.IR binmail (1),
+.IR mail.local (1)
+for use with a mail delivery filter such as
+.IR procmail (1) .
+.PP
+Because of security considerations (see below)
+.I dmail
+is not intended to be used for direct delivery by the mailer daemon;
+.IR tmail (1)
+is the preferred tool for this purpose.  If
+.I dmail
+is used for mailer daemon delivery, the mailer daemon must invoke
+.I dmail
+with the
+.I dmail
+process' user id set to the recipient's user id.
+.PP
+When
+.I dmail
+exits, it returns exit status values to enable
+.IR procmail (1)
+to determine whether a message was delivered successfully or had a
+temporary (requeue for later delivery) or permanent (return to sender)
+failure.
+.PP
+If the
+.I user
+name is present, it must be the same as the logged-in user name.
+.PP
+If the 
+.I +folder
+extension is included in the user argument (or appears by itself if there
+is no user argument), 
+.I dmail
+will attempt to deliver to the designated folder.  If the folder does not 
+exist or the extension is not included, the message is delivered to the 
+user's INBOX.
+If delivery is to INBOX and no INBOX currently exists,
+.I dmail
+will create a new INBOX.
+.I dmail
+recognizes the format of an existing INBOX or folder, and appends the new
+message in that format.
+.PP
+The \fB-D\fR flag specifies debugging; this enables additional message
+telemetry.
+.PP
+The \fB-f\fR or \fB-r\fR flag is used to specify a Return-Path.  The header
+.br
+   Return-Path: <\fIfrom_name\fR> 
+.br 
+is prepended to the message before delivery.
+.PP
+The
+.B -s
+flag specifies that the message will be flagged as being "seen".
+.PP
+The \fB-k\fR flag is used to specify delivery keywords, which are set on
+the message at delivery time if and
+.B only
+if the keywords are already defined in the mailbox.  Multiple keywords can be
+specified by using a quoted string, e.g.,
+.br
+   dmail -k "$Junk Discard" +junkbox
+.br 
+.SH RESTRICTIONS
+Absolute pathnames and 
+.I ~user
+specifications are not permitted in
+.I +folder
+extensions.
+.SH SECURITY CONSIDERATIONS
+Unlike
+.I tmail
+you can use
+.I dmail
+to deliver to IMAP4 namespace names via
+.I +folder
+extensions.  This means that it is possible to deliver to
+.IR mh (1)
+format mailboxes.
+.PP
+However, this can also include such namespaces as #shared, #public,
+and #ftp.  In most cases, it is undesirable to allow anybody sending
+mail to the user to deliver to these namespaces.  Consequently, there
+needs to be a rule in place in the configuration of either
+.IR sendmail (8)
+or
+.IR procmail (1)
+to prevent such abuse.
+.SH AUTHOR
+Mark Crispin, MRC@CAC.Washington.EDU
+.SH "SEE ALSO"
+binmail(1)
+.br
+procmail(1)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmail/dmail.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,661 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Procmail-Callable Mail Delivery Module
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	5 April 1993
+ * Last Edited:	30 October 2008
+ */
+
+#include <stdio.h>
+#include <pwd.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <sysexits.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include "c-client.h"
+#include "dquota.h"
+
+
+/* Globals */
+
+char *version = "18";		/* dmail edit version */
+int debug = NIL;		/* debugging (don't fork) */
+int flagseen = NIL;		/* flag message as seen */
+int trycreate = NIL;		/* flag saying gotta create before appending */
+int critical = NIL;		/* flag saying in critical code */
+char *sender = NIL;		/* message origin */
+char *keywords = NIL;		/* keyword list */
+long precedence = 0;		/* delivery precedence - used by quota hook */
+
+
+/* Function prototypes */
+
+void file_string_init (STRING *s,void *data,unsigned long size);
+char file_string_next (STRING *s);
+void file_string_setpos (STRING *s,unsigned long i);
+int main (int argc,char *argv[]);
+int deliver (FILE *f,unsigned long msglen,char *user);
+long ibxpath (MAILSTREAM *ds,char **mailbox,char *path);
+int deliver_safely (MAILSTREAM *prt,STRING *st,char *mailbox,char *path,
+		    char *tmp);
+int delivery_unsafe (char *path,struct stat *sbuf,char *tmp);
+int fail (char *string,int code);
+
+
+/* File string driver for file stringstructs */
+
+STRINGDRIVER file_string = {
+  file_string_init,		/* initialize string structure */
+  file_string_next,		/* get next byte in string structure */
+  file_string_setpos		/* set position in string structure */
+};
+
+
+/* Cache buffer for file stringstructs */
+
+#define CHUNKLEN 16384
+char chunk[CHUNKLEN];
+
+/* Initialize file string structure for file stringstruct
+ * Accepts: string structure
+ *	    pointer to string
+ *	    size of string
+ */
+
+void file_string_init (STRING *s,void *data,unsigned long size)
+{
+  s->data = data;		/* note fd */
+  s->size = size;		/* note size */
+  s->chunk = chunk;
+  s->chunksize = (unsigned long) CHUNKLEN;
+  SETPOS (s,0);			/* set initial position */
+}
+
+
+/* Get next character from file stringstruct
+ * Accepts: string structure
+ * Returns: character, string structure chunk refreshed
+ */
+
+char file_string_next (STRING *s)
+{
+  char c = *s->curpos++;	/* get next byte */
+  SETPOS (s,GETPOS (s));	/* move to next chunk */
+  return c;			/* return the byte */
+}
+
+
+/* Set string pointer position for file stringstruct
+ * Accepts: string structure
+ *	    new position
+ */
+
+void file_string_setpos (STRING *s,unsigned long i)
+{
+  if (i > s->size) i = s->size;	/* don't permit setting beyond EOF */
+  s->offset = i;		/* set new offset */
+  s->curpos = s->chunk;		/* reset position */
+				/* set size of data */
+  if (s->cursize = min (s->chunksize,SIZE (s))) {
+				/* move to that position in the file */
+    fseek ((FILE *) s->data,s->offset,SEEK_SET);
+    fread (s->curpos,sizeof (char),(unsigned int) s->cursize,(FILE *) s->data);
+  }
+}
+
+/* Main program */
+
+int main (int argc,char *argv[])
+{
+  FILE *f = NIL;
+  int c,ret = 0;
+  unsigned long msglen;
+  char *s,tmp[MAILTMPLEN];
+  uid_t ruid = getuid ();
+  struct passwd *pwd = ruid ? getpwnam ("daemon") : NIL;
+  openlog ("dmail",LOG_PID,LOG_MAIL);
+				/* must not be root or daemon! */
+  if (!ruid || (pwd && (pwd->pw_uid == ruid)))
+    _exit (fail ("dmail may not be invoked by root or daemon",EX_USAGE));
+#include "linkage.c"
+				/* process all flags */
+  for (--argc; argc && (*(s = *++argv)) == '-'; argc--) switch (s[1]) {
+  case 'D':			/* debug */
+    debug = T;			/* extra debugging */
+    break;
+  case 's':			/* deliver as seen */
+    flagseen = T;
+    break;
+  case 'f':
+  case 'r':			/* flag giving return path */
+    if (sender) _exit (fail ("duplicate -r",EX_USAGE));
+    if (argc--) sender = cpystr (*++argv);
+    else _exit (fail ("missing argument to -r",EX_USAGE));
+    break;
+  case 'k':
+    if (keywords) _exit (fail ("duplicate -k",EX_USAGE));
+    if (argc--) keywords = cpystr (*++argv);
+    else _exit (fail ("missing argument to -k",EX_USAGE));
+    break;
+  case 'p':
+    if (s[2] && ((s[2] == '-') || isdigit (s[2]))) precedence = atol (s + 2);
+    else if (argc-- && ((*(s = *++argv) == '-') || isdigit (*s)))
+      precedence = atol (s);
+    else _exit (fail ("missing argument to -p",EX_USAGE));
+    break;
+  default:			/* anything else */
+    _exit (fail ("unknown switch",EX_USAGE));
+  }
+
+  if (argc > 1) _exit (fail ("too many recipients",EX_USAGE));
+  else if (!(f = tmpfile ())) _exit(fail ("can't make temp file",EX_TEMPFAIL));
+				/* build delivery headers */
+  if (sender) fprintf (f,"Return-Path: <%s>\015\012",sender);
+				/* start Received line: */
+  fprintf (f,"Received: via dmail-%s.%s for %s; ",CCLIENTVERSION,version,
+	   (argc == 1) ? *argv : myusername ());
+  rfc822_date (tmp);
+  fputs (tmp,f);
+  fputs ("\015\012",f);
+				/* copy text from standard input */
+  if (!fgets (tmp,MAILTMPLEN-1,stdin) || !(s = strchr (tmp,'\n')) ||
+      (s == tmp) || s[1]) _exit (fail ("bad first message line",EX_USAGE));
+  else if (s[-1] == '\015') {	/* nuke leading "From " line */
+    if ((tmp[0] != 'F') || (tmp[1] != 'r') || (tmp[2] != 'o') ||
+	(tmp[3] != 'm') || (tmp[4] != ' ')) fputs (tmp,f);
+    while ((c = getchar ()) != EOF) putc (c,f);
+  }
+  else {
+    if ((tmp[0] != 'F') || (tmp[1] != 'r') || (tmp[2] != 'o') ||
+	(tmp[3] != 'm') || (tmp[4] != ' ')) {
+      *s++ = '\015';		/* overwrite NL with CRLF */
+      *s++ = '\012';
+      *s = '\0';		/* tie off string */
+      fputs (tmp,f);		/* write line */
+    }
+  }
+				/* copy text from standard input */
+  while ((c = getchar ()) != EOF) {
+				/* add CR if needed */
+    if (c == '\012') putc ('\015',f);
+    putc (c,f);
+  }
+  msglen = ftell (f);		/* size of message */
+  fflush (f);			/* make sure all changes written out */
+  if (ferror (f)) ret = fail ("error writing temp file",EX_TEMPFAIL);
+  else if (!msglen) ret = fail ("empty message",EX_TEMPFAIL);
+				/* single delivery */
+  else ret = deliver (f,msglen,argc ? *argv : myusername ());
+  fclose (f);			/* all done with temporary file */
+  _exit (ret);			/* normal exit */
+  return 0;			/* stupid gcc */
+}
+
+/* Deliver message to recipient list
+ * Accepts: file description of message temporary file
+ *	    size of message temporary file in bytes
+ *	    recipient name
+ * Returns: NIL if success, else error code
+ */
+
+int deliver (FILE *f,unsigned long msglen,char *user)
+{
+  MAILSTREAM *ds = NIL;
+  char *s,*mailbox,tmp[MAILTMPLEN],path[MAILTMPLEN];
+  STRING st;
+  struct stat sbuf;
+				/* have a mailbox specifier? */
+  if (mailbox = strchr (user,'+')) {
+    *mailbox++ = '\0';		/* yes, tie off user name */
+    if (!*mailbox || !compare_cstring ((unsigned char *) mailbox,"INBOX"))
+      mailbox = NIL;		/* user+ and user+INBOX same as user */
+  }
+  if (!*user) user = myusername ();
+  else if (strcmp (user,myusername ()))
+    return fail ("can't deliver to other user",EX_CANTCREAT);
+  sprintf (tmp,"delivering to %.80s+%.80s",user,mailbox ? mailbox : "INBOX");
+  mm_dlog (tmp);
+				/* prepare stringstruct */
+  INIT (&st,file_string,(void *) f,msglen);
+  if (mailbox) {		/* non-INBOX name */
+    switch (mailbox[0]) {	/* make sure a valid name */
+    default:			/* other names, try to deliver if not INBOX */
+      if (!strstr (mailbox,"..") && !strstr (mailbox,"//") &&
+	  !strstr (mailbox,"/~") && mailboxfile (path,mailbox) && path[0] &&
+	  !deliver_safely (NIL,&st,mailbox,path,tmp)) return NIL;
+    case '%': case '*':		/* wildcards not valid */
+    case '/':			/* absolute path names not valid */
+    case '~':			/* user names not valid */
+      sprintf (tmp,"invalid mailbox name %.80s+%.80s",user,mailbox);
+      mm_log (tmp,WARN);
+      break;
+    }
+    mm_dlog ("retrying delivery to INBOX");
+    SETPOS (&st,0);		/* rewind stringstruct just in case */
+  }
+
+				/* no -I, resolve "INBOX" into path */
+  if (mailboxfile (path,mailbox = "INBOX") && !path[0]) {
+				/* clear box, get generic INBOX prototype */
+    if (!(ds = mail_open (NIL,"INBOX",OP_PROTOTYPE)))
+      fatal ("no INBOX prototype");
+				/* standard system driver? */
+    if (!strcmp (ds->dtb->name,"unix") || !strcmp (ds->dtb->name,"mmdf")) {
+      strcpy (path,sysinbox ());/* use system INBOX */
+      if (!lstat (path,&sbuf))	/* deliver to existing system INBOX */
+	return deliver_safely (ds,&st,mailbox,path,tmp);
+    }
+    else {			/* other driver, try ~/INBOX */
+      if ((mailboxfile (path,"&&&&&") == path) &&
+	  (s = strstr (path,"&&&&&")) && strcpy (s,"INBOX") &&
+	  !lstat (path,&sbuf)){	/* deliver to existing ~/INBOX */
+	sprintf (tmp,"#driver.%s/INBOX",ds->dtb->name);
+	return deliver_safely (ds,&st,cpystr (tmp),path,tmp);
+      }
+    }
+				/* not dummy, deliver to driver imputed path */
+    if (strcmp (ds->dtb->name,"dummy"))
+      return (ibxpath (ds,&mailbox,path) && !lstat (path,&sbuf)) ?
+	deliver_safely (ds,&st,mailbox,path,tmp) :
+	  fail ("unable to resolve INBOX path",EX_CANTCREAT);
+				/* dummy, empty imputed append path exist? */
+    if (ibxpath (ds = default_proto (T),&mailbox,path) &&
+	!lstat (path,&sbuf) && !sbuf.st_size)
+      return deliver_safely (ds,&st,mailbox,path,tmp);
+				/* impute path that we will create */
+    if (!ibxpath (ds = default_proto (NIL),&mailbox,path))
+      return fail ("unable to resolve INBOX",EX_CANTCREAT);
+  }
+				/* black box, must create, get create proto */
+  else if (lstat (path,&sbuf)) ds = default_proto (NIL);
+  else {			/* black box, existing file */
+				/* empty file, get append prototype */
+    if (!sbuf.st_size) ds = default_proto (T);
+				/* non-empty, get prototype from its data */
+    else if (!(ds = mail_open (NIL,"INBOX",OP_PROTOTYPE)))
+      fatal ("no INBOX prototype");
+				/* error if unknown format */
+    if (!strcmp (ds->dtb->name,"phile"))
+      return fail ("unknown format INBOX",EX_UNAVAILABLE);
+				/* otherwise can deliver to it */
+    return deliver_safely (ds,&st,mailbox,path,tmp);
+  }
+  sprintf (tmp,"attempting to create mailbox %.80s path %.80s",mailbox,path);
+  mm_dlog (tmp);
+				/* supplicate to the Evil One */
+  if (!path_create (ds,path)) return fail ("can't create INBOX",EX_CANTCREAT);
+  sprintf (tmp,"created %.80s",path);
+  mm_dlog (tmp);
+				/* deliver the message */
+  return deliver_safely (ds,&st,mailbox,path,tmp);
+}
+
+/* Resolve INBOX from driver prototype into mailbox name and filesystem path
+ * Accepts: driver prototype
+ * 	    pointer to mailbox name string pointer
+ *	    buffer to return mailbox path
+ * Returns: T if success, NIL if error
+ */
+
+long ibxpath (MAILSTREAM *ds,char **mailbox,char *path)
+{
+  char *s,tmp[MAILTMPLEN];
+  long ret = T;
+  if (!ds) return NIL;
+  else if (!strcmp (ds->dtb->name,"unix") || !strcmp (ds->dtb->name,"mmdf"))
+    strcpy (path,sysinbox ());	/* use system INBOX for unix and MMDF */
+  else if (!strcmp (ds->dtb->name,"tenex"))
+    ret = (mailboxfile (path,"mail.txt") == path) ? T : NIL;
+  else if (!strcmp (ds->dtb->name,"mtx"))
+    ret = (mailboxfile (path,"INBOX.MTX") == path) ? T : NIL;
+  else if (!strcmp (ds->dtb->name,"mbox"))
+    ret = (mailboxfile (path,"mbox") == path) ? T : NIL;
+				/* better not be a namespace driver */
+  else if (ds->dtb->flags & DR_NAMESPACE) return NIL;
+				/* INBOX in home directory */
+  else ret = ((mailboxfile (path,"&&&&&") == path) &&
+	      (s = strstr (path,"&&&&&")) && strcpy (s,"INBOX")) ? T : NIL;
+  if (ret) {			/* don't bother if lossage */
+    sprintf (tmp,"#driver.%s/INBOX",ds->dtb->name);
+    *mailbox = cpystr (tmp);	/* name of INBOX in this namespace */
+  }
+  return ret;
+}
+
+/* Deliver safely
+ * Accepts: prototype stream to force mailbox format
+ *	    stringstruct of message temporary file or NIL for check only
+ *	    mailbox name
+ *	    filesystem path name
+ *	    scratch buffer for messages
+ * Returns: NIL if success, else error code
+ */
+
+int deliver_safely (MAILSTREAM *prt,STRING *st,char *mailbox,char *path,
+		    char *tmp)
+{
+  struct stat sbuf;
+  char *flags = NIL;
+  int i = delivery_unsafe (path,&sbuf,tmp);
+  if (i) return i;		/* give up now if delivery unsafe */
+				/* directory, not file */
+  if ((sbuf.st_mode & S_IFMT) == S_IFDIR) {
+    if (sbuf.st_mode & 0001) {	/* listable directories may be worrisome */
+      sprintf (tmp,"WARNING: directory %.80s is listable",path);
+      mm_log (tmp,WARN);
+    }
+  }
+  else {			/* file, not directory */
+    if (sbuf.st_nlink != 1) {	/* multiple links may be worrisome */
+      sprintf (tmp,"WARNING: multiple links to file %.80s",path);
+      mm_log (tmp,WARN);
+    }
+    if (sbuf.st_mode & 0111) {	/* executable files may be worrisome */
+      sprintf (tmp,"WARNING: file %.80s is executable",path);
+      mm_log (tmp,WARN);
+    }
+  }
+  if (sbuf.st_mode & 0002) {	/* public-write files may be worrisome */
+    sprintf (tmp,"WARNING: file %.80s is publicly-writable",path);
+    mm_log (tmp,WARN);
+  }
+  if (sbuf.st_mode & 0004) {	/* public-write files may be worrisome */
+    sprintf (tmp,"WARNING: file %.80s is publicly-readable",path);
+    mm_log (tmp,WARN);
+  }
+				/* check site-written quota procedure */
+  if (!dmail_quota (st,path,tmp,sender,precedence))
+    return fail (tmp,EX_CANTCREAT);
+				/* so far, so good */
+  sprintf (tmp,"%s appending to %.80s (%s %.80s)",
+	   prt ? prt->dtb->name : "default",mailbox,
+	   ((sbuf.st_mode & S_IFMT) == S_IFDIR) ? "directory" : "file",path);
+  mm_dlog (tmp);
+  if (keywords) {		/* any keywords requested? */
+    if (flagseen) sprintf (flags = tmp,"\\Seen %.1000s",keywords);
+    else flags = keywords;
+  }
+  else if (flagseen) flags = "\\Seen";
+				/* do the append now! */
+  if (!mail_append_full (prt,mailbox,flags,NIL,st)) {
+    sprintf (tmp,"message delivery failed to %.80s",path);
+    return fail (tmp,EX_CANTCREAT);
+  }
+				/* note success */
+  sprintf (tmp,"delivered to %.80s",path);
+  mm_log (tmp,NIL);
+				/* make sure nothing evil this way comes */
+  return delivery_unsafe (path,&sbuf,tmp);
+}
+
+/* Verify that delivery is safe
+ * Accepts: path name
+ *	    stat buffer
+ *	    scratch buffer for messages
+ * Returns: NIL if delivery is safe, error code if unsafe
+ */
+
+int delivery_unsafe (char *path,struct stat *sbuf,char *tmp)
+{
+  u_short type;
+  sprintf (tmp,"Verifying safe delivery to %.80s",path);
+  mm_dlog (tmp);
+				/* prepare message just in case */
+  sprintf (tmp,"delivery to %.80s unsafe: ",path);
+				/* unsafe if can't get its status */
+  if (lstat (path,sbuf)) strcat (tmp,strerror (errno));
+				/* check file type */
+  else switch (sbuf->st_mode & S_IFMT) {
+  case S_IFDIR:			/* directory is always OK */
+    return NIL;
+  case S_IFREG:			/* file is unsafe if setuid */
+    if (sbuf->st_mode & S_ISUID) strcat (tmp,"setuid file");
+				/* or setgid */
+    else if (sbuf->st_mode & S_ISGID) strcat (tmp,"setgid file");
+    else return NIL;		/* otherwise safe */
+    break;
+  case S_IFCHR: strcat (tmp,"character special"); break;
+  case S_IFBLK: strcat (tmp,"block special"); break;
+  case S_IFLNK: strcat (tmp,"symbolic link"); break;
+  case S_IFSOCK: strcat (tmp,"socket"); break;
+  default:
+    sprintf (tmp + strlen (tmp),"file type %07o",(unsigned int) type);
+  }
+  return fail (tmp,EX_CANTCREAT);
+}
+
+/* Report an error
+ * Accepts: string to output
+ */
+
+int fail (char *string,int code)
+{
+  mm_log (string,ERROR);	/* pass up the string */
+  switch (code) {
+#if T
+  case EX_USAGE:
+  case EX_OSERR:
+  case EX_SOFTWARE:
+  case EX_NOUSER:
+  case EX_CANTCREAT:
+    code = EX_TEMPFAIL;		/* coerce these to TEMPFAIL */
+    break;
+#endif
+  case -1:			/* quota failure... */
+    code = EX_CANTCREAT;	/* ...really returns this code */
+    break;
+  default:
+    break;
+  }
+  return code;			/* error code to return */
+}
+
+/* Co-routines from MAIL library */
+
+
+/* Message matches a search
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void mm_searched (MAILSTREAM *stream,unsigned long msgno)
+{
+  fatal ("mm_searched() call");
+}
+
+
+/* Message exists (i.e. there are that many messages in the mailbox)
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void mm_exists (MAILSTREAM *stream,unsigned long number)
+{
+  fatal ("mm_exists() call");
+}
+
+
+/* Message expunged
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void mm_expunged (MAILSTREAM *stream,unsigned long number)
+{
+  fatal ("mm_expunged() call");
+}
+
+
+/* Message flags update seen
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void mm_flags (MAILSTREAM *stream,unsigned long number)
+{
+}
+
+/* Mailbox found
+ * Accepts: MAIL stream
+ *	    delimiter
+ *	    mailbox name
+ *	    mailbox attributes
+ */
+
+void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes)
+{
+  fatal ("mm_list() call");
+}
+
+
+/* Subscribed mailbox found
+ * Accepts: MAIL stream
+ *	    delimiter
+ *	    mailbox name
+ *	    mailbox attributes
+ */
+
+void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes)
+{
+  fatal ("mm_lsub() call");
+}
+
+
+/* Mailbox status
+ * Accepts: MAIL stream
+ *	    mailbox name
+ *	    mailbox status
+ */
+
+void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
+{
+  fatal ("mm_status() call");
+}
+
+/* Notification event
+ * Accepts: MAIL stream
+ *	    string to log
+ *	    error flag
+ */
+
+void mm_notify (MAILSTREAM *stream,char *string,long errflg)
+{
+  char tmp[MAILTMPLEN];
+  tmp[11] = '\0';		/* see if TRYCREATE */
+  if (!strcmp (ucase (strncpy (tmp,string,11)),"[TRYCREATE]")) trycreate = T;
+  mm_log (string,errflg);	/* just do mm_log action */
+}
+
+
+/* Log an event for the user to see
+ * Accepts: string to log
+ *	    error flag
+ */
+
+void mm_log (char *string,long errflg)
+{
+  if (trycreate)mm_dlog(string);/* debug logging only if trycreate in effect */
+  else {			/* ordinary logging */
+    fprintf (stderr,"%s\n",string);
+    switch (errflg) {  
+    case NIL:			/* no error */
+      syslog (LOG_INFO,"%s",string);
+      break;
+    case PARSE:			/* parsing problem */
+    case WARN:			/* warning */
+      syslog (LOG_WARNING,"%s",string);
+      break;
+    case ERROR:			/* error */
+    default:
+      syslog (LOG_ERR,"%s",string);
+      break;
+    }
+  }
+}
+
+
+/* Log an event to debugging telemetry
+ * Accepts: string to log
+ */
+
+void mm_dlog (char *string)
+{
+  if (debug) fprintf (stderr,"%s\n",string);
+  syslog (LOG_DEBUG,"%s",string);
+}
+
+/* Get user name and password for this host
+ * Accepts: parse of network mailbox name
+ *	    where to return user name
+ *	    where to return password
+ *	    trial count
+ */
+
+void mm_login (NETMBX *mb,char *username,char *password,long trial)
+{
+  fatal ("mm_login() call");
+}
+
+
+/* About to enter critical code
+ * Accepts: stream
+ */
+
+void mm_critical (MAILSTREAM *stream)
+{
+  critical = T;			/* note in critical code */
+}
+
+
+/* About to exit critical code
+ * Accepts: stream
+ */
+
+void mm_nocritical (MAILSTREAM *stream)
+{
+  critical = NIL;		/* note not in critical code */
+}
+
+
+/* Disk error found
+ * Accepts: stream
+ *	    system error code
+ *	    flag indicating that mailbox may be clobbered
+ * Returns: T if user wants to abort
+ */
+
+long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
+{
+  return T;
+}
+
+
+/* Log a fatal error event
+ * Accepts: string to log
+ */
+
+void mm_fatal (char *string)
+{
+  printf ("?%s\n",string);	/* shouldn't happen normally */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmail/dquota.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,44 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Procmail-Callable Mail Delivery Module Quota Hook
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 September 2007
+ * Last Edited:	10 September 2007
+ */
+
+#include "c-client.h"
+
+/* Site-written routine to validate delivery per quota and policy
+ * Accepts: stringstruct of message temporary file
+ *	    filesystem path
+ *	    return path
+ *	    buffer to write error message
+ *	    precedence setting
+ * Returns: T if can deliver, or NIL if quota issue and must bounce
+ */
+
+long dmail_quota (STRING *msg,char *path,char *tmp,char *sender,
+		  long precedence)
+{
+  return LONGT;			/* dummy success return */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmail/dquota.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,32 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Procmail-Callable Mail Delivery Module Quota Hook
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 September 2007
+ * Last Edited:	10 September 2007
+ */
+
+/* Function prototypes */
+
+long dmail_quota (STRING *msg,char *path,char *tmp,char *sender,
+		  long precedence);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/imapd/Makefile	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,68 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+
+# Program:	IMAPD Makefile
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		5 November 1990
+# Last Edited:	30 August 2006
+
+
+ALERT=/etc/imapd.alert
+USERALERT=.imapalert
+SHUTDOWN=/etc/nologin
+ANO=/etc/anonymous.newsgroups
+NNTP=/etc/imapd.nntp
+SHELL= /bin/sh
+
+
+# Un-comment this to get somewhat better interoperability with Netscape.  It
+# causes the "Manage Mail" menu item to open the given URL, e.g. to point to
+# an alternative IMAP client (e.g. Pine) or perhaps to a homebrew mail
+# account management page.
+#NSBD= -DNETSCAPE_BRAIN_DAMAGE=\"http://www.washington.edu/pine\"
+
+
+# Get local definitions from c-client directory
+
+C = ../c-client
+CCLIENTLIB = $C/c-client.a
+CC = `cat $C/CCTYPE`
+CFLAGS = -I$C `cat $C/CFLAGS` $(NSBD) $(ENBD) -DANOFILE=\"$(ANO)\" \
+	-DALERTFILE=\"$(ALERT)\" -DNNTPFILE=\"$(NNTP)\" \
+	-DUSERALERTFILE=\"$(USERALERT)\" -DSHUTDOWNFILE=\"$(SHUTDOWN)\"
+LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS`
+
+all:	imapd
+
+imapd: $(CCLIENTLIB) imapd.o
+	$(CC) $(CFLAGS) -o imapd imapd.o $(LDFLAGS)
+
+imapd.o: $C/mail.h $C/misc.h $C/osdep.h
+
+$(CCLIENTLIB):
+	cd $C;make
+
+clean:
+	rm -f *.o imapd || true
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo 'not war?'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/imapd/imapd.8	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,48 @@
+.ig
+ * ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+..
+.TH IMAPD 8 "August 30, 2006"
+.UC 5
+.SH NAME
+IMAPd \- Internet Message Access Protocol server
+.SH SYNOPSIS
+.B /usr/etc/imapd
+.SH DESCRIPTION
+.I imapd
+is a server which supports the
+.B IMAP4rev1
+remote mail access protocol as documented in RFC-3501.
+.I imapd
+is invoked by the internet server (see
+.IR inetd (8)),
+normally for requests to connect to the
+.B IMAP
+port as indicated by the
+.I /etc/services
+file (see
+.IR services (5)).
+Normally, this is port 143 for plaintext IMAP and 993 for SSL IMAP.
+.PP
+This daemons contains CRAM-MD5 support.  See the md5.txt documentation
+file for additional information.
+.PP
+.I imapd
+can also be accessed via
+.IR rsh (1)
+by many Unix-based clients.  To do this, the
+.I imapd
+binary must have a link to
+.I /etc/rimapd
+since this is where this software expects it to be located.
+.SH "SEE ALSO"
+rsh(1) ipopd(8)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/imapd/imapd.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,4608 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	IMAP4rev1 server
+ *
+ * Author:	Mark Crispin
+ *		UW Technology
+ *		University of Washington
+ *		Seattle, WA  98195
+ *		Internet: MRC@Washington.EDU
+ *
+ * Date:	5 November 1990
+ * Last Edited:	3 March 2008
+ */
+
+/* Parameter files */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <signal.h>
+#include <setjmp.h>
+#include <time.h>
+#include "c-client.h"
+#include "newsrc.h"
+#include <sys/stat.h>
+
+
+#define CRLF PSOUT ("\015\012")	/* primary output terpri */
+
+
+/* Timeouts and timers */
+
+#define MINUTES *60
+
+#define LOGINTIMEOUT 3 MINUTES	/* not logged in autologout timer */
+#define TIMEOUT 30 MINUTES	/* RFC 3501 minimum autologout timer */
+#define INPUTTIMEOUT 5 MINUTES	/* timer for additional command input */
+#define ALERTTIMER 1 MINUTES	/* alert check timer */
+#define SHUTDOWNTIMER 1 MINUTES	/* shutdown dally timer */
+#define IDLETIMER 1 MINUTES	/* IDLE command poll timer */
+#define CHECKTIMER 15 MINUTES	/* IDLE command last checkpoint timer */
+
+
+#define LITSTKLEN 20		/* length of literal stack */
+#define MAXCLIENTLIT 10000	/* maximum non-APPEND client literal size
+				 * must be smaller than 4294967295
+				 */
+#define MAXAPPENDTXT 0x40000000	/* maximum APPEND literal size
+				 * must be smaller than 4294967295
+				 */
+#define CMDLEN 65536		/* size of command buffer */
+
+
+/* Server states */
+
+#define LOGIN 0
+#define SELECT 1
+#define OPEN 2
+#define LOGOUT 3
+
+/* Body text fetching */
+
+typedef struct text_args {
+  char *section;		/* body section */
+  STRINGLIST *lines;		/* header lines */
+  unsigned long first;		/* first octet to fetch */
+  unsigned long last;		/* number of octets to fetch */
+  long flags;			/* fetch flags */
+  long binary;			/* binary flags */
+} TEXTARGS;
+
+#define FTB_BINARY 0x1		/* fetch as binary */
+#define FTB_SIZE 0x2		/* fetch size only */
+
+
+/* Append data */
+
+typedef struct append_data {
+  unsigned char *arg;		/* append argument pointer */
+  char *flags;			/* message flags */
+  char *date;			/* message date */
+  char *msg;			/* message text */
+  STRING *message;		/* message stringstruct */
+} APPENDDATA;
+
+
+/* Message pointer */
+
+typedef struct msg_data {
+  MAILSTREAM *stream;		/* stream */
+  unsigned long msgno;		/* message number */
+  char *flags;			/* current flags */
+  char *date;			/* current date */
+  STRING *message;		/* stringstruct of message */
+} MSGDATA;
+
+/* Function prototypes */
+
+int main (int argc,char *argv[]);
+void ping_mailbox (unsigned long uid);
+time_t palert (char *file,time_t oldtime);
+void msg_string_init (STRING *s,void *data,unsigned long size);
+char msg_string_next (STRING *s);
+void msg_string_setpos (STRING *s,unsigned long i);
+void new_flags (MAILSTREAM *stream);
+void settimeout (unsigned int i);
+void clkint (void);
+void kodint (void);
+void hupint (void);
+void trmint (void);
+void staint (void);
+char *sout (char *s,char *t);
+char *nout (char *s,unsigned long n,unsigned long base);
+void slurp (char *s,int n,unsigned long timeout);
+void inliteral (char *s,unsigned long n);
+unsigned char *flush (void);
+void ioerror (FILE *f,char *reason);
+unsigned char *parse_astring (unsigned char **arg,unsigned long *i,
+			      unsigned char *del);
+unsigned char *snarf (unsigned char **arg);
+unsigned char *snarf_base64 (unsigned char **arg);
+unsigned char *snarf_list (unsigned char **arg);
+STRINGLIST *parse_stringlist (unsigned char **s,int *list);
+unsigned long uidmax (MAILSTREAM *stream);
+long parse_criteria (SEARCHPGM *pgm,unsigned char **arg,unsigned long maxmsg,
+		     unsigned long maxuid,unsigned long depth);
+long parse_criterion (SEARCHPGM *pgm,unsigned char **arg,unsigned long msgmsg,
+		      unsigned long maxuid,unsigned long depth);
+long crit_date (unsigned short *date,unsigned char **arg);
+long crit_date_work (unsigned short *date,unsigned char **arg);
+long crit_set (SEARCHSET **set,unsigned char **arg,unsigned long maxima);
+long crit_number (unsigned long *number,unsigned char **arg);
+long crit_string (STRINGLIST **string,unsigned char **arg);
+
+void fetch (char *t,unsigned long uid);
+typedef void (*fetchfn_t) (unsigned long i,void *args);
+void fetch_work (char *t,unsigned long uid,fetchfn_t f[],void *fa[]);
+void fetch_bodystructure (unsigned long i,void *args);
+void fetch_body (unsigned long i,void *args);
+void fetch_body_part_mime (unsigned long i,void *args);
+void fetch_body_part_contents (unsigned long i,void *args);
+void fetch_body_part_binary (unsigned long i,void *args);
+void fetch_body_part_header (unsigned long i,void *args);
+void fetch_body_part_text (unsigned long i,void *args);
+void remember (unsigned long uid,char *id,SIZEDTEXT *st);
+void fetch_envelope (unsigned long i,void *args);
+void fetch_encoding (unsigned long i,void *args);
+void changed_flags (unsigned long i,int f);
+void fetch_flags (unsigned long i,void *args);
+void put_flag (int *c,char *s);
+void fetch_internaldate (unsigned long i,void *args);
+void fetch_uid (unsigned long i,void *args);
+void fetch_rfc822 (unsigned long i,void *args);
+void fetch_rfc822_header (unsigned long i,void *args);
+void fetch_rfc822_size (unsigned long i,void *args);
+void fetch_rfc822_text (unsigned long i,void *args);
+void penv (ENVELOPE *env);
+void pbodystructure (BODY *body);
+void pbody (BODY *body);
+void pparam (PARAMETER *param);
+void paddr (ADDRESS *a);
+void pset (SEARCHSET **set);
+void pnum (unsigned long i);
+void pstring (char *s);
+void pnstring (char *s);
+void pastring (char *s);
+void psizedquoted (SIZEDTEXT *s);
+void psizedliteral (SIZEDTEXT *s,STRING *st);
+void psizedstring (SIZEDTEXT *s,STRING *st);
+void psizedastring (SIZEDTEXT *s);
+void pastringlist (STRINGLIST *s);
+void pnstringorlist (STRINGLIST *s);
+void pbodypartstring (unsigned long msgno,char *id,SIZEDTEXT *st,STRING *bs,
+		      TEXTARGS *ta);
+void ptext (SIZEDTEXT *s,STRING *st);
+void pthread (THREADNODE *thr);
+void pcapability (long flag);
+long nameok (char *ref,char *name);
+char *bboardname (char *cmd,char *name);
+long isnewsproxy (char *name);
+long newsproxypattern (char *ref,char *pat,char *pattern,long flag);
+char *imap_responder (void *challenge,unsigned long clen,unsigned long *rlen);
+long proxycopy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long proxy_append (MAILSTREAM *stream,void *data,char **flags,char **date,
+		   STRING **message);
+long append_msg (MAILSTREAM *stream,void *data,char **flags,char **date,
+		 STRING **message);
+void copyuid (MAILSTREAM *stream,char *mailbox,unsigned long uidvalidity,
+	      SEARCHSET *sourceset,SEARCHSET *destset);
+void appenduid (char *mailbox,unsigned long uidvalidity,SEARCHSET *set);
+char *referral (MAILSTREAM *stream,char *url,long code);
+void mm_list_work (char *what,int delimiter,char *name,long attributes);
+char *lasterror (void);
+
+/* Global storage */
+
+char *version = "404";		/* edit number of this server */
+char *logout = "Logout";	/* syslogreason for logout */
+char *goodbye = NIL;		/* bye reason */
+time_t alerttime = 0;		/* time of last alert */
+time_t sysalerttime = 0;	/* time of last system alert */
+time_t useralerttime = 0;	/* time of last user alert */
+time_t lastcheck = 0;		/* time of last checkpoint */
+time_t shutdowntime = 0;	/* time of last shutdown */
+int state = LOGIN;		/* server state */
+int cancelled = NIL;		/* authenticate cancelled */
+int trycreate = 0;		/* saw a trycreate */
+int finding = NIL;		/* doing old FIND command */
+int anonymous = 0;		/* non-zero if anonymous */
+int critical = NIL;		/* non-zero if in critical code */
+int quell_events = NIL;		/* non-zero if in FETCH response */
+int existsquelled = NIL;	/* non-zero if an EXISTS was quelled */
+int proxylist = NIL;		/* doing a proxy LIST */
+MAILSTREAM *stream = NIL;	/* mailbox stream */
+DRIVER *curdriver = NIL;	/* note current driver */
+MAILSTREAM *tstream = NIL;	/* temporary mailbox stream */
+unsigned int nflags = 0;	/* current number of keywords */
+unsigned long nmsgs =0xffffffff;/* last reported # of messages and recent */
+unsigned long recent = 0xffffffff;
+char *nntpproxy = NIL;		/* NNTP proxy name */
+unsigned char *user = NIL;	/* user name */
+unsigned char *pass = NIL;	/* password */
+unsigned char *initial = NIL;	/* initial response */
+unsigned char cmdbuf[CMDLEN];	/* command buffer */
+char *status = "starting up";	/* server status */
+char *tag;			/* tag portion of command */
+unsigned char *cmd;		/* command portion of command */
+unsigned char *arg;		/* pointer to current argument of command */
+char *lstwrn = NIL;		/* last warning message from c-client */
+char *lsterr = NIL;		/* last error message from c-client */
+char *lstref = NIL;		/* last referral from c-client */
+char *response = NIL;		/* command response */
+struct {
+  unsigned long size;		/* size of current LITERAL+ */
+  unsigned int ok : 1;		/* LITERAL+ in effect */
+} litplus;
+int litsp = 0;			/* literal stack pointer */
+char *litstk[LITSTKLEN];	/* stack to hold literals */
+unsigned long uidvalidity = 0;	/* last reported UID validity */
+unsigned long lastuid = 0;	/* last fetched uid */
+char *lastid = NIL;		/* last fetched body id for this message */
+char *lastsel = NIL;		/* last selected mailbox name */
+SIZEDTEXT lastst = {NIL,0};	/* last sizedtext */
+unsigned long cauidvalidity = 0;/* UIDVALIDITY for COPYUID/APPENDUID */
+SEARCHSET *csset = NIL;		/* COPYUID source set */
+SEARCHSET *caset = NIL;		/* COPYUID/APPENDUID destination set */
+jmp_buf jmpenv;			/* stack context for setjmp */
+
+
+/* Response texts which appear in multiple places */
+
+char *win = "%.80s OK ";
+char *rowin = "%.80s OK [READ-ONLY] %.80s completed\015\012";
+char *rwwin = "%.80s OK [READ-WRITE] %.80s completed\015\012";
+char *lose = "%.80s NO ";
+char *logwin = "%.80s OK [";
+char *losetry = "%.80s NO [TRYCREATE] %.80s failed: %.900s\015\012";
+char *loseunknowncte = "%.80s NO [UNKNOWN-CTE] %.80s failed: %.900s\015\012";
+char *badcmd = "%.80s BAD Command unrecognized: %.80s\015\012";
+char *misarg = "%.80s BAD Missing or invalid argument to %.80s\015\012";
+char *badarg = "%.80s BAD Argument given to %.80s when none expected\015\012";
+char *badseq = "%.80s BAD Bogus sequence in %.80s: %.80s\015\012";
+char *badatt = "%.80s BAD Bogus attribute list in %.80s\015\012";
+char *badbin = "%.80s BAD Syntax error in binary specifier\015\012";
+
+/* Message string driver for message stringstructs */
+
+STRINGDRIVER msg_string = {
+  msg_string_init,		/* initialize string structure */
+  msg_string_next,		/* get next byte in string structure */
+  msg_string_setpos		/* set position in string structure */
+};
+
+/* Main program */
+
+int main (int argc,char *argv[])
+{
+  unsigned long i,uid;
+  long f;
+  unsigned char *s,*t,*u,*v,tmp[MAILTMPLEN];
+  struct stat sbuf;
+  logouthook_t lgoh;
+  int ret = 0;
+  time_t autologouttime = 0;
+  char *pgmname;
+				/* if case we get borked immediately */
+  if (setjmp (jmpenv)) _exit (1);
+  pgmname = (argc && argv[0]) ?
+    (((s = strrchr (argv[0],'/')) || (s = strrchr (argv[0],'\\'))) ?
+     (char *) s+1 : argv[0]) : "imapd";
+				/* set service name before linkage */
+  mail_parameters (NIL,SET_SERVICENAME,(void *) "imap");
+#include "linkage.c"
+  rfc822_date (tmp);		/* get date/time at startup */
+				/* initialize server */
+  server_init (pgmname,"imap","imaps",clkint,kodint,hupint,trmint,staint);
+				/* forbid automatic untagged expunge */
+  mail_parameters (NIL,SET_EXPUNGEATPING,NIL);
+				/* arm proxy copy callback */
+  mail_parameters (NIL,SET_MAILPROXYCOPY,(void *) proxycopy);
+				/* arm referral callback */
+  mail_parameters (NIL,SET_IMAPREFERRAL,(void *) referral);
+				/* arm COPYUID callback */
+  mail_parameters (NIL,SET_COPYUID,(void *) copyuid);
+				/* arm APPENDUID callback */
+  mail_parameters (NIL,SET_APPENDUID,(void *) appenduid);
+
+  if (stat (SHUTDOWNFILE,&sbuf)) {
+    char proxy[MAILTMPLEN];
+    FILE *nntp = fopen (NNTPFILE,"r");
+    if (nntp) {			/* desire NNTP proxy? */
+      if (fgets (proxy,MAILTMPLEN,nntp)) {
+				/* remove newline and set NNTP proxy */
+	if (s = strchr (proxy,'\n')) *s = '\0';
+	nntpproxy = cpystr (proxy);
+				/* disable the news driver */
+	mail_parameters (NIL,DISABLE_DRIVER,"news");
+      }
+      fclose (nntp);		/* done reading proxy name */
+    }
+    s = myusername_full (&i);	/* get user name and flags */
+    switch (i) {
+    case MU_NOTLOGGEDIN:
+      PSOUT ("* OK [");		/* not logged in, ordinary startup */
+      pcapability (-1);
+      break;
+    case MU_ANONYMOUS:
+      anonymous = T;		/* anonymous user, fall into default */
+      s = "ANONYMOUS";
+    case MU_LOGGEDIN:
+      PSOUT ("* PREAUTH [");	/* already logged in, pre-authorized */
+      pcapability (1);
+      user = cpystr (s);	/* copy user name */
+      pass = cpystr ("*");	/* set fake password */
+      state = SELECT;		/* enter select state */
+      break;
+    default:
+      fatal ("Unknown state from myusername_full()");
+    }
+    PSOUT ("] ");
+    if (user) {			/* preauthenticated as someone? */
+      PSOUT ("Pre-authenticated user ");
+      PSOUT (user);
+      PBOUT (' ');
+    }
+  }
+  else {			/* login disabled */
+    PSOUT ("* BYE Service not available ");
+    state = LOGOUT;
+  }
+  PSOUT (tcp_serverhost ());
+  PSOUT (" IMAP4rev1 ");
+  PSOUT (CCLIENTVERSION);
+  PBOUT ('.');
+  PSOUT (version);
+  PSOUT (" at ");
+  PSOUT (tmp);
+  CRLF;
+  PFLUSH ();			/* dump output buffer */
+  switch (state) {		/* do this after the banner */
+  case LOGIN:
+    autologouttime = time (0) + LOGINTIMEOUT;
+    break;
+  case SELECT:
+    syslog (LOG_INFO,"Preauthenticated user=%.80s host=%.80s",
+	    user,tcp_clienthost ());
+    break;
+  }
+
+  if (setjmp (jmpenv)) {	/* die if a signal handler say so */
+				/* in case we get borked now */
+    if (setjmp (jmpenv)) _exit (1);
+				/* need to close stream gracefully? */
+    if (stream && !stream->lock && (stream->dtb->flags & DR_XPOINT))
+      stream = mail_close (stream);
+    ret = 1;			/* set exit status */
+  }
+  else while (state != LOGOUT) {/* command processing loop */
+    slurp (cmdbuf,CMDLEN,TIMEOUT);
+				/* no more last error or literal */
+    if (lstwrn) fs_give ((void **) &lstwrn);
+    if (lsterr) fs_give ((void **) &lsterr);
+    if (lstref) fs_give ((void **) &lstref);
+    while (litsp) fs_give ((void **) &litstk[--litsp]);
+				/* find end of line */
+    if (!strchr (cmdbuf,'\012')) {
+      if (t = strchr (cmdbuf,' ')) *t = '\0';
+      if ((t - cmdbuf) > 100) t = NIL;
+      flush ();			/* flush excess */
+      if (state == LOGIN)	/* error if NLI */
+	syslog (LOG_INFO,"Line too long before authentication host=%.80s",
+		tcp_clienthost ());
+      sprintf (tmp,response,t ? (char *) cmdbuf : "*");
+      PSOUT (tmp);
+    }
+    else if (!(tag = strtok (cmdbuf," \015\012"))) {
+      if (state == LOGIN)	/* error if NLI */
+	syslog (LOG_INFO,"Null command before authentication host=%.80s",
+		tcp_clienthost ());
+      PSOUT ("* BAD Null command\015\012");
+    }
+    else if (strlen (tag) > 50) PSOUT ("* BAD Excessively long tag\015\012");
+    else if (!(s = strtok (NIL," \015\012"))) {
+      if (state == LOGIN)	/* error if NLI */
+	syslog (LOG_INFO,"Missing command before authentication host=%.80s",
+		tcp_clienthost ());
+      PSOUT (tag);
+      PSOUT (" BAD Missing command\015\012");
+    }
+    else {			/* parse command */
+      response = win;		/* set default response */
+      finding = NIL;		/* no longer FINDing */
+      ucase (s);		/* canonicalize command case */
+				/* UID command? */
+      if (!strcmp (s,"UID") && strtok (NIL," \015\012")) {
+	uid = T;		/* a UID command */
+	s[3] = ' ';		/* restore the space delimiter */
+	ucase (s);		/* make sure command all uppercase */
+      }
+      else uid = NIL;		/* not a UID command */
+				/* flush previous saved command */
+      if (cmd) fs_give ((void **) &cmd);
+      cmd = cpystr (s);		/* save current command */
+				/* snarf argument, see if possible litplus */
+      if ((arg = strtok (NIL,"\015\012")) && ((i = strlen (arg)) > 3) &&
+	  (arg[i - 1] == '}') && (arg[i - 2] == '+') && isdigit (arg[i - 3])) {
+				/* back over possible count */
+	for (i -= 4; i && isdigit (arg[i]); i--);
+	if (arg[i] == '{') {	/* found a literal? */
+	  litplus.ok = T;	/* yes, note LITERAL+ in effect, set size */
+	  litplus.size = strtoul (arg + i + 1,NIL,10);
+	}
+      }
+
+				/* these commands always valid */
+      if (!strcmp (cmd,"NOOP")) {
+	if (arg) response = badarg;
+	else if (stream)	/* allow untagged EXPUNGE */
+	  mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
+      }
+      else if (!strcmp (cmd,"LOGOUT")) {
+	if (arg) response = badarg;
+	else {			/* time to say farewell */
+	  server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
+	  if (lastsel) fs_give ((void **) &lastsel);
+	  if (state == OPEN) stream = mail_close (stream);
+	  state = LOGOUT;
+	  PSOUT ("* BYE ");
+	  PSOUT (mylocalhost ());
+	  PSOUT (" IMAP4rev1 server terminating connection\015\012");
+	}
+      }
+      else if (!strcmp (cmd,"CAPABILITY")) {
+	if (arg) response = badarg;
+	else {
+	  PSOUT ("* ");
+	  pcapability (0);	/* print capabilities */
+	  CRLF;
+	}
+	if (stream)		/* allow untagged EXPUNGE */
+	  mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
+      }
+#ifdef NETSCAPE_BRAIN_DAMAGE
+      else if (!strcmp (cmd,"NETSCAPE")) {
+	PSOUT ("* OK [NETSCAPE]\015\012* VERSION 1.0 UNIX\015\012* ACCOUNT-URL \"");
+	PSOUT (NETSCAPE_BRAIN_DAMAGE);
+	PBOUT ('"');
+	CRLF;
+      }
+#endif
+
+      else switch (state) {	/* dispatch depending upon state */
+      case LOGIN:		/* waiting to get logged in */
+				/* new style authentication */
+	if (!strcmp (cmd,"AUTHENTICATE")) {
+	  if (user) fs_give ((void **) &user);
+	  if (pass) fs_give ((void **) &pass);
+	  initial = NIL;	/* no initial argument */
+	  cancelled = NIL;	/* not cancelled */
+				/* mandatory first argument */
+	  if (!(s = snarf (&arg))) response = misarg;
+	  else if (arg && !(initial = snarf_base64 (&arg)))
+	    response = misarg;	/* optional second argument */
+	  else if (arg) response = badarg;
+	  else if (!strcmp (ucase (s),"ANONYMOUS") && !stat (ANOFILE,&sbuf)) {
+	    if (!(s = imap_responder ("",0,NIL)))
+	      response ="%.80s BAD AUTHENTICATE ANONYMOUS cancelled\015\012";
+	    else if (anonymous_login (argc,argv)) {
+	      anonymous = T;	/* note we are anonymous */
+	      user = cpystr ("ANONYMOUS");
+	      pass = cpystr ("*");
+	      state = SELECT;	/* make select */
+	      alerttime = 0;	/* force alert */
+	      response = logwin;/* return logged-in capabilities */
+	      syslog (LOG_INFO,"Authenticated anonymous=%.80s host=%.80s",s,
+		      tcp_clienthost ());
+	      fs_give ((void **) &s);
+	    }
+	    else response ="%.80s NO AUTHENTICATE ANONYMOUS failed\015\012";
+	  }
+	  else if (user = cpystr (mail_auth (s,imap_responder,argc,argv))) {
+	    pass = cpystr ("*");
+	    state = SELECT;	/* make select */
+	    alerttime = 0;	/* force alert */
+	    response = logwin;	/* return logged-in capabilities */
+	    syslog (LOG_INFO,"Authenticated user=%.80s host=%.80s mech=%.80s",
+		    user,tcp_clienthost (),s);
+	  }
+
+	  else {
+	    AUTHENTICATOR *auth = mail_lookup_auth (1);
+	    char *msg = (char *) fs_get (strlen (cmd) + strlen (s) + 2);
+	    sprintf (msg,"%s %s",cmd,s);
+	    fs_give ((void **) &cmd);
+	    cmd = msg;
+	    for (i = !mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL);
+		 auth && compare_cstring (s,auth->name); auth = auth->next);
+	    /* Failed authentication when hidden looks like invalid command.
+	     * This is intentional but confused me when I was debugging.
+	     */
+	    if (auth && auth->server && !(auth->flags & AU_DISABLE) &&
+		!(auth->flags & AU_HIDE) && (i || (auth->flags & AU_SECURE))) {
+	      response = lose;
+	      if (cancelled) {
+		if (lsterr) fs_give ((void **) &lsterr);
+		lsterr = cpystr ("cancelled by user");
+	      }
+	      if (!lsterr)	/* catch-all */
+		lsterr = cpystr ("Invalid authentication credentials");
+	      syslog (LOG_INFO,"AUTHENTICATE %.80s failure host=%.80s",s,
+		      tcp_clienthost ());
+	    }
+	    else {
+	      response = badcmd;
+	      syslog (LOG_INFO,"AUTHENTICATE %.80s invalid host=%.80s",s,
+		      tcp_clienthost ());
+	    }
+	  }
+	}
+
+				/* plaintext login with password */
+	else if (!strcmp (cmd,"LOGIN")) {
+	  if (user) fs_give ((void **) &user);
+	  if (pass) fs_give ((void **) &pass);
+				/* two arguments */
+	  if (!((user = cpystr (snarf (&arg))) &&
+		(pass = cpystr (snarf (&arg))))) response = misarg;
+	  else if (arg) response = badarg;
+				/* see if we allow anonymous */
+	  else if (!compare_cstring (user,"ANONYMOUS") &&
+		   !stat (ANOFILE,&sbuf) && anonymous_login (argc,argv)) {
+	    anonymous = T;	/* note we are anonymous */
+	    ucase (user);	/* make all uppercase for consistency */
+	    state = SELECT;	/* make select */
+	    alerttime = 0;	/* force alert */
+	    response = logwin;	/* return logged-in capabilities */
+	    syslog (LOG_INFO,"Login anonymous=%.80s host=%.80s",pass,
+		    tcp_clienthost ());
+	  }
+	  else {		/* delimit user from possible admin */
+	    if (s = strchr (user,'*')) *s++ ='\0';
+				/* see if username and password are OK */
+	    if (server_login (user,pass,s,argc,argv)) {
+	      state = SELECT;	/* make select */
+	      alerttime = 0;	/* force alert */
+	      response = logwin;/* return logged-in capabilities */
+	      syslog (LOG_INFO,"Login user=%.80s host=%.80s",user,
+		      tcp_clienthost ());
+	    }
+	    else {
+	      response = lose;
+	      if (!lsterr) lsterr = cpystr ("Invalid login credentials");
+	    }
+	  }
+	}
+				/* start TLS security */
+	else if (!strcmp (cmd,"STARTTLS")) {
+	  if (arg) response = badarg;
+	  else if (lsterr = ssl_start_tls (pgmname)) response = lose;
+	}
+	else response = badcmd;
+	break;
+
+      case OPEN:		/* valid only when mailbox open */
+				/* fetch mailbox attributes */
+	if (!strcmp (cmd,"FETCH") || !strcmp (cmd,"UID FETCH")) {
+	  if (!(arg && (s = strtok (arg," ")) && (t = strtok(NIL,"\015\012"))))
+	    response = misarg;
+	  else if (uid ? mail_uid_sequence (stream,s) :
+		   mail_sequence (stream,s)) fetch (t,uid);
+	  else response = badseq;
+	}
+				/* store mailbox attributes */
+	else if (!strcmp (cmd,"STORE") || !strcmp (cmd,"UID STORE")) {
+				/* must have three arguments */
+	  if (!(arg && (s = strtok (arg," ")) && (v = strtok (NIL," ")) &&
+		(t = strtok (NIL,"\015\012")))) response = misarg;
+	  else if (!(uid ? mail_uid_sequence (stream,s) :
+		     mail_sequence (stream,s))) response = badseq;
+	  else {
+	    f = ST_SET | (uid ? ST_UID : NIL)|((v[5]&&v[6]) ? ST_SILENT : NIL);
+	    if (!strcmp (ucase (v),"FLAGS") || !strcmp (v,"FLAGS.SILENT")) {
+	      strcpy (tmp,"\\Answered \\Flagged \\Deleted \\Draft \\Seen");
+	      for (i = 0, u = tmp;
+		   (i < NUSERFLAGS) && (v = stream->user_flags[i]); i++)
+	        if (strlen (v) <
+		    ((size_t) (MAILTMPLEN - ((u += strlen (u)) + 2 - tmp)))) {
+		  *u++ = ' ';	/* write next flag */
+		  strcpy (u,v);
+		}
+	      mail_flag (stream,s,tmp,f & ~ST_SET);
+	    }
+	    else if (!strcmp (v,"-FLAGS") || !strcmp (v,"-FLAGS.SILENT"))
+	      f &= ~ST_SET;	/* clear flags */
+	    else if (strcmp (v,"+FLAGS") && strcmp (v,"+FLAGS.SILENT")) {
+	      response = badatt;
+	      break;
+	    }
+				/* find last keyword */
+	    for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i]; i++);
+	    mail_flag (stream,s,t,f);
+				/* any new keywords appeared? */
+	    if (i < NUSERFLAGS && stream->user_flags[i]) new_flags (stream);
+				/* return flags if silence not wanted */
+	    if (uid ? mail_uid_sequence (stream,s) : mail_sequence (stream,s))
+	      for (i = 1; i <= nmsgs; i++) if (mail_elt(stream,i)->sequence)
+		mail_elt (stream,i)->spare2 = (f & ST_SILENT) ? NIL : T;
+	  }
+	}
+
+				/* check for new mail */
+	else if (!strcmp (cmd,"CHECK")) {
+				/* no arguments */
+	  if (arg) response = badarg;
+	  else if (!anonymous) {
+	    mail_check (stream);
+				/* remember last check time */
+	    lastcheck = time (0);
+	  }
+	}
+				/* expunge deleted messages */
+	else if (!(anonymous || (strcmp (cmd,"EXPUNGE") &&
+				 strcmp (cmd,"UID EXPUNGE")))) {
+	  if (uid && !arg) response = misarg;
+	  else if (!uid && arg) response = badarg;
+	  else {		/* expunge deleted or specified UIDs */
+	    mail_expunge_full (stream,arg,arg ? EX_UID : NIL);
+				/* remember last checkpoint */
+	    lastcheck = time (0);
+	  }
+	}
+				/* close mailbox */
+	else if (!strcmp (cmd,"CLOSE") || !strcmp (cmd,"UNSELECT")) {
+				/* no arguments */
+	  if (arg) response = badarg;
+	  else {
+				/* no last uid */
+	    uidvalidity = lastuid = 0;
+	    if (lastsel) fs_give ((void **) &lastsel);
+	    if (lastid) fs_give ((void **) &lastid);
+	    if (lastst.data) fs_give ((void **) &lastst.data);
+	    stream = mail_close_full (stream,((*cmd == 'C') && !anonymous) ?
+				      CL_EXPUNGE : NIL);
+	    state = SELECT;	/* no longer opened */
+	    lastcheck = 0;	/* no last checkpoint */
+	  }
+	}
+	else if (!anonymous &&	/* copy message(s) */
+		 (!strcmp (cmd,"COPY") || !strcmp (cmd,"UID COPY"))) {
+	  trycreate = NIL;	/* no trycreate status */
+	  if (!(arg && (s = strtok (arg," ")) && (arg = strtok(NIL,"\015\012"))
+		&& (t = snarf (&arg)))) response = misarg;
+	  else if (arg) response = badarg;
+	  else if (!nmsgs) {
+	    response = lose;
+	    if (!lsterr) lsterr = cpystr ("Mailbox is empty");
+	  }
+	  else if (!(uid ? mail_uid_sequence (stream,s) :
+		     mail_sequence (stream,s))) response = badseq;
+				/* try copy */
+	  else if (!mail_copy_full (stream,s,t,uid ? CP_UID : NIL)) {
+	    response = trycreate ? losetry : lose;
+	    if (!lsterr) lsterr = cpystr ("No such destination mailbox");
+	  }
+	}
+
+				/* sort mailbox */
+	else if (!strcmp (cmd,"SORT") || !strcmp (cmd,"UID SORT")) {
+				/* must have four arguments */
+	  if (!(arg && (*arg == '(') && (t = strchr (s = arg + 1,')')) &&
+		(t[1] == ' ') && (*(arg = t + 2)))) response = misarg;
+	  else {		/* read criteria */
+	    SEARCHPGM *spg = NIL;
+	    char *cs = NIL;
+	    SORTPGM *pgm = NIL,*pg = NIL;
+	    unsigned long *slst,*sl;
+	    *t = NIL;		/* tie off criteria list */
+	    if (!(s = strtok (ucase (s)," "))) response = badatt;
+	    else {
+	      do {		/* parse sort attributes */
+		if (pg) pg = pg->next = mail_newsortpgm ();
+		else pgm = pg = mail_newsortpgm ();
+		if (!strcmp (s,"REVERSE")) {
+		  pg->reverse = T;
+		  if (!(s = strtok (NIL," "))) {
+		    s = "";	/* end of attributes */
+		    break;
+		  }
+		}
+		if (!strcmp (s,"DATE")) pg->function = SORTDATE;
+		else if (!strcmp (s,"ARRIVAL")) pg->function = SORTARRIVAL;
+		else if (!strcmp (s,"FROM")) pg->function = SORTFROM;
+		else if (!strcmp (s,"SUBJECT")) pg->function = SORTSUBJECT;
+		else if (!strcmp (s,"TO")) pg->function = SORTTO;
+		else if (!strcmp (s,"CC")) pg->function = SORTCC;
+		else if (!strcmp (s,"SIZE")) pg->function = SORTSIZE;
+		else break;
+	      } while (s = strtok (NIL," "));
+				/* bad SORT attribute */
+	      if (s) response = badatt;
+				/* get charset and search criteria */
+	      else if (!((t = snarf (&arg)) && (cs = cpystr (t)) && arg &&
+			 *arg)) response = misarg;
+				/* parse search criteria  */
+	      else if (!parse_criteria (spg = mail_newsearchpgm (),&arg,nmsgs,
+					uidmax (stream),0)) response = badatt;
+	      else if (arg && *arg) response = badarg;
+	      else if (slst = mail_sort (stream,cs,spg,pgm,uid ? SE_UID:NIL)) {
+		PSOUT ("* SORT");
+		for (sl = slst; *sl; sl++) {
+		  PBOUT (' ');
+		  pnum (*sl);
+		}
+		CRLF;
+		fs_give ((void **) &slst);
+	      }
+	    }
+	    if (pgm) mail_free_sortpgm (&pgm);
+	    if (spg) mail_free_searchpgm (&spg);
+	    if (cs) fs_give ((void **) &cs);
+	  }
+	}
+
+				/* thread mailbox */
+	else if (!strcmp (cmd,"THREAD") || !strcmp (cmd,"UID THREAD")) {
+	  THREADNODE *thr;
+	  SEARCHPGM *spg = NIL;
+	  char *cs = NIL;
+				/* must have four arguments */
+	  if (!(arg && (s = strtok (arg," ")) && (cs = strtok (NIL," ")) &&
+		(cs = cpystr (cs)) && (arg = strtok (NIL,"\015\012"))))
+	    response = misarg;
+	  else if (!parse_criteria (spg = mail_newsearchpgm (),&arg,nmsgs,
+				    uidmax (stream),0)) response = badatt;
+	  else if (arg && *arg) response = badarg;
+	  else {
+	    if (thr = mail_thread (stream,s,cs,spg,uid ? SE_UID : NIL)) {
+	      PSOUT ("* THREAD ");
+	      pthread (thr);
+	      mail_free_threadnode (&thr);
+	    }
+	    else PSOUT ("* THREAD");
+	    CRLF;
+	  }
+	  if (spg) mail_free_searchpgm (&spg);
+	  if (cs) fs_give ((void **) &cs);
+	}
+
+				/* search mailbox */
+        else if (!strcmp (cmd,"SEARCH") || !strcmp (cmd,"UID SEARCH")) {
+	  int retval = NIL;
+	  char *charset = NIL;
+	  SEARCHPGM *pgm;
+	  response = misarg;	/* assume failure */
+	  if (!arg) break;	/* one or more arguments required */
+	  if (((arg[0] == 'R') || (arg[0] == 'r')) &&
+	      ((arg[1] == 'E') || (arg[1] == 'e')) &&
+	      ((arg[2] == 'T') || (arg[2] == 't')) &&
+	      ((arg[3] == 'U') || (arg[3] == 'u')) &&
+	      ((arg[4] == 'R') || (arg[4] == 'r')) &&
+	      ((arg[5] == 'N') || (arg[5] == 'n')) &&
+	      (arg[6] == ' ') && (arg[7] == '(')) {
+	    retval = 0x4000;	/* return is specified */
+	    for (arg += 8; *arg && (*arg != ')'); ) {
+	      if (((arg[0] == 'M') || (arg[0] == 'm')) &&
+		  ((arg[1] == 'I') || (arg[1] == 'i')) &&
+		  ((arg[2] == 'N') || (arg[2] == 'n')) &&
+		  ((arg[3] == ' ') || (arg[3] == ')'))) {
+		retval |= 0x1;
+		arg += 3;
+	      }
+	      else if (((arg[0] == 'M') || (arg[0] == 'm')) &&
+		       ((arg[1] == 'A') || (arg[1] == 'a')) &&
+		       ((arg[2] == 'X') || (arg[2] == 'x')) &&
+		       ((arg[3] == ' ') || (arg[3] == ')'))) {
+		retval |= 0x2;
+		arg += 3;
+	      }
+	      else if (((arg[0] == 'A') || (arg[0] == 'a')) &&
+		       ((arg[1] == 'L') || (arg[1] == 'l')) &&
+		       ((arg[2] == 'L') || (arg[2] == 'l')) &&
+		       ((arg[3] == ' ') || (arg[3] == ')'))) {
+		retval |= 0x4;
+		arg += 3;
+	      }
+	      else if (((arg[0] == 'C') || (arg[0] == 'c')) &&
+		       ((arg[1] == 'O') || (arg[1] == 'o')) &&
+		       ((arg[2] == 'U') || (arg[2] == 'u')) &&
+		       ((arg[3] == 'N') || (arg[3] == 'n')) &&
+		       ((arg[4] == 'T') || (arg[4] == 't')) &&
+		       ((arg[5] == ' ') || (arg[5] == ')'))) {
+		retval |= 0x10;
+		arg += 5;
+	      }
+	      else break;	/* unknown return value */
+				/* more return values to come */
+	      if ((*arg == ' ') && (arg[1] != ')')) ++arg;
+	    }
+				/* RETURN list must be properly terminated */
+	    if ((*arg++ != ')') || (*arg++ != ' ')) break;
+				/* default return value is ALL */
+	    if (!(retval &= 0x3fff)) retval = 0x4;
+	  }
+
+				/* character set specified? */
+	  if (((arg[0] == 'C') || (arg[0] == 'c')) &&
+	      ((arg[1] == 'H') || (arg[1] == 'h')) &&
+	      ((arg[2] == 'A') || (arg[2] == 'a')) &&
+	      ((arg[3] == 'R') || (arg[3] == 'r')) &&
+	      ((arg[4] == 'S') || (arg[4] == 's')) &&
+	      ((arg[5] == 'E') || (arg[5] == 'e')) &&
+	      ((arg[6] == 'T') || (arg[6] == 't')) &&
+	      (arg[7] == ' ')) {
+	    arg += 8;		/* yes, skip over CHARSET token */
+	    if (s = snarf (&arg)) charset = cpystr (s);
+	    else break;		/* missing character set */
+	  }
+				/* must have arguments here */
+	  if (!(arg && *arg)) break;
+	  if (parse_criteria (pgm = mail_newsearchpgm (),&arg,nmsgs,
+			      uidmax (stream),0) && !*arg) {
+	    response = win;	/* looks good, try the search */
+	    mail_search_full (stream,charset,pgm,SE_FREE);
+				/* output search results if success */
+	    if (response == win) {
+	      if (retval) {	/* ESEARCH desired */
+		PSOUT ("* ESEARCH (TAG ");
+		pstring (tag);
+		PBOUT (')');
+		if (uid) PSOUT (" UID");
+				/* wants MIN */
+		if (retval & 0x1) {
+		  for (i = 1; (i <= nmsgs) && !mail_elt (stream,i)->searched;
+		       ++i);
+		  if (i <= nmsgs) {
+		    PSOUT (" MIN ");
+		    pnum (uid ? mail_uid (stream,i) : i);
+		  }
+		}
+				/* wants MAX */
+		if (retval & 0x2) {
+		  for (i = nmsgs; i && !mail_elt (stream,i)->searched; --i);
+		  if (i) {
+		    PSOUT (" MAX ");
+		    pnum (uid ? mail_uid (stream,i) : i);
+		  }
+		}
+
+				/* wants ALL */
+		if (retval & 0x4) {
+		  unsigned long j;
+				/* find first match */
+		  for (i = 1; (i <= nmsgs) && !mail_elt (stream,i)->searched;
+		       ++i);
+		  if (i <= nmsgs) {
+		    PSOUT (" ALL ");
+		    pnum (uid ? mail_uid (stream,i) : i);
+		    j = i;	/* last message output */
+		  }
+		  while (++i <= nmsgs) {
+		    if (mail_elt (stream,i)->searched) {
+		      while ((++i <= nmsgs) && mail_elt (stream,i)->searched);
+				/* previous message is end of range */
+		      if (j != --i) {
+			PBOUT (':');
+			pnum (uid ? mail_uid (stream,i) : i);
+		      }
+		    }
+				/* search for next match */
+		    while ((++i <= nmsgs) && !mail_elt (stream,i)->searched);
+		    if (i <= nmsgs) {
+		      PBOUT (',');
+		      pnum (uid ? mail_uid (stream,i) : i);
+		      j = i;	/* last message output */
+		    }
+		  }
+		}
+				/* wants COUNT */
+		if (retval & 0x10) {
+		  unsigned long j;
+		  for (i = 1, j = 0; i <= nmsgs; ++i)
+		    if (mail_elt (stream,i)->searched) ++j;
+		  PSOUT (" COUNT ");
+		  pnum (j);
+		}
+	      }
+	      else {		/* standard search */
+		PSOUT ("* SEARCH");
+		for (i = 1; i <= nmsgs; ++i)
+		  if (mail_elt (stream,i)->searched) {
+		    PBOUT (' ');
+		    pnum (uid ? mail_uid (stream,i) : i);
+		  }
+	      }
+	      CRLF;
+	    }
+	  }
+	  else mail_free_searchpgm (&pgm);
+	  if (charset) fs_give ((void **) &charset);
+	}
+
+	else			/* fall into select case */
+      case SELECT:		/* valid whenever logged in */
+				/* select new mailbox */
+	  if (!(strcmp (cmd,"SELECT") && strcmp (cmd,"EXAMINE") &&
+		strcmp (cmd,"BBOARD"))) {
+				/* single argument */
+	  if (!(s = snarf (&arg))) response = misarg;
+	  else if (arg) response = badarg;
+	  else if (nameok (NIL,s = bboardname (cmd,s))) {
+	    DRIVER *factory = mail_valid (NIL,s,NIL);
+	    f = (anonymous ? OP_ANONYMOUS + OP_READONLY : NIL) |
+	      ((*cmd == 'S') ? NIL : OP_READONLY);
+	    curdriver = NIL;	/* no drivers known */
+				/* no last uid */
+	    uidvalidity = lastuid = 0;
+	    if (lastid) fs_give ((void **) &lastid);
+	    if (lastst.data) fs_give ((void **) &lastst.data);
+	    nflags = 0;		/* force update */
+	    nmsgs = recent = 0xffffffff;
+	    if (factory && !strcmp (factory->name,"phile") &&
+		(stream = mail_open (stream,s,f | OP_SILENT)) &&
+		(response == win)) {
+	      BODY *b;
+				/* see if proxy open */
+	      if ((mail_elt (stream,1)->rfc822_size < 400) &&
+		  mail_fetchstructure (stream,1,&b) && (b->type == TYPETEXT) &&
+		  (t = mail_fetch_text (stream,1,NIL,&i,NIL)) &&
+		  (i < MAILTMPLEN) && (t[0] == '{')) {
+				/* copy and tie off */
+		strncpy (tmp,t,i)[i] = '\0';
+				/* nuke any trailing newline */
+		if (t = strpbrk (tmp,"\r\n")) *t = '\0';
+				/* try to open proxy */
+		if ((tstream = mail_open (NIL,tmp,f | OP_SILENT)) &&
+		    (response == win) && tstream->nmsgs) {
+		  s = tmp;	/* got it, close the link */
+		  mail_close (stream);
+		  stream = tstream;
+		  tstream = NIL;
+		}
+	      }
+				/* now give the exists event */
+	      stream->silent = NIL;
+	      mm_exists (stream,stream->nmsgs);
+	    }
+	    else if (!factory && isnewsproxy (s)) {
+	      sprintf (tmp,"{%.300s/nntp}%.300s",nntpproxy,(char *) s+6);
+	      stream = mail_open (stream,tmp,f);
+	    }
+				/* open stream normally then */
+	    else stream = mail_open (stream,s,f);
+
+	    if (stream && (response == win)) {
+	      state = OPEN;	/* note state open */
+	      if (lastsel) fs_give ((void **) &lastsel);
+				/* canonicalize INBOX */
+	      if (!compare_cstring (s,"#MHINBOX"))
+		lastsel = cpystr ("#MHINBOX");
+	      else lastsel = cpystr (compare_cstring (s,"INBOX") ?
+				     (char *) s : "INBOX");
+				/* note readonly/readwrite */
+	      response = stream->rdonly ? rowin : rwwin;
+	      if (anonymous)
+		syslog (LOG_INFO,"Anonymous select of %.80s host=%.80s",
+			stream->mailbox,tcp_clienthost ());
+	      lastcheck = 0;	/* no last check */
+	    }
+	    else {		/* failed, nuke old selection */
+	      if (stream) stream = mail_close (stream);
+	      state = SELECT;	/* no mailbox open now */
+	      if (lastsel) fs_give ((void **) &lastsel);
+	      response = lose;	/* open failed */
+	    }
+	  }
+	}
+
+				/* APPEND message to mailbox */
+	else if (!(anonymous || strcmp (cmd,"APPEND"))) {
+				/* parse mailbox name */
+	  if ((s = snarf (&arg)) && arg) {
+	    STRING st;		/* message stringstruct */
+	    APPENDDATA ad;
+	    ad.arg = arg;	/* command arguments */
+				/* no message yet */
+	    ad.flags = ad.date = ad.msg = NIL;
+	    ad.message = &st;	/* pointer to stringstruct to use */
+	    trycreate = NIL;	/* no trycreate status */
+	    if (!mail_append_multiple (NIL,s,append_msg,(void *) &ad)) {
+	      if (response == win) response = trycreate ? losetry : lose;
+				/* this can happen with #driver. hack */
+	      if (!lsterr) lsterr = cpystr ("No such destination mailbox");
+	    }
+				/* clean up any message text left behind */
+	    if (ad.flags) fs_give ((void **) &ad.flags);
+	    if (ad.date) fs_give ((void **) &ad.date);
+	    if (ad.msg) fs_give ((void **) &ad.msg);
+	  }
+	  else response = misarg;
+	  if (stream)		/* allow untagged EXPUNGE */
+	    mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
+	}
+				/* list mailboxes */
+	else if (!strcmp (cmd,"LIST") || !strcmp (cmd,"RLIST")) {
+				/* get reference and mailbox argument */
+	  if (!((s = snarf (&arg)) && (t = snarf_list (&arg))))
+	    response = misarg;
+	  else if (arg) response = badarg;
+				/* make sure anonymous can't do bad things */
+	  else if (nameok (s,t)) {
+	    if (newsproxypattern (s,t,tmp,LONGT)) {
+	      proxylist = T;
+	      mail_list (NIL,"",tmp);
+	      proxylist = NIL;
+	    }
+	    else mail_list (NIL,s,t);
+	  }
+	  if (stream)		/* allow untagged EXPUNGE */
+	    mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
+	}
+				/* scan mailboxes */
+	else if (!strcmp (cmd,"SCAN")) {
+				/* get arguments */
+	  if (!((s = snarf (&arg)) && (t = snarf_list (&arg)) &&
+		(u = snarf (&arg)))) response = misarg;
+	  else if (arg) response = badarg;
+				/* make sure anonymous can't do bad things */
+	  else if (nameok (s,t)) {
+	    if (newsproxypattern (s,t,tmp,NIL))
+	      mm_log ("SCAN not permitted for news",ERROR);
+	    else mail_scan (NIL,s,t,u);
+	  }
+	  if (stream)		/* allow untagged EXPUNGE */
+	    mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
+	}
+				/* list subscribed mailboxes */
+	else if (!strcmp (cmd,"LSUB") || !strcmp (cmd,"RLSUB")) {
+				/* get reference and mailbox argument */
+	  if (!((s = snarf (&arg)) && (t = snarf_list (&arg))))
+	    response = misarg;
+	  else if (arg) response = badarg;
+				/* make sure anonymous can't do bad things */
+	  else if (nameok (s,t)) {
+	    if (newsproxypattern (s,t,tmp,NIL)) newsrc_lsub (NIL,tmp);
+	    else mail_lsub (NIL,s,t);
+	  }
+	  if (stream)		/* allow untagged EXPUNGE */
+	    mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
+	}
+
+				/* find mailboxes */
+	else if (!strcmp (cmd,"FIND")) {
+				/* get subcommand and true argument */
+	  if (!(arg && (s = strtok (arg," \015\012")) && (s == cmd + 5) &&
+		(cmd[4] = ' ') && ucase (s) &&
+		(arg = strtok (NIL,"\015\012")) && (s = snarf_list (&arg))))
+	    response = misarg;	/* missing required argument */
+	  else if (arg) response = badarg;
+				/* punt on single-char wildcards */
+	  else if (strpbrk (s,"%?")) response =
+	    "%.80s NO IMAP2 ? and %% wildcards not supported: %.80s\015\012";
+	  else if (nameok (NIL,s)) {
+	    finding = T;	/* note that we are FINDing */
+				/* dispatch based on type */
+	    if (!strcmp (cmd,"FIND MAILBOXES") && !anonymous)
+	      mail_lsub (NIL,NIL,s);
+	    else if (!strcmp (cmd,"FIND ALL.MAILBOXES")) {
+				/* convert * to % for compatible behavior */
+	      for (t = s; *t; t++) if (*t == '*') *t = '%';
+	      mail_list (NIL,NIL,s);
+	    }
+	    else response = badcmd;
+	  }
+	  if (stream)		/* allow untagged EXPUNGE */
+	    mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
+	}
+
+				/* status of mailbox */
+	else if (!strcmp (cmd,"STATUS")) {
+	  if (!((s = snarf (&arg)) && arg && (*arg++ == '(') &&
+		(t = strchr (arg,')')) && (t - arg) && !t[1]))
+	    response = misarg;
+	  else {
+	    f = NIL;		/* initially no flags */
+	    *t = '\0';		/* tie off flag string */
+				/* read flags */
+	    t = strtok (ucase (arg)," ");
+	    do {		/* parse each one; unknown generate warning */
+	      if (!strcmp (t,"MESSAGES")) f |= SA_MESSAGES;
+	      else if (!strcmp (t,"RECENT")) f |= SA_RECENT;
+	      else if (!strcmp (t,"UNSEEN")) f |= SA_UNSEEN;
+	      else if (!strcmp (t,"UIDNEXT")) f |= SA_UIDNEXT;
+	      else if (!strcmp (t,"UIDVALIDITY")) f |= SA_UIDVALIDITY;
+	      else {
+		PSOUT ("* NO Unknown status flag ");
+		PSOUT (t);
+		CRLF;
+	      }
+	    } while (t = strtok (NIL," "));
+	    ping_mailbox (uid);	/* in case the fool did STATUS on open mbx */
+	    PFLUSH ();		/* make sure stdout is dumped in case slave */
+	    if (!compare_cstring (s,"INBOX")) s = "INBOX";
+	    else if (!compare_cstring (s,"#MHINBOX")) s = "#MHINBOX";
+	    if (state == LOGOUT) response = lose;
+				/* get mailbox status */
+	    else if (lastsel && (!strcmp (s,lastsel) ||
+				 (stream && !strcmp (s,stream->mailbox)))) {
+	      unsigned long unseen;
+				/* snarl at cretins which do this */
+	      PSOUT ("* NO CLIENT BUG DETECTED: STATUS on selected mailbox: ");
+	      PSOUT (s);
+	      CRLF;
+	      tmp[0] = ' '; tmp[1] = '\0';
+	      if (f & SA_MESSAGES)
+		sprintf (tmp + strlen (tmp)," MESSAGES %lu",stream->nmsgs);
+	      if (f & SA_RECENT)
+		sprintf (tmp + strlen (tmp)," RECENT %lu",stream->recent);
+	      if (f & SA_UNSEEN) {
+		for (i = 1,unseen = 0; i <= stream->nmsgs; i++)
+		  if (!mail_elt (stream,i)->seen) unseen++;
+		sprintf (tmp + strlen (tmp)," UNSEEN %lu",unseen);
+	      }
+	      if (f & SA_UIDNEXT)
+		sprintf (tmp + strlen (tmp)," UIDNEXT %lu",stream->uid_last+1);
+	      if (f & SA_UIDVALIDITY)
+		sprintf (tmp + strlen(tmp)," UIDVALIDITY %lu",
+			 stream->uid_validity);
+	      tmp[1] = '(';
+	      strcat (tmp,")\015\012");
+	      PSOUT ("* STATUS ");
+	      pastring (s);
+	      PSOUT (tmp);
+	    }
+	    else if (isnewsproxy (s)) {
+	      sprintf (tmp,"{%.300s/nntp}%.300s",nntpproxy,(char *) s+6);
+	      if (!mail_status (NIL,tmp,f)) response = lose;
+	    }
+	    else if (!mail_status (NIL,s,f)) response = lose;
+	  }
+	  if (stream)		/* allow untagged EXPUNGE */
+	    mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
+	}
+
+				/* subscribe to mailbox */
+	else if (!(anonymous || strcmp (cmd,"SUBSCRIBE"))) {
+				/* get <mailbox> or MAILBOX <mailbox> */
+	  if (!(s = snarf (&arg))) response = misarg;
+	  else if (arg) {	/* IMAP2bis form */
+	    if (compare_cstring (s,"MAILBOX")) response = badarg;
+	    else if (!(s = snarf (&arg))) response = misarg;
+	    else if (arg) response = badarg;
+	    else mail_subscribe (NIL,s);
+	  }
+	  else if (isnewsproxy (s)) newsrc_update (NIL,s+6,':');
+	  else mail_subscribe (NIL,s);
+	  if (stream)		/* allow untagged EXPUNGE */
+	    mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
+	}
+				/* unsubscribe to mailbox */
+	else if (!(anonymous || strcmp (cmd,"UNSUBSCRIBE"))) {
+				/* get <mailbox> or MAILBOX <mailbox> */
+	  if (!(s = snarf (&arg))) response = misarg;
+	  else if (arg) {	/* IMAP2bis form */
+	    if (compare_cstring (s,"MAILBOX")) response = badarg;
+	    else if (!(s = snarf (&arg))) response = misarg;
+	    else if (arg) response = badarg;
+	    else if (isnewsproxy (s)) newsrc_update (NIL,s+6,'!');
+	    else mail_unsubscribe (NIL,s);
+	  }
+	  else mail_unsubscribe (NIL,s);
+	  if (stream)		/* allow untagged EXPUNGE */
+	    mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
+	}
+
+	else if (!strcmp (cmd,"NAMESPACE")) {
+	  if (arg) response = badarg;
+	  else {
+	    NAMESPACE **ns = (NAMESPACE **) mail_parameters(NIL,GET_NAMESPACE,
+							     NIL);
+	    NAMESPACE *n;
+	    PARAMETER *p;
+	    PSOUT ("* NAMESPACE");
+	    if (ns) for (i = 0; i < 3; i++) {
+	      if (n = ns[i]) {
+		PSOUT (" (");
+		do {
+		  PBOUT ('(');
+		  pstring (n->name);
+		  switch (n->delimiter) {
+		  case '\\':	/* quoted delimiter */
+		  case '"':
+		    PSOUT (" \"\\\\\"");
+		    break;
+		  case '\0':	/* no delimiter */
+		    PSOUT (" NIL");
+		    break;
+		  default:	/* unquoted delimiter */
+		    PSOUT (" \"");
+		    PBOUT (n->delimiter);
+		    PBOUT ('"');
+		    break;
+		  }
+				/* NAMESPACE extensions are hairy */
+		  if (p = n->param) do {
+		    PBOUT (' ');
+		    pstring (p->attribute);
+		    PSOUT (" (");
+		    do pstring (p->value);
+		    while (p->next && !p->next->attribute && (p = p->next));
+		    PBOUT (')');
+		  } while (p = p->next);
+		  PBOUT (')');
+		} while (n = n->next);
+		PBOUT (')');
+	      }
+	      else PSOUT (" NIL");
+	    }
+	    else PSOUT (" NIL NIL NIL");
+	    CRLF;
+	  }
+	  if (stream)		/* allow untagged EXPUNGE */
+	    mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
+	}
+
+				/* create mailbox */
+	else if (!(anonymous || strcmp (cmd,"CREATE"))) {
+	  if (!(s = snarf (&arg))) response = misarg;
+	  else if (arg) response = badarg;
+	  else mail_create (NIL,s);
+	  if (stream)		/* allow untagged EXPUNGE */
+	    mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
+	}
+				/* delete mailbox */
+	else if (!(anonymous || strcmp (cmd,"DELETE"))) {
+	  if (!(s = snarf (&arg))) response = misarg;
+	  else if (arg) response = badarg;
+	  else {		/* make sure not selected */
+	    if (lastsel && (!strcmp (s,lastsel) ||
+			    (stream && !strcmp (s,stream->mailbox))))
+	      mm_log ("Can not DELETE the selected mailbox",ERROR);
+	    else mail_delete (NIL,s);
+	  }
+	  if (stream)		/* allow untagged EXPUNGE */
+	    mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
+	}
+				/* rename mailbox */
+	else if (!(anonymous || strcmp (cmd,"RENAME"))) {
+	  if (!((s = snarf (&arg)) && (t = snarf (&arg)))) response = misarg;
+	  else if (arg) response = badarg;
+	  else {		/* make sure not selected */
+	    if (!compare_cstring (s,"INBOX")) s = "INBOX";
+	    else if (!compare_cstring (s,"#MHINBOX")) s = "#MHINBOX";
+	    if (lastsel && (!strcmp (s,lastsel) ||
+			    (stream && !strcmp (s,stream->mailbox))))
+	      mm_log ("Can not RENAME the selected mailbox",ERROR);
+	    else mail_rename (NIL,s,t);
+	  }
+	  if (stream)		/* allow untagged EXPUNGE */
+	    mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,(void *) stream);
+	}
+
+				/* idle mode */
+	else if (!strcmp (cmd,"IDLE")) {
+				/* no arguments */
+	  if (arg) response = badarg;
+	  else {		/* tell client ready for argument */
+	    unsigned long donefake = 0;
+	    PSOUT ("+ Waiting for DONE\015\012");
+	    PFLUSH ();		/* dump output buffer */
+				/* inactivity countdown */
+	    i = ((TIMEOUT) / (IDLETIMER)) + 1;
+	    do {		/* main idle loop */
+	      if (!donefake) {	/* don't ping mailbox if faking */
+		mail_parameters (stream,SET_ONETIMEEXPUNGEATPING,
+				 (void *) stream);
+		ping_mailbox (uid);
+				/* maybe do a checkpoint if not anonymous */
+		if (!anonymous && stream && (time (0) > lastcheck + CHECKTIMER)) {
+		  mail_check (stream);
+				/* cancel likely altwin from mail_check() */
+		  if (lsterr) fs_give ((void **) &lsterr);
+		  if (lstwrn) fs_give ((void **) &lstwrn);
+				/* remember last checkpoint */
+		  lastcheck = time (0);
+		}
+	      }
+	      if (lstwrn) {	/* have a warning? */
+		PSOUT ("* NO ");
+		PSOUT (lstwrn);
+		CRLF;
+		fs_give ((void **) &lstwrn);
+	      }
+	      if (!(i % 2)) {	/* prevent NAT timeouts */
+		sprintf (tmp,"* OK Timeout in %lu minutes\015\012",
+			 (i * IDLETIMER) / 60);
+		PSOUT (tmp);
+	      }
+				/* two minutes before the end... */
+	      if ((state == OPEN) && (i <= 2)) {
+		sprintf (tmp,"* %lu EXISTS\015\012* %lu RECENT\015\012",
+			 donefake = nmsgs + 1,recent + 1);
+		PSOUT (tmp);	/* prod client to wake up */
+	      }
+	      PFLUSH ();	/* dump output buffer */
+	    } while ((state != LOGOUT) && !INWAIT (IDLETIMER) && --i);
+
+				/* time to exit idle loop */
+	    if (state != LOGOUT) {
+	      if (i) {		/* still have time left? */
+				/* yes, read expected DONE */
+		slurp (tmp,MAILTMPLEN,INPUTTIMEOUT);
+		if (((tmp[0] != 'D') && (tmp[0] != 'd')) ||
+		    ((tmp[1] != 'O') && (tmp[1] != 'o')) ||
+		    ((tmp[2] != 'N') && (tmp[2] != 'n')) ||
+		    ((tmp[3] != 'E') && (tmp[3] != 'e')) ||
+		    (((tmp[4] != '\015') || (tmp[5] != '\012')) &&
+		     (tmp[4] != '\012')))
+		  response = "%.80s BAD Bogus IDLE continuation\015\012";
+		if (donefake) {	/* if faking at the end */
+				/* send EXPUNGE (should be just 1) */
+		  while (donefake > nmsgs) {
+		    sprintf (tmp,"* %lu EXPUNGE\015\012",donefake--);
+		    PSOUT (tmp);
+		  }
+		  sprintf (tmp,"* %lu EXISTS\015\012* %lu RECENT\015\012",
+			   nmsgs,recent);
+		  PSOUT (tmp);
+		}
+	      }
+	      else clkint ();	/* otherwise do autologout action */
+	    }
+	  }
+	}
+	else response = badcmd;
+	break;
+      default:
+        response = "%.80s BAD Unknown state for %.80s command\015\012";
+	break;
+      }
+
+      while (litplus.ok) {	/* any unread LITERAL+? */
+	litplus.ok = NIL;	/* yes, cancel it now */
+	clearerr (stdin);	/* clear stdin errors */
+	status = "discarding unread literal";
+				/* read literal and discard it */
+	while (i = (litplus.size > MAILTMPLEN) ? MAILTMPLEN : litplus.size) {
+	  if (state == LOGOUT) litplus.size = 0;
+	  else {
+	    settimeout (INPUTTIMEOUT);
+	    if (PSINR (tmp,i)) litplus.size -= i;
+	    else {
+	      ioerror (stdin,status);
+	      litplus.size = 0;	/* in case it continues */
+	    }
+	  }
+	}
+	settimeout (0);		/* stop timeout */
+				/* get new command tail */
+	slurp (tmp,MAILTMPLEN,INPUTTIMEOUT);
+				/* locate end of line */
+	if (t = strchr (tmp,'\012')) {
+				/* back over CR */
+	  if ((t > tmp) && (t[-1] == '\015')) --t;
+	  *t = NIL;		/* tie off CRLF */
+				/* possible LITERAL+? */
+	  if (((i = strlen (tmp)) > 3) && (tmp[i - 1] == '}') &&
+	      (tmp[i - 2] == '+') && isdigit (tmp[i - 3])) {
+				/* back over possible count */
+	    for (i -= 4; i && isdigit (tmp[i]); i--);
+	    if (tmp[i] == '{') {	/* found a literal? */
+	      litplus.ok = T;	/* yes, note LITERAL+ in effect, set size */
+	      litplus.size = strtoul (tmp + i + 1,NIL,10);
+	    }
+	  }
+	}
+	else flush ();		/* overlong line after LITERAL+, punt */
+      }
+      ping_mailbox (uid);	/* update mailbox status before response */
+      if (lstwrn && lsterr) {	/* output most recent warning */
+	PSOUT ("* NO ");
+	PSOUT (lstwrn);
+	CRLF;
+	fs_give ((void **) &lstwrn);
+      }
+
+      if (response == logwin) {	/* authentication win message */
+	sprintf (tmp,response,lstref ? "*" : tag);
+	PSOUT (tmp);		/* start response */
+	pcapability (1);	/* print logged-in capabilities */
+	PSOUT ("] User ");
+	PSOUT (user);
+	PSOUT (" authenticated\015\012");
+	if (lstref) {
+	  sprintf (tmp,response,tag);
+	  PSOUT (tmp);		/* start response */
+	  PSOUT ("[REFERRAL ");
+	  PSOUT (lstref);
+	  PSOUT ("] ");
+	  PSOUT (lasterror ());
+	  CRLF;
+	}
+      }
+      else if ((response == win) || (response == lose)) {
+	sprintf (tmp,response,tag);
+	PSOUT (tmp);
+	if (cauidvalidity) {	/* COPYUID/APPENDUID response? */
+	  sprintf (tmp,"[%.80sUID %lu ",(char *)
+		   ((s = strchr (cmd,' ')) ? s+1 : cmd),cauidvalidity);
+	  PSOUT (tmp);
+	  cauidvalidity = 0;	/* cancel response for future */
+	  if (csset) {
+	    pset (&csset);
+	    PBOUT (' ');
+	  }
+	  pset (&caset);
+	  PSOUT ("] ");
+	}
+	else if (lstref) {	/* have a referral? */
+	  PSOUT ("[REFERRAL ");
+	  PSOUT (lstref);
+	  PSOUT ("] ");
+	}
+	if (lsterr || lstwrn) PSOUT (lasterror ());
+	else {
+	  PSOUT (cmd);
+	  PSOUT ((response == win) ? " completed" : "failed");
+	}
+	CRLF;
+      }
+      else {			/* normal response */
+	if ((response == rowin) || (response == rwwin)) {
+	  if (lstwrn) {		/* output most recent warning */
+	    PSOUT ("* NO ");
+	    PSOUT (lstwrn);
+	    CRLF;
+	    fs_give ((void **) &lstwrn);
+	  }
+	}
+	sprintf (tmp,response,tag,cmd,lasterror ());
+	PSOUT (tmp);		/* output response */
+      }
+    }
+    PFLUSH ();			/* make sure output blatted */
+
+    if (autologouttime) {	/* have an autologout in effect? */
+				/* cancel if no longer waiting for login */
+      if (state != LOGIN) autologouttime = 0;
+				/* took too long to login */
+      else if (autologouttime < time (0)) {
+	logout = goodbye = "Autologout";
+	stream = NIL;
+	state = LOGOUT;		/* sayonara */
+      }
+    }
+  }
+  if (goodbye && !quell_events){/* have a goodbye message? */
+    PSOUT ("* BYE ");		/* utter it */
+    PSOUT (goodbye);
+    CRLF;
+    PFLUSH ();			/* make sure blatted */
+  }
+  syslog (LOG_INFO,"%s user=%.80s host=%.80s",logout,
+	  user ? (char *) user : "???",tcp_clienthost ());
+				/* do logout hook if needed */
+  if (lgoh = (logouthook_t) mail_parameters (NIL,GET_LOGOUTHOOK,NIL))
+    (*lgoh) (mail_parameters (NIL,GET_LOGOUTDATA,NIL));
+  _exit (ret);			/* all done */
+  return ret;			/* stupid compilers */
+}
+
+/* Ping mailbox during each cycle.  Also check alerts
+ * Accepts: last command was UID flag
+ */
+
+void ping_mailbox (unsigned long uid)
+{
+  unsigned long i;
+  char tmp[MAILTMPLEN];
+  if (state == OPEN) {
+    if (!mail_ping (stream)) {	/* make sure stream still alive */
+      PSOUT ("* BYE ");
+      PSOUT (mylocalhost ());
+      PSOUT (" Fatal mailbox error: ");
+      PSOUT (lasterror ());
+      CRLF;
+      stream = NIL;		/* don't try to clean up stream */
+      state = LOGOUT;		/* go away */
+      syslog (LOG_INFO,
+	      "Fatal mailbox error user=%.80s host=%.80s mbx=%.80s: %.80s",
+	      user ? (char *) user : "???",tcp_clienthost (),
+	      (stream && stream->mailbox) ? stream->mailbox : "???",
+	      lasterror ());
+      return;
+    }
+				/* change in number of messages? */
+    if (existsquelled || (nmsgs != stream->nmsgs)) {
+      PSOUT ("* ");
+      pnum (nmsgs = stream->nmsgs);
+      PSOUT (" EXISTS\015\012");
+    }
+				/* change in recent messages? */
+    if (existsquelled || (recent != stream->recent)) {
+      PSOUT ("* ");
+      pnum (recent = stream->recent);
+      PSOUT (" RECENT\015\012");
+    }
+    existsquelled = NIL;	/* don't do this until asked again */
+    if (stream->uid_validity && (stream->uid_validity != uidvalidity)) {
+      PSOUT ("* OK [UIDVALIDITY ");
+      pnum (stream->uid_validity);
+      PSOUT ("] UID validity status\015\012* OK [UIDNEXT ");
+      pnum (stream->uid_last + 1);
+      PSOUT ("] Predicted next UID\015\012");
+      if (stream->uid_nosticky) {
+	PSOUT ("* NO [UIDNOTSTICKY] Non-permanent unique identifiers: ");
+	PSOUT (stream->mailbox);
+	CRLF;
+      }
+      uidvalidity = stream->uid_validity;
+    }
+
+				/* don't bother if driver changed */
+    if (curdriver == stream->dtb) {
+				/* first report any new flags */
+      if ((nflags < NUSERFLAGS) && stream->user_flags[nflags])
+	new_flags (stream);
+      for (i = 1; i <= nmsgs; i++) if (mail_elt (stream,i)->spare2) {
+	PSOUT ("* ");
+	pnum (i);
+	PSOUT (" FETCH (");
+	fetch_flags (i,NIL);	/* output changed flags */
+	if (uid) {		/* need to include UIDs in response? */
+	  PBOUT (' ');
+	  fetch_uid (i,NIL);
+	}
+	PSOUT (")\015\012");
+      }
+    }
+    else {			/* driver changed */
+      new_flags (stream);	/* send mailbox flags */
+      if (curdriver) {		/* note readonly/write if possible change */
+	PSOUT ("* OK [READ-");
+	PSOUT (stream->rdonly ? "ONLY" : "WRITE");
+	PSOUT ("] Mailbox status\015\012");
+      }
+      curdriver = stream->dtb;
+      if (nmsgs) {		/* get flags for all messages */
+	sprintf (tmp,"1:%lu",nmsgs);
+	mail_fetch_flags (stream,tmp,NIL);
+				/* don't do this if newsrc already did */
+	if (!(curdriver->flags & DR_NEWS)) {
+				/* find first unseen message */
+	  for (i = 1; i <= nmsgs && mail_elt (stream,i)->seen; i++);
+	  if (i <= nmsgs) {
+	    PSOUT ("* OK [UNSEEN ");
+	    pnum (i);
+	    PSOUT ("] first unseen message in ");
+	    PSOUT (stream->mailbox);
+	    CRLF;
+	  }
+	}
+      }
+    }
+  }
+  if (shutdowntime && (time (0) > shutdowntime + SHUTDOWNTIMER)) {
+    PSOUT ("* BYE Server shutting down\015\012");
+    state = LOGOUT;
+  }
+				/* don't do these stat()s every cycle */
+  else if (time (0) > alerttime + ALERTTIMER) { 
+    struct stat sbuf;
+				/* have a shutdown file? */
+    if (!stat (SHUTDOWNFILE,&sbuf)) {
+      PSOUT ("* OK [ALERT] Server shutting down shortly\015\012");
+      shutdowntime = time (0);
+    }
+    alerttime = time (0);	/* output any new alerts */
+    sysalerttime = palert (ALERTFILE,sysalerttime);
+    if (state != LOGIN)		/* do user alert if logged in */
+      useralerttime = palert (mailboxfile (tmp,USERALERTFILE),useralerttime);
+  }
+}
+
+/* Print an alert file
+ * Accepts: path of alert file
+ *	    time of last printed alert file
+ * Returns: updated time of last printed alert file
+ */
+
+time_t palert (char *file,time_t oldtime)
+{
+  FILE *alf;
+  struct stat sbuf;
+  int c,lc = '\012';
+				/* have a new alert file? */
+  if (stat (file,&sbuf) || (sbuf.st_mtime <= oldtime) ||
+      !(alf = fopen (file,"r"))) return oldtime;
+				/* yes, display it */
+  while ((c = getc (alf)) != EOF) {
+    if (lc == '\012') PSOUT ("* OK [ALERT] ");
+    switch (c) {		/* output character */
+    case '\012':		/* newline means do CRLF */
+      CRLF;
+    case '\015':		/* flush CRs */
+    case '\0':			/* flush nulls */
+      break;
+    default:
+      PBOUT (c);		/* output all other characters */
+      break;
+    }
+    lc = c;			/* note previous character */
+  }
+  fclose (alf);
+  if (lc != '\012') CRLF;	/* final terminating CRLF */
+  return sbuf.st_mtime;		/* return updated last alert time */
+}
+
+/* Initialize file string structure for file stringstruct
+ * Accepts: string structure
+ *	    pointer to message data structure
+ *	    size of string
+ */
+
+void msg_string_init (STRING *s,void *data,unsigned long size)
+{
+  MSGDATA *md = (MSGDATA *) data;
+  s->data = data;		/* note stream/msgno and header length */
+#if 0
+  s->size = size;		/* message size */
+  s->curpos = s->chunk =	/* load header */
+    mail_fetchheader_full (md->stream,md->msgno,NIL,&s->data1,
+			   FT_PREFETCHTEXT | FT_PEEK);
+#else	/* This kludge is necessary because of broken mail stores */
+  mail_fetchtext_full (md->stream,md->msgno,&s->size,FT_PEEK);
+  s->curpos = s->chunk =	/* load header */
+    mail_fetchheader_full (md->stream,md->msgno,NIL,&s->data1,FT_PEEK);
+  s->size += s->data1;		/* header + body size */
+#endif
+  s->cursize = s->chunksize = s->data1;
+  s->offset = 0;		/* offset is start of message */
+}
+
+
+/* Get next character from file stringstruct
+ * Accepts: string structure
+ * Returns: character, string structure chunk refreshed
+ */
+
+char msg_string_next (STRING *s)
+{
+  char c = *s->curpos++;	/* get next byte */
+  SETPOS (s,GETPOS (s));	/* move to next chunk */
+  return c;			/* return the byte */
+}
+
+
+/* Set string pointer position for file stringstruct
+ * Accepts: string structure
+ *	    new position
+ */
+
+void msg_string_setpos (STRING *s,unsigned long i)
+{
+  MSGDATA *md = (MSGDATA *) s->data;
+  if (i < s->data1) {		/* want header? */
+    s->chunk = mail_fetchheader_full (md->stream,md->msgno,NIL,NIL,FT_PEEK);
+    s->chunksize = s->data1;	/* header length */
+    s->offset = 0;		/* offset is start of message */
+  }
+  else if (i < s->size) {	/* want body */
+    s->chunk = mail_fetchtext_full (md->stream,md->msgno,NIL,FT_PEEK);
+    s->chunksize = s->size - s->data1;
+    s->offset = s->data1;	/* offset is end of header */
+  }
+  else {			/* off end of message */
+    s->chunk = NIL;		/* make sure that we crack on this then */
+    s->chunksize = 1;		/* make sure SNX cracks the right way... */
+    s->offset = i;
+  }
+				/* initial position and size */
+  s->curpos = s->chunk + (i -= s->offset);
+  s->cursize = s->chunksize - i;
+}
+
+/* Send flags for stream
+ * Accepts: MAIL stream
+ *	    scratch buffer
+ */
+
+void new_flags (MAILSTREAM *stream)
+{
+  int i,c;
+  PSOUT ("* FLAGS (");
+  for (i = 0; i < NUSERFLAGS; i++) if (stream->user_flags[i]) {
+    PSOUT (stream->user_flags[i]);
+    PBOUT (' ');
+    nflags = i + 1;
+  }
+  PSOUT ("\\Answered \\Flagged \\Deleted \\Draft \\Seen)\015\012* OK [PERMANENTFLAGS (");
+  for (i = c = 0; i < NUSERFLAGS; i++)
+    if ((stream->perm_user_flags & (1 << i)) && stream->user_flags[i])
+      put_flag (&c,stream->user_flags[i]);
+  if (stream->kwd_create) put_flag (&c,"\\*");
+  if (stream->perm_answered) put_flag (&c,"\\Answered");
+  if (stream->perm_flagged) put_flag (&c,"\\Flagged");
+  if (stream->perm_deleted) put_flag (&c,"\\Deleted");
+  if (stream->perm_draft) put_flag (&c,"\\Draft");
+  if (stream->perm_seen) put_flag (&c,"\\Seen");
+  PSOUT (")] Permanent flags\015\012");
+}
+
+/* Set timeout
+ * Accepts: desired interval
+ */
+
+void settimeout (unsigned int i)
+{
+				/* limit if not logged in */
+  if (i) alarm ((state == LOGIN) ? LOGINTIMEOUT : i);
+  else alarm (0);
+}
+
+
+/* Clock interrupt
+ * Returns only if critical code in progress
+ */
+
+void clkint (void)
+{
+  settimeout (0);		/* disable all interrupts */
+  server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
+  logout = "Autologout";
+  goodbye = "Autologout (idle for too long)";
+  if (critical) {		/* must defer if in critical code(?) */
+    close (0);			/* kill stdin */
+    state = LOGOUT;		/* die as soon as we can */
+  }
+  else longjmp (jmpenv,1);	/* die now */
+}
+
+
+/* Kiss Of Death interrupt
+ * Returns only if critical code in progress
+ */
+
+void kodint (void)
+{
+  settimeout (0);		/* disable all interrupts */
+  server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
+  logout = goodbye = "Killed (lost mailbox lock)";
+  if (critical) {		/* must defer if in critical code */
+    close (0);			/* kill stdin */
+    state = LOGOUT;		/* die as soon as we can */
+  }
+  else longjmp (jmpenv,1);	/* die now */
+}
+
+/* Hangup interrupt
+ * Returns only if critical code in progress
+ */
+
+void hupint (void)
+{
+  settimeout (0);		/* disable all interrupts */
+  server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
+  logout = "Hangup";
+  goodbye = NIL;		/* other end is already gone */
+  if (critical) {		/* must defer if in critical code */
+    close (0);			/* kill stdin */
+    close (1);			/* and stdout */
+    state = LOGOUT;		/* die as soon as we can */
+  }
+  else longjmp (jmpenv,1);	/* die now */
+}
+
+
+/* Termination interrupt
+ * Returns only if critical code in progress
+ */
+
+void trmint (void)
+{
+  settimeout (0);		/* disable all interrupts */
+  server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
+  logout = goodbye = "Killed (terminated)";
+  /* Make no attempt at graceful closure since a shutdown may be in
+   * progress, and we won't have any time to do mail_close() actions
+   */
+  stream = NIL;
+  if (critical) {		/* must defer if in critical code */
+    close (0);			/* kill stdin */
+    close (1);			/* and stdout */
+    state = LOGOUT;		/* die as soon as we can */
+  }
+  else longjmp (jmpenv,1);	/* die now */
+}
+
+/* The routines on this and the next page eschew the use of non-syscall libc
+ * routines (especially stdio) for a reason.  Also, these hideous #if
+ * condtionals need to be replaced.
+ */
+
+#ifndef unix
+#define unix 0
+#endif
+
+
+/* Status request interrupt
+ * Always returns
+ */
+
+void staint (void)
+{
+#if unix
+  int fd;
+  char *s,buf[8*MAILTMPLEN];
+  unsigned long pid = getpid ();
+				/* build file name */
+  s = nout (sout (buf,"/tmp/imapd-status."),pid,10);
+  if (user) s = sout (sout (s,"."),user);
+  *s = '\0';			/* tie off file name */
+  if ((fd = open (buf,O_WRONLY | O_CREAT | O_TRUNC,0666)) >= 0) {
+    fchmod (fd,0666);
+    s = nout (sout (buf,"PID="),pid,10);
+    if (user) s = sout (sout (s,", user="),user);
+    switch (state) {
+    case LOGIN:
+      s = sout (s,", not logged in");
+      break;
+    case SELECT:
+      s = sout (s,", logged in");
+      break;
+    case OPEN:
+      s = sout (s,", mailbox open");
+      break;
+    case LOGOUT:
+      s = sout (s,", logging out");
+      break;
+    }
+    if (stream && stream->mailbox)
+      s = sout (sout (s,"\nmailbox="),stream->mailbox);
+    *s++ = '\n';
+    if (status) {
+      s = sout (s,status);
+      if (cmd) s = sout (sout (s,", last command="),cmd);
+    }
+    else s = sout (sout (s,cmd)," in progress");
+    *s++ = '\n';
+    write (fd,buf,s-buf);
+    close (fd);
+  }
+#endif
+}
+
+/* Write string
+ * Accepts: destination string pointer
+ *	    string
+ * Returns: updated string pointer
+ */
+
+char *sout (char *s,char *t)
+{
+  while (*t) *s++ = *t++;
+  return s;
+}
+
+
+/* Write number
+ * Accepts: destination string pointer
+ *	    number
+ *	    base
+ * Returns: updated string pointer
+ */
+
+char *nout (char *s,unsigned long n,unsigned long base)
+{
+  char stack[256];
+  char *t = stack;
+				/* push PID digits on stack */
+  do *t++ = (char) (n % base) + '0';
+  while (n /= base);
+				/* pop digits from stack */
+  while (t > stack) *s++ = *--t;
+  return s;
+}
+
+/* Slurp a command line
+ * Accepts: buffer pointer
+ *	    buffer size
+ *	    input timeout
+ */
+
+void slurp (char *s,int n,unsigned long timeout)
+{
+  memset (s,'\0',n);		/* zap buffer */
+  if (state != LOGOUT) {	/* get a command under timeout */
+    settimeout (timeout);
+    clearerr (stdin);		/* clear stdin errors */
+    status = "reading line";
+    if (!PSIN (s,n-1)) ioerror (stdin,status);
+    settimeout (0);		/* make sure timeout disabled */
+    status = NIL;
+  }
+}
+
+
+/* Read a literal
+ * Accepts: destination buffer (must be size+1 for trailing NUL)
+ *	    size of buffer (must be less than 4294967295)
+ */
+
+void inliteral (char *s,unsigned long n)
+{
+  unsigned long i;
+  if (litplus.ok) {		/* no more LITERAL+ to worry about */
+    litplus.ok = NIL;
+    litplus.size = 0;
+  }
+  else {			/* otherwise tell client ready for argument */
+    PSOUT ("+ Ready for argument\015\012");
+    PFLUSH ();			/* dump output buffer */
+  }
+  clearerr (stdin);		/* clear stdin errors */
+  memset (s,'\0',n+1);		/* zap buffer */
+  status = "reading literal";
+  while (n) {			/* get data under timeout */
+    if (state == LOGOUT) n = 0;
+    else {
+      settimeout (INPUTTIMEOUT);
+      i = min (n,8192);		/* must read at least 8K within timeout */
+      if (PSINR (s,i)) {
+	s += i;
+	n -= i;
+      }
+      else {
+	ioerror (stdin,status);
+	n = 0;			/* in case it continues */
+      }
+      settimeout (0);		/* stop timeout */
+    }
+  }
+}
+
+/* Flush until newline seen
+ * Returns: NIL, always
+ */
+
+unsigned char *flush (void)
+{
+  int c;
+  if (state != LOGOUT) {
+    settimeout (INPUTTIMEOUT);
+    clearerr (stdin);		/* clear stdin errors */
+    status = "flushing line";
+    while ((c = PBIN ()) != '\012') if (c == EOF) ioerror (stdin,status);
+    settimeout (0);		/* make sure timeout disabled */
+  }
+  response = "%.80s BAD Command line too long\015\012";
+  status = NIL;
+  return NIL;
+}
+
+
+/* Report command stream error and die
+ * Accepts: stdin or stdout (whichever got the error)
+ *	    reason (what caller was doing)
+ */
+
+void ioerror (FILE *f,char *reason)
+{
+  static char msg[MAILTMPLEN];
+  char *s,*t;
+  if (logout) {			/* say nothing if already dying */
+    settimeout (0);		/* disable all interrupts */
+    server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
+				/* write error string */
+    for (s = ferror (f) ? strerror (errno) : "Unexpected client disconnect",
+	   t = logout = msg; *s; *t++ = *s++);
+    for (s = ", while "; *s; *t++ = *s++);
+    for (s = reason; *s; *t++ = *s++);
+    if (critical) {		/* must defer if in critical code */
+      close (0);		/* kill stdin */
+      close (1);		/* and stdout */
+      state = LOGOUT;		/* die as soon as we can */
+    }
+    else longjmp (jmpenv,1);	/* die now */
+  }
+}
+
+/* Parse an IMAP astring
+ * Accepts: pointer to argument text pointer
+ *	    pointer to returned size
+ *	    pointer to returned delimiter
+ * Returns: argument
+ */
+
+unsigned char *parse_astring (unsigned char **arg,unsigned long *size,
+			      unsigned char *del)
+{
+  unsigned long i;
+  unsigned char c,*s,*t,*v;
+  if (!*arg) return NIL;	/* better be an argument */
+  switch (**arg) {		/* see what the argument is */
+  default:			/* atom */
+    for (s = t = *arg, i = 0;
+	 (*t > ' ') && (*t < 0x7f) && (*t != '(') && (*t != ')') &&
+	 (*t != '{') && (*t != '%') && (*t != '*') && (*t != '"') &&
+	 (*t != '\\'); ++t,++i);
+    if (*size = i) break;	/* got atom if non-empty */
+  case ')': case '%': case '*': case '\\': case '\0': case ' ':
+   return NIL;			/* empty atom is a bogon */
+  case '"':			/* hunt for trailing quote */
+    for (s = t = v = *arg + 1; (c = *t++) != '"'; *v++ = c) {
+				/* quote next character */
+      if (c == '\\') switch (c = *t++) {
+      case '"': case '\\': break;
+      default: return NIL;	/* invalid quote-next */
+      }
+				/* else must be a CHAR */
+      if (!c || (c & 0x80)) return NIL;
+    }
+    *v = '\0';			/* tie off string */
+    *size = v - s;		/* return size */
+    break;
+
+  case '{':			/* literal string */
+    s = *arg + 1;		/* get size */
+    if (!isdigit (*s)) return NIL;
+    if ((*size = i = strtoul (s,(char **) &t,10)) > MAXCLIENTLIT) {
+      mm_notify (NIL,"Absurdly long client literal",ERROR);
+      syslog (LOG_INFO,"Overlong (%lu) client literal user=%.80s host=%.80s",
+	      i,user ? (char *) user : "???",tcp_clienthost ());
+      return NIL;
+    }
+    switch (*t) {		/* validate end of literal */
+    case '+':			/* non-blocking literal */
+      if (*++t != '}') return NIL;
+    case '}':
+      if (!t[1]) break;		/* OK if end of line */
+    default:
+      return NIL;		/* bad literal */
+    }
+    if (litsp >= LITSTKLEN) {	/* make sure don't overflow stack */
+      mm_notify (NIL,"Too many literals in command",ERROR);
+      return NIL;
+    }
+				/* get a literal buffer */
+    inliteral (s = litstk[litsp++] = (char *) fs_get (i+1),i);
+    				/* get new command tail */
+    slurp (*arg = t,CMDLEN - (t - cmdbuf),INPUTTIMEOUT);
+    if (!strchr (t,'\012')) return flush ();
+				/* reset strtok mechanism, tie off if done */
+    if (!strtok (t,"\015\012")) *t = '\0';
+				/* possible LITERAL+? */
+    if (((i = strlen (t)) > 3) && (t[i - 1] == '}') &&
+	(t[i - 2] == '+') && isdigit (t[i - 3])) {
+				/* back over possible count */
+      for (i -= 4; i && isdigit (t[i]); i--);
+      if (t[i] == '{') {	/* found a literal? */
+	litplus.ok = T;		/* yes, note LITERAL+ in effect, set size */
+	litplus.size = strtoul (t + i + 1,NIL,10);
+      }
+    }
+    break;
+  }
+  if (*del = *t) {		/* have a delimiter? */
+    *t++ = '\0';		/* yes, stomp on it */
+    *arg = t;			/* update argument pointer */
+  }
+  else *arg = NIL;		/* no more arguments */
+  return s;
+}
+
+/* Snarf a command argument (simple jacket into parse_astring())
+ * Accepts: pointer to argument text pointer
+ * Returns: argument
+ */
+
+unsigned char *snarf (unsigned char **arg)
+{
+  unsigned long i;
+  unsigned char c;
+  unsigned char *s = parse_astring (arg,&i,&c);
+  return ((c == ' ') || !c) ? s : NIL;
+}
+
+
+/* Snarf a BASE64 argument for SASL-IR
+ * Accepts: pointer to argument text pointer
+ * Returns: argument
+ */
+
+unsigned char *snarf_base64 (unsigned char **arg)
+{
+  unsigned char *ret = *arg;
+  unsigned char *s = ret + 1;
+  static char base64mask[256] = {
+   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+   0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,
+   0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,
+   0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,
+   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+  };
+  if (*(ret = *arg) == '=');	/* easy case if zero-length argument */
+				/* must be at least one BASE64 char */
+  else if (!base64mask[*ret]) return NIL;
+  else {			/* quick and dirty */
+    while (base64mask[*s++]);	/* scan until end of BASE64 */
+    if (*s == '=') ++s;		/* allow up to two padding chars */
+    if (*s == '=') ++s;
+  }
+  switch (*s) {			/* anything following the argument? */
+  case ' ':			/* another argument */
+    *s++ = '\0';		/* tie off previous argument */
+    *arg = s;			/* and update argument pointer */
+    break;
+  case '\0':			/* end of command */
+    *arg = NIL;
+    break;
+  default:			/* syntax error */
+    return NIL;
+  }
+  return ret;			/* return BASE64 string */
+}
+
+/* Snarf a list command argument (simple jacket into parse_astring())
+ * Accepts: pointer to argument text pointer
+ * Returns: argument
+ */
+
+unsigned char *snarf_list (unsigned char **arg)
+{
+  unsigned long i;
+  unsigned char c,*s,*t;
+  if (!*arg) return NIL;	/* better be an argument */
+  switch (**arg) {
+  default:			/* atom and/or wildcard chars */
+    for (s = t = *arg, i = 0;
+	 (*t > ' ') && (*t != '(') && (*t != ')') && (*t != '{') &&
+	 (*t != '"') && (*t != '\\'); ++t,++i);
+    if (c = *t) {		/* have a delimiter? */
+      *t++ = '\0';		/* stomp on it */
+      *arg = t;			/* update argument pointer */
+    }
+    else *arg = NIL;
+    break;
+  case ')': case '\\': case '\0': case ' ':
+    return NIL;			/* empty name is bogus */
+  case '"':			/* quoted string? */
+  case '{':			/* or literal? */
+    s = parse_astring (arg,&i,&c);
+    break;
+  }
+  return ((c == ' ') || !c) ? s : NIL;
+}
+
+/* Get a list of header lines
+ * Accepts: pointer to string pointer
+ *	    pointer to list flag
+ * Returns: string list
+ */
+
+STRINGLIST *parse_stringlist (unsigned char **s,int *list)
+{
+  char c = ' ',*t;
+  unsigned long i;
+  STRINGLIST *ret = NIL,*cur = NIL;
+  if (*s && **s == '(') {	/* proper list? */
+    ++*s;			/* for each item in list */
+    while ((c == ' ') && (t = parse_astring (s,&i,&c))) {
+				/* get new block */
+      if (cur) cur = cur->next = mail_newstringlist ();
+      else cur = ret = mail_newstringlist ();
+				/* note text */
+      cur->text.data = (unsigned char *) fs_get (i + 1);
+      memcpy (cur->text.data,t,i);
+      cur->text.size = i;		/* and size */
+    }
+				/* must be end of list */
+    if (c != ')') mail_free_stringlist (&ret);
+  }
+  if (t = *s) {			/* need to reload strtok() state? */
+				/* end of a list? */
+    if (*list && (*t == ')') && !t[1]) *list = NIL;
+    else {
+      *--t = ' ';		/* patch a space back in */
+      *--t = 'x';		/* and a hokey character before that */
+      t = strtok (t," ");	/* reset to *s */
+    }
+  }
+  return ret;
+}
+
+/* Get value of UID * for criteria parsing
+ * Accepts: stream
+ * Returns: maximum UID
+ */
+
+unsigned long uidmax (MAILSTREAM *stream)
+{
+  return stream->nmsgs ? mail_uid (stream,stream->nmsgs) : 0xffffffff;
+}
+
+
+/* Parse search criteria
+ * Accepts: search program to write criteria into
+ *	    pointer to argument text pointer
+ *	    maximum message number
+ *	    maximum UID
+ *	    logical nesting depth
+ * Returns: T if success, NIL if error
+ */
+
+long parse_criteria (SEARCHPGM *pgm,unsigned char **arg,unsigned long maxmsg,
+		     unsigned long maxuid,unsigned long depth)
+{
+  if (arg && *arg) {		/* must be an argument */
+				/* parse criteria */
+    do if (!parse_criterion (pgm,arg,maxmsg,maxuid,depth)) return NIL;
+				/* as long as a space delimiter */
+    while (**arg == ' ' && (*arg)++);
+				/* failed if not end of criteria */
+    if (**arg && **arg != ')') return NIL;
+  }
+  return T;			/* success */
+}
+
+/* Parse a search criterion
+ * Accepts: search program to write criterion into
+ *	    pointer to argument text pointer
+ *	    maximum message number
+ *	    maximum UID
+ *	    logical nesting depth
+ * Returns: T if success, NIL if error
+ */
+
+long parse_criterion (SEARCHPGM *pgm,unsigned char **arg,unsigned long maxmsg,
+		      unsigned long maxuid,unsigned long depth)
+{
+  unsigned long i;
+  unsigned char c = NIL,*s,*t,*v,*tail,*del;
+  SEARCHSET **set;
+  SEARCHPGMLIST **not;
+  SEARCHOR **or;
+  SEARCHHEADER **hdr;
+  long ret = NIL;
+				/* better be an argument */
+  if ((depth > 500) || !(arg && *arg));
+  else if (**arg == '(') {	/* list of criteria? */
+    (*arg)++;			/* yes, parse the criteria */
+    if (parse_criteria (pgm,arg,maxmsg,maxuid,depth+1) && **arg == ')') {
+      (*arg)++;			/* skip closing paren */
+      ret = T;			/* successful parse of list */
+    }
+  }
+  else {			/* find end of criterion */
+    if (!(tail = strpbrk ((s = *arg)," )"))) tail = *arg + strlen (*arg);
+    c = *(del = tail);		/* remember the delimiter */
+    *del = '\0';		/* tie off criterion */
+    switch (*ucase (s)) {	/* dispatch based on character */
+    case '*':			/* sequence */
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+      if (*(set = &pgm->msgno)){/* already a sequence? */
+				/* silly, but not as silly as the client! */
+	for (not = &pgm->not; *not; not = &(*not)->next);
+	*not = mail_newsearchpgmlist ();
+	set = &((*not)->pgm->not = mail_newsearchpgmlist ())->pgm->msgno;
+      }
+      ret = crit_set (set,&s,maxmsg) && (tail == s);
+      break;
+    case 'A':			/* possible ALL, ANSWERED */
+      if (!strcmp (s+1,"LL")) ret = T;
+      else if (!strcmp (s+1,"NSWERED")) ret = pgm->answered = T;
+      break;
+
+    case 'B':			/* possible BCC, BEFORE, BODY */
+      if (!strcmp (s+1,"CC") && c == ' ' && *++tail)
+	ret = crit_string (&pgm->bcc,&tail);
+      else if (!strcmp (s+1,"EFORE") && c == ' ' && *++tail)
+	ret = crit_date (&pgm->before,&tail);
+      else if (!strcmp (s+1,"ODY") && c == ' ' && *++tail)
+	ret = crit_string (&pgm->body,&tail);
+      break;
+    case 'C':			/* possible CC */
+      if (!strcmp (s+1,"C") && c == ' ' && *++tail)
+	ret = crit_string (&pgm->cc,&tail);
+      break;
+    case 'D':			/* possible DELETED */
+      if (!strcmp (s+1,"ELETED")) ret = pgm->deleted = T;
+      if (!strcmp (s+1,"RAFT")) ret = pgm->draft = T;
+      break;
+    case 'F':			/* possible FLAGGED, FROM */
+      if (!strcmp (s+1,"LAGGED")) ret = pgm->flagged = T;
+      else if (!strcmp (s+1,"ROM") && c == ' ' && *++tail)
+	ret = crit_string (&pgm->from,&tail);
+      break;
+    case 'H':			/* possible HEADER */
+      if (!strcmp (s+1,"EADER") && c == ' ' && *(v = tail + 1) &&
+	  (s = parse_astring (&v,&i,&c)) && i && c == ' ' &&
+	  (t = parse_astring (&v,&i,&c))) {
+	for (hdr = &pgm->header; *hdr; hdr = &(*hdr)->next);
+	*hdr = mail_newsearchheader (s,t);
+				/* update tail, restore delimiter */
+	*(tail = v ? v - 1 : t + i) = c;
+	ret = T;		/* success */
+      }
+      break;
+    case 'K':			/* possible KEYWORD */
+      if (!strcmp (s+1,"EYWORD") && c == ' ' && *++tail)
+	ret = crit_string (&pgm->keyword,&tail);
+      break;
+    case 'L':
+      if (!strcmp (s+1,"ARGER") && c == ' ' && *++tail)
+	ret = crit_number (&pgm->larger,&tail);
+      break;
+    case 'N':			/* possible NEW, NOT */
+      if (!strcmp (s+1,"EW")) ret = pgm->recent = pgm->unseen = T;
+      else if (!strcmp (s+1,"OT") && c == ' ' && *++tail) {
+	for (not = &pgm->not; *not; not = &(*not)->next);
+	*not = mail_newsearchpgmlist ();
+	ret = parse_criterion ((*not)->pgm,&tail,maxmsg,maxuid,depth+1);
+      }
+      break;
+
+    case 'O':			/* possible OLD, ON */
+      if (!strcmp (s+1,"LD")) ret = pgm->old = T;
+      else if (!strcmp (s+1,"N") && c == ' ' && *++tail)
+	ret = crit_date (&pgm->on,&tail);
+      else if (!strcmp (s+1,"R") && c == ' ') {
+	for (or = &pgm->or; *or; or = &(*or)->next);
+	*or = mail_newsearchor ();
+	ret = *++tail && parse_criterion((*or)->first,&tail,maxmsg,maxuid,
+					 depth+1) &&
+	  (*tail == ' ') && *++tail &&
+	  parse_criterion ((*or)->second,&tail,maxmsg,maxuid,depth+1);
+      }
+      else if (!strcmp (s+1,"LDER") && c == ' ' && *++tail)
+	ret = crit_number (&pgm->older,&tail);
+      break;
+    case 'R':			/* possible RECENT */
+      if (!strcmp (s+1,"ECENT")) ret = pgm->recent = T;
+      break;
+    case 'S':			/* possible SEEN, SINCE, SUBJECT */
+      if (!strcmp (s+1,"EEN")) ret = pgm->seen = T;
+      else if (!strcmp (s+1,"ENTBEFORE") && c == ' ' && *++tail)
+	ret = crit_date (&pgm->sentbefore,&tail);
+      else if (!strcmp (s+1,"ENTON") && c == ' ' && *++tail)
+	ret = crit_date (&pgm->senton,&tail);
+      else if (!strcmp (s+1,"ENTSINCE") && c == ' ' && *++tail)
+	ret = crit_date (&pgm->sentsince,&tail);
+      else if (!strcmp (s+1,"INCE") && c == ' ' && *++tail)
+	ret = crit_date (&pgm->since,&tail);
+      else if (!strcmp (s+1,"MALLER") && c == ' ' && *++tail)
+	ret = crit_number (&pgm->smaller,&tail);
+      else if (!strcmp (s+1,"UBJECT") && c == ' ' && *++tail)
+	ret = crit_string (&pgm->subject,&tail);
+      break;
+    case 'T':			/* possible TEXT, TO */
+      if (!strcmp (s+1,"EXT") && c == ' ' && *++tail)
+	ret = crit_string (&pgm->text,&tail);
+      else if (!strcmp (s+1,"O") && c == ' ' && *++tail)
+	ret = crit_string (&pgm->to,&tail);
+      break;
+
+    case 'U':			/* possible UID, UN* */
+      if (!strcmp (s+1,"ID") && c== ' ' && *++tail) {
+	if (*(set = &pgm->uid)){/* already a sequence? */
+				/* silly, but not as silly as the client! */
+	  for (not = &pgm->not; *not; not = &(*not)->next);
+	  *not = mail_newsearchpgmlist ();
+	  set = &((*not)->pgm->not = mail_newsearchpgmlist ())->pgm->uid;
+	}
+	ret = crit_set (set,&tail,maxuid);
+      }
+      else if (!strcmp (s+1,"NANSWERED")) ret = pgm->unanswered = T;
+      else if (!strcmp (s+1,"NDELETED")) ret = pgm->undeleted = T;
+      else if (!strcmp (s+1,"NDRAFT")) ret = pgm->undraft = T;
+      else if (!strcmp (s+1,"NFLAGGED")) ret = pgm->unflagged = T;
+      else if (!strcmp (s+1,"NKEYWORD") && c == ' ' && *++tail)
+	ret = crit_string (&pgm->unkeyword,&tail);
+      else if (!strcmp (s+1,"NSEEN")) ret = pgm->unseen = T;
+      break;
+    case 'Y':			/* possible YOUNGER */
+      if (!strcmp (s+1,"OUNGER") && c == ' ' && *++tail)
+	ret = crit_number (&pgm->younger,&tail);
+      break;
+    default:			/* oh dear */
+      break;
+    }
+    if (ret) {			/* only bother if success */
+      *del = c;			/* restore delimiter */
+      *arg = tail;		/* update argument pointer */
+    }
+  }
+  return ret;			/* return more to come */
+}
+
+/* Parse a search date criterion
+ * Accepts: date to write into
+ *	    pointer to argument text pointer
+ * Returns: T if success, NIL if error
+ */
+
+long crit_date (unsigned short *date,unsigned char **arg)
+{
+  if (*date) return NIL;	/* can't double this value */
+				/* handle quoted form */
+  if (**arg != '"') return crit_date_work (date,arg);
+  (*arg)++;			/* skip past opening quote */
+  if (!(crit_date_work (date,arg) && (**arg == '"'))) return NIL;
+  (*arg)++;			/* skip closing quote */
+  return T;
+}
+
+/* Worker routine to parse a search date criterion
+ * Accepts: date to write into
+ *	    pointer to argument text pointer
+ * Returns: T if success, NIL if error
+ */
+
+long crit_date_work (unsigned short *date,unsigned char **arg)
+{
+  int d,m,y;
+				/* day */
+  if (isdigit (d = *(*arg)++) || ((d == ' ') && isdigit (**arg))) {
+    if (d == ' ') d = 0;	/* leading space */
+    else d -= '0';		/* first digit */
+    if (isdigit (**arg)) {	/* if a second digit */
+      d *= 10;			/* slide over first digit */
+      d += *(*arg)++ - '0';	/* second digit */
+    }
+    if ((**arg == '-') && (y = *++(*arg))) {
+      m = (y >= 'a' ? y - 'a' : y - 'A') * 1024;
+      if ((y = *++(*arg))) {
+	m += (y >= 'a' ? y - 'a' : y - 'A') * 32;
+	if ((y = *++(*arg))) {
+	  m += (y >= 'a' ? y - 'a' : y - 'A');
+	  switch (m) {		/* determine the month */
+	  case (('J'-'A') * 1024) + (('A'-'A') * 32) + ('N'-'A'): m = 1; break;
+	  case (('F'-'A') * 1024) + (('E'-'A') * 32) + ('B'-'A'): m = 2; break;
+	  case (('M'-'A') * 1024) + (('A'-'A') * 32) + ('R'-'A'): m = 3; break;
+	  case (('A'-'A') * 1024) + (('P'-'A') * 32) + ('R'-'A'): m = 4; break;
+	  case (('M'-'A') * 1024) + (('A'-'A') * 32) + ('Y'-'A'): m = 5; break;
+	  case (('J'-'A') * 1024) + (('U'-'A') * 32) + ('N'-'A'): m = 6; break;
+	  case (('J'-'A') * 1024) + (('U'-'A') * 32) + ('L'-'A'): m = 7; break;
+	  case (('A'-'A') * 1024) + (('U'-'A') * 32) + ('G'-'A'): m = 8; break;
+	  case (('S'-'A') * 1024) + (('E'-'A') * 32) + ('P'-'A'): m = 9; break;
+	  case (('O'-'A') * 1024) + (('C'-'A') * 32) + ('T'-'A'): m = 10;break;
+	  case (('N'-'A') * 1024) + (('O'-'A') * 32) + ('V'-'A'): m = 11;break;
+	  case (('D'-'A') * 1024) + (('E'-'A') * 32) + ('C'-'A'): m = 12;break;
+	  default: return NIL;
+	  }
+	  if ((*++(*arg) == '-') && isdigit (*++(*arg))) {
+	    y = 0;		/* init year */
+	    do {
+	      y *= 10;		/* add this number */
+	      y += *(*arg)++ - '0';
+	    }
+	    while (isdigit (**arg));
+				/* minimal validity check of date */
+	    if (d < 1 || d > 31 || m < 1 || m > 12 || y < 0) return NIL; 
+				/* time began on UNIX in 1970 */
+	    if (y < 100) y += (y >= (BASEYEAR - 1900)) ? 1900 : 2000;
+				/* return value */
+	    *date = mail_shortdate (y - BASEYEAR,m,d);
+	    return T;		/* success */
+	  }
+	}
+      }
+    }
+  }
+  return NIL;			/* else error */
+}
+
+/* Parse a search set criterion
+ * Accepts: set to write into
+ *	    pointer to argument text pointer
+ *	    maximum value permitted
+ * Returns: T if success, NIL if error
+ */
+
+long crit_set (SEARCHSET **set,unsigned char **arg,unsigned long maxima)
+{
+  unsigned long i = 0;
+  if (*set) return NIL;		/* can't double this value */
+  *set = mail_newsearchset ();	/* instantiate a new search set */
+  if (**arg == '*') {		/* maxnum? */
+    (*arg)++;			/* skip past that number */
+    (*set)->first = maxima;
+  }
+  else if (crit_number (&i,arg) && i) (*set)->first = i;
+  else return NIL;		/* bogon */
+  switch (**arg) {		/* decide based on delimiter */
+  case ':':			/* sequence range */
+    i = 0;			/* reset for crit_number() */
+    if (*++(*arg) == '*') {	/* maxnum? */
+      (*arg)++;			/* skip past that number */
+      (*set)->last = maxima;
+    }
+    else if (crit_number (&i,arg) && i) {
+      if (i < (*set)->first) {	/* backwards range */
+	(*set)->last = (*set)->first;
+	(*set)->first = i;
+      }
+      else (*set)->last = i;	/* set last number */
+    }
+    else return NIL;		/* bogon */
+    if (**arg != ',') break;	/* drop into comma case if comma seen */
+  case ',':
+    (*arg)++;			/* skip past delimiter */
+    return crit_set (&(*set)->next,arg,maxima);
+  default:
+    break;
+  }
+  return T;			/* return success */
+}
+
+/* Parse a search number criterion
+ * Accepts: number to write into
+ *	    pointer to argument text pointer
+ * Returns: T if success, NIL if error
+ */
+
+long crit_number (unsigned long *number,unsigned char **arg)
+{
+				/* can't double this value */
+  if (*number || !isdigit (**arg)) return NIL;
+  *number = 0;
+  while (isdigit (**arg)) {	/* found a digit? */
+    *number *= 10;		/* add a decade */
+    *number += *(*arg)++ - '0';	/* add number */
+  }
+  return T;
+}
+
+
+/* Parse a search string criterion
+ * Accepts: date to write into
+ *	    pointer to argument text pointer
+ * Returns: T if success, NIL if error
+ */
+
+long crit_string (STRINGLIST **string,unsigned char **arg)
+{
+  unsigned long i;
+  char c;
+  char *s = parse_astring (arg,&i,&c);
+  if (!s) return NIL;
+				/* find tail of list */
+  while (*string) string = &(*string)->next;
+  *string = mail_newstringlist ();
+  (*string)->text.data = (unsigned char *) fs_get (i + 1);
+  memcpy ((*string)->text.data,s,i);
+  (*string)->text.data[i] = '\0';
+  (*string)->text.size = i;
+				/* if end of arguments, wrap it up here */
+  if (!*arg) *arg = (char *) (*string)->text.data + i;
+  else (*--(*arg) = c);		/* back up pointer, restore delimiter */
+  return T;
+}
+
+/* Fetch message data
+ * Accepts: string of data items to be fetched (must be writeable)
+ *	    UID fetch flag
+ */
+
+#define MAXFETCH 100
+
+void fetch (char *t,unsigned long uid)
+{
+  fetchfn_t f[MAXFETCH +2];
+  void *fa[MAXFETCH + 2];
+  int k;
+  memset ((void *) f,NIL,sizeof (f));
+  memset ((void *) fa,NIL,sizeof (fa));
+  fetch_work (t,uid,f,fa);	/* do the work */
+				/* clean up arguments */
+  for (k = 1; f[k]; k++) if (fa[k]) (*f[k]) (0,fa[k]);
+}
+
+
+/* Fetch message data worker routine
+ * Accepts: string of data items to be fetched (must be writeable)
+ *	    UID fetch flag
+ *	    function dispatch vector
+ *	    function argument vector
+ */
+
+void fetch_work (char *t,unsigned long uid,fetchfn_t f[],void *fa[])
+{
+  unsigned char *s,*v;
+  unsigned long i;
+  unsigned long k = 0;
+  BODY *b;
+  int list = NIL;
+  int parse_envs = NIL;
+  int parse_bodies = NIL;
+  if (uid) {			/* need to fetch UIDs? */
+    fa[k] = NIL;		/* no argument */
+    f[k++] = fetch_uid;		/* push a UID fetch on the stack */
+  }
+
+				/* process macros */
+  if (!strcmp (ucase (t),"ALL"))
+    strcpy (t,"(FLAGS INTERNALDATE RFC822.SIZE ENVELOPE)");
+  else if (!strcmp (t,"FULL"))
+    strcpy (t,"(FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY)");
+  else if (!strcmp (t,"FAST")) strcpy (t,"(FLAGS INTERNALDATE RFC822.SIZE)");
+  if (list = (*t == '(')) t++;	/* skip open paren */
+  if (s = strtok (t," ")) do {	/* parse attribute list */
+    if (list && (i = strlen (s)) && (s[i-1] == ')')) {
+      list = NIL;		/* done with list */
+      s[i-1] = '\0';		/* tie off last item */
+    }
+    fa[k] = NIL;		/* default to no argument */
+    if (!strcmp (s,"UID")) {	/* no-op if implicit */
+      if (!uid) f[k++] = fetch_uid;
+    }
+    else if (!strcmp (s,"FLAGS")) f[k++] = fetch_flags;
+    else if (!strcmp (s,"INTERNALDATE")) f[k++] = fetch_internaldate;
+    else if (!strcmp (s,"RFC822.SIZE")) f[k++] = fetch_rfc822_size;
+    else if (!strcmp (s,"ENVELOPE")) {
+      parse_envs = T;		/* we will need to parse envelopes */
+      f[k++] = fetch_envelope;
+    }
+    else if (!strcmp (s,"BODY")) {
+      parse_envs = parse_bodies = T;
+      f[k++] = fetch_body;
+    }
+    else if (!strcmp (s,"BODYSTRUCTURE")) {
+      parse_envs = parse_bodies = T;
+      f[k++] = fetch_bodystructure;
+    }
+    else if (!strcmp (s,"RFC822")) {
+      fa[k] = s[6] ? (void *) FT_PEEK : NIL;
+      f[k++] = fetch_rfc822;
+    }
+    else if (!strcmp (s,"RFC822.HEADER")) f[k++] = fetch_rfc822_header;
+    else if (!strcmp (s,"RFC822.TEXT")) {
+      fa[k] = s[11] ? (void *) FT_PEEK : NIL;
+      f[k++] = fetch_rfc822_text;
+    }
+
+    else if (!strncmp (s,"BODY[",5) || !strncmp (s,"BODY.PEEK[",10) ||
+	     !strncmp (s,"BINARY[",7) || !strncmp (s,"BINARY.PEEK[",12) ||
+	     !strncmp (s,"BINARY.SIZE[",12)) {
+      TEXTARGS *ta = (TEXTARGS *)
+	memset (fs_get (sizeof (TEXTARGS)),0,sizeof (TEXTARGS));
+      if (s[1] == 'I') {	/* body or binary? */
+	ta->binary = FTB_BINARY;/* binary */
+	f[k] = fetch_body_part_binary;
+	if (s[6] == '.') {	/* wanted peek or size? */
+	  if (s[7] == 'P') ta->flags = FT_PEEK;
+	  else ta->binary |= FTB_SIZE;
+	  s += 12;		/* skip to section specifier */
+	}
+	else s += 7;		/* skip to section specifier */
+	if (!isdigit (*s)) {	/* make sure top-level digit */
+	  fs_give ((void **) &ta);
+	  response = badbin;
+	  return;
+	}
+      }
+      else {			/* body */
+	f[k] = fetch_body_part_contents;
+	if (s[4] == '.') {	/* wanted peek? */
+	  ta->flags = FT_PEEK;
+	  s += 10;		/* skip to section specifier */
+	}
+	else s += 5;		/* skip to section specifier */
+      }
+      if (*(v = s) != ']') {	/* non-empty section specifier? */
+	if (isdigit (*v)) {	/* have section specifier? */
+				/* need envelopes and bodies */
+	  parse_envs = parse_bodies = T;
+	  while (isdigit (*v))	/* scan to end of section specifier */
+	    if ((*++v == '.') && isdigit (v[1])) v++;
+				/* any IMAP4rev1 stuff following? */
+	  if ((*v == '.') && isalpha (v[1])) {
+	    if (ta->binary) {	/* not if binary you don't */
+	      fs_give ((void **) &ta);
+	      response = badbin;
+	      return;
+	    }
+	    *v++ = '\0';	/* yes, tie off section specifier */
+	    if (!strncmp (v,"MIME",4)) {
+	      v += 4;		/* found <section>.MIME */
+	      f[k] = fetch_body_part_mime;
+	    }
+	  }
+	  else if (*v != ']') {	/* better be the end if no IMAP4rev1 stuff */
+	    fs_give ((void **) &ta);/* clean up */
+	    response = "%.80s BAD Syntax error in section specifier\015\012";
+	    return;
+	  }
+	}
+
+	if (*v != ']') {	/* IMAP4rev1 stuff here? */
+	  if (!strncmp (v,"HEADER",6)) {
+	    *v = '\0';		/* tie off in case top level */
+	    v += 6;		/* found [<section>.]HEADER */
+	    f[k] = fetch_body_part_header;
+				/* partial headers wanted? */
+	    if (!strncmp (v,".FIELDS",7)) {
+	      v += 7;		/* yes */
+	      if (!strncmp (v,".NOT",4)) {
+		v += 4;		/* want to exclude named headers */
+		ta->flags |= FT_NOT;
+	      }
+	      if (*v || !(v = strtok (NIL,"\015\012")) ||
+		  !(ta->lines = parse_stringlist (&v,&list))) {
+		fs_give ((void **) &ta);/* clean up */
+		response = "%.80s BAD Syntax error in header fields\015\012";
+		return;
+	      }
+	    }
+	  }
+	  else if (!strncmp (v,"TEXT",4)) {
+	    *v = '\0';		/* tie off in case top level */
+	    v += 4;		/* found [<section>.]TEXT */
+	    f[k] = fetch_body_part_text;
+	  }
+	  else {
+	    fs_give ((void **) &ta);/* clean up */
+	    response = "%.80s BAD Unknown section text specifier\015\012";
+	    return;
+	  }
+	}
+      }
+				/* tie off section */
+      if (*v == ']') *v++ = '\0';
+      else {			/* bogon */
+	if (ta->lines) mail_free_stringlist (&ta->lines);
+	fs_give ((void **) &ta);/* clean up */
+	response = "%.80s BAD Section specifier not terminated\015\012";
+	return;
+      }
+
+      if ((*v == '<') &&	/* partial specifier? */
+	  ((ta->binary & FTB_SIZE) ||
+	   !(isdigit (v[1]) && ((ta->first = strtoul (v+1,(char **) &v,10)) ||
+				v) &&
+	     (*v++ == '.') && (ta->last = strtoul (v,(char **) &v,10)) &&
+	     (*v++ == '>')))) {
+	if (ta->lines) mail_free_stringlist (&ta->lines);
+	fs_give ((void **) &ta);
+	response ="%.80s BAD Syntax error in partial text specifier\015\012";
+	return;
+      }
+      switch (*v) {		/* what's there now? */
+      case ' ':			/* more follows */
+	*--v = ' ';		/* patch a space back in */
+	*--v = 'x';		/* and a hokey character before that */
+	strtok (v," ");		/* reset strtok mechanism */
+	break;
+      case '\0':		/* none */
+	break;
+      case ')':			/* end of list */
+	if (list && !v[1]) {	/* make sure of that */
+	  list = NIL;
+	  strtok (v," ");	/* reset strtok mechanism */
+	  break;		/* all done */
+	}
+				/* otherwise it's a bogon, drop in */
+      default:			/* bogon */
+	if (ta->lines) mail_free_stringlist (&ta->lines);
+	fs_give ((void **) &ta);
+	response = "%.80s BAD Syntax error after section specifier\015\012";
+	return;
+      }
+				/* make copy of section specifier */
+      if (s && *s) ta->section = cpystr (s);
+      fa[k++] = (void *) ta;	/* set argument */
+    }
+    else {			/* unknown attribute */
+      response = badatt;
+      return;
+    }
+  } while ((s = strtok (NIL," ")) && (k < MAXFETCH) && list);
+  else {
+    response = misarg;		/* missing attribute list */
+    return;
+  }
+
+  if (s) {			/* too many attributes? */
+    response = "%.80s BAD Excessively complex FETCH attribute list\015\012";
+    return;
+  }
+  if (list) {			/* too many attributes? */
+    response = "%.80s BAD Unterminated FETCH attribute list\015\012";
+    return;
+  }
+  f[k] = NIL;			/* tie off attribute list */
+				/* c-client clobbers sequence, use spare */
+  for (i = 1; i <= nmsgs; i++)
+    mail_elt (stream,i)->spare = mail_elt (stream,i)->sequence;
+				/* for each requested message */
+  for (i = 1; (i <= nmsgs) && (response != loseunknowncte); i++) {
+				/* kill if dying */
+    if (state == LOGOUT) longjmp (jmpenv,1);
+    if (mail_elt (stream,i)->spare) {
+				/* parse envelope, set body, do warnings */
+      if (parse_envs) mail_fetchstructure (stream,i,parse_bodies ? &b : NIL);
+      quell_events = T;		/* can't do any events now */
+      PSOUT ("* ");		/* leader */
+      pnum (i);
+      PSOUT (" FETCH (");
+      (*f[0]) (i,fa[0]);	/* do first attribute */
+				/* for each subsequent attribute */
+      for (k = 1; f[k] && (response != loseunknowncte); k++) {
+	PBOUT (' ');		/* delimit with space */
+	(*f[k]) (i,fa[k]);	/* do that attribute */
+      }
+      PSOUT (")\015\012");	/* trailer */
+      quell_events = NIL;	/* events alright now */
+    }
+  }
+}
+
+/* Fetch message body structure (extensible)
+ * Accepts: message number
+ *	    extra argument
+ */
+
+void fetch_bodystructure (unsigned long i,void *args)
+{
+  BODY *body;
+  mail_fetchstructure (stream,i,&body);
+  PSOUT ("BODYSTRUCTURE ");
+  pbodystructure (body);	/* output body */
+}
+
+
+/* Fetch message body structure (non-extensible)
+ * Accepts: message number
+ *	    extra argument
+ */
+
+
+void fetch_body (unsigned long i,void *args)
+{
+  BODY *body;
+  mail_fetchstructure (stream,i,&body);
+  PSOUT ("BODY ");		/* output attribute */
+  pbody (body);			/* output body */
+}
+
+/* Fetch body part MIME header
+ * Accepts: message number
+ *	    extra argument
+ */
+
+void fetch_body_part_mime (unsigned long i,void *args)
+{
+  TEXTARGS *ta = (TEXTARGS *) args;
+  if (i) {			/* do work? */
+    SIZEDTEXT st;
+    unsigned long uid = mail_uid (stream,i);
+    char *tmp = (char *) fs_get (100 + strlen (ta->section));
+    sprintf (tmp,"BODY[%s.MIME]",ta->section);
+				/* try to use remembered text */
+    if (lastuid && (uid == lastuid) && !strcmp (tmp,lastid)) st = lastst;
+    else {			/* get data */
+      st.data = (unsigned char *)
+	mail_fetch_mime (stream,i,ta->section,&st.size,ta->flags);
+      if (ta->first || ta->last) remember (uid,tmp,&st);
+    }
+    pbodypartstring (i,tmp,&st,NIL,ta);
+    fs_give ((void **) &tmp);
+  }
+  else {			/* clean up the arguments */
+    fs_give ((void **) &ta->section);
+    fs_give ((void **) &args);
+  }
+}
+
+
+/* Fetch body part contents
+ * Accepts: message number
+ *	    extra argument
+ */
+
+void fetch_body_part_contents (unsigned long i,void *args)
+{
+  TEXTARGS *ta = (TEXTARGS *) args;
+  if (i) {			/* do work? */
+    SIZEDTEXT st;
+    char *tmp = (char *) fs_get (100+(ta->section ? strlen (ta->section) : 0));
+    unsigned long uid = mail_uid (stream,i);
+    sprintf (tmp,"BODY[%s]",ta->section ? ta->section : "");
+				/* try to use remembered text */
+    if (lastuid && (uid == lastuid) && !strcmp (tmp,lastid)) st = lastst;
+				/* get data */
+    else if ((st.data = (unsigned char *)
+	      mail_fetch_body (stream,i,ta->section,&st.size,
+			       ta->flags | FT_RETURNSTRINGSTRUCT)) &&
+	     (ta->first || ta->last)) remember (uid,tmp,&st);
+    pbodypartstring (i,tmp,&st,&stream->private.string,ta);
+    fs_give ((void **) &tmp);
+  }
+  else {			/* clean up the arguments */
+    if (ta->section) fs_give ((void **) &ta->section);
+    fs_give ((void **) &args);
+  }
+}
+
+/* Fetch body part binary
+ * Accepts: message number
+ *	    extra argument
+ * Someday fix this to use stringstruct instead of memory
+ */
+
+void fetch_body_part_binary (unsigned long i,void *args)
+{
+  TEXTARGS *ta = (TEXTARGS *) args;
+  if (i) {			/* do work? */
+    SIZEDTEXT st,cst;
+    BODY *body = mail_body (stream,i,ta->section);
+    char *tmp = (char *) fs_get (100+(ta->section ? strlen (ta->section) : 0));
+    unsigned long uid = mail_uid (stream,i);
+				/* try to use remembered text */
+    if (lastuid && (uid == lastuid) && !strcmp (tmp,lastid)) st = lastst;
+    else {			/* get data */
+      st.data = (unsigned char *)
+	mail_fetch_body (stream,i,ta->section,&st.size,ta->flags);
+      if (ta->first || ta->last) remember (uid,tmp,&st);
+    }
+				/* what encoding was used? */
+    if (body) switch (body->encoding) {
+    case ENCBASE64:
+      if (cst.data = rfc822_base64 (st.data,st.size,&cst.size)) break;
+      fetch_uid (i,NIL);	/* wrote a space, so must do something */
+      if (lsterr) fs_give ((void **) &lsterr);
+      lsterr = cpystr ("Undecodable BASE64 contents");
+      response = loseunknowncte;
+      fs_give ((void **) &tmp);
+      return;
+    case ENCQUOTEDPRINTABLE:
+      if (cst.data = rfc822_qprint (st.data,st.size,&cst.size)) break;
+      fetch_uid (i,NIL);	/* wrote a space, so must do something */
+      if (lsterr) fs_give ((void **) &lsterr);
+      lsterr = cpystr ("Undecodable QUOTED-PRINTABLE contents");
+      response = loseunknowncte;
+      fs_give ((void **) &tmp);
+      return;
+    case ENC7BIT:		/* no need to convert any of these */
+    case ENC8BIT:
+    case ENCBINARY:
+      cst.data = NIL;		/* no converted data to free */
+      break;
+    default:			/* unknown encoding, oops */
+      fetch_uid (i,NIL);	/* wrote a space, so must do something */
+      if (lsterr) fs_give ((void **) &lsterr);
+      lsterr = cpystr ("Unknown Content-Transfer-Encoding");
+      response = loseunknowncte;
+      fs_give ((void **) &tmp);
+      return;
+    }
+    else {
+      if (lsterr) fs_give ((void **) &lsterr);
+      lsterr = cpystr ("Invalid body part");
+      response = loseunknowncte;
+      fs_give ((void **) &tmp);
+      return;
+    }
+
+				/* use decoded version if exists */
+    if (cst.data) memcpy ((void *) &st,(void *) &cst,sizeof (SIZEDTEXT));
+    if (ta->binary & FTB_SIZE) {/* just want size? */
+      sprintf (tmp,"BINARY.SIZE[%s] %lu",ta->section ? ta->section : "",
+	       st.size);
+      PSOUT (tmp);
+    }
+    else {			/* no, blat binary data */
+      int f = mail_elt (stream,i)->seen;
+      if (st.data) {		/* only if have useful data */
+				/* partial specifier */
+	if (ta->first || ta->last)
+	  sprintf (tmp,"BINARY[%s]<%lu> ",
+		   ta->section ? ta->section : "",ta->first);
+	else sprintf (tmp,"BINARY[%s] ",ta->section ? ta->section : "");
+  				/* in case first byte beyond end of text */
+	if (st.size <= ta->first) st.size = ta->first = 0;
+	else {			/* offset and truncate */
+	  st.data += ta->first;	/* move to desired position */
+	  st.size -= ta->first;	/* reduced size */
+	  if (ta->last && (st.size > ta->last)) st.size = ta->last;
+	}
+	if (st.size) sprintf (tmp + strlen (tmp),"{%lu}\015\012",st.size);
+	else strcat (tmp,"\"\"");
+	PSOUT (tmp);		/* write binary output */
+	if (st.size && (PSOUTR (&st) == EOF)) ioerror(stdout,"writing binary");
+      }
+      else {
+	sprintf (tmp,"BINARY[%s] NIL",ta->section ? ta->section : "");
+	PSOUT (tmp);
+      }
+      changed_flags (i,f);	/* write changed flags */
+    }
+				/* free converted data */
+    if (cst.data) fs_give ((void **) &cst.data);
+    fs_give ((void **) &tmp);	/* and temporary string */
+  }
+  else {			/* clean up the arguments */
+    if (ta->section) fs_give ((void **) &ta->section);
+    fs_give ((void **) &args);
+  }
+}
+
+/* Fetch MESSAGE/RFC822 body part header
+ * Accepts: message number
+ *	    extra argument
+ */
+
+void fetch_body_part_header (unsigned long i,void *args)
+{
+  TEXTARGS *ta = (TEXTARGS *) args;
+  unsigned long len = 100 + (ta->section ? strlen (ta->section) : 0);
+  STRINGLIST *s;
+  for (s = ta->lines; s; s = s->next) len += s->text.size + 1;
+  if (i) {			/* do work? */
+    SIZEDTEXT st;
+    char *tmp = (char *) fs_get (len);
+    PSOUT ("BODY[");
+				/* output attribute */
+    if (ta->section && *ta->section) {
+      PSOUT (ta->section);
+      PBOUT ('.');
+    }
+    PSOUT ("HEADER");
+    if (ta->lines) {
+      PSOUT ((ta->flags & FT_NOT) ? ".FIELDS.NOT " : ".FIELDS ");
+      pastringlist (ta->lines);
+    }
+    strcpy (tmp,"]");		/* close section specifier */
+    st.data = (unsigned char *)	/* get data (no hope in using remember here) */
+      mail_fetch_header (stream,i,ta->section,ta->lines,&st.size,ta->flags);
+    pbodypartstring (i,tmp,&st,NIL,ta);
+    fs_give ((void **) &tmp);
+  }
+  else {			/* clean up the arguments */
+    if (ta->lines) mail_free_stringlist (&ta->lines);
+    if (ta->section) fs_give ((void **) &ta->section);
+    fs_give ((void **) &args);
+  }
+}
+
+/* Fetch MESSAGE/RFC822 body part text
+ * Accepts: message number
+ *	    extra argument
+ */
+
+void fetch_body_part_text (unsigned long i,void *args)
+{
+  TEXTARGS *ta = (TEXTARGS *) args;
+  if (i) {			/* do work? */
+    SIZEDTEXT st;
+    char *tmp = (char *) fs_get (100+(ta->section ? strlen (ta->section) : 0));
+    unsigned long uid = mail_uid (stream,i);
+				/* output attribute */
+    if (ta->section && *ta->section) sprintf (tmp,"BODY[%s.TEXT]",ta->section);
+    else strcpy (tmp,"BODY[TEXT]");
+				/* try to use remembered text */
+    if (lastuid && (uid == lastuid) && !strcmp (tmp,lastid)) st = lastst;
+				/* get data */
+    else if ((st.data = (unsigned char *)
+	      mail_fetch_text (stream,i,ta->section,&st.size,
+			       ta->flags | FT_RETURNSTRINGSTRUCT)) &&
+	     (ta->first || ta->last)) remember (uid,tmp,&st);
+    pbodypartstring (i,tmp,&st,&stream->private.string,ta);
+    fs_give ((void **) &tmp);
+  }
+  else {			/* clean up the arguments */
+    if (ta->section) fs_give ((void **) &ta->section);
+    fs_give ((void **) &args);
+  }
+}
+
+
+/* Remember body part text for subsequent partial fetching
+ * Accepts: message UID
+ *	    body part id
+ *	    text
+ *	    string
+ */
+
+void remember (unsigned long uid,char *id,SIZEDTEXT *st)
+{
+  lastuid = uid;		/* remember UID */
+  if (lastid) fs_give ((void **) &lastid);
+  lastid = cpystr (id);		/* remember body part id */
+  if (lastst.data) fs_give ((void **) &lastst.data);
+				/* remember text */
+  lastst.data = (unsigned char *)
+    memcpy (fs_get (st->size + 1),st->data,st->size);
+  lastst.size = st->size;
+}
+
+
+/* Fetch envelope
+ * Accepts: message number
+ *	    extra argument
+ */
+
+void fetch_envelope (unsigned long i,void *args)
+{
+  ENVELOPE *env = mail_fetchenvelope (stream,i);
+  PSOUT ("ENVELOPE ");		/* output attribute */
+  penv (env);			/* output envelope */
+}
+
+/* Fetch flags
+ * Accepts: message number
+ *	    extra argument
+ */
+
+void fetch_flags (unsigned long i,void *args)
+{
+  unsigned long u;
+  char *t,tmp[MAILTMPLEN];
+  int c = NIL;
+  MESSAGECACHE *elt = mail_elt (stream,i);
+  if (!elt->valid) {		/* have valid flags yet? */
+    sprintf (tmp,"%lu",i);
+    mail_fetch_flags (stream,tmp,NIL);
+  }
+  PSOUT ("FLAGS (");		/* output attribute */
+				/* output system flags */
+  if (elt->recent) put_flag (&c,"\\Recent");
+  if (elt->seen) put_flag (&c,"\\Seen");
+  if (elt->deleted) put_flag (&c,"\\Deleted");
+  if (elt->flagged) put_flag (&c,"\\Flagged");
+  if (elt->answered) put_flag (&c,"\\Answered");
+  if (elt->draft) put_flag (&c,"\\Draft");
+  if (u = elt->user_flags) do	/* any user flags? */
+    if (t = stream->user_flags[find_rightmost_bit (&u)]) put_flag (&c,t);
+  while (u);			/* until no more user flags */
+  PBOUT (')');			/* end of flags */
+  elt->spare2 = NIL;		/* we've sent the update */
+}
+
+
+/* Output a flag
+ * Accepts: pointer to current delimiter character
+ *	    flag to output
+ * Changes delimiter character to space
+ */
+
+void put_flag (int *c,char *s)
+{
+  if (*c) PBOUT (*c);		/* put delimiter */
+  PSOUT (s);			/* dump flag */
+  *c = ' ';			/* change delimiter if necessary */
+}
+
+
+/* Output flags if was unseen
+ * Accepts: message number
+ *	    prior value of Seen flag
+ */
+
+void changed_flags (unsigned long i,int f)
+{
+				/* was unseen, now seen? */
+  if (!f && mail_elt (stream,i)->seen) {
+    PBOUT (' ');		/* yes, delimit with space */
+    fetch_flags (i,NIL);	/* output flags */
+  }
+}
+
+/* Fetch message internal date
+ * Accepts: message number
+ *	    extra argument
+ */
+
+void fetch_internaldate (unsigned long i,void *args)
+{
+  char tmp[MAILTMPLEN];
+  MESSAGECACHE *elt = mail_elt (stream,i);
+  if (!elt->day) {		/* have internal date yet? */
+    sprintf (tmp,"%lu",i);
+    mail_fetch_fast (stream,tmp,NIL);
+  }
+  PSOUT ("INTERNALDATE \"");
+  PSOUT (mail_date (tmp,elt));
+  PBOUT ('"');
+}
+
+
+/* Fetch unique identifier
+ * Accepts: message number
+ *	    extra argument
+ */
+
+void fetch_uid (unsigned long i,void *args)
+{
+  PSOUT ("UID ");
+  pnum (mail_uid (stream,i));
+}
+
+/* Fetch complete RFC-822 format message
+ * Accepts: message number
+ *	    extra argument
+ */
+
+void fetch_rfc822 (unsigned long i,void *args)
+{
+  if (i) {			/* do work? */
+    int f = mail_elt (stream,i)->seen;
+#if 0
+    SIZEDTEXT st;
+    st.data = (unsigned char *)
+      mail_fetch_message (stream,i,&st.size,(long) args);
+    pbodypartstring (i,"RFC822",&st,NIL,NIL);
+#else
+    /* Yes, this version is bletcherous, but mail_fetch_message() requires
+       too much memory */
+    SIZEDTEXT txt,hdr;
+    char *s = mail_fetch_header (stream,i,NIL,NIL,&hdr.size,FT_PEEK);
+    hdr.data = (unsigned char *) memcpy (fs_get (hdr.size),s,hdr.size);
+    txt.data = (unsigned char *)
+      mail_fetch_text (stream,i,NIL,&txt.size,
+		       ((long) args) | FT_RETURNSTRINGSTRUCT);
+    PSOUT ("RFC822 {");
+    pnum (hdr.size + txt.size);
+    PSOUT ("}\015\012");
+    ptext (&hdr,NIL);
+    ptext (&txt,&stream->private.string);
+    fs_give ((void **) &hdr.data);
+#endif
+    changed_flags (i,f);	/* output changed flags */
+  }
+}
+
+
+/* Fetch RFC-822 header
+ * Accepts: message number
+ *	    extra argument
+ */
+
+void fetch_rfc822_header (unsigned long i,void *args)
+{
+  SIZEDTEXT st;
+  st.data = (unsigned char *)
+    mail_fetch_header (stream,i,NIL,NIL,&st.size,FT_PEEK);
+  pbodypartstring (i,"RFC822.HEADER",&st,NIL,NIL);
+}
+
+
+/* Fetch RFC-822 message length
+ * Accepts: message number
+ *	    extra argument
+ */
+
+void fetch_rfc822_size (unsigned long i,void *args)
+{
+  char tmp[MAILTMPLEN];
+  MESSAGECACHE *elt = mail_elt (stream,i);
+  if (!elt->rfc822_size) {	/* have message size yet? */
+    sprintf (tmp,"%lu",i);
+    mail_fetch_fast (stream,tmp,NIL);
+  }
+  PSOUT ("RFC822.SIZE ");
+  pnum (elt->rfc822_size);
+}
+
+/* Fetch RFC-822 text only
+ * Accepts: message number
+ *	    extra argument
+ */
+
+void fetch_rfc822_text (unsigned long i,void *args)
+{
+  if (i) {			/* do work? */
+    int f = mail_elt (stream,i)->seen;
+    SIZEDTEXT st;
+    st.data = (unsigned char *)
+      mail_fetch_text (stream,i,NIL,&st.size,
+		       ((long) args) | FT_RETURNSTRINGSTRUCT);
+    pbodypartstring (i,"RFC822.TEXT",&st,&stream->private.string,NIL);
+  }
+}
+
+/* Print envelope
+ * Accepts: body
+ */
+
+void penv (ENVELOPE *env)
+{
+  PBOUT ('(');			/* delimiter */
+  if (env) {			/* only if there is an envelope */
+    pnstring (env->date);	/* output envelope fields */
+    PBOUT (' ');
+    pnstring (env->subject);
+    PBOUT (' ');
+    paddr (env->from);
+    PBOUT (' ');
+    paddr (env->sender);
+    PBOUT (' ');
+    paddr (env->reply_to);
+    PBOUT (' ');
+    paddr (env->to);
+    PBOUT (' ');
+    paddr (env->cc);
+    PBOUT (' ');
+    paddr (env->bcc);
+    PBOUT (' ');
+    pnstring (env->in_reply_to);
+    PBOUT (' ');
+    pnstring (env->message_id);
+  }
+				/* no envelope */
+  else PSOUT ("NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL");
+  PBOUT (')');			/* end of envelope */
+}
+
+/* Print body structure (extensible)
+ * Accepts: body
+ */
+
+void pbodystructure (BODY *body)
+{
+  PBOUT ('(');			/* delimiter */
+  if (body) {			/* only if there is a body */
+    PART *part;
+				/* multipart type? */
+    if (body->type == TYPEMULTIPART) {
+				/* print each part */
+      if (part = body->nested.part)
+	for (; part; part = part->next) pbodystructure (&(part->body));
+      else pbodystructure (NIL);
+      PBOUT (' ');		/* space delimiter */
+      pstring (body->subtype);	/* subtype */
+      PBOUT (' ');
+      pparam (body->parameter);	/* multipart body extension data */
+      PBOUT (' ');
+      if (body->disposition.type) {
+	PBOUT ('(');
+	pstring (body->disposition.type);
+	PBOUT (' ');
+	pparam (body->disposition.parameter);
+	PBOUT (')');
+      }
+      else PSOUT ("NIL");
+      PBOUT (' ');
+      pnstringorlist (body->language);
+      PBOUT (' ');
+      pnstring (body->location);
+    }
+
+    else {			/* non-multipart body type */
+      pstring ((char *) body_types[body->type]);
+      PBOUT (' ');
+      pstring (body->subtype);
+      PBOUT (' ');
+      pparam (body->parameter);
+      PBOUT (' ');
+      pnstring (body->id);
+      PBOUT (' ');
+      pnstring (body->description);
+      PBOUT (' ');
+      pstring ((char *) body_encodings[body->encoding]);
+      PBOUT (' ');
+      pnum (body->size.bytes);
+      switch (body->type) {	/* extra stuff depends upon body type */
+      case TYPEMESSAGE:
+				/* can't do this if not RFC822 */
+	if (strcmp (body->subtype,"RFC822")) break;
+	PBOUT (' ');
+	penv (body->nested.msg->env);
+	PBOUT (' ');
+	pbodystructure (body->nested.msg->body);
+      case TYPETEXT:
+	PBOUT (' ');
+	pnum (body->size.lines);
+	break;
+      default:
+	break;
+      }
+      PBOUT (' ');
+      pnstring (body->md5);
+      PBOUT (' ');
+      if (body->disposition.type) {
+	PBOUT ('(');
+	pstring (body->disposition.type);
+	PBOUT (' ');
+	pparam (body->disposition.parameter);
+	PBOUT (')');
+      }
+      else PSOUT ("NIL");
+      PBOUT (' ');
+      pnstringorlist (body->language);
+      PBOUT (' ');
+      pnstring (body->location);
+    }
+  }
+				/* no body */
+  else PSOUT ("\"TEXT\" \"PLAIN\" (\"CHARSET\" \"US-ASCII\") NIL NIL \"7BIT\" 0 0 NIL NIL NIL NIL");
+  PBOUT (')');			/* end of body */
+}
+
+/* Print body (non-extensible)
+ * Accepts: body
+ */
+
+void pbody (BODY *body)
+{
+  PBOUT ('(');			/* delimiter */
+  if (body) {			/* only if there is a body */
+    PART *part;
+				/* multipart type? */
+    if (body->type == TYPEMULTIPART) {
+				/* print each part */
+      if (part = body->nested.part)
+	for (; part; part = part->next) pbody (&(part->body));
+      else pbody (NIL);
+      PBOUT (' ');		/* space delimiter */
+      pstring (body->subtype);	/* and finally the subtype */
+    }
+    else {			/* non-multipart body type */
+      pstring ((char *) body_types[body->type]);
+      PBOUT (' ');
+      pstring (body->subtype);
+      PBOUT (' ');
+      pparam (body->parameter);
+      PBOUT (' ');
+      pnstring (body->id);
+      PBOUT (' ');
+      pnstring (body->description);
+      PBOUT (' ');
+      pstring ((char *) body_encodings[body->encoding]);
+      PBOUT (' ');
+      pnum (body->size.bytes);
+      switch (body->type) {	/* extra stuff depends upon body type */
+      case TYPEMESSAGE:
+				/* can't do this if not RFC822 */
+	if (strcmp (body->subtype,"RFC822")) break;
+	PBOUT (' ');
+	penv (body->nested.msg ? body->nested.msg->env : NIL);
+	PBOUT (' ');
+	pbody (body->nested.msg ? body->nested.msg->body : NIL);
+      case TYPETEXT:
+	PBOUT (' ');
+	pnum (body->size.lines);
+	break;
+      default:
+	break;
+      }
+    }
+  }
+				/* no body */
+  else PSOUT ("\"TEXT\" \"PLAIN\" (\"CHARSET\" \"US-ASCII\") NIL NIL \"7BIT\" 0 0");
+  PBOUT (')');			/* end of body */
+}
+
+/* Print parameter list
+ * Accepts: paramter
+ */
+
+void pparam (PARAMETER *param)
+{
+  if (param) {			/* one specified? */
+    PBOUT ('(');
+    do {
+      pstring (param->attribute);
+      PBOUT (' ');
+      pstring (param->value);
+      if (param = param->next) PBOUT (' ');
+    } while (param);
+    PBOUT (')');		/* end of parameters */
+  }
+  else PSOUT ("NIL");
+}
+
+
+/* Print address list
+ * Accepts: address list
+ */
+
+void paddr (ADDRESS *a)
+{
+  if (a) {			/* have anything in address? */
+    PBOUT ('(');		/* open the address list */
+    do {			/* for each address */
+      PBOUT ('(');		/* open the address */
+      pnstring (a->personal);	/* personal name */
+      PBOUT (' ');
+      pnstring (a->adl);	/* at-domain-list */
+      PBOUT (' ');
+      pnstring (a->mailbox);	/* mailbox */
+      PBOUT (' ');
+      pnstring (a->host);	/* domain name of mailbox's host */
+      PBOUT (')');		/* terminate address */
+    } while (a = a->next);	/* until end of address */
+    PBOUT (')');		/* close address list */
+  }
+  else PSOUT ("NIL");		/* empty address */
+}
+
+/* Print set
+ * Accepts: set
+ */
+
+void pset (SEARCHSET **set)
+{
+  SEARCHSET *cur = *set;
+  while (cur) {			/* while there's a set to do */
+    pnum (cur->first);		/* output first value */
+    if (cur->last) {		/* if range, output second value of range */
+      PBOUT (':');
+      pnum (cur->last);
+    }
+    if (cur = cur->next) PBOUT (',');
+  }
+  mail_free_searchset (set);	/* flush set */
+}
+
+
+/* Print number
+ * Accepts: number
+ */
+
+void pnum (unsigned long i)
+{
+  char tmp[MAILTMPLEN];
+  sprintf (tmp,"%lu",i);
+  PSOUT (tmp);
+}
+
+
+/* Print string
+ * Accepts: string
+ */
+
+void pstring (char *s)
+{
+  SIZEDTEXT st;
+  st.data = (unsigned char *) s;/* set up sized text */
+  st.size = strlen (s);
+  psizedstring (&st,NIL);	/* print string */
+}
+
+
+/* Print nstring
+ * Accepts: string or NIL
+ */
+
+void pnstring (char *s)
+{
+  if (s) pstring (s);		/* print string */
+  else PSOUT ("NIL");
+}
+
+
+/* Print atom or string
+ * Accepts: astring
+ */
+
+void pastring (char *s)
+{
+  char *t;
+  if (!*s) PSOUT ("\"\"");	/* empty string */
+  else {			/* see if atom */
+    for (t = s; (*t > ' ') && !(*t & 0x80) &&
+	 (*t != '"') && (*t != '\\') && (*t != '(') && (*t != ')') &&
+	 (*t != '{') && (*t != '%') && (*t != '*'); t++);
+    if (*t) pstring (s);	/* not an atom */
+    else PSOUT (s);		/* else plop down as atomic */
+  }
+}
+
+/* Print sized text as quoted
+ * Accepts: sized text
+ */
+
+void psizedquoted (SIZEDTEXT *s)
+{
+  PBOUT ('"');			/* use quoted string */
+  ptext (s,NIL);
+  PBOUT ('"');
+}
+
+
+/* Print sized text as literal
+ * Accepts: sized text
+ */
+
+void psizedliteral (SIZEDTEXT *s,STRING *st)
+{
+  PBOUT ('{');			/* print literal size */
+  pnum (s->size);
+  PSOUT ("}\015\012");
+  ptext (s,st);
+}
+
+/* Print sized text as literal or quoted string
+ * Accepts: sized text
+ *	    alternative stringstruct of text
+ */
+
+void psizedstring (SIZEDTEXT *s,STRING *st)
+{
+  unsigned char c;
+  unsigned long i;
+		
+  if (s->data) {		/* if text, check if must use literal */
+    for (i = 0; ((i < s->size) && ((c = s->data[i]) & 0xe0) &&
+		 !(c & 0x80) && (c != '"') && (c != '\\')); ++i);
+				/* must use literal if not all QUOTED-CHAR */
+    if (i < s->size) psizedliteral (s,st);
+    else psizedquoted (s);
+  }
+  else psizedliteral (s,st);
+}
+
+
+/* Print sized text as literal or quoted string
+ * Accepts: sized text
+ */
+
+void psizedastring (SIZEDTEXT *s)
+{
+  unsigned long i;
+  unsigned int atomp = s->size ? T : NIL;
+  for (i = 0; i < s->size; i++){/* check if must use literal */
+    if (!(s->data[i] & 0xe0) || (s->data[i] & 0x80) ||
+	(s->data[i] == '"') || (s->data[i] == '\\')) {
+      psizedliteral (s,NIL);
+      return;
+    }
+    else switch (s->data[i]) {	/* else see if any atom-specials */
+    case '(': case ')': case '{': case ' ':
+    case '%': case '*':		/* list-wildcards */
+    case ']':			/* resp-specials */
+				/* CTL and quoted-specials in literal check */
+      atomp = NIL;		/* not an atom */
+    }
+  }
+  if (atomp) ptext (s,NIL);	/* print as atom */
+  else psizedquoted (s);	/* print as quoted string */
+}
+
+/* Print string list
+ * Accepts: string list
+ */
+
+void pastringlist (STRINGLIST *s)
+{
+  PBOUT ('(');			/* start list */
+  do {
+    psizedastring (&s->text);	/* output list member */
+    if (s->next) PBOUT (' ');
+  } while (s = s->next);
+  PBOUT (')');			/* terminate list */
+}
+
+
+/* Print nstring or list of strings
+ * Accepts: string / string list
+ */
+
+void pnstringorlist (STRINGLIST *s)
+{
+  if (!s) PSOUT ("NIL");	/* no argument given */
+  else if (s->next) {		/* output list as list of strings*/
+    PBOUT ('(');		/* start list */
+    do {			/* output list member */
+      psizedstring (&s->text,NIL);
+      if (s->next) PBOUT (' ');
+    } while (s = s->next);
+    PBOUT (')');		/* terminate list */
+  } 
+				/* and single-element list as string */
+  else psizedstring (&s->text,NIL);
+}
+
+/* Print body part string
+ * Accepts: message number
+ *	    body part id (note: must have space at end to append stuff)
+ *	    sized text of string
+ *	    alternative stringstruct of string
+ *	    text printing arguments
+ */
+
+void pbodypartstring (unsigned long msgno,char *id,SIZEDTEXT *st,STRING *bs,
+		      TEXTARGS *ta)
+{
+  int f = mail_elt (stream,msgno)->seen;
+				/* ignore stringstruct if non-initialized */
+  if (bs && !bs->curpos) bs = NIL;
+  if (ta && st->size) {		/* only if have useful data */
+				/* partial specifier */
+    if (ta->first || ta->last) sprintf (id + strlen (id),"<%lu>",ta->first);
+  				/* in case first byte beyond end of text */
+    if (st->size <= ta->first) st->size = ta->first = 0;
+    else {
+      if (st->data) {		/* offset and truncate */
+	st->data += ta->first;	/* move to desired position */
+	st->size -= ta->first;	/* reduced size */
+      }
+      else if (bs && (SIZE (bs) >= ta->first))
+	SETPOS (bs,ta->first + GETPOS (bs));
+      else st->size = 0;	/* shouldn't happen */
+      if (ta->last && (st->size > ta->last)) st->size = ta->last;
+    }
+  }
+  PSOUT (id);
+  PBOUT (' ');
+  psizedstring (st,bs);		/* output string */
+  changed_flags (msgno,f);	/* and changed flags */
+}
+
+/*  RFC 3501 technically forbids NULs in literals.  Normally, the delivering
+ * MTA would take care of MIME converting the message text so that it is
+ * NUL-free.  If it doesn't, then we have the choice of either violating
+ * IMAP by sending NULs, corrupting the data, or going to lots of work to do
+ * MIME conversion in the IMAP server.
+ */
+
+/* Print raw sized text
+ * Accepts: sizedtext
+ */
+
+void ptext (SIZEDTEXT *txt,STRING *st)
+{
+  unsigned char c,*s;
+  unsigned long i = txt->size;
+  if (s = txt->data) while (i && ((PBOUT ((c = *s++) ? c : 0x80) != EOF))) --i;
+  else if (st) while (i && (PBOUT ((c = SNX (st)) ? c : 0x80) != EOF)) --i;
+				/* failed to complete? */
+  if (i) ioerror (stdout,"writing text");
+}
+
+/* Print thread
+ * Accepts: thread
+ */
+
+void pthread (THREADNODE *thr)
+{
+  THREADNODE *t;
+  while (thr) {			/* for each branch */
+    PBOUT ('(');		/* open branch */
+    if (thr->num) {		/* first node message number */
+      pnum (thr->num);
+      if (t = thr->next) {	/* any subsequent nodes? */
+	PBOUT (' ');
+	while (t) {		/* for each subsequent node */
+	  if (t->branch) {	/* branches? */
+	    pthread (t);	/* yes, recurse to do branch */
+	    t = NIL;		/* done */
+	  }
+	  else {		/* just output this number */
+	    pnum (t->num);
+	    t = t->next;	/* and do next message */
+	  }
+	  if (t) PBOUT (' ');	/* delimit if more to come */
+	}
+      }
+    }
+    else pthread (thr->next);	/* nest for dummy */
+    PBOUT (')');		/* done with this branch */
+    thr = thr->branch;		/* do next branch */
+  }
+}
+
+/* Print capabilities
+ * Accepts: option flag
+ */
+
+void pcapability (long flag)
+{
+  unsigned long i;
+  char *s;
+  struct stat sbuf;
+  AUTHENTICATOR *auth;
+  THREADER *thr = (THREADER *) mail_parameters (NIL,GET_THREADERS,NIL);
+				/* always output protocol level */
+  PSOUT ("CAPABILITY IMAP4REV1 I18NLEVEL=1 LITERAL+");
+#ifdef NETSCAPE_BRAIN_DAMAGE
+  PSOUT (" X-NETSCAPE");
+#endif
+  if (flag >= 0) {		/* want post-authentication capabilities? */
+    PSOUT (" IDLE UIDPLUS NAMESPACE CHILDREN MAILBOX-REFERRALS BINARY UNSELECT ESEARCH WITHIN SCAN SORT");
+    while (thr) {		/* threaders */
+      PSOUT (" THREAD=");
+      PSOUT (thr->name);
+      thr = thr->next;
+    }
+    if (!anonymous) PSOUT (" MULTIAPPEND");
+  }
+  if (flag <= 0) {		/* want pre-authentication capabilities? */
+    PSOUT (" SASL-IR LOGIN-REFERRALS");
+    if (s = ssl_start_tls (NIL)) fs_give ((void **) &s);
+    else PSOUT (" STARTTLS");
+				/* disable plaintext */
+    if (!(i = !mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL)))
+      PSOUT (" LOGINDISABLED");
+    for (auth = mail_lookup_auth (1); auth; auth = auth->next)
+      if (auth->server && !(auth->flags & AU_DISABLE) &&
+	  !(auth->flags & AU_HIDE) && (i || (auth->flags & AU_SECURE))) {
+	PSOUT (" AUTH=");
+	PSOUT (auth->name);
+      }
+    if (!stat (ANOFILE,&sbuf)) PSOUT (" AUTH=ANONYMOUS");
+  }
+}
+
+/* Anonymous users may only use these mailboxes in these namespaces */
+
+char *oktab[] = {"#news.", "#ftp/", "#public/", 0};
+
+
+/* Check if mailbox name is OK
+ * Accepts: reference name
+ *	    mailbox name
+ */
+
+long nameok (char *ref,char *name)
+{
+  int i;
+  unsigned char *s,*t;
+  if (!name) return NIL;	/* failure if missing name */
+  if (!anonymous) return T;	/* otherwise OK if not anonymous */
+				/* validate reference */
+  if (ref && ((*ref == '#') || (*ref == '{')))
+    for (i = 0; oktab[i]; i++) {
+      for (s = ref, t = oktab[i]; *t && !compare_uchar (*s,*t); s++, t++);
+      if (!*t) {		/* reference OK */
+	if (*name == '#') break;/* check name if override */
+	else return T;		/* otherwise done */
+      }
+    }
+				/* ordinary names are OK */
+  if ((*name != '#') && (*name != '{')) return T;
+  for (i = 0; oktab[i]; i++) {	/* validate mailbox */
+    for (s = name, t = oktab[i]; *t && !compare_uchar (*s,*t); s++, t++);
+    if (!*t) return T;		/* name is OK */
+  }
+  response = "%.80s NO Anonymous may not %.80s this name\015\012";
+  return NIL;
+}
+
+
+/* Convert possible BBoard name to actual name
+ * Accepts: command
+ *	    mailbox name
+ * Returns: maibox name
+ */
+
+char *bboardname (char *cmd,char *name)
+{
+  if (cmd[0] == 'B') {		/* want bboard? */
+    char *s = litstk[litsp++] = (char *) fs_get (strlen (name) + 9);
+    sprintf (s,"#public/%s",(*name == '/') ? name+1 : name);
+    name = s;
+  }
+  return name;
+}
+
+/* Test if name is news proxy
+ * Accepts: name
+ * Returns: T if news proxy, NIL otherwise
+ */
+
+long isnewsproxy (char *name)
+{
+  return (nntpproxy && (name[0] == '#') &&
+	  ((name[1] == 'N') || (name[1] == 'n')) &&
+	  ((name[2] == 'E') || (name[2] == 'e')) &&
+	  ((name[3] == 'W') || (name[3] == 'w')) &&
+	  ((name[4] == 'S') || (name[4] == 's')) && (name[5] == '.')) ?
+    LONGT : NIL;
+}
+
+
+/* News proxy generate canonical pattern
+ * Accepts: reference
+ *	    pattern
+ *	    buffer to return canonical pattern
+ * Returns: T on success with pattern in buffer, NIL on failure
+ */
+
+long newsproxypattern (char *ref,char *pat,char *pattern,long flag)
+{
+  if (!nntpproxy) return NIL;
+  if (strlen (ref) > NETMAXMBX) {
+    sprintf (pattern,"Invalid reference specification: %.80s",ref);
+    mm_log (pattern,ERROR);
+    return NIL;
+  }
+  if (strlen (pat) > NETMAXMBX) {
+    sprintf (pattern,"Invalid pattern specification: %.80s",pat);
+    mm_log (pattern,ERROR);
+    return NIL;
+  }
+  if (flag) {			/* prepend proxy specifier */
+    sprintf (pattern,"{%.300s/nntp}",nntpproxy);
+    pattern += strlen (pattern);
+  }
+  if (*ref) {			/* have a reference */
+    strcpy (pattern,ref);	/* copy reference to pattern */
+				/* # overrides mailbox field in reference */
+    if (*pat == '#') strcpy (pattern,pat);
+				/* pattern starts, reference ends, with . */
+    else if ((*pat == '.') && (pattern[strlen (pattern) - 1] == '.'))
+      strcat (pattern,pat + 1);	/* append, omitting one of the period */
+    else strcat (pattern,pat);	/* anything else is just appended */
+  }
+  else strcpy (pattern,pat);	/* just have basic name */
+  return isnewsproxy (pattern);
+}
+
+/* IMAP4rev1 Authentication responder
+ * Accepts: challenge
+ *	    length of challenge
+ *	    pointer to response length return location if non-NIL
+ * Returns: response
+ */
+
+#define RESPBUFLEN 8*MAILTMPLEN
+
+char *imap_responder (void *challenge,unsigned long clen,unsigned long *rlen)
+{
+  unsigned long i,j;
+  unsigned char *t,resp[RESPBUFLEN];
+  if (initial) {		/* initial response given? */
+    if (clen) return NIL;	/* not permitted */
+				/* set up response */
+    i = strlen ((char *) (t = initial));
+    initial = NIL;		/* no more initial response */
+    if ((*t == '=') && !t[1]) {	/* SASL-IR does this for 0-length response */
+      if (rlen) *rlen = 0;	/* set length zero if empty */
+      return cpystr ("");	/* and return empty string as response */
+    }
+  }
+  else {			/* issue challenge, get response */
+    PSOUT ("+ ");
+    for (t = rfc822_binary ((void *) challenge,clen,&i),j = 0; j < i; j++)
+      if (t[j] > ' ') PBOUT (t[j]);
+    fs_give ((void **) &t);
+    CRLF;
+    PFLUSH ();			/* dump output buffer */
+				/* slurp response buffer */
+    slurp ((char *) resp,RESPBUFLEN,INPUTTIMEOUT);
+    if (!(t = (unsigned char *) strchr ((char *) resp,'\012')))
+      return (char *) flush ();
+    if (t[-1] == '\015') --t;	/* remove CR */
+    *t = '\0';			/* tie off buffer */
+    if (resp[0] == '*') {
+      cancelled = T;
+      return NIL;
+    }
+    i = t - resp;		/* length of response */
+    t = resp;			/* set up for return call */
+  }
+  return (i % 4) ? NIL :	/* return if valid BASE64 */
+    (char *) rfc822_base64 (t,i,rlen ? rlen : &i);
+}
+
+/* Proxy copy across mailbox formats
+ * Accepts: mail stream
+ *	    sequence to copy on this stream
+ *	    destination mailbox
+ *	    option flags
+ * Returns: T if success, else NIL
+ */
+
+long proxycopy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  MAILSTREAM *ts;
+  STRING st;
+  MSGDATA md;
+  SEARCHSET *set;
+  char tmp[MAILTMPLEN];
+  unsigned long i,j;
+  md.stream = stream;
+  md.msgno = 0;
+  md.flags = md.date = NIL;
+  md.message = &st;
+  /* Currently ignores CP_MOVE and CP_DEBUG */
+  if (!((options & CP_UID) ?	/* validate sequence */
+	mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence)))
+    return NIL;
+  response = win;		/* cancel previous errors */
+  if (lsterr) fs_give ((void **) &lsterr);
+				/* c-client clobbers sequence, use spare */
+  for (i = 1,j = 0,set = mail_newsearchset (); i <= nmsgs; i++)
+    if (mail_elt (stream,i)->spare = mail_elt (stream,i)->sequence) {
+      mail_append_set (set,mail_uid (stream,i));
+      if (!j) md.msgno = (j = i) - 1;
+    }
+				/* only if at least one message to copy */
+  if (j && !mail_append_multiple (NIL,mailbox,proxy_append,(void *) &md)) {
+    response = trycreate ? losetry : lose;
+    if (set) mail_free_searchset (&set);
+    return NIL;
+  }
+  if (caset) csset = set;	/* set for return value now */
+  else if (set) mail_free_searchset (&set);
+  response = win;		/* stomp any previous babble */
+  if (md.msgno) {		/* get new driver name if was dummy */
+    sprintf (tmp,"Cross-format (%.80s -> %.80s) COPY completed",
+	     stream->dtb->name,(ts = mail_open (NIL,mailbox,OP_PROTOTYPE)) ?
+	     ts->dtb->name : "unknown");
+    mm_log (tmp,NIL);
+  }
+  return LONGT;
+}
+
+/* Proxy append message callback
+ * Accepts: MAIL stream
+ *	    append data package
+ *	    pointer to return initial flags
+ *	    pointer to return message internal date
+ *	    pointer to return stringstruct of message or NIL to stop
+ * Returns: T if success (have message or stop), NIL if error
+ */
+
+long proxy_append (MAILSTREAM *stream,void *data,char **flags,char **date,
+		   STRING **message)
+{
+  MESSAGECACHE *elt;
+  unsigned long i;
+  char *s,*t,tmp[MAILTMPLEN];
+  MSGDATA *md = (MSGDATA *) data;
+  if (md->flags) fs_give ((void **) &md->flags);
+  if (md->date) fs_give ((void **) &md->date);
+  *message = NIL;		/* assume all done */
+  *flags = *date = NIL;
+  while (++md->msgno <= nmsgs)
+    if ((elt = mail_elt (md->stream,md->msgno))->spare) {
+      if (!(elt->valid && elt->day)) {
+	sprintf (tmp,"%lu",md->msgno);
+	mail_fetch_fast (md->stream,tmp,NIL);
+      }
+      memset (s = tmp,0,MAILTMPLEN);
+				/* copy flags */
+      if (elt->seen) strcat (s," \\Seen");
+      if (elt->deleted) strcat (s," \\Deleted");
+      if (elt->flagged) strcat (s," \\Flagged");
+      if (elt->answered) strcat (s," \\Answered");
+      if (elt->draft) strcat (s," \\Draft");
+      if (i = elt->user_flags) do 
+	if ((t = md->stream->user_flags[find_rightmost_bit (&i)]) && *t &&
+	    (strlen (t) < ((size_t) (MAILTMPLEN-((s += strlen (s))+2-tmp))))) {
+	*s++ = ' ';		/* space delimiter */
+	strcpy (s,t);
+      } while (i);		/* until no more user flags */
+      *message = md->message;	/* set up return values */
+      *flags = md->flags = cpystr (tmp + 1);
+      *date = md->date = cpystr (mail_date (tmp,elt));
+      INIT (md->message,msg_string,(void *) md,elt->rfc822_size);
+      break;			/* process this message */
+    }
+  return LONGT;
+}
+
+/* Append message callback
+ * Accepts: MAIL stream
+ *	    append data package
+ *	    pointer to return initial flags
+ *	    pointer to return message internal date
+ *	    pointer to return stringstruct of message or NIL to stop
+ * Returns: T if success (have message or stop), NIL if error
+ */
+
+long append_msg (MAILSTREAM *stream,void *data,char **flags,char **date,
+		 STRING **message)
+{
+  unsigned long i,j;
+  char *t;
+  APPENDDATA *ad = (APPENDDATA *) data;
+  unsigned char *arg = ad->arg;
+				/* flush text of previous message */
+  if (t = ad->flags) fs_give ((void **) &ad->flags);
+  if (t = ad->date) fs_give ((void **) &ad->date);
+  if (t = ad->msg) fs_give ((void **) &ad->msg);
+  *flags = *date = NIL;		/* assume no flags or date */
+  if (t) {			/* have previous message? */
+    if (!*arg) {		/* if least one message, and no more coming */
+      *message = NIL;		/* set stop */
+      return LONGT;		/* return success */
+    }
+    else if (*arg++ != ' ') {	/* must have a delimiter to next argument */
+      response = misarg;	/* oops */
+      return NIL;
+    }
+  }
+  *message = ad->message;	/* return pointer to message stringstruct */
+  if (*arg == '(') {		/* parse optional flag list */
+    t = ++arg;			/* pointer to flag list contents */
+    while (*arg && (*arg != ')')) arg++;
+    if (*arg) *arg++ = '\0';
+    if (*arg == ' ') arg++;
+    *flags = ad->flags = cpystr (t);
+  }
+				/* parse optional date */
+  if (*arg == '"') *date = ad->date = cpystr (snarf (&arg));
+  if (!arg || (*arg != '{'))	/* parse message */
+    response = "%.80s BAD Missing literal in %.80s\015\012";
+  else if (!isdigit (arg[1]))
+    response = "%.80s BAD Missing message to %.80s\015\012";
+  else if (!(i = strtoul (arg+1,&t,10)))
+    response = "%.80s NO Empty message to %.80s\015\012";
+  else if (i > MAXAPPENDTXT)	/* maybe relax this a little */
+    response = "%.80s NO Excessively large message to %.80s\015\012";
+  else if (((*t == '+') && (t[1] == '}') && !t[2]) || ((*t == '}') && !t[1])) {
+				/* get a literal buffer */
+    inliteral (ad->msg = (char *) fs_get (i+1),i);
+    				/* get new command tail */
+    slurp (ad->arg,CMDLEN - (ad->arg - cmdbuf),INPUTTIMEOUT);
+    if (strchr (ad->arg,'\012')) {
+				/* reset strtok mechanism, tie off if done */
+      if (!strtok (ad->arg,"\015\012")) *ad->arg = '\0';
+				/* possible LITERAL+? */
+      if (((j = strlen (ad->arg)) > 3) && (ad->arg[j - 1] == '}') &&
+	  (ad->arg[j - 2] == '+') && isdigit (ad->arg[j - 3])) {
+				/* back over possible count */
+	for (j -= 4; j && isdigit (ad->arg[j]); j--);
+	if (ad->arg[j] == '{') {/* found a literal? */
+	  litplus.ok = T;	/* yes, note LITERAL+ in effect, set size */
+	  litplus.size = strtoul (ad->arg + j + 1,NIL,10);
+	}
+      }
+				/* initialize stringstruct */
+      INIT (ad->message,mail_string,(void *) ad->msg,i);
+      return LONGT;		/* ready to go */
+    }
+    flush ();			/* didn't find end of line? */
+    fs_give ((void **) &ad->msg);
+  }
+  else response = badarg;	/* not a literal */
+  return NIL;			/* error */
+}
+
+/* Got COPY UID data
+ * Accepts: MAIL stream
+ *	    mailbox name
+ *	    UID validity
+ *	    source set of UIDs
+ *	    destination set of UIDs
+ */
+
+void copyuid (MAILSTREAM *stream,char *mailbox,unsigned long uidvalidity,
+	      SEARCHSET *sourceset,SEARCHSET *destset)
+{
+  if (cauidvalidity) fatal ("duplicate COPYUID/APPENDUID data");
+  cauidvalidity = uidvalidity;
+  csset = sourceset;
+  caset = destset;
+}
+
+
+/* Got APPEND UID data
+ * Accepts: mailbox name
+ *	    UID validity
+ *	    destination set of UIDs
+ */
+
+void appenduid (char *mailbox,unsigned long uidvalidity,SEARCHSET *set)
+{
+  copyuid (NIL,mailbox,uidvalidity,NIL,set);
+}
+
+
+/* Got a referral
+ * Accepts: MAIL stream
+ *	    URL
+ *	    referral type code
+ */
+
+char *referral (MAILSTREAM *stream,char *url,long code)
+{
+  if (lstref) fs_give ((void **) &lstref);
+  lstref = cpystr (url);	/* set referral */
+				/* set error if not a logged in referral */
+  if (code != REFAUTH) response = lose;
+  if (!lsterr) lsterr = cpystr ("Try referral URL");
+  return NIL;			/* don't chase referrals for now */
+}
+
+/* Co-routines from MAIL library */
+
+
+/* Message matches a search
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void mm_searched (MAILSTREAM *s,unsigned long msgno)
+{
+				/* nothing to do here */
+}
+
+
+/* Message exists (i.e. there are that many messages in the mailbox)
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void mm_exists (MAILSTREAM *s,unsigned long number)
+{
+				/* note change in number of messages */
+  if ((s != tstream) && (nmsgs != number)) {
+    nmsgs = number;		/* always update number of messages */
+    if (quell_events) existsquelled = T;
+    else {
+      PSOUT ("* ");
+      pnum (nmsgs);
+      PSOUT (" EXISTS\015\012");
+    }
+    recent = 0xffffffff;	/* make sure update recent too */
+  }
+}
+
+
+/* Message expunged
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void mm_expunged (MAILSTREAM *s,unsigned long number)
+{
+  if (quell_events) fatal ("Impossible EXPUNGE event");
+  if (s != tstream) {
+    PSOUT ("* ");
+    pnum (number);
+    PSOUT (" EXPUNGE\015\012");
+  }
+  nmsgs--;
+  existsquelled = T;		/* do EXISTS when command done */
+}
+
+
+/* Message status changed
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void mm_flags (MAILSTREAM *s,unsigned long number)
+{
+  if (s != tstream) mail_elt (s,number)->spare2 = T;
+}
+
+/* Mailbox found
+ * Accepts: hierarchy delimiter
+ *	    mailbox name
+ *	    attributes
+ */
+
+void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes)
+{
+  mm_list_work ("LIST",delimiter,name,attributes);
+}
+
+
+/* Subscribed mailbox found
+ * Accepts: hierarchy delimiter
+ *	    mailbox name
+ *	    attributes
+ */
+
+void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes)
+{
+  mm_list_work ("LSUB",delimiter,name,attributes);
+}
+
+
+/* Mailbox status
+ * Accepts: MAIL stream
+ *	    mailbox name
+ *	    mailbox status
+ */
+
+void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
+{
+  if (!quell_events) {
+    char tmp[MAILTMPLEN];
+    tmp[0] = tmp[1] = '\0';
+    if (status->flags & SA_MESSAGES)
+      sprintf (tmp + strlen (tmp)," MESSAGES %lu",status->messages);
+    if (status->flags & SA_RECENT)
+      sprintf (tmp + strlen (tmp)," RECENT %lu",status->recent);
+    if (status->flags & SA_UNSEEN)
+      sprintf (tmp + strlen (tmp)," UNSEEN %lu",status->unseen);
+    if (status->flags & SA_UIDNEXT)
+      sprintf (tmp + strlen (tmp)," UIDNEXT %lu",status->uidnext);
+    if (status->flags & SA_UIDVALIDITY)
+      sprintf (tmp + strlen(tmp)," UIDVALIDITY %lu",status->uidvalidity);
+    PSOUT ("* STATUS ");
+    pastring (mailbox);
+    PSOUT (" (");
+    PSOUT (tmp+1);
+    PBOUT (')');
+    CRLF;
+  }
+}
+
+/* Worker routine for LIST and LSUB
+ * Accepts: name of response
+ *	    hierarchy delimiter
+ *	    mailbox name
+ *	    attributes
+ */
+
+void mm_list_work (char *what,int delimiter,char *name,long attributes)
+{
+  char *s;
+  if (!quell_events) {
+    char tmp[MAILTMPLEN];
+    if (finding) {
+      PSOUT ("* MAILBOX ");
+      PSOUT (name);
+    }
+				/* new form */
+    else if ((cmd[0] == 'R') || !(attributes & LATT_REFERRAL)) {
+      PSOUT ("* ");
+      PSOUT (what);
+      PSOUT (" (");
+      tmp[0] = tmp[1] = '\0';
+      if (attributes & LATT_NOINFERIORS) strcat (tmp," \\NoInferiors");
+      if (attributes & LATT_NOSELECT) strcat (tmp," \\NoSelect");
+      if (attributes & LATT_MARKED) strcat (tmp," \\Marked");
+      if (attributes & LATT_UNMARKED) strcat (tmp," \\UnMarked");
+      if (attributes & LATT_HASCHILDREN) strcat (tmp," \\HasChildren");
+      if (attributes & LATT_HASNOCHILDREN) strcat (tmp," \\HasNoChildren");
+      PSOUT (tmp+1);
+      switch (delimiter) {
+      case '\\':		/* quoted delimiter */
+      case '"':
+	PSOUT (") \"\\");
+	PBOUT (delimiter);
+	PBOUT ('"');
+	break;
+      case '\0':		/* no delimiter */
+	PSOUT (") NIL");
+	break;
+      default:			/* unquoted delimiter */
+	PSOUT (") \"");
+	PBOUT (delimiter);
+	PBOUT ('"');
+	break;
+      }
+      PBOUT (' ');
+				/* output mailbox name */
+      if (proxylist && (s = strchr (name,'}'))) pastring (s+1);
+      else pastring (name);
+    }
+    CRLF;
+  }
+}
+
+/* Notification event
+ * Accepts: MAIL stream
+ *	    string to log
+ *	    error flag
+ */
+
+void mm_notify (MAILSTREAM *stream,char *string,long errflg)
+{
+  SIZEDTEXT msg;
+  char *s,*code;
+  if (!quell_events && (!tstream || (stream != tstream))) {
+    switch (errflg) {
+    case NIL:			/* information message, set as OK response */
+      if ((string[0] == '[') &&
+	  ((string[1] == 'T') || (string[1] == 't')) &&
+	  ((string[2] == 'R') || (string[2] == 'r')) &&
+	  ((string[3] == 'Y') || (string[3] == 'y')) &&
+	  ((string[4] == 'C') || (string[4] == 'c')) &&
+	  ((string[5] == 'R') || (string[5] == 'r')) &&
+	  ((string[6] == 'E') || (string[6] == 'e')) &&
+	  ((string[7] == 'A') || (string[7] == 'a')) &&
+	  ((string[8] == 'T') || (string[8] == 't')) &&
+	  ((string[9] == 'E') || (string[9] == 'e')) && (string[10] == ']'))
+	trycreate = T;
+    case BYE:			/* some other server signing off */
+    case PARSE:			/* parse glitch, output unsolicited OK */
+      code = "* OK ";
+      break;
+    case WARN:			/* warning, output unsolicited NO (kludge!) */
+      code = "* NO ";
+      break;
+    case ERROR:			/* error that broke command */
+    default:			/* default should never happen */
+      code = "* BAD ";
+      break;
+    }
+    PSOUT (code);
+    msg.size = (s = strpbrk ((char *) (msg.data = (unsigned char *) string),
+			     "\015\012")) ?
+      (s - string) : strlen (string);
+    PSOUTR (&msg);
+    CRLF;
+    PFLUSH ();			/* let client see it immediately */
+  }
+}
+
+/* Log an event for the user to see
+ * Accepts: string to log
+ *	    error flag
+ */
+
+void mm_log (char *string,long errflg)
+{
+  SIZEDTEXT msg;
+  char *s;
+  msg.size = 
+    (s = strpbrk ((char *) (msg.data = (unsigned char *) string),"\015\012")) ?
+      (s - string) : strlen (string);
+  switch (errflg) {
+  case NIL:			/* information message, set as OK response */
+    if (response == win) {	/* only if no other response yet */
+      if (lsterr) {		/* if there was a previous message */
+	if (!quell_events) {
+	  PSOUT ("* OK ");	/* blat it out */
+	  PSOUT (lsterr);
+	  CRLF;
+	  PFLUSH ();		/* let client see it immediately */
+	}
+	fs_give ((void **) &lsterr);
+      }
+      lsterr = cpystr (string); /* copy string for later use */
+      if (s) lsterr[s - string] = NIL;
+    }
+    break;
+  case PARSE:			/* parse glitch, output unsolicited OK */
+    if (!quell_events) {
+      PSOUT ("* OK [PARSE] ");
+      PSOUTR (&msg);
+      CRLF;
+      PFLUSH ();		/* let client see it immediately */
+    }
+    break;
+  case WARN:			/* warning, output unsolicited NO */
+				/* ignore "Mailbox is empty" (KLUDGE!) */
+    if (strcmp (string,"Mailbox is empty")) {
+      if (lstwrn) {		/* have previous warning? */
+	if (!quell_events) {
+	  PSOUT ("* NO ");
+	  PSOUT (lstwrn);
+	  CRLF;
+	  PFLUSH ();		/* make sure client sees it immediately */
+	}
+	fs_give ((void **) &lstwrn);
+      }
+      lstwrn = cpystr (string); /* note last warning */
+      if (s) lstwrn[s - string] = NIL;
+    }
+    break;
+  case ERROR:			/* error that broke command */
+  default:			/* default should never happen */
+    response = trycreate ? losetry : lose;
+    if (lsterr) fs_give ((void **) &lsterr);
+    lsterr = cpystr (string);	/* note last error */
+    if (s) lsterr[s - string] = NIL;
+    break;
+  }
+}
+
+/* Return last error
+ */
+
+char *lasterror (void)
+{
+  if (lsterr) return lsterr;
+  if (lstwrn) return lstwrn;
+  return "<unknown>";
+}
+
+
+/* Log an event to debugging telemetry
+ * Accepts: string to log
+ */
+
+void mm_dlog (char *string)
+{
+  mm_log (string,WARN);		/* shouldn't happen normally */
+}
+
+/* Get user name and password for this host
+ * Accepts: parse of network user name
+ *	    where to return user name
+ *	    where to return password
+ *	    trial count
+ */
+
+void mm_login (NETMBX *mb,char *username,char *password,long trial)
+{
+				/* set user name */
+  strncpy (username,*mb->user ? mb->user : (char *) user,NETMAXUSER);
+  strncpy (password,pass,256);	/* and password */
+}
+
+
+/* About to enter critical code
+ * Accepts: stream
+ */
+
+void mm_critical (MAILSTREAM *s)
+{
+  ++critical;
+}
+
+
+/* About to exit critical code
+ * Accepts: stream
+ */
+
+void mm_nocritical (MAILSTREAM *s)
+{
+				/* go non-critical, pending death? */
+  if (!--critical && (state == LOGOUT)) {
+				/* clean up iff needed */
+    if (s && (stream != s) && !s->lock && (s->dtb->flags & DR_XPOINT))
+      s = mail_close (s);
+    longjmp (jmpenv,1);		/* die now */
+  }
+}
+
+/* Disk error found
+ * Accepts: stream
+ *	    system error code
+ *	    flag indicating that mailbox may be clobbered
+ * Returns: abort flag
+ */
+
+long mm_diskerror (MAILSTREAM *s,long errcode,long serious)
+{
+  if (serious) {		/* try your damnest if clobberage likely */
+    mm_notify (s,"Retrying to fix probable mailbox damage!",ERROR);
+    PFLUSH ();			/* dump output buffer */
+    syslog (LOG_ALERT,
+	    "Retrying after disk error user=%.80s host=%.80s mbx=%.80s: %.80s",
+	    user ? (char *) user : "???",tcp_clienthost (),
+	    (stream && stream->mailbox) ? stream->mailbox : "???",
+	    strerror (errcode));
+    settimeout (0);		/* make damn sure timeout disabled */
+    sleep (60);			/* give it some time to clear up */
+    return NIL;
+  }
+  if (!quell_events) {		/* otherwise die before more damage is done */
+    PSOUT ("* NO Disk error: ");
+    PSOUT (strerror (errcode));
+    CRLF;
+  }
+  return T;
+}
+
+
+/* Log a fatal error event
+ * Accepts: string to log
+ */
+
+void mm_fatal (char *string)
+{
+  SIZEDTEXT msg;
+  char *s;
+  msg.size = 
+    (s = strpbrk ((char *) (msg.data = (unsigned char *) string),"\015\012")) ?
+      (s - string) : strlen (string);
+  if (!quell_events) {
+    PSOUT ("* BYE [ALERT] IMAP4rev1 server crashing: ");
+    PSOUTR (&msg);
+    CRLF;
+    PFLUSH ();
+  }
+  syslog (LOG_ALERT,"Fatal error user=%.80s host=%.80s mbx=%.80s: %.80s",
+	  user ? (char *) user : "???",tcp_clienthost (),
+	  (stream && stream->mailbox) ? stream->mailbox : "???",string);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/imapd/makefile.nt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,55 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+
+# Program:	IMAPD Makefile for Windows 9x and Windows NT
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		5 November 1990
+# Last Edited:	30 August 2006
+
+
+ALERT=\\imapd.alert
+USERALERT=alert.txt
+SHUTDOWN=\\nologin
+ANO=\\anonymous.newsgroups
+NNTP=\\imapd.nntp
+
+C = ..\c-client
+CCLIENTLIB = $C\cclient.lib
+LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib
+OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
+VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
+CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS) -DALERTFILE=\"$(ALERT)\" -DNNTPFILE=\"$(NNTP)\" -DUSERALERTFILE=\"$(USERALERT)\" -DANOFILE=\"$(ANO)\" -DSHUTDOWNFILE=\"$(SHUTDOWN)\"
+
+imapd: $(CCLIENTLIB) imapd.obj
+	LINK /NOLOGO imapd.obj $(LIBS)
+
+imapd.obj: $C\mail.h $C\misc.h $C\osdep.h
+
+$(CCLIENTLIB):
+	@echo Make c-client first
+	false
+
+clean:
+	del *.obj *.exe *.lib *.exp || rem
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo not war?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/imapd/makefile.ntk	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,58 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+
+# Program:	IMAPD Makefile for Windows 9x and Windows NT + Kerberos
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		5 November 1990
+# Last Edited:	30 August 2006
+
+
+ALERT=\\imapd.alert
+USERALERT=alert.txt
+SHUTDOWN=\\nologin
+ANO=\\anonymous.newsgroups
+NNTP=\\imapd.nntp
+
+
+C = ..\c-client
+CCLIENTLIB = $C\cclient.lib
+K5 =  \k5\lib
+K5LIB = $(K5)\comerr32.lib $(K5)\gssapi32.lib $(K5)\krb5_32.lib
+LIBS = $(CCLIENTLIB) $(K5LIB) ws2_32.lib winmm.lib advapi32.lib
+OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
+VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
+CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS) -DALERTFILE=\"$(ALERT)\" -DNNTPFILE=\"$(NNTP)\" -DUSERALERTFILE=\"$(USERALERT)\" -DANOFILE=\"$(ANO)\" -DSHUTDOWNFILE=\"$(SHUTDOWN)\"
+
+imapd: $(CCLIENTLIB) imapd.obj
+	LINK /NOLOGO imapd.obj $(LIBS)
+
+imapd.obj: $C\mail.h $C\misc.h $C\osdep.h
+
+$(CCLIENTLIB):
+	@echo Make c-client first
+	false
+
+clean:
+	del *.obj *.exe *.lib *.exp || rem
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo not war?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/imapd/makefile.w2k	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,56 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+
+# Program:	IMAPD Makefile for Windows 2000/XP
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		5 November 1990
+# Last Edited:	30 August 2006
+
+
+ALERT=\\imapd.alert
+USERALERT=alert.txt
+SHUTDOWN=\\nologin
+ANO=\\anonymous.newsgroups
+NNTP=\\imapd.nntp
+
+
+C = ..\c-client
+CCLIENTLIB = $C\cclient.lib
+LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib secur32.lib crypt32.lib
+OSCOMPAT = /DWIN32
+VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
+CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS) -DALERTFILE=\"$(ALERT)\" -DNNTPFILE=\"$(NNTP)\" -DUSERALERTFILE=\"$(USERALERT)\" -DANOFILE=\"$(ANO)\" -DSHUTDOWNFILE=\"$(SHUTDOWN)\"
+
+imapd: $(CCLIENTLIB) imapd.obj
+	LINK /NOLOGO imapd.obj $(LIBS)
+
+imapd.obj: $C\mail.h $C\misc.h $C\osdep.h
+
+$(CCLIENTLIB):
+	@echo Make c-client first
+	false
+
+clean:
+	del *.obj *.exe *.lib *.exp || rem
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo not war?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ipopd/Makefile	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,58 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+
+# Program:	IPOPD client Makefile
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		28 October 1990
+# Last Edited:	30 August 2006
+
+
+C = ../c-client
+CCLIENTLIB = $C/c-client.a
+SHELL = /bin/sh
+
+# Get local definitions from c-client directory
+
+CC = `cat $C/CCTYPE`
+CFLAGS = -I$C `cat $C/CFLAGS`
+LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS`
+
+ipopd: ipop2d ipop3d
+
+ipop2d: $(CCLIENTLIB) ipop2d.o
+	$(CC) $(CFLAGS) -o ipop2d ipop2d.o $(LDFLAGS)
+
+ipop3d: $(CCLIENTLIB) ipop3d.o
+	$(CC) $(CFLAGS) -o ipop3d ipop3d.o $(LDFLAGS)
+
+ipop2d.o: $C/mail.h $C/misc.h $C/osdep.h
+
+ipop3d.o: $C/mail.h $C/misc.h $C/osdep.h
+
+$(CCLIENTLIB):
+	cd $C;make
+
+clean:
+	rm -f *.o ipop2d ipop3d || true
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo 'not war?'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ipopd/ipop2d.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,711 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	IPOP2D - IMAP to POP2 conversion server
+ *
+ * Author:	Mark Crispin
+ *		UW Technology
+ *		University of Washington
+ *		Seattle, WA  98195
+ *		Internet: MRC@Washington.EDU
+ *
+ * Date:	28 October 1990
+ * Last Edited:	13 February 2008
+ */
+
+
+/* Parameter files */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <signal.h>
+#include <time.h>
+#include "c-client.h"
+
+
+/* Autologout timer */
+#define KODTIMEOUT 60*5
+#define LOGINTIMEOUT 60*3
+#define TIMEOUT 60*30
+
+
+/* Size of temporary buffers */
+#define TMPLEN 1024
+
+
+/* Server states */
+
+#define LISN 0
+#define AUTH 1
+#define MBOX 2
+#define ITEM 3
+#define NEXT 4
+#define DONE 5
+
+/* Global storage */
+
+char *version = "75";		/* edit number of this server */
+short state = LISN;		/* server state */
+short critical = NIL;		/* non-zero if in critical code */
+MAILSTREAM *stream = NIL;	/* mailbox stream */
+time_t idletime = 0;		/* time we went idle */
+unsigned long nmsgs = 0;	/* number of messages */
+unsigned long current = 1;	/* current message number */
+unsigned long size = 0;		/* size of current message */
+char status[MAILTMPLEN];	/* space for status string */
+char *user = "";		/* user name */
+char *pass = "";		/* password */
+unsigned long *msg = NIL;	/* message translation vector */
+char *logout = "Logout";
+char *goodbye = "+ Sayonara\015\012";
+
+
+/* Function prototypes */
+
+int main (int argc,char *argv[]);
+void sayonara (int status);
+void clkint ();
+void kodint ();
+void hupint ();
+void trmint ();
+short c_helo (char *t,int argc,char *argv[]);
+short c_fold (char *t);
+short c_read (char *t);
+short c_retr (char *t);
+short c_acks (char *t);
+short c_ackd (char *t);
+short c_nack (char *t);
+
+/* Main program */
+
+int main (int argc,char *argv[])
+{
+  char *s,*t;
+  char cmdbuf[TMPLEN];
+  char *pgmname = (argc && argv[0]) ?
+    (((s = strrchr (argv[0],'/')) || (s = strrchr (argv[0],'\\'))) ?
+     s+1 : argv[0]) : "ipop2d";
+				/* set service name before linkage */
+  mail_parameters (NIL,SET_SERVICENAME,(void *) "pop");
+#include "linkage.c"
+  if (mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL)) {
+    goodbye = "- POP2 server disabled on this system\015\012";
+    sayonara (1);
+  }
+				/* initialize server */
+  server_init (pgmname,"pop",NIL,clkint,kodint,hupint,trmint,NIL);
+  /* There are reports of POP2 clients which get upset if anything appears
+   * between the "+" and the "POP2" in the greeting.
+   */
+  printf ("+ POP2 %s %s.%s server ready\015\012",tcp_serverhost (),
+	  CCLIENTVERSION,version);
+  fflush (stdout);		/* dump output buffer */
+  state = AUTH;			/* initial server state */
+  while (state != DONE) {	/* command processing loop */
+    idletime = time (0);	/* get a command under timeout */
+    alarm ((state != AUTH) ? TIMEOUT : LOGINTIMEOUT);
+    clearerr (stdin);		/* clear stdin errors */
+    while (!fgets (cmdbuf,TMPLEN-1,stdin)) {
+      if (ferror (stdin) && (errno == EINTR)) clearerr (stdin);
+      else {
+	char *e = ferror (stdin) ?
+	  strerror (errno) : "Unexpected client disconnect";
+	alarm (0);		/* disable all interrupts */
+	server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
+	sprintf (logout = cmdbuf,"%.80s while reading line",e);
+	state = DONE;
+	stream = mail_close (stream);
+	goodbye = NIL;
+	sayonara (1);
+      }
+    }
+    alarm (0);			/* make sure timeout disabled */
+    idletime = 0;		/* no longer idle */
+				/* find end of line */
+    if (!strchr (cmdbuf,'\012')) {
+      server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
+      logout = "- Command line too long\015\012";
+      state = DONE;
+    }
+    else if (!(s = strtok (cmdbuf," \015\012"))) {
+      server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
+      goodbye = "- Missing or null command\015\012";
+      state = DONE;
+    }
+    else {			/* dispatch based on command */
+      ucase (s);		/* canonicalize case */
+				/* snarf argument */
+      t = strtok (NIL,"\015\012");
+      if ((state == AUTH) && !strcmp (s,"HELO")) state = c_helo (t,argc,argv);
+      else if ((state == MBOX || state == ITEM) && !strcmp (s,"FOLD"))
+ 	state = c_fold (t);
+      else if ((state == MBOX || state == ITEM) && !strcmp (s,"READ"))
+	state = c_read (t);
+      else if ((state == ITEM) && !strcmp (s,"RETR")) state = c_retr (t);
+      else if ((state == NEXT) && !strcmp (s,"ACKS")) state = c_acks (t);
+      else if ((state == NEXT) && !strcmp (s,"ACKD")) state = c_ackd (t);
+      else if ((state == NEXT) && !strcmp (s,"NACK")) state = c_nack (t);
+      else if ((state == AUTH || state == MBOX || state == ITEM) &&
+	       !strcmp (s,"QUIT")) {
+	server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
+	state = DONE;		/* done in either case */
+	if (t) goodbye = "- Bogus argument given to QUIT\015\012";
+	else {			/* expunge the stream */
+	  if (stream && nmsgs) stream = mail_close_full (stream,CL_EXPUNGE);
+	  stream = NIL;		/* don't repeat it */
+	}
+      }
+      else {			/* some other or inappropriate command */
+	server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
+	goodbye = "- Bogus or out of sequence command\015\012";
+	state = DONE;
+      }
+    }
+    fflush (stdout);		/* make sure output blatted */
+  }
+				/* clean up the stream */
+  if (stream) mail_close (stream);
+  sayonara (0);
+  return 0;			/* stupid compilers */
+}
+
+
+/* Say goodbye
+ * Accepts: exit status
+ *
+ * Does not return
+ */
+
+void sayonara (int status)
+{
+  logouthook_t lgoh = (logouthook_t) mail_parameters (NIL,GET_LOGOUTHOOK,NIL);
+  if (goodbye) {		/* have a goodbye message? */
+    fputs (goodbye,stdout);
+    fflush (stdout);		/* make sure blatted */
+  }
+  syslog (LOG_INFO,"%s user=%.80s host=%.80s",logout,
+	  user ? (char *) user : "???",tcp_clienthost ());
+				/* do logout hook if needed */
+  if (lgoh) (*lgoh) (mail_parameters (NIL,GET_LOGOUTDATA,NIL));
+  _exit (status);		/* all done */
+}
+
+/* Clock interrupt
+ */
+
+void clkint ()
+{
+  alarm (0);		/* disable all interrupts */
+  server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
+  goodbye = "- Autologout; idle for too long\015\012";
+  logout = "Autologout";
+  state = DONE;			/* mark state done in either case */
+  if (!critical) {		/* badly host if in critical code */
+    if (stream && !stream->lock) mail_close (stream);
+    stream = NIL;
+    sayonara (1);		/* die die die */
+  }
+}
+
+
+/* Kiss Of Death interrupt
+ */
+
+void kodint ()
+{
+				/* only if in command wait */
+  if (idletime && ((time (0) - idletime) > KODTIMEOUT)) {
+    alarm (0);		/* disable all interrupts */
+    server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
+    goodbye = "- Killed (lost mailbox lock)\015\012";
+    logout = "Killed (lost mailbox lock)";
+    state = DONE;		/* mark state done in either case */
+    if (!critical) {		/* badly host if in critical code */
+      if (stream && !stream->lock) mail_close (stream);
+      stream = NIL;
+      sayonara (1);		/* die die die */
+    }
+  }
+}
+
+
+/* Hangup interrupt
+ */
+
+void hupint ()
+{
+  alarm (0);		/* disable all interrupts */
+  server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
+  goodbye = NIL;
+  logout = "Hangup";
+  state = DONE;			/* mark state done in either case */
+  if (!critical) {		/* badly host if in critical code */
+    if (stream && !stream->lock) mail_close (stream);
+    stream = NIL;
+    sayonara (1);		/* die die die */
+  }
+}
+
+
+/* Termination interrupt
+ */
+
+void trmint ()
+{
+  alarm (0);		/* disable all interrupts */
+  server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
+  goodbye = "- Killed (terminated)\015\012";
+  logout = "Killed (terminated)";
+  if (critical) state = DONE;	/* mark state done in either case */
+  /* Make no attempt at graceful closure since a shutdown may be in
+   * progress, and we won't have any time to do mail_close() actions.
+   */
+  else sayonara (1);		/* die die die */
+}
+
+/* Parse HELO command
+ * Accepts: pointer to command argument
+ * Returns: new state
+ */
+
+short c_helo (char *t,int argc,char *argv[])
+{
+  char *s,*u,*p;
+  char tmp[TMPLEN];
+  if ((!(t && *t && (u = strtok (t," ")) && (p = strtok (NIL,"\015\012")))) ||
+      (strlen (p) >= TMPLEN)) {	/* get user name and password */
+    fputs ("- Missing user or password\015\012",stdout);
+    return DONE;
+  }
+				/* copy password, handle quoting */
+  for (s = tmp; *p; p++) *s++ = (*p == '\\') ? *++p : *p;
+  *s = '\0';			/* tie off string */
+  pass = cpystr (tmp);
+  if (!(s = strchr (u,':'))) {	/* want remote mailbox? */
+				/* no, delimit user from possible admin */
+    if (s = strchr (u,'*')) *s++ = '\0';
+    if (server_login (user = cpystr (u),pass,s,argc,argv)) {
+      syslog (LOG_INFO,"%sLogin user=%.80s host=%.80s",s ? "Admin " : "",
+	      user,tcp_clienthost ());
+      return c_fold ("INBOX");	/* local; select INBOX */
+    }
+  }
+#ifndef DISABLE_POP_PROXY
+				/* can't do if can't log in as anonymous */
+  else if (anonymous_login (argc,argv)) {
+    *s++ = '\0';		/* separate host name from user name */
+    user = cpystr (s);		/* note user name */
+    syslog (LOG_INFO,"IMAP login to host=%.80s user=%.80s host=%.80s",u,user,
+	    tcp_clienthost ());
+				/* initially remote INBOX */
+    sprintf (tmp,"{%.128s/user=%.128s}INBOX",u,user);
+				/* disable rimap just in case */
+    mail_parameters (NIL,SET_RSHTIMEOUT,0);
+    return c_fold (tmp);
+  }
+#endif
+  fputs ("- Bad login\015\012",stdout);
+  return DONE;
+}
+
+/* Parse FOLD command
+ * Accepts: pointer to command argument
+ * Returns: new state
+ */
+
+short c_fold (char *t)
+{
+  unsigned long i,j,flags;
+  char *s = NIL,tmp[2*TMPLEN];
+  NETMBX mb;
+  if (!(t && *t)) {		/* make sure there's an argument */
+    fputs ("- Missing mailbox name\015\012",stdout);
+    return DONE;
+  }
+  myusername_full (&flags);	/* get user type flags */
+				/* expunge old stream */
+  if (stream && nmsgs) mail_expunge (stream);
+  nmsgs = 0;			/* no more messages */
+  if (msg) fs_give ((void **) &msg);
+#ifndef DISABLE_POP_PROXY
+  if (flags == MU_ANONYMOUS) {	/* don't permit proxy to leave IMAP */
+    if (stream) {		/* not first time */
+      if (!(stream->mailbox && (s = strchr (stream->mailbox,'}'))))
+	fatal ("bad previous mailbox name");
+      strncpy (tmp,stream->mailbox,i = (++s - stream->mailbox));
+      if (i >= TMPLEN) fatal ("ridiculous network prefix");
+      strcpy (tmp+i,t);		/* append mailbox to initial spec */
+      t = tmp;
+    }
+				/* must be net name first time */
+    else if (!mail_valid_net_parse (t,&mb)) fatal ("anonymous folder bogon");
+  }
+#endif
+				/* open mailbox, note # of messages */
+  if (j = (stream = mail_open (stream,t,NIL)) ? stream->nmsgs : 0) {
+    sprintf (tmp,"1:%lu",j);	/* fetch fast information for all messages */
+    mail_fetch_fast (stream,tmp,NIL);
+    msg = (unsigned long *) fs_get ((stream->nmsgs + 1) *
+				    sizeof (unsigned long));
+    for (i = 1; i <= j; i++)	/* find undeleted messages, add to vector */
+      if (!mail_elt (stream,i)->deleted) msg[++nmsgs] = i;
+  }
+#ifndef DISABLE_POP_PROXY
+  if (!stream && (flags == MU_ANONYMOUS)) {
+    fputs ("- Bad login\015\012",stdout);
+    return DONE;
+  }
+#endif
+  printf ("#%lu messages in %s\015\012",nmsgs,stream ? stream->mailbox :
+	  "<none>");
+  return MBOX;
+}
+
+/* Parse READ command
+ * Accepts: pointer to command argument
+ * Returns: new state
+ */
+
+short c_read (char *t)
+{
+  MESSAGECACHE *elt = NIL;
+  if (t && *t) {		/* have a message number argument? */
+				/* validity check message number */
+    if (((current = strtoul (t,NIL,10)) < 1) || (current > nmsgs)) {
+      fputs ("- Invalid message number given to READ\015\012",stdout);
+      return DONE;
+    }
+  }
+  else if (current > nmsgs) {	/* at end of mailbox? */
+    fputs ("=0 No more messages\015\012",stdout);
+    return MBOX;
+  }
+				/* set size if message valid and exists */
+  size = msg[current] ? (elt = mail_elt(stream,msg[current]))->rfc822_size : 0;
+  if (elt) sprintf (status,"Status: %s%s\015\012",
+		    elt->seen ? "R" : " ",elt->recent ? " " : "O");
+  else status[0] = '\0';	/* no status */
+  size += strlen (status);	/* update size to reflect status */
+				/* display results */
+  printf ("=%lu characters in message %lu\015\012",size + 2,current);
+  return ITEM;
+}
+
+
+/* Parse RETR command
+ * Accepts: pointer to command argument
+ * Returns: new state
+ */
+
+short c_retr (char *t)
+{
+  unsigned long i,j;
+  STRING *bs;
+  if (t) {			/* disallow argument */
+    fputs ("- Bogus argument given to RETR\015\012",stdout);
+    return DONE;
+  }
+  if (size) {			/* message size valid? */
+    t = mail_fetch_header (stream,msg[current],NIL,NIL,&i,FT_PEEK);
+    if (i > 2) {		/* only if there is something */
+      i -= 2;			/* lop off last two octets */
+      while (i) {		/* blat the header */
+	if (!(j = fwrite (t,sizeof (char),i,stdout))) return DONE;
+	if (i -= j) t += j;	/* advance to incomplete data */
+      }
+    }
+    fputs (status,stdout);	/* yes, output message */
+    fputs ("\015\012",stdout);	/* delimit header from text */
+    if (t = mail_fetch_text (stream,msg[current],NIL,&i,FT_RETURNSTRINGSTRUCT))
+      while (i) {		/* blat the text */
+	if (!(j = fwrite (t,sizeof (char),i,stdout))) return DONE;
+	if (i -= j) t += j;	/* advance to incomplete data */
+      }
+    else for (bs = &stream->private.string; i--; )
+      if (putc (SNX (bs),stdout) == EOF) return DONE;
+    fputs ("\015\012",stdout);	/* trailer to coddle PCNFS' NFSMAIL */
+  }
+  else return DONE;		/* otherwise go away */
+  return NEXT;
+}
+
+/* Parse ACKS command
+ * Accepts: pointer to command argument
+ * Returns: new state
+ */
+
+short c_acks (char *t)
+{
+  char tmp[TMPLEN];
+  if (t) {			/* disallow argument */
+    fputs ("- Bogus argument given to ACKS\015\012",stdout);
+    return DONE;
+  }
+				/* mark message as seen */
+  sprintf (tmp,"%lu",msg[current++]);
+  mail_setflag (stream,tmp,"\\Seen");
+  return c_read (NIL);		/* end message reading transaction */
+}
+
+
+/* Parse ACKD command
+ * Accepts: pointer to command argument
+ * Returns: new state
+ */
+
+short c_ackd (char *t)
+{
+  char tmp[TMPLEN];
+  if (t) {			/* disallow argument */
+    fputs ("- Bogus argument given to ACKD\015\012",stdout);
+    return DONE;
+  }
+				/* mark message as seen and deleted */
+  sprintf (tmp,"%lu",msg[current]);
+  mail_setflag (stream,tmp,"\\Seen \\Deleted");
+  msg[current++] = 0;		/* mark message as deleted */
+  return c_read (NIL);		/* end message reading transaction */
+}
+
+
+/* Parse NACK command
+ * Accepts: pointer to command argument
+ * Returns: new state
+ */
+
+short c_nack (char *t)
+{
+  if (t) {			/* disallow argument */
+    fputs ("- Bogus argument given to NACK\015\012",stdout);
+    return DONE;
+  }
+  return c_read (NIL);		/* end message reading transaction */
+}
+
+/* Co-routines from MAIL library */
+
+
+/* Message matches a search
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void mm_searched (MAILSTREAM *stream,unsigned long msgno)
+{
+  /* Never called */
+}
+
+
+/* Message exists (i.e. there are that many messages in the mailbox)
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void mm_exists (MAILSTREAM *stream,unsigned long number)
+{
+  /* Can't use this mechanism.  POP has no means of notifying the client of
+     new mail during the session. */
+}
+
+
+/* Message expunged
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void mm_expunged (MAILSTREAM *stream,unsigned long number)
+{
+  if (state != DONE) {		/* ignore if closing */
+				/* someone else screwed us */
+    goodbye = "- Mailbox expunged from under me!\015\012";
+    if (stream && !stream->lock) mail_close (stream);
+    stream = NIL;
+    sayonara (1);
+  }
+}
+
+
+/* Message status changed
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void mm_flags (MAILSTREAM *stream,unsigned long number)
+{
+  /* This isn't used */
+}
+
+
+/* Mailbox found
+ * Accepts: MAIL stream
+ *	    hierarchy delimiter
+ *	    mailbox name
+ *	    mailbox attributes
+ */
+
+void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes)
+{
+  /* This isn't used */
+}
+
+
+/* Subscribe mailbox found
+ * Accepts: MAIL stream
+ *	    hierarchy delimiter
+ *	    mailbox name
+ *	    mailbox attributes
+ */
+
+void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes)
+{
+  /* This isn't used */
+}
+
+
+/* Mailbox status
+ * Accepts: MAIL stream
+ *	    mailbox name
+ *	    mailbox status
+ */
+
+void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
+{
+  /* This isn't used */
+}
+
+/* Notification event
+ * Accepts: MAIL stream
+ *	    string to log
+ *	    error flag
+ */
+
+void mm_notify (MAILSTREAM *stream,char *string,long errflg)
+{
+  mm_log (string,errflg);	/* just do mm_log action */
+}
+
+
+/* Log an event for the user to see
+ * Accepts: string to log
+ *	    error flag
+ */
+
+void mm_log (char *string,long errflg)
+{
+  switch (errflg) {
+  case NIL:			/* information message */
+  case PARSE:			/* parse glitch */
+    break;			/* too many of these to log */
+  case WARN:			/* warning */
+    syslog (LOG_DEBUG,"%s",string);
+    break;
+  case BYE:			/* driver broke connection */
+    if (state != DONE) {
+      char tmp[MAILTMPLEN];
+      alarm (0);		/* disable all interrupts */
+      server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
+      sprintf (logout = tmp,"Mailbox closed (%.80s)",string);
+      sayonara (1);
+    }
+    break;
+  case ERROR:			/* error that broke command */
+  default:			/* default should never happen */
+    syslog (LOG_NOTICE,"%s",string);
+    break;
+  }
+}
+
+
+/* Log an event to debugging telemetry
+ * Accepts: string to log
+ */
+
+void mm_dlog (char *string)
+{
+  /* Not doing anything here for now */
+}
+
+
+/* Get user name and password for this host
+ * Accepts: parse of network mailbox name
+ *	    where to return user name
+ *	    where to return password
+ *	    trial count
+ */
+
+void mm_login (NETMBX *mb,char *username,char *password,long trial)
+{
+				/* set user name */
+  strncpy (username,*mb->user ? mb->user : user,NETMAXUSER-1);
+  strncpy (password,pass,255);	/* and password */
+  username[NETMAXUSER] = password[255] = '\0';
+}
+
+/* About to enter critical code
+ * Accepts: stream
+ */
+
+void mm_critical (MAILSTREAM *stream)
+{
+  ++critical;
+}
+
+
+/* About to exit critical code
+ * Accepts: stream
+ */
+
+void mm_nocritical (MAILSTREAM *stream)
+{
+  --critical;
+}
+
+
+/* Disk error found
+ * Accepts: stream
+ *	    system error code
+ *	    flag indicating that mailbox may be clobbered
+ * Returns: abort flag
+ */
+
+long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
+{
+  if (serious) {		/* try your damnest if clobberage likely */
+    syslog (LOG_ALERT,
+	    "Retrying after disk error user=%.80s host=%.80s mbx=%.80s: %.80s",
+	    user,tcp_clienthost (),
+	    (stream && stream->mailbox) ? stream->mailbox : "???",
+	    strerror (errcode));
+    alarm (0);			/* make damn sure timeout disabled */
+    sleep (60);			/* give it some time to clear up */
+    return NIL;
+  }
+  syslog (LOG_ALERT,"Fatal disk error user=%.80s host=%.80s mbx=%.80s: %.80s",
+	  user,tcp_clienthost (),
+	  (stream && stream->mailbox) ? stream->mailbox : "???",
+	  strerror (errcode));
+  return T;
+}
+
+
+/* Log a fatal error event
+ * Accepts: string to log
+ */
+
+void mm_fatal (char *string)
+{
+  mm_log (string,ERROR);	/* shouldn't happen normally */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ipopd/ipop3d.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1082 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	IPOP3D - IMAP to POP3 conversion server
+ *
+ * Author:	Mark Crispin
+ *		UW Technology
+ *		University of Washington
+ *		Seattle, WA  98195
+ *		Internet: MRC@Washington.EDU
+ *
+ * Date:	1 November 1990
+ * Last Edited:	19 February 2008
+ */
+
+/* Parameter files */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <signal.h>
+#include <time.h>
+#include "c-client.h"
+
+
+#define CRLF PSOUT ("\015\012")	/* primary output terpri */
+
+
+/* Autologout timer */
+#define KODTIMEOUT 60*5
+#define LOGINTIMEOUT 60*3
+#define TIMEOUT 60*10
+
+
+/* Server states */
+
+#define AUTHORIZATION 0
+#define TRANSACTION 1
+#define UPDATE 2
+#define LOGOUT 3
+
+/* Eudora food */
+
+#define STATUS "Status: %s%s\015\012"
+#define SLEN (sizeof (STATUS)-3)
+
+
+/* Global storage */
+
+char *version = "104";		/* edit number of this server */
+short state = AUTHORIZATION;	/* server state */
+short critical = NIL;		/* non-zero if in critical code */
+MAILSTREAM *stream = NIL;	/* mailbox stream */
+time_t idletime = 0;		/* time we went idle */
+unsigned long nmsgs = 0;	/* current number of messages */
+unsigned long ndele = 0;	/* number of deletes */
+unsigned long nseen = 0;	/* number of mark-seens */
+unsigned long last = 0;		/* highest message accessed */
+unsigned long il = 0;		/* initial last message */
+char challenge[128];		/* challenge */
+char *host = NIL;		/* remote host name */
+char *user = NIL;		/* user name */
+char *pass = NIL;		/* password */
+char *initial = NIL;		/* initial response */
+long *msg = NIL;		/* message translation vector */
+short *flags = NIL;		/* flags */
+char *logout = "Logout";
+char *goodbye = "+OK Sayonara\015\012";
+
+
+/* POP3 flags */
+
+#define DELE 0x1
+#define SEEN 0x2
+
+
+/* Function prototypes */
+
+int main (int argc,char *argv[]);
+void sayonara (int status);
+void clkint ();
+void kodint ();
+void hupint ();
+void trmint ();
+int pass_login (char *t,int argc,char *argv[]);
+char *apop_login (char *chal,char *user,char *md5,int argc,char *argv[]);
+char *responder (void *challenge,unsigned long clen,unsigned long *rlen);
+int mbxopen (char *mailbox);
+long blat (char *text,long lines,unsigned long size,STRING *st);
+void rset ();
+
+/* Main program */
+
+int main (int argc,char *argv[])
+{
+  unsigned long i,j,k;
+  char *s,*t;
+  char tmp[MAILTMPLEN];
+  time_t autologouttime;
+  char *pgmname = (argc && argv[0]) ?
+    (((s = strrchr (argv[0],'/')) || (s = strrchr (argv[0],'\\'))) ?
+     s+1 : argv[0]) : "ipop3d";
+				/* set service name before linkage */
+  mail_parameters (NIL,SET_SERVICENAME,(void *) "pop");
+#include "linkage.c"
+				/* initialize server */
+  server_init (pgmname,"pop3","pop3s",clkint,kodint,hupint,trmint,NIL);
+  mail_parameters (NIL,SET_BLOCKENVINIT,VOIDT);
+  s = myusername_full (&i);	/* get user name and flags */
+  mail_parameters (NIL,SET_BLOCKENVINIT,NIL);
+  if (i == MU_LOGGEDIN) {	/* allow EXTERNAL if logged in already */
+    mail_parameters (NIL,UNHIDE_AUTHENTICATOR,(void *) "EXTERNAL");
+    mail_parameters (NIL,SET_EXTERNALAUTHID,(void *) s);
+  }
+  {				/* set up MD5 challenge */
+    AUTHENTICATOR *auth = mail_lookup_auth (1);
+    while (auth && compare_cstring (auth->name,"CRAM-MD5")) auth = auth->next;
+				/* build challenge -- less than 128 chars */
+    if (auth && auth->server && !(auth->flags & AU_DISABLE))
+      sprintf (challenge,"<%lx.%lx@%.64s>",(unsigned long) getpid (),
+	       (unsigned long) time (0),tcp_serverhost ());
+    else challenge[0] = '\0';	/* no MD5 authentication */
+  }
+  /* There are reports of POP3 clients which get upset if anything appears
+   * between the "+OK" and the "POP3" in the greeting.
+   */
+  PSOUT ("+OK POP3 ");
+  if (!challenge[0]) {		/* if no MD5 enable, output host name */
+    PSOUT (tcp_serverhost ());
+    PBOUT (' ');
+  }
+  PSOUT (CCLIENTVERSION);
+  PBOUT ('.');
+  PSOUT (version);
+  PSOUT (" server ready");
+  if (challenge[0]) {		/* if MD5 enable, output challenge here */
+    PBOUT (' ');
+    PSOUT (challenge);
+  }
+  CRLF;
+  PFLUSH ();			/* dump output buffer */
+  autologouttime = time (0) + LOGINTIMEOUT;
+				/* command processing loop */
+  while ((state != UPDATE) && (state != LOGOUT)) {
+    idletime = time (0);	/* get a command under timeout */
+    alarm ((state == TRANSACTION) ? TIMEOUT : LOGINTIMEOUT);
+    clearerr (stdin);		/* clear stdin errors */
+				/* read command line */
+    while (!PSIN (tmp,MAILTMPLEN)) {
+				/* ignore if some interrupt */
+      if (ferror (stdin) && (errno == EINTR)) clearerr (stdin);
+      else {
+	char *e = ferror (stdin) ?
+	  strerror (errno) : "Unexpected client disconnect";
+	alarm (0);		/* disable all interrupts */
+	server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
+	sprintf (logout = tmp,"%.80s, while reading line",e);
+	goodbye = NIL;
+	rset ();		/* try to gracefully close the stream */
+	if (state == TRANSACTION) mail_close (stream);
+	stream = NIL;
+	state = LOGOUT;
+	sayonara (1);
+      }
+    }
+    alarm (0);			/* make sure timeout disabled */
+    idletime = 0;		/* no longer idle */
+
+    if (!strchr (tmp,'\012'))	/* find end of line */
+      PSOUT ("-ERR Command line too long\015\012");
+    else if (!(s = strtok (tmp," \015\012")))
+      PSOUT ("-ERR Null command\015\012");
+    else {			/* dispatch based on command */
+      ucase (s);		/* canonicalize case */
+				/* snarf argument */
+      t = strtok (NIL,"\015\012");
+				/* QUIT command always valid */
+      if (!strcmp (s,"QUIT")) state = UPDATE;
+      else if (!strcmp (s,"CAPA")) {
+	AUTHENTICATOR *auth;
+	PSOUT ("+OK Capability list follows:\015\012");
+	PSOUT ("TOP\015\012LOGIN-DELAY 180\015\012UIDL\015\012");
+	if (s = ssl_start_tls (NIL)) fs_give ((void **) &s);
+	else PSOUT ("STLS\015\012");
+	if (i = !mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL))
+	  PSOUT ("USER\015\012");
+				/* display secure server authenticators */
+	for (auth = mail_lookup_auth (1), s = "SASL"; auth; auth = auth->next)
+	  if (auth->server && !(auth->flags & AU_DISABLE) &&
+	      !(auth->flags & AU_HIDE) && (i || (auth->flags & AU_SECURE))) {
+	    if (s) {
+	      PSOUT (s);
+	      s = NIL;
+	    }
+	    PBOUT (' ');
+	    PSOUT (auth->name);
+	  }
+	PSOUT (s ? ".\015\012" : "\015\012.\015\012");
+      }
+
+      else switch (state) {	/* else dispatch based on state */
+      case AUTHORIZATION:	/* waiting to get logged in */
+	if (!strcmp (s,"AUTH")) {
+	  if (t && *t) {	/* mechanism given? */
+	    if (host) fs_give ((void **) &host);
+	    if (user) fs_give ((void **) &user);
+	    if (pass) fs_give ((void **) &pass);
+	    s = strtok (t," ");	/* get mechanism name */
+				/* get initial response */
+	    if (initial = strtok (NIL,"\015\012")) {
+	      if ((*initial == '=') && !initial[1]) ++initial;
+	      else if (!*initial) initial = NIL;
+	    }
+	    if (!(user = cpystr (mail_auth (s,responder,argc,argv)))) {
+	      PSOUT ("-ERR Bad authentication\015\012");
+	      syslog (LOG_INFO,"AUTHENTICATE %s failure host=%.80s",s,
+		      tcp_clienthost ());
+	    }
+	    else if ((state = mbxopen ("INBOX")) == TRANSACTION)
+	      syslog (LOG_INFO,"Auth user=%.80s host=%.80s nmsgs=%lu/%lu",
+		      user,tcp_clienthost (),nmsgs,stream->nmsgs);
+	    else syslog (LOG_INFO,"Auth user=%.80s host=%.80s no mailbox",
+			 user,tcp_clienthost ());
+	  }
+	  else {
+	    AUTHENTICATOR *auth;
+	    PSOUT ("+OK Supported authentication mechanisms:\015\012");
+	    i = !mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL);
+	    for (auth = mail_lookup_auth (1); auth; auth = auth->next)
+	      if (auth->server && !(auth->flags & AU_DISABLE) &&
+		  !(auth->flags & AU_HIDE) &&
+		  (i || (auth->flags & AU_SECURE))) {
+		PSOUT (auth->name);
+		CRLF;
+	      }
+	    PBOUT ('.');
+	    CRLF;
+	  }
+	}
+
+	else if (!strcmp (s,"APOP")) {
+	  if (challenge[0]) {	/* can do it if have an MD5 challenge */
+	    if (host) fs_give ((void **) &host);
+	    if (user) fs_give ((void **) &user);
+	    if (pass) fs_give ((void **) &pass);
+				/* get user name */
+	    if (!(t && *t && (s = strtok (t," ")) && (t = strtok(NIL,"\012"))))
+	      PSOUT ("-ERR Missing APOP argument\015\012");
+	    else if (!(user = apop_login (challenge,s,t,argc,argv)))
+	      PSOUT ("-ERR Bad APOP\015\012");
+	    else if ((state = mbxopen ("INBOX")) == TRANSACTION)
+	      syslog (LOG_INFO,"APOP user=%.80s host=%.80s nmsgs=%lu/%lu",
+		      user,tcp_clienthost (),nmsgs,stream->nmsgs);
+	    else syslog (LOG_INFO,"APOP user=%.80s host=%.80s no mailbox",
+			 user,tcp_clienthost ());
+	  }
+	  else PSOUT ("-ERR Not supported\015\012");
+	}
+				/* (chuckle) */
+	else if (!strcmp (s,"RPOP"))
+	  PSOUT ("-ERR Nice try, bunkie\015\012");
+	else if (!strcmp (s,"STLS")) {
+	  if (t = ssl_start_tls (pgmname)) {
+	    PSOUT ("-ERR STLS failed: ");
+	    PSOUT (t);
+	    CRLF;
+	  }
+	  else PSOUT ("+OK STLS completed\015\012");
+	}
+	else if (!mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL) &&
+		 !strcmp (s,"USER")) {
+	  if (host) fs_give ((void **) &host);
+	  if (user) fs_give ((void **) &user);
+	  if (pass) fs_give ((void **) &pass);
+	  if (t && *t) {	/* if user name given */
+				/* skip leading whitespace (bogus clients!) */
+	    while (*t == ' ') ++t;
+				/* remote user name? */
+	    if (s = strchr (t,':')) {
+	      *s++ = '\0';	/* tie off host name */
+	      host = cpystr (t);/* copy host name */
+	      user = cpystr (s);/* copy user name */
+	    }
+				/* local user name */
+	    else user = cpystr (t);
+	    PSOUT ("+OK User name accepted, password please\015\012");
+	  }
+	  else PSOUT ("-ERR Missing username argument\015\012");
+	}
+	else if (!mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL) &&
+		 user && *user && !strcmp (s,"PASS"))
+	  state = pass_login (t,argc,argv);
+	else PSOUT ("-ERR Unknown AUTHORIZATION state command\015\012");
+	break;
+
+      case TRANSACTION:		/* logged in */
+	if (!strcmp (s,"STAT")) {
+	  for (i = 1,j = 0,k = 0; i <= nmsgs; i++)
+				/* message still exists? */
+	    if (msg[i] && !(flags[i] & DELE)) {
+	      j++;		/* count one more undeleted message */
+	      k += mail_elt (stream,msg[i])->rfc822_size + SLEN;
+	    }
+	  sprintf (tmp,"+OK %lu %lu\015\012",j,k);
+	  PSOUT (tmp);
+	}
+	else if (!strcmp (s,"LIST")) {
+	  if (t && *t) {	/* argument do single message */
+	    if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && msg[i] &&
+		!(flags[i] & DELE)) {
+	      sprintf (tmp,"+OK %lu %lu\015\012",i,
+		       mail_elt(stream,msg[i])->rfc822_size + SLEN);
+	      PSOUT (tmp);
+	    }
+	    else PSOUT ("-ERR No such message\015\012");
+	  }
+	  else {		/* entire mailbox */
+	    PSOUT ("+OK Mailbox scan listing follows\015\012");
+	    for (i = 1,j = 0,k = 0; i <= nmsgs; i++)
+	      if (msg[i] && !(flags[i] & DELE)) {
+		sprintf (tmp,"%lu %lu\015\012",i,
+			 mail_elt (stream,msg[i])->rfc822_size + SLEN);
+		PSOUT (tmp);
+	      }
+	    PBOUT ('.');	/* end of list */
+	    CRLF;
+	  }
+	}
+	else if (!strcmp (s,"UIDL")) {
+	  if (t && *t) {	/* argument do single message */
+	    if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && msg[i] &&
+		!(flags[i] & DELE)) {
+	      sprintf (tmp,"+OK %lu %08lx%08lx\015\012",i,stream->uid_validity,
+		       mail_uid (stream,msg[i]));
+	      PSOUT (tmp);
+	    }
+	    else PSOUT ("-ERR No such message\015\012");
+	  }
+	  else {		/* entire mailbox */
+	    PSOUT ("+OK Unique-ID listing follows\015\012");
+	    for (i = 1,j = 0,k = 0; i <= nmsgs; i++)
+	      if (msg[i] && !(flags[i] & DELE)) {
+		sprintf (tmp,"%lu %08lx%08lx\015\012",i,stream->uid_validity,
+			 mail_uid (stream,msg[i]));
+		PSOUT (tmp);
+	      }
+	    PBOUT ('.');	/* end of list */
+	    CRLF;
+	  }
+	}
+
+	else if (!strcmp (s,"RETR")) {
+	  if (t && *t) {	/* must have an argument */
+	    if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && msg[i] &&
+		!(flags[i] & DELE)) {
+	      MESSAGECACHE *elt;
+				/* update highest message accessed */
+	      if (i > last) last = i;
+	      sprintf (tmp,"+OK %lu octets\015\012",
+		       (elt = mail_elt (stream,msg[i]))->rfc822_size + SLEN);
+	      PSOUT (tmp);
+				/* if not marked seen or noted to be marked */
+	      if (!(elt->seen || (flags[i] & SEEN))) {
+		++nseen;	/* note that we need to mark it seen */
+		flags[i] |= SEEN;
+	      }
+				/* get header */
+	      t = mail_fetch_header (stream,msg[i],NIL,NIL,&k,FT_PEEK);
+	      blat (t,-1,k,NIL);/* write up to trailing CRLF */
+				/* build status */
+	      sprintf (tmp,STATUS,elt->seen ? "R" : " ",
+		       elt->recent ? " " : "O");
+	      if (k < 4) CRLF;	/* don't write Status: if no header */
+				/* normal header ending with CRLF CRLF? */
+	      else if (t[k-3] == '\012') {
+		PSOUT (tmp);	/* write status */
+		CRLF;		/* then write second CRLF */
+	      }
+	      else {		/* abnormal - no blank line at end of header */
+		CRLF;		/* write CRLF first then */
+		PSOUT (tmp);
+	      }
+				/* output text */
+	      t = mail_fetch_text (stream,msg[i],NIL,&k,
+				   FT_RETURNSTRINGSTRUCT | FT_PEEK);
+	      if (k) {		/* only if there is a text body */
+		blat (t,-1,k,&stream->private.string);
+		CRLF;		/* end of list */
+	      }
+	      PBOUT ('.');
+	      CRLF;
+	    }
+	    else PSOUT ("-ERR No such message\015\012");
+	  }
+	  else PSOUT ("-ERR Missing message number argument\015\012");
+	}
+
+	else if (!strcmp (s,"DELE")) {
+	  if (t && *t) {	/* must have an argument */
+	    if ((i = strtoul (t,NIL,10)) && (i <= nmsgs) && msg[i] &&
+		!(flags[i] & DELE)) {
+				/* update highest message accessed */
+	      if (i > last) last = i;
+	      flags[i] |= DELE;	/* note that deletion is requested */
+	      PSOUT ("+OK Message deleted\015\012");
+	      ++ndele;		/* one more message deleted */
+	    }
+	    else PSOUT ("-ERR No such message\015\012");
+	  }
+	  else PSOUT ("-ERR Missing message number argument\015\012");
+	}
+	else if (!strcmp (s,"NOOP"))
+	  PSOUT ("+OK No-op to you too!\015\012");
+	else if (!strcmp (s,"LAST")) {
+	  sprintf (tmp,"+OK %lu\015\012",last);
+	  PSOUT (tmp);
+	}
+	else if (!strcmp (s,"RSET")) {
+	  rset ();		/* reset the mailbox */
+	  PSOUT ("+OK Reset state\015\012");
+	}
+
+	else if (!strcmp (s,"TOP")) {
+	  if (t && *t && (i =strtoul (t,&s,10)) && (i <= nmsgs) && msg[i] &&
+	      !(flags[i] & DELE)) {
+				/* skip whitespace */
+	    while (*s == ' ') s++;
+				/* make sure line count argument good */
+	    if ((*s >= '0') && (*s <= '9')) {
+	      MESSAGECACHE *elt = mail_elt (stream,msg[i]);
+	      j = strtoul (s,NIL,10);
+				/* update highest message accessed */
+	      if (i > last) last = i;
+	      PSOUT ("+OK Top of message follows\015\012");
+				/* get header */
+	      t = mail_fetch_header (stream,msg[i],NIL,NIL,&k,FT_PEEK);
+	      blat (t,-1,k,NIL);/* write up to trailing CRLF */
+				/* build status */
+	      sprintf (tmp,STATUS,elt->seen ? "R" : " ",
+		       elt->recent ? " " : "O");
+	      if (k < 4) CRLF;	/* don't write Status: if no header */
+				/* normal header ending with CRLF CRLF? */
+	      else if (t[k-3] == '\012') {
+		PSOUT (tmp);	/* write status */
+		CRLF;		/* then write second CRLF */
+	      }
+	      else {		/* abnormal - no blank line at end of header */
+		CRLF;		/* write CRLF first then */
+		PSOUT (tmp);
+	      }
+	      if (j) {		/* want any text lines? */
+				/* output text */
+		t = mail_fetch_text (stream,msg[i],NIL,&k,
+				     FT_PEEK | FT_RETURNSTRINGSTRUCT);
+				/* tie off final line if full text output */
+		if (k && (j -= blat (t,j,k,&stream->private.string))) CRLF;
+	      }
+	      PBOUT ('.');	/* end of list */
+	      CRLF;
+	    }
+	    else PSOUT ("-ERR Bad line count argument\015\012");
+	  }
+	  else PSOUT ("-ERR Bad message number argument\015\012");
+	}
+
+	else if (!strcmp (s,"XTND"))
+	  PSOUT ("-ERR Sorry I can't do that\015\012");
+	else PSOUT ("-ERR Unknown TRANSACTION state command\015\012");
+	break;
+      default:
+        PSOUT ("-ERR Server in unknown state\015\012");
+	break;
+      }
+    }
+    PFLUSH ();			/* make sure output finished */
+    if (autologouttime) {	/* have an autologout in effect? */
+				/* cancel if no longer waiting for login */
+      if (state != AUTHORIZATION) autologouttime = 0;
+				/* took too long to login */
+      else if (autologouttime < time (0)) {
+	goodbye = "-ERR Autologout\015\012";
+	logout = "Autologout";
+	state = LOGOUT;		/* sayonara */
+      }
+    }
+  }
+
+				/* open and need to update? */
+  if (stream && (state == UPDATE)) {
+    if (nseen) {		/* only bother if messages need marking seen */
+      *(s = tmp) = '\0';	/* clear sequence */
+      for (i = 1; i <= nmsgs; ++i) if (flags[i] & SEEN) {
+	for (j = i + 1, k = 0; (j <= nmsgs) && (flags[j] & SEEN); ++j) k = j;
+	if (k) sprintf (s,",%lu:%lu",i,k);
+	else sprintf (s,",%lu",i);
+	s += strlen (s);		/* point to end of string */
+	if ((s - tmp) > (MAILTMPLEN - 30)) {
+	  mail_setflag (stream,tmp + 1,"\\Seen");
+	  *(s = tmp) = '\0';	/* restart sequence */
+	}
+	i = j;			/* continue after the range */
+      }
+      if (tmp[0]) mail_setflag (stream,tmp + 1,"\\Seen");
+    }
+    if (ndele) {		/* any messages to delete? */
+      *(s = tmp) = '\0';	/* clear sequence */
+      for (i = 1; i <= nmsgs; ++i) if (flags[i] & DELE) {
+	for (j = i + 1, k = 0; (j <= nmsgs) && (flags[j] & DELE); ++j) k = j;
+	if (k) sprintf (s,",%lu:%lu",i,k);
+	else sprintf (s,",%lu",i);
+	s += strlen (s);	/* point to end of string */
+	if ((s - tmp) > (MAILTMPLEN - 30)) {
+	  mail_setflag (stream,tmp + 1,"\\Deleted");
+	  *(s = tmp) = '\0';	/* restart sequence */
+	}
+	i = j;			/* continue after the range */
+      }
+      if (tmp[0]) mail_setflag (stream,tmp + 1,"\\Deleted");
+      mail_expunge (stream);
+    }
+    syslog (LOG_INFO,"Update user=%.80s host=%.80s nmsgs=%lu ndele=%lu nseen=%lu",
+	    user,tcp_clienthost (),stream->nmsgs,ndele,nseen);
+    mail_close (stream);
+  }
+  sayonara (0);
+  return 0;			/* stupid compilers */
+}
+
+
+/* Say goodbye
+ * Accepts: exit status
+ *
+ * Does not return
+ */
+
+void sayonara (int status)
+{
+  logouthook_t lgoh = (logouthook_t) mail_parameters (NIL,GET_LOGOUTHOOK,NIL);
+  if (goodbye) {		/* have a goodbye message? */
+    PSOUT (goodbye);
+    PFLUSH ();			/* make sure blatted */
+  }
+  syslog (LOG_INFO,"%s user=%.80s host=%.80s",logout,
+	  user ? (char *) user : "???",tcp_clienthost ());
+				/* do logout hook if needed */
+  if (lgoh) (*lgoh) (mail_parameters (NIL,GET_LOGOUTDATA,NIL));
+  _exit (status);		/* all done */
+}
+
+/* Clock interrupt
+ */
+
+void clkint ()
+{
+  alarm (0);			/* disable all interrupts */
+  server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
+  goodbye = "-ERR Autologout; idle for too long\015\012";
+  logout = "Autologout";
+  if (critical) state = LOGOUT;	/* badly hosed if in critical code */
+  else {			/* try to gracefully close the stream */
+    if ((state == TRANSACTION) && !stream->lock) {
+      rset ();
+      mail_close (stream);
+    }
+    state = LOGOUT;
+    stream = NIL;
+    sayonara (1);
+  }
+}
+
+
+/* Kiss Of Death interrupt
+ */
+
+void kodint ()
+{
+				/* only if idle */
+  if (idletime && ((time (0) - idletime) > KODTIMEOUT)) {
+    alarm (0);			/* disable all interrupts */
+    server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
+    goodbye = "-ERR Received Kiss of Death\015\012";
+    logout = "Killed (lost mailbox lock)";
+    if (critical) state =LOGOUT;/* must defer if in critical code */
+    else {			/* try to gracefully close the stream */
+      if ((state == TRANSACTION) && !stream->lock) {
+	rset ();
+	mail_close (stream);
+      }
+      state = LOGOUT;
+      stream = NIL;
+      sayonara (1);		/* die die die */
+    }
+  }
+}
+
+
+/* Hangup interrupt
+ */
+
+void hupint ()
+{
+  alarm (0);			/* disable all interrupts */
+  server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
+  goodbye = NIL;		/* nobody left to talk to */
+  logout = "Hangup";
+  if (critical) state = LOGOUT;	/* must defer if in critical code */
+  else {			/* try to gracefully close the stream */
+    if ((state == TRANSACTION) && !stream->lock) {
+      rset ();
+      mail_close (stream);
+    }
+    state = LOGOUT;
+    stream = NIL;
+    sayonara (1);		/* die die die */
+  }
+}
+
+
+/* Termination interrupt
+ */
+
+void trmint ()
+{
+  alarm (0);			/* disable all interrupts */
+  server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
+  goodbye = "-ERR Killed\015\012";
+  logout = "Killed";
+  if (critical) state = LOGOUT;	/* must defer if in critical code */
+  /* Make no attempt at graceful closure since a shutdown may be in
+   * progress, and we won't have any time to do mail_close() actions.
+   */
+  else sayonara (1);		/* die die die */
+}
+
+/* Parse PASS command
+ * Accepts: pointer to command argument
+ * Returns: new state
+ */
+
+int pass_login (char *t,int argc,char *argv[])
+{
+  char tmp[MAILTMPLEN];
+				/* flush old passowrd */
+  if (pass) fs_give ((void **) &pass);
+  if (!(t && *t)) {		/* if no password given */
+    PSOUT ("-ERR Missing password argument\015\012");
+    return AUTHORIZATION;
+  }
+  pass = cpystr (t);		/* copy password argument */
+  if (!host) {			/* want remote mailbox? */
+				/* no, delimit user from possible admin */
+    if (t = strchr (user,'*')) *t++ ='\0';
+				/* attempt the login */
+    if (server_login (user,pass,t,argc,argv)) {
+      int ret = mbxopen ("INBOX");
+      if (ret == TRANSACTION)	/* mailbox opened OK? */
+	syslog (LOG_INFO,"%sLogin user=%.80s host=%.80s nmsgs=%lu/%lu",
+		t ? "Admin " : "",user,tcp_clienthost (),nmsgs,stream->nmsgs);
+      else syslog (LOG_INFO,"%sLogin user=%.80s host=%.80s no mailbox",
+		   t ? "Admin " : "",user,tcp_clienthost ());
+      return ret;
+    }
+  }
+#ifndef DISABLE_POP_PROXY
+				/* remote; build remote INBOX */
+  else if (anonymous_login (argc,argv)) {
+    syslog (LOG_INFO,"IMAP login to host=%.80s user=%.80s host=%.80s",host,
+	    user,tcp_clienthost ());
+    sprintf (tmp,"{%.128s/user=%.128s}INBOX",host,user);
+				/* disable rimap just in case */
+    mail_parameters (NIL,SET_RSHTIMEOUT,0);
+    return mbxopen (tmp);
+  }
+#endif
+				/* vague error message to confuse crackers */
+  PSOUT ("-ERR Bad login\015\012");
+  return AUTHORIZATION;
+}
+
+/* Authentication responder
+ * Accepts: challenge
+ *	    length of challenge
+ *	    pointer to response length return location if non-NIL
+ * Returns: response
+ */
+
+#define RESPBUFLEN 8*MAILTMPLEN
+
+char *responder (void *challenge,unsigned long clen,unsigned long *rlen)
+{
+  unsigned long i,j;
+  unsigned char *t,resp[RESPBUFLEN];
+  char tmp[MAILTMPLEN];
+  if (initial) {		/* initial response given? */
+    if (clen) return NIL;	/* not permitted */
+				/* set up response */
+    t = (unsigned char *) initial;
+    initial = NIL;		/* no more initial response */
+    return (char *) rfc822_base64 (t,strlen ((char *) t),rlen ? rlen : &i);
+  }
+  PSOUT ("+ ");
+  for (t = rfc822_binary (challenge,clen,&i),j = 0; j < i; j++)
+    if (t[j] > ' ') PBOUT (t[j]);
+  fs_give ((void **) &t);
+  CRLF;
+  PFLUSH ();			/* dump output buffer */
+  resp[RESPBUFLEN-1] = '\0';	/* last buffer character is guaranteed NUL */
+  alarm (LOGINTIMEOUT);		/* get a response under timeout */
+  clearerr (stdin);		/* clear stdin errors */
+				/* read buffer */
+  while (!PSIN ((char *) resp,RESPBUFLEN)) {
+				/* ignore if some interrupt */
+    if (ferror (stdin) && (errno == EINTR)) clearerr (stdin);
+    else {
+      char *e = ferror (stdin) ?
+	strerror (errno) : "Command stream end of file";
+      alarm (0);		/* disable all interrupts */
+      server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
+      sprintf (logout = tmp,"%.80s, while reading authentication",e);
+      goodbye = NIL;
+      state = LOGOUT;
+      sayonara (1);
+    }
+  }
+  if (!(t = (unsigned char *) strchr ((char *) resp,'\012'))) {
+    int c;
+    while ((c = PBIN ()) != '\012') if (c == EOF) {
+				/* ignore if some interrupt */
+      if (ferror (stdin) && (errno == EINTR)) clearerr (stdin);
+      else {
+	char *e = ferror (stdin) ?
+	  strerror (errno) : "Command stream end of file";
+	alarm (0);		/* disable all interrupts */
+	server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
+	sprintf (logout = tmp,"%.80s, while reading auth char",e);
+	goodbye = NIL;
+	state = LOGOUT;
+	sayonara (1);
+      }
+    }
+    return NIL;
+  }
+  alarm (0);			/* make sure timeout disabled */
+  if (t[-1] == '\015') --t;	/* remove CR */
+  *t = '\0';			/* tie off buffer */
+  return (resp[0] != '*') ?
+    (char *) rfc822_base64 (resp,t-resp,rlen ? rlen : &i) : NIL;
+}
+
+/* Select mailbox
+ * Accepts: mailbox name
+ * Returns: new state
+ */
+
+int mbxopen (char *mailbox)
+{
+  unsigned long i,j;
+  char tmp[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  if (msg) fs_give ((void **) &msg);
+				/* open mailbox */
+  if (!(stream = mail_open (stream,mailbox,NIL)))
+    goodbye = "-ERR Unable to open user's INBOX\015\012";
+  else if (stream->rdonly)	/* make sure not readonly */
+    goodbye = "-ERR Can't get lock.  Mailbox in use\015\012";
+  else {
+    nmsgs = 0;			/* no messages yet */
+    if (j = stream->nmsgs) {	/* if mailbox non-empty */
+      sprintf (tmp,"1:%lu",j);	/* fetch fast information for all messages */
+      mail_fetch_fast (stream,tmp,NIL);
+    }
+				/* create 1-origin tables */
+    msg = (long *) fs_get (++j * sizeof (long));
+    flags = (short *) fs_get (j * sizeof (short));
+				/* build map */
+    for (i = 1; i < j; ++i) if (!(elt = mail_elt (stream,i))->deleted) {
+      msg[++nmsgs] = i;		/* note the presence of this message */
+      if (elt->seen) il = nmsgs;/* and set up initial LAST */
+    }
+				/* make sure unused map entries are zero */
+    for (i = nmsgs + 1; i < j; ++i) msg[i] = 0;
+    rset ();			/* do implicit RSET */
+    sprintf (tmp,"+OK Mailbox open, %lu messages\015\012",nmsgs);
+    PSOUT (tmp);
+    return TRANSACTION;
+  }
+  syslog (LOG_INFO,"Error opening or locking INBOX user=%.80s host=%.80s",
+	  user,tcp_clienthost ());
+  return UPDATE;
+}
+
+/* Blat a string with dot checking
+ * Accepts: string
+ *	    maximum number of lines if greater than zero
+ *	    maximum number of bytes to output
+ *	    alternative stringstruct
+ * Returns: number of lines output
+ *
+ * This routine is uglier and kludgier than it should be, just to be robust
+ * in the case of a message which doesn't end in a newline.  Yes, this routine
+ * does truncate the last two bytes from the text.  Since it is normally a
+ * newline and the main routine adds it back, it usually does not make a
+ * difference.  But if it isn't, since the newline is required and the octet
+ * counts have to match, there's no choice but to truncate.
+ */
+
+long blat (char *text,long lines,unsigned long size,STRING *st)
+{
+  char c,d,e;
+  long ret = 0;
+				/* no-op if zero lines or empty string */
+  if (!(lines && (size-- > 2))) return 0;
+  if (text) {
+    c = *text++; d = *text++;	/* collect first two bytes */
+    if (c == '.') PBOUT ('.');	/* double string-leading dot if necessary */
+    while (lines && --size) {	/* copy loop */
+      e = *text++;		/* get next byte */
+      PBOUT (c);		/* output character */
+      if (c == '\012') {	/* end of line? */
+	ret++; --lines;		/* count another line */
+				/* double leading dot as necessary */
+	if (lines && size && (d == '.')) PBOUT ('.');
+      }
+      c = d; d = e;		/* move to next character */
+    }
+  }
+  else {
+    c = SNX (st); d = SNX (st);	/* collect first two bytes */
+    if (c == '.') PBOUT ('.');	/* double string-leading dot if necessary */
+    while (lines && --size) {	/* copy loop */
+      e = SNX (st);		/* get next byte */
+      PBOUT (c);		/* output character */
+      if (c == '\012') {	/* end of line? */
+	ret++; --lines;		/* count another line */
+				/* double leading dot as necessary */
+	if (lines && size && (d == '.')) PBOUT ('.');
+      }
+      c = d; d = e;		/* move to next character */
+    }
+  }
+  return ret;
+}
+
+/* Reset mailbox
+ */
+
+void rset ()
+{
+				/* clear all flags */
+  if (flags) memset ((void *) flags,0,(nmsgs + 1) * sizeof (short));
+  ndele = nseen = 0;		/* no more deleted or seen messages */
+  last = il;			/* restore previous LAST value */
+}
+
+/* Co-routines from MAIL library */
+
+
+/* Message matches a search
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void mm_searched (MAILSTREAM *stream,unsigned long msgno)
+{
+  /* Never called */
+}
+
+
+/* Message exists (i.e. there are that many messages in the mailbox)
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void mm_exists (MAILSTREAM *stream,unsigned long number)
+{
+  /* Can't use this mechanism.  POP has no means of notifying the client of
+     new mail during the session. */
+}
+
+
+/* Message expunged
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void mm_expunged (MAILSTREAM *stream,unsigned long number)
+{
+  unsigned long i = number + 1;
+  msg[number] = 0;		/* I bet that this will annoy someone */
+  while (i <= nmsgs) --msg[i++];
+}
+
+
+/* Message flag status change
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void mm_flags (MAILSTREAM *stream,unsigned long number)
+{
+  /* This isn't used */
+}
+
+
+/* Mailbox found
+ * Accepts: MAIL stream
+ *	    hierarchy delimiter
+ *	    mailbox name
+ *	    mailbox attributes
+ */
+
+void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes)
+{
+  /* This isn't used */
+}
+
+
+/* Subscribe mailbox found
+ * Accepts: MAIL stream
+ *	    hierarchy delimiter
+ *	    mailbox name
+ *	    mailbox attributes
+ */
+
+void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes)
+{
+  /* This isn't used */
+}
+
+
+/* Mailbox status
+ * Accepts: MAIL stream
+ *	    mailbox name
+ *	    mailbox status
+ */
+
+void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
+{
+  /* This isn't used */
+}
+
+/* Notification event
+ * Accepts: MAIL stream
+ *	    string to log
+ *	    error flag
+ */
+
+void mm_notify (MAILSTREAM *stream,char *string,long errflg)
+{
+  mm_log (string,errflg);	/* just do mm_log action */
+}
+
+
+/* Log an event for the user to see
+ * Accepts: string to log
+ *	    error flag
+ */
+
+void mm_log (char *string,long errflg)
+{
+  switch (errflg) {
+  case NIL:			/* information message */
+  case PARSE:			/* parse glitch */
+    break;			/* too many of these to log */
+  case WARN:			/* warning */
+    syslog (LOG_DEBUG,"%s",string);
+    break;
+  case BYE:			/* driver broke connection */
+    if (state != UPDATE) {
+      char tmp[MAILTMPLEN];
+      alarm (0);		/* disable all interrupts */
+      server_init (NIL,NIL,NIL,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN,SIG_IGN);
+      sprintf (logout = tmp,"Mailbox closed (%.80s)",string);
+      goodbye = NIL;
+      state = LOGOUT;
+      sayonara (1);
+    }
+    break;
+  case ERROR:			/* error that broke command */
+  default:			/* default should never happen */
+    syslog (LOG_NOTICE,"%s",string);
+    break;
+  }
+}    
+
+
+/* Log an event to debugging telemetry
+ * Accepts: string to log
+ */
+
+void mm_dlog (char *string)
+{
+  /* Not doing anything here for now */
+}
+
+
+/* Get user name and password for this host
+ * Accepts: parse of network mailbox name
+ *	    where to return user name
+ *	    where to return password
+ *	    trial count
+ */
+
+void mm_login (NETMBX *mb,char *username,char *password,long trial)
+{
+				/* set user name */
+  strncpy (username,*mb->user ? mb->user : user,NETMAXUSER-1);
+  if (pass) {
+    strncpy (password,pass,255);/* and password */
+    fs_give ((void **) &pass);
+  }
+  else memset (password,0,256);	/* no password to send, abort login */
+  username[NETMAXUSER] = password[255] = '\0';
+}
+
+/* About to enter critical code
+ * Accepts: stream
+ */
+
+void mm_critical (MAILSTREAM *stream)
+{
+  ++critical;
+}
+
+
+/* About to exit critical code
+ * Accepts: stream
+ */
+
+void mm_nocritical (MAILSTREAM *stream)
+{
+  --critical;
+}
+
+
+/* Disk error found
+ * Accepts: stream
+ *	    system error code
+ *	    flag indicating that mailbox may be clobbered
+ * Returns: abort flag
+ */
+
+long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
+{
+  if (serious) {		/* try your damnest if clobberage likely */
+    syslog (LOG_ALERT,
+	    "Retrying after disk error user=%.80s host=%.80s mbx=%.80s: %.80s",
+	    user,tcp_clienthost (),
+	    (stream && stream->mailbox) ? stream->mailbox : "???",
+	    strerror (errcode));
+    alarm (0);			/* make damn sure timeout disabled */
+    sleep (60);			/* give it some time to clear up */
+    return NIL;
+  }
+  syslog (LOG_ALERT,"Fatal disk error user=%.80s host=%.80s mbx=%.80s: %.80s",
+	  user,tcp_clienthost (),
+	  (stream && stream->mailbox) ? stream->mailbox : "???",
+	  strerror (errcode));
+  return T;
+}
+
+
+/* Log a fatal error event
+ * Accepts: string to log
+ */
+
+void mm_fatal (char *string)
+{
+  mm_log (string,ERROR);	/* shouldn't happen normally */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ipopd/ipopd.8	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,75 @@
+.ig
+ * ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+..
+.TH IPOPD 8 "August 30, 2006"
+.UC 5
+.SH NAME
+IPOPd \- Post Office Protocol server
+.SH SYNOPSIS
+.B /usr/etc/ipop2d
+.PP
+.B /usr/etc/ipop3d
+.SH DESCRIPTION
+.I ipop2d
+and
+.I ipop3d
+are servers which support the
+.B POP2
+and
+.B POP3
+remote mail access protocols respectively.
+.I ipop2d
+and
+.I ipop3d
+can also be used by
+.B POP2
+and
+.B POP3
+clients respecitively to access mailboxes on
+.B IMAP
+servers by specifying a login user name in the form <host>:<user>
+e.g.,
+.B SERVER.WASHINGTON.EDU:SMITH.
+.PP
+These daemons contain CRAM-MD5 and APOP support.  See the md5.txt
+documentation file for additional information.
+.PP
+.I ipop2d
+and
+.I ipop3d
+are invoked by the internet server (see
+.IR inetd (8)),
+normally for requests to connect to the
+.B POP
+port as indicated by the
+.I /etc/services
+file (see
+.IR services (5)).
+.SH "SEE ALSO"
+imapd(8)
+.SH BUGS
+The
+.B POP2
+and
+.B POP3
+protocols are intrinsically less flexible than
+.B IMAP
+and do not maintain `read' vs `unread' state on the server.  As a result,
+most
+.B POP
+based software transfers all the mail from the server to the client and
+deletes it from the server.  This necessarily locks the user into using only
+a single client.
+.PP
+.B POP3
+does not allow you to specify an alternate folder from the user's default.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ipopd/makefile.nt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,57 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+
+# Program:	IPOPD Makefile for Windows 9x and Windows NT
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		28 October 1990
+# Last Edited:	30 August 2006
+
+
+C = ..\c-client
+CCLIENTLIB = $C\cclient.lib
+LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib
+OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
+VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
+CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
+
+
+ipopd: ipop2d ipop3d
+
+ipop2d: $(CCLIENTLIB) ipop2d.obj
+	LINK /NOLOGO ipop2d.obj $(LIBS)
+
+ipop3d: $(CCLIENTLIB) ipop3d.obj
+	LINK /NOLOGO ipop3d.obj $(LIBS)
+
+ipop2d.obj: $C\mail.h $C\misc.h $C\osdep.h
+
+ipop3d.obj: $C\mail.h $C\misc.h $C\osdep.h
+
+$(CCLIENTLIB):
+	@echo Make c-client first
+	false
+
+clean:
+	del *.obj *.exe *.lib *.exp || rem
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo not war?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ipopd/makefile.ntk	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,58 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+
+# Program:	IPOPD Makefile for Windows 9x and Windows NT + Kerberos
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		28 October 1990
+# Last Edited:	30 August 2006
+
+
+C = ..\c-client
+CCLIENTLIB = $C\cclient.lib
+K5 = \k5\lib
+K5LIB = $(K5)\comerr32.lib $(K5)\gssapi32.lib $(K5)\krb5_32.lib
+LIBS = $(CCLIENTLIB) $(K5LIB) ws2_32.lib winmm.lib advapi32.lib
+OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
+VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
+CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
+
+ipopd: ipop2d ipop3d
+
+ipop2d: $(CCLIENTLIB) ipop2d.obj
+	LINK /NOLOGO ipop2d.obj $(LIBS)
+
+ipop3d: $(CCLIENTLIB) ipop3d.obj
+	LINK /NOLOGO ipop3d.obj $(LIBS)
+
+ipop2d.obj: $C\mail.h $C\misc.h $C\osdep.h
+
+ipop3d.obj: $C\mail.h $C\misc.h $C\osdep.h
+
+$(CCLIENTLIB):
+	@echo Make c-client first
+	false
+
+clean:
+	del *.obj *.exe *.lib *.exp || rem
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo not war?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ipopd/makefile.w2k	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,56 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+
+# Program:	IPOPD Makefile for Windows 2000/XP
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		28 October 1990
+# Last Edited:	30 August 2006
+
+
+C = ..\c-client
+CCLIENTLIB = $C\cclient.lib
+LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib secur32.lib crypt32.lib
+OSCOMPAT = /DWIN32
+VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
+CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
+
+ipopd: ipop2d ipop3d
+
+ipop2d: $(CCLIENTLIB) ipop2d.obj
+	LINK /NOLOGO ipop2d.obj $(LIBS)
+
+ipop3d: $(CCLIENTLIB) ipop3d.obj
+	LINK /NOLOGO ipop3d.obj $(LIBS)
+
+ipop2d.obj: $C\mail.h $C\misc.h $C\osdep.h
+
+ipop3d.obj: $C\mail.h $C\misc.h $C\osdep.h
+
+$(CCLIENTLIB):
+	@echo Make c-client first
+	false
+
+clean:
+	del *.obj *.exe *.lib *.exp || rem
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo not war?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mailutil/Makefile	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,51 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+
+# Program:	mailutil Makefile
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		2 February 1993
+# Last Edited:	30 August 2006
+
+
+C = ../c-client
+CCLIENTLIB = $C/c-client.a
+SHELL = /bin/sh
+
+# Get local definitions from c-client directory
+
+CC = `cat $C/CCTYPE`
+CFLAGS = -I$C `cat $C/CFLAGS`
+LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS`
+
+mailutil: $(CCLIENTLIB) mailutil.o
+	$(CC) $(CFLAGS) -o mailutil mailutil.o $(LDFLAGS)
+
+mailutil.o: $C/mail.h $C/misc.h $C/osdep.h
+
+$(CCLIENTLIB):
+	cd $C;make
+
+clean:
+	rm -f *.o mailutil
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo 'not war?'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mailutil/mailutil.1	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,264 @@
+.ig
+ * ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+..
+.TH mailutil 1 "March 3, 2008" 
+.SH NAME
+mailutil - mail utility program
+.nh
+.SH SYNTAX
+.B mailutil command [switches] [arguments]
+.PP
+All commands accept the -d, -v, and -u switches in addition to any
+command-specific switches.
+.PP
+.B mailutil check [MAILBOX]
+.PP
+.B mailutil create MAILBOX
+.PP
+.B mailutil delete MAILBOX
+.PP
+.B mailutil rename SOURCE DESTINATION
+.PP
+.B mailutil copy [-rw] [-kw] [-ig] SOURCE DESTINATION
+.PP
+.B mailutil move [-rw] [-kw] [-ig] SOURCE DESTINATION
+.PP
+.B mailutil append [-rw] [-kw] [-ig] SOURCE DESTINATION
+.PP
+.B mailutil appenddelete [-rw] [-kw] [-ig] SOURCE DESTINATION
+.PP
+.B mailutil prune MAILBOX CRITERIA
+.PP
+.B mailutil transfer [-m mode] [-rw] [-kw] [-ig] SOURCE DESTINATION
+.SH DESCRIPTION
+.B mailutil
+replaces the old chkmail, imapcopy, imapmove, imapxfer, mbxcopy,
+mbxcreat, and mbxcvt programs.
+.PP
+.B mailutil check
+determines whether new mail exists in the given mailbox (the default
+is INBOX).  The number of new messages is defined as the number of
+messages that have "Recent" status set.  If the mailbox contains no
+new messages, 
+.B mailutil check
+will indicate that no new mail is present;
+otherwise, it will report the number of new messages.  In either case,
+it will also indicate the canonical form of the name of the mailbox.
+.PP
+.B mailutil create
+creates a new
+.I mailbox
+with the given name.  The mailbox name must not already exist.  A mailbox
+can be created in a particular format by prefixing the name with 
+.I #driver.
+followed by the format name and a
+.I /
+character.  For example, the command
+.br
+   mailutil create #driver.mbx/junkmail
+.br
+will create a new mailbox named "junkmail" in mbx format.
+.PP
+.B mailutil delete
+deletes an existing
+.I mailbox
+with the given name.
+.PP
+.B mailutil rename
+renames an existing mailbox to a new name (which must not already exist).
+This only works if the old and new names are in the same mail store.  A
+more general means to rename a mailbox is to do a
+.B mailutil copy
+of the old name to the new name, followed by a
+.B mailutil delete
+of the old name.
+.PP
+.B mailutil copy
+creates a new mailbox and copies messages from the old mailbox to the
+new mailbox.  As in
+.B mailutil create
+a mailbox format can be specified with the new mailbox.  For example, the
+command
+.br
+   mailutil copy INBOX #driver.mbx/INBOX
+.br
+will copy messages from your existing INBOX to an mbx-format INBOX.
+.PP
+.B mailutil move
+is similar to
+.B mailutil copy
+but in addition will also remove (delete and expunge) the messages from the
+old mailbox after copying them to the new mailbox.
+.PP
+.B mailutil append
+and
+.B mailutil appenddelete
+are similar to
+.B mailutil copy
+and
+.B mailutil move
+respectively except that they do not create the destination mailbox.
+.PP
+.B mailutil prune
+prunes the mailbox of messages which match certain criteria, which are
+in the form of IMAP2 (RFC 1176) SEARCH arguments.  For example, the
+command.
+.br
+  mailutil prune INBOX "before 1-jan-2004"
+.br
+will delete and expunge all messages written before January 1, 2004.
+.PP
+Note that mailutil implements pruning by deleting the matching messages,
+and then expunging the mailbox.  Consequently, mailutil will also expunge
+any messages which were deleted at the time of the pruning.
+.PP
+.B mailutil transfer
+copies an entire hierarchy of mailboxes from the named source to the
+named destination.  Mailboxes are created on the destination as
+needed.  Any error in copying messages will cause the transfer to stop.
+.PP
+Normally, any error in creation will cause the transfer to stop.
+However, if
+.B -m MODE
+or
+.B -merge MODE
+is specified, a merging transfer is performed.  The
+.B MODE
+argument indicats the type of merge:
+.PP
+.B -m[erge] prompt
+indicates that the user should be asked for an alternative name to create.
+If creating the new name fails, the user will be asked again.
+.PP
+.B -m[erge] append
+indicates that it's alright to copy the messages into an existing mailbox
+with that name.  If the mailbox does not exist, the user will be prompted
+for an alternative name.
+.PP
+.B -m[erge] suffix=XXXX
+where XXXX is any string, indicates that an alternative name should be
+built by appending the given suffix to the name.  It that alternative name
+can't be created, then the user will be prompted for an alternative name.
+.PP
+The source hierarchy consists of all mailboxes which start
+with the given source name.  With the exception of a remote system
+specification (within "{}" braces), the source name is used as the
+name of the destination.  The destination hierarchy is a prefix
+applied to any new names being created.  For example,
+.br
+   mailutil transfer foo bar
+.br
+will copy all mailboxes with names beginning with "foo" to names
+beginning with "bar" (hence "foobar" will be copied to "barfoobar").
+Similarly,
+.br
+   mailutil transfer "{imap.foo.com}" "{imap.bar.com}old/"
+.br
+will copy all mailboxes from the imap.foo.com IMAP server to
+equivalent names starting with "old/" on the imap.bar.com IMAP server.
+.SH FLAGS
+The
+.B -d
+or
+.B -debug
+flag prints full debugging telemetry including protocol operations.
+.PP
+The
+.B -v
+or
+.B -verbose
+flag prints verbose (non-error) telemetry.
+.PP
+The
+.B -u USERID
+or
+.B -user USERID
+switch attempts to become the indicated user.  This is for the benefit of
+system administrators who want to do mailutil operations on a userid that
+does not normally have shell access.
+.PP
+The
+.B -rw
+or
+.B -rwcopy
+flag causes the source mailbox to be open in readwrite mode rather than
+readonly mode.  Normally, mailutil tries to use readonly mode to avoid
+altering any flags in the source mailbox, but some mailbox types, e.g.
+POP3, can't be open in readonly mode.
+.PP
+The
+.B -kw
+or
+.B -kwcopy
+flag causes the keywords of the source mailbox to be created in the
+destination mailbox.  Normally, mailutil does not create keywords in
+the destination mailbox so only those keywords that are already defined
+in the destination mailbox will be preserved.  Note that some IMAP servers
+may automatically create keywords, so this flag may not be necessary.
+.PP
+The
+.B -ig
+or
+.B -ignore
+flag causes the keywords of the source mailbox to be ignored completely
+and no attempt is made to copy them to the destination mailbox.
+.PP
+The
+.B -ig[nore]
+and
+.B -kw[copy]
+flags are mutually exclusive.
+.SH ARGUMENTS
+The arguments are standard c-client mailbox names.  A
+variety of mailbox name formats and types of mailboxes are supported
+by c-client; examples of the most common forms of names are:
+.PP
+.I
+.IP Name 15
+.I Meaning
+.IP INBOX
+primary incoming mail folder on the local system
+.IP archive/tx-project
+mail folder named "tx-project" in "archive" subdirectory of local
+filesystem home directory
+.IP {imapserver.foo.com}INBOX
+primary incoming mail folder on IMAP server system
+"imapserver.foo.com"
+.IP {imapserver.foo.com}archive/tx-project
+mail folder named "tx-project" in "archive" subdirectory on IMAP
+server system "imapserver.foo.com"
+.IP #news.comp.mail.misc
+newsgroup "comp.mail.misc" on local filesystem
+.IP {newserver.foo.com/nntp}comp.mail.misc
+newsgroup "comp.mail.misc" on NNTP server system "newserver.foo.com"
+.IP {popserver.foo.com/pop3}
+mail folder on POP3 server system "popserver.foo.com"
+.LP
+See your system manager for more information about the types of
+mailboxes which are available on your system.
+.SH RESTRICTIONS
+You must surround a
+.I {host}mailbox
+argument with quotation marks if you run
+.B mailutil
+from
+.IR csh (1)
+or another shell for which braces have special meaning.
+.PP
+You must surround a
+.I #driver.format/mailbox
+argument with quotation marks if you run
+.B mailutil
+from a shell in which "#" is the comment character.
+.SH AUTHOR
+Mark Crispin, MRC@Washington.EDU
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mailutil/mailutil.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,942 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Mail utility
+ *
+ * Author:	Mark Crispin
+ *		UW Technology
+ *		University of Washington
+ *		Seattle, WA  98195
+ *		Internet: MRC@Washington.EDU
+ *
+ * Date:	2 February 1994
+ * Last Edited:	19 February 2008
+ */
+
+
+#include <stdio.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "c-client.h"
+#ifdef SYSCONFIG		/* defined in env_unix.h */
+#include <pwd.h>
+#endif
+
+/* Globals */
+
+char *version = "13";		/* edit number */
+int debugp = NIL;		/* flag saying debug */
+int verbosep = NIL;		/* flag saying verbose */
+int rwcopyp = NIL;		/* flag saying readwrite copy (for POP) */
+int kwcopyp = NIL;		/* flag saying keyword copy */
+int ignorep = NIL;		/* flag saying ignore keywords */
+int critical = NIL;		/* flag saying in critical code */
+int trycreate = NIL;		/* [TRYCREATE] seen */
+char *suffix = NIL;		/* suffer merge mode suffix text */
+int ddelim = -1;		/* destination delimiter */
+FILE *f = NIL;
+
+/* Usage strings */
+
+char *usage2 = "usage: %s %s\n\n%s\n";
+char *usage3 = "usage: %s %s %s\n\n%s\n";
+char *usgchk = "check [MAILBOX]";
+char *usgcre = "create MAILBOX";
+char *usgdel = "delete MAILBOX";
+char *usgren = "rename SOURCE DESTINATION";
+char *usgcpymov = "[-rw[copy]] [-kw[copy]] [-ig[nore]] SOURCE DESTINATION";
+char *usgappdel = "[-rw[copy]] [-kw[copy]] [-ig[nore]] SOURCE DESTINATION";
+char *usgprn = "prune mailbox SEARCH_CRITERIA";
+char *usgxfr = "transfer [-rw[copy]] [-kw[copy]] [-ig[nore]] [-m[erge] m] SOURCE DEST";
+#ifdef SYSCONFIG
+char *stdsw = "Standard switches valid with any command:\n\t[-d[ebug]] [-v[erbose]] [-u[ser] userid] [--]";
+#else
+char *stdsw = "Standard switches valid with any command:\n\t[-d[ebug]] [-v[erbose]]";
+#endif
+
+/* Merge modes */
+
+#define mPROMPT 1
+#define mAPPEND 2
+#define mSUFFIX 3
+
+
+/* Function prototypes */
+
+void ms_init (STRING *s,void *data,unsigned long size);
+char ms_next (STRING *s);
+void ms_setpos (STRING *s,unsigned long i);
+int main (int argc,char *argv[]);
+SEARCHPGM *prune_criteria (char *criteria);
+int prune_criteria_number (unsigned long *number,char **r);
+int mbxcopy (MAILSTREAM *source,MAILSTREAM *dest,char *dst,int create,int del,
+	     int mode);
+long mm_append (MAILSTREAM *stream,void *data,char **flags,char **date,
+		STRING **message);
+
+
+/* Append package */
+
+typedef struct append_package {
+  MAILSTREAM *stream;		/* source stream */
+  unsigned long msgno;		/* current message number */
+  unsigned long msgmax;		/* maximum message number */
+  char *flags;			/* current flags */
+  char *date;			/* message internal date */
+  STRING *message;		/* stringstruct of message */
+} APPENDPACKAGE;
+
+
+/* Message string driver for message stringstructs */
+
+STRINGDRIVER mstring = {
+  ms_init,			/* initialize string structure */
+  ms_next,			/* get next byte in string structure */
+  ms_setpos			/* set position in string structure */
+};
+
+/* Initialize file string structure for file stringstruct
+ * Accepts: string structure
+ *	    pointer to message data structure
+ *	    size of string
+ */
+
+void ms_init (STRING *s,void *data,unsigned long size)
+{
+  APPENDPACKAGE *md = (APPENDPACKAGE *) data;
+  s->data = data;		/* note stream/msgno and header length */
+  mail_fetch_header (md->stream,md->msgno,NIL,NIL,&s->data1,
+		     FT_PREFETCHTEXT|FT_PEEK);
+#if 0
+  s->size = size;		/* message size */
+#else	/* This kludge is necessary because of broken IMAP servers (sigh!) */
+  mail_fetch_text (md->stream,md->msgno,NIL,&s->size,FT_PEEK);
+  s->size += s->data1;		/* header + body size */
+#endif
+  SETPOS (s,0);
+}
+
+
+/* Get next character from file stringstruct
+ * Accepts: string structure
+ * Returns: character, string structure chunk refreshed
+ */
+
+char ms_next (STRING *s)
+{
+  char c = *s->curpos++;	/* get next byte */
+  SETPOS (s,GETPOS (s));	/* move to next chunk */
+  return c;			/* return the byte */
+}
+
+
+/* Set string pointer position for file stringstruct
+ * Accepts: string structure
+ *	    new position
+ */
+
+void ms_setpos (STRING *s,unsigned long i)
+{
+  APPENDPACKAGE *md = (APPENDPACKAGE *) s->data;
+  if (i < s->data1) {		/* want header? */
+    s->chunk = mail_fetch_header (md->stream,md->msgno,NIL,NIL,NIL,FT_PEEK);
+    s->chunksize = s->data1;	/* header length */
+    s->offset = 0;		/* offset is start of message */
+  }
+  else if (i < s->size) {	/* want body */
+    s->chunk = mail_fetch_text (md->stream,md->msgno,NIL,NIL,FT_PEEK);
+    s->chunksize = s->size - s->data1;
+    s->offset = s->data1;	/* offset is end of header */
+  }
+  else {			/* off end of message */
+    s->chunk = NIL;		/* make sure that we crack on this then */
+    s->chunksize = 1;		/* make sure SNX cracks the right way... */
+    s->offset = i;
+  }
+				/* initial position and size */
+  s->curpos = s->chunk + (i -= s->offset);
+  s->cursize = s->chunksize - i;
+}
+
+/* Main program */
+
+int main (int argc,char *argv[])
+{
+  MAILSTREAM *source = NIL;
+  MAILSTREAM *dest = NIL;
+  SEARCHPGM *criteria;
+  char c,*s,*dp,*t,*t1,tmp[MAILTMPLEN],mbx[MAILTMPLEN];
+  unsigned long m,len,curlen,start,last;
+  int i;
+  int merge = NIL;
+  int retcode = 1;
+  int moreswitchp = T;
+  char *cmd = NIL;
+  char *src = NIL;
+  char *dst = NIL;
+  char *pgm = argc ? argv[0] : "mailutil";
+#include "linkage.c"
+  for (i = 1; i < argc; i++) {
+    s = argv[i];		/* pick up argument */
+				/* parse switches */
+    if (moreswitchp && (*s == '-')) {
+      if (!strcmp (s,"-debug") || !strcmp (s,"-d")) debugp = T;
+      else if (!strcmp (s,"-verbose") || !strcmp (s,"-v")) verbosep = T;
+      else if (!strcmp (s,"-rwcopy") || !strcmp (s,"-rw")) rwcopyp = T;
+      else if (!strcmp (s,"-kwcopy") || !strcmp (s,"-kw")) kwcopyp = T;
+      else if (!strcmp (s,"-ignore") || !strcmp (s,"-ig")) ignorep = T;
+      else if ((!strcmp (s,"-merge") || !strcmp (s,"-m")) && (++i < argc)) {
+	if (!strcmp (s = argv[i],"prompt")) merge = mPROMPT;
+	else if (!strcmp (s,"append")) merge = mAPPEND;
+	else if (!strncmp (s,"suffix=",7) && s[7]) {
+	  merge = mSUFFIX;
+	  suffix = cpystr (s+7);
+	}
+	else {
+	  printf ("unknown merge option: %s\n",s);
+	  exit (retcode);
+	}
+      }
+
+#ifdef SYSCONFIG
+      else if ((!strcmp (s,"-user") || !strcmp (s,"-u")) && (++i < argc)) {
+	struct passwd *pw = getpwnam (s = argv[i]);
+	if (!pw) {
+	  printf ("unknown user id: %s\n",argv[i]);
+	  exit (retcode);
+	}
+	else if (setuid (pw->pw_uid)) {
+	  perror ("unable to change user id");
+	  exit (retcode);
+	}
+      }
+#endif
+				/* -- means no more switches, so mailbox
+				   name can start with "-" */
+      else if ((s[1] == '-') && !s[2]) moreswitchp = NIL;
+      else {
+	printf ("unknown switch: %s\n",s);
+	exit (retcode);
+      }
+    }
+    else if (!cmd) cmd = s;	/* first non-switch is command */
+    else if (!src) src = s;	/* second non-switch is source */
+    else if (!dst) dst = s;	/* third non-switch is destination */
+    else {
+      printf ("unknown argument: %s\n",s);
+      exit (retcode);
+    }
+  }
+  if (kwcopyp && ignorep) {
+    puts ("-kwcopy and -ignore are mutually exclusive");
+    exit (retcode);
+  }
+  if (!cmd) cmd = "";		/* prevent SEGV */
+
+  if (!strcmp (cmd,"check")) {	/* check for new messages */
+    if (!src) src = "INBOX";
+    if (dst || merge || rwcopyp || kwcopyp || ignorep)
+      printf (usage2,pgm,usgchk,stdsw);
+    else if (mail_status (source = (*src == '{') ?
+			  mail_open (NIL,src,OP_HALFOPEN |
+				     (debugp ? OP_DEBUG : NIL)) : NIL,
+			  src,SA_MESSAGES | SA_RECENT | SA_UNSEEN))
+      retcode = 0;
+  }
+  else if (!strcmp (cmd,"create")) {
+    if (!src || dst || merge || rwcopyp || kwcopyp || ignorep)
+      printf (usage2,pgm,usgcre,stdsw);
+    else if (mail_create (source = (*src == '{') ?
+			  mail_open (NIL,src,OP_HALFOPEN |
+				     (debugp ? OP_DEBUG : NIL)) : NIL,src))
+      retcode = 0;
+  }
+  else if (!strcmp (cmd,"delete")) {
+    if (!src || dst || merge || rwcopyp || kwcopyp || ignorep)
+      printf (usage2,pgm,usgdel,stdsw);
+    else if (mail_delete (source = (*src == '{') ?
+			  mail_open (NIL,src,OP_HALFOPEN |
+				     (debugp ? OP_DEBUG : NIL)) : NIL,src))
+      retcode = 0;
+  }
+  else if (!strcmp (cmd,"rename")) {
+    if (!src || !dst || merge || rwcopyp || kwcopyp || ignorep)
+      printf (usage2,pgm,usgren,stdsw);
+    else if (mail_rename (source = (*src == '{') ?
+			  mail_open (NIL,src,OP_HALFOPEN |
+				     (debugp ? OP_DEBUG : NIL)) : NIL,src,dst))
+      retcode = 0;
+  }
+
+  else if ((i = !strcmp (cmd,"move")) || !strcmp (cmd,"copy")) {
+    if (!src || !dst || merge) printf (usage3,pgm,cmd,usgcpymov,stdsw);
+    else if (source = mail_open (NIL,src,((i || rwcopyp) ? NIL : OP_READONLY) |
+				 (debugp ? OP_DEBUG : NIL))) {
+      dest = NIL;		/* open destination stream if network */
+      if ((*dst != '{') || (dest = mail_open (NIL,dst,OP_HALFOPEN |
+					      (debugp ? OP_DEBUG : NIL)))) {
+	if (mbxcopy (source,dest,dst,T,i,merge)) retcode = 0;
+      }
+    }
+  }
+  else if ((i = !strcmp (cmd,"appenddelete")) || !strcmp (cmd,"append")) {
+    if (!src || !dst || merge) printf (usage3,pgm,cmd,usgappdel,stdsw);
+    else if (source = mail_open (NIL,src,((i || rwcopyp) ? NIL : OP_READONLY) |
+				 (debugp ? OP_DEBUG : NIL))) {
+      dest = NIL;		/* open destination stream if network */
+      if ((*dst != '{') || (dest = mail_open (NIL,dst,OP_HALFOPEN |
+					      (debugp ? OP_DEBUG : NIL)))) {
+	if (mbxcopy (source,dest,dst,NIL,i,merge)) retcode = 0;
+      }
+    }
+  }
+
+  else if (!strcmp (cmd,"prune")) {
+    if (!src || !dst || merge || rwcopyp || kwcopyp || ignorep ||
+	!(criteria = prune_criteria (dst))) printf (usage2,pgm,usgprn,stdsw);
+    else if ((source = mail_open (NIL,src,(debugp ? OP_DEBUG : NIL))) &&
+	     mail_search_full (source,NIL,criteria,SE_FREE)) {
+      for (m = 1, s = t = NIL, len = start = last = 0; m <= source->nmsgs; m++)
+	if (mail_elt (source,m)->searched) {
+	  if (s) {		/* continuing a range? */
+	    if (m == last + 1) last = m;
+	    else {		/* no, end of previous range? */
+	      if (last != start) sprintf (t,":%lu,%lu",last,m);
+				/* no, just this message */
+	      else sprintf (t,",%lu",m);
+	      start = last = m;	/* either way, start new range */
+				/* running out of space? */
+	      if ((len - (curlen = (t += strlen (t)) - s)) < 20) {
+		fs_resize ((void **) &s,len += MAILTMPLEN);
+		t = s + curlen;	/* relocate current pointer */
+	      }
+	    }
+	  }
+	  else {		/* first time, start new buffer */
+	    s = (char *) fs_get (len = MAILTMPLEN);
+	    sprintf (s,"%lu",start = last = m);
+	    t = s + strlen (s);	/* end of buffer */
+	  }
+	}
+				/* finish last range if necessary */
+      if (last != start) sprintf (t,":%lu",last);
+      if (s) {			/* delete/expunge any matching messages */
+	mail_flag (source,s,"\\Deleted",ST_SET);
+	m = source->nmsgs;	/* get number of messages before purge */
+	mail_expunge (source);
+	printf ("%lu message(s) purged\n",m - source->nmsgs);
+	fs_give ((void **) &s);	/* flush buffer */
+      }
+      else puts ("No matching messages, so nothing purged");
+      source = mail_close (source);
+    }
+  }
+
+  else if (!strcmp (cmd,"transfer")) {
+    if (!src || !dst) printf (usage2,pgm,usgxfr,stdsw);
+    else if ((*src == '{') &&	/* open source mailbox */
+	     !(source = mail_open (NIL,src,OP_HALFOPEN |
+				   (debugp ? OP_DEBUG : NIL))));
+    else if ((*dst == '{') &&	/* open destination server */
+	     !(dest = mail_open (NIL,dst,OP_HALFOPEN |
+				 (debugp ? OP_DEBUG : NIL))));
+    else if (!(f = tmpfile ())) puts ("can't open temporary file");
+    else {
+      if (verbosep) puts ("Listing mailboxes...");
+      if (dest) strcpy (strchr (strcpy (tmp,dest->mailbox),'}') + 1,
+			dp = strchr (dst,'}') + 1);
+      else {
+	dp = dst;
+	tmp[0] = '\0';
+      }
+      mail_list (dest,tmp,"");
+      rewind (f);		/* list all mailboxes matching prefix */
+      if (ddelim < 0) {		/* if server failed to give delimiter */
+	puts ("warning: unable to get destination hierarchy delimiter!");
+	ddelim = 0;		/* default to none */
+      }
+      if (source) strcpy (strchr (strcpy (tmp,source->mailbox),'}') + 1,
+			  strchr (src,'}') + 1);
+      else strcpy (tmp,src);
+      mail_list (source,tmp,"*");
+      rewind (f);
+				/* read back mailbox names */
+      for (retcode = 0; !retcode && (fgets (tmp,MAILTMPLEN-1,f)); ) {
+	if (t = strchr (tmp+1,'\n')) *t = '\0';
+	for (t = mbx,t1 = dest ? dest->mailbox : "",c = NIL; (c != '}') && *t1;
+	     *t++ = c= *t1++);
+	for (t1 = dp; *t1; *t++ = *t1++);
+				/* point to name without delim or netspec */
+	t1 = source ? (strchr (tmp+1,'}') + 1) : tmp + 1;
+				/* src and mbx have different delimiters? */
+	if (ddelim && (ddelim != tmp[0]))
+	  while (c = *t1++) {	/* swap delimiters then */
+	    if (c == ddelim) c = tmp[0] ? tmp[0] : 'x';
+	    else if (c == tmp[0]) c = ddelim;
+	    *t++ = c;
+	  }
+				/* easy case */
+	else while (*t1) *t++ = *t1++;
+	*t++ = '\0';
+	if (verbosep) {
+	  printf ("Copying %s\n  => %s\n",tmp+1,mbx);
+	  fflush (stdout);
+	}
+	if (source = mail_open (source,tmp+1,(debugp ? OP_DEBUG : NIL) | 
+				(rwcopyp ? NIL : OP_READONLY))) {
+	  if (!mbxcopy (source,dest,mbx,T,NIL,merge)) retcode = 1;
+	  if (source->dtb->flags & DR_LOCAL) source = mail_close (source);
+	}
+	else printf ("can't open source mailbox %s\n",tmp+1);
+      }
+    }
+  }
+
+  else {
+    printf ("%s version %s.%s\n\n",pgm,CCLIENTVERSION,version);
+    printf (usage2,pgm,"command [switches] arguments",stdsw);
+    printf ("\nCommands:\n %s\n",usgchk);
+    puts   ("   ;; report number of messages and new messages");
+    printf (" %s\n",usgcre);
+    puts   ("   ;; create new mailbox");
+    printf (" %s\n",usgdel);
+    puts   ("   ;; delete existing mailbox");
+    printf (" %s\n",usgren);
+    puts   ("   ;; rename mailbox to a new name");
+    printf (" copy %s\n",usgcpymov);
+    printf (" move %s\n",usgcpymov);
+    puts   ("   ;; create new mailbox and copy/move messages");
+    printf (" append %s\n",usgappdel);
+    printf (" appenddelete %s\n",usgappdel);
+    puts   ("   ;; copy/move messages to existing mailbox");
+    printf (" %s\n",usgprn);
+    puts   ("   ;; prune mailbox of messages matching criteria");
+    printf (" %s\n",usgxfr);
+    puts   ("   ;; copy source hierarchy to destination");
+    puts   ("   ;;  -merge modes are prompt, append, or suffix=xxxx");
+  }
+				/* close streams */
+  if (source) mail_close (source);
+  if (dest) mail_close (dest);
+  exit (retcode);
+  return retcode;		/* stupid compilers */
+}
+
+/* Pruning criteria, somewhat extended from mail_criteria()
+ * Accepts: criteria
+ * Returns: search program if parse successful, else NIL
+ */
+
+SEARCHPGM *prune_criteria (char *criteria)
+{
+  SEARCHPGM *pgm = NIL;
+  char *criterion,*r,tmp[MAILTMPLEN];
+  int f;
+  if (criteria) {		/* only if criteria defined */
+				/* make writeable copy of criteria */
+    criteria = cpystr (criteria);
+				/* for each criterion */
+    for (pgm = mail_newsearchpgm (), criterion = strtok_r (criteria," ",&r);
+	 criterion; (criterion = strtok_r (NIL," ",&r))) {
+      f = NIL;			/* init then scan the criterion */
+      switch (*ucase (criterion)) {
+      case 'A':			/* possible ALL, ANSWERED */
+	if (!strcmp (criterion+1,"LL")) f = T;
+	else if (!strcmp (criterion+1,"NSWERED")) f = pgm->answered = T;
+	break;
+      case 'B':			/* possible BCC, BEFORE, BODY */
+	if (!strcmp (criterion+1,"CC"))
+	  f = mail_criteria_string (&pgm->bcc,&r);
+	else if (!strcmp (criterion+1,"EFORE"))
+	  f = mail_criteria_date (&pgm->before,&r);
+	else if (!strcmp (criterion+1,"ODY"))
+	  f = mail_criteria_string (&pgm->body,&r);
+	break;
+      case 'C':			/* possible CC */
+	if (!strcmp (criterion+1,"C")) f = mail_criteria_string (&pgm->cc,&r);
+	break;
+      case 'D':			/* possible DELETED, DRAFT */
+	if (!strcmp (criterion+1,"ELETED")) f = pgm->deleted = T;
+	else if (!strcmp (criterion+1,"RAFT")) f = pgm->draft = T;
+	break;
+      case 'F':			/* possible FLAGGED, FROM */
+	if (!strcmp (criterion+1,"LAGGED")) f = pgm->flagged = T;
+	else if (!strcmp (criterion+1,"ROM"))
+	  f = mail_criteria_string (&pgm->from,&r);
+	break;
+      case 'K':			/* possible KEYWORD */
+	if (!strcmp (criterion+1,"EYWORD"))
+	  f = mail_criteria_string (&pgm->keyword,&r);
+	break;
+      case 'L':			/* possible LARGER */
+	if (!strcmp (criterion+1,"ARGER"))
+	  f = prune_criteria_number (&pgm->larger,&r);
+
+      case 'N':			/* possible NEW */
+	if (!strcmp (criterion+1,"EW")) f = pgm->recent = pgm->unseen = T;
+	break;
+      case 'O':			/* possible OLD, ON */
+	if (!strcmp (criterion+1,"LD")) f = pgm->old = T;
+	else if (!strcmp (criterion+1,"N"))
+	  f = mail_criteria_date (&pgm->on,&r);
+	break;
+      case 'R':			/* possible RECENT */
+	if (!strcmp (criterion+1,"ECENT")) f = pgm->recent = T;
+	break;
+      case 'S':			/* possible SEEN, SENT*, SINCE, SMALLER,
+				   SUBJECT */
+	if (!strcmp (criterion+1,"EEN")) f = pgm->seen = T;
+	else if (!strncmp (criterion+1,"ENT",3)) {
+	  if (!strcmp (criterion+4,"BEFORE"))
+	    f = mail_criteria_date (&pgm->sentbefore,&r);
+	  else if (!strcmp (criterion+4,"ON"))
+	    f = mail_criteria_date (&pgm->senton,&r);
+	  else if (!strcmp (criterion+4,"SINCE"))
+	    f = mail_criteria_date (&pgm->sentsince,&r);
+	}
+	else if (!strcmp (criterion+1,"INCE"))
+	  f = mail_criteria_date (&pgm->since,&r);
+	else if (!strcmp (criterion+1,"MALLER"))
+	  f = prune_criteria_number (&pgm->smaller,&r);
+	else if (!strcmp (criterion+1,"UBJECT"))
+	  f = mail_criteria_string (&pgm->subject,&r);
+	break;
+      case 'T':			/* possible TEXT, TO */
+	if (!strcmp (criterion+1,"EXT"))
+	  f = mail_criteria_string (&pgm->text,&r);
+	else if (!strcmp (criterion+1,"O"))
+	  f = mail_criteria_string (&pgm->to,&r);
+	break;
+      case 'U':			/* possible UN* */
+	if (criterion[1] == 'N') {
+	  if (!strcmp (criterion+2,"ANSWERED")) f = pgm->unanswered = T;
+	  else if (!strcmp (criterion+2,"DELETED")) f = pgm->undeleted = T;
+	  else if (!strcmp (criterion+2,"DRAFT")) f = pgm->undraft = T;
+	  else if (!strcmp (criterion+2,"FLAGGED")) f = pgm->unflagged = T;
+	  else if (!strcmp (criterion+2,"KEYWORD"))
+	    f = mail_criteria_string (&pgm->unkeyword,&r);
+	  else if (!strcmp (criterion+2,"SEEN")) f = pgm->unseen = T;
+	}
+	break;
+      default:			/* we will barf below */
+	break;
+      }
+
+      if (!f) {			/* if can't identify criterion */
+	sprintf (tmp,"Unknown search criterion: %.30s",criterion);
+	MM_LOG (tmp,ERROR);
+	mail_free_searchpgm (&pgm);
+	break;
+      }
+    }
+				/* no longer need copy of criteria */
+    fs_give ((void **) &criteria);
+  }
+  return pgm;
+}
+
+
+/* Parse a number
+ * Accepts: pointer to integer to return
+ *	    pointer to strtok state
+ * Returns: T if successful, else NIL
+ */
+
+int prune_criteria_number (unsigned long *number,char **r)
+{
+  char *t;
+  STRINGLIST *s = NIL;
+				/* parse the date and return fn if OK */
+  int ret = (mail_criteria_string (&s,r) &&
+	     (*number = strtoul ((char *) s->text.data,&t,10)) && !*t) ?
+	       T : NIL;
+  if (s) mail_free_stringlist (&s);
+  return ret;
+}
+
+/* Copy mailbox
+ * Accepts: stream open on source
+ *	    halfopen stream for destination or NIL
+ *	    destination mailbox name
+ *	    non-zero to create destination mailbox
+ *	    non-zero to delete messages from source after copying
+ *	    merge mode
+ * Returns: T if success, NIL if error
+ */
+
+int mbxcopy (MAILSTREAM *source,MAILSTREAM *dest,char *dst,int create,int del,
+	     int mode)
+{
+  char *s,tmp[MAILTMPLEN];
+  APPENDPACKAGE ap;
+  STRING st;
+  char *ndst = NIL;
+  int ret = NIL;
+  trycreate = NIL;		/* no TRYCREATE yet */
+  if (create) while (!mail_create (dest,dst) && (mode != mAPPEND)) {
+    switch (mode) {
+    case mPROMPT:		/* prompt user for new name */
+      tmp[0] = '\0';
+      while (!tmp[0]) {		/* read name */
+	fputs ("alternative name: ",stdout);
+	fflush (stdout);
+	fgets (tmp,MAILTMPLEN-1,stdin);
+	if (s = strchr (tmp,'\n')) *s = '\0';
+      }
+      if (ndst) fs_give ((void **) &ndst);
+      ndst = cpystr (tmp);
+      break;
+    case mSUFFIX:		/* try again with new suffix */
+      if (ndst) fs_give ((void **) &ndst);
+      sprintf (ndst = (char *) fs_get (strlen (dst) + strlen (suffix) + 1),
+	       "%s%s",dst,suffix);
+      printf ("retry to create %s\n",ndst);
+      mode = mPROMPT;		/* switch to prompt mode if name fails */
+      break;
+    case NIL:			/* not merging */
+      return NIL;
+    }
+    if (ndst) dst = ndst;	/* if alternative name given, use it */
+  }
+
+  if (kwcopyp) {
+    int i;
+    size_t len;
+    char *dummymsg = "Date: Thu, 18 May 2006 00:00 -0700\r\nFrom: dummy@example.com\r\nSubject: dummy\r\n\r\ndummy\r\n";
+    for (i = 0,len = 0; i < NUSERFLAGS; ++i)
+      if (source->user_flags[i]) len += strlen (source->user_flags[i]) + 1;
+    if (len) {			/* easy if no user flags to copy... */
+      char *t;
+      char *tail = "\\Deleted)";
+      char *flags = (char *) fs_get (1 + len + strlen (tail) + 1);
+      s = flags; *s++ = '(';
+      for (i = 0; i < NUSERFLAGS; ++i) if (t = source->user_flags[i]) {
+	while (*t) *s++ = *t++;
+	*s++ = ' ';
+      }
+      strcpy (s,tail);		/* terminate flags list */
+      if ((dst[0] == '#') && ((dst[1] == 'D') || (dst[1] == 'd')) &&
+	  ((dst[2] == 'R') || (dst[2] == 'r')) &&
+	  ((dst[3] == 'I') || (dst[3] == 'i')) &&
+	  ((dst[4] == 'V') || (dst[4] == 'v')) &&
+	  ((dst[5] == 'E') || (dst[5] == 'e')) &&
+	  ((dst[6] == 'R') || (dst[6] == 'r')) && (dst[7] == '.') &&
+	  (t = strchr (dst+8,'/'))) ++t;
+      else t = dst;
+      INIT (&st,mail_string,dummymsg,strlen (dummymsg));
+      if (!(mail_append (dest,dst,&st) &&
+	    (dest = mail_open (dest,t,debugp ? OP_DEBUG : NIL)))) {
+	fs_give ((void **) &flags);
+	return NIL;
+      }
+      mail_setflag (dest,"*",flags);
+      mail_expunge (dest);
+      fs_give ((void **) &flags);
+    }
+  }
+
+  if (source->nmsgs) {		/* non-empty source */
+    if (verbosep) printf ("%s [%lu message(s)] => %s\n",
+			      source->mailbox,source->nmsgs,dst);
+    ap.stream = source;		/* prepare append package */
+    ap.msgno = 0;
+    ap.msgmax = source->nmsgs;
+    ap.flags = ap.date = NIL;
+    ap.message = &st;
+				/* make sure we have all messages */
+    sprintf (tmp,"1:%lu",ap.msgmax);
+    mail_fetchfast (source,tmp);
+    if (mail_append_multiple (dest,dst,mm_append,(void *) &ap)) {
+      --ap.msgno;		/* make sure user knows it won */
+      if (verbosep) printf ("[Ok %lu messages(s)]\n",ap.msgno);
+      if (del && ap.msgno) {	/* delete source messages */
+	sprintf (tmp,"1:%lu",ap.msgno);
+	mail_flag (source,tmp,"\\Deleted",ST_SET);
+				/* flush moved messages */
+	mail_expunge (source);
+      }
+      ret = T;
+    }
+    else if ((mode == mAPPEND) && trycreate)
+      ret = mbxcopy (source,dest,dst,create,del,mPROMPT);
+    else if (verbosep) puts ("[Failed]");
+  }
+  else {			/* empty source */
+    if (verbosep) printf ("%s [empty] => %s\n",source->mailbox,dst);
+    ret = T;
+  }
+  if (ndst) fs_give ((void **) &ndst);
+  return ret;
+}
+
+/* Append callback
+ * Accepts: mail stream
+ *	    append package
+ *	    pointer to return flags
+ *	    pointer to return date
+ *	    pointer to return message stringstruct
+ * Returns: T on success
+ */
+
+long mm_append (MAILSTREAM *stream,void *data,char **flags,char **date,
+		STRING **message)
+{
+  char *t,*t1,tmp[MAILTMPLEN];
+  unsigned long u;
+  MESSAGECACHE *elt;
+  APPENDPACKAGE *ap = (APPENDPACKAGE *) data;
+  *flags = *date = NIL;		/* assume no flags or date */
+  if (ap->flags) fs_give ((void **) &ap->flags);
+  if (ap->date) fs_give ((void **) &ap->date);
+  mail_gc (ap->stream,GC_TEXTS);
+  if (++ap->msgno <= ap->msgmax) {
+				/* initialize flag string */
+    memset (t = tmp,0,MAILTMPLEN);
+				/* output system flags */
+    if ((elt = mail_elt (ap->stream,ap->msgno))->seen) strcat (t," \\Seen");
+    if (elt->deleted) strcat (t," \\Deleted");
+    if (elt->flagged) strcat (t," \\Flagged");
+    if (elt->answered) strcat (t," \\Answered");
+    if (elt->draft) strcat (t," \\Draft");
+				/* any user flags? */
+    if (!ignorep && (u = elt->user_flags)) do
+      if ((t1 = ap->stream->user_flags[find_rightmost_bit (&u)]) &&
+	  (MAILTMPLEN - ((t += strlen (t)) - tmp)) > (long) (2 + strlen (t1))){
+	*t++ = ' ';		/* space delimiter */
+	strcpy (t,t1);		/* copy the user flag */
+      }
+    while (u);			/* until no more user flags */
+    *flags = ap->flags = cpystr (tmp + 1);
+    *date = ap->date = cpystr (mail_date (tmp,elt));
+    *message = ap->message;	/* message stringstruct */
+    INIT (ap->message,mstring,(void *) ap,elt->rfc822_size);
+  }
+  else *message = NIL;		/* all done */
+  return LONGT;
+}
+
+/* Co-routines from MAIL library */
+
+
+/* Message matches a search
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void mm_searched (MAILSTREAM *stream,unsigned long msgno)
+{
+				/* dummy routine */
+}
+
+
+/* Message exists (i.e. there are that many messages in the mailbox)
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void mm_exists (MAILSTREAM *stream,unsigned long number)
+{
+				/* dummy routine */
+}
+
+
+/* Message expunged
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void mm_expunged (MAILSTREAM *stream,unsigned long number)
+{
+				/* dummy routine */
+}
+
+
+/* Message flags update seen
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void mm_flags (MAILSTREAM *stream,unsigned long number)
+{
+				/* dummy routine */
+}
+
+/* Mailbox found
+ * Accepts: MAIL stream
+ *	    hierarchy delimiter
+ *	    mailbox name
+ *	    mailbox attributes
+ */
+
+void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes)
+{
+				/* note destination delimiter */
+  if (ddelim < 0) ddelim = delimiter;
+				/* if got a selectable name */
+  else if (!(attributes & LATT_NOSELECT) && *name)
+    fprintf (f,"%c%s\n",delimiter,name);
+}
+
+
+/* Subscribe mailbox found
+ * Accepts: MAIL stream
+ *	    hierarchy delimiter
+ *	    mailbox name
+ *	    mailbox attributes
+ */
+
+void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes)
+{
+				/* dummy routine */
+}
+
+
+/* Mailbox status
+ * Accepts: MAIL stream
+ *	    mailbox name
+ *	    mailbox status
+ */
+
+void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
+{
+  if (status->recent || status->unseen)
+    printf ("%lu new message(s) (%lu unseen),",status->recent,status->unseen);
+  else fputs ("No new messages,",stdout);
+  printf (" %lu total in %s\n",status->messages,mailbox);
+}
+
+/* Notification event
+ * Accepts: MAIL stream
+ *	    string to log
+ *	    error flag
+ */
+
+void mm_notify (MAILSTREAM *stream,char *string,long errflg)
+{
+  if (!errflg && (string[0] == '[') &&
+      ((string[1] == 'T') || (string[1] == 't')) &&
+      ((string[2] == 'R') || (string[2] == 'r')) &&
+      ((string[3] == 'Y') || (string[3] == 'y')) &&
+      ((string[4] == 'C') || (string[4] == 'c')) &&
+      ((string[5] == 'R') || (string[5] == 'r')) &&
+      ((string[6] == 'E') || (string[6] == 'e')) &&
+      ((string[7] == 'A') || (string[7] == 'a')) &&
+      ((string[8] == 'T') || (string[8] == 't')) &&
+      ((string[9] == 'E') || (string[9] == 'e')) &&
+      (string[10] == ']'))
+    trycreate = T;  
+  mm_log (string,errflg);	/* just do mm_log action */
+}
+
+
+/* Log an event for the user to see
+ * Accepts: string to log
+ *	    error flag
+ */
+
+void mm_log (char *string,long errflg)
+{
+  switch (errflg) {  
+  case BYE:
+  case NIL:			/* no error */
+    if (verbosep) fprintf (stderr,"[%s]\n",string);
+    break;
+  case PARSE:			/* parsing problem */
+  case WARN:			/* warning */
+    fprintf (stderr,"warning: %s\n",string);
+    break;
+  case ERROR:			/* error */
+  default:
+    fprintf (stderr,"%s\n",string);
+    break;
+  }
+}
+
+
+/* Log an event to debugging telemetry
+ * Accepts: string to log
+ */
+
+void mm_dlog (char *string)
+{
+  fprintf (stderr,"%s\n",string);
+}
+
+/* Get user name and password for this host
+ * Accepts: parse of network mailbox name
+ *	    where to return user name
+ *	    where to return password
+ *	    trial count
+ */
+
+void mm_login (NETMBX *mb,char *username,char *password,long trial)
+{
+  char *s,tmp[MAILTMPLEN];
+  sprintf (s = tmp,"{%s/%s",mb->host,mb->service);
+  if (*mb->user) sprintf (tmp+strlen (tmp),"/user=%s",
+			  strcpy (username,mb->user));
+  if (*mb->authuser) sprintf (tmp+strlen (tmp),"/authuser=%s",mb->authuser);
+  if (*mb->user) strcat (s = tmp,"} password:");
+  else {
+    printf ("%s} username: ",tmp);
+    fgets (username,NETMAXUSER-1,stdin);
+    username[NETMAXUSER-1] = '\0';
+    if (s = strchr (username,'\n')) *s = '\0';
+    s = "password: ";
+  }
+  strcpy (password,getpass (s));
+}
+
+
+/* About to enter critical code
+ * Accepts: stream
+ */
+
+void mm_critical (MAILSTREAM *stream)
+{
+  critical = T;			/* note in critical code */
+}
+
+
+/* About to exit critical code
+ * Accepts: stream
+ */
+
+void mm_nocritical (MAILSTREAM *stream)
+{
+  critical = NIL;		/* note not in critical code */
+}
+
+
+/* Disk error found
+ * Accepts: stream
+ *	    system error code
+ *	    flag indicating that mailbox may be clobbered
+ * Returns: T if user wants to abort
+ */
+
+long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
+{
+  return T;
+}
+
+
+/* Log a fatal error event
+ * Accepts: string to log
+ */
+
+void mm_fatal (char *string)
+{
+  fprintf (stderr,"FATAL: %s\n",string);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mailutil/makefile.nt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,50 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+
+# Program:	MAILUTIL Makefile for Windows 9x and Windows NT
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		25 February 1996
+# Last Edited:	30 August 2006
+
+
+C = ..\c-client
+CCLIENTLIB = $C\cclient.lib
+LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib
+CFLAGS= -I$C /MT /W3 /DWIN32 /D_WIN32_WINNT=0x0400 -nologo $(EXTRACFLAGS)
+OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
+VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
+CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
+
+mailutil: $(CCLIENTLIB) mailutil.obj
+	LINK /NOLOGO mailutil.obj $(LIBS)
+
+mailutil.obj: $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h mailutil.c
+
+$(CCLIENTLIB):
+	@echo Make c-client first
+	false
+
+clean:
+	del *.obj *.exe *.lib *.exp || rem
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo not war?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mailutil/makefile.ntk	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,51 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+
+# Program:	MAILUTIL Makefile for Windows 9x and Windows NT + Kerberos
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		25 February 1996
+# Last Edited:	30 August 2006
+
+
+C = ..\c-client
+CCLIENTLIB = $C\cclient.lib
+K5 = \k5\lib
+K5LIB = $(K5)\comerr32.lib $(K5)\gssapi32.lib $(K5)\krb5_32.lib
+LIBS = $(CCLIENTLIB) $(K5LIB) ws2_32.lib winmm.lib advapi32.lib
+OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
+VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
+CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
+
+mailutil: $(CCLIENTLIB) mailutil.obj
+	LINK /NOLOGO mailutil.obj $(LIBS)
+
+mailutil.obj: $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h mailutil.c
+
+$(CCLIENTLIB):
+	@echo Make c-client first
+	false
+
+clean:
+	del *.obj *.exe *.lib *.exp || rem
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo not war?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mailutil/makefile.w2k	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,49 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+
+# Program:	MAILUTIL Makefile for Windows 2000/XP
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		25 February 1996
+# Last Edited:	30 August 2006
+
+
+C = ..\c-client
+CCLIENTLIB = $C\cclient.lib
+LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib secur32.lib crypt32.lib
+OSCOMPAT = /DWIN32
+VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
+CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
+
+mailutil: $(CCLIENTLIB) mailutil.obj
+	LINK /NOLOGO mailutil.obj $(LIBS)
+
+mailutil.obj: $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h mailutil.c
+
+$(CCLIENTLIB):
+	@echo Make c-client first
+	false
+
+clean:
+	del *.obj *.exe *.lib *.exp || rem
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo not war?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mlock/Makefile	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,51 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+
+# Program:	MLOCK Makefile
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		8 February 1999
+# Last Edited:	30 August 2006
+
+
+C = ../c-client
+SHELL = /bin/sh
+
+# Get local definitions from c-client directory
+
+CC = `cat $C/CCTYPE`
+CFLAGS = `cat $C/CFLAGS`
+
+all:	mlock
+
+mlock:	mlock.o
+	$(CC) $(CFLAGS) -o mlock mlock.o
+
+install: mlock
+	chgrp mail mlock
+	chmod 3711 mlock
+	cp -p mlock /etc/mlock
+
+clean:
+	rm -f *.o mlock || true
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo 'not war?'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mlock/mlock.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,175 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Standalone Mailbox Lock program
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	8 February 1999
+ * Last Edited:	3 March 2008
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sysexits.h>
+#include <syslog.h>
+#include <grp.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <string.h>
+
+#define LOCKTIMEOUT 5		/* lock timeout in minutes */
+#define LOCKPROTECTION 0664
+
+#ifndef MAXHOSTNAMELEN		/* Solaris still sucks */
+#define MAXHOSTNAMELEN 256
+#endif
+
+/* Fatal error
+ * Accepts: Message string
+ *	    exit code
+ * Returns: code
+ */
+
+int die (char *msg,int code)
+{
+  syslog (LOG_NOTICE,"(%u) %s",code,msg);
+  write (1,"?",1);		/* indicate "impossible" failure */
+  return code;
+}
+
+
+int main (int argc,char *argv[])
+{
+  int ld,i;
+  int tries = LOCKTIMEOUT * 60 - 1;
+  char *s,*dir,*file,*lock,*hitch,tmp[1024];
+  size_t dlen,len;
+  struct stat sb,fsb;
+  struct group *grp = getgrnam ("mail");
+				/* get syslog */
+  openlog (argv[0],LOG_PID,LOG_MAIL);
+  if (!grp || (grp->gr_gid != getegid ()))
+    return die ("not setgid mail",EX_USAGE);
+  if (argc != 3) return die ("invalid arguments",EX_USAGE);
+  for (s = argv[1]; *s; s++)
+    if (!isdigit (*s)) return die ("invalid fd",EX_USAGE);
+				/* find directory */
+  if ((*argv[2] != '/') || !(file = strrchr (argv[2],'/')) || !file[1])
+    return die ("invalid path",EX_USAGE);
+				/* calculate lengths of directory and file */
+  if (!(dlen = file - argv[2])) dlen = 1;
+  len = strlen (++file);
+				/* make buffers */
+  dir = (char *) malloc (dlen + 1);
+  lock = (char *) malloc (len + 6);
+  hitch = (char *) malloc (len + 6 + 40 + MAXHOSTNAMELEN);
+  if (!dir || !lock || !hitch) return die ("malloc failure",errno);
+  strncpy (dir,argv[2],dlen);	/* connect to desired directory */
+  dir[dlen] = '\0';
+  printf ("dir=%s, file=%s\n",dir,file);
+  chdir (dir);
+				/* get device/inode of file descriptor */
+  if (fstat (atoi (argv[1]),&fsb)) return die ("fstat failure",errno);
+				/* better be a regular file */
+  if ((fsb.st_mode & S_IFMT) != S_IFREG)
+    return die ("fd not regular file",EX_USAGE);
+				/* now get device/inode of file */
+  if (lstat (file,&sb)) return die ("lstat failure",errno);
+				/* does it match? */
+  if ((sb.st_mode & S_IFMT) != S_IFREG)
+    return die ("name not regular file",EX_USAGE);
+  if ((sb.st_dev != fsb.st_dev) || (sb.st_ino != fsb.st_ino))
+    return die ("fd and name different",EX_USAGE);
+				/* build lock filename */
+  sprintf (lock,"%s.lock",file);
+  if (!lstat (lock,&sb) && ((sb.st_mode & S_IFMT) != S_IFREG))
+    return die ("existing lock not regular file",EX_NOPERM);
+
+  do {				/* until OK or out of tries */
+    if (!stat (lock,&sb) && (time (0) > (sb.st_ctime + LOCKTIMEOUT * 60)))
+      unlink (lock);		/* time out lock if enough time has passed */
+    /* SUN-OS had an NFS
+     * As kludgy as an albatross;
+     * And everywhere that it was installed,
+     * It was a total loss.
+     * -- MRC 9/25/91
+     */
+				/* build hitching post file name */
+    sprintf (hitch,"%s.%lu.%lu.",lock,(unsigned long) time (0),
+	     (unsigned long) getpid ());
+    len = strlen (hitch);	/* append local host name */
+    gethostname (hitch + len,MAXHOSTNAMELEN);
+				/* try to get hitching-post file */
+    if ((ld = open (hitch,O_WRONLY|O_CREAT|O_EXCL,LOCKPROTECTION)) >= 0) {
+				/* make sure others can break the lock */
+      chmod (hitch,LOCKPROTECTION);
+				/* get device/inode of hitch file */
+      if (fstat (ld,&fsb)) return die ("hitch fstat failure",errno);
+      close (ld);		/* close the hitching-post */
+      /* Note: link() may return an error even if it actually succeeded.  So we
+       * always check for success via the link count, and ignore the error if
+       * the link count is right.
+       */
+				/* tie hitching-post to lock */
+      i = link (hitch,lock) ? errno : 0;
+				/* success if link count now 2 */
+      if (stat (hitch,&sb) || (sb.st_nlink != 2) ||
+	  (fsb.st_dev != sb.st_dev) || (fsb.st_ino != sb.st_ino)) {
+	ld = -1;		/* failed to hitch */
+	if (i == EPERM) {	/* was it because links not allowed? */
+	  /* Probably a FAT filesystem on Linux.  It can't be NFS, so try
+	   * creating the lock file directly.
+	   */
+	  if ((ld = open (lock,O_WRONLY|O_CREAT|O_EXCL,LOCKPROTECTION)) >= 0) {
+	    /* get device/inode of lock file */
+	    if (fstat (ld,&fsb)) return die ("lock fstat failure",errno);
+	    close (ld);		/* close the file */
+	  }
+				/* give up immediately if protection failure */
+	  else if (errno != EEXIST) tries = 0;
+	}
+      }
+      unlink (hitch);		/* flush hitching post */
+    }
+				/* give up immediately if protection failure */
+    else if (errno == EACCES) tries = 0;
+    if (ld < 0) {		/* lock failed */
+      if (tries--) sleep (1);	/* sleep 1 second and try again */
+      else {
+	write (1,"-",1);	/* hard failure */
+	return EX_CANTCREAT;
+      }
+    }
+  } while (ld < 0);
+  write (1,"+",1);		/* indicate that all is well */
+  read (0,tmp,1);		/* read continue signal from parent */
+				/* flush the lock file */
+  if (!stat (lock,&sb) && (fsb.st_dev == sb.st_dev) &&
+      (fsb.st_ino == sb.st_ino)) unlink (lock);
+  else syslog (LOG_NOTICE,"lock file %s/%s changed dev/inode",dir,lock);
+  return EX_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mtest/Makefile	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,53 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+
+# Program:	MTEST Makefile
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		25 February 1996
+# Last Edited:	30 August 2006
+
+
+C = ../c-client
+CCLIENTLIB = $C/c-client.a
+SHELL = /bin/sh
+
+# Get local definitions from c-client directory
+
+CC = `cat $C/CCTYPE`
+CFLAGS = -I$C `cat $C/CFLAGS`
+LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS`
+
+all:	mtest
+
+mtest: $(CCLIENTLIB) mtest.o
+	$(CC) $(CFLAGS) -o mtest mtest.o $(LDFLAGS)
+
+mtest.o: $C/mail.h $C/misc.h $C/osdep.h $C/rfc822.h $C/smtp.h $C/nntp.h
+
+$(CCLIENTLIB):
+	cd $C;make
+
+clean:
+	rm -f *.o mtest || true
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo 'not war?'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mtest/makefile.nt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,49 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+
+# Program:	MTEST Makefile for Windows 9x and Windows NT
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		25 February 1996
+# Last Edited:	30 August 2006
+
+
+C = ..\c-client
+CCLIENTLIB = $C\cclient.lib
+LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib
+OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
+VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
+CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
+
+mtest: $(CCLIENTLIB) mtest.obj
+	LINK /NOLOGO mtest.obj $(LIBS)
+
+mtest.obj: $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h mtest.c
+
+$(CCLIENTLIB):
+	@echo Make c-client first
+	false
+
+clean:
+	del *.obj *.exe *.lib *.exp || rem
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo not war?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mtest/makefile.ntk	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,51 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+
+# Program:	MTEST Makefile for Windows 9x and Windows NT + Kerberos
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		25 February 1996
+# Last Edited:	30 August 2006
+
+
+C = ..\c-client
+CCLIENTLIB = $C\cclient.lib
+K5 = \k5\lib
+K5LIB = $(K5)\comerr32.lib $(K5)\gssapi32.lib $(K5)\krb5_32.lib
+LIBS = $(CCLIENTLIB) $(K5LIB) ws2_32.lib winmm.lib advapi32.lib
+OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
+VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
+CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
+
+mtest: $(CCLIENTLIB) mtest.obj
+	LINK /NOLOGO mtest.obj $(LIBS)
+
+mtest.obj: $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h mtest.c
+
+$(CCLIENTLIB):
+	@echo Make c-client first
+	false
+
+clean:
+	del *.obj *.exe *.lib *.exp || rem
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo not war?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mtest/makefile.os2	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,53 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+
+# Program:	MTEST Makefile
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		25 February 1996
+# Last Edited:	30 August 2006
+
+# Thanks to Nicholas Paul Sheppard who contributed the original version
+
+CC = gcc
+CFLAGS = -O2 -Zomf
+LD = gcc
+LDFLAGS = -s -Zomf -Zcrtdll
+
+C = ..\c-client
+CCLIENTLIB = $C\\c-client.lib
+LIBS = $(CCLIENTLIB) -l socket
+
+mtest.exe: $(CCLIENTLIB) mtest.obj
+	$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+$(CCLIENTLIB):
+	@echo Make c-client first
+	false
+
+mtest.obj: mtest.c $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h
+	$(CC) $(CFLAGS) -I$C -o $@ -c $<
+
+clean:
+	if exist *.obj del *.obj
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo not war?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mtest/makefile.w2k	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,49 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+
+# Program:	MTEST Makefile for Windows 2000/XP
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		25 February 1996
+# Last Edited:	30 August 2006
+
+
+C = ..\c-client
+CCLIENTLIB = $C\cclient.lib
+LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib secur32.lib crypt32.lib
+OSCOMPAT = /DWIN32
+VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
+CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
+
+mtest: $(CCLIENTLIB) mtest.obj
+	LINK /NOLOGO mtest.obj $(LIBS)
+
+mtest.obj: $C\mail.h $C\smtp.h $C\misc.h $C\osdep.h mtest.c
+
+$(CCLIENTLIB):
+	@echo Make c-client first
+	false
+
+clean:
+	del *.obj *.exe *.lib *.exp || rem
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo not war?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mtest/mtest.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,813 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Mail library test program
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	8 July 1988
+ * Last Edited:	5 November 2007
+ *
+ * This original version of this file is
+ * Copyright 1988 Stanford University
+ * and was developed in the Symbolic Systems Resources Group of the Knowledge
+ * Systems Laboratory at Stanford University in 1987-88, and was funded by the
+ * Biomedical Research Technology Program of the NationalInstitutes of Health
+ * under grant number RR-00785.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <signal.h>
+#include "c-client.h"
+#include "imap4r1.h"
+
+/* Excellent reasons to hate ifdefs, and why my real code never uses them */
+
+#ifndef unix
+# define unix 0
+#endif
+
+#if unix
+# define UNIXLIKE 1
+# define MACOS 0
+# include <pwd.h>
+#else
+# define UNIXLIKE 0
+# ifdef noErr
+#  define MACOS 1
+#  include <Memory.h>
+# else
+#  define MACOS 0
+# endif
+#endif
+
+char *curhst = NIL;		/* currently connected host */
+char *curusr = NIL;		/* current login user */
+char personalname[MAILTMPLEN];	/* user's personal name */
+
+static char *hostlist[] = {	/* SMTP server host list */
+  "mailhost",
+  "localhost",
+  NIL
+};
+
+static char *newslist[] = {	/* Netnews server host list */
+  "news",
+  NIL
+};
+
+int main (void);
+void mm (MAILSTREAM *stream,long debug);
+void overview_header (MAILSTREAM *stream,unsigned long uid,OVERVIEW *ov,
+		      unsigned long msgno);
+void header (MAILSTREAM *stream,long msgno);
+void display_body (BODY *body,char *pfx,long i);
+void status (MAILSTREAM *stream);
+void prompt (char *msg,char *txt);
+void smtptest (long debug);
+
+/* Main program - initialization */
+
+int main ()
+{
+  MAILSTREAM *stream = NIL;
+  void *sdb = NIL;
+  char *s,tmp[MAILTMPLEN];
+  long debug;
+#include "linkage.c"
+#if MACOS
+  {
+    size_t *base = (size_t *) 0x000908;
+				/* increase stack size on a Mac */
+    SetApplLimit ((Ptr) (*base - (size_t) 65535L));
+  }
+#endif
+  curusr = cpystr (((s = myusername ()) && *s) ? s : "somebody");
+#if UNIXLIKE
+  {
+    char *suffix;
+    struct passwd *pwd = getpwnam (curusr);
+    if (pwd) {
+      strcpy (tmp,pwd->pw_gecos);
+				/* dyke out the office and phone poop */
+      if (suffix = strchr (tmp,',')) suffix[0] = '\0';
+      strcpy (personalname,tmp);/* make a permanent copy of it */
+    }
+    else personalname[0] = '\0';
+  }
+#else
+  personalname[0] = '\0';
+#endif
+  curhst = cpystr (mylocalhost ());
+  puts ("MTest -- C client test program");
+  if (!*personalname) prompt ("Personal name: ",personalname);
+				/* user wants protocol telemetry? */
+  prompt ("Debug protocol (y/n)?",tmp);
+  ucase (tmp);
+  debug = (tmp[0] == 'Y') ? T : NIL;
+  do {
+    prompt ("Mailbox ('?' for help): ",tmp);
+    if (!strcmp (tmp,"?")) {
+      puts ("Enter INBOX, mailbox name, or IMAP mailbox as {host}mailbox");
+      puts ("Known local mailboxes:");
+      mail_list (NIL,NIL,"%");
+      if (s = sm_read (&sdb)) {
+	puts ("Local subscribed mailboxes:");
+	do (mm_lsub (NIL,NIL,s,NIL));
+	while (s = sm_read (&sdb));
+      }
+      puts ("or just hit return to quit");
+    }
+    else if (tmp[0]) stream = mail_open (stream,tmp,debug ? OP_DEBUG : NIL);
+  } while (!stream && tmp[0]);
+  mm (stream,debug);		/* run user interface if opened */
+#if MACOS
+				/* clean up resolver */
+  if (resolveropen) CloseResolver ();
+#endif
+  return NIL;
+}
+
+/* MM command loop
+ * Accepts: MAIL stream
+ */
+
+void mm (MAILSTREAM *stream,long debug)
+{
+  void *sdb = NIL;
+  char cmd[MAILTMPLEN];
+  char *s,*arg;
+  unsigned long i;
+  unsigned long last = 0;
+  BODY *body;
+  status (stream);		/* first report message status */
+  while (stream) {
+    prompt ("MTest>",cmd);	/* prompt user, get command */
+				/* get argument */
+    if (arg = strchr (cmd,' ')) *arg++ = '\0';
+    switch (*ucase (cmd)) {	/* dispatch based on command */
+    case 'B':			/* Body command */
+      if (arg) last = atoi (arg);
+      else if (!last) {
+	puts ("?Missing message number");
+	break;
+      }
+      if (last && (last <= stream->nmsgs)) {
+	mail_fetchstructure (stream,last,&body);
+	if (body) display_body (body,NIL,(long) 0);
+	else puts ("%No body information available");
+      }
+      else puts ("?Bad message number");
+      break;
+    case 'C':			/* Check command */
+      mail_check (stream);
+      status (stream);
+      break;
+    case 'D':			/* Delete command */
+      if (arg) last = atoi (arg);
+      else {
+	if (last == 0) {
+	  puts ("?Missing message number");
+	  break;
+	}
+	arg = cmd;
+	sprintf (arg,"%lu",last);
+      }
+      if (last && (last <= stream->nmsgs))
+	mail_setflag (stream,arg,"\\DELETED");
+      else puts ("?Bad message number");
+      break;
+    case 'E':			/* Expunge command */
+      mail_expunge (stream);
+      last = 0;
+      break;
+    case 'F':			/* Find command */
+      if (!arg) {
+	arg = "%";
+	if (s = sm_read (&sdb)) {
+	  puts ("Local network subscribed mailboxes:");
+	  do if (*s == '{') (mm_lsub (NIL,NIL,s,NIL));
+	  while (s = sm_read (&sdb));
+	}
+      }
+      puts ("Subscribed mailboxes:");
+      mail_lsub (((arg[0] == '{') && (*stream->mailbox == '{')) ? stream : NIL,
+		 NIL,arg);
+      puts ("Known mailboxes:");
+      mail_list (((arg[0] == '{') && (*stream->mailbox == '{')) ? stream : NIL,
+		 NIL,arg);
+      break;
+    case 'G':
+      mail_gc (stream,GC_ENV|GC_TEXTS|GC_ELT);
+      break;
+    case 'H':			/* Headers command */
+      if (arg) {
+	if (!(last = atoi (arg))) {
+	  mail_search (stream,arg);
+	  for (i = 1; i <= stream->nmsgs; ++i)
+	    if (mail_elt (stream,i)->searched) header (stream,i);
+	  break;
+	}
+      }
+      else if (last == 0) {
+	puts ("?Missing message number");
+	break;
+      }
+      if (last && (last <= stream->nmsgs)) header (stream,last);
+      else puts ("?Bad message number");
+      break;
+    case 'L':			/* Literal command */
+      if (arg) last = atoi (arg);
+      else if (!last) {
+	puts ("?Missing message number");
+	break;
+      }
+      if (last && (last <= stream->nmsgs))
+	puts (mail_fetch_message (stream,last,NIL,NIL));
+      else puts ("?Bad message number");
+      break;
+    case 'M':
+      mail_status (NIL,arg ? arg : stream->mailbox,
+		   SA_MESSAGES|SA_RECENT|SA_UNSEEN|SA_UIDNEXT|SA_UIDVALIDITY);
+      break;
+    case 'N':			/* New mailbox command */
+      if (!arg) {
+	puts ("?Missing mailbox");
+	break;
+      }
+				/* get the new mailbox */
+      while (!(stream = mail_open (stream,arg,debug))) {
+	prompt ("Mailbox: ",arg);
+	if (!arg[0]) break;
+      }
+      last = 0;
+      status (stream);
+      break;
+    case 'O':			/* Overview command */
+      if (!arg) {
+	puts ("?Missing UID");
+	break;
+      }
+      mail_fetch_overview (stream,arg,overview_header);
+      break;
+    case 'P':			/* Ping command */
+      mail_ping (stream);
+      status (stream);
+      break;
+    case 'Q':			/* Quit command */
+      mail_close (stream);
+      stream = NIL;
+      break;
+    case 'S':			/* Send command */
+      smtptest (debug);
+      break;
+    case '\0':			/* null command (type next message) */
+      if (!last || (last++ >= stream->nmsgs)) {
+	puts ("%No next message");
+	break;
+      }
+    case 'T':			/* Type command */
+      if (arg) last = atoi (arg);
+      else if (!last) {
+	puts ("?Missing message number");
+	break;
+      }
+      if (last && (last <= stream->nmsgs)) {
+	STRINGLIST *lines = mail_newstringlist ();
+	STRINGLIST *cur = lines;
+	cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
+					   cpystr ("Date")));
+	cur = cur->next = mail_newstringlist ();
+	cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
+					   cpystr ("From")));
+	cur = cur->next = mail_newstringlist ();
+	cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
+					   cpystr (">From")));
+	cur = cur->next = mail_newstringlist ();
+	cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
+					   cpystr ("Subject")));
+	cur = cur->next = mail_newstringlist ();
+	cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
+					   cpystr ("To")));
+	cur = cur->next = mail_newstringlist ();
+	cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
+					   cpystr ("cc")));
+	cur = cur->next = mail_newstringlist ();
+	cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
+					   cpystr ("Newsgroups")));
+	printf ("%s",mail_fetchheader_full (stream,last,lines,NIL,NIL));
+	puts (mail_fetchtext (stream,last));
+	mail_free_stringlist (&lines);
+      }
+      else puts ("?Bad message number");
+      break;
+    case 'U':			/* Undelete command */
+      if (arg) last = atoi (arg);
+      else {
+	if (!last) {
+	  puts ("?Missing message number");
+	  break;
+	}
+	arg = cmd;
+	sprintf (arg,"%lu",last);
+      }
+      if (last > 0 && last <= stream->nmsgs)
+	mail_clearflag (stream,arg,"\\DELETED");
+      else puts ("?Bad message number");
+      break;
+    case 'X':			/* Xit command */
+      mail_expunge (stream);
+      mail_close (stream);
+      stream = NIL;
+      break;
+    case '+':
+      mail_debug (stream); debug = T;
+      break;
+    case '-':
+      mail_nodebug (stream); debug = NIL;
+      break;
+    case '?':			/* ? command */
+      puts ("Body, Check, Delete, Expunge, Find, GC, Headers, Literal,");
+      puts (" MailboxStatus, New Mailbox, Overview, Ping, Quit, Send, Type,");
+      puts ("Undelete, Xit, +, -, or <RETURN> for next message");
+      break;
+    default:			/* bogus command */
+      printf ("?Unrecognized command: %s\n",cmd);
+      break;
+    }
+  }
+}
+
+/* MM display header
+ * Accepts: IMAP2 stream
+ *	    message number
+ */
+
+void overview_header (MAILSTREAM *stream,unsigned long uid,OVERVIEW *ov,
+		      unsigned long msgno)
+{
+  if (ov) {
+    unsigned long i;
+    char *t,tmp[MAILTMPLEN];
+    ADDRESS *adr;
+    MESSAGECACHE *elt = mail_elt (stream,msgno);
+    MESSAGECACHE selt;
+    tmp[0] = elt->recent ? (elt->seen ? 'R': 'N') : ' ';
+    tmp[1] = (elt->recent | elt->seen) ? ' ' : 'U';
+    tmp[2] = elt->flagged ? 'F' : ' ';
+    tmp[3] = elt->answered ? 'A' : ' ';
+    tmp[4] = elt->deleted ? 'D' : ' ';
+    mail_parse_date (&selt,ov->date);
+    sprintf (tmp+5,"%4lu) ",elt->msgno);
+    mail_date (tmp+11,&selt);
+    tmp[17] = ' ';
+    tmp[18] = '\0';
+    memset (tmp+18,' ',(size_t) 20);
+    tmp[38] = '\0';		/* tie off with null */
+				/* get first from address from envelope */
+    for (adr = ov->from; adr && !adr->host; adr = adr->next);
+    if (adr) {			/* if a personal name exists use it */
+      if (!(t = adr->personal))
+	sprintf (t = tmp+400,"%s@%s",adr->mailbox,adr->host);
+      memcpy (tmp+18,t,(size_t) min (20,(long) strlen (t)));
+    }
+    strcat (tmp," ");
+    if (i = elt->user_flags) {
+      strcat (tmp,"{");
+      while (i) {
+	strcat (tmp,stream->user_flags[find_rightmost_bit (&i)]);
+	if (i) strcat (tmp," ");
+      }
+      strcat (tmp,"} ");
+    }
+    sprintf (tmp + strlen (tmp),"%.25s (%lu chars)",
+	     ov->subject ? ov->subject : " ",ov->optional.octets);
+    puts (tmp);
+  }
+  else printf ("%%No overview for UID %lu\n",uid);
+}
+
+/* MM display header
+ * Accepts: IMAP2 stream
+ *	    message number
+ */
+
+void header (MAILSTREAM *stream,long msgno)
+{
+  unsigned long i;
+  char tmp[MAILTMPLEN];
+  char *t;
+  MESSAGECACHE *cache = mail_elt (stream,msgno);
+  mail_fetchstructure (stream,msgno,NIL);
+  tmp[0] = cache->recent ? (cache->seen ? 'R': 'N') : ' ';
+  tmp[1] = (cache->recent | cache->seen) ? ' ' : 'U';
+  tmp[2] = cache->flagged ? 'F' : ' ';
+  tmp[3] = cache->answered ? 'A' : ' ';
+  tmp[4] = cache->deleted ? 'D' : ' ';
+  sprintf (tmp+5,"%4lu) ",cache->msgno);
+  mail_date (tmp+11,cache);
+  tmp[17] = ' ';
+  tmp[18] = '\0';
+  mail_fetchfrom (tmp+18,stream,msgno,(long) 20);
+  strcat (tmp," ");
+  if (i = cache->user_flags) {
+    strcat (tmp,"{");
+    while (i) {
+      strcat (tmp,stream->user_flags[find_rightmost_bit (&i)]);
+      if (i) strcat (tmp," ");
+    }
+    strcat (tmp,"} ");
+  }
+  mail_fetchsubject (t = tmp + strlen (tmp),stream,msgno,(long) 25);
+  sprintf (t += strlen (t)," (%lu chars)",cache->rfc822_size);
+  puts (tmp);
+}
+
+/* MM display body
+ * Accepts: BODY structure pointer
+ *	    prefix string
+ *	    index
+ */
+
+void display_body (BODY *body,char *pfx,long i)
+{
+  char tmp[MAILTMPLEN];
+  char *s = tmp;
+  PARAMETER *par;
+  PART *part;			/* multipart doesn't have a row to itself */
+  if (body->type == TYPEMULTIPART) {
+				/* if not first time, extend prefix */
+    if (pfx) sprintf (tmp,"%s%ld.",pfx,++i);
+    else tmp[0] = '\0';
+    for (i = 0,part = body->nested.part; part; part = part->next)
+      display_body (&part->body,tmp,i++);
+  }
+  else {			/* non-multipart, output oneline descriptor */
+    if (!pfx) pfx = "";		/* dummy prefix if top level */
+    sprintf (s," %s%ld %s",pfx,++i,body_types[body->type]);
+    if (body->subtype) sprintf (s += strlen (s),"/%s",body->subtype);
+    if (body->description) sprintf (s += strlen (s)," (%s)",body->description);
+    if (par = body->parameter) do
+      sprintf (s += strlen (s),";%s=%s",par->attribute,par->value);
+    while (par = par->next);
+    if (body->id) sprintf (s += strlen (s),", id = %s",body->id);
+    switch (body->type) {	/* bytes or lines depending upon body type */
+    case TYPEMESSAGE:		/* encapsulated message */
+    case TYPETEXT:		/* plain text */
+      sprintf (s += strlen (s)," (%lu lines)",body->size.lines);
+      break;
+    default:
+      sprintf (s += strlen (s)," (%lu bytes)",body->size.bytes);
+      break;
+    }
+    puts (tmp);			/* output this line */
+				/* encapsulated message? */
+    if ((body->type == TYPEMESSAGE) && !strcmp (body->subtype,"RFC822") &&
+	(body = body->nested.msg->body)) {
+      if (body->type == TYPEMULTIPART) display_body (body,pfx,i-1);
+      else {			/* build encapsulation prefix */
+	sprintf (tmp,"%s%ld.",pfx,i);
+	display_body (body,tmp,(long) 0);
+      }
+    }
+  }
+}
+
+/* MM status report
+ * Accepts: MAIL stream
+ */
+
+void status (MAILSTREAM *stream)
+{
+  unsigned long i;
+  char *s,date[MAILTMPLEN];
+  THREADER *thr;
+  AUTHENTICATOR *auth;
+  rfc822_date (date);
+  puts (date);
+  if (stream) {
+    if (stream->mailbox)
+      printf (" %s mailbox: %s, %lu messages, %lu recent\n",
+	      stream->dtb->name,stream->mailbox,stream->nmsgs,stream->recent);
+    else puts ("%No mailbox is open on this stream");
+    if (stream->user_flags[0]) {
+      printf ("Keywords: %s",stream->user_flags[0]);
+      for (i = 1; i < NUSERFLAGS && stream->user_flags[i]; ++i)
+	printf (", %s",stream->user_flags[i]);
+      puts ("");
+    }
+    if (!strcmp (stream->dtb->name,"imap")) {
+      if (LEVELIMAP4rev1 (stream)) s = "IMAP4rev1 (RFC 3501)";
+      else if (LEVEL1730 (stream)) s = "IMAP4 (RFC 1730)";
+      else if (LEVELIMAP2bis (stream)) s = "IMAP2bis";
+      else if (LEVEL1176 (stream)) s = "IMAP2 (RFC 1176)";
+      else s = "IMAP2 (RFC 1064)";
+      printf ("%s server %s\n",s,imap_host (stream));
+      if (LEVELIMAP4 (stream)) {
+	if (i = imap_cap (stream)->auth) {
+	  s = "";
+	  printf ("Mutually-supported SASL mechanisms:");
+	  while (auth = mail_lookup_auth (find_rightmost_bit (&i) + 1)) {
+	    printf (" %s",auth->name);
+	    if (!strcmp (auth->name,"PLAIN"))
+	      s = "\n  [LOGIN will not be listed here if PLAIN is supported]";
+	  }
+	  puts (s);
+	}
+	printf ("Supported standard extensions:\n");
+	if (LEVELACL (stream)) puts (" Access Control lists (RFC 2086)");
+	if (LEVELQUOTA (stream)) puts (" Quotas (RFC 2087)");
+	if (LEVELLITERALPLUS (stream))
+	  puts (" Non-synchronizing literals (RFC 2088)");
+	if (LEVELIDLE (stream)) puts (" IDLE unsolicited update (RFC 2177)");
+	if (LEVELMBX_REF (stream)) puts (" Mailbox referrals (RFC 2193)");
+	if (LEVELLOG_REF (stream)) puts (" Login referrals (RFC 2221)");
+	if (LEVELANONYMOUS (stream)) puts (" Anonymous access (RFC 2245)");
+	if (LEVELNAMESPACE (stream)) puts (" Multiple namespaces (RFC 2342)");
+	if (LEVELUIDPLUS (stream)) puts (" Extended UID behavior (RFC 2359)");
+	if (LEVELSTARTTLS (stream))
+	  puts (" Transport Layer Security (RFC 2595)");
+	if (LEVELLOGINDISABLED (stream))
+	  puts (" LOGIN command disabled (RFC 2595)");
+	if (LEVELID (stream))
+	  puts (" Implementation identity negotiation (RFC 2971)");
+	if (LEVELCHILDREN (stream))
+	  puts (" LIST children announcement (RFC 3348)");
+	if (LEVELMULTIAPPEND (stream))
+	  puts (" Atomic multiple APPEND (RFC 3502)");
+	if (LEVELBINARY (stream))
+	  puts (" Binary body content (RFC 3516)");
+	if (LEVELUNSELECT (stream)) puts (" Mailbox unselect (RFC 3691)");
+	if (LEVELURLAUTH (stream))
+	  puts (" URL authenticated fetch (RFC 4467)");
+	if (LEVELCATENATE (stream)) puts (" Catenation (RFC 4469)");
+	if (LEVELCONDSTORE (stream)) puts (" Conditional STORE (RFC 4551)");
+	if (LEVELESEARCH (stream)) puts (" Extended SEARCH (RFC 4731)");
+	puts ("Supported draft extensions:");
+	if (LEVELSASLIR (stream)) puts (" SASL initial client response");
+	if (LEVELSORT (stream)) puts (" Server-based sorting");
+	if (LEVELTHREAD (stream)) {
+	  printf (" Server-based threading:");
+	  for (thr = imap_cap (stream)->threader; thr; thr = thr->next)
+	    printf (" %s",thr->name);
+	  putchar ('\n');
+	}
+	if (LEVELSCAN (stream)) puts (" Mailbox text scan");
+	if (i = imap_cap (stream)->extlevel) {
+	  printf ("Supported BODYSTRUCTURE extensions:");
+	  switch (i) {
+	  case BODYEXTLOC: printf (" location");
+	  case BODYEXTLANG: printf (" language");
+	  case BODYEXTDSP: printf (" disposition");
+	  case BODYEXTMD5: printf (" MD5\n");
+	  }
+	}
+      }
+      else putchar ('\n');
+    }
+  }
+}
+
+
+/* Prompt user for input
+ * Accepts: pointer to prompt message
+ *          pointer to input buffer
+ */
+
+void prompt (char *msg,char *txt)
+{
+  printf ("%s",msg);
+  gets (txt);
+}
+
+/* Interfaces to C-client */
+
+
+void mm_searched (MAILSTREAM *stream,unsigned long number)
+{
+}
+
+
+void mm_exists (MAILSTREAM *stream,unsigned long number)
+{
+}
+
+
+void mm_expunged (MAILSTREAM *stream,unsigned long number)
+{
+}
+
+
+void mm_flags (MAILSTREAM *stream,unsigned long number)
+{
+}
+
+
+void mm_notify (MAILSTREAM *stream,char *string,long errflg)
+{
+  mm_log (string,errflg);
+}
+
+
+void mm_list (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
+{
+  putchar (' ');
+  if (delimiter) putchar (delimiter);
+  else fputs ("NIL",stdout);
+  putchar (' ');
+  fputs (mailbox,stdout);
+  if (attributes & LATT_NOINFERIORS) fputs (", no inferiors",stdout);
+  if (attributes & LATT_NOSELECT) fputs (", no select",stdout);
+  if (attributes & LATT_MARKED) fputs (", marked",stdout);
+  if (attributes & LATT_UNMARKED) fputs (", unmarked",stdout);
+  putchar ('\n');
+}
+
+
+void mm_lsub (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
+{
+  putchar (' ');
+  if (delimiter) putchar (delimiter);
+  else fputs ("NIL",stdout);
+  putchar (' ');
+  fputs (mailbox,stdout);
+  if (attributes & LATT_NOINFERIORS) fputs (", no inferiors",stdout);
+  if (attributes & LATT_NOSELECT) fputs (", no select",stdout);
+  if (attributes & LATT_MARKED) fputs (", marked",stdout);
+  if (attributes & LATT_UNMARKED) fputs (", unmarked",stdout);
+  putchar ('\n');
+}
+
+
+void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
+{
+  printf (" Mailbox %s",mailbox);
+  if (status->flags & SA_MESSAGES) printf (", %lu messages",status->messages);
+  if (status->flags & SA_RECENT) printf (", %lu recent",status->recent);
+  if (status->flags & SA_UNSEEN) printf (", %lu unseen",status->unseen);
+  if (status->flags & SA_UIDVALIDITY) printf (", %lu UID validity",
+					      status->uidvalidity);
+  if (status->flags & SA_UIDNEXT) printf (", %lu next UID",status->uidnext);
+  printf ("\n");
+}
+
+
+void mm_log (char *string,long errflg)
+{
+  switch ((short) errflg) {
+  case NIL:
+    printf ("[%s]\n",string);
+    break;
+  case PARSE:
+  case WARN:
+    printf ("%%%s\n",string);
+    break;
+  case ERROR:
+    printf ("?%s\n",string);
+    break;
+  }
+}
+
+
+void mm_dlog (char *string)
+{
+  puts (string);
+}
+
+
+void mm_login (NETMBX *mb,char *user,char *pwd,long trial)
+{
+  char *s,tmp[MAILTMPLEN];
+  if (curhst) fs_give ((void **) &curhst);
+  curhst = (char *) fs_get (1+strlen (mb->host));
+  strcpy (curhst,mb->host);
+  sprintf (s = tmp,"{%s/%s",mb->host,mb->service);
+  if (*mb->user) sprintf (tmp+strlen (tmp),"/user=%s",strcpy (user,mb->user));
+  if (*mb->authuser) sprintf (tmp+strlen (tmp),"/authuser=%s",mb->authuser);
+  if (*mb->user) strcat (s = tmp,"} password:");
+  else {
+    printf ("%s} username: ",tmp);
+    fgets (user,NETMAXUSER-1,stdin);
+    user[NETMAXUSER-1] = '\0';
+    if (s = strchr (user,'\n')) *s = '\0';
+    s = "password: ";
+  }
+  if (curusr) fs_give ((void **) &curusr);
+  curusr = cpystr (user);
+  strcpy (pwd,getpass (s));
+}
+
+
+void mm_critical (MAILSTREAM *stream)
+{
+}
+
+
+void mm_nocritical (MAILSTREAM *stream)
+{
+}
+
+
+long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
+{
+#if UNIXLIKE
+  kill (getpid (),SIGSTOP);
+#else
+  abort ();
+#endif
+  return NIL;
+}
+
+
+void mm_fatal (char *string)
+{
+  printf ("?%s\n",string);
+}
+
+/* SMTP tester */
+
+void smtptest (long debug)
+{
+  SENDSTREAM *stream = NIL;
+  char line[MAILTMPLEN];
+  char *text = (char *) fs_get (8*MAILTMPLEN);
+  ENVELOPE *msg = mail_newenvelope ();
+  BODY *body = mail_newbody ();
+  msg->from = mail_newaddr ();
+  msg->from->personal = cpystr (personalname);
+  msg->from->mailbox = cpystr (curusr);
+  msg->from->host = cpystr (curhst);
+  msg->return_path = mail_newaddr ();
+  msg->return_path->mailbox = cpystr (curusr);
+  msg->return_path->host = cpystr (curhst);
+  prompt ("To: ",line);
+  rfc822_parse_adrlist (&msg->to,line,curhst);
+  if (msg->to) {
+    prompt ("cc: ",line);
+    rfc822_parse_adrlist (&msg->cc,line,curhst);
+  }
+  else {
+    prompt ("Newsgroups: ",line);
+    if (*line) msg->newsgroups = cpystr (line);
+    else {
+      mail_free_body (&body);
+      mail_free_envelope (&msg);
+      fs_give ((void **) &text);
+      return;
+    }
+  }
+  prompt ("Subject: ",line);
+  msg->subject = cpystr (line);
+  puts (" Msg (end with a line with only a '.'):");
+  body->type = TYPETEXT;
+  *text = '\0';
+  while (gets (line)) {
+    if (line[0] == '.') {
+      if (line[1] == '\0') break;
+      else strcat (text,".");
+    }
+    strcat (text,line);
+    strcat (text,"\015\012");
+  }
+  body->contents.text.data = (unsigned char *) text;
+  body->contents.text.size = strlen (text);
+  rfc822_date (line);
+  msg->date = (char *) fs_get (1+strlen (line));
+  strcpy (msg->date,line);
+  if (msg->to) {
+    puts ("Sending...");
+    if (stream = smtp_open (hostlist,debug)) {
+      if (smtp_mail (stream,"MAIL",msg,body)) puts ("[Ok]");
+      else printf ("[Failed - %s]\n",stream->reply);
+    }
+  }
+  else {
+    puts ("Posting...");
+    if (stream = nntp_open (newslist,debug)) {
+      if (nntp_mail (stream,msg,body)) puts ("[Ok]");
+      else printf ("[Failed - %s]\n",stream->reply);
+    }
+  }
+  if (stream) smtp_close (stream);
+  else puts ("[Can't open connection to any server]");
+  mail_free_envelope (&msg);
+  mail_free_body (&body);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/Makefile	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,231 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+
+# Program:	C client makefile for Amiga
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		11 May 1989
+# Last Edited:	5 November 2006
+
+
+# Command line build parameters
+
+EXTRAAUTHENTICATORS=
+EXTRADRIVERS=mbox
+PASSWDTYPE=std
+
+
+# Build parameters normally set by the individual port
+
+AMICFLAGS=-O -DNO_INLINE_STDARG -Dunix
+AMILDFLAGS=/pine/libc.a -lamiga -lauto
+CHECKPW=std
+LOGINPW=std
+ACTIVEFILE=/UULib/News/Active
+SPOOLDIR=/usr/spool
+MAILSPOOL=/AmiTCP/Mail
+NEWSSPOOL=/UUNews
+MD5PWD="/etc/cram-md5.pwd"
+
+
+# Default formats for creating new mailboxes and for empty mailboxes in the
+# default namespace; must be set to the associated driver's prototype.
+#
+# The CREATEPROTO is the default format for new mailbox creation.
+# The EMPTYPROTO is the default format for handling zero-byte files.
+#
+# Normally, this is set by the individual port.
+#
+# NOTE: namespace formats (e.g. mh and news) can not be set as a default format
+# since they do not exist in the default namespace.  Also, it is meaningless to
+# set certain other formats (e.g. mbx, mx, and mix) as the EMPTYPROTO since
+# these formats can never be empty files.
+
+CREATEPROTO=unixproto
+EMPTYPROTO=unixproto
+
+
+# Commands possibly overriden by the individual port
+
+ARRC=ar rc
+CC=cc
+LN=cp
+RANLIB=ranlib
+RM=rm -f
+
+
+# Standard distribution build parameters
+
+DEFAULTAUTHENTICATORS=ext md5 pla log
+DEFAULTDRIVERS=imap nntp pop3 mix mx mbx tenex mtx mh mmdf unix news phile
+CHUNKSIZE=65536
+
+
+# Normally no need to change any of these
+
+ARCHIVE=c-client.a
+BINARIES=mail.o misc.o newsrc.o smanager.o osdep.o utf8.o utf8aux.o \
+ dummy.o pseudo.o netmsg.o flstring.o fdstring.o \
+ rfc822.o nntp.o smtp.o imap4r1.o pop3.o \
+ unix.o mbx.o mmdf.o tenex.o mtx.o news.o phile.o mh.o mx.o mix.o
+CFLAGS=$(BASECFLAGS) $(EXTRACFLAGS)
+MAKE=make
+MV=mv
+SHELL=/bin/sh
+
+
+# Primary build command
+
+BUILDOPTIONS= EXTRACFLAGS=$(EXTRACFLAGS) EXTRALDFLAGS=$(EXTRALDFLAGS)\
+ EXTRADRIVERS=$(EXTRADRIVERS) EXTRAAUTHENTICATORS=$(EXTRAAUTHENTICATORS)\
+ PASSWDTYPE=$(PASSWDTYPE)
+BUILD=$(MAKE) build $(BUILDOPTIONS) $(SPECIALS)
+
+
+# Here if no make argument established
+
+missing: osdep.h
+	$(MAKE) $(ARCHIVE) CC=`cat CCTYPE` CFLAGS="`cat CFLAGS`"
+
+osdep.h:
+	@echo You must specify what type of system
+	@false
+
+
+# Current ports
+
+ami:	# AmigaDOS
+	$(BUILD) OS=$@ \
+	 BASECFLAGS="-DOLD $(AMICFLAGS)" \
+	 BASELDFLAGS="$(AMILDFLAGS) -lamitcp000" \
+	 CC=gcc
+
+am2:	# AmigaDOS with a 68020+
+	$(BUILD) OS=ami \
+	 BASECFLAGS="-DOLD -m68020 $(AMICFLAGS)" \
+	 BASELDFLAGS="$(AMILDFLAGS) -lamitcp" \
+	 CC=gcc
+
+amn:	# AmigaDOS with a 680x0 using "new" socket library
+	$(BUILD) OS=ami \
+	 BASELDFLAGS="$(AMILDFLAGS) -lnewamitcp000" \
+	 CC=gcc
+
+ama:	# AmigaDOS using AS225R2
+	$(BUILD) OS=ami \
+	 MAILSPOOL=/INet/Mail \
+	 BASECFLAGS="-m68020 $(AMICFLAGS)" \
+	 BASELDFLAGS="$(AMILDFLAGS) -las225r2" \
+	 CC=gcc
+
+# Build it!
+
+build:	clean once ckp$(PASSWDTYPE) $(EXTRAAUTHENTICATORS) $(ARCHIVE)
+
+$(ARCHIVE): $(BINARIES)
+	$(RM) $(ARCHIVE) || true
+	$(ARRC) $(ARCHIVE) $(BINARIES)
+	$(RANLIB) $(ARCHIVE)
+
+# Cleanup
+
+clean:
+	$(RM) *.o linkage.[ch] auths.c $(ARCHIVE) osdep.* *TYPE *FLAGS || true
+
+
+# Dependencies
+
+dummy.o: mail.h misc.h osdep.h dummy.h
+fdstring.o: mail.h misc.h osdep.h fdstring.h
+flstring.o: mail.h misc.h osdep.h flstring.h
+imap4r1.o: mail.h misc.h osdep.h imap4r1.h rfc822.h
+mail.o: mail.h misc.h osdep.h rfc822.h linkage.h
+mbx.o: mail.h misc.h osdep.h dummy.h
+mh.o: mail.h misc.h osdep.h mh.h dummy.h
+mix.o: mail.h misc.h osdep.h dummy.h
+mx.o: mail.h misc.h osdep.h mx.h dummy.h
+misc.o: mail.h misc.h osdep.h
+mmdf.o: mail.h misc.h osdep.h pseudo.h dummy.h
+mtx.o: mail.h misc.h osdep.h dummy.h
+netmsg.o: mail.h misc.h osdep.h netmsg.h
+news.o: mail.h misc.h osdep.h
+newsrc.o: mail.h misc.h osdep.h newsrc.h
+nntp.o: mail.h misc.h osdep.h netmsg.h smtp.h nntp.h rfc822.h
+phile.o: mail.h misc.h osdep.h rfc822.h dummy.h
+pseudo.o: pseudo.h
+pop3.o: mail.h misc.h osdep.h pop3.h rfc822.h
+smanager.o: mail.h misc.h osdep.h
+smtp.o: mail.h misc.h osdep.h smtp.h rfc822.h
+rfc822.o: mail.h misc.h osdep.h rfc822.h
+tenex.o: mail.h misc.h osdep.h dummy.h
+unix.o: mail.h misc.h osdep.h unix.h pseudo.h dummy.h
+utf8.o: mail.h misc.h osdep.h utf8.h
+utf8aux.o: mail.h misc.h osdep.h utf8.h
+
+
+# OS-dependent
+
+osdep.o:mail.h misc.h env.h fs.h ftl.h nl.h tcp.h \
+	osdep.h env_ami.h tcp_ami.h \
+	osdep.c env_ami.c fs_ami.c ftl_ami.c nl_ami.c tcp_ami.c \
+	auths.c gethstid.c \
+	gr_waitp.c \
+	auth_log.c auth_md5.c auth_pla.c \
+	pmatch.c scandir.c \
+	tz_bsd.c \
+	write.c \
+	strerror.c strpbrk.c strstr.c strtok.c strtoul.c \
+	OSCFLAGS
+	$(CC) $(CFLAGS) `cat OSCFLAGS` -c osdep.c
+
+osdep.c: osdepbas.c osdepckp.c osdeplog.c osdepssl.c
+	$(RM) osdep.c || true
+	cat osdepbas.c osdepckp.c osdeplog.c osdepssl.c > osdep.c
+
+
+# Once-only environment setup
+
+once:
+	@echo Once-only environment setup...
+	./drivers $(EXTRADRIVERS) $(DEFAULTDRIVERS) dummy
+	./mkauths $(EXTRAAUTHENTICATORS) $(DEFAULTAUTHENTICATORS)
+	echo $(CC) > CCTYPE
+	echo $(CFLAGS) -DCHUNKSIZE=$(CHUNKSIZE) > CFLAGS
+	echo -DCREATEPROTO=$(CREATEPROTO) -DEMPTYPROTO=$(EMPTYPROTO) \
+	 -DMD5ENABLE=\"$(MD5PWD)\" -DMAILSPOOL=\"$(MAILSPOOL)\" \
+	 -DACTIVEFILE=\"$(ACTIVEFILE)\" -DNEWSSPOOL=\"$(NEWSSPOOL)\" \
+	 -DANONYMOUSHOME=\"$(MAILSPOOL)/anonymous\" > OSCFLAGS
+	echo $(BASELDFLAGS) $(EXTRALDFLAGS) > LDFLAGS
+	$(LN) os_$(OS).h osdep.h
+	$(LN) os_$(OS).c osdepbas.c
+	$(LN) log_$(LOGINPW).c osdeplog.c
+	$(LN) ssl_none.c osdepssl.c
+
+
+# Password checkers
+
+ckpstd:	# Port standard
+	$(LN) ckp_$(CHECKPW).c osdepckp.c
+
+
+# A monument to a hack of long ago and far away...
+
+love:
+	@echo not war?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/ckp_std.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,42 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Standard check password
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Check password
+ * Accepts: login passwd struct
+ *	    password string
+ *	    argument count
+ *	    argument vector
+ * Returns: passwd struct if password validated, NIL otherwise
+ */
+
+struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
+{
+  return (pw->pw_passwd && pw->pw_passwd[0] && pw->pw_passwd[1] &&
+	  !strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) ?
+	    pw : NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/drivers	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,36 @@
+#!/bin/sh
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+# Program:	Driver Linkage Generator
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		11 October 1989
+# Last Edited:	30 August 2006
+
+
+# Erase old driver linkage
+rm -f linkage.[ch]
+
+# Now define the new list
+for driver
+ do
+  echo "extern DRIVER "$driver"driver;" >> linkage.h
+  echo "  mail_link (&"$driver"driver);		/* link in the $driver driver */" | cat >> linkage.c
+done
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/dummy.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,809 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Dummy routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	9 May 1991
+ * Last Edited:	1 June 2007
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "mail.h"
+#include "osdep.h"
+#include <pwd.h>
+#include <sys/stat.h>
+#include "dummy.h"
+#include "misc.h"
+
+/* Function prototypes */
+
+DRIVER *dummy_valid (char *name);
+void *dummy_parameters (long function,void *value);
+void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents,
+		      long level);
+long dummy_listed (MAILSTREAM *stream,char delimiter,char *name,
+		   long attributes,char *contents);
+long dummy_subscribe (MAILSTREAM *stream,char *mailbox);
+MAILSTREAM *dummy_open (MAILSTREAM *stream);
+void dummy_close (MAILSTREAM *stream,long options);
+long dummy_ping (MAILSTREAM *stream);
+void dummy_check (MAILSTREAM *stream);
+long dummy_expunge (MAILSTREAM *stream,char *sequence,long options);
+long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+/* Dummy routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER dummydriver = {
+  "dummy",			/* driver name */
+  DR_LOCAL|DR_MAIL,		/* driver flags */
+  (DRIVER *) NIL,		/* next driver */
+  dummy_valid,			/* mailbox is valid for us */
+  dummy_parameters,		/* manipulate parameters */
+  dummy_scan,			/* scan mailboxes */
+  dummy_list,			/* list mailboxes */
+  dummy_lsub,			/* list subscribed mailboxes */
+  dummy_subscribe,		/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  dummy_create,			/* create mailbox */
+  dummy_delete,			/* delete mailbox */
+  dummy_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  dummy_open,			/* open mailbox */
+  dummy_close,			/* close mailbox */
+  NIL,				/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message structure */
+  NIL,				/* fetch header */
+  NIL,				/* fetch text */
+  NIL,				/* fetch message data */
+  NIL,				/* unique identifier */
+  NIL,				/* message number from UID */
+  NIL,				/* modify flags */
+  NIL,				/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  dummy_ping,			/* ping mailbox to see if still alive */
+  dummy_check,			/* check for new messages */
+  dummy_expunge,		/* expunge deleted messages */
+  dummy_copy,			/* copy messages to another mailbox */
+  dummy_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM dummyproto = {&dummydriver};
+
+/* Dummy validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *dummy_valid (char *name)
+{
+  char *s,tmp[MAILTMPLEN];
+  struct stat sbuf;
+				/* must be valid local mailbox */
+  if (name && *name && (*name != '{') && (s = mailboxfile (tmp,name))) {
+				/* indeterminate clearbox INBOX */
+    if (!*s) return &dummydriver;
+    else if (!stat (s,&sbuf)) switch (sbuf.st_mode & S_IFMT) {
+    case S_IFREG:
+    case S_IFDIR:
+      return &dummydriver;
+    }
+				/* blackbox INBOX does not exist yet */
+    else if (!compare_cstring (name,"INBOX")) return &dummydriver;
+  }
+  return NIL;
+}
+
+
+/* Dummy manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *dummy_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case GET_INBOXPATH:
+    if (value) ret = dummy_file ((char *) value,"INBOX");
+    break;
+  }
+  return ret;
+}
+
+/* Dummy scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  DRIVER *drivers;
+  char *s,test[MAILTMPLEN],file[MAILTMPLEN];
+  long i;
+  if (!pat || !*pat) {		/* empty pattern? */
+    if (dummy_canonicalize (test,ref,"*")) {
+				/* tie off name at root */
+      if (s = strchr (test,'/')) *++s = '\0';
+      else test[0] = '\0';
+      dummy_listed (stream,'/',test,LATT_NOSELECT,NIL);
+    }
+  }
+				/* get canonical form of name */
+  else if (dummy_canonicalize (test,ref,pat)) {
+				/* found any wildcards? */
+    if (s = strpbrk (test,"%*")) {
+				/* yes, copy name up to that point */
+      strncpy (file,test,i = s - test);
+      file[i] = '\0';		/* tie off */
+    }
+    else strcpy (file,test);	/* use just that name then */
+    if (s = strrchr (file,'/')){/* find directory name */
+      *++s = '\0';		/* found, tie off at that point */
+      s = file;
+    }
+				/* silly case */
+    else if ((file[0] == '~') || (file[0] == '#')) s = file;
+				/* do the work */
+    dummy_list_work (stream,s,test,contents,0);
+				/* always an INBOX */
+    if (pmatch ("INBOX",ucase (test))) {
+				/* done if have a dirfmt INBOX */
+      for (drivers = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL);
+	   drivers && !(!(drivers->flags & DR_DISABLE) &&
+			(drivers->flags & DR_DIRFMT) &&
+			(*drivers->valid) ("INBOX")); drivers = drivers->next);
+				/* list INBOX appropriately */
+      dummy_listed (stream,drivers ? '/' : NIL,"INBOX",
+		    drivers ? NIL : LATT_NOINFERIORS,contents);
+    }
+  }
+}
+
+
+/* Dummy list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void dummy_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  dummy_scan (stream,ref,pat,NIL);
+}
+
+/* Dummy list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  void *sdb = NIL;
+  char *s,*t,test[MAILTMPLEN],tmp[MAILTMPLEN];
+  int showuppers = pat[strlen (pat) - 1] == '%';
+				/* get canonical form of name */
+  if (dummy_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) do
+    if (*s != '{') {
+      if (!compare_cstring (s,"INBOX") &&
+	  pmatch ("INBOX",ucase (strcpy (tmp,test))))
+	mm_lsub (stream,NIL,s,LATT_NOINFERIORS);
+      else if (pmatch_full (s,test,'/')) mm_lsub (stream,'/',s,NIL);
+      else while (showuppers && (t = strrchr (s,'/'))) {
+	*t = '\0';		/* tie off the name */
+	if (pmatch_full (s,test,'/')) mm_lsub (stream,'/',s,LATT_NOSELECT);
+      }
+    }
+  while (s = sm_read (&sdb));	/* until no more subscriptions */
+}
+
+
+/* Dummy subscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to add to subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_subscribe (MAILSTREAM *stream,char *mailbox)
+{
+  char *s,tmp[MAILTMPLEN];
+  struct stat sbuf;
+				/* must be valid local mailbox */
+  if ((s = mailboxfile (tmp,mailbox)) && *s && !stat (s,&sbuf))
+    switch (sbuf.st_mode & S_IFMT) {
+    case S_IFDIR:		/* allow but snarl */
+      sprintf (tmp,"CLIENT BUG DETECTED: subscribe of non-mailbox directory %.80s",
+	       mailbox);
+      MM_NOTIFY (stream,tmp,WARN);
+    case S_IFREG:
+      return sm_subscribe (mailbox);
+    }
+  sprintf (tmp,"Can't subscribe %.80s: not a mailbox",mailbox);
+  MM_LOG (tmp,ERROR);
+  return NIL;
+}
+
+/* Dummy list mailboxes worker routine
+ * Accepts: mail stream
+ *	    directory name to search
+ *	    search pattern
+ *	    string to scan
+ *	    search level
+ */
+
+void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents,
+		      long level)
+{
+  DRIVER *drivers;
+  dirfmttest_t dt;
+  DIR *dp;
+  struct direct *d;
+  struct stat sbuf;
+  char tmp[MAILTMPLEN],path[MAILTMPLEN];
+  size_t len = 0;
+				/* punt if bogus name */
+  if (!mailboxdir (tmp,dir,NIL)) return;
+  if (dp = opendir (tmp)) {	/* do nothing if can't open directory */
+				/* see if a non-namespace directory format */
+    for (drivers = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL), dt = NIL;
+	 dir && !dt && drivers; drivers = drivers->next)
+      if (!(drivers->flags & DR_DISABLE) && (drivers->flags & DR_DIRFMT) &&
+	  (*drivers->valid) (dir))
+	dt = mail_parameters ((*drivers->open) (NIL),GET_DIRFMTTEST,NIL);
+				/* list it if at top-level */
+    if (!level && dir && pmatch_full (dir,pat,'/') && !pmatch (dir,"INBOX"))
+      dummy_listed (stream,'/',dir,dt ? NIL : LATT_NOSELECT,contents);
+
+				/* scan directory, ignore . and .. */
+    if (!dir || dir[(len = strlen (dir)) - 1] == '/') while (d = readdir (dp))
+      if ((!(dt && (*dt) (d->d_name))) &&
+	  ((d->d_name[0] != '.') ||
+	   (((long) mail_parameters (NIL,GET_HIDEDOTFILES,NIL)) ? NIL :
+	    (d->d_name[1] && (((d->d_name[1] != '.') || d->d_name[2]))))) &&
+	  ((len + strlen (d->d_name)) <= NETMAXMBX)) {
+				/* see if name is useful */
+	if (dir) sprintf (tmp,"%s%s",dir,d->d_name);
+	else strcpy (tmp,d->d_name);
+				/* make sure useful and can get info */
+	if ((pmatch_full (strcpy (path,tmp),pat,'/') ||
+	     pmatch_full (strcat (path,"/"),pat,'/') ||
+	     dmatch (path,pat,'/')) &&
+	    mailboxdir (path,dir,"x") && (len = strlen (path)) &&
+	    strcpy (path+len-1,d->d_name) && !stat (path,&sbuf)) {
+				/* only interested in file type */
+	  switch (sbuf.st_mode & S_IFMT) {
+	  case S_IFDIR:		/* directory? */
+				/* form with trailing / */
+	    sprintf (path,"%s/",tmp);
+				/* skip listing if INBOX */
+	    if (!pmatch (tmp,"INBOX")) {
+	      if (pmatch_full (tmp,pat,'/')) {
+		if (!dummy_listed (stream,'/',tmp,LATT_NOSELECT,contents))
+		  break;
+	      }
+				/* try again with trailing / */
+	      else if (pmatch_full (path,pat,'/') &&
+		       !dummy_listed (stream,'/',path,LATT_NOSELECT,contents))
+		break;
+	    }
+	    if (dmatch (path,pat,'/') &&
+		(level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL)))
+	      dummy_list_work (stream,path,pat,contents,level+1);
+	    break;
+	  case S_IFREG:		/* ordinary name */
+	    /* Must use ctime for systems that don't update mtime properly */
+	    if (pmatch_full (tmp,pat,'/') && compare_cstring (tmp,"INBOX"))
+	      dummy_listed (stream,'/',tmp,LATT_NOINFERIORS +
+			    ((sbuf.st_size && (sbuf.st_atime < sbuf.st_ctime))?
+			     LATT_MARKED : LATT_UNMARKED),contents);
+	    break;
+	  }
+	}
+      }
+    closedir (dp);		/* all done, flush directory */
+  }
+}
+
+/* Scan file for contents
+ * Accepts: driver to use
+ *	    file name
+ *	    desired contents
+ *	    length of contents
+ *	    size of file
+ * Returns: NIL if contents not found, T if found
+ */
+
+long scan_contents (DRIVER *dtb,char *name,char *contents,
+		    unsigned long csiz,unsigned long fsiz)
+{
+  scancontents_t sc = dtb ?
+    (scancontents_t) (*dtb->parameters) (GET_SCANCONTENTS,NIL) : NIL;
+  return (*(sc ? sc : dummy_scan_contents)) (name,contents,csiz,fsiz);
+}
+
+
+/* Scan file for contents
+ * Accepts: file name
+ *	    desired contents
+ *	    length of contents
+ *	    size of file
+ * Returns: NIL if contents not found, T if found
+ */
+
+#define BUFSIZE 4*MAILTMPLEN
+
+long dummy_scan_contents (char *name,char *contents,unsigned long csiz,
+			  unsigned long fsiz)
+{
+  int fd;
+  unsigned long ssiz,bsiz;
+  char *buf;
+				/* forget it if can't select or open */
+  if ((fd = open (name,O_RDONLY,NIL)) >= 0) {
+				/* get buffer including slop */    
+    buf = (char *) fs_get (BUFSIZE + (ssiz = 4 * ((csiz / 4) + 1)) + 1);
+    memset (buf,'\0',ssiz);	/* no slop area the first time */
+    while (fsiz) {		/* until end of file */
+      read (fd,buf+ssiz,bsiz = min (fsiz,BUFSIZE));
+      if (search ((unsigned char *) buf,bsiz+ssiz,
+		  (unsigned char *) contents,csiz)) break;
+      memcpy (buf,buf+BUFSIZE,ssiz);
+      fsiz -= bsiz;		/* note that we read that much */
+    }
+    fs_give ((void **) &buf);	/* flush buffer */
+    close (fd);			/* finished with file */
+    if (fsiz) return T;		/* found */
+  }
+  return NIL;			/* not found */
+}
+
+/* Mailbox found
+ * Accepts: MAIL stream
+ *	    hierarchy delimiter
+ *	    mailbox name
+ *	    attributes
+ *	    contents to search before calling mm_list()
+ * Returns: NIL if should abort hierarchy search, else T (currently always)
+ */
+
+long dummy_listed (MAILSTREAM *stream,char delimiter,char *name,
+		   long attributes,char *contents)
+{
+  DRIVER *d;
+  DIR *dp;
+  struct direct *dr;
+  dirfmttest_t dt;
+  unsigned long csiz;
+  struct stat sbuf;
+  int nochild;
+  char *s,tmp[MAILTMPLEN];
+  if (!(attributes & LATT_NOINFERIORS) && mailboxdir (tmp,name,NIL) &&
+      (dp = opendir (tmp))) {	/* if not \NoInferiors */
+				/* locate dirfmttest if any */
+    for (d = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL), dt = NIL;
+	 !dt && d; d = d->next)
+      if (!(d->flags & DR_DISABLE) && (d->flags & DR_DIRFMT) &&
+	  (*d->valid) (name))
+	dt = mail_parameters ((*d->open) (NIL),GET_DIRFMTTEST,NIL);
+				/* scan directory for children */
+    for (nochild = T; nochild && (dr = readdir (dp)); )
+      if ((!(dt && (*dt) (dr->d_name))) &&
+	  ((dr->d_name[0] != '.') ||
+	   (((long) mail_parameters (NIL,GET_HIDEDOTFILES,NIL)) ? NIL :
+	    (dr->d_name[1] && ((dr->d_name[1] != '.') || dr->d_name[2])))))
+	nochild = NIL;
+    attributes |= nochild ? LATT_HASNOCHILDREN : LATT_HASCHILDREN;
+    closedir (dp);		/* all done, flush directory */
+  }
+  d = NIL;			/* don't \NoSelect dir if it has a driver */
+  if ((attributes & LATT_NOSELECT) && (d = mail_valid (NIL,name,NIL)) &&
+      (d != &dummydriver)) attributes &= ~LATT_NOSELECT;
+  if (!contents ||		/* notify main program */
+      (!(attributes & LATT_NOSELECT) && (csiz = strlen (contents)) &&
+       (s = mailboxfile (tmp,name)) &&
+       (*s || (s = mail_parameters (NIL,GET_INBOXPATH,tmp))) &&
+       !stat (s,&sbuf) && (d || (csiz <= sbuf.st_size)) &&
+       SAFE_SCAN_CONTENTS (d,tmp,contents,csiz,sbuf.st_size)))
+    mm_list (stream,delimiter,name,attributes);
+  return T;
+}
+
+/* Dummy create mailbox
+ * Accepts: mail stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_create (MAILSTREAM *stream,char *mailbox)
+{
+  char *s,tmp[MAILTMPLEN];
+  long ret = NIL;
+				/* validate name */
+  if (!(compare_cstring (mailbox,"INBOX") && (s = dummy_file (tmp,mailbox)))) {
+    sprintf (tmp,"Can't create %.80s: invalid name",mailbox);
+    MM_LOG (tmp,ERROR);
+  }
+				/* create the name, done if made directory */
+  else if ((ret = dummy_create_path (stream,tmp,get_dir_protection(mailbox)))&&
+	   (s = strrchr (s,'/')) && !s[1]) return T;
+  return ret ? set_mbx_protections (mailbox,tmp) : NIL;
+}
+
+/* Dummy create path
+ * Accepts: mail stream
+ *	    path name to create
+ *	    directory mode
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode)
+{
+  struct stat sbuf;
+  char c,*s,tmp[MAILTMPLEN];
+  int fd;
+  long ret = NIL;
+  char *t = strrchr (path,'/');
+  int wantdir = t && !t[1];
+  int mask = umask (0);
+  if (wantdir) *t = '\0';	/* flush trailing delimiter for directory */
+  if (s = strrchr (path,'/')) {	/* found superior to this name? */
+    c = *++s;			/* remember first character of inferior */
+    *s = '\0';			/* tie off to get just superior */
+				/* name doesn't exist, create it */
+    if ((stat (path,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+	!dummy_create_path (stream,path,dirmode)) {
+      umask (mask);		/* restore mask */
+      return NIL;
+    }
+    *s = c;			/* restore full name */
+  }
+  if (wantdir) {		/* want to create directory? */
+    ret = !mkdir (path,(int) dirmode);
+    *t = '/';			/* restore directory delimiter */
+  }
+				/* create file */
+  else if ((fd = open (path,O_WRONLY|O_CREAT|O_EXCL,
+		       (long) mail_parameters(NIL,GET_MBXPROTECTION,NIL))) >=0)
+    ret = !close (fd);
+  if (!ret) {			/* error? */
+    sprintf (tmp,"Can't create mailbox node %.80s: %.80s",path,strerror (errno));
+    MM_LOG (tmp,ERROR);
+  }
+  umask (mask);			/* restore mask */
+  return ret;			/* return status */
+}
+
+/* Dummy delete mailbox
+ * Accepts: mail stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_delete (MAILSTREAM *stream,char *mailbox)
+{
+  struct stat sbuf;
+  char *s,tmp[MAILTMPLEN];
+  if (!(s = dummy_file (tmp,mailbox))) {
+    sprintf (tmp,"Can't delete - invalid name: %.80s",s);
+    MM_LOG (tmp,ERROR);
+  }
+				/* no trailing / (workaround BSD kernel bug) */
+  if ((s = strrchr (tmp,'/')) && !s[1]) *s = '\0';
+  if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) == S_IFDIR) ?
+      rmdir (tmp) : unlink (tmp)) {
+    sprintf (tmp,"Can't delete mailbox %.80s: %.80s",mailbox,strerror (errno));
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+  return T;			/* return success */
+}
+
+/* Mail rename mailbox
+ * Accepts: mail stream
+ *	    old mailbox name
+ *	    new mailbox name
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  struct stat sbuf;
+  char c,*s,tmp[MAILTMPLEN],mbx[MAILTMPLEN],oldname[MAILTMPLEN];
+				/* no trailing / allowed */
+  if (!dummy_file (oldname,old) || !(s = dummy_file (mbx,newname)) ||
+      stat (oldname,&sbuf) || ((s = strrchr (s,'/')) && !s[1] &&
+			       ((sbuf.st_mode & S_IFMT) != S_IFDIR))) {
+    sprintf (mbx,"Can't rename %.80s to %.80s: invalid name",old,newname);
+    MM_LOG (mbx,ERROR);
+    return NIL;
+  }
+  if (s) {			/* found a directory delimiter? */
+    if (!s[1]) *s = '\0';	/* ignore trailing delimiter */
+    else {			/* found superior to destination name? */
+      c = *++s;			/* remember first character of inferior */
+      *s = '\0';		/* tie off to get just superior */
+				/* name doesn't exist, create it */
+      if ((stat (mbx,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+	  !dummy_create (stream,mbx)) return NIL;
+      *s = c;			/* restore full name */
+    }
+  }
+				/* rename of non-ex INBOX creates dest */
+  if (!compare_cstring (old,"INBOX") && stat (oldname,&sbuf))
+    return dummy_create (NIL,mbx);
+  if (rename (oldname,mbx)) {
+    sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %.80s",old,newname,
+	     strerror (errno));
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+  return T;			/* return success */
+}
+
+/* Dummy open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *dummy_open (MAILSTREAM *stream)
+{
+  int fd;
+  char err[MAILTMPLEN],tmp[MAILTMPLEN];
+  struct stat sbuf;
+				/* OP_PROTOTYPE call */
+  if (!stream) return &dummyproto;
+  err[0] = '\0';		/* no error message yet */
+				/* can we open the file? */
+  if (!dummy_file (tmp,stream->mailbox))
+    sprintf (err,"Can't open this name: %.80s",stream->mailbox);
+  else if ((fd = open (tmp,O_RDONLY,NIL)) < 0) {
+				/* no, error unless INBOX */
+    if (compare_cstring (stream->mailbox,"INBOX"))
+      sprintf (err,"%.80s: %.80s",strerror (errno),stream->mailbox);
+  }
+  else {			/* file had better be empty then */
+    fstat (fd,&sbuf);		/* sniff at its size */
+    close (fd);
+    if ((sbuf.st_mode & S_IFMT) != S_IFREG)
+      sprintf (err,"Can't open %.80s: not a selectable mailbox",
+	       stream->mailbox);
+    else if (sbuf.st_size)	/* bogus format if non-empty */
+      sprintf (err,"Can't open %.80s (file %.80s): not in valid mailbox format",
+	       stream->mailbox,tmp);
+  }
+  if (err[0]) {			/* if an error happened */
+    MM_LOG (err,stream->silent ? WARN : ERROR);
+    return NIL;
+  }
+  else if (!stream->silent) {	/* only if silence not requested */
+    mail_exists (stream,0);	/* say there are 0 messages */
+    mail_recent (stream,0);	/* and certainly no recent ones! */
+    stream->uid_validity = time (0);
+  }
+  stream->inbox = T;		/* note that it's an INBOX */
+  return stream;		/* return success */
+}
+
+
+/* Dummy close
+ * Accepts: MAIL stream
+ *	    options
+ */
+
+void dummy_close (MAILSTREAM *stream,long options)
+{
+				/* return silently */
+}
+
+/* Dummy ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ */
+
+long dummy_ping (MAILSTREAM *stream)
+{
+  MAILSTREAM *test;
+  if (time (0) >=		/* time to do another test? */
+      ((time_t) (stream->gensym +
+		 (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL)))) {
+				/* has mailbox format changed? */
+    if ((test = mail_open (NIL,stream->mailbox,OP_PROTOTYPE)) &&
+	(test->dtb != stream->dtb) &&
+	(test = mail_open (NIL,stream->mailbox,NIL))) {
+				/* preserve some resources */
+      test->original_mailbox = stream->original_mailbox;
+      stream->original_mailbox = NIL;
+      test->sparep = stream->sparep;
+      stream->sparep = NIL;
+      test->sequence = stream->sequence;
+      mail_close ((MAILSTREAM *) /* flush resources used by dummy stream */
+		  memcpy (fs_get (sizeof (MAILSTREAM)),stream,
+			  sizeof (MAILSTREAM)));
+				/* swap the streams */
+      memcpy (stream,test,sizeof (MAILSTREAM));
+      fs_give ((void **) &test);/* flush test now that copied */
+				/* make sure application knows */
+      mail_exists (stream,stream->recent = stream->nmsgs);
+    }
+				/* still hasn't changed */
+    else stream->gensym = time (0);
+  }
+  return T;
+}
+
+
+/* Dummy check mailbox
+ * Accepts: MAIL stream
+ * No-op for readonly files, since read/writer can expunge it from under us!
+ */
+
+void dummy_check (MAILSTREAM *stream)
+{
+  dummy_ping (stream);		/* invoke ping */
+}
+
+
+/* Dummy expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long dummy_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  return LONGT;
+}
+
+/* Dummy copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    options
+ * Returns: T if copy successful, else NIL
+ */
+
+long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+      mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy");
+  return NIL;
+}
+
+
+/* Dummy append message string
+ * Accepts: mail stream
+ *	    destination mailbox
+ *	    append callback function
+ *	    data for callback
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct stat sbuf;
+  int fd = -1;
+  int e;
+  char tmp[MAILTMPLEN];
+  MAILSTREAM *ts = default_proto (T);
+				/* append to INBOX? */
+  if (!compare_cstring (mailbox,"INBOX")) {
+				/* yes, if no empty proto try creating */
+    if (!ts && !(*(ts = default_proto (NIL))->dtb->create) (ts,"INBOX"))
+      ts = NIL;
+  }
+  else if (dummy_file (tmp,mailbox) && ((fd = open (tmp,O_RDONLY,NIL)) < 0)) {
+    if ((e = errno) == ENOENT) /* failed, was it no such file? */
+      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+    sprintf (tmp,"%.80s: %.80s",strerror (e),mailbox);
+    MM_LOG (tmp,ERROR);		/* pass up error */
+    return NIL;			/* always fails */
+  }
+  else if (fd >= 0) {		/* found file? */
+    fstat (fd,&sbuf);		/* get its size */
+    close (fd);			/* toss out the fd */
+    if (sbuf.st_size) ts = NIL; /* non-empty file? */
+  }
+  if (ts) return (*ts->dtb->append) (stream,mailbox,af,data);
+  sprintf (tmp,"Indeterminate mailbox format: %.80s",mailbox);
+  MM_LOG (tmp,ERROR);
+  return NIL;
+}
+
+/* Dummy mail generate file string
+ * Accepts: temporary buffer to write into
+ *	    mailbox name string
+ * Returns: local file string or NIL if failure
+ */
+
+char *dummy_file (char *dst,char *name)
+{
+  char *s = mailboxfile (dst,name);
+				/* return our standard inbox */
+  return (s && !*s) ? strcpy (dst,sysinbox ()) : s;
+}
+
+
+/* Dummy canonicalize name
+ * Accepts: buffer to write name
+ *	    reference
+ *	    pattern
+ * Returns: T if success, NIL if failure
+ */
+
+long dummy_canonicalize (char *tmp,char *ref,char *pat)
+{
+  unsigned long i;
+  char *s;
+  if (ref) {			/* preliminary reference check */
+    if (*ref == '{') return NIL;/* remote reference not allowed */
+    else if (!*ref) ref = NIL;	/* treat empty reference as no reference */
+  }
+  switch (*pat) {
+  case '#':			/* namespace name */
+    if (mailboxfile (tmp,pat)) strcpy (tmp,pat);
+    else return NIL;		/* unknown namespace */
+    break;
+  case '{':			/* remote names not allowed */
+    return NIL;
+  case '/':			/* rooted name */
+  case '~':			/* home directory name */
+    if (!ref || (*ref != '#')) {/* non-namespace reference? */
+      strcpy (tmp,pat);		/* yes, ignore */
+      break;
+    }
+				/* fall through */
+  default:			/* apply reference for all other names */
+    if (!ref) strcpy (tmp,pat);	/* just copy if no namespace */
+    else if ((*ref != '#') || mailboxfile (tmp,ref)) {
+				/* wants root of name? */
+      if (*pat == '/') strcpy (strchr (strcpy (tmp,ref),'/'),pat);
+				/* otherwise just append */
+      else sprintf (tmp,"%s%s",ref,pat);
+    }
+    else return NIL;		/* unknown namespace */
+  }
+				/* count wildcards */
+  for (i = 0, s = tmp; *s; *s++) if ((*s == '*') || (*s == '%')) ++i;
+  if (i > MAXWILDCARDS) {	/* ridiculous wildcarding? */
+    MM_LOG ("Excessive wildcards in LIST/LSUB",ERROR);
+    return NIL;
+  }
+  return T;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/dummy.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,43 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Dummy routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	9 May 1991
+ * Last Edited:	30 August 2006
+ */
+
+/* Exported function prototypes */
+
+void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void dummy_list (MAILSTREAM *stream,char *ref,char *pat);
+void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long scan_contents (DRIVER *dtb,char *name,char *contents,
+		    unsigned long csiz,unsigned long fsiz);
+long dummy_scan_contents (char *name,char *contents,unsigned long csiz,
+			  unsigned long fsiz);
+long dummy_create (MAILSTREAM *stream,char *mailbox);
+long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode);
+long dummy_delete (MAILSTREAM *stream,char *mailbox);
+long dummy_rename (MAILSTREAM *stream,char *old,char *newname);
+char *dummy_file (char *dst,char *name);
+long dummy_canonicalize (char *tmp,char *ref,char *pat);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/env_ami.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1282 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Amiga environment routines
+ *
+ * Author:	Mark Crispin
+ *		UW Technology
+ *		Seattle, WA  98195
+ *		Internet: MRC@Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	15 May 2008
+ */
+
+#include <grp.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+/* c-client environment parameters */
+
+static char *myUserName = NIL;	/* user name */
+static char *myHomeDir = NIL;	/* home directory name */
+static char *myMailboxDir = NIL;/* mailbox directory name */
+static char *myLocalHost = NIL;	/* local host name */
+static char *myNewsrc = NIL;	/* newsrc file name */
+static char *mailsubdir = NIL;	/* mail subdirectory name */
+static char *sysInbox = NIL;	/* system inbox name */
+static char *newsActive = NIL;	/* news active file */
+static char *newsSpool = NIL;	/* news spool */
+				/* anonymous home directory */
+static char *anonymousHome = NIL;
+static char *ftpHome = NIL;	/* ftp export home directory */
+static char *publicHome = NIL;	/* public home directory */
+static char *sharedHome = NIL;	/* shared home directory */
+static short anonymous = NIL;	/* is anonymous */
+static short restrictBox = NIL;	/* is a restricted box */
+static short has_no_life = NIL;	/* is a cretin with no life */
+				/* block environment init */
+static short block_env_init = NIL;
+static short hideDotFiles = NIL;/* hide files whose names start with . */
+				/* advertise filesystem root */
+static short advertisetheworld = NIL;
+				/* disable automatic shared namespaces */
+static short noautomaticsharedns = NIL;
+static short no822tztext = NIL;	/* disable RFC [2]822 timezone text */
+static short netfsstatbug = NIL;/* compensate for broken stat() on network
+				 * filesystems (AFS and old NFS).  Don't do
+				 * this unless you really have to!
+				 */
+				/* 1 = disable plaintext, 2 = if not SSL */
+static long disablePlaintext = NIL;
+static long list_max_level = 20;/* maximum level of list recursion */
+				/* default file protection */
+static long mbx_protection = 0600;
+				/* default directory protection */
+static long dir_protection = 0700;
+				/* default lock file protection */
+static long lock_protection = MANDATORYLOCKPROT;
+				/* default ftp file protection */
+static long ftp_protection = 0644;
+static long ftp_dir_protection = 0755;
+				/* default public file protection */
+static long public_protection = 0666;
+static long public_dir_protection = 0777;
+				/* default shared file protection */
+static long shared_protection = 0660;
+static long shared_dir_protection = 0770;
+static long locktimeout = 5;	/* default lock timeout */
+				/* default prototypes */
+static MAILSTREAM *createProto = NIL;
+static MAILSTREAM *appendProto = NIL;
+				/* default user flags */
+static char *userFlags[NUSERFLAGS] = {NIL};
+static NAMESPACE *nslist[3];	/* namespace list */
+static int logtry = 3;		/* number of server login tries */
+				/* block notification */
+static blocknotify_t mailblocknotify = mm_blocknotify;
+
+/* Amiga namespaces */
+
+				/* personal mh namespace */
+static NAMESPACE nsmhf = {"#mh/",'/',NIL,NIL};
+static NAMESPACE nsmh = {"#mhinbox",NIL,NIL,&nsmhf};
+				/* home namespace */
+static NAMESPACE nshome = {"",'/',NIL,&nsmh};
+				/* Amiga other user namespace */
+static NAMESPACE nsamigaother = {"~",'/',NIL,NIL};
+				/* public (anonymous OK) namespace */
+static NAMESPACE nspublic = {"#public/",'/',NIL,NIL};
+				/* netnews namespace */
+static NAMESPACE nsnews = {"#news.",'.',NIL,&nspublic};
+				/* FTP export namespace */
+static NAMESPACE nsftp = {"#ftp/",'/',NIL,&nsnews};
+				/* shared (no anonymous) namespace */
+static NAMESPACE nsshared = {"#shared/",'/',NIL,&nsftp};
+				/* world namespace */
+static NAMESPACE nsworld = {"/",'/',NIL,&nsshared};
+
+#include "write.c"		/* include safe writing routines */
+#include "pmatch.c"		/* include wildcard pattern matcher */
+
+/* Get all authenticators */
+
+#include "auths.c"
+
+/* Environment manipulate parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *env_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case GET_NAMESPACE:
+    ret = (void *) nslist;
+    break;
+  case SET_USERNAME:
+    if (myUserName) fs_give ((void **) &myUserName);
+    myUserName = cpystr ((char *) value);
+  case GET_USERNAME:
+    ret = (void *) myUserName;
+    break;
+  case SET_HOMEDIR:
+    if (myHomeDir) fs_give ((void **) &myHomeDir);
+    myHomeDir = cpystr ((char *) value);
+  case GET_HOMEDIR:
+    ret = (void *) myHomeDir;
+    break;
+  case SET_LOCALHOST:
+    if (myLocalHost) fs_give ((void **) &myLocalHost);
+    myLocalHost = cpystr ((char *) value);
+  case GET_LOCALHOST:
+    ret = (void *) myLocalHost;
+    break;
+  case SET_NEWSRC:
+    if (myNewsrc) fs_give ((void **) &myNewsrc);
+    myNewsrc = cpystr ((char *) value);
+  case GET_NEWSRC:
+    ret = (void *) myNewsrc;
+    break;
+  case SET_NEWSACTIVE:
+    if (newsActive) fs_give ((void **) &newsActive);
+    newsActive = cpystr ((char *) value);
+  case GET_NEWSACTIVE:
+    ret = (void *) newsActive;
+    break;
+  case SET_NEWSSPOOL:
+    if (newsSpool) fs_give ((void **) &newsSpool);
+    newsSpool = cpystr ((char *) value);
+  case GET_NEWSSPOOL:
+    ret = (void *) newsSpool;
+    break;
+
+  case SET_ANONYMOUSHOME:
+    if (anonymousHome) fs_give ((void **) &anonymousHome);
+    anonymousHome = cpystr ((char *) value);
+  case GET_ANONYMOUSHOME:
+    if (!anonymousHome) anonymousHome = cpystr (ANONYMOUSHOME);
+    ret = (void *) anonymousHome;
+    break;
+  case SET_FTPHOME:
+    if (ftpHome) fs_give ((void **) &ftpHome);
+    ftpHome = cpystr ((char *) value);
+  case GET_FTPHOME:
+    ret = (void *) ftpHome;
+    break;
+  case SET_PUBLICHOME:
+    if (publicHome) fs_give ((void **) &publicHome);
+    publicHome = cpystr ((char *) value);
+  case GET_PUBLICHOME:
+    ret = (void *) publicHome;
+    break;
+  case SET_SHAREDHOME:
+    if (sharedHome) fs_give ((void **) &sharedHome);
+    sharedHome = cpystr ((char *) value);
+  case GET_SHAREDHOME:
+    ret = (void *) sharedHome;
+    break;
+  case SET_SYSINBOX:
+    if (sysInbox) fs_give ((void **) &sysInbox);
+    sysInbox = cpystr ((char *) value);
+  case GET_SYSINBOX:
+    ret = (void *) sysInbox;
+    break;
+  case SET_LISTMAXLEVEL:
+    list_max_level = (long) value;
+  case GET_LISTMAXLEVEL:
+    ret = (void *) list_max_level;
+    break;
+
+  case SET_MBXPROTECTION:
+    mbx_protection = (long) value;
+  case GET_MBXPROTECTION:
+    ret = (void *) mbx_protection;
+    break;
+  case SET_DIRPROTECTION:
+    dir_protection = (long) value;
+  case GET_DIRPROTECTION:
+    ret = (void *) dir_protection;
+    break;
+  case SET_LOCKPROTECTION:
+    lock_protection = (long) value;
+  case GET_LOCKPROTECTION:
+    ret = (void *) lock_protection;
+    break;
+  case SET_FTPPROTECTION:
+    ftp_protection = (long) value;
+  case GET_FTPPROTECTION:
+    ret = (void *) ftp_protection;
+    break;
+  case SET_PUBLICPROTECTION:
+    public_protection = (long) value;
+  case GET_PUBLICPROTECTION:
+    ret = (void *) public_protection;
+    break;
+  case SET_SHAREDPROTECTION:
+    shared_protection = (long) value;
+  case GET_SHAREDPROTECTION:
+    ret = (void *) shared_protection;
+    break;
+  case SET_FTPDIRPROTECTION:
+    ftp_dir_protection = (long) value;
+  case GET_FTPDIRPROTECTION:
+    ret = (void *) ftp_dir_protection;
+    break;
+  case SET_PUBLICDIRPROTECTION:
+    public_dir_protection = (long) value;
+  case GET_PUBLICDIRPROTECTION:
+    ret = (void *) public_dir_protection;
+    break;
+  case SET_SHAREDDIRPROTECTION:
+    shared_dir_protection = (long) value;
+  case GET_SHAREDDIRPROTECTION:
+    ret = (void *) shared_dir_protection;
+    break;
+
+  case SET_LOCKTIMEOUT:
+    locktimeout = (long) value;
+  case GET_LOCKTIMEOUT:
+    ret = (void *) locktimeout;
+    break;
+  case SET_HIDEDOTFILES:
+    hideDotFiles = value ? T : NIL;
+  case GET_HIDEDOTFILES:
+    ret = (void *) (hideDotFiles ? VOIDT : NIL);
+    break;
+  case SET_DISABLEPLAINTEXT:
+    disablePlaintext = (long) value;
+  case GET_DISABLEPLAINTEXT:
+    ret = (void *) disablePlaintext;
+    break;
+  case SET_ADVERTISETHEWORLD:
+    advertisetheworld = value ? T : NIL;
+  case GET_ADVERTISETHEWORLD:
+    ret = (void *) (advertisetheworld ? VOIDT : NIL);
+    break;
+  case SET_DISABLEAUTOSHAREDNS:
+    noautomaticsharedns = value ? T : NIL;
+  case GET_DISABLEAUTOSHAREDNS:
+    ret = (void *) (noautomaticsharedns ? VOIDT : NIL);
+    break;
+  case SET_DISABLE822TZTEXT:
+    no822tztext = value ? T : NIL;
+  case GET_DISABLE822TZTEXT:
+    ret = (void *) (no822tztext ? VOIDT : NIL);
+    break;
+  case SET_USERHASNOLIFE:
+    has_no_life = value ? T : NIL;
+  case GET_USERHASNOLIFE:
+    ret = (void *) (has_no_life ? VOIDT : NIL);
+    break;
+  case SET_NETFSSTATBUG:
+    netfsstatbug = value ? T : NIL;
+  case GET_NETFSSTATBUG:
+    ret = (void *) (netfsstatbug ? VOIDT : NIL);
+    break;
+  case SET_BLOCKENVINIT:
+    block_env_init = value ? T : NIL;
+  case GET_BLOCKENVINIT:
+    ret = (void *) (block_env_init ? VOIDT : NIL);
+    break;
+  case SET_BLOCKNOTIFY:
+    mailblocknotify = (blocknotify_t) value;
+  case GET_BLOCKNOTIFY:
+    ret = (void *) mailblocknotify;
+    break;
+  }
+  return ret;
+}
+
+/* Write current time
+ * Accepts: destination string
+ *	    optional format of day-of-week prefix
+ *	    format of date and time
+ *	    flag whether to append symbolic timezone
+ */
+
+static void do_date (char *date,char *prefix,char *fmt,int suffix)
+{
+  time_t tn = time (0);
+  struct tm *t = gmtime (&tn);
+  int zone = t->tm_hour * 60 + t->tm_min;
+  int julian = t->tm_yday;
+  t = localtime (&tn);		/* get local time now */
+				/* minus UTC minutes since midnight */
+  zone = t->tm_hour * 60 + t->tm_min - zone;
+  /* julian can be one of:
+   *  36x  local time is December 31, UTC is January 1, offset -24 hours
+   *    1  local time is 1 day ahead of UTC, offset +24 hours
+   *    0  local time is same day as UTC, no offset
+   *   -1  local time is 1 day behind UTC, offset -24 hours
+   * -36x  local time is January 1, UTC is December 31, offset +24 hours
+   */
+  if (julian = t->tm_yday -julian)
+    zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
+  if (prefix) {			/* want day of week? */
+    sprintf (date,prefix,days[t->tm_wday]);
+    date += strlen (date);	/* make next sprintf append */
+  }
+				/* output the date */
+  sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
+	   t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
+				/* append timezone suffix if desired */
+  if (suffix) rfc822_timezone (date,(void *) t);
+}
+
+/* Write current time in RFC 822 format
+ * Accepts: destination string
+ */
+
+void rfc822_date (char *date)
+{
+  do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d",
+	   no822tztext ? NIL : T);
+}
+
+
+/* Write current time in fixed-width RFC 822 format
+ * Accepts: destination string
+ */
+
+void rfc822_fixed_date (char *date)
+{
+  do_date (date,NIL,"%02d %s %4d %02d:%02d:%02d %+03d%02d",NIL);
+}
+
+
+/* Write current time in internal format
+ * Accepts: destination string
+ */
+
+void internal_date (char *date)
+{
+  do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL);
+}
+
+/* Initialize server
+ * Accepts: server name for syslog or NIL
+ *	    /etc/services service name or NIL
+ *	    alternate /etc/services service name or NIL
+ *	    clock interrupt handler
+ *	    kiss-of-death interrupt handler
+ *	    hangup interrupt handler
+ *	    termination interrupt handler
+ */
+
+void server_init (char *server,char *service,char *sslservice,
+		  void *clkint,void *kodint,void *hupint,void *trmint,
+		  void *staint)
+{
+  int onceonly = server && service && sslservice;
+  if (onceonly) {		/* set server name in syslog */
+    int mask;
+    openlog (myServerName = cpystr (server),LOG_PID,syslog_facility);
+    fclose (stderr);		/* possibly save a process ID */
+
+    switch (mask = umask (022)){/* check old umask */
+    case 0:			/* definitely unreasonable */
+    case 022:			/* don't need to change it */
+      break;
+    default:			/* already was a reasonable value */
+      umask (mask);		/* so change it back */
+    }
+  }
+  arm_signal (SIGALRM,clkint);	/* prepare for clock interrupt */
+  arm_signal (SIGUSR2,kodint);	/* prepare for Kiss Of Death */
+  arm_signal (SIGHUP,hupint);	/* prepare for hangup */
+  arm_signal (SIGPIPE,hupint);	/* alternative hangup */
+  arm_signal (SIGTERM,trmint);	/* prepare for termination */
+				/* status dump */
+  if (staint) arm_signal (SIGUSR1,staint);
+  if (onceonly) {		/* set up network and maybe SSL */
+    long port;
+    struct servent *sv;
+    /* Use SSL if SSL service, or if server starts with "s" and not service */
+    if (((port = tcp_serverport ()) >= 0)) {
+      if ((sv = getservbyname (service,"tcp")) && (port == ntohs (sv->s_port)))
+	syslog (LOG_DEBUG,"%s service init from %s",service,tcp_clientaddr ());
+      else if ((sv = getservbyname (sslservice,"tcp")) &&
+	       (port == ntohs (sv->s_port))) {
+	syslog (LOG_DEBUG,"%s SSL service init from %s",sslservice,
+		tcp_clientaddr ());
+	ssl_server_init (server);
+      }
+      else {			/* not service or SSL service port */
+	syslog (LOG_DEBUG,"port %ld service init from %s",port,
+		tcp_clientaddr ());
+	if (*server == 's') ssl_server_init (server);
+      }
+    }
+  }
+}
+
+/* Wait for stdin input
+ * Accepts: timeout in seconds
+ * Returns: T if have input on stdin, else NIL
+ */
+
+long server_input_wait (long seconds)
+{
+  fd_set rfd,efd;
+  struct timeval tmo;
+  FD_ZERO (&rfd);
+  FD_ZERO (&efd);
+  FD_SET (0,&rfd);
+  FD_SET (0,&efd);
+  tmo.tv_sec = seconds; tmo.tv_usec = 0;
+  return select (1,&rfd,0,&efd,&tmo) ? LONGT : NIL;
+}
+
+/* Return Amiga password entry for user name
+ * Accepts: user name string
+ * Returns: password entry
+ *
+ * Tries all-lowercase form of user name if given user name fails
+ */
+
+static struct passwd *pwuser (unsigned char *user)
+{
+  unsigned char *s;
+  struct passwd *pw = getpwnam (user);
+  if (!pw) {			/* failed, see if any uppercase characters */
+    for (s = user; *s && ((*s < 'A') || (*s > 'Z')); s++);
+    if (*s) {			/* yes, try all lowercase form */
+      pw = getpwnam (s = lcase (cpystr (user)));
+      fs_give ((void **) &s);
+    }
+  }
+  return pw;
+}
+
+
+/* Validate password for user name
+ * Accepts: user name string
+ *	    password string
+ *	    argument count
+ *	    argument vector
+ * Returns: password entry if validated
+ *
+ * Tries password+1 if password fails and starts with space
+ */
+
+static struct passwd *valpwd (char *user,char *pwd,int argc,char *argv[])
+{
+  char *s;
+  struct passwd *pw;
+  struct passwd *ret = NIL;
+  if (auth_md5.server) {	/* using CRAM-MD5 authentication? */
+    if (s = auth_md5_pwd (user)) {
+      if (!strcmp (s,pwd) || ((*pwd == ' ') && pwd[1] && !strcmp (s,pwd+1)))
+	ret = pwuser (user);	/* validated, get passwd entry for user */
+      memset (s,0,strlen (s));	/* erase sensitive information */
+      fs_give ((void **) &s);
+    }
+  }
+  else if (pw = pwuser (user)) {/* can get user? */
+    s = cpystr (pw->pw_name);	/* copy returned name in case we need it */
+    if (*pwd && !(ret = checkpw (pw,pwd,argc,argv)) &&
+	(*pwd == ' ') && pwd[1] && (ret = pwuser (s)))
+      ret = checkpw (pw,pwd+1,argc,argv);
+    fs_give ((void **) &s);	/* don't need copy of name any more */
+  }
+  return ret;
+}
+
+/* Server log in
+ * Accepts: user name string
+ *	    password string
+ *	    authenticating user name string
+ *	    argument count
+ *	    argument vector
+ * Returns: T if password validated, NIL otherwise
+ */
+
+long server_login (char *user,char *pwd,char *authuser,int argc,char *argv[])
+{
+  struct passwd *pw = NIL;
+  int level = LOG_NOTICE;
+  char *err = "failed";
+				/* cretins still haven't given up */
+  if ((strlen (user) >= NETMAXUSER) ||
+      (authuser && (strlen (authuser) >= NETMAXUSER))) {
+    level = LOG_ALERT;		/* escalate this alert */
+    err = "SYSTEM BREAK-IN ATTEMPT";
+    logtry = 0;			/* render this session useless */
+  }
+  else if (logtry-- <= 0) err = "excessive login failures";
+  else if (disablePlaintext) err = "disabled";
+  else if (!(authuser && *authuser)) pw = valpwd (user,pwd,argc,argv);
+  else if (valpwd (authuser,pwd,argc,argv)) pw = pwuser (user);
+  if (pw && pw_login (pw,authuser,pw->pw_name,NIL,argc,argv)) return T;
+  syslog (level|LOG_AUTH,"Login %s user=%.64s auth=%.64s host=%.80s",err,
+	  user,(authuser && *authuser) ? authuser : user,tcp_clienthost ());
+  sleep (3);			/* slow down possible cracker */
+  return NIL;
+}
+
+/* Authenticated server log in
+ * Accepts: user name string
+ *	    authenticating user name string
+ *	    argument count
+ *	    argument vector
+ * Returns: T if password validated, NIL otherwise
+ */
+
+long authserver_login (char *user,char *authuser,int argc,char *argv[])
+{
+  return pw_login (pwuser (user),authuser,user,NIL,argc,argv);
+}
+
+
+/* Log in as anonymous daemon
+ * Accepts: argument count
+ *	    argument vector
+ * Returns: T if successful, NIL if error
+ */
+
+long anonymous_login (int argc,char *argv[])
+{
+				/* log in Mr. A. N. Onymous */
+  return pw_login (getpwnam (ANONYMOUSUSER),NIL,NIL,
+		   (char *) mail_parameters (NIL,GET_ANONYMOUSHOME,NIL),
+		   argc,argv);
+}
+
+/* Finish log in and environment initialization
+ * Accepts: passwd struct for loginpw()
+ *	    optional authentication user name
+ *	    user name (NIL for anonymous)
+ *	    home directory (NIL to use directory from passwd struct)
+ *	    argument count
+ *	    argument vector
+ * Returns: T if successful, NIL if error
+ */
+
+long pw_login (struct passwd *pw,char *auser,char *user,char *home,int argc,
+	       char *argv[])
+{
+  struct group *gr;
+  char **t;
+  long ret = NIL;
+  if (pw && pw->pw_uid) {	/* must have passwd struct for non-UID 0 */
+				/* make safe copies of user and home */
+    if (user) user = cpystr (pw->pw_name);
+    home = cpystr (home ? home : pw->pw_dir);
+				/* authorization ID .NE. authentication ID? */
+    if (user && auser && *auser && compare_cstring (auser,user)) {
+				/* scan list of mail administrators */
+      if ((gr = getgrnam (ADMINGROUP)) && (t = gr->gr_mem)) while (*t && !ret)
+	if (!compare_cstring (auser,*t++))
+	  ret = pw_login (pw,NIL,user,home,argc,argv);
+      syslog (LOG_NOTICE|LOG_AUTH,"%s %.80s override of user=%.80s host=%.80s",
+	      ret ? "Admin" : "Failed",auser,user,tcp_clienthost ());
+    }
+				/* normal login */
+    else if (((pw->pw_uid == geteuid ()) || loginpw (pw,argc,argv)) &&
+	     (ret = env_init (user,home))) chdir (myhomedir ());
+    fs_give ((void **) &home);	/* clean up */
+    if (user) fs_give ((void **) &user);
+  }
+  return ret;			/* return status */
+}
+
+/* Initialize environment
+ * Accepts: user name (NIL for anonymous)
+ *	    home directory name
+ * Returns: T, always
+ */
+
+long env_init (char *user,char *home)
+{
+  extern MAILSTREAM CREATEPROTO;
+  extern MAILSTREAM EMPTYPROTO;
+  struct passwd *pw;
+  struct stat sbuf;
+  char tmp[MAILTMPLEN];
+				/* don't init if blocked */
+  if (block_env_init) return LONGT;
+  if (myUserName) fatal ("env_init called twice!");
+				/* set up user name */
+  myUserName = cpystr (user ? user : ANONYMOUSUSER);
+  if (user) {			/* remember user name and home directory */
+    nslist[0] = &nshome;	/* home namespace */
+    nslist[1] = &nsamigaother;
+    nslist[2] = advertisetheworld ? &nsworld : &nsshared;
+  }
+  else {			/* anonymous user */
+    nslist[0] = nslist[1] = NIL,nslist[2] = &nsftp;
+    sprintf (tmp,"%s/INBOX",
+	     home = (char *) mail_parameters (NIL,GET_ANONYMOUSHOME,NIL));
+    sysInbox = cpystr (tmp);	/* make system INBOX */
+    anonymous = T;		/* flag as anonymous */
+  }
+  myHomeDir = cpystr (home);	/* set home directory */
+  if (!noautomaticsharedns) {
+				/* #ftp namespace */
+    if (!ftpHome && (pw = getpwnam ("ftp"))) ftpHome = cpystr (pw->pw_dir);
+				/* #public namespace */
+    if (!publicHome && (pw = getpwnam ("imappublic")))
+      publicHome = cpystr (pw->pw_dir);
+				/* #shared namespace */
+    if (!anonymous && !sharedHome && (pw = getpwnam ("imapshared")))
+      sharedHome = cpystr (pw->pw_dir);
+  }
+  if (!myLocalHost) mylocalhost ();
+  if (!myNewsrc) myNewsrc = cpystr(strcat (strcpy (tmp,myHomeDir),"/.newsrc"));
+  if (!newsActive) newsActive = cpystr (ACTIVEFILE);
+  if (!newsSpool) newsSpool = cpystr (NEWSSPOOL);
+				/* force default prototype to be set */
+  if (!createProto) createProto = &CREATEPROTO;
+  if (!appendProto) appendProto = &EMPTYPROTO;
+				/* re-do open action to get flags */
+  (*createProto->dtb->open) (NIL);
+  endpwent ();			/* close pw database */
+  return T;
+}
+ 
+/* Return my user name
+ * Accepts: pointer to optional flags
+ * Returns: my user name
+ */
+
+char *myusername_full (unsigned long *flags)
+{
+  struct passwd *pw;
+  struct stat sbuf;
+  char *s;
+  unsigned long euid;
+  char *ret = UNLOGGEDUSER;
+				/* no user name yet and not root? */
+  if (!myUserName && (euid = geteuid ())) {
+				/* yes, look up getlogin() user name or EUID */
+    if (((s = (char *) getlogin ()) && *s && (strlen (s) < NETMAXUSER) &&
+	 (pw = getpwnam (s)) && (pw->pw_uid == euid)) ||
+	(pw = getpwuid (euid))) {
+      if (block_env_init) {	/* don't env_init if blocked */
+	if (flags) *flags = MU_LOGGEDIN;
+	return pw->pw_name;
+      }
+      env_init (pw->pw_name,
+		((s = getenv ("HOME")) && *s && (strlen (s) < NETMAXMBX) &&
+		 !stat (s,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) ?
+		s : pw->pw_dir);
+    }
+    else fatal ("Unable to look up user name");
+  }
+  if (myUserName) {		/* logged in? */
+    if (flags) *flags = anonymous ? MU_ANONYMOUS : MU_LOGGEDIN;
+    ret = myUserName;		/* return user name */
+  }
+  else if (flags) *flags = MU_NOTLOGGEDIN;
+  return ret;
+}
+/* Return my local host name
+ * Returns: my local host name
+ */
+
+char *mylocalhost ()
+{
+  char tmp[MAILTMPLEN];
+  struct hostent *host_name;
+  if (!myLocalHost) myLocalHost = cpystr (gethostname (tmp,MAILTMPLEN-1) ?
+					  "random-pc" : tcp_canonical (tmp));
+  return myLocalHost;
+}
+
+/* Return my home directory name
+ * Returns: my home directory name
+ */
+
+char *myhomedir ()
+{
+  if (!myHomeDir) myusername ();/* initialize if first time */
+  return myHomeDir ? myHomeDir : "";
+}
+
+
+/* Return my home mailbox name
+ * Returns: my home directory name
+ */
+
+static char *mymailboxdir ()
+{
+  char *home = myhomedir ();
+  if (!myMailboxDir && home) {	/* initialize if first time */
+    if (mailsubdir) {
+      char tmp[MAILTMPLEN];
+      sprintf (tmp,"%s/%s",home,mailsubdir);
+      myMailboxDir = cpystr (tmp);/* use pre-defined subdirectory of home */
+    }
+    else myMailboxDir = cpystr (home);
+  }
+  return myMailboxDir ? myMailboxDir : "";
+}
+
+
+/* Return system standard INBOX
+ * Accepts: buffer string
+ */
+
+char *sysinbox ()
+{
+  char tmp[MAILTMPLEN];
+  if (!sysInbox) {		/* initialize if first time */
+    sprintf (tmp,"%s/%s",MAILSPOOL,myusername ());
+    sysInbox = cpystr (tmp);	/* system inbox is from mail spool */
+  }
+  return sysInbox;
+}
+
+/* Return mailbox directory name
+ * Accepts: destination buffer
+ *	    directory prefix
+ *	    name in directory
+ * Returns: file name or NIL if error
+ */
+
+char *mailboxdir (char *dst,char *dir,char *name)
+{
+  char tmp[MAILTMPLEN];
+  if (dir || name) {		/* if either argument provided */
+    if (dir) {
+      if (strlen (dir) > NETMAXMBX) return NIL;
+      strcpy (tmp,dir);		/* write directory prefix */
+    }
+    else tmp[0] = '\0';		/* otherwise null string */
+    if (name) {
+      if (strlen (name) > NETMAXMBX) return NIL;
+      strcat (tmp,name);	/* write name in directory */
+    }
+				/* validate name, return its name */
+    if (!mailboxfile (dst,tmp)) return NIL;
+  }
+				/* no arguments, wants mailbox directory */
+  else strcpy (dst,mymailboxdir ());
+  return dst;			/* return the name */
+}
+
+/* Return mailbox file name
+ * Accepts: destination buffer
+ *	    mailbox name
+ * Returns: file name or empty string for driver-selected INBOX or NIL if error
+ */
+
+char *mailboxfile (char *dst,char *name)
+{
+  struct passwd *pw;
+  char *s;
+  if (!name || !*name || (*name == '{') || (strlen (name) > NETMAXMBX) ||
+      ((anonymous || restrictBox || (*name == '#')) &&
+       (strstr (name,"..") || strstr (name,"//") || strstr (name,"/~"))))
+    dst = NIL;			/* invalid name */
+  else switch (*name) {		/* determine mailbox type based upon name */
+  case '#':			/* namespace name */
+				/* #ftp/ namespace */
+    if (((name[1] == 'f') || (name[1] == 'F')) &&
+	((name[2] == 't') || (name[2] == 'T')) &&
+	((name[3] == 'p') || (name[3] == 'P')) &&
+	(name[4] == '/') && ftpHome) sprintf (dst,"%s/%s",ftpHome,name+5);
+				/* #public/ and #shared/ namespaces */
+    else if ((((name[1] == 'p') || (name[1] == 'P')) &&
+	      ((name[2] == 'u') || (name[2] == 'U')) &&
+	      ((name[3] == 'b') || (name[3] == 'B')) &&
+	      ((name[4] == 'l') || (name[4] == 'L')) &&
+	      ((name[5] == 'i') || (name[5] == 'I')) &&
+	      ((name[6] == 'c') || (name[6] == 'C')) &&
+	      (name[7] == '/') && (s = publicHome)) ||
+	     (!anonymous && ((name[1] == 's') || (name[1] == 'S')) &&
+	      ((name[2] == 'h') || (name[2] == 'H')) &&
+	      ((name[3] == 'a') || (name[3] == 'A')) &&
+	      ((name[4] == 'r') || (name[4] == 'R')) &&
+	      ((name[5] == 'e') || (name[5] == 'E')) &&
+	      ((name[6] == 'd') || (name[6] == 'D')) &&
+	      (name[7] == '/') && (s = sharedHome)))
+      sprintf (dst,"%s/%s",s,compare_cstring (name,"INBOX") ? name : "INBOX");
+    else dst = NIL;		/* unknown namespace */
+    break;
+
+  case '/':			/* root access */
+    if (anonymous) dst = NIL;	/* anonymous forbidden to do this */
+    else if ((restrictBox & RESTRICTROOT) && strcmp (name,sysinbox ()))
+      dst = NIL;		/* restricted and not access to sysinbox */
+    else strcpy (dst,name);	/* unrestricted, copy root name */
+    break;
+  case '~':			/* other user access */
+				/* bad syntax or anonymous can't win */
+    if (!*++name || anonymous) dst = NIL;
+				/* ~/ equivalent to ordinary name */
+    else if (*name == '/') sprintf (dst,"%s/%s",mymailboxdir (),name+1);
+				/* other user forbidden if restricted */
+    else if (restrictBox & RESTRICTOTHERUSER) dst = NIL;
+    else {			/* clear box other user */
+				/* copy user name */
+      for (s = dst; *name && (*name != '/'); *s++ = *name++);
+      *s++ = '\0';		/* tie off user name, look up in passwd file */
+      if ((pw = getpwnam (dst)) && pw->pw_dir) {
+	if (*name) name++;	/* skip past the slash */
+				/* canonicalize case of INBOX */
+	if (!compare_cstring (name,"INBOX")) name = "INBOX";
+				/* remove trailing / from directory */
+	if ((s = strrchr (pw->pw_dir,'/')) && !s[1]) *s = '\0';
+				/* don't allow ~root/ if restricted root */
+	if ((restrictBox & RESTRICTROOT) && !*pw->pw_dir) dst = NIL;
+				/* build final name w/ subdir if needed */
+	else if (mailsubdir) sprintf (dst,"%s/%s/%s",pw->pw_dir,mailsubdir,name);
+	else sprintf (dst,"%s/%s",pw->pw_dir,name);
+      }
+      else dst = NIL;		/* no such user */
+    }
+    break;
+  case 'I': case 'i':		/* possible INBOX */
+    if (!compare_cstring (name+1,"NBOX")) {
+				/* if anonymous, use INBOX in mailbox dir */
+      if (anonymous) sprintf (dst,"%s/INBOX",mymailboxdir ());
+      else *dst = '\0';		/* otherwise driver selects the name */
+      break;
+    }
+				/* drop into to ordinary name case */
+  default:			/* ordinary name is easy */
+    sprintf (dst,"%s/%s",mymailboxdir (),name);
+    break;
+  }
+  return dst;			/* return final name */
+}
+
+/* Dot-lock file locker
+ * Accepts: file name to lock
+ *	    destination buffer for lock file name
+ *	    open file description on file name to lock
+ * Returns: T if success, NIL if failure
+ */
+
+long dotlock_lock (char *file,DOTLOCK *base,int fd)
+{
+  int i = locktimeout * 60;
+  int j,mask,retry,pi[2],po[2];
+  char *s,tmp[MAILTMPLEN];
+  struct stat sb;
+				/* flush absurd file name */
+  if (strlen (file) > 512) return NIL;
+				/* build lock filename */
+  sprintf (base->lock,"%s.lock",file);
+				/* assume no pipe */
+  base->pipei = base->pipeo = -1;
+  do {				/* make sure not symlink */
+    if (!(j = chk_notsymlink (base->lock,&sb))) return NIL;
+				/* time out if file older than 5 minutes */
+    if ((j > 0) && ((time (0)) >= (sb.st_ctime + locktimeout * 60))) i = 0;
+				/* try to create the lock */
+    if ((j = open (name,O_WRONLY|O_CREAT|O_EXCL,(int) lock_protection)) >= 0) {
+      close (i);		/* make the file, now close it */
+      chmod (base->lock,(int) lock_protection);
+      return LONGT;
+    }
+    if (errno == EEXIST) {	/* already locked? */
+      retry = -1;		/* can try again */
+      if (!(i%15)) {		/* time to notify? */
+	sprintf (tmp,"Mailbox %.80s is locked, will override in %d seconds...",
+		 file,i);
+	mm_log (tmp,WARN);
+      }
+      sleep (1);		/* wait 1 second before next try */
+    }
+    else retry = i = 0;		/* hard failure, no more retries */
+  } while (i--);		/* until out of retries */
+  if (retry < 0) {		/* still returning retry after locktimeout? */
+    if (!(j = chk_notsymlink (base->lock,&sb))) return NIL;
+    if ((j > 0) && ((time (0)) < (sb.st_ctime + locktimeout * 60))) {
+      sprintf (tmp,"Mailbox vulnerable - seizing %ld second old lock",
+	       (long) (time (0) - sb.st_ctime));
+      mm_log (tmp,WARN);
+    }
+    mask = umask (0);
+    unlink (base->lock);	/* try to remove the old file */
+				/* seize the lock */
+    if ((i = open (base->lock,O_WRONLY|O_CREAT,(int) lock_protection)) >= 0) {
+      close (i);		/* don't need descriptor any more */
+      sprintf (tmp,"Mailbox %.80s lock overridden",file);
+      mm_log (tmp,NIL);
+      chmod (base->lock,(int) lock_protection);
+      umask (mask)		/* restore old umask */
+      return LONGT;
+    }
+    umask (mask)		/* restore old umask */
+  }
+
+  if (fd >= 0) switch (errno) {
+  case EACCES:			/* protection failure? */
+				/* make command pipes */
+    if (!stat (LOCKPGM,&sb) && (pipe (pi) >= 0)) {
+				/* if input pipes usable create output pipes */
+      if ((pi[0] < FD_SETSIZE) && (pi[1] < FD_SETSIZE) && (pipe (po) >= 0)) {
+				/* make sure output pipes are usable */
+	if ((po[0] >= FD_SETSIZE) || (po[1] >= FD_SETSIZE));
+				/* all is good, make inferior process */
+	else if (!(j = fork ())) {
+	  if (!fork ()) {	/* make grandchild so it's inherited by init */
+	    long cf;		/* don't change caller vars in case vfork() */
+	    char *argv[4],arg[20];
+				/* prepare argument vector */
+	    sprintf (arg,"%d",fd);
+	    argv[0] = LOCKPGM; argv[1] = arg;
+	    argv[2] = file; argv[3] = NIL;
+				/* set parent's I/O to my O/I */
+	    dup2 (pi[1],1); dup2 (pi[1],2); dup2 (po[0],0);
+				/* close all unnecessary descriptors */
+	    for (cf = max (20,max (max (pi[0],pi[1]),max(po[0],po[1])));
+		 cf >= 3; --cf) if (cf != fd) close (cf);
+				/* be our own process group */
+	    setpgrp (0,getpid ());
+				/* now run it */
+	    _exit (execv (argv[0],argv));
+	  }
+	  _exit (1);		/* child is done */
+	}
+	else if (j > 0) {	/* parent process */
+	  fd_set rfd;
+	  struct timeval tmo;
+	  FD_ZERO (&rfd);
+	  FD_SET (pi[0],&rfd);
+	  tmo.tv_sec = locktimeout * 60;
+	  grim_pid_reap (j,NIL);/* reap child; grandchild now owned by init */
+				/* read response from locking program */
+	  if (select (pi[0]+1,&rfd,0,0,&tmo) &&
+	      (read (pi[0],tmp,1) == 1) && (tmp[0] == '+')) {
+				/* success, record pipes */
+	    base->pipei = pi[0]; base->pipeo = po[1];
+				/* close child's side of the pipes */
+	    close (pi[1]); close (po[0]);
+	    return LONGT;
+	  }
+	}
+	close (po[0]); close (po[1]);
+      }
+      close (pi[0]); close (pi[1]);
+    }
+				/* find directory/file delimiter */
+    if (s = strrchr (base->lock,'/')) {
+      *s = '\0';		/* tie off at directory */
+      sprintf(tmp,		/* generate default message */
+	      "Mailbox vulnerable - directory %.80s must have 1777 protection",
+	      base->lock);
+				/* definitely not 1777 if can't stat */
+      mask = stat (base->lock,&sb) ? 0 : (sb.st_mode & 1777);
+      *s = '/';			/* restore lock name */
+      if (mask != 1777) {	/* default warning if not 1777 */
+	MM_LOG (tmp,WARN);
+	break;
+      }
+    }
+  default:
+    sprintf (tmp,"Mailbox vulnerable - error creating %.80s: %s",
+	     base->lock,strerror (errno));
+    mm_log (tmp,WARN);		/* this is probably not good */
+    break;
+  }
+  base->lock[0] = '\0';		/* don't use lock files */
+  return NIL;
+}
+
+/* Dot-lock file unlocker
+ * Accepts: lock file name
+ * Returns: T if success, NIL if failure
+ */
+
+long dotlock_unlock (DOTLOCK *base)
+{
+  long ret = LONGT;
+  if (base && base->lock[0]) {
+    if (base->pipei >= 0) {	/* if running through a pipe unlocker */
+      ret = (write (base->pipeo,"+",1) == 1);
+				/* nuke the pipes */
+      close (base->pipei); close (base->pipeo);
+    }
+    else ret = !unlink (base->lock);
+  }
+  return ret;
+}
+
+/* Lock file name
+ * Accepts: scratch buffer
+ *	    file name
+ *	    type of locking operation (LOCK_SH or LOCK_EX)
+ *	    pointer to return PID of locker
+ * Returns: file descriptor of lock or negative if error
+ */
+
+int lockname (char *lock,char *fname,int op,long *pid)
+{
+  struct stat sbuf;
+  *pid = 0;			/* no locker PID */
+  return stat (fname,&sbuf) ? -1 : lock_work (lock,&sbuf,op,pid);
+}
+
+
+/* Lock file descriptor
+ * Accepts: file descriptor
+ *	    lock file name buffer
+ *	    type of locking operation (LOCK_SH or LOCK_EX)
+ * Returns: file descriptor of lock or negative if error
+ */
+
+int lockfd (int fd,char *lock,int op)
+{
+  struct stat sbuf;
+  return fstat (fd,&sbuf) ? -1 : lock_work (lock,&sbuf,op,NIL);
+}
+
+/* Lock file name worker
+ * Accepts: lock file name
+ *	    pointer to stat() buffer
+ *	    type of locking operation (LOCK_SH or LOCK_EX)
+ *	    pointer to return PID of locker
+ * Returns: file descriptor of lock or negative if error
+ */
+
+int lock_work (char *lock,void *sb,int op,long *pid)
+{
+  struct stat lsb,fsb;
+  struct stat *sbuf = (struct stat *) sb;
+  char tmp[MAILTMPLEN];
+  long i;
+  int fd;
+  int mask = umask (0);
+  if (pid) *pid = 0;		/* initialize return PID */
+				/* make temporary lock file name */
+  sprintf (lock,"%s/.%lx.%lx","/tmp",
+	   (unsigned long) sbuf->st_dev,(unsigned long) sbuf->st_ino);
+  while (T) {			/* until get a good lock */
+    do switch ((int) chk_notsymlink (lock,&lsb)) {
+    case 1:			/* exists just once */
+      if (((fd = open (lock,O_RDWR,lock_protection)) >= 0) ||
+	  (errno != ENOENT) || (chk_notsymlink (lock,&lsb) >= 0)) break;
+    case -1:			/* name doesn't exist */
+      fd = open (lock,O_RDWR|O_CREAT|O_EXCL,lock_protection);
+      break;
+    default:			/* multiple hard links */
+      mm_log ("hard link to lock name",ERROR);
+      syslog (LOG_CRIT,"SECURITY PROBLEM: hard link to lock name: %.80s",lock);
+    case 0:			/* symlink (already did syslog) */
+      umask (mask);		/* restore old mask */
+      return -1;		/* fail: no lock file */
+    } while ((fd < 0) && (errno == EEXIST));
+    if (fd < 0) {		/* failed to get file descriptor */
+      syslog (LOG_INFO,"Mailbox lock file %s open failure: %s",lock,
+	      strerror (errno));
+      if (stat ("/tmp",&lsb))
+	syslog (LOG_CRIT,"SYSTEM ERROR: no /tmp: %s",strerror (errno));
+      else if ((lsb.st_mode & 01777) != 01777)
+	mm_log ("Can't lock for write: /tmp must have 1777 protection",WARN);
+      umask (mask);		/* restore old mask */
+      return -1;		/* fail: can't open lock file */
+    }
+
+				/* non-blocking form */
+    if (op & LOCK_NB) i = flock (fd,op);
+    else {			/* blocking form */
+      (*mailblocknotify) (BLOCK_FILELOCK,NIL);
+      i = flock (fd,op);
+      (*mailblocknotify) (BLOCK_NONE,NIL);
+    }
+    if (i) {			/* failed, get other process' PID */
+      if (pid && !fstat (fd,&fsb) && (i = min (fsb.st_size,MAILTMPLEN-1)) &&
+	  (read (fd,tmp,i) == i) && !(tmp[i] = 0) && ((i = atol (tmp)) > 0))
+	*pid = i;
+      close (fd);		/* failed, give up on lock */
+      umask (mask);		/* restore old mask */
+      return -1;		/* fail: can't lock */
+    }
+				/* make sure this lock is good for us */
+    if (!lstat (lock,&lsb) && ((lsb.st_mode & S_IFMT) != S_IFLNK) &&
+	!fstat (fd,&fsb) && (lsb.st_dev == fsb.st_dev) &&
+	(lsb.st_ino == fsb.st_ino) && (fsb.st_nlink == 1)) break;
+    close (fd);			/* lock not right, drop fd and try again */
+  }
+				/* make sure mode OK (don't use fchmod()) */
+  chmod (lock,(int) lock_protection);
+  umask (mask);			/* restore old mask */
+  return fd;			/* success */
+}
+
+/* Check to make sure not a symlink
+ * Accepts: file name
+ *	    stat buffer
+ * Returns: -1 if doesn't exist, NIL if symlink, else number of hard links
+ */
+
+long chk_notsymlink (char *name,void *sb)
+{
+  struct stat *sbuf = (struct stat *) sb;
+				/* name exists? */
+  if (lstat (name,sbuf)) return -1;
+				/* forbid symbolic link */
+  if ((sbuf->st_mode & S_IFMT) == S_IFLNK) {
+    mm_log ("symbolic link on lock name",ERROR);
+    syslog (LOG_CRIT,"SECURITY PROBLEM: symbolic link on lock name: %.80s",
+	    name);
+    return NIL;
+  }
+  return (long) sbuf->st_nlink;	/* return number of hard links */
+}
+
+
+/* Unlock file descriptor
+ * Accepts: file descriptor
+ *	    lock file name from lockfd()
+ */
+
+void unlockfd (int fd,char *lock)
+{
+				/* delete the file if no sharers */
+  if (!flock (fd,LOCK_EX|LOCK_NB)) unlink (lock);
+  flock (fd,LOCK_UN);		/* unlock it */
+  close (fd);			/* close it */
+}
+
+/* Set proper file protection for mailbox
+ * Accepts: mailbox name
+ *	    actual file path name
+ * Returns: T, always
+ */
+
+long set_mbx_protections (char *mailbox,char *path)
+{
+  struct stat sbuf;
+  int mode = (int) mbx_protection;
+  if (*mailbox == '#') {	/* possible namespace? */
+      if (((mailbox[1] == 'f') || (mailbox[1] == 'F')) &&
+	  ((mailbox[2] == 't') || (mailbox[2] == 'T')) &&
+	  ((mailbox[3] == 'p') || (mailbox[3] == 'P')) &&
+	  (mailbox[4] == '/')) mode = (int) ftp_protection;
+      else if (((mailbox[1] == 'p') || (mailbox[1] == 'P')) &&
+	       ((mailbox[2] == 'u') || (mailbox[2] == 'U')) &&
+	       ((mailbox[3] == 'b') || (mailbox[3] == 'B')) &&
+	       ((mailbox[4] == 'l') || (mailbox[4] == 'L')) &&
+	       ((mailbox[5] == 'i') || (mailbox[5] == 'I')) &&
+	       ((mailbox[6] == 'c') || (mailbox[6] == 'C')) &&
+	       (mailbox[7] == '/')) mode = (int) public_protection;
+      else if (((mailbox[1] == 's') || (mailbox[1] == 'S')) &&
+	       ((mailbox[2] == 'h') || (mailbox[2] == 'H')) &&
+	       ((mailbox[3] == 'a') || (mailbox[3] == 'A')) &&
+	       ((mailbox[4] == 'r') || (mailbox[4] == 'R')) &&
+	       ((mailbox[5] == 'e') || (mailbox[5] == 'E')) &&
+	       ((mailbox[6] == 'd') || (mailbox[6] == 'D')) &&
+	       (mailbox[7] == '/')) mode = (int) shared_protection;
+  }
+				/* if a directory */
+  if (!stat (path,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) {
+				/* set owner search if allow read or write */
+    if (mode & 0600) mode |= 0100;
+    if (mode & 060) mode |= 010;/* set group search if allow read or write */
+    if (mode & 06) mode |= 01;	/* set world search if allow read or write */
+				/* preserve directory SGID bit */
+    if (sbuf.st_mode & S_ISGID) mode |= S_ISGID;
+  }
+  chmod (path,mode);		/* set the new protection, ignore failure */
+  return LONGT;
+}
+
+/* Get proper directory protection
+ * Accepts: mailbox name
+ * Returns: directory mode, always
+ */
+
+long get_dir_protection (char *mailbox)
+{
+  if (*mailbox == '#') {	/* possible namespace? */
+      if (((mailbox[1] == 'f') || (mailbox[1] == 'F')) &&
+	  ((mailbox[2] == 't') || (mailbox[2] == 'T')) &&
+	  ((mailbox[3] == 'p') || (mailbox[3] == 'P')) &&
+	  (mailbox[4] == '/')) return ftp_dir_protection;
+      else if (((mailbox[1] == 'p') || (mailbox[1] == 'P')) &&
+	       ((mailbox[2] == 'u') || (mailbox[2] == 'U')) &&
+	       ((mailbox[3] == 'b') || (mailbox[3] == 'B')) &&
+	       ((mailbox[4] == 'l') || (mailbox[4] == 'L')) &&
+	       ((mailbox[5] == 'i') || (mailbox[5] == 'I')) &&
+	       ((mailbox[6] == 'c') || (mailbox[6] == 'C')) &&
+	       (mailbox[7] == '/')) return public_dir_protection;
+      else if (((mailbox[1] == 's') || (mailbox[1] == 'S')) &&
+	       ((mailbox[2] == 'h') || (mailbox[2] == 'H')) &&
+	       ((mailbox[3] == 'a') || (mailbox[3] == 'A')) &&
+	       ((mailbox[4] == 'r') || (mailbox[4] == 'R')) &&
+	       ((mailbox[5] == 'e') || (mailbox[5] == 'E')) &&
+	       ((mailbox[6] == 'd') || (mailbox[6] == 'D')) &&
+	       (mailbox[7] == '/')) return shared_dir_protection;
+  }
+  return dir_protection;
+}
+
+/* Determine default prototype stream to user
+ * Accepts: type (NIL for create, T for append)
+ * Returns: default prototype stream
+ */
+
+MAILSTREAM *default_proto (long type)
+{
+  myusername ();		/* make sure initialized */
+				/* return default driver's prototype */
+  return type ? appendProto : createProto;
+}
+
+
+/* Set up user flags for stream
+ * Accepts: MAIL stream
+ * Returns: MAIL stream with user flags set up
+ */
+
+MAILSTREAM *user_flags (MAILSTREAM *stream)
+{
+  int i;
+  myusername ();		/* make sure initialized */
+  for (i = 0; i < NUSERFLAGS && userFlags[i]; ++i)
+    if (!stream->user_flags[i]) stream->user_flags[i] = cpystr (userFlags[i]);
+  return stream;
+}
+
+
+/* Return nth user flag
+ * Accepts: user flag number
+ * Returns: flag
+ */
+
+char *default_user_flag (unsigned long i)
+{
+  myusername ();		/* make sure initialized */
+  return userFlags[i];
+}
+
+/* Default block notify routine
+ * Accepts: reason for calling
+ *	    data
+ * Returns: data
+ */
+
+void *mm_blocknotify (int reason,void *data)
+{
+  void *ret = data;
+  switch (reason) {
+  case BLOCK_SENSITIVE:		/* entering sensitive code */
+    ret = (void *) alarm (0);
+    break;
+  case BLOCK_NONSENSITIVE:	/* exiting sensitive code */
+    if ((unsigned int) data) alarm ((unsigned int) data);
+    break;
+  default:			/* ignore all other reasons */
+    break;
+  }
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/env_ami.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,95 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX environment routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+typedef struct dotlock_base {
+  char lock[MAILTMPLEN];
+  int pipei;
+  int pipeo;
+} DOTLOCK;
+
+
+/* Bits that can be set in restrictBox */
+
+#define RESTRICTROOT 0x1	/* restricted box doesn't allow root */
+#define RESTRICTOTHERUSER 0x2	/* restricted box doesn't allow other user */
+
+/* Subscription definitions for UNIX */
+
+#define SUBSCRIPTIONFILE(t) sprintf (t,"%s/.mailboxlist",myhomedir ())
+#define SUBSCRIPTIONTEMP(t) sprintf (t,"%s/.mlbxlsttmp",myhomedir ())
+
+
+/* dorc() options */
+
+#define SYSCONFIG "/etc/c-client.cf"
+
+
+/* Special users */
+
+#define ANONYMOUSUSER "nobody"	/* anonymous user */
+#define UNLOGGEDUSER "root"	/* unlogged-in user */
+#define ADMINGROUP "mailadm"	/* mail administrator group */
+
+/* Function prototypes */
+
+#include "env.h"
+
+void rfc822_fixed_date (char *date);
+long env_init (char *user,char *home);
+char *myusername_full (unsigned long *flags);
+#define MU_LOGGEDIN 0
+#define MU_NOTLOGGEDIN 1
+#define MU_ANONYMOUS 2
+#define myusername() \
+  myusername_full (NIL)
+char *sysinbox ();
+char *mailboxdir (char *dst,char *dir,char *name);
+long dotlock_lock (char *file,DOTLOCK *base,int fd);
+long dotlock_unlock (DOTLOCK *base);
+int lockname (char *lock,char *fname,int op,long *pid);
+int lockfd (int fd,char *lock,int op);
+int lock_work (char *lock,void *sbuf,int op,long *pid);
+long chk_notsymlink (char *name,void *sbuf);
+void unlockfd (int fd,char *lock);
+long set_mbx_protections (char *mailbox,char *path);
+long get_dir_protection (char *mailbox);
+MAILSTREAM *user_flags (MAILSTREAM *stream);
+char *default_user_flag (unsigned long i);
+void dorc (char *file,long flag);
+long path_create (MAILSTREAM *stream,char *mailbox);
+void grim_pid_reap_status (int pid,int killreq,void *status);
+#define grim_pid_reap(pid,killreq) \
+  grim_pid_reap_status (pid,killreq,NIL)
+long safe_write (int fd,char *buf,long nbytes);
+void *arm_signal (int sig,void *action);
+struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]);
+long loginpw (struct passwd *pw,int argc,char *argv[]);
+long pw_login (struct passwd *pw,char *auser,char *user,char *home,int argc,
+	       char *argv[]);
+void *mm_blocknotify (int reason,void *data);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/fdstring.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,99 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	File descriptor string routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	15 April 1997
+ * Last Edited:	4 April 2007
+ */
+
+#include "mail.h"
+#include "osdep.h"
+#include "misc.h"
+#include "fdstring.h"
+
+/* String driver for fd stringstructs */
+
+static void fd_string_init (STRING *s,void *data,unsigned long size);
+static char fd_string_next (STRING *s);
+static void fd_string_setpos (STRING *s,unsigned long i);
+
+STRINGDRIVER fd_string = {
+  fd_string_init,		/* initialize string structure */
+  fd_string_next,		/* get next byte in string structure */
+  fd_string_setpos		/* set position in string structure */
+};
+
+
+/* Initialize string structure for fd stringstruct
+ * Accepts: string structure
+ *	    pointer to string
+ *	    size of string
+ */
+
+static void fd_string_init (STRING *s,void *data,unsigned long size)
+{
+  FDDATA *d = (FDDATA *) data;
+				/* note fd */
+  s->data = (void *) (unsigned long) d->fd;
+  s->data1 = d->pos;		/* note file offset */
+  s->size = size;		/* note size */
+  s->curpos = s->chunk = d->chunk;
+  s->chunksize = (unsigned long) d->chunksize;
+  s->offset = 0;		/* initial position */
+				/* and size of data */
+  s->cursize = min (s->chunksize,size);
+				/* move to that position in the file */
+  lseek (d->fd,d->pos,L_SET);
+  read (d->fd,s->chunk,(size_t) s->cursize);
+}
+
+/* Get next character from fd stringstruct
+ * Accepts: string structure
+ * Returns: character, string structure chunk refreshed
+ */
+
+static char fd_string_next (STRING *s)
+{
+  char c = *s->curpos++;	/* get next byte */
+  SETPOS (s,GETPOS (s));	/* move to next chunk */
+  return c;			/* return the byte */
+}
+
+
+/* Set string pointer position for fd stringstruct
+ * Accepts: string structure
+ *	    new position
+ */
+
+static void fd_string_setpos (STRING *s,unsigned long i)
+{
+  if (i > s->size) i = s->size;	/* don't permit setting beyond EOF */
+  s->offset = i;		/* set new offset */
+  s->curpos = s->chunk;		/* reset position */
+				/* set size of data */
+  if (s->cursize = min (s->chunksize,SIZE (s))) {
+				/* move to that position in the file */
+    lseek ((long) s->data,s->data1 + s->offset,L_SET);
+    read ((long) s->data,s->curpos,(size_t) s->cursize);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/fdstring.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,39 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	File descriptor string routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	15 April 1997
+ * Last Edited:	30 August 2006
+ */
+
+/* Driver-dependent data passed to init method */
+
+typedef struct fd_data {
+  int fd;			/* file descriptor */
+  unsigned long pos;		/* initial position */
+  char *chunk;			/* I/O buffer chunk */
+  unsigned long chunksize;	/* I/O buffer chunk length */
+} FDDATA;
+
+
+extern STRINGDRIVER fd_string;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/fs_ami.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,71 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Free storage management routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Get a block of free storage
+ * Accepts: size of desired block
+ * Returns: free storage block
+ */
+
+void *fs_get (size_t size)
+{
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  void *data = (*bn) (BLOCK_SENSITIVE,NIL);
+  void *block = malloc (size ? size : (size_t) 1);
+  if (!block) fatal ("Out of memory");
+  (*bn) (BLOCK_NONSENSITIVE,data);
+  return (block);
+}
+
+
+/* Resize a block of free storage
+ * Accepts: ** pointer to current block
+ *	    new size
+ */
+
+void fs_resize (void **block,size_t size)
+{
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  void *data = (*bn) (BLOCK_SENSITIVE,NIL);
+  if (!(*block = realloc (*block,size ? size : (size_t) 1)))
+    fatal ("Can't resize memory");
+  (*bn) (BLOCK_NONSENSITIVE,data);
+}
+
+
+/* Return a block of free storage
+ * Accepts: ** pointer to free storage block
+ */
+
+void fs_give (void **block)
+{
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  void *data = (*bn) (BLOCK_SENSITIVE,NIL);
+  free (*block);
+  *block = NIL;
+  (*bn) (BLOCK_NONSENSITIVE,data);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/ftl_ami.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,38 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	DOS/VMS/TOPS-20 crash management routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Report a fatal error
+ * Accepts: string to output
+ */
+
+void fatal (char *string)
+{
+  mm_fatal (string);		/* pass up the string */
+  abort ();			/* die horribly */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/gethstid.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,38 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Get host ID emulator
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	3 May 1995
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Emulator for BSD gethostid() call
+ * Returns: unique identifier for this machine
+ */
+
+long gethostid (void)
+{
+  /* No gethostid() here, so just fake it and hope things turn out okay. */
+  return 0xdeadface;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/gr_waitp.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,39 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX Grim PID Reaper -- waitpid() version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	30 November 1993
+ * Last Edited:	30 August 2006
+ */
+ 
+/* Grim PID reaper
+ * Accepts: process ID
+ *	    kill request flag
+ *	    status return value
+ */
+
+void grim_pid_reap_status (int pid,int killreq,void *status)
+{
+  if (killreq) kill(pid,SIGHUP);/* kill if not already dead */
+  while ((waitpid (pid,status,NIL) < 0) && (errno != ECHILD));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/log_std.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,44 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Standard login
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Log in
+ * Accepts: login passwd struct
+ *	    argument count
+ *	    argument vector
+ * Returns: T if success, NIL otherwise
+ */
+
+long loginpw (struct passwd *pw,int argc,char *argv[])
+{
+  uid_t uid = pw->pw_uid;
+  char *name = cpystr (pw->pw_name);
+  long ret = !(setgid (pw->pw_gid) || initgroups (name,pw->pw_gid) ||
+	       setuid (uid));
+  fs_give ((void **) &name);
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/mbx.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1855 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	MBX mail routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	3 October 1995
+ * Last Edited:	11 October 2007
+ */
+
+
+/*				FILE TIME SEMANTICS
+ *
+ * The atime is the last read time of the file.
+ * The mtime is the last flags update time of the file.
+ * The ctime is the last write time of the file.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "mail.h"
+#include "osdep.h"
+#include <pwd.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "misc.h"
+#include "dummy.h"
+#include "fdstring.h"
+
+
+/* Build parameters */
+
+#define HDRSIZE 2048
+
+
+/* Kludge to make Cygwin happy */
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+/* MBX I/O stream local data */
+	
+typedef struct mbx_local {
+  unsigned int flagcheck: 1;	/* if ping should sweep for flags */
+  unsigned int expok: 1;	/* if expunging OK in ping */
+  unsigned int expunged : 1;	/* if one or more expunged messages */
+  int fd;			/* file descriptor for I/O */
+  int ld;			/* lock file descriptor */
+  int ffuserflag;		/* first free user flag */
+  off_t filesize;		/* file size parsed */
+  time_t filetime;		/* last file time */
+  time_t lastsnarf;		/* last snarf time */
+  unsigned long lastpid;	/* PID of last writer */
+  unsigned char *buf;		/* temporary buffer */
+  unsigned long buflen;		/* current size of temporary buffer */
+  char lock[MAILTMPLEN];	/* buffer to write lock name */
+} MBXLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((MBXLOCAL *) stream->local)
+
+/* Function prototypes */
+
+DRIVER *mbx_valid (char *name);
+int mbx_isvalid (MAILSTREAM **stream,char *name,char *tmp,int *ld,char *lock,
+		 long flags);
+void *mbx_parameters (long function,void *value);
+void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void mbx_list (MAILSTREAM *stream,char *ref,char *pat);
+void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long mbx_create (MAILSTREAM *stream,char *mailbox);
+long mbx_delete (MAILSTREAM *stream,char *mailbox);
+long mbx_rename (MAILSTREAM *stream,char *old,char *newname);
+long mbx_status (MAILSTREAM *stream,char *mbx,long flags);
+MAILSTREAM *mbx_open (MAILSTREAM *stream);
+void mbx_close (MAILSTREAM *stream,long options);
+void mbx_abort (MAILSTREAM *stream);
+void mbx_flags (MAILSTREAM *stream,char *sequence,long flags);
+char *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
+		  long flags);
+long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
+void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
+long mbx_ping (MAILSTREAM *stream);
+void mbx_check (MAILSTREAM *stream);
+long mbx_expunge (MAILSTREAM *stream,char *sequence,long options);
+void mbx_snarf (MAILSTREAM *stream);
+long mbx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long mbx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+char *mbx_file (char *dst,char *name);
+long mbx_parse (MAILSTREAM *stream);
+MESSAGECACHE *mbx_elt (MAILSTREAM *stream,unsigned long msgno,long expok);
+unsigned long mbx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt);
+void mbx_update_header (MAILSTREAM *stream);
+void mbx_update_status (MAILSTREAM *stream,unsigned long msgno,long flags);
+unsigned long mbx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			  unsigned long *size,char **hdr);
+unsigned long mbx_rewrite (MAILSTREAM *stream,unsigned long *reclaimed,
+			   long flags);
+long mbx_flaglock (MAILSTREAM *stream);
+
+/* MBX mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER mbxdriver = {
+  "mbx",			/* driver name */
+  DR_LOCAL|DR_MAIL|DR_CRLF|DR_LOCKING,
+				/* driver flags */
+  (DRIVER *) NIL,		/* next driver */
+  mbx_valid,			/* mailbox is valid for us */
+  mbx_parameters,		/* manipulate parameters */
+  mbx_scan,			/* scan mailboxes */
+  mbx_list,			/* list mailboxes */
+  mbx_lsub,			/* list subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  mbx_create,			/* create mailbox */
+  mbx_delete,			/* delete mailbox */
+  mbx_rename,			/* rename mailbox */
+  mbx_status,			/* status of mailbox */
+  mbx_open,			/* open mailbox */
+  mbx_close,			/* close mailbox */
+  mbx_flags,			/* fetch message "fast" attributes */
+  mbx_flags,			/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  mbx_header,			/* fetch message header */
+  mbx_text,			/* fetch message body */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  mbx_flag,			/* modify flags */
+  mbx_flagmsg,			/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  mbx_ping,			/* ping mailbox to see if still alive */
+  mbx_check,			/* check for new messages */
+  mbx_expunge,			/* expunge deleted messages */
+  mbx_copy,			/* copy messages to another mailbox */
+  mbx_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM mbxproto = {&mbxdriver};
+
+/* MBX mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *mbx_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+  int fd = mbx_isvalid (NIL,name,tmp,NIL,NIL,NIL);
+  if (fd < 0) return NIL;
+  close (fd);			/* don't need the fd now */
+  return &mbxdriver;
+}
+
+
+/* MBX mail test for valid mailbox
+ * Accepts: returned stream with valid mailbox keywords
+ *	    mailbox name
+ *	    scratch buffer
+ *	    returned lock fd
+ *	    returned lock name
+ *	    RW flags or NIL for readonly
+ * Returns: file descriptor if valid, NIL otherwise
+ */
+
+#define MBXISVALIDNOUID 0x1	/* RW, don't do UID action */
+#define MBXISVALIDUID 0x2	/* RW, do UID action */
+
+int mbx_isvalid (MAILSTREAM **stream,char *name,char *tmp,int *ld,char *lock,
+		 long flags)
+{
+  int fd,upd;
+  int ret = -1;
+  unsigned long i;
+  long j,k;
+  off_t pos;
+  char c,*s,*t,hdr[HDRSIZE];
+  struct stat sbuf;
+  time_t tp[2];
+  int error = EINVAL;		/* assume invalid argument */
+  if (ld) *ld = -1;		/* initially no lock */
+  if ((s = mbx_file (tmp,name)) && !stat (s,&sbuf) &&
+      ((fd = open (tmp,(flags ? O_RDWR : O_RDONLY)|O_BINARY,NIL)) >= 0)) {
+    error = -1;			/* bogus format */
+		/* I love cretinous C compilers -- don't you? */
+    if (read (fd,hdr,HDRSIZE) == HDRSIZE)
+      if ((hdr[0] == '*') && (hdr[1] == 'm') && (hdr[2] == 'b') &&
+	  (hdr[3] == 'x') && (hdr[4] == '*') && (hdr[5] == '\015') &&
+	  (hdr[6] == '\012') && isxdigit (hdr[7]) && isxdigit (hdr[8]))
+	if (isxdigit (hdr[9]) && isxdigit (hdr[10]) && isxdigit (hdr[11]) &&
+	    isxdigit (hdr[12]) && isxdigit (hdr[13]) && isxdigit (hdr[14]) &&
+	    isxdigit (c = hdr[15]) && isxdigit (hdr[16]))
+	  if (isxdigit (hdr[17]) && isxdigit (hdr[18]) &&
+	      isxdigit (hdr[19]) && isxdigit (hdr[20]) &&
+	      isxdigit (hdr[21]) && isxdigit (hdr[22]) &&
+	      (hdr[23] == '\015') && (hdr[24] == '\012')) {
+	    ret = fd;		/* mbx format */
+
+	    if (stream) {	/* lock if making mini-stream */
+	      if (flock (fd,LOCK_SH) ||
+		  (flags && ((*ld = lockfd (fd,lock,LOCK_EX)) < 0))) ret = -1;
+				/* reread data now that locked */
+	      else if (lseek (fd,0,L_SET) ||
+		       (read (fd,hdr,HDRSIZE) != HDRSIZE)) ret = -1;
+	      else {
+		*stream = (MAILSTREAM *) memset (fs_get (sizeof (MAILSTREAM)),
+						 0,sizeof (MAILSTREAM));
+		hdr[15] = '\0';	/* tie off UIDVALIDITY */
+		(*stream)->uid_validity = strtoul (hdr+7,NIL,16);
+		hdr[15] = c;	/* now get UIDLAST */
+		(*stream)->uid_last = strtoul (hdr+15,NIL,16);
+				/* parse user flags */
+		for (i = 0, s = hdr + 25;
+		     (i < NUSERFLAGS) && (t = strchr (s,'\015')) && (t - s);
+		     i++, s = t + 2) {
+		  *t = '\0';	/* tie off flag */
+		  if (strlen (s) <= MAXUSERFLAG)
+		    (*stream)->user_flags[i] = cpystr (s);
+		}
+				/* make sure have true UIDLAST */
+		if (flags & MBXISVALIDUID) {
+		  for (upd = NIL,pos = 2048, k = 0; pos < sbuf.st_size;
+		       pos += (j + k)) {
+				/* read header for this message */
+		    lseek (fd,pos,L_SET);
+		    if ((j = read (fd,hdr,64)) >= 0) {
+		      hdr[j] = '\0';
+		      if ((s = strchr (hdr,'\015')) && (s[1] == '\012')) {
+			*s = '\0';
+			k = s + 2 - hdr;
+			if ((s = strchr (hdr,',')) &&
+			    (j = strtol (s+1,&s,10)) && (*s == ';') &&
+			    (s = strchr (s+1,'-'))) {
+				/* get UID if there is any */
+			  i = strtoul (++s,&t,16);
+			  if (!*t && (t == (s + 8)) &&
+			      (i <= (*stream)->uid_last)) {
+			    if (!i) {
+			      lseek (fd,pos + s - hdr,L_SET);
+			      sprintf (hdr,"%08lx",++(*stream)->uid_last);
+			      write (fd,hdr,8);
+			      upd = T;
+			    }
+			    continue;
+			  }
+			}
+		      }
+		      ret = -1;	/* error, give up */
+		      *stream = mail_close (*stream);
+		      pos = sbuf.st_size + 1;
+		      j = k = 0;
+		    }
+		  }
+
+		  if (upd) {	/* need to update hdr with new UIDLAST? */
+		    lseek (fd,15,L_SET);
+		    sprintf (hdr,"%08lx",(*stream)->uid_last);
+		    write (fd,hdr,8);
+		  }
+		}
+	      }
+	    }
+	  }
+    if (ret != fd) close (fd);	/* close the file */
+    else lseek (fd,0,L_SET);	/* else rewind to start */
+				/* \Marked status? */
+    if (sbuf.st_ctime > sbuf.st_atime) {
+      tp[0] = sbuf.st_atime;	/* preserve atime and mtime */
+      tp[1] = sbuf.st_mtime;
+      utime (tmp,tp);		/* set the times */
+    }
+  }
+				/* in case INBOX but not mbx format */
+  else if (((error = errno) == ENOENT) && !compare_cstring (name,"INBOX"))
+    error = -1;
+  if ((ret < 0) && ld && (*ld >= 0)) {
+    unlockfd (*ld,lock);
+    *ld = -1;
+  }
+  errno = error;		/* return as last error */
+  return ret;			/* return what we should */
+}
+
+/* MBX manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *mbx_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case GET_INBOXPATH:
+    if (value) ret = mbx_file ((char *) value,"INBOX");
+    break;
+  case SET_ONETIMEEXPUNGEATPING:
+    if (value) ((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expok = T;
+  case GET_ONETIMEEXPUNGEATPING:
+    if (value) ret = (void *)
+      (((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expok ? VOIDT : NIL);
+    break;
+  }
+  return ret;
+}
+
+
+/* MBX mail scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* MBX mail list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mbx_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_list (NIL,ref,pat);
+}
+
+
+/* MBX mail list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_lsub (NIL,ref,pat);
+}
+
+/* MBX mail create mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long mbx_create (MAILSTREAM *stream,char *mailbox)
+{
+  char *s,*t,mbx[MAILTMPLEN],tmp[HDRSIZE];
+  long ret = NIL;
+  int i,fd;
+  if (!(s = mbx_file (mbx,mailbox))) {
+    sprintf (mbx,"Can't create %.80s: invalid name",mailbox);
+    MM_LOG (mbx,ERROR);
+  }
+				/* create underlying file */
+  else if (dummy_create_path (stream,s,get_dir_protection (mailbox))) {
+				/* done if made directory */
+    if ((s = strrchr (s,'/')) && !s[1]) return T;
+    if ((fd = open (mbx,O_WRONLY|O_BINARY,NIL)) < 0) {
+      sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno));
+      MM_LOG (tmp,ERROR);
+      unlink (mbx);		/* delete the file */
+    }
+    else {
+      memset (tmp,'\0',HDRSIZE);/* initialize header */
+      sprintf (s = tmp,"*mbx*\015\012%08lx00000000\015\012",
+	       (unsigned long) time (0));
+      for (i = 0; i < NUSERFLAGS; ++i) {
+	t = (stream && stream->user_flags[i]) ? stream->user_flags[i] :
+	  ((t = default_user_flag (i)) ? t : "");
+	sprintf (s += strlen (s),"%s\015\012",t);
+      }
+      if (write (fd,tmp,HDRSIZE) != HDRSIZE) {
+	sprintf (tmp,"Can't initialize mailbox node %.80s: %s",
+		 mbx,strerror (errno));
+	MM_LOG (tmp,ERROR);
+	unlink (mbx);		/* delete the file */
+      }
+      else ret = T;		/* success */
+      close (fd);		/* close file */
+    }
+  }
+				/* set proper protections */
+  return ret ? set_mbx_protections (mailbox,mbx) : NIL;
+}
+
+
+/* MBX mail delete mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long mbx_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return mbx_rename (stream,mailbox,NIL);
+}
+
+/* MBX mail rename mailbox
+ * Accepts: MAIL stream
+ *	    old mailbox name
+ *	    new mailbox name (or NIL for delete)
+ * Returns: T on success, NIL on failure
+ */
+
+long mbx_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  long ret = LONGT;
+  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  int fd,ld;
+  struct stat sbuf;
+  if (!mbx_file (file,old) ||
+      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
+		   ((s = strrchr (tmp,'/')) && !s[1])))) {
+    sprintf (tmp,newname ?
+	     "Can't rename mailbox %.80s to %.80s: invalid name" :
+	     "Can't delete mailbox %.80s: invalid name",
+	     old,newname);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+  else if ((fd = open (file,O_RDWR|O_BINARY,NIL)) < 0) {
+    sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno));
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+				/* get parse/append permission */
+  if ((ld = lockfd (fd,lock,LOCK_EX)) < 0) {
+    MM_LOG ("Unable to lock rename mailbox",ERROR);
+    return NIL;
+  }
+				/* lock out other users */
+  if (flock (fd,LOCK_EX|LOCK_NB)) {
+    close (fd);			/* couldn't lock, give up on it then */
+    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
+    MM_LOG (tmp,ERROR);
+    unlockfd (ld,lock);		/* release exclusive parse/append permission */
+    return NIL;
+  }
+
+  if (newname) {		/* want rename? */
+				/* found superior to destination name? */
+    if (s = strrchr (tmp,'/')) {
+      c = *++s;			/* remember first character of inferior */
+      *s = '\0';		/* tie off to get just superior */
+				/* superior name doesn't exist, create it */
+      if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+	  !dummy_create_path (stream,tmp,get_dir_protection (newname)))
+	ret = NIL;
+      else *s = c;		/* restore full name */
+    }
+				/* rename the file */
+    if (ret && rename (file,tmp)) {
+      sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
+	       strerror (errno));
+      MM_LOG (tmp,ERROR);
+      ret = NIL;		/* set failure */
+    }
+  }
+  else if (unlink (file)) {
+    sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
+    MM_LOG (tmp,ERROR);
+    ret = NIL;			/* set failure */
+  }
+  flock (fd,LOCK_UN);		/* release lock on the file */
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+  close (fd);			/* close the file */
+				/* recreate file if renamed INBOX */
+  if (ret && !compare_cstring (old,"INBOX")) mbx_create (NIL,"INBOX");
+  return ret;			/* return success */
+}
+
+/* MBX Mail status
+ * Accepts: mail stream
+ *	    mailbox name
+ *	    status flags
+ * Returns: T on success, NIL on failure
+ */
+
+long mbx_status (MAILSTREAM *stream,char *mbx,long flags)
+{
+  MAILSTATUS status;
+  unsigned long i;
+  MAILSTREAM *tstream = NIL;
+  MAILSTREAM *systream = NIL;
+				/* make temporary stream (unless this mbx) */
+  if (!stream && !(stream = tstream =
+		   mail_open (NIL,mbx,OP_READONLY|OP_SILENT)))
+    return NIL;
+  status.flags = flags;		/* return status values */
+  status.messages = stream->nmsgs;
+  status.recent = stream->recent;
+  if (flags & SA_UNSEEN)	/* must search to get unseen messages */
+    for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++)
+      if (!mail_elt (stream,i)->seen) status.unseen++;
+  status.uidnext = stream->uid_last + 1;
+  status.uidvalidity = stream->uid_validity;
+				/* calculate post-snarf results */
+  if (!status.recent && stream->inbox &&
+      (systream = mail_open (NIL,sysinbox (),OP_READONLY|OP_SILENT))) {
+    status.messages += systream->nmsgs;
+    status.recent += systream->recent;
+    if (flags & SA_UNSEEN)	/* must search to get unseen messages */
+      for (i = 1; i <= systream->nmsgs; i++)
+	if (!mail_elt (systream,i)->seen) status.unseen++;
+				/* kludge but probably good enough */
+    status.uidnext += systream->nmsgs;
+  }
+  MM_STATUS(stream,mbx,&status);/* pass status to main program */
+  if (tstream) mail_close (tstream);
+  if (systream) mail_close (systream);
+  return T;			/* success */
+}
+
+/* MBX mail open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *mbx_open (MAILSTREAM *stream)
+{
+  int fd,ld;
+  short silent;
+  char tmp[MAILTMPLEN];
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return user_flags (&mbxproto);
+  if (stream->local) fatal ("mbx recycle stream");
+				/* canonicalize the mailbox name */
+  if (!mbx_file (tmp,stream->mailbox)) {
+    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
+    MM_LOG (tmp,ERROR);
+  }
+  if (stream->rdonly ||
+      (fd = open (tmp,O_RDWR|O_BINARY,NIL)) < 0) {
+    if ((fd = open (tmp,O_RDONLY|O_BINARY,NIL)) < 0) {
+      sprintf (tmp,"Can't open mailbox: %s",strerror (errno));
+      MM_LOG (tmp,ERROR);
+      return NIL;
+    }
+    else if (!stream->rdonly) {	/* got it, but readonly */
+      MM_LOG ("Can't get write access to mailbox, access is readonly",WARN);
+      stream->rdonly = T;
+    }
+  }
+
+  stream->local = memset (fs_get (sizeof (MBXLOCAL)),NIL,sizeof (MBXLOCAL));
+  LOCAL->fd = fd;		/* bind the file */
+  LOCAL->ld = -1;		/* no flaglock */
+  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
+  LOCAL->buflen = CHUNKSIZE - 1;
+				/* note if an INBOX or not */
+  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
+  fs_give ((void **) &stream->mailbox);
+  stream->mailbox = cpystr (tmp);
+				/* get parse/append permission */
+  if ((ld = lockfd (LOCAL->fd,tmp,LOCK_EX)) < 0) {
+    MM_LOG ("Unable to lock open mailbox",ERROR);
+    return NIL;
+  }
+  (*bn) (BLOCK_FILELOCK,NIL);
+  flock (LOCAL->fd,LOCK_SH);	/* lock the file */
+  (*bn) (BLOCK_NONE,NIL);
+  unlockfd (ld,tmp);		/* release shared parse permission */
+  LOCAL->filesize = HDRSIZE;	/* initialize parsed file size */
+				/* time not set up yet */
+  LOCAL->lastsnarf = LOCAL->filetime = 0;
+  LOCAL->expok = LOCAL->flagcheck = NIL;
+  stream->sequence++;		/* bump sequence number */
+				/* parse mailbox */
+  stream->nmsgs = stream->recent = 0;
+  silent = stream->silent;	/* defer events */
+  stream->silent = T;
+  if (mbx_ping (stream) && !stream->nmsgs)
+    MM_LOG ("Mailbox is empty",(long) NIL);
+  stream->silent = silent;	/* now notify upper level */
+  mail_exists (stream,stream->nmsgs);
+  mail_recent (stream,stream->recent);
+  if (!LOCAL) return NIL;	/* failure if stream died */
+  stream->perm_seen = stream->perm_deleted = stream->perm_flagged =
+    stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T;
+  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
+  stream->kwd_create = (stream->user_flags[NUSERFLAGS-1] || stream->rdonly) ?
+    NIL : T;			/* can we create new user flags? */
+  return stream;		/* return stream to caller */
+}
+
+/* MBX mail close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void mbx_close (MAILSTREAM *stream,long options)
+{
+  if (stream && LOCAL) {	/* only if a file is open */
+    int silent = stream->silent;
+    stream->silent = T;		/* note this stream is dying */
+				/* do an expunge if requested */
+    if (options & CL_EXPUNGE) mbx_expunge (stream,NIL,NIL);
+    else {			/* otherwise do a checkpoint to purge */
+      LOCAL->expok = T;		/*  possible expunged messages */
+      mbx_ping (stream);
+    }
+    stream->silent = silent;	/* restore previous status */
+    mbx_abort (stream);
+  }
+}
+
+
+/* MBX mail abort stream
+ * Accepts: MAIL stream
+ */
+
+void mbx_abort (MAILSTREAM *stream)
+{
+  if (stream && LOCAL) {	/* only if a file is open */
+    flock (LOCAL->fd,LOCK_UN);	/* unlock local file */
+    close (LOCAL->fd);		/* close the local file */
+				/* free local text buffer */
+    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+
+/* MBX mail fetch flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ * Sniffs at file to see if some other process changed the flags
+ */
+
+void mbx_flags (MAILSTREAM *stream,char *sequence,long flags)
+{
+  MESSAGECACHE *elt;
+  unsigned long i;
+  if (mbx_ping (stream) && 	/* ping mailbox, get new status for messages */
+      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
+       mail_sequence (stream,sequence)))
+    for (i = 1; i <= stream->nmsgs; i++) 
+      if ((elt = mail_elt (stream,i))->sequence && !elt->valid)
+	mbx_elt (stream,i,NIL);
+}
+
+/* MBX mail fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+char *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
+		  long flags)
+{
+  unsigned long i;
+  char *s;
+  *length = 0;			/* default to empty */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+				/* get header position, possibly header */
+  i = mbx_hdrpos (stream,msgno,length,&s);
+  if (!s) {			/* mbx_hdrpos() returned header? */
+    lseek (LOCAL->fd,i,L_SET);	/* no, get to header position */
+				/* is buffer big enough? */
+    if (*length > LOCAL->buflen) {
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get ((LOCAL->buflen = *length) + 1);
+    }
+				/* slurp the data */
+    read (LOCAL->fd,s = LOCAL->buf,*length);
+  }
+  s[*length] = '\0';		/* tie off string */
+  return s;
+}
+
+/* MBX mail fetch message text (body only)
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: T on success, NIL on failure
+ */
+
+long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  FDDATA d;
+  unsigned long i,j;
+  MESSAGECACHE *elt;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+				/* get message status */
+  elt = mbx_elt (stream,msgno,NIL);
+				/* if message not seen */
+  if (!(flags & FT_PEEK) && !elt->seen && mbx_flaglock (stream)) {
+    elt->seen = T;		/* mark message as seen */
+				/* recalculate status */
+    mbx_update_status (stream,msgno,NIL);
+    MM_FLAGS (stream,msgno);
+				/* update flags */
+    mbx_flag (stream,NIL,NIL,NIL);
+  }
+  if (!LOCAL) return NIL;	/* mbx_flaglock() could have aborted */
+				/* find header position */
+  i = mbx_hdrpos (stream,msgno,&j,NIL);
+  d.fd = LOCAL->fd;		/* set up file descriptor */
+  d.pos = i + j;
+  d.chunk = LOCAL->buf;	/* initial buffer chunk */
+  d.chunksize = CHUNKSIZE;
+  INIT (bs,fd_string,&d,elt->rfc822_size - j);
+  return LONGT;			/* success */
+}
+
+/* MBX mail modify flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    flag(s)
+ *	    option flags
+ * Unlocks flag lock
+ */
+
+void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
+{
+  time_t tp[2];
+  struct stat sbuf;
+  unsigned long oldpid = LOCAL->lastpid;
+				/* make sure the update takes */
+  if (!stream->rdonly && LOCAL && (LOCAL->fd >= 0) && (LOCAL->ld >= 0)) {
+    fsync (LOCAL->fd);
+    fstat (LOCAL->fd,&sbuf);	/* get current write time */
+    tp[1] = LOCAL->filetime = sbuf.st_mtime;
+				/* we are the last flag updater */
+    LOCAL->lastpid = (unsigned long) getpid ();
+				/* update header if needed */
+    if (((LOCAL->ffuserflag < NUSERFLAGS) &&
+	 stream->user_flags[LOCAL->ffuserflag]) || (oldpid != LOCAL->lastpid))
+      mbx_update_header (stream);
+    tp[0] = time (0);		/* make sure read comes after all that */
+    utime (stream->mailbox,tp);
+  }
+  if (LOCAL->ld >= 0) {		/* unlock now */
+    unlockfd (LOCAL->ld,LOCAL->lock);
+    LOCAL->ld = -1;
+  }
+}
+
+
+/* MBX mail per-message modify flags
+ * Accepts: MAIL stream
+ *	    message cache element
+ */
+
+void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  if (mbx_flaglock (stream)) mbx_update_status (stream,elt->msgno,NIL);
+}
+
+/* MBX mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream still alive, NIL if not
+ */
+
+long mbx_ping (MAILSTREAM *stream)
+{
+  unsigned long i,pos;
+  long ret = NIL;
+  int ld;
+  char lock[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  struct stat sbuf;
+  if (stream && LOCAL) {	/* only if stream already open */
+    int snarf = stream->inbox && !stream->rdonly;
+    ret = LONGT;		/* assume OK */
+    fstat (LOCAL->fd,&sbuf);	/* get current file poop */
+				/* allow expunge if permitted at ping */
+    if (mail_parameters (NIL,GET_EXPUNGEATPING,NIL)) LOCAL->expok = T;
+				/* if external modification */
+    if (LOCAL->filetime && (LOCAL->filetime < sbuf.st_mtime))
+      LOCAL->flagcheck = T;	/* upgrade to flag checking */
+				/* new mail or flagcheck handling needed? */
+    if (((sbuf.st_size - LOCAL->filesize) || LOCAL->flagcheck ||
+	 !stream->nmsgs || snarf) &&
+	((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) >= 0)) {
+				/* reparse header if not flagchecking */
+      if (!LOCAL->flagcheck) ret = mbx_parse (stream);
+				/* sweep mailbox for changed message status */
+      else if (ret = mbx_parse (stream)) {
+	unsigned long recent = 0;
+	LOCAL->filetime = sbuf.st_mtime;
+	for (i = 1; i <= stream->nmsgs; )
+	  if (elt = mbx_elt (stream,i,LOCAL->expok)) {
+	    if (elt->recent) ++recent;
+	    ++i;
+	  }
+	mail_recent (stream,recent);
+	LOCAL->flagcheck = NIL;	/* got all the updates */
+      }
+				/* always reparse header at least */
+      if (ret && snarf) {	/* snarf new messages if still OK */
+	mbx_snarf (stream);
+				/* parse snarfed messages */
+	ret = mbx_parse (stream);
+      }
+      unlockfd (ld,lock);	/* release shared parse/append permission */
+    }
+    if (ret) {			/* must still be alive */
+      if (!LOCAL->expunged)	/* look for holes if none known yet */
+	for (i = 1, pos = HDRSIZE;
+	     !LOCAL->expunged && (i <= stream->nmsgs);
+	     i++, pos += elt->private.special.text.size + elt->rfc822_size)
+	  if ((elt = mail_elt (stream,i))->private.special.offset != pos)
+	    LOCAL->expunged = T;/* found a hole */
+				/* burp any holes */
+      if (LOCAL->expunged && !stream->rdonly) {
+	if (mbx_rewrite (stream,&i,NIL)) fatal ("expunge on check");
+	if (i) {		/* any space reclaimed? */
+	  LOCAL->expunged = NIL;/* no more pending expunge */
+	  sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",i);
+	  MM_LOG (LOCAL->buf,(long) NIL);
+	}
+      }
+      LOCAL->expok = NIL;	/* no more expok */
+    }
+  }
+  return ret;			/* return result of the parse */
+}
+
+/* MBX mail check mailbox (reparses status too)
+ * Accepts: MAIL stream
+ */
+
+void mbx_check (MAILSTREAM *stream)
+{
+  if (LOCAL) LOCAL->expok = T;	/* mark that a check is desired */
+  if (mbx_ping (stream)) MM_LOG ("Check completed",(long) NIL);
+}
+
+
+/* MBX mail expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T if success, NIL if failure
+ */
+
+long mbx_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  long ret;
+  unsigned long nexp,reclaimed;
+  if (ret = sequence ? ((options & EX_UID) ?
+			mail_uid_sequence (stream,sequence) :
+			mail_sequence (stream,sequence)) : LONGT) {
+    if (!mbx_ping (stream));	/* do nothing if stream dead */
+    else if (stream->rdonly)	/* won't do on readonly files! */
+      MM_LOG ("Expunge ignored on readonly mailbox",WARN);
+				/* if expunged any messages */
+    else if (nexp = mbx_rewrite (stream,&reclaimed,sequence ? -1 : 1)) {
+      sprintf (LOCAL->buf,"Expunged %lu messages",nexp);
+      MM_LOG (LOCAL->buf,(long) NIL);
+    }
+    else if (reclaimed) {	 /* or if any prior expunged space reclaimed */
+      sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",reclaimed);
+      MM_LOG (LOCAL->buf,(long) NIL);
+    }
+    else MM_LOG ("No messages deleted, so no update needed",(long) NIL);
+  }
+  return ret;
+}
+
+/* MBX mail snarf messages from system inbox
+ * Accepts: MAIL stream, already locked
+ */
+
+void mbx_snarf (MAILSTREAM *stream)
+{
+  unsigned long i = 0;
+  unsigned long j,r,hdrlen,txtlen;
+  struct stat sbuf;
+  char *hdr,*txt,tmp[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  MAILSTREAM *sysibx = NIL;
+				/* give up if can't get exclusive permission */
+  if ((time (0) >= (LOCAL->lastsnarf +
+		    (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL))) &&
+      strcmp (sysinbox (),stream->mailbox)) {
+    MM_CRITICAL (stream);	/* go critical */
+				/* sizes match and anything in sysinbox? */
+    if (!stat (sysinbox (),&sbuf) && sbuf.st_size &&
+	!fstat (LOCAL->fd,&sbuf) && (sbuf.st_size == LOCAL->filesize) && 
+	(sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) &&
+	(!sysibx->rdonly) && (r = sysibx->nmsgs)) {
+				/* yes, go to end of file in our mailbox */
+      lseek (LOCAL->fd,sbuf.st_size,L_SET);
+				/* for each message in sysibx mailbox */
+      while (r && (++i <= sysibx->nmsgs)) {
+				/* snarf message from system INBOX */
+	hdr = cpystr (mail_fetchheader_full (sysibx,i,NIL,&hdrlen,NIL));
+	txt = mail_fetchtext_full (sysibx,i,&txtlen,FT_PEEK);
+				/* if have a message */
+	if (j = hdrlen + txtlen) {
+				/* build header line */
+	  mail_date (LOCAL->buf,elt = mail_elt (sysibx,i));
+	  sprintf (LOCAL->buf + strlen (LOCAL->buf),
+		   ",%lu;00000000%04x-00000000\015\012",j,(unsigned)
+		   ((fSEEN * elt->seen) +
+		    (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) +
+		    (fANSWERED * elt->answered) + (fDRAFT * elt->draft)));
+				/* copy message */
+	  if ((write (LOCAL->fd,LOCAL->buf,strlen (LOCAL->buf)) < 0) ||
+	      (write (LOCAL->fd,hdr,hdrlen) < 0) ||
+	      (write (LOCAL->fd,txt,txtlen) < 0)) r = 0;
+	}
+	fs_give ((void **) &hdr);
+      }
+
+				/* make sure all the updates take */
+      if (fsync (LOCAL->fd)) r = 0;
+      if (r) {			/* delete all the messages we copied */
+	if (r == 1) strcpy (tmp,"1");
+	else sprintf (tmp,"1:%lu",r);
+	mail_setflag (sysibx,tmp,"\\Deleted");
+	mail_expunge (sysibx);	/* now expunge all those messages */
+      }
+      else {
+	sprintf (LOCAL->buf,"Can't copy new mail: %s",strerror (errno));
+	MM_LOG (LOCAL->buf,WARN);
+	ftruncate (LOCAL->fd,sbuf.st_size);
+      }
+      fstat (LOCAL->fd,&sbuf);	/* yes, get current file size */
+      LOCAL->filetime = sbuf.st_mtime;
+    }
+    if (sysibx) mail_close (sysibx);
+    MM_NOCRITICAL (stream);	/* release critical */
+    LOCAL->lastsnarf = time (0);/* note time of last snarf */
+  }
+}
+
+/* MBX mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if success, NIL if failed
+ */
+
+long mbx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  struct stat sbuf;
+  time_t tp[2];
+  MESSAGECACHE *elt;
+  unsigned long i,j,k,m;
+  long ret = LONGT;
+  int fd,ld;
+  char *s,*t,file[MAILTMPLEN],lock[MAILTMPLEN];
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+  copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL);
+  SEARCHSET *source = cu ? mail_newsearchset () : NIL;
+  SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
+  MAILSTREAM *dstream = NIL;
+  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+	mail_sequence (stream,sequence))) return NIL;
+				/* make sure valid mailbox */
+  if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock,
+			 cu ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0)
+    switch (errno) {
+    case ENOENT:		/* no such file? */
+      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
+      return NIL;
+    case EACCES:		/* file protected */
+      sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
+      MM_LOG (LOCAL->buf,ERROR);
+      return NIL;
+    case EINVAL:
+      if (pc) return (*pc) (stream,sequence,mailbox,options);
+      sprintf (LOCAL->buf,"Invalid MBX-format mailbox name: %.80s",mailbox);
+      MM_LOG (LOCAL->buf,ERROR);
+      return NIL;
+    default:
+      if (pc) return (*pc) (stream,sequence,mailbox,options);
+      sprintf (LOCAL->buf,"Not a MBX-format mailbox: %.80s",mailbox);
+      MM_LOG (LOCAL->buf,ERROR);
+      return NIL;
+    }
+  MM_CRITICAL (stream);		/* go critical */
+  fstat (fd,&sbuf);		/* get current file size */
+  lseek (fd,sbuf.st_size,L_SET);/* move to end of file */
+
+				/* for each requested message */
+  for (i = 1; ret && (i <= stream->nmsgs); i++) 
+    if ((elt = mail_elt (stream,i))->sequence) {
+      lseek (LOCAL->fd,elt->private.special.offset +
+	     elt->private.special.text.size,L_SET);
+      mail_date(LOCAL->buf,elt);/* build target header */
+				/* get target keyword mask */
+      for (j = elt->user_flags, k = 0; j; )
+	if (s = stream->user_flags[find_rightmost_bit (&j)])
+	  for (m = 0; (m < NUSERFLAGS) && (t = dstream->user_flags[m]); m++)
+	    if (!compare_cstring (s,t) && (k |= 1 << m)) break;
+      sprintf (LOCAL->buf+strlen(LOCAL->buf),",%lu;%08lx%04x-%08lx\015\012",
+	       elt->rfc822_size,k,(unsigned)
+	       ((fSEEN * elt->seen) + (fDELETED * elt->deleted) +
+		(fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
+		(fDRAFT * elt->draft)),cu ? ++dstream->uid_last : 0);
+				/* write target header */
+      if (ret = (write (fd,LOCAL->buf,strlen (LOCAL->buf)) > 0)) {
+	for (k = elt->rfc822_size; ret && (j = min (k,LOCAL->buflen)); k -= j){
+	  read (LOCAL->fd,LOCAL->buf,j);
+	  ret = write (fd,LOCAL->buf,j) >= 0;
+	}
+	if (cu) {		/* need to pass back new UID? */
+	  mail_append_set (source,mail_uid (stream,i));
+	  mail_append_set (dest,dstream->uid_last);
+	}
+      }
+    }
+
+				/* make sure all the updates take */
+  if (!(ret && (ret = !fsync (fd)))) {
+    sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno));
+    MM_LOG (LOCAL->buf,ERROR);
+    ftruncate (fd,sbuf.st_size);
+  }
+  if (cu && ret) {		/* return sets if doing COPYUID */
+    (*cu) (stream,mailbox,dstream->uid_validity,source,dest);
+    lseek (fd,15,L_SET);	/* update UIDLAST */
+    sprintf (LOCAL->buf,"%08lx",dstream->uid_last);
+    write (fd,LOCAL->buf,8);
+  }
+  else {			/* flush any sets we may have built */
+    mail_free_searchset (&source);
+    mail_free_searchset (&dest);
+  }
+  if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */
+				/* else preserve \Marked status */
+  else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0);
+  tp[1] = sbuf.st_mtime;	/* preserve mtime */
+  utime (file,tp);		/* set the times */
+  close (fd);			/* close the file */
+  MM_NOCRITICAL (stream);	/* release critical */
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+				/* delete all requested messages */
+  if (ret && (options & CP_MOVE) && mbx_flaglock (stream)) {
+    for (i = 1; i <= stream->nmsgs; i++) if (mail_elt (stream,i)->sequence) {
+				/* mark message deleted */
+      mbx_elt (stream,i,NIL)->deleted = T;
+				/* recalculate status */
+      mbx_update_status (stream,i,NIL);
+    }
+				/* update flags */
+    mbx_flag (stream,NIL,NIL,NIL);
+  }
+  if (dstream != stream) mail_close (dstream);
+  return ret;
+}
+
+/* MBX mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long mbx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct stat sbuf;
+  int fd,ld;
+  char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  time_t tp[2];
+  FILE *df;
+  MESSAGECACHE elt;
+  long f;
+  unsigned long i,uf;
+  STRING *message;
+  long ret = NIL;
+  MAILSTREAM *dstream = NIL;
+  appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL);
+  SEARCHSET *dst = au ? mail_newsearchset () : NIL;
+				/* make sure valid mailbox */
+  if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock,
+			 au ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0)
+    switch (errno) {
+    case ENOENT:		/* no such file? */
+      if (compare_cstring (mailbox,"INBOX")) {
+	MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+	return NIL;
+      }
+				/* can create INBOX here */
+      mbx_create (dstream = stream ? stream : user_flags (&mbxproto),"INBOX");
+      if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock,
+			     au ? MBXISVALIDUID : MBXISVALIDNOUID)) >= 0)
+	break;
+    case EACCES:		/* file protected */
+      sprintf (tmp,"Can't access destination: %.80s",mailbox);
+      MM_LOG (tmp,ERROR);
+      return NIL;
+    case EINVAL:
+      sprintf (tmp,"Invalid MBX-format mailbox name: %.80s",mailbox);
+      MM_LOG (tmp,ERROR);
+      return NIL;
+    default:
+      sprintf (tmp,"Not a MBX-format mailbox: %.80s",mailbox);
+      MM_LOG (tmp,ERROR);
+      return NIL;
+    }
+
+				/* get first message */
+  if (!MM_APPEND (af) (dstream,data,&flags,&date,&message)) close (fd);
+  else if (!(df = fdopen (fd,"r+b"))) {
+    MM_LOG ("Unable to reopen append mailbox",ERROR);
+    close (fd);
+  }
+  else {
+    MM_CRITICAL (dstream);	/* go critical */
+    fstat (fd,&sbuf);		/* get current file size */
+    fseek (df,sbuf.st_size,SEEK_SET);
+    errno = 0;
+    for (ret = LONGT; ret && message; ) {
+      if (!SIZE (message)) {	/* guard against zero-length */
+	MM_LOG ("Append of zero-length message",ERROR);
+	ret = NIL;
+	break;
+      }
+      f = mail_parse_flags (dstream,flags,&uf);
+      if (date) {		/* parse date if given */
+	if (!mail_parse_date (&elt,date)) {
+	  sprintf (tmp,"Bad date in append: %.80s",date);
+	  MM_LOG (tmp,ERROR);
+	  ret = NIL;		/* mark failure */
+	  break;
+	}
+	mail_date (tmp,&elt);	/* write preseved date */
+      }
+      else internal_date (tmp);	/* get current date in IMAP format */
+				/* write header */
+      if (fprintf (df,"%s,%lu;%08lx%04lx-%08lx\015\012",tmp,i = SIZE (message),
+		   uf,(unsigned long) f,au ? ++dstream->uid_last : 0) < 0)
+	ret = NIL;
+      else {			/* write message */
+	size_t j;
+	if (!message->cursize) SETPOS (message,GETPOS (message));
+	while (i && (j = fwrite (message->curpos,1,message->cursize,df))) {
+	  i -= j;
+	  SETPOS (message,GETPOS (message) + j);
+	}
+				/* get next message */
+	if (i || !MM_APPEND (af) (dstream,data,&flags,&date,&message))
+	  ret = NIL;
+	else if (au) mail_append_set (dst,dstream->uid_last);
+      }
+    }
+
+				/* if error... */
+    if (!ret || (fflush (df) == EOF)) {
+				/* revert file */
+      ftruncate (fd,sbuf.st_size);
+      close (fd);		/* make sure fclose() doesn't corrupt us */
+      if (errno) {
+	sprintf (tmp,"Message append failed: %s",strerror (errno));
+	MM_LOG (tmp,ERROR);
+      }
+      ret = NIL;
+    }
+    if (au && ret) {		/* return sets if doing APPENDUID */
+      (*au) (mailbox,dstream->uid_validity,dst);
+      fseek (df,15,SEEK_SET);	/* update UIDLAST */
+      fprintf (df,"%08lx",dstream->uid_last);
+    }
+    else mail_free_searchset (&dst);
+				/* set atime to now-1 if successful copy */
+    if (ret) tp[0] = time (0) - 1;
+				/* else preserve \Marked status */
+    else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0);
+    tp[1] = sbuf.st_mtime;	/* preserve mtime */
+    utime (file,tp);		/* set the times */
+    fclose (df);		/* close the file */
+    MM_NOCRITICAL (dstream);	/* release critical */
+  }
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+  if (dstream != stream) mail_close (dstream);
+  return ret;
+}
+
+/* Internal routines */
+
+
+/* MBX mail generate file string
+ * Accepts: temporary buffer to write into
+ *	    mailbox name string
+ * Returns: local file string or NIL if failure
+ */
+
+char *mbx_file (char *dst,char *name)
+{
+  char *s = mailboxfile (dst,name);
+  return (s && !*s) ? mailboxfile (dst,"~/INBOX") : s;
+}
+
+/* MBX mail parse mailbox
+ * Accepts: MAIL stream
+ * Returns: T if parse OK
+ *	    NIL if failure, stream aborted
+ */
+
+long mbx_parse (MAILSTREAM *stream)
+{
+  struct stat sbuf;
+  MESSAGECACHE *elt = NIL;
+  unsigned char c,*s,*t,*x;
+  char tmp[MAILTMPLEN];
+  unsigned long i,j,k,m;
+  off_t curpos = LOCAL->filesize;
+  unsigned long nmsgs = stream->nmsgs;
+  unsigned long recent = stream->recent;
+  unsigned long lastuid = 0;
+  short dirty = NIL;
+  short added = NIL;
+  short silent = stream->silent;
+  short uidwarn = T;
+  fstat (LOCAL->fd,&sbuf);	/* get status */
+  if (sbuf.st_size < curpos) {	/* sanity check */
+    sprintf (tmp,"Mailbox shrank from %lu to %lu!",
+	     (unsigned long) curpos,(unsigned long) sbuf.st_size);
+    MM_LOG (tmp,ERROR);
+    mbx_abort (stream);
+    return NIL;
+  }
+  lseek (LOCAL->fd,0,L_SET);	/* rewind file */
+				/* read internal header */
+  read (LOCAL->fd,LOCAL->buf,HDRSIZE);
+  LOCAL->buf[HDRSIZE] = '\0';	/* tie off header */
+  c = LOCAL->buf[15];		/* save first character of last UID */
+  LOCAL->buf[15] = '\0';
+				/* parse UID validity */
+  stream->uid_validity = strtoul (LOCAL->buf + 7,NIL,16);
+  LOCAL->buf[15] = c;		/* restore first character of last UID */
+				/* parse last UID */
+  i = strtoul (LOCAL->buf + 15,NIL,16);
+  stream->uid_last = stream->rdonly ? max (i,stream->uid_last) : i;
+				/* parse user flags */
+  for (i = 0, s = LOCAL->buf + 25;
+       (i < NUSERFLAGS) && (t = strchr (s,'\015')) && (t - s);
+       i++, s = t + 2) {
+    *t = '\0';			/* tie off flag */
+    if (!stream->user_flags[i] && (strlen (s) <= MAXUSERFLAG))
+      stream->user_flags[i] = cpystr (s);
+  }
+  LOCAL->ffuserflag = (int) i;	/* first free user flag */
+
+				/* get current last flag updater PID */
+  i = (isxdigit (LOCAL->buf[HDRSIZE-10]) && isxdigit (LOCAL->buf[HDRSIZE-9]) &&
+       isxdigit (LOCAL->buf[HDRSIZE-8]) && isxdigit (LOCAL->buf[HDRSIZE-7]) &&
+       isxdigit (LOCAL->buf[HDRSIZE-6]) && isxdigit (LOCAL->buf[HDRSIZE-5]) &&
+       isxdigit (LOCAL->buf[HDRSIZE-4]) && isxdigit (LOCAL->buf[HDRSIZE-3]) &&
+       (LOCAL->buf[HDRSIZE-2] == '\015') && (LOCAL->buf[HDRSIZE-1] == '\012'))?
+    strtoul (LOCAL->buf + HDRSIZE - 8,NIL,16) : 0;
+				/* set flagcheck if lastpid changed */
+  if (LOCAL->lastpid && (LOCAL->lastpid != i)) LOCAL->flagcheck = T;
+  LOCAL->lastpid = i;		/* set as last PID */
+  stream->silent = T;		/* don't pass up exists events yet */
+  while (sbuf.st_size - curpos){/* while there is stuff to parse */
+				/* get to that position in the file */
+    lseek (LOCAL->fd,curpos,L_SET);
+    if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) {
+      sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s",
+	       (unsigned long) curpos,(unsigned long) sbuf.st_size,
+	       i ? strerror (errno) : "no data read");
+      MM_LOG (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+    LOCAL->buf[i] = '\0';	/* tie off buffer just in case */
+    if (!((s = strchr (LOCAL->buf,'\015')) && (s[1] == '\012'))) {
+      sprintf (tmp,"Unable to find CRLF at %lu in %lu bytes, text: %.80s",
+	       (unsigned long) curpos,i,(char *) LOCAL->buf);
+      MM_LOG (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+    *s = '\0';			/* tie off header line */
+    i = (s + 2) - LOCAL->buf;	/* note start of text offset */
+    if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) {
+      sprintf (tmp,"Unable to parse internal header at %lu: %.80s",
+	       (unsigned long) curpos,(char *) LOCAL->buf);
+      MM_LOG (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+    if (!(isxdigit (t[1]) && isxdigit (t[2]) && isxdigit (t[3]) &&
+	  isxdigit (t[4]) && isxdigit (t[5]) && isxdigit (t[6]) &&
+	  isxdigit (t[7]) && isxdigit (t[8]) && isxdigit (t[9]) &&
+	  isxdigit (t[10]) && isxdigit (t[11]) && isxdigit (t[12]))) {
+      sprintf (tmp,"Unable to parse message flags at %lu: %.80s",
+	       (unsigned long) curpos,(char *) LOCAL->buf);
+      MM_LOG (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+    if ((t[13] != '-') || t[22] ||
+	!(isxdigit (t[14]) && isxdigit (t[15]) && isxdigit (t[16]) &&
+	  isxdigit (t[17]) && isxdigit (t[18]) && isxdigit (t[19]) &&
+	  isxdigit (t[20]) && isxdigit (t[21]))) {
+      sprintf (tmp,"Unable to parse message UID at %lu: %.80s",
+	       (unsigned long) curpos,(char *) LOCAL->buf);
+      MM_LOG (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+
+    *s++ = '\0'; *t++ = '\0';	/* break up fields */
+				/* get message size */
+    if (!(j = strtoul (s,(char **) &x,10)) && (!(x && *x))) {
+      sprintf (tmp,"Unable to parse message size at %lu: %.80s,%.80s;%.80s",
+	       (unsigned long) curpos,(char *) LOCAL->buf,(char *) s,
+	       (char *) t);
+      MM_LOG (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+				/* make sure didn't run off end of file */
+    if (((off_t) (curpos + i + j)) > sbuf.st_size) {
+      sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
+	       (unsigned long) curpos,(unsigned long) (curpos + i + j),
+	       (unsigned long) sbuf.st_size);
+      MM_LOG (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+				/* parse UID */
+    if ((m = strtoul (t+13,NIL,16)) &&
+	((m <= lastuid) || (m > stream->uid_last))) {
+      if (uidwarn) {
+	sprintf (tmp,"Invalid UID %08lx in message %lu, rebuilding UIDs",
+		 m,nmsgs+1);
+	MM_LOG (tmp,WARN);
+	uidwarn = NIL;
+				/* restart UID validity */
+	stream->uid_validity = time (0);
+      }
+      m = 0;			/* lose this UID */
+      dirty = T;		/* mark dirty, set new lastuid */
+      stream->uid_last = lastuid;
+    }
+
+    t[12] = '\0';		/* parse system flags */
+    if ((k = strtoul (t+8,NIL,16)) & fEXPUNGED) {
+      if (m) lastuid = m;	/* expunge message, update last UID seen */
+      else {			/* no UID assigned? */
+	lastuid = ++stream->uid_last;
+	dirty = T;
+      }
+    }
+    else {			/* not expunged, swell the cache */
+      added = T;		/* note that a new message was added */
+      mail_exists (stream,++nmsgs);
+				/* instantiate an elt for this message */
+      (elt = mail_elt (stream,nmsgs))->valid = T;
+				/* parse the date */
+      if (!mail_parse_date (elt,LOCAL->buf)) {
+	sprintf (tmp,"Unable to parse message date at %lu: %.80s",
+		 (unsigned long) curpos,(char *) LOCAL->buf);
+	MM_LOG (tmp,ERROR);
+	mbx_abort (stream);
+	return NIL;
+      }
+				/* note file offset of header */
+      elt->private.special.offset = curpos;
+				/* and internal header size */
+      elt->private.special.text.size = i;
+				/* header size not known yet */
+      elt->private.msg.header.text.size = 0;
+      elt->rfc822_size = j;	/* note message size */
+				/* calculate system flags */
+      if (k & fSEEN) elt->seen = T;
+      if (k & fDELETED) elt->deleted = T;
+      if (k & fFLAGGED) elt->flagged = T;
+      if (k & fANSWERED) elt->answered = T;
+      if (k & fDRAFT) elt->draft = T;
+      t[8] = '\0';		/* get user flags value */
+      elt->user_flags = strtoul (t,NIL,16);
+				/* UID already assigned? */
+      if (!(elt->private.uid = m) || !(k & fOLD)) {
+	elt->recent = T;	/* no, mark as recent */
+	++recent;		/* count up a new recent message */
+	dirty = T;		/* and must rewrite header */
+				/* assign new UID */
+	if (!elt->private.uid) elt->private.uid = ++stream->uid_last;
+	mbx_update_status (stream,elt->msgno,NIL);
+      }
+				/* update last parsed UID */
+      lastuid = elt->private.uid;
+    }
+    curpos += i + j;		/* update position */
+  }
+
+  if (dirty && !stream->rdonly){/* update header */
+    mbx_update_header (stream);
+    fsync (LOCAL->fd);		/* make sure all the UID updates take */
+  }
+				/* update parsed file size and time */
+  LOCAL->filesize = sbuf.st_size;
+  fstat (LOCAL->fd,&sbuf);	/* get status again to ensure time is right */
+  LOCAL->filetime = sbuf.st_mtime;
+  if (added && !stream->rdonly){/* make sure atime updated */
+    time_t tp[2];
+    tp[0] = time (0);
+    tp[1] = LOCAL->filetime;
+    utime (stream->mailbox,tp);
+  }
+  stream->silent = silent;	/* can pass up events now */
+  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
+  mail_recent (stream,recent);	/* and of change in recent messages */
+  return LONGT;			/* return the winnage */
+}
+
+/* MBX get cache element with status updating from file
+ * Accepts: MAIL stream
+ *	    message number
+ *	    expunge OK flag
+ * Returns: cache element
+ */
+
+MESSAGECACHE *mbx_elt (MAILSTREAM *stream,unsigned long msgno,long expok)
+{
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  struct {			/* old flags */
+    unsigned int seen : 1;
+    unsigned int deleted : 1;
+    unsigned int flagged : 1;
+    unsigned int answered : 1;
+    unsigned int draft : 1;
+    unsigned long user_flags;
+  } old;
+  old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged;
+  old.answered = elt->answered; old.draft = elt->draft;
+  old.user_flags = elt->user_flags;
+				/* get new flags */
+  if (mbx_read_flags (stream,elt) && expok) {
+    mail_expunged (stream,elt->msgno);
+    return NIL;			/* return this message was expunged */
+  }
+  if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
+      (old.flagged != elt->flagged) || (old.answered != elt->answered) ||
+      (old.draft != elt->draft) || (old.user_flags != elt->user_flags))
+    MM_FLAGS (stream,msgno);	/* let top level know */
+  return elt;
+}
+
+/* MBX read flags from file
+ * Accepts: MAIL stream
+ *	    cache element
+ * Returns: non-NIL if message expunged
+ */
+
+unsigned long mbx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  unsigned long i;
+  struct stat sbuf;
+  fstat (LOCAL->fd,&sbuf);	/* get status */
+				/* make sure file size is good */
+  if (sbuf.st_size < LOCAL->filesize) {
+    sprintf (LOCAL->buf,"Mailbox shrank from %lu to %lu in flag read!",
+	     (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
+    fatal (LOCAL->buf);
+  }
+				/* set the seek pointer */
+  lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	 elt->private.special.text.size - 24,L_SET);
+				/* read the new flags */
+  if (read (LOCAL->fd,LOCAL->buf,14) < 0) {
+    sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno));
+    fatal (LOCAL->buf);
+  }
+  if ((LOCAL->buf[0] != ';') || (LOCAL->buf[13] != '-')) {
+    LOCAL->buf[14] = '\0';	/* tie off buffer for error message */
+    sprintf (LOCAL->buf+50,"Invalid flags for message %lu (%lu %lu): %s",
+	     elt->msgno,elt->private.special.offset,
+	     elt->private.special.text.size,(char *) LOCAL->buf);
+    fatal (LOCAL->buf+50);
+  }
+  LOCAL->buf[13] = '\0';	/* tie off buffer */
+				/* calculate system flags */
+  i = strtoul (LOCAL->buf+9,NIL,16);
+  elt->seen = i & fSEEN ? T : NIL;
+  elt->deleted = i & fDELETED ? T : NIL;
+  elt->flagged = i & fFLAGGED ? T : NIL;
+  elt->answered = i & fANSWERED ? T : NIL;
+  elt->draft = i & fDRAFT ? T : NIL;
+  LOCAL->expunged |= i & fEXPUNGED ? T : NIL;
+  LOCAL->buf[9] = '\0';		/* tie off flags */
+				/* get user flags value */
+  elt->user_flags = strtoul (LOCAL->buf+1,NIL,16);
+  elt->valid = T;		/* have valid flags now */
+  return i & fEXPUNGED;
+}
+
+/* MBX update header
+ * Accepts: MAIL stream
+ */
+
+#ifndef CYGKLUDGEOFFSET
+#define CYGKLUDGEOFFSET 0
+#endif
+
+void mbx_update_header (MAILSTREAM *stream)
+{
+  int i;
+  char *s = LOCAL->buf;
+  memset (s,'\0',HDRSIZE);	/* initialize header */
+  sprintf (s,"*mbx*\015\012%08lx%08lx\015\012",
+	   stream->uid_validity,stream->uid_last);
+  for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i]; ++i)
+    sprintf (s += strlen (s),"%s\015\012",stream->user_flags[i]);
+  LOCAL->ffuserflag = i;	/* first free user flag */
+				/* can we create more user flags? */
+  stream->kwd_create = (i < NUSERFLAGS) ? T : NIL;
+				/* write reserved lines */
+  while (i++ < NUSERFLAGS) strcat (s,"\015\012");
+  sprintf (LOCAL->buf + HDRSIZE - 10,"%08lx\015\012",LOCAL->lastpid);
+  while (T) {			/* rewind file */
+    lseek (LOCAL->fd,CYGKLUDGEOFFSET,L_SET);
+				/* write new header */
+    if (write (LOCAL->fd,LOCAL->buf + CYGKLUDGEOFFSET,
+	       HDRSIZE - CYGKLUDGEOFFSET) > 0) break;
+    MM_NOTIFY (stream,strerror (errno),WARN);
+    MM_DISKERROR (stream,errno,T);
+  }
+}
+
+/* MBX update status string
+ * Accepts: MAIL stream
+ *	    message number
+ *	    flags
+ */
+
+void mbx_update_status (MAILSTREAM *stream,unsigned long msgno,long flags)
+{
+  struct stat sbuf;
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+				/* readonly */
+  if (stream->rdonly || !elt->valid) mbx_read_flags (stream,elt);
+  else {			/* readwrite */
+    fstat (LOCAL->fd,&sbuf);	/* get status */
+				/* make sure file size is good */
+    if (sbuf.st_size < LOCAL->filesize) {
+      sprintf (LOCAL->buf,"Mailbox shrank from %lu to %lu in flag update!",
+	       (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
+      fatal (LOCAL->buf);
+    }
+				/* set the seek pointer */
+    lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	   elt->private.special.text.size - 24,L_SET);
+				/* read the new flags */
+    if (read (LOCAL->fd,LOCAL->buf,14) < 0) {
+      sprintf (LOCAL->buf,"Unable to read old status: %s",strerror (errno));
+      fatal (LOCAL->buf);
+    }
+    if ((LOCAL->buf[0] != ';') || (LOCAL->buf[13] != '-')) {
+      LOCAL->buf[14] = '\0';	/* tie off buffer for error message */
+      sprintf (LOCAL->buf+50,"Invalid flags for message %lu (%lu %lu): %s",
+	       elt->msgno,elt->private.special.offset,
+	       elt->private.special.text.size,(char *) LOCAL->buf);
+      fatal (LOCAL->buf+50);
+    }
+				/* print new flag string */
+    sprintf (LOCAL->buf,"%08lx%04x-%08lx",elt->user_flags,(unsigned)
+	     (((elt->deleted && flags) ?
+	       fEXPUNGED : (strtoul (LOCAL->buf+9,NIL,16)) & fEXPUNGED) +
+	      (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
+	      (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
+	      (fDRAFT * elt->draft) + fOLD),elt->private.uid);
+    while (T) {			/* get to that place in the file */
+      lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	     elt->private.special.text.size - 23,L_SET);
+				/* write new flags and UID */
+      if (write (LOCAL->fd,LOCAL->buf,21) > 0) break;
+      MM_NOTIFY (stream,strerror (errno),WARN);
+      MM_DISKERROR (stream,errno,T);
+    }
+  }
+}
+
+/* MBX locate header for a message
+ * Accepts: MAIL stream
+ *	    message number
+ *	    pointer to returned header size
+ *	    pointer to possible returned header
+ * Returns: position of header in file
+ */
+
+#define HDRBUFLEN 16384		/* good enough for most headers */
+#define SLOP 4			/* CR LF CR LF */
+
+unsigned long mbx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			  unsigned long *size,char **hdr)
+{
+  unsigned long siz,done;
+  long i;
+  unsigned char *s,*t,*te;
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  unsigned long ret = elt->private.special.offset +
+    elt->private.special.text.size;
+  if (hdr) *hdr = NIL;		/* assume no header returned */
+				/* is header size known? */ 
+  if (*size = elt->private.msg.header.text.size) return ret;
+				/* paranoia check */
+  if (LOCAL->buflen < (HDRBUFLEN + SLOP))
+    fatal ("LOCAL->buf smaller than HDRBUFLEN");
+  lseek (LOCAL->fd,ret,L_SET);	/* get to header position */
+				/* read HDRBUFLEN chunks with 4 byte slop */
+  for (done = siz = 0, s = LOCAL->buf;
+       (i = min ((long) (elt->rfc822_size - done),(long) HDRBUFLEN)) &&
+       (read (LOCAL->fd,s,i) == i);
+       done += i, siz += (t - LOCAL->buf) - SLOP, s = LOCAL->buf + SLOP) {
+    te = (t = s + i) - 12;	/* calculate end of fast scan */
+				/* fast scan for CR */
+    for (s = LOCAL->buf; s < te;)
+      if (((*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') ||
+	   (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') ||
+	   (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') ||
+	   (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015')) &&
+	  (*s == '\012') && (*++s == '\015') && (*++s == '\012')) {
+	*size = elt->private.msg.header.text.size = siz + (++s - LOCAL->buf);
+	if (hdr) *hdr = LOCAL->buf;
+	return ret;
+      }
+    for (te = t - 3; (s < te);)	/* final character-at-a-time scan */
+      if ((*s++ == '\015') && (*s == '\012') && (*++s == '\015') &&
+	  (*++s == '\012')) {
+	*size = elt->private.msg.header.text.size = siz + (++s - LOCAL->buf);
+	if (hdr) *hdr = LOCAL->buf;
+	return ret;
+      }
+    if (i <= SLOP) break;	/* end of data */
+				/* slide over last 4 bytes */
+    memmove (LOCAL->buf,t - SLOP,SLOP);
+    hdr = NIL;			/* can't return header this way */
+  }
+				/* not found: header consumes entire message */
+  elt->private.msg.header.text.size = *size = elt->rfc822_size;
+  if (hdr) *hdr = LOCAL->buf;	/* possibly return header too */
+  return ret;
+}
+
+/* MBX mail rewrite mailbox
+ * Accepts: MAIL stream
+ *	    pointer to return reclaimed size
+ *	    flags (0 = no expunge, 1 = expunge deleted, -1 = expunge sequence)
+ * Returns: number of expunged messages
+ */
+
+unsigned long mbx_rewrite (MAILSTREAM *stream,unsigned long *reclaimed,
+			   long flags)
+{
+  time_t tp[2];
+  struct stat sbuf;
+  off_t pos,ppos;
+  int ld;
+  unsigned long i,j,k,m,delta;
+  unsigned long n = *reclaimed = 0;
+  unsigned long recent = 0;
+  char lock[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  /* The cretins who designed flock() created a window of vulnerability in
+   * upgrading locks from shared to exclusive or downgrading from exclusive
+   * to shared.  Rather than maintain the lock at shared status at a minimum,
+   * flock() actually *releases* the former lock.  Obviously they never talked
+   * to any database guys.  Fortunately, we have the parse/append permission
+   * lock.  If we require this lock before going exclusive on the mailbox,
+   * another process can not sneak in and steal the exclusive mailbox lock on
+   * us, because it will block on trying to get parse/append permission first.
+   */
+				/* get parse/append permission */
+  if ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) < 0) {
+    MM_LOG ("Unable to lock mailbox for rewrite",ERROR);
+    return 0;
+  }
+  fstat (LOCAL->fd,&sbuf);	/* get current write time */
+  if (LOCAL->filetime && !LOCAL->flagcheck &&
+      (LOCAL->filetime < sbuf.st_mtime)) LOCAL->flagcheck = T;
+  if (!mbx_parse (stream)) {	/* make sure see any newly-arrived messages */
+    unlockfd (ld,lock);		/* failed?? */
+    return 0;
+  }
+  if (LOCAL->flagcheck) {	/* sweep flags if need flagcheck */
+    LOCAL->filetime = sbuf.st_mtime;
+    for (i = 1; i <= stream->nmsgs; ++i) mbx_elt (stream,i,NIL);
+    LOCAL->flagcheck = NIL;
+  }
+
+				/* get exclusive access */
+  if (!flock (LOCAL->fd,LOCK_EX|LOCK_NB)) {
+    MM_CRITICAL (stream);	/* go critical */
+    for (i = 1,delta = 0,pos = ppos = HDRSIZE; i <= stream->nmsgs; ) {
+				/* note if message not at predicted location */
+      if (m = (elt = mbx_elt (stream,i,NIL))->private.special.offset - ppos) {
+	ppos = elt->private.special.offset;
+	*reclaimed += m;	/* note reclaimed message space */
+	delta += m;		/* and as expunge delta  */
+      }
+				/* number of bytes to smash or preserve */
+      ppos += (k = elt->private.special.text.size + elt->rfc822_size);
+				/* if need to expunge this message*/
+      if (flags && elt->deleted && ((flags > 0) || elt->sequence)) {
+	delta += k;		/* number of bytes to delete */
+	mail_expunged(stream,i);/* notify upper levels */
+	n++;			/* count up one more expunged message */
+      }
+      else {			/* preserved message */
+	i++;			/* count this message */
+	if (elt->recent) ++recent;
+	if (delta) {		/* moved, note first byte to preserve */
+	  j = elt->private.special.offset;
+	  do {			/* read from source position */
+	    m = min (k,LOCAL->buflen);
+	    lseek (LOCAL->fd,j,L_SET);
+	    read (LOCAL->fd,LOCAL->buf,m);
+	    pos = j - delta;	/* write to destination position */
+	    while (T) {
+	      lseek (LOCAL->fd,pos,L_SET);
+	      if (write (LOCAL->fd,LOCAL->buf,m) > 0) break;
+	      MM_NOTIFY (stream,strerror (errno),WARN);
+	      MM_DISKERROR (stream,errno,T);
+	    }
+	    pos += m;		/* new position */
+	    j += m;		/* next chunk, perhaps */
+	  } while (k -= m);	/* until done */
+				/* note the new address of this text */
+	  elt->private.special.offset -= delta;
+	}
+				/* preserved but no deleted messages yet */
+	else pos = elt->private.special.offset + k;
+      }
+    }
+				/* deltaed file size match position? */
+    if (m = (LOCAL->filesize -= delta) - pos) {
+      *reclaimed += m;		/* probably an fEXPUNGED msg */
+      LOCAL->filesize = pos;	/* set correct size */
+    }
+				/* truncate file after last message */
+    ftruncate (LOCAL->fd,LOCAL->filesize);
+    fsync (LOCAL->fd);		/* force disk update */
+    MM_NOCRITICAL (stream);	/* release critical */
+    (*bn) (BLOCK_FILELOCK,NIL);
+    flock (LOCAL->fd,LOCK_SH);	/* allow sharers again */
+    (*bn) (BLOCK_NONE,NIL);
+  }
+
+  else {			/* can't get exclusive */
+    (*bn) (BLOCK_FILELOCK,NIL);
+    flock (LOCAL->fd,LOCK_SH);	/* recover previous shared mailbox lock */
+    (*bn) (BLOCK_NONE,NIL);
+				/* do hide-expunge when shared */
+    if (flags) for (i = 1; i <= stream->nmsgs; ) {
+      if (elt = mbx_elt (stream,i,T)) {
+				/* make the message invisible */
+	if (elt->deleted && ((flags > 0) || elt->sequence)) {
+	  mbx_update_status (stream,elt->msgno,LONGT);
+				/* notify upper levels */
+	  mail_expunged (stream,i);
+	  n++;			/* count up one more expunged message */
+	}
+	else {
+	  i++;			/* preserved message */
+	  if (elt->recent) ++recent;
+	}
+      }
+      else n++;			/* count up one more expunged message */
+    }
+    fsync (LOCAL->fd);		/* force disk update */
+  }
+  fstat (LOCAL->fd,&sbuf);	/* get new write time */
+  tp[1] = LOCAL->filetime = sbuf.st_mtime;
+  tp[0] = time (0);		/* reset atime to now */
+  utime (stream->mailbox,tp);
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+				/* notify upper level of new mailbox size */
+  mail_exists (stream,stream->nmsgs);
+  mail_recent (stream,recent);
+  return n;			/* return number of expunged messages */
+}
+
+/* MBX mail lock for flag updating
+ * Accepts: stream
+ * Returns: T if successful, NIL if failure
+ */
+
+long mbx_flaglock (MAILSTREAM *stream)
+{
+  struct stat sbuf;
+  unsigned long i;
+  int ld;
+  char lock[MAILTMPLEN];
+				/* no-op if readonly or already locked */
+  if (!stream->rdonly && LOCAL && (LOCAL->fd >= 0) && (LOCAL->ld < 0)) {
+				/* lock now */
+    if ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) < 0) return NIL;
+    if (!LOCAL->flagcheck) {	/* don't do this if flagcheck already needed */
+      if (LOCAL->filetime) {	/* know previous time? */
+	fstat (LOCAL->fd,&sbuf);/* get current write time */
+	if (LOCAL->filetime < sbuf.st_mtime) LOCAL->flagcheck = T;
+	LOCAL->filetime = 0;	/* don't do this test for any other messages */
+      }
+      if (!mbx_parse (stream)) {/* parse mailbox */
+	unlockfd (ld,lock);	/* shouldn't happen */
+	return NIL;
+      }
+      if (LOCAL->flagcheck)	/* invalidate cache if flagcheck */
+	for (i = 1; i <= stream->nmsgs; ++i) mail_elt (stream,i)->valid = NIL;
+    }
+    LOCAL->ld = ld;		/* copy to stream for subsequent calls */
+    memcpy (LOCAL->lock,lock,MAILTMPLEN);
+  }
+  return LONGT;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/mh.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1283 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	MH mail routines
+ *
+ * Author(s):	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	23 February 1992
+ * Last Edited:	11 October 2007
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "mail.h"
+#include "osdep.h"
+#include <pwd.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "misc.h"
+#include "dummy.h"
+#include "fdstring.h"
+
+
+/* Build parameters */
+
+#define MHINBOX "#mhinbox"	/* corresponds to namespace in env_unix.c */
+#define MHINBOXDIR "inbox"
+#define MHPROFILE ".mh_profile"
+#define MHCOMMA ','
+#define MHSEQUENCE ".mh_sequence"
+#define MHSEQUENCES ".mh_sequences"
+#define MHPATH "Mail"
+
+
+/* mh_load_message() flags */
+
+#define MLM_HEADER 0x1		/* load message text */
+#define MLM_TEXT 0x2		/* load message text */
+
+/* MH I/O stream local data */
+	
+typedef struct mh_local {
+  char *dir;			/* spool directory name */
+  unsigned char buf[CHUNKSIZE];	/* temporary buffer */
+  unsigned long cachedtexts;	/* total size of all cached texts */
+  time_t scantime;		/* last time directory scanned */
+} MHLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((MHLOCAL *) stream->local)
+
+
+/* Function prototypes */
+
+DRIVER *mh_valid (char *name);
+int mh_isvalid (char *name,char *tmp,long synonly);
+int mh_namevalid (char *name);
+char *mh_path (char *tmp);
+void *mh_parameters (long function,void *value);
+long mh_dirfmttest (char *name);
+void mh_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void mh_list (MAILSTREAM *stream,char *ref,char *pat);
+void mh_lsub (MAILSTREAM *stream,char *ref,char *pat);
+void mh_list_work (MAILSTREAM *stream,char *dir,char *pat,long level);
+long mh_subscribe (MAILSTREAM *stream,char *mailbox);
+long mh_unsubscribe (MAILSTREAM *stream,char *mailbox);
+long mh_create (MAILSTREAM *stream,char *mailbox);
+long mh_delete (MAILSTREAM *stream,char *mailbox);
+long mh_rename (MAILSTREAM *stream,char *old,char *newname);
+MAILSTREAM *mh_open (MAILSTREAM *stream);
+void mh_close (MAILSTREAM *stream,long options);
+void mh_fast (MAILSTREAM *stream,char *sequence,long flags);
+void mh_load_message (MAILSTREAM *stream,unsigned long msgno,long flags);
+char *mh_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
+		 long flags);
+long mh_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+long mh_ping (MAILSTREAM *stream);
+void mh_check (MAILSTREAM *stream);
+long mh_expunge (MAILSTREAM *stream,char *sequence,long options);
+long mh_copy (MAILSTREAM *stream,char *sequence,char *mailbox,
+	      long options);
+long mh_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+int mh_select (struct direct *name);
+int mh_numsort (const void *d1,const void *d2);
+char *mh_file (char *dst,char *name);
+long mh_canonicalize (char *pattern,char *ref,char *pat);
+void mh_setdate (char *file,MESSAGECACHE *elt);
+
+/* MH mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER mhdriver = {
+  "mh",				/* driver name */
+				/* driver flags */
+  DR_MAIL|DR_LOCAL|DR_NOFAST|DR_NAMESPACE|DR_NOSTICKY|DR_DIRFMT,
+  (DRIVER *) NIL,		/* next driver */
+  mh_valid,			/* mailbox is valid for us */
+  mh_parameters,		/* manipulate parameters */
+  mh_scan,			/* scan mailboxes */
+  mh_list,			/* find mailboxes */
+  mh_lsub,			/* find subscribed mailboxes */
+  mh_subscribe,			/* subscribe to mailbox */
+  mh_unsubscribe,		/* unsubscribe from mailbox */
+  mh_create,			/* create mailbox */
+  mh_delete,			/* delete mailbox */
+  mh_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  mh_open,			/* open mailbox */
+  mh_close,			/* close mailbox */
+  mh_fast,			/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  mh_header,			/* fetch message header */
+  mh_text,			/* fetch message body */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  NIL,				/* modify flags */
+  NIL,				/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  mh_ping,			/* ping mailbox to see if still alive */
+  mh_check,			/* check for new messages */
+  mh_expunge,			/* expunge deleted messages */
+  mh_copy,			/* copy messages to another mailbox */
+  mh_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM mhproto = {&mhdriver};
+
+
+static char *mh_profile = NIL;	/* holds MH profile */
+static char *mh_pathname = NIL;	/* holds MH path name */
+static long mh_once = 0;	/* already snarled once */
+static long mh_allow_inbox =NIL;/* allow INBOX as well as MHINBOX */
+
+/* MH mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *mh_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+  return mh_isvalid (name,tmp,T) ? &mhdriver : NIL;
+}
+
+
+/* MH mail test for valid mailbox
+ * Accepts: mailbox name
+ *	    temporary buffer to use
+ *	    syntax only test flag
+ * Returns: T if valid, NIL otherwise
+ */
+
+int mh_isvalid (char *name,char *tmp,long synonly)
+{
+  struct stat sbuf;
+  char *s,*t,altname[MAILTMPLEN];
+  unsigned long i;
+  int ret = NIL;
+  errno = NIL;			/* zap any error condition */
+				/* mh name? */
+  if ((mh_allow_inbox && !compare_cstring (name,"INBOX")) ||
+      !compare_cstring (name,MHINBOX) ||
+      ((name[0] == '#') && ((name[1] == 'm') || (name[1] == 'M')) &&
+       ((name[2] == 'h') || (name[2] == 'H')) && (name[3] == '/') && name[4])){
+    if (mh_path (tmp))		/* validate name if INBOX or not synonly */
+      ret = (synonly && compare_cstring (name,"INBOX")) ?
+	T : ((stat (mh_file (tmp,name),&sbuf) == 0) &&
+	     (sbuf.st_mode & S_IFMT) == S_IFDIR);
+    else if (!mh_once++) {	/* only report error once */
+      sprintf (tmp,"%.900s not found, mh format names disabled",mh_profile);
+      mm_log (tmp,WARN);
+    }
+  }
+				/* see if non-NS name within mh hierarchy */
+  else if ((name[0] != '#') && (s = mh_path (tmp)) && (i = strlen (s)) &&
+	   (t = mailboxfile (tmp,name)) && !strncmp (t,s,i) &&
+	   (tmp[i] == '/') && tmp[i+1]) {
+    sprintf (altname,"#mh%.900s",tmp+i);
+				/* can't do synonly here! */
+    ret = mh_isvalid (altname,tmp,NIL);
+  }
+  else errno = EINVAL;		/* bogus name */
+  return ret;
+}
+
+/* MH mail test for valid mailbox
+ * Accepts: mailbox name
+ * Returns: T if valid, NIL otherwise
+ */
+
+int mh_namevalid (char *name)
+{
+  char *s;
+  if (name[0] == '#' && (name[1] == 'm' || name[1] == 'M') &&
+      (name[2] == 'h' || name[2] == 'H') && name[3] == '/')
+    for (s = name; s && *s;) {	/* make sure no all-digit nodes */
+      if (isdigit (*s)) s++;	/* digit, check this node further... */
+      else if (*s == '/') break;/* all digit node, barf */
+				/* non-digit, skip to next node or return */
+      else if (!((s = strchr (s+1,'/')) && *++s)) return T;
+    }
+  return NIL;			/* all numeric or empty node */
+}
+
+/* Return MH path
+ * Accepts: temporary buffer
+ * Returns: MH path or NIL if MH disabled
+ */
+
+char *mh_path (char *tmp)
+{
+  char *s,*t,*v,*r;
+  int fd;
+  struct stat sbuf;
+  if (!mh_profile) {		/* build mh_profile and mh_pathname now */
+    sprintf (tmp,"%s/%s",myhomedir (),MHPROFILE);
+    if ((fd = open (mh_profile = cpystr (tmp),O_RDONLY,NIL)) >= 0) {
+      fstat (fd,&sbuf);		/* yes, get size and read file */
+      read (fd,(t = (char *) fs_get (sbuf.st_size + 1)),sbuf.st_size);
+      close (fd);		/* don't need the file any more */
+      t[sbuf.st_size] = '\0';	/* tie it off */
+				/* parse profile file */
+      for (s = strtok_r (t,"\r\n",&r); s && *s; s = strtok_r (NIL,"\r\n",&r)) {
+				/* found space in line? */
+	if (v = strpbrk (s," \t")) {
+	  *v++ = '\0';		/* tie off, is keyword "Path:"? */
+	  if (!compare_cstring (s,"Path:")) {
+				/* skip whitespace */
+	    while ((*v == ' ') || (*v == '\t')) ++v;
+				/* absolute path? */
+	    if (*v == '/') s = v;
+	    else sprintf (s = tmp,"%s/%s",myhomedir (),v);
+				/* copy name */
+	    mh_pathname = cpystr (s);
+	    break;		/* don't need to look at rest of file */
+	  }
+	}
+      }
+      fs_give ((void **) &t);	/* flush profile text */
+      if (!mh_pathname) {	/* default path if not in the profile */
+	sprintf (tmp,"%s/%s",myhomedir (),MHPATH);
+	mh_pathname = cpystr (tmp);
+      }
+    }
+  }
+  return mh_pathname;
+}
+
+/* MH manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *mh_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case GET_INBOXPATH:
+    if (value) ret = mh_file ((char *) value,"INBOX");
+    break;
+  case GET_DIRFMTTEST:
+    ret = (void *) mh_dirfmttest;
+    break;
+  case SET_MHPROFILE:
+    if (mh_profile) fs_give ((void **) &mh_profile);
+    mh_profile = cpystr ((char *) value);
+  case GET_MHPROFILE:
+    ret = (void *) mh_profile;
+    break;
+  case SET_MHPATH:
+    if (mh_pathname) fs_give ((void **) &mh_pathname);
+    mh_pathname = cpystr ((char *) value);
+  case GET_MHPATH:
+    ret = (void *) mh_pathname;
+    break;
+  case SET_MHALLOWINBOX:
+    mh_allow_inbox = value ? T : NIL;
+  case GET_MHALLOWINBOX:
+    ret = (void *) (mh_allow_inbox ? VOIDT : NIL);
+  }
+  return ret;
+}
+
+
+/* MH test for directory format internal node
+ * Accepts: candidate node name
+ * Returns: T if internal name, NIL otherwise
+ */
+
+long mh_dirfmttest (char *s)
+{
+  int c;
+				/* sequence(s) file is an internal name */
+  if (strcmp (s,MHSEQUENCE) && strcmp (s,MHSEQUENCES)) {
+    if (*s == MHCOMMA) ++s;	/* else comma + all numeric name */
+				/* success if all-numeric */
+    while (c = *s++) if (!isdigit (c)) return NIL;
+  }
+  return LONGT;
+}
+
+/* MH scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void mh_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  char *s,test[MAILTMPLEN],file[MAILTMPLEN];
+  long i = 0;
+  if (!pat || !*pat) {		/* empty pattern? */
+    if (mh_canonicalize (test,ref,"*")) {
+				/* tie off name at root */
+      if (s = strchr (test,'/')) *++s = '\0';
+      else test[0] = '\0';
+      mm_list (stream,'/',test,LATT_NOSELECT);
+    }
+  }
+				/* get canonical form of name */
+  else if (mh_canonicalize (test,ref,pat)) {
+    if (contents) {		/* maybe I'll implement this someday */
+      mm_log ("Scan not valid for mh mailboxes",ERROR);
+      return;
+    }
+    if (test[3] == '/') {	/* looking down levels? */
+				/* yes, found any wildcards? */
+      if (s = strpbrk (test,"%*")) {
+				/* yes, copy name up to that point */
+	strncpy (file,test+4,i = s - (test+4));
+	file[i] = '\0';		/* tie off */
+      }
+      else strcpy (file,test+4);/* use just that name then */
+				/* find directory name */
+      if (s = strrchr (file,'/')) {
+	*s = '\0';		/* found, tie off at that point */
+	s = file;
+      }
+				/* do the work */
+      mh_list_work (stream,s,test,0);
+    }
+				/* always an INBOX */
+    if (!compare_cstring (test,MHINBOX))
+      mm_list (stream,NIL,MHINBOX,LATT_NOINFERIORS);
+  }
+}
+
+/* MH list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mh_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  mh_scan (stream,ref,pat,NIL);
+}
+
+
+/* MH list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mh_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  void *sdb = NIL;
+  char *s,test[MAILTMPLEN];
+				/* get canonical form of name */
+  if (mh_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) {
+    do if (pmatch_full (s,test,'/')) mm_lsub (stream,'/',s,NIL);
+    while (s = sm_read (&sdb)); /* until no more subscriptions */
+  }
+}
+
+/* MH list mailboxes worker routine
+ * Accepts: mail stream
+ *	    directory name to search
+ *	    search pattern
+ *	    search level
+ */
+
+void mh_list_work (MAILSTREAM *stream,char *dir,char *pat,long level)
+{
+  DIR *dp;
+  struct direct *d;
+  struct stat sbuf;
+  char *cp,*np,curdir[MAILTMPLEN],name[MAILTMPLEN];
+				/* build MH name to search */
+  if (dir) sprintf (name,"#mh/%s/",dir);
+  else strcpy (name,"#mh/");
+				/* make directory name, punt if bogus */
+  if (!mh_file (curdir,name)) return;
+  cp = curdir + strlen (curdir);/* end of directory name */
+  np = name + strlen (name);	/* end of MH name */
+  if (dp = opendir (curdir)) {	/* open directory */
+    while (d = readdir (dp))	/* scan, ignore . and numeric names */
+      if ((d->d_name[0] != '.') && !mh_select (d)) {
+	strcpy (cp,d->d_name);	/* make directory name */
+	if (!stat (curdir,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) {
+	  strcpy (np,d->d_name);/* make mh name of directory name */
+				/* yes, an MH name if full match */
+	  if (pmatch_full (name,pat,'/')) mm_list (stream,'/',name,NIL);
+				/* check if should recurse */
+	  if (dmatch (name,pat,'/') &&
+	      (level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL)))
+	    mh_list_work (stream,name+4,pat,level+1);
+	}
+      }
+    closedir (dp);		/* all done, flush directory */
+  }
+}
+
+/* MH mail subscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to add to subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long mh_subscribe (MAILSTREAM *stream,char *mailbox)
+{
+  return sm_subscribe (mailbox);
+}
+
+
+/* MH mail unsubscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to delete from subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long mh_unsubscribe (MAILSTREAM *stream,char *mailbox)
+{
+  return sm_unsubscribe (mailbox);
+}
+
+/* MH mail create mailbox
+ * Accepts: mail stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long mh_create (MAILSTREAM *stream,char *mailbox)
+{
+  char tmp[MAILTMPLEN];
+  if (!mh_namevalid (mailbox))	/* validate name */
+    sprintf (tmp,"Can't create mailbox %.80s: invalid MH-format name",mailbox);
+				/* must not already exist */
+  else if (mh_isvalid (mailbox,tmp,NIL))
+    sprintf (tmp,"Can't create mailbox %.80s: mailbox already exists",mailbox);
+  else if (!mh_path (tmp)) return NIL;
+				/* try to make it */
+  else if (!(mh_file (tmp,mailbox) &&
+	     dummy_create_path (stream,strcat (tmp,"/"),
+				get_dir_protection (mailbox))))
+    sprintf (tmp,"Can't create mailbox %.80s: %s",mailbox,strerror (errno));
+  else return LONGT;		/* success */
+  mm_log (tmp,ERROR);
+  return NIL;
+}
+
+/* MH mail delete mailbox
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long mh_delete (MAILSTREAM *stream,char *mailbox)
+{
+  DIR *dirp;
+  struct direct *d;
+  int i;
+  char tmp[MAILTMPLEN];
+				/* is mailbox valid? */
+  if (!mh_isvalid (mailbox,tmp,NIL)) {
+    sprintf (tmp,"Can't delete mailbox %.80s: no such mailbox",mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* get name of directory */
+  i = strlen (mh_file (tmp,mailbox));
+  if (dirp = opendir (tmp)) {	/* open directory */
+    tmp[i++] = '/';		/* now apply trailing delimiter */
+				/* massacre all mh owned files */
+    while (d = readdir (dirp)) if (mh_dirfmttest (d->d_name)) {
+      strcpy (tmp + i,d->d_name);
+      unlink (tmp);		/* sayonara */
+    }
+    closedir (dirp);		/* flush directory */
+  }
+				/* try to remove the directory */
+  if (rmdir (mh_file (tmp,mailbox))) {
+    sprintf (tmp,"Can't delete mailbox %.80s: %s",mailbox,strerror (errno));
+    mm_log (tmp,WARN);
+  }
+  return T;			/* return success */
+}
+
+/* MH mail rename mailbox
+ * Accepts: MH mail stream
+ *	    old mailbox name
+ *	    new mailbox name
+ * Returns: T on success, NIL on failure
+ */
+
+long mh_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  char c,*s,tmp[MAILTMPLEN],tmp1[MAILTMPLEN];
+  struct stat sbuf;
+				/* old mailbox name must be valid */
+  if (!mh_isvalid (old,tmp,NIL))
+    sprintf (tmp,"Can't rename mailbox %.80s: no such mailbox",old);
+  else if (!mh_namevalid (newname))
+    sprintf (tmp,"Can't rename to mailbox %.80s: invalid MH-format name",
+	     newname);
+				/* new mailbox name must not be valid */
+  else if (mh_isvalid (newname,tmp,NIL))
+    sprintf (tmp,"Can't rename to mailbox %.80s: destination already exists",
+	     newname);
+				/* success if can rename the directory */
+  else {			/* found superior to destination name? */
+    if (s = strrchr (mh_file (tmp1,newname),'/')) {
+      c = *++s;			/* remember first character of inferior */
+      *s = '\0';		/* tie off to get just superior */
+				/* name doesn't exist, create it */
+      if ((stat (tmp1,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+	  !dummy_create_path (stream,tmp1,get_dir_protection (newname)))
+	return NIL;
+      *s = c;			/* restore full name */
+    }
+    if (!rename (mh_file (tmp,old),tmp1)) return T;
+    sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",
+	     old,newname,strerror (errno));
+  }
+  mm_log (tmp,ERROR);		/* something failed */
+  return NIL;
+}
+
+/* MH mail open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *mh_open (MAILSTREAM *stream)
+{
+  char tmp[MAILTMPLEN];
+  if (!stream) return &mhproto;	/* return prototype for OP_PROTOTYPE call */
+  if (stream->local) fatal ("mh recycle stream");
+  stream->local = fs_get (sizeof (MHLOCAL));
+  /* INBOXness is one of the following:
+   * #mhinbox (case-independent)
+   * #mh/inbox (mh is case-independent, inbox is case-dependent)
+   * INBOX (case-independent
+   */		
+  stream->inbox =		/* note if an INBOX or not */
+    (!compare_cstring (stream->mailbox,MHINBOX) ||
+     ((stream->mailbox[0] == '#') &&
+      ((stream->mailbox[1] == 'm') || (stream->mailbox[1] == 'M')) &&
+      ((stream->mailbox[2] == 'h') || (stream->mailbox[2] == 'H')) &&
+      (stream->mailbox[3] == '/') && !strcmp (stream->mailbox+4,MHINBOXDIR)) ||
+     !compare_cstring (stream->mailbox,"INBOX")) ? T : NIL;
+  mh_file (tmp,stream->mailbox);/* get directory name */
+  LOCAL->dir = cpystr (tmp);	/* copy directory name for later */
+  LOCAL->scantime = 0;		/* not scanned yet */
+  LOCAL->cachedtexts = 0;	/* no cached texts */
+  stream->sequence++;		/* bump sequence number */
+				/* parse mailbox */
+  stream->nmsgs = stream->recent = 0;
+  if (!mh_ping (stream)) return NIL;
+  if (!(stream->nmsgs || stream->silent))
+    mm_log ("Mailbox is empty",(long) NIL);
+  return stream;		/* return stream to caller */
+}
+
+/* MH mail close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void mh_close (MAILSTREAM *stream,long options)
+{
+  if (LOCAL) {			/* only if a file is open */
+    int silent = stream->silent;
+    stream->silent = T;		/* note this stream is dying */
+    if (options & CL_EXPUNGE) mh_expunge (stream,NIL,NIL);
+    if (LOCAL->dir) fs_give ((void **) &LOCAL->dir);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+    stream->silent = silent;	/* reset silent state */
+  }
+}
+
+
+/* MH mail fetch fast information
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ */
+
+void mh_fast (MAILSTREAM *stream,char *sequence,long flags)
+{
+  MESSAGECACHE *elt;
+  unsigned long i;
+				/* set up metadata for all messages */
+  if (stream && LOCAL && ((flags & FT_UID) ?
+			  mail_uid_sequence (stream,sequence) :
+			  mail_sequence (stream,sequence)))
+    for (i = 1; i <= stream->nmsgs; i++)
+      if ((elt = mail_elt (stream,i))->sequence &&
+	  !(elt->day && elt->rfc822_size)) mh_load_message (stream,i,NIL);
+}
+
+/* MH load message into cache
+ * Accepts: MAIL stream
+ *	    message #
+ *	    option flags
+ */
+
+void mh_load_message (MAILSTREAM *stream,unsigned long msgno,long flags)
+{
+  unsigned long i,j,nlseen;
+  int fd;
+  unsigned char c,*t;
+  struct stat sbuf;
+  MESSAGECACHE *elt;
+  FDDATA d;
+  STRING bs;
+  elt = mail_elt (stream,msgno);/* get elt */
+				/* build message file name */
+  sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid);
+				/* anything we need not currently cached? */
+  if ((!elt->day || !elt->rfc822_size ||
+       ((flags & MLM_HEADER) && !elt->private.msg.header.text.data) ||
+       ((flags & MLM_TEXT) && !elt->private.msg.text.text.data)) &&
+      ((fd = open (LOCAL->buf,O_RDONLY,NIL)) >= 0)) {
+    fstat (fd,&sbuf);		/* get file metadata */
+    d.fd = fd;			/* set up file descriptor */
+    d.pos = 0;			/* start of file */
+    d.chunk = LOCAL->buf;
+    d.chunksize = CHUNKSIZE;
+    INIT (&bs,fd_string,&d,sbuf.st_size);
+    if (!elt->day) {		/* set internaldate to file date */
+      struct tm *tm = gmtime (&sbuf.st_mtime);
+      elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1;
+      elt->year = tm->tm_year + 1900 - BASEYEAR;
+      elt->hours = tm->tm_hour; elt->minutes = tm->tm_min;
+      elt->seconds = tm->tm_sec;
+      elt->zhours = 0; elt->zminutes = 0;
+    }
+
+    if (!elt->rfc822_size) {	/* know message size yet? */
+      for (i = 0, j = SIZE (&bs), nlseen = 0; j--; ) switch (SNX (&bs)) {
+      case '\015':		/* unlikely carriage return */
+	if (!j || (CHR (&bs) != '\012')) {
+	  i++;			/* ugh, raw CR */
+	  nlseen = NIL;
+	  break;
+	}
+	SNX (&bs);		/* eat the line feed, drop in */
+	--j;
+      case '\012':		/* line feed? */
+	i += 2;			/* count a CRLF */
+				/* header size known yet? */
+	if (!elt->private.msg.header.text.size && nlseen) {
+				/* note position in file */
+	  elt->private.special.text.size = GETPOS (&bs);
+				/* and CRLF-adjusted size */
+	  elt->private.msg.header.text.size = i;
+	}
+	nlseen = T;		/* note newline seen */
+	break;
+      default:			/* ordinary chararacter */
+	i++;
+	nlseen = NIL;
+	break;
+      }
+      SETPOS (&bs,0);		/* restore old position */
+      elt->rfc822_size = i;	/* note that we have size now */
+				/* header is entire message if no delimiter */
+      if (!elt->private.msg.header.text.size)
+	elt->private.msg.header.text.size = elt->rfc822_size;
+				/* text is remainder of message */
+      elt->private.msg.text.text.size =
+	elt->rfc822_size - elt->private.msg.header.text.size;
+    }
+				/* need to load cache with message data? */
+    if (((flags & MLM_HEADER) && !elt->private.msg.header.text.data) ||
+	((flags & MLM_TEXT) && !elt->private.msg.text.text.data)) {
+				/* purge cache if too big */
+      if (LOCAL->cachedtexts > max (stream->nmsgs * 4096,2097152)) {
+				/* just can't keep that much */
+	mail_gc (stream,GC_TEXTS);
+	LOCAL->cachedtexts = 0;
+      }
+
+      if ((flags & MLM_HEADER) && !elt->private.msg.header.text.data) {
+	t = elt->private.msg.header.text.data =
+	  (unsigned char *) fs_get (elt->private.msg.header.text.size + 1);
+	LOCAL->cachedtexts += elt->private.msg.header.text.size;
+				/* read in message header */
+	for (i = 0; i < elt->private.msg.header.text.size; i++)
+	  switch (c = SNX (&bs)) {
+	  case '\015':		/* unlikely carriage return */
+	    *t++ = c;
+	    if ((CHR (&bs) == '\012')) {
+	      *t++ = SNX (&bs);
+	      i++;
+	    }
+	    break;
+	  case '\012':		/* line feed? */
+	    *t++ = '\015';
+	    i++;
+	  default:
+	    *t++ = c;
+	    break;
+	  }
+	*t = '\0';		/* tie off string */
+	if ((t - elt->private.msg.header.text.data) !=
+	    elt->private.msg.header.text.size) fatal ("mh hdr size mismatch");
+      }
+      if ((flags & MLM_TEXT) && !elt->private.msg.text.text.data) {
+	t = elt->private.msg.text.text.data =
+	  (unsigned char *) fs_get (elt->private.msg.text.text.size + 1);
+	SETPOS (&bs,elt->private.special.text.size);
+	LOCAL->cachedtexts += elt->private.msg.text.text.size;
+				/* read in message text */
+	for (i = 0; i < elt->private.msg.text.text.size; i++)
+	  switch (c = SNX (&bs)) {
+	  case '\015':		/* unlikely carriage return */
+	    *t++ = c;
+	    if ((CHR (&bs) == '\012')) {
+	      *t++ = SNX (&bs);
+	      i++;
+	    }
+	    break;
+	  case '\012':		/* line feed? */
+	    *t++ = '\015';
+	    i++;
+	  default:
+	    *t++ = c;
+	    break;
+	  }
+	*t = '\0';		/* tie off string */
+	if ((t - elt->private.msg.text.text.data) !=
+	    elt->private.msg.text.text.size) fatal ("mh txt size mismatch");
+      }
+    }
+    close (fd);			/* flush message file */
+  }
+}
+
+/* MH mail fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+char *mh_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
+		 long flags)
+{
+  MESSAGECACHE *elt;
+  *length = 0;			/* default to empty */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+  elt = mail_elt (stream,msgno);/* get elt */
+  if (!elt->private.msg.header.text.data)
+    mh_load_message (stream,msgno,MLM_HEADER);
+  *length = elt->private.msg.header.text.size;
+  return (char *) elt->private.msg.header.text.data;
+}
+
+
+/* MH mail fetch message text (body only)
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned stringstruct
+ *	    option flags
+ * Returns: T on success, NIL on failure
+ */
+
+long mh_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  MESSAGECACHE *elt;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+  elt = mail_elt (stream,msgno);/* get elt */
+				/* snarf message if don't have it yet */
+  if (!elt->private.msg.text.text.data) {
+    mh_load_message (stream,msgno,MLM_TEXT);
+    if (!elt->private.msg.text.text.data) return NIL;
+  }
+  if (!(flags & FT_PEEK)) {	/* mark as seen */
+    mail_elt (stream,msgno)->seen = T;
+    mm_flags (stream,msgno);
+  }
+  INIT (bs,mail_string,elt->private.msg.text.text.data,
+	elt->private.msg.text.text.size);
+  return T;
+}
+
+/* MH mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ */
+
+long mh_ping (MAILSTREAM *stream)
+{
+  MAILSTREAM *sysibx = NIL;
+  MESSAGECACHE *elt,*selt;
+  struct stat sbuf;
+  char *s,tmp[MAILTMPLEN];
+  int fd;
+  unsigned long i,j,r;
+  unsigned long old = stream->uid_last;
+  long nmsgs = stream->nmsgs;
+  long recent = stream->recent;
+  int silent = stream->silent;
+  if (stat (LOCAL->dir,&sbuf)) {/* directory exists? */
+    if (stream->inbox &&	/* no, create if INBOX */
+	dummy_create_path (stream,strcat (mh_file (tmp,MHINBOX),"/"),
+			   get_dir_protection ("INBOX"))) return T;
+    sprintf (tmp,"Can't open mailbox %.80s: no such mailbox",stream->mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+  stream->silent = T;		/* don't pass up mm_exists() events yet */
+  if (sbuf.st_ctime != LOCAL->scantime) {
+    struct direct **names = NIL;
+    long nfiles = scandir (LOCAL->dir,&names,mh_select,mh_numsort);
+    if (nfiles < 0) nfiles = 0;	/* in case error */
+				/* note scanned now */
+    LOCAL->scantime = sbuf.st_ctime;
+				/* scan directory */
+    for (i = 0; i < nfiles; ++i) {
+				/* if newly seen, add to list */
+      if ((j = atoi (names[i]->d_name)) > old) {
+	mail_exists (stream,++nmsgs);
+	stream->uid_last = (elt = mail_elt (stream,nmsgs))->private.uid = j;
+	elt->valid = T;		/* note valid flags */
+	if (old) {		/* other than the first pass? */
+	  elt->recent = T;	/* yup, mark as recent */
+	  recent++;		/* bump recent count */
+	}
+	else {			/* see if already read */
+	  sprintf (tmp,"%s/%s",LOCAL->dir,names[i]->d_name);
+	  if (!stat (tmp,&sbuf) && (sbuf.st_atime > sbuf.st_mtime))
+	    elt->seen = T;
+	}
+      }
+      fs_give ((void **) &names[i]);
+    }
+				/* free directory */
+    if (s = (void *) names) fs_give ((void **) &s);
+  }
+
+				/* if INBOX, snarf from system INBOX  */
+  if (stream->inbox && strcmp (sysinbox (),stream->mailbox)) {
+    old = stream->uid_last;
+    mm_critical (stream);	/* go critical */
+				/* see if anything in system inbox */
+    if (!stat (sysinbox (),&sbuf) && sbuf.st_size &&
+	(sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) &&
+	!sysibx->rdonly && (r = sysibx->nmsgs)) {
+      for (i = 1; i <= r; ++i) {/* for each message in sysinbox mailbox */
+				/* build file name we will use */
+	sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,++old);
+				/* snarf message from Berkeley mailbox */
+	selt = mail_elt (sysibx,i);
+	if (((fd = open (LOCAL->buf,O_WRONLY|O_CREAT|O_EXCL,
+			 (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL)))
+	     >= 0) &&
+	    (s = mail_fetchheader_full (sysibx,i,NIL,&j,FT_INTERNAL)) &&
+	    (write (fd,s,j) == j) &&
+	    (s = mail_fetchtext_full (sysibx,i,&j,FT_INTERNAL|FT_PEEK)) &&
+	    (write (fd,s,j) == j) && !fsync (fd) && !close (fd)) {
+				/* swell the cache */
+	  mail_exists (stream,++nmsgs);
+	  stream->uid_last =	/* create new elt, note its file number */
+	    (elt = mail_elt (stream,nmsgs))->private.uid = old;
+	  recent++;		/* bump recent count */
+				/* set up initial flags and date */
+	  elt->valid = elt->recent = T;
+	  elt->seen = selt->seen;
+	  elt->deleted = selt->deleted;
+	  elt->flagged = selt->flagged;
+	  elt->answered = selt->answered;
+	  elt->draft = selt->draft;
+	  elt->day = selt->day;elt->month = selt->month;elt->year = selt->year;
+	  elt->hours = selt->hours;elt->minutes = selt->minutes;
+	  elt->seconds = selt->seconds;
+	  elt->zhours = selt->zhours; elt->zminutes = selt->zminutes;
+	  elt->zoccident = selt->zoccident;
+	  mh_setdate (LOCAL->buf,elt);
+	  sprintf (tmp,"%lu",i);/* delete it from the sysinbox */
+	  mail_flag (sysibx,tmp,"\\Deleted",ST_SET);
+	}
+
+	else {			/* failed to snarf */
+	  if (fd) {		/* did it ever get opened? */
+	    close (fd);		/* close descriptor */
+	    unlink (LOCAL->buf);/* flush this file */
+	  }
+	  sprintf (tmp,"Message copy to MH mailbox failed: %.80s",
+		   s,strerror (errno));
+	  mm_log (tmp,ERROR);
+	  r = 0;		/* stop the snarf in its tracks */
+	}
+      }
+				/* update scan time */
+      if (!stat (LOCAL->dir,&sbuf)) LOCAL->scantime = sbuf.st_ctime;      
+      mail_expunge (sysibx);	/* now expunge all those messages */
+    }
+    if (sysibx) mail_close (sysibx);
+    mm_nocritical (stream);	/* release critical */
+  }
+  stream->silent = silent;	/* can pass up events now */
+  mail_exists (stream,nmsgs);	/* notify upper level of mailbox size */
+  mail_recent (stream,recent);
+  return T;			/* return that we are alive */
+}
+
+/* MH mail check mailbox
+ * Accepts: MAIL stream
+ */
+
+void mh_check (MAILSTREAM *stream)
+{
+  /* Perhaps in the future this will preserve flags */
+  if (mh_ping (stream)) mm_log ("Check completed",(long) NIL);
+}
+
+
+/* MH mail expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long mh_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  long ret;
+  MESSAGECACHE *elt;
+  unsigned long i = 1;
+  unsigned long n = 0;
+  unsigned long recent = stream->recent;
+  if (ret = sequence ? ((options & EX_UID) ?
+			mail_uid_sequence (stream,sequence) :
+			mail_sequence (stream,sequence)) : LONGT) {
+    mm_critical (stream);	/* go critical */
+    while (i <= stream->nmsgs) {/* for each message */
+      elt = mail_elt (stream,i);/* if deleted, need to trash it */
+      if (elt->deleted && (sequence ? elt->sequence : T)) {
+	sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid);
+	if (unlink (LOCAL->buf)) {/* try to delete the message */
+	  sprintf (LOCAL->buf,"Expunge of message %lu failed, aborted: %s",i,
+		   strerror (errno));
+	  mm_log (LOCAL->buf,(long) NIL);
+	  break;
+	}
+				/* note uncached */
+	LOCAL->cachedtexts -= ((elt->private.msg.header.text.data ?
+				elt->private.msg.header.text.size : 0) +
+			       (elt->private.msg.text.text.data ?
+				elt->private.msg.text.text.size : 0));
+	mail_gc_msg (&elt->private.msg,GC_ENV | GC_TEXTS);
+				/* if recent, note one less recent message */
+	if (elt->recent) --recent;
+				/* notify upper levels */
+	mail_expunged (stream,i);
+	n++;			/* count up one more expunged message */
+      }
+      else i++;			/* otherwise try next message */
+    }
+    if (n) {			/* output the news if any expunged */
+      sprintf (LOCAL->buf,"Expunged %lu messages",n);
+      mm_log (LOCAL->buf,(long) NIL);
+    }
+    else mm_log ("No messages deleted, so no update needed",(long) NIL);
+    mm_nocritical (stream);	/* release critical */
+				/* notify upper level of new mailbox size */
+    mail_exists (stream,stream->nmsgs);
+    mail_recent (stream,recent);
+  }
+  return ret;
+}
+
+/* MH mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if copy successful, else NIL
+ */
+
+long mh_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  FDDATA d;
+  STRING st;
+  MESSAGECACHE *elt;
+  struct stat sbuf;
+  int fd;
+  unsigned long i;
+  char flags[MAILTMPLEN],date[MAILTMPLEN];
+  appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL);
+  long ret = NIL;
+				/* copy the messages */
+  if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+      mail_sequence (stream,sequence))
+    for (i = 1; i <= stream->nmsgs; i++) 
+      if ((elt = mail_elt (stream,i))->sequence) {
+	sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid);
+	if ((fd = open (LOCAL->buf,O_RDONLY,NIL)) < 0) return NIL;
+	fstat (fd,&sbuf);	/* get size of message */
+	if (!elt->day) {	/* set internaldate to file date if needed */
+	  struct tm *tm = gmtime (&sbuf.st_mtime);
+	  elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1;
+	  elt->year = tm->tm_year + 1900 - BASEYEAR;
+	  elt->hours = tm->tm_hour; elt->minutes = tm->tm_min;
+	  elt->seconds = tm->tm_sec;
+	  elt->zhours = 0; elt->zminutes = 0;
+	}
+	d.fd = fd;		/* set up file descriptor */
+	d.pos = 0;		/* start of file */
+	d.chunk = LOCAL->buf;
+	d.chunksize = CHUNKSIZE;
+				/* kludge; mh_append would just strip CRs */
+	INIT (&st,fd_string,&d,sbuf.st_size);
+				/* init flag string */
+	flags[0] = flags[1] = '\0';
+	if (elt->seen) strcat (flags," \\Seen");
+	if (elt->deleted) strcat (flags," \\Deleted");
+	if (elt->flagged) strcat (flags," \\Flagged");
+	if (elt->answered) strcat (flags," \\Answered");
+	if (elt->draft) strcat (flags," \\Draft");
+	flags[0] = '(';		/* open list */
+	strcat (flags,")");	/* close list */
+	mail_date (date,elt);	/* generate internal date */
+	if (au) mail_parameters (NIL,SET_APPENDUID,NIL);
+	if ((ret = mail_append_full (NIL,mailbox,flags,date,&st)) &&
+	    (options & CP_MOVE)) elt->deleted = T;
+	if (au) mail_parameters (NIL,SET_APPENDUID,(void *) au);
+	close (fd);
+      }
+  if (ret && mail_parameters (NIL,GET_COPYUID,NIL))
+    mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN);
+  return ret;			/* return success */
+}
+
+/* MH mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long mh_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct direct **names = NIL;
+  int fd;
+  char c,*flags,*date,*s,tmp[MAILTMPLEN];
+  STRING *message;
+  MESSAGECACHE elt;
+  FILE *df;
+  long i,size,last,nfiles;
+  long ret = LONGT;
+				/* default stream to prototype */
+  if (!stream) stream = &mhproto;
+				/* make sure valid mailbox */
+  if (!mh_isvalid (mailbox,tmp,NIL)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    if (!((!compare_cstring (mailbox,MHINBOX) ||
+	   !compare_cstring (mailbox,"INBOX")) &&
+	  (mh_file (tmp,MHINBOX) &&
+	   dummy_create_path (stream,strcat (tmp,"/"),
+			      get_dir_protection (mailbox))))) {
+      mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+      return NIL;
+    }
+				/* falls through */
+  case 0:			/* merely empty file? */
+    break;
+  case EINVAL:
+    sprintf (tmp,"Invalid MH-format mailbox name: %.80s",mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;
+  default:
+    sprintf (tmp,"Not a MH-format mailbox: %.80s",mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* get first message */
+  if (!(*af) (stream,data,&flags,&date,&message)) return NIL;
+  if ((nfiles = scandir (tmp,&names,mh_select,mh_numsort)) > 0) {
+				/* largest number */
+    last = atoi (names[nfiles-1]->d_name);    
+    for (i = 0; i < nfiles; ++i) /* free directory */
+      fs_give ((void **) &names[i]);
+  }
+  else last = 0;		/* no messages here yet */
+  if (s = (void *) names) fs_give ((void **) &s);
+
+  mm_critical (stream);		/* go critical */
+  do {
+    if (!SIZE (message)) {	/* guard against zero-length */
+      mm_log ("Append of zero-length message",ERROR);
+      ret = NIL;
+      break;
+    }
+    if (date) {			/* want to preserve date? */
+				/* yes, parse date into an elt */
+      if (!mail_parse_date (&elt,date)) {
+	sprintf (tmp,"Bad date in append: %.80s",date);
+	mm_log (tmp,ERROR);
+	ret = NIL;
+	break;
+      }
+    }
+    mh_file (tmp,mailbox);	/* build file name we will use */
+    sprintf (tmp + strlen (tmp),"/%ld",++last);
+    if (((fd = open (tmp,O_WRONLY|O_CREAT|O_EXCL,
+		     (long)mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0)||
+	!(df = fdopen (fd,"ab"))) {
+      sprintf (tmp,"Can't open append message: %s",strerror (errno));
+      mm_log (tmp,ERROR);
+      ret = NIL;
+      break;
+    }
+				/* copy the data w/o CR's */
+    for (size = 0,i = SIZE (message); i && ret; --i)
+      if (((c = SNX (message)) != '\015') && (putc (c,df) == EOF)) ret = NIL;
+				/* close the file */
+    if (!ret || fclose (df)) {
+      unlink (tmp);		/* delete message */
+      sprintf (tmp,"Message append failed: %s",strerror (errno));
+      mm_log (tmp,ERROR);
+      ret = NIL;
+    }
+    if (ret) {			/* set the date for this message */
+      if (date) mh_setdate (tmp,&elt);
+				/* get next message */
+      if (!(*af) (stream,data,&flags,&date,&message)) ret = NIL;
+    }
+  } while (ret && message);
+  mm_nocritical (stream);	/* release critical */
+  if (ret && mail_parameters (NIL,GET_APPENDUID,NIL))
+    mm_log ("Can not return meaningful APPENDUID with this mailbox format",
+	    WARN);
+  return ret;
+}
+
+/* Internal routines */
+
+
+/* MH file name selection test
+ * Accepts: candidate directory entry
+ * Returns: T to use file name, NIL to skip it
+ */
+
+int mh_select (struct direct *name)
+{
+  char c;
+  char *s = name->d_name;
+  while (c = *s++) if (!isdigit (c)) return NIL;
+  return T;
+}
+
+
+/* MH file name comparision
+ * Accepts: first candidate directory entry
+ *	    second candidate directory entry
+ * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2
+ */
+
+int mh_numsort (const void *d1,const void *d2)
+{
+  return atoi ((*(struct direct **) d1)->d_name) -
+    atoi ((*(struct direct **) d2)->d_name);
+}
+
+
+/* MH mail build file name
+ * Accepts: destination string
+ *          source
+ * Returns: destination
+ */
+
+char *mh_file (char *dst,char *name)
+{
+  char *s;
+  char *path = mh_path (dst);
+  if (!path) fatal ("No mh path in mh_file()!");
+				/* INBOX becomes "inbox" in the MH path */
+  if (!compare_cstring (name,MHINBOX) || !compare_cstring (name,"INBOX"))
+    sprintf (dst,"%.900s/%.80s",path,MHINBOXDIR);
+				/* #mh names skip past prefix */
+  else if (*name == '#') sprintf (dst,"%.100s/%.900s",path,name + 4);
+  else mailboxfile (dst,name);	/* all other names */
+				/* tie off unnecessary trailing / */
+  if ((s = strrchr (dst,'/')) && !s[1] && (s[-1] == '/')) *s = '\0';
+  return dst;
+}
+
+/* MH canonicalize name
+ * Accepts: buffer to write name
+ *	    reference
+ *	    pattern
+ * Returns: T if success, NIL if failure
+ */
+
+long mh_canonicalize (char *pattern,char *ref,char *pat)
+{
+  unsigned long i;
+  char *s,tmp[MAILTMPLEN];
+  if (ref && *ref) {		/* have a reference */
+    strcpy (pattern,ref);	/* copy reference to pattern */
+				/* # overrides mailbox field in reference */
+    if (*pat == '#') strcpy (pattern,pat);
+				/* pattern starts, reference ends, with / */
+    else if ((*pat == '/') && (pattern[strlen (pattern) - 1] == '/'))
+      strcat (pattern,pat + 1);	/* append, omitting one of the period */
+    else strcat (pattern,pat);	/* anything else is just appended */
+  }
+  else strcpy (pattern,pat);	/* just have basic name */
+  if (mh_isvalid (pattern,tmp,T)) {
+				/* count wildcards */
+    for (i = 0, s = pattern; *s; *s++) if ((*s == '*') || (*s == '%')) ++i;
+				/* success if not too many */
+    if (i <= MAXWILDCARDS) return LONGT;
+    mm_log ("Excessive wildcards in LIST/LSUB",ERROR);
+  }
+  return NIL;
+}
+
+/* Set date for message
+ * Accepts: file name
+ *	    elt containing date
+ */
+
+void mh_setdate (char *file,MESSAGECACHE *elt)
+{
+  time_t tp[2];
+  tp[0] = time (0);		/* atime is now */
+  tp[1] = mail_longdate (elt);	/* modification time */
+  utime (file,tp);		/* set the times */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/mix.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,2834 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	MIX mail routines
+ *
+ * Author(s):	Mark Crispin
+ *		UW Technology
+ *		University of Washington
+ *		Seattle, WA  98195
+ *		Internet: MRC@Washington.EDU
+ *
+ * Date:	1 March 2006
+ * Last Edited:	7 May 2008
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "mail.h"
+#include "osdep.h"
+#include <pwd.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "misc.h"
+#include "dummy.h"
+#include "fdstring.h"
+
+/* MIX definitions */
+
+#define MEGABYTE (1024*1024)
+
+#define MIXDATAROLL MEGABYTE	/* size at which we roll to a new file */
+
+
+/* MIX files */
+
+#define MIXNAME ".mix"		/* prefix for all MIX file names */
+#define MIXMETA "meta"		/* suffix for metadata */
+#define MIXINDEX "index"	/* suffix for index */
+#define MIXSTATUS "status"	/* suffix for status */
+#define MIXSORTCACHE "sortcache"/* suffix for sortcache */
+#define METAMAX (MEGABYTE-1)	/* maximum metadata file size (sanity check) */
+
+
+/* MIX file formats */
+
+				/* sequence format (all but msg files) */
+#define SEQFMT "S%08lx\015\012"
+				/* metadata file format */
+#define MTAFMT "V%08lx\015\012L%08lx\015\012N%08lx\015\012"
+				/* index file record format */
+#define IXRFMT ":%08lx:%04d%02d%02d%02d%02d%02d%c%02d%02d:%08lx:%08lx:%08lx:%08lx:%08lx:\015\012"
+				/* status file record format */
+#define STRFMT ":%08lx:%08lx:%04x:%08lx:\015\012"
+				/* message file header format */
+#define MSRFMT "%s%08lx:%04d%02d%02d%02d%02d%02d%c%02d%02d:%08lx:\015\012"
+#define MSGTOK ":msg:"
+#define MSGTSZ (sizeof(MSGTOK)-1)
+				/* sortcache file record format */
+#define SCRFMT ":%08lx:%08lx:%08lx:%08lx:%08lx:%c%08lx:%08lx:%08lx:\015\012"
+
+/* MIX I/O stream local data */
+	
+typedef struct mix_local {
+  unsigned long curmsg;		/* current message file number */
+  unsigned long newmsg;		/* current new message file number */
+  time_t lastsnarf;		/* last snarf time */
+  int msgfd;			/* file description of current msg file */
+  int mfd;			/* file descriptor of open metadata */
+  unsigned long metaseq;	/* metadata sequence */
+  char *index;			/* mailbox index name */
+  unsigned long indexseq;	/* index sequence */
+  char *status;			/* mailbox status name */
+  unsigned long statusseq;	/* status sequence */
+  char *sortcache;		/* mailbox sortcache name */
+  unsigned long sortcacheseq;	/* sortcache sequence */
+  unsigned char *buf;		/* temporary buffer */
+  unsigned long buflen;		/* current size of temporary buffer */
+  unsigned int expok : 1;	/* non-zero if expunge reports OK */
+  unsigned int internal : 1;	/* internally opened, do not validate */
+} MIXLOCAL;
+
+
+#define MIXBURP struct mix_burp
+
+MIXBURP {
+  unsigned long fileno;		/* message file number */
+  char *name;			/* message file name */
+  SEARCHSET *tail;		/* tail of ranges */
+  SEARCHSET set;		/* set of retained ranges */
+  MIXBURP *next;		/* next file to burp */
+};
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((MIXLOCAL *) stream->local)
+
+/* Function prototypes */
+
+DRIVER *mix_valid (char *name);
+long mix_isvalid (char *name,char *meta);
+void *mix_parameters (long function,void *value);
+long mix_dirfmttest (char *name);
+void mix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+long mix_scan_contents (char *name,char *contents,unsigned long csiz,
+			unsigned long fsiz);
+void mix_list (MAILSTREAM *stream,char *ref,char *pat);
+void mix_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long mix_subscribe (MAILSTREAM *stream,char *mailbox);
+long mix_unsubscribe (MAILSTREAM *stream,char *mailbox);
+long mix_create (MAILSTREAM *stream,char *mailbox);
+long mix_delete (MAILSTREAM *stream,char *mailbox);
+long mix_rename (MAILSTREAM *stream,char *old,char *newname);
+int mix_rselect (struct direct *name);
+MAILSTREAM *mix_open (MAILSTREAM *stream);
+void mix_close (MAILSTREAM *stream,long options);
+void mix_abort (MAILSTREAM *stream);
+char *mix_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
+		  long flags);
+long mix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+void mix_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
+unsigned long *mix_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
+			 SORTPGM *pgm,long flags);
+THREADNODE *mix_thread (MAILSTREAM *stream,char *type,char *charset,
+			SEARCHPGM *spg,long flags);
+long mix_ping (MAILSTREAM *stream);
+void mix_check (MAILSTREAM *stream);
+long mix_expunge (MAILSTREAM *stream,char *sequence,long options);
+int mix_select (struct direct *name);
+int mix_msgfsort (const void *d1,const void *d2);
+long mix_addset (SEARCHSET **set,unsigned long start,unsigned long size);
+long mix_burp (MAILSTREAM *stream,MIXBURP *burp,unsigned long *reclaimed);
+long mix_burp_check (SEARCHSET *set,size_t size,char *file);
+long mix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,
+	       long options);
+long mix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+long mix_append_msg (MAILSTREAM *stream,FILE *f,char *flags,MESSAGECACHE *delt,
+		     STRING *msg,SEARCHSET *set,unsigned long seq);
+
+FILE *mix_parse (MAILSTREAM *stream,FILE **idxf,long iflags,long sflags);
+char *mix_meta_slurp (MAILSTREAM *stream,unsigned long *seq);
+long mix_meta_update (MAILSTREAM *stream);
+long mix_index_update (MAILSTREAM *stream,FILE *idxf,long flag);
+long mix_status_update (MAILSTREAM *stream,FILE *statf,long flag);
+FILE *mix_data_open (MAILSTREAM *stream,int *fd,long *size,
+		     unsigned long newsize);
+FILE *mix_sortcache_open (MAILSTREAM *stream);
+long mix_sortcache_update (MAILSTREAM *stream,FILE **sortcache);
+char *mix_read_record (FILE *f,char *buf,unsigned long buflen,char *type);
+unsigned long mix_read_sequence (FILE *f);
+char *mix_dir (char *dst,char *name);
+char *mix_file (char *dst,char *dir,char *name);
+char *mix_file_data (char *dst,char *dir,unsigned long data);
+unsigned long mix_modseq (unsigned long oldseq);
+
+/* MIX mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER mixdriver = {
+  "mix",			/* driver name */
+				/* driver flags */
+  DR_MAIL|DR_LOCAL|DR_NOFAST|DR_CRLF|DR_LOCKING|DR_DIRFMT|DR_MODSEQ,
+  (DRIVER *) NIL,		/* next driver */
+  mix_valid,			/* mailbox is valid for us */
+  mix_parameters,		/* manipulate parameters */
+  mix_scan,			/* scan mailboxes */
+  mix_list,			/* find mailboxes */
+  mix_lsub,			/* find subscribed mailboxes */
+  mix_subscribe,		/* subscribe to mailbox */
+  mix_unsubscribe,		/* unsubscribe from mailbox */
+  mix_create,			/* create mailbox */
+  mix_delete,			/* delete mailbox */
+  mix_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  mix_open,			/* open mailbox */
+  mix_close,			/* close mailbox */
+  NIL,				/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  mix_header,			/* fetch message header only */
+  mix_text,			/* fetch message body only */
+  NIL,				/* fetch partial message test */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  mix_flag,			/* modify flags */
+  NIL,				/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  mix_sort,			/* sort messages */
+  mix_thread,			/* thread messages */
+  mix_ping,			/* ping mailbox to see if still alive */
+  mix_check,			/* check for new messages */
+  mix_expunge,			/* expunge deleted messages */
+  mix_copy,			/* copy messages to another mailbox */
+  mix_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM mixproto = {&mixdriver};
+
+/* MIX mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *mix_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+  return mix_isvalid (name,tmp) ? &mixdriver : NIL;
+}
+
+
+/* MIX mail test for valid mailbox
+ * Accepts: mailbox name
+ *	    buffer to return meta name
+ * Returns: T if valid, NIL otherwise, metadata name written in both cases
+ */
+
+long mix_isvalid (char *name,char *meta)
+{
+  char dir[MAILTMPLEN];
+  struct stat sbuf;
+				/* validate name as directory */
+  if (!(errno = ((strlen (name) > NETMAXMBX) ? ENAMETOOLONG : NIL)) &&
+      *mix_dir (dir,name) && mix_file (meta,dir,MIXMETA) &&
+      !stat (dir,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) {
+				/* name is directory; is it mix? */
+    if (!stat (meta,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG))
+      return LONGT;
+    else errno = NIL;		/* directory but not mix */
+  }
+  return NIL;
+}
+
+/* MIX manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *mix_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case GET_INBOXPATH:
+    if (value) ret = mailboxfile ((char *) value,"~/INBOX");
+    break;
+  case GET_DIRFMTTEST:
+    ret = (void *) mix_dirfmttest;
+    break;
+  case GET_SCANCONTENTS:
+    ret = (void *) mix_scan_contents;
+    break;
+  case SET_ONETIMEEXPUNGEATPING:
+    if (value) ((MIXLOCAL *) ((MAILSTREAM *) value)->local)->expok = T;
+  case GET_ONETIMEEXPUNGEATPING:
+    if (value) ret = (void *)
+      (((MIXLOCAL *) ((MAILSTREAM *) value)->local)->expok ? VOIDT : NIL);
+    break;
+  }
+  return ret;
+}
+
+
+/* MIX test for directory format internal node
+ * Accepts: candidate node name
+ * Returns: T if internal name, NIL otherwise
+ */
+
+long mix_dirfmttest (char *name)
+{
+				/* belongs to MIX if starts with .mix */
+  return strncmp (name,MIXNAME,sizeof (MIXNAME) - 1) ? NIL : LONGT;
+}
+
+/* MIX mail scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void mix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* MIX scan mailbox for contents
+ * Accepts: mailbox name
+ *	    desired contents
+ *	    contents size
+ *	    file size (ignored)
+ * Returns: NIL if contents not found, T if found
+ */
+
+long mix_scan_contents (char *name,char *contents,unsigned long csiz,
+			unsigned long fsiz)
+{
+  long i,nfiles;
+  void *a;
+  char *s;
+  long ret = NIL;
+  size_t namelen = strlen (name);
+  struct stat sbuf;
+  struct direct **names = NIL;
+  if ((nfiles = scandir (name,&names,mix_select,mix_msgfsort)) > 0)
+    for (i = 0; i < nfiles; ++i) {
+      if (!ret) {
+	sprintf (s = (char *) fs_get (namelen + strlen (names[i]->d_name) + 2),
+		 "%s/%s",name,names[i]->d_name);
+	if (!stat (s,&sbuf) && (csiz <= sbuf.st_size))
+	  ret = dummy_scan_contents (s,contents,csiz,sbuf.st_size);
+	fs_give ((void **) &s);
+      }
+      fs_give ((void **) &names[i]);
+    }
+				/* free directory list */
+  if (a = (void *) names) fs_give ((void **) &a);
+  return ret;
+}
+
+/* MIX list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mix_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_list (NIL,ref,pat);
+}
+
+
+/* MIX list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mix_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_lsub (NIL,ref,pat);
+}
+
+/* MIX mail subscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to add to subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long mix_subscribe (MAILSTREAM *stream,char *mailbox)
+{
+  return sm_subscribe (mailbox);
+}
+
+
+/* MIX mail unsubscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to delete from subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long mix_unsubscribe (MAILSTREAM *stream,char *mailbox)
+{
+  return sm_unsubscribe (mailbox);
+}
+
+/* MIX mail create mailbox
+ * Accepts: mail stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long mix_create (MAILSTREAM *stream,char *mailbox)
+{
+  DRIVER *test;
+  FILE *f;
+  int c,i;
+  char *t,tmp[MAILTMPLEN],file[MAILTMPLEN];
+  char *s = strrchr (mailbox,'/');
+  unsigned long now = time (NIL);
+  long ret = NIL;
+				/* always create \NoSelect if trailing /  */
+  if (s && !s[1]) return dummy_create (stream,mailbox);
+				/* validate name */
+  if (mix_dirfmttest (s ? s + 1 : mailbox))
+    sprintf(tmp,"Can't create mailbox %.80s: invalid MIX-format name",mailbox);
+				/* must not already exist */
+  else if ((test = mail_valid (NIL,mailbox,NIL)) &&
+	   strcmp (test->name,"dummy"))
+    sprintf (tmp,"Can't create mailbox %.80s: mailbox already exists",mailbox);
+				/* create directory and metadata */
+  else if (!dummy_create_path (stream,
+			       mix_file (file,mix_dir (tmp,mailbox),MIXMETA),
+			       get_dir_protection (mailbox)))
+    sprintf (tmp,"Can't create mailbox %.80s: %.80s",mailbox,strerror (errno));
+  else if (!(f = fopen (file,"w")))
+    sprintf (tmp,"Can't re-open metadata %.80s: %.80s",mailbox,
+	     strerror (errno));
+  else {			/* success, write initial metadata */
+    fprintf (f,SEQFMT,now);
+    fprintf (f,MTAFMT,now,0,now);
+    for (i = 0, c = 'K'; (i < NUSERFLAGS) &&
+	   (t = (stream && stream->user_flags[i]) ? stream->user_flags[i] :
+	    default_user_flag (i)) && *t; ++i) {
+      putc (c,f);		/* write another keyword */
+      fputs (t,f);
+      c = ' ';			/* delimiter is now space */
+    }
+    fclose (f);
+    set_mbx_protections (mailbox,file);
+				/* point to suffix */
+    s = file + strlen (file) - (sizeof (MIXMETA) - 1);
+    strcpy (s,MIXINDEX);	/* create index */
+    if (!dummy_create_path (stream,file,get_dir_protection (mailbox)))
+      sprintf (tmp,"Can't create mix mailbox index: %.80s",strerror (errno));
+    else {
+      set_mbx_protections (mailbox,file);
+      strcpy (s,MIXSTATUS);	/* create status */
+      if (!dummy_create_path (stream,file,get_dir_protection (mailbox)))
+	sprintf (tmp,"Can't create mix mailbox status: %.80s",
+		 strerror (errno));
+      else {
+	set_mbx_protections (mailbox,file);
+	sprintf (s,"%08lx",now);/* message file */
+	if (!dummy_create_path (stream,file,get_dir_protection (mailbox)))
+	  sprintf (tmp,"Can't create mix mailbox data: %.80s",
+		   strerror (errno));
+	else {
+	  set_mbx_protections (mailbox,file);
+	  ret = LONGT;	/* declare success at this point */
+	}
+      }
+    }
+  }
+  if (!ret) MM_LOG (tmp,ERROR);	/* some error */
+  return ret;
+}
+
+/* MIX mail delete mailbox
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long mix_delete (MAILSTREAM *stream,char *mailbox)
+{
+  DIR *dirp;
+  struct direct *d;
+  int fd = -1;
+  char *s,tmp[MAILTMPLEN];
+  if (!mix_isvalid (mailbox,tmp))
+    sprintf (tmp,"Can't delete mailbox %.80s: no such mailbox",mailbox);
+  else if (((fd = open (tmp,O_RDWR,NIL)) < 0) || flock (fd,LOCK_EX|LOCK_NB))
+    sprintf (tmp,"Can't lock mailbox for delete: %.80s",mailbox);
+				/* delete metadata */
+  else if (unlink (tmp)) sprintf (tmp,"Can't delete mailbox %.80s index: %80s",
+				  mailbox,strerror (errno));
+  else {
+    close (fd);			/* close descriptor on deleted metadata */
+				/* get directory name */
+    *(s = strrchr (tmp,'/')) = '\0';
+    if (dirp = opendir (tmp)) {	/* open directory */
+      *s++ = '/';		/* restore delimiter */
+				/* massacre messages */
+      while (d = readdir (dirp)) if (mix_dirfmttest (d->d_name)) {
+	strcpy (s,d->d_name);	/* make path */
+	unlink (tmp);		/* sayonara */
+      }
+      closedir (dirp);		/* flush directory */
+      *(s = strrchr (tmp,'/')) = '\0';
+      if (rmdir (tmp)) {	/* try to remove the directory */
+	sprintf (tmp,"Can't delete name %.80s: %.80s",
+		 mailbox,strerror (errno));
+	MM_LOG (tmp,WARN);
+      }
+    }
+    return T;			/* always success */
+  }
+  if (fd >= 0) close (fd);	/* close any descriptor on metadata */
+  MM_LOG (tmp,ERROR);		/* something failed */
+  return NIL;
+}
+
+/* MIX mail rename mailbox
+ * Accepts: MIX mail stream
+ *	    old mailbox name
+ *	    new mailbox name
+ * Returns: T on success, NIL on failure
+ */
+
+long mix_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  char c,*s,tmp[MAILTMPLEN],tmp1[MAILTMPLEN];
+  struct stat sbuf;
+  int fd = -1;
+  if (!mix_isvalid (old,tmp))
+    sprintf (tmp,"Can't rename mailbox %.80s: no such mailbox",old);
+  else if (((fd = open (tmp,O_RDWR,NIL)) < 0) || flock (fd,LOCK_EX|LOCK_NB))
+    sprintf (tmp,"Can't lock mailbox for rename: %.80s",old);
+  else if (mix_dirfmttest ((s = strrchr (newname,'/')) ? s + 1 : newname))
+    sprintf (tmp,"Can't rename to mailbox %.80s: invalid MIX-format name",
+	     newname);
+				/* new mailbox name must not be valid */
+  else if (mix_isvalid (newname,tmp))
+    sprintf (tmp,"Can't rename to mailbox %.80s: destination already exists",
+	     newname);
+  else {
+    mix_dir (tmp,old);		/* build old directory name */
+    mix_dir (tmp1,newname);	/* and new directory name */
+				/* easy if not INBOX */
+    if (compare_cstring (old,"INBOX")) {
+				/* found superior to destination name? */
+      if (s = strrchr (tmp1,'/')) {
+	c = *++s;		/* remember first character of inferior */
+	*s = '\0';		/* tie off to get just superior */
+				/* name doesn't exist, create it */
+	if ((stat (tmp1,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+	    !dummy_create_path (stream,tmp1,get_dir_protection (newname)))
+	  return NIL;
+	*s = c;			/* restore full name */
+      }
+      if (!rename (tmp,tmp1)) {
+	close (fd);		/* close descriptor on metadata */
+	return LONGT;
+      }
+    }
+
+				/* RFC 3501 requires this */
+    else if (dummy_create_path (stream,strcat (tmp1,"/"),
+				get_dir_protection (newname))) {
+      void *a;
+      int i,n,lasterror;
+      char *src,*dst;
+      struct direct **names = NIL;
+      size_t srcl = strlen (tmp);
+      size_t dstl = strlen (tmp1);
+				/* rename each mix file to new directory */
+      for (i = lasterror = 0,n = scandir (tmp,&names,mix_rselect,alphasort);
+	   i < n; ++i) {
+	size_t len = strlen (names[i]->d_name);
+	sprintf (src = (char *) fs_get (srcl + len + 2),"%s/%s",
+		 tmp,names[i]->d_name);
+	sprintf (dst = (char *) fs_get (dstl + len + 1),"%s%s",
+		 tmp1,names[i]->d_name);
+	if (rename (src,dst)) lasterror = errno;
+	fs_give ((void **) &src);
+	fs_give ((void **) &dst);
+	fs_give ((void **) &names[i]);
+      }
+				/* free directory list */
+      if (a = (void *) names) fs_give ((void **) &a);
+      if (lasterror) errno = lasterror;
+      else {
+	close (fd);		/* close descriptor on metadata */
+	return mix_create (NIL,"INBOX");
+      }
+    }
+    sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %.80s",
+	     old,newname,strerror (errno));
+  }
+  if (fd >= 0) close (fd);	/* close any descriptor on metadata */
+  MM_LOG (tmp,ERROR);		/* something failed */
+  return NIL;
+}
+
+
+/* MIX test for mix name
+ * Accepts: candidate directory name
+ * Returns: T if mix file name, NIL otherwise
+ */
+
+int mix_rselect (struct direct *name)
+{
+  return mix_dirfmttest (name->d_name);
+}
+
+/* MIX mail open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *mix_open (MAILSTREAM *stream)
+{
+  short silent;
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return user_flags (&mixproto);
+  if (stream->local) fatal ("mix recycle stream");
+  stream->local = memset (fs_get (sizeof (MIXLOCAL)),0,sizeof (MIXLOCAL));
+				/* note if an INBOX or not */
+  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
+				/* make temporary buffer */
+  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
+  LOCAL->buflen = CHUNKSIZE - 1;
+				/* set stream->mailbox to be directory name */
+  mix_dir (LOCAL->buf,stream->mailbox);
+  fs_give ((void **) &stream->mailbox);
+  stream->mailbox = cpystr (LOCAL->buf);
+  LOCAL->msgfd = -1;		/* currently no file open */
+  if (!(((!stream->rdonly &&	/* open metadata file */
+	  ((LOCAL->mfd = open (mix_file (LOCAL->buf,stream->mailbox,MIXMETA),
+			       O_RDWR,NIL)) >= 0)) ||
+	 ((stream->rdonly = T) &&
+	  ((LOCAL->mfd = open (mix_file (LOCAL->buf,stream->mailbox,MIXMETA),
+			       O_RDONLY,NIL)) >= 0))) &&
+	!flock (LOCAL->mfd,LOCK_SH))) {
+    MM_LOG ("Error opening mix metadata file",ERROR);
+    mix_abort (stream);
+    stream = NIL;		/* open fails */
+  }
+  else {			/* metadata open, complete open */
+    LOCAL->index = cpystr (mix_file (LOCAL->buf,stream->mailbox,MIXINDEX));
+    LOCAL->status = cpystr (mix_file (LOCAL->buf,stream->mailbox,MIXSTATUS));
+    LOCAL->sortcache = cpystr (mix_file (LOCAL->buf,stream->mailbox,
+					 MIXSORTCACHE));
+    stream->sequence++;		/* bump sequence number */
+				/* parse mailbox */
+    stream->nmsgs = stream->recent = 0;
+    if (silent = stream->silent) LOCAL->internal = T;
+    stream->silent = T;
+    if (mix_ping (stream)) {	/* do initial ping */
+				/* try burping in case we are exclusive */
+      if (!stream->rdonly) mix_expunge (stream,"",NIL);
+      if (!(stream->nmsgs || stream->silent))
+	MM_LOG ("Mailbox is empty",(long) NIL);
+      stream->silent = silent;	/* now notify upper level */
+      mail_exists (stream,stream->nmsgs);
+      stream->perm_seen = stream->perm_deleted = stream->perm_flagged =
+	stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T;
+      stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
+      stream->kwd_create =	/* can we create new user flags? */
+	(stream->user_flags[NUSERFLAGS-1] || stream->rdonly) ? NIL : T;
+    }
+    else {			/* got murdelyzed in ping */
+      mix_abort (stream);
+      stream = NIL;
+    }
+  }
+  return stream;		/* return stream to caller */
+}
+
+/* MIX mail close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void mix_close (MAILSTREAM *stream,long options)
+{
+  if (LOCAL) {			/* only if a file is open */
+    int silent = stream->silent;
+    stream->silent = T;		/* note this stream is dying */
+				/* burp-only or expunge */
+    mix_expunge (stream,(options & CL_EXPUNGE) ? NIL : "",NIL);
+    mix_abort (stream);
+    stream->silent = silent;	/* reset silent state */
+  }
+}
+
+
+/* MIX mail abort stream
+ * Accepts: MAIL stream
+ */
+
+void mix_abort (MAILSTREAM *stream)
+{
+  if (LOCAL) {			/* only if a file is open */
+				/* close current message file if open */
+    if (LOCAL->msgfd >= 0) close (LOCAL->msgfd);
+				/* close current metadata file if open */
+    if (LOCAL->mfd >= 0) close (LOCAL->mfd);
+    if (LOCAL->index) fs_give ((void **) &LOCAL->index);
+    if (LOCAL->status) fs_give ((void **) &LOCAL->status);
+    if (LOCAL->sortcache) fs_give ((void **) &LOCAL->sortcache);
+				/* free local scratch buffer */
+    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+/* MIX mail fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+char *mix_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
+		  long flags)
+{
+  unsigned long i,j,k;
+  int fd;
+  char *s,tmp[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  if (length) *length = 0;	/* default return */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+  elt = mail_elt (stream,msgno);/* get elt */
+				/* is message in current message file? */
+  if ((LOCAL->msgfd < 0) || (elt->private.spare.data != LOCAL->curmsg)) {
+    if (LOCAL->msgfd >= 0) close (LOCAL->msgfd);
+    if ((LOCAL->msgfd = open (mix_file_data (LOCAL->buf,stream->mailbox,
+					     elt->private.spare.data),
+					     O_RDONLY,NIL)) < 0) return "";
+				/* got file */
+    LOCAL->curmsg = elt->private.spare.data;
+  }    
+  lseek (LOCAL->msgfd,elt->private.special.offset,L_SET);
+				/* size of special data and header */
+  j = elt->private.msg.header.offset + elt->private.msg.header.text.size;
+  if (j > LOCAL->buflen) {	/* is buffer big enough? */
+				/* no, make one that is */
+    fs_give ((void **) &LOCAL->buf);
+    LOCAL->buf = (char *) fs_get ((LOCAL->buflen = j) + 1);
+  }
+  /* Maybe someday validate internaldate too */
+				/* slurp special data + header, validate */
+  if ((read (LOCAL->msgfd,LOCAL->buf,j) == j) &&
+      !strncmp (LOCAL->buf,MSGTOK,MSGTSZ) &&
+      (elt->private.uid == strtoul ((char *) LOCAL->buf + MSGTSZ,&s,16)) &&
+      (*s++ == ':') && (s = strchr (s,':')) &&
+      (k = strtoul (s+1,&s,16)) && (*s++ == ':') &&
+      (s < (char *) (LOCAL->buf + elt->private.msg.header.offset))) {
+				/* won, set offset and size of message */
+    i = elt->private.msg.header.offset;
+    *length = elt->private.msg.header.text.size;
+    if (k != elt->rfc822_size) {
+      sprintf (tmp,"Inconsistency in mix message size, uid=%lx (%lu != %lu)",
+	       elt->private.uid,elt->rfc822_size,k);
+      MM_LOG (tmp,WARN);
+    }
+  }
+  else {			/* document the problem */
+    LOCAL->buf[100] = '\0';	/* tie off buffer at no more than 100 octets */
+				/* or at newline, whichever is first */
+    if (s = strpbrk (LOCAL->buf,"\015\012")) *s = '\0';
+    sprintf (tmp,"Error reading mix message header, uid=%lx, s=%.0lx, h=%s",
+	     elt->private.uid,elt->rfc822_size,LOCAL->buf);
+    MM_LOG (tmp,ERROR);
+    *length = i = j = 0;	/* default to empty */
+  }
+  LOCAL->buf[j] = '\0';		/* tie off buffer at the end */
+  return (char *) LOCAL->buf + i;
+}
+
+/* MIX mail fetch message text (body only)
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned stringstruct
+ *	    option flags
+ * Returns: T on success, NIL on failure
+ */
+
+long mix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  unsigned long i;
+  FDDATA d;
+  MESSAGECACHE *elt;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+  elt = mail_elt (stream,msgno);
+				/* is message in current message file? */
+  if ((LOCAL->msgfd < 0) || (elt->private.spare.data != LOCAL->curmsg)) {
+    if (LOCAL->msgfd >= 0) close (LOCAL->msgfd);
+    if ((LOCAL->msgfd = open (mix_file_data (LOCAL->buf,stream->mailbox,
+					     elt->private.spare.data),
+					     O_RDONLY,NIL)) < 0) return NIL;
+				/* got file */
+    LOCAL->curmsg = elt->private.spare.data;
+  }    
+				/* doing non-peek fetch? */
+  if (!(flags & FT_PEEK) && !elt->seen) {
+    FILE *idxf;			/* yes, process metadata/index/status */
+    FILE *statf = mix_parse (stream,&idxf,NIL,LONGT);
+    elt->seen = T;		/* mark as seen */
+    MM_FLAGS (stream,elt->msgno);
+				/* update status file if possible */
+    if (statf && !stream->rdonly) {
+      elt->private.mod = LOCAL->statusseq = mix_modseq (LOCAL->statusseq);
+      mix_status_update (stream,statf,NIL);
+    }
+    if (idxf) fclose (idxf);	/* release index and status file */
+    if (statf) fclose (statf);
+  } 
+  d.fd = LOCAL->msgfd;		/* set up file descriptor */
+				/* offset of message text */
+  d.pos = elt->private.special.offset + elt->private.msg.header.offset +
+    elt->private.msg.header.text.size;
+  d.chunk = LOCAL->buf;		/* initial buffer chunk */
+  d.chunksize = CHUNKSIZE;	/* chunk size */
+  INIT (bs,fd_string,&d,elt->rfc822_size - elt->private.msg.header.text.size);
+  return T;
+}
+
+/* MIX mail modify flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    flag(s)
+ *	    option flags
+ */
+
+void mix_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
+{
+  MESSAGECACHE *elt;
+  unsigned long i,uf,ffkey;
+  long f;
+  short nf;
+  FILE *idxf;
+  FILE *statf = mix_parse (stream,&idxf,NIL,LONGT);
+  unsigned long seq = mix_modseq (LOCAL->statusseq);
+				/* find first free key */
+  for (ffkey = 0; (ffkey < NUSERFLAGS) && stream->user_flags[ffkey]; ++ffkey);
+				/* parse sequence and flags */
+  if (((flags & ST_UID) ? mail_uid_sequence (stream,sequence) :
+       mail_sequence (stream,sequence)) &&
+      ((f = mail_parse_flags (stream,flag,&uf)) || uf)) {
+				/* alter flags */
+    for (i = 1,nf = (flags & ST_SET) ? T : NIL; i <= stream->nmsgs; i++)
+      if ((elt = mail_elt (stream,i))->sequence) {
+	struct {		/* old flags */
+	  unsigned int seen : 1;
+	  unsigned int deleted : 1;
+	  unsigned int flagged : 1;
+	  unsigned int answered : 1;
+	  unsigned int draft : 1;
+	  unsigned long user_flags;
+	} old;
+	old.seen = elt->seen; old.deleted = elt->deleted;
+	old.flagged = elt->flagged; old.answered = elt->answered;
+	old.draft = elt->draft; old.user_flags = elt->user_flags;
+	if (f&fSEEN) elt->seen = nf;
+	if (f&fDELETED) elt->deleted = nf;
+	if (f&fFLAGGED) elt->flagged = nf;
+	if (f&fANSWERED) elt->answered = nf;
+	if (f&fDRAFT) elt->draft = nf;
+				/* user flags */
+	if (flags & ST_SET) elt->user_flags |= uf;
+	else elt->user_flags &= ~uf;
+	if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
+	    (old.flagged != elt->flagged) ||
+	    (old.answered != elt->answered) || (old.draft != elt->draft) ||
+	    (old.user_flags != elt->user_flags)) {
+	  if (!stream->rdonly) elt->private.mod = LOCAL->statusseq = seq;
+	  MM_FLAGS (stream,elt->msgno);
+	}
+      }
+				/* update status file after change */
+    if (statf && (seq == LOCAL->statusseq))
+      mix_status_update (stream,statf,NIL);
+				/* update metadata if created a keyword */
+    if ((ffkey < NUSERFLAGS) && stream->user_flags[ffkey] &&
+	!mix_meta_update (stream))
+      MM_LOG ("Error updating mix metadata after keyword creation",ERROR);
+  }
+  if (statf) fclose (statf);	/* release status file if still open */
+  if (idxf) fclose (idxf);	/* release index file */
+}
+
+/* MIX mail sort messages
+ * Accepts: mail stream
+ *	    character set
+ *	    search program
+ *	    sort program
+ *	    option flags
+ * Returns: vector of sorted message sequences or NIL if error
+ */
+
+unsigned long *mix_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
+			 SORTPGM *pgm,long flags)
+{
+  unsigned long *ret;
+  FILE *sortcache = mix_sortcache_open (stream);
+  ret = mail_sort_msgs (stream,charset,spg,pgm,flags);
+  mix_sortcache_update (stream,&sortcache);
+  return ret;
+}
+
+
+/* MIX mail thread messages
+ * Accepts: mail stream
+ *	    thread type
+ *	    character set
+ *	    search program
+ *	    option flags
+ * Returns: thread node tree or NIL if error
+ */
+
+THREADNODE *mix_thread (MAILSTREAM *stream,char *type,char *charset,
+			SEARCHPGM *spg,long flags)
+{
+  THREADNODE *ret;
+  FILE *sortcache = mix_sortcache_open (stream);
+  ret = mail_thread_msgs (stream,type,charset,spg,flags,mail_sort_msgs);
+  mix_sortcache_update (stream,&sortcache);
+  return ret;
+}
+
+/* MIX mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ */
+
+static int snarfing = 0;	/* lock against recursive snarfing */
+
+long mix_ping (MAILSTREAM *stream)
+{
+  FILE *idxf,*statf;
+  struct stat sbuf;
+  STRING msg;
+  MESSAGECACHE *elt;
+  int mfd,ifd,sfd;
+  unsigned long i,msglen;
+  char *message,date[MAILTMPLEN],flags[MAILTMPLEN];
+  MAILSTREAM *sysibx = NIL;
+  long ret = NIL;
+  long snarfok = LONGT;
+				/* time to snarf? */
+  if (stream->inbox && !stream->rdonly && !snarfing &&
+      (time (0) >= (LOCAL->lastsnarf +
+		    (time_t) mail_parameters (NIL,GET_SNARFINTERVAL,NIL)))) {
+    appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL);
+    copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL);
+    MM_CRITICAL (stream);	/* go critical */
+    snarfing = T;		/* don't recursively snarf */
+				/* disable APPENDUID/COPYUID callbacks */
+    mail_parameters (NIL,SET_APPENDUID,NIL);
+    mail_parameters (NIL,SET_COPYUID,NIL);
+				/* sizes match and anything in sysinbox? */
+    if (!stat (sysinbox (),&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG) &&
+	sbuf.st_size &&	(sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) &&
+	!sysibx->rdonly && sysibx->nmsgs) {
+				/* for each message in sysibx mailbox */
+      for (i = 1; snarfok && (i <= sysibx->nmsgs); ++i)
+	if (!(elt = mail_elt (sysibx,i))->deleted &&
+	    (message = mail_fetch_message (sysibx,i,&msglen,FT_PEEK)) &&
+	    msglen) {
+	  mail_date (date,elt);	/* make internal date string */
+				/* make flag string */
+	  flags[0] = flags[1] = '\0';
+	  if (elt->seen) strcat (flags," \\Seen");
+	  if (elt->flagged) strcat (flags," \\Flagged");
+	  if (elt->answered) strcat (flags," \\Answered");
+	  if (elt->draft) strcat (flags," \\Draft");
+	  flags[0] = '(';
+	  strcat (flags,")");
+	  INIT (&msg,mail_string,message,msglen);
+	  if (snarfok = mail_append_full (stream,"INBOX",flags,date,&msg)) {
+	    char sequence[15];
+	    sprintf (sequence,"%lu",i);
+	    mail_flag (sysibx,sequence,"\\Deleted",ST_SET);
+	  }
+	}
+
+				/* now expunge all those messages */
+      if (snarfok) mail_expunge (sysibx);
+      else {
+	sprintf (LOCAL->buf,"Can't copy new mail at message: %lu",i - 1);
+	MM_LOG (LOCAL->buf,WARN);
+      }
+    }
+    if (sysibx) mail_close (sysibx);
+				/* reenable APPENDUID/COPYUID */
+    mail_parameters (NIL,SET_APPENDUID,(void *) au);
+    mail_parameters (NIL,SET_COPYUID,(void *) cu);
+    snarfing = NIL;		/* no longer snarfing */
+    MM_NOCRITICAL (stream);	/* release critical */
+    LOCAL->lastsnarf = time (0);/* note time of last snarf */
+  }
+				/* expunging OK if global flag set */
+  if (mail_parameters (NIL,GET_EXPUNGEATPING,NIL)) LOCAL->expok = T;
+				/* process metadata/index/status */
+  if (statf = mix_parse (stream,&idxf,LONGT,
+			 (LOCAL->internal ? NIL : LONGT))) {
+    fclose (statf);		/* just close the status file */
+    ret = LONGT;		/* declare success */
+  }
+  if (idxf) fclose (idxf);	/* release index file */
+  LOCAL->expok = NIL;		/* expunge no longer OK */
+  if (!ret) mix_abort (stream);	/* murdelyze stream if ping fails */
+  return ret;
+}
+
+
+/* MIX mail checkpoint mailbox (burp only)
+ * Accepts: MAIL stream
+ */
+
+void mix_check (MAILSTREAM *stream)
+{
+  if (stream->rdonly)		/* won't do on readonly files! */
+    MM_LOG ("Checkpoint ignored on readonly mailbox",NIL);
+				/* do burp-only expunge action */
+  if (mix_expunge (stream,"",NIL)) MM_LOG ("Check completed",(long) NIL);
+}
+
+/* MIX mail expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL, empty string for burp only
+ *	    expunge options
+ * Returns: T on success, NIL if failure
+ */
+
+long mix_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  FILE *idxf = NIL;
+  FILE *statf = NIL;
+  MESSAGECACHE *elt;
+  int ifd,sfd;
+  long ret;
+  unsigned long i;
+  unsigned long nexp = 0;
+  unsigned long reclaimed = 0;
+  int burponly = (sequence && !*sequence);
+  LOCAL->expok = T;		/* expunge during ping is OK */
+  if (!(ret = burponly || !sequence ||
+	((options & EX_UID) ?
+	 mail_uid_sequence (stream,sequence) :
+	 mail_sequence (stream,sequence))) || stream->rdonly);
+				/* read index and open status exclusive */
+  else if (statf = mix_parse (stream,&idxf,LONGT,
+			      LOCAL->internal ? NIL : LONGT)) {
+				/* expunge unless just burping */
+    if (!burponly) for (i = 1; i <= stream->nmsgs;) {
+      elt = mail_elt (stream,i);/* need to expunge this message? */
+      if (sequence ? elt->sequence : elt->deleted) {
+	++nexp;			/* yes, make it so */
+	mail_expunged (stream,i);
+      }
+      else ++i;		       /* otherwise advance to next message */
+    }
+
+				/* burp if can get exclusive access */
+    if (!flock (LOCAL->mfd,LOCK_EX|LOCK_NB)) {
+      void *a;
+      struct direct **names = NIL;
+      long nfiles = scandir (stream->mailbox,&names,mix_select,mix_msgfsort);
+      if (nfiles > 0) {		/* if have message files */
+	MIXBURP *burp,*cur;
+				/* initialize burp list */
+	for (i = 0, burp = cur = NIL; i < nfiles; ++i) {
+	  MIXBURP *nxt = (MIXBURP *) memset (fs_get (sizeof (MIXBURP)),0,
+					     sizeof (MIXBURP));
+				/* another file found */
+	  if (cur) cur = cur->next = nxt;
+	  else cur = burp = nxt;
+	  cur->name = names[i]->d_name;
+	  cur->fileno = strtoul (cur->name + sizeof (MIXNAME) - 1,NIL,16);
+	  cur->tail = &cur->set;
+	  fs_give ((void **) &names[i]);
+	}
+				/* now load ranges */
+	for (i = 1, cur = burp; ret && (i <= stream->nmsgs); i++) {
+				/* is this message in current set? */
+	  elt = mail_elt (stream,i);
+	  if (cur && (elt->private.spare.data != cur->fileno)) {
+				/* restart if necessary */
+	    if (elt->private.spare.data < cur->fileno) cur = burp;
+				/* hunt for appropriate mailbox */
+	    while (cur && (elt->private.spare.data > cur->fileno))
+	      cur = cur->next;
+				/* ought to have found it now... */
+	    if (cur && (elt->private.spare.data != cur->fileno)) cur = NIL;
+	  }
+				/* if found, add to set */
+	  if (cur) ret = mix_addset (&cur->tail,elt->private.special.offset,
+				     elt->private.msg.header.offset +
+				     elt->rfc822_size);
+	  else {		/* uh-oh */
+	    sprintf (LOCAL->buf,"Can't locate mix message file %.08lx",
+		     elt->private.spare.data);
+	    MM_LOG (LOCAL->buf,ERROR);
+	    ret = NIL;
+	  }
+	}
+	if (ret) 		/* if no errors, burp all files */
+	  for (cur = burp; ret && cur; cur = cur->next) {
+				/* if non-empty, burp it */
+	    if (cur->set.last) ret = mix_burp (stream,cur,&reclaimed);
+				/* empty, delete it unless new msg file */
+	    else if (mix_file_data (LOCAL->buf,stream->mailbox,cur->fileno) &&
+		     ((cur->fileno == LOCAL->newmsg) ?
+		      truncate (LOCAL->buf,0) : unlink (LOCAL->buf))) {
+	      sprintf (LOCAL->buf,
+		       "Can't delete empty message file %.80s: %.80s",
+		       cur->name,strerror (errno));
+	      MM_LOG (LOCAL->buf,WARN);
+	    }
+	  }
+      }
+      else MM_LOG ("No mix message files found during expunge",WARN);
+				/* free directory list */
+      if (a = (void *) names) fs_give ((void **) &a);
+    }
+
+				/* either way, re-acquire shared lock */
+    if (flock (LOCAL->mfd,LOCK_SH|LOCK_NB))
+      fatal ("Unable to re-acquire metadata shared lock!");
+    /* Do this step even if ret is NIL (meaning some burp problem)! */
+    if (nexp || reclaimed) {	/* rewrite index and status if changed */
+      LOCAL->indexseq = mix_modseq (LOCAL->indexseq);
+      if (mix_index_update (stream,idxf,NIL)) {
+	LOCAL->statusseq = mix_modseq (LOCAL->statusseq);
+				/* set failure if update fails */
+	ret = mix_status_update (stream,statf,NIL);
+      }
+    }
+  }
+  if (statf) fclose (statf);	/* close status if still open */
+  if (idxf) fclose (idxf);	/* close index if still open */
+  LOCAL->expok = NIL;		/* cancel expok */
+  if (ret) {			/* only if success */
+    char *s = NIL;
+    if (nexp) sprintf (s = LOCAL->buf,"Expunged %lu messages",nexp);
+    else if (reclaimed)
+      sprintf (s=LOCAL->buf,"Reclaimed %lu bytes of expunged space",reclaimed);
+    else if (!burponly)
+      s = stream->rdonly ? "Expunge ignored on readonly mailbox" :
+	   "No messages deleted, so no update needed";
+    if (s) MM_LOG (s,(long) NIL);
+  }
+  return ret;
+}
+
+/* MIX test for message file name
+ * Accepts: candidate directory name
+ * Returns: T if message file name, NIL otherwise
+ *
+ * ".mix" with no suffix was used by experimental versions
+ */
+
+int mix_select (struct direct *name)
+{
+  char c,*s;
+				/* make sure name has prefix */
+  if (mix_dirfmttest (name->d_name)) {
+    for (c = *(s = name->d_name + sizeof (MIXNAME) - 1); c && isxdigit (c);
+	 c = *s++);
+    if (!c) return T;		/* all-hex or no suffix */
+  }
+  return NIL;			/* not suffix or non-hex */
+}
+
+
+/* MIX msg file name comparision
+ * Accepts: first candidate directory entry
+ *	    second candidate directory entry
+ * Returns: -1 if d1 < d2, 0 if d1 == d2, 1 d1 > d2
+ */
+
+int mix_msgfsort (const void *d1,const void *d2)
+{
+  char *n1 = (*(struct direct **) d1)->d_name + sizeof (MIXNAME) - 1;
+  char *n2 = (*(struct direct **) d2)->d_name + sizeof (MIXNAME) - 1;
+  return compare_ulong (*n1 ? strtoul (n1,NIL,16) : 0,
+			*n2 ? strtoul (n2,NIL,16) : 0);
+}
+
+
+/* MIX add a range to a set
+ * Accepts: pointer to set to add
+ *	    start of set
+ *	    size of set
+ * Returns: T if success, set updated, NIL otherwise
+ */
+
+long mix_addset (SEARCHSET **set,unsigned long start,unsigned long size)
+{
+  SEARCHSET *s = *set;
+  if (start < s->last) {	/* sanity check */
+    char tmp[MAILTMPLEN];
+    sprintf (tmp,"Backwards-running mix index %lu < %lu",start,s->last);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+				/* range initially empty? */
+  if (!s->last) s->first = start;
+  else if (start > s->last)	/* no, start new range if can't append */
+    (*set = s = s->next = mail_newsearchset ())->first = start;
+  s->last = start + size;	/* end of current range */
+  return LONGT;
+}
+
+/* MIX burp message file
+ * Accepts: MAIL stream
+ *	    current burp block for this message
+ * Returns: T if successful, NIL if failed
+ */
+
+static char *staterr = "Error in stat of mix message file %.80s: %.80s";
+static char *truncerr = "Error truncating mix message file %.80s: %.80s";
+
+long mix_burp (MAILSTREAM *stream,MIXBURP *burp,unsigned long *reclaimed)
+{
+  MESSAGECACHE *elt;
+  SEARCHSET *set;
+  struct stat sbuf;
+  off_t rpos,wpos;
+  size_t size,wsize,wpending,written;
+  int fd;
+  FILE *f;
+  void *s;
+  unsigned long i;
+  long ret = NIL;
+				/* build file name */
+  mix_file_data (LOCAL->buf,stream->mailbox,burp->fileno);
+				/* need to burp at start or multiple ranges? */
+  if (!burp->set.first && !burp->set.next) {
+				/* easy case, single range at start of file */
+    if (stat (LOCAL->buf,&sbuf)) {
+      sprintf (LOCAL->buf,staterr,burp->name,strerror (errno));
+      MM_LOG (LOCAL->buf,ERROR);
+    }
+				/* is this range sane? */
+    else if (mix_burp_check (&burp->set,sbuf.st_size,LOCAL->buf)) {
+				/* if matches range then no burp needed! */
+      if (burp->set.last == sbuf.st_size) ret = LONGT;
+				/* just need to remove cruft at end */
+      else if (ret = !truncate (LOCAL->buf,burp->set.last))
+	*reclaimed += sbuf.st_size - burp->set.last;
+      else {
+	sprintf (LOCAL->buf,truncerr,burp->name,strerror (errno));
+	MM_LOG (LOCAL->buf,ERROR);
+      }
+    }
+  }
+				/* have to do more work, get the file */
+  else if (((fd = open (LOCAL->buf,O_RDWR,NIL)) < 0) ||
+	   !(f = fdopen (fd,"r+b"))) {
+    sprintf (LOCAL->buf,"Error opening mix message file %.80s: %.80s",
+	     burp->name,strerror (errno));
+    MM_LOG (LOCAL->buf,ERROR);
+    if (fd >= 0) close (fd);	/* in case fdopen() failure */
+  }
+  else if (fstat (fd,&sbuf)) {	/* get file size */
+    sprintf (LOCAL->buf,staterr,burp->name,strerror (errno));
+    MM_LOG (LOCAL->buf,ERROR);
+    fclose (f);
+  }
+
+				/* only if sane */
+  else if (mix_burp_check (&burp->set,sbuf.st_size,LOCAL->buf)) {
+				/* make sure each range starts with token */
+    for (set = &burp->set; set; set = set->next)
+      if (fseek (f,set->first,SEEK_SET) ||
+	  (fread (LOCAL->buf,1,MSGTSZ,f) != MSGTSZ) ||
+	  strncmp (LOCAL->buf,MSGTOK,MSGTSZ)) {
+	sprintf (LOCAL->buf,"Bad message token in mix message file at %lu",
+		 set->first);
+	MM_LOG (LOCAL->buf,ERROR);
+	fclose (f);
+	return NIL;		/* burp fails for this file */
+      }
+				/* burp out each old message */
+    for (set = &burp->set, wpos = 0; set; set = set->next) {
+				/* move down this range */
+      for (rpos = set->first, size = set->last - set->first;
+	   size; size -= wsize) {
+	if (rpos != wpos) {	/* data to skip at start? */
+				/* no, slide this buffer down */
+	  wsize = min (size,LOCAL->buflen);
+				/* failure is not an option here */
+	  while (fseek (f,rpos,SEEK_SET) ||
+		 (fread (LOCAL->buf,1,wsize,f) != wsize)) {
+	    MM_NOTIFY (stream,strerror (errno),WARN);
+	    MM_DISKERROR (stream,errno,T);
+	  }
+				/* nor here */
+	  while (fseek (f,wpos,SEEK_SET)) {
+	    MM_NOTIFY (stream,strerror (errno),WARN);
+	    MM_DISKERROR (stream,errno,T);
+	  }
+				/* and especially not here */
+	  for (s = LOCAL->buf, wpending = wsize; wpending; wpending -= written)
+	    if (!(written = fwrite (LOCAL->buf,1,wpending,f))) {
+	      MM_NOTIFY (stream,strerror (errno),WARN);
+	      MM_DISKERROR (stream,errno,T);
+	    }
+	}
+	else wsize = size;	/* nothing to skip, say we wrote it all */
+	rpos += wsize; wpos += wsize;
+      }
+    }
+
+    while (fflush (f)) {	/* failure also not an option here... */
+      MM_NOTIFY (stream,strerror (errno),WARN);
+      MM_DISKERROR (stream,errno,T);
+    }
+    if (ftruncate (fd,wpos)) {	/* flush cruft at end of file */
+      sprintf (LOCAL->buf,truncerr,burp->name,strerror (errno));
+      MM_LOG (LOCAL->buf,WARN);
+    }
+    else *reclaimed += rpos - wpos;
+    ret = !fclose (f);		/* close file */
+				/* slide down message positions in index */
+    for (i = 1,rpos = 0; i <= stream->nmsgs; ++i)
+      if ((elt = mail_elt (stream,i))->private.spare.data == burp->fileno) {
+	elt->private.special.offset = rpos;
+	rpos += elt->private.msg.header.offset + elt->rfc822_size;
+      }
+				/* debugging */
+    if (rpos != wpos) fatal ("burp size consistency check!");
+  }
+  return ret;
+}
+
+
+/* MIX burp sanity check to make sure not burping off end of file
+ * Accepts: burp set
+ *	    file size
+ *	    file name
+ * Returns: T if sane, NIL if insane
+ */
+
+long mix_burp_check (SEARCHSET *set,size_t size,char *file)
+{
+  do if (set->last > size) {	/* sanity check */
+    char tmp[MAILTMPLEN];
+    sprintf (tmp,"Unexpected short mix message file %.80s %lu < %lu",
+	     file,size,set->last);
+    MM_LOG (tmp,ERROR);
+    return NIL;			/* don't burp this file at all */
+  } while (set = set->next);
+  return LONGT;
+}
+
+/* MIX mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if copy successful, else NIL
+ */
+
+long mix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  FDDATA d;
+  STRING st;
+  char tmp[2*MAILTMPLEN];
+  long ret = mix_isvalid (mailbox,LOCAL->buf);
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+  MAILSTREAM *astream = NIL;
+  FILE *idxf = NIL;
+  FILE *msgf = NIL;
+  FILE *statf = NIL;
+  if (!ret) switch (errno) {	/* make sure valid mailbox */
+  case NIL:			/* no error in stat() */
+    if (pc) return (*pc) (stream,sequence,mailbox,options);
+    sprintf (tmp,"Not a MIX-format mailbox: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    break;
+  default:			/* some stat() error */
+    MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
+    break;
+  }
+				/* get sequence to copy */
+  else if (!(ret = ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+		    mail_sequence (stream,sequence))));
+				/* acquire stream to append */
+  else if (ret = ((astream = mail_open (NIL,mailbox,OP_SILENT)) &&
+		  !astream->rdonly &&
+		  (((MIXLOCAL *) astream->local)->expok = T) &&
+		  (statf = mix_parse (astream,&idxf,LONGT,NIL))) ?
+	   LONGT : NIL) {
+    int fd;
+    unsigned long i;
+    MESSAGECACHE *elt;
+    unsigned long newsize,hdrsize,size;
+    MIXLOCAL *local = (MIXLOCAL *) astream->local;
+    unsigned long seq = mix_modseq (local->metaseq);
+				/* make sure new modseq fits */
+    if (local->indexseq > seq) seq = local->indexseq + 1;
+    if (local->statusseq > seq) seq = local->statusseq + 1;
+				/* calculate size of per-message header */
+    sprintf (local->buf,MSRFMT,MSGTOK,0,0,0,0,0,0,0,'+',0,0,0);
+    hdrsize = strlen (local->buf);
+
+    MM_CRITICAL (stream);	/* go critical */
+    astream->silent = T;	/* no events here */
+				/* calculate size that will be added */
+    for (i = 1, newsize = 0; i <= stream->nmsgs; ++i)
+      if ((elt = mail_elt (stream,i))->sequence)
+	newsize += hdrsize + elt->rfc822_size;
+				/* open data file */
+    if (msgf = mix_data_open (astream,&fd,&size,newsize)) {
+      char *t;
+      unsigned long j,uid,uidv;
+      copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL);
+      SEARCHSET *source = cu ? mail_newsearchset () : NIL;
+      SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
+      for (i = 1,uid = uidv = 0; ret && (i <= stream->nmsgs); ++i) 
+	if (((elt = mail_elt (stream,i))->sequence) && elt->rfc822_size) {
+				/* is message in current message file? */
+	  if ((LOCAL->msgfd < 0) ||
+	      (elt->private.spare.data != LOCAL->curmsg)) {
+	    if (LOCAL->msgfd >= 0) close (LOCAL->msgfd);
+	    if ((LOCAL->msgfd = open (mix_file_data (LOCAL->buf,
+						     stream->mailbox,
+						     elt->private.spare.data),
+				      O_RDONLY,NIL)) >= 0)
+	      LOCAL->curmsg = elt->private.spare.data;
+	  }
+	  if (LOCAL->msgfd < 0) ret = NIL;
+	  else {		/* got file */
+	    d.fd = LOCAL->msgfd;/* set up file descriptor */
+				/* start of message */
+	    d.pos = elt->private.special.offset +
+	      elt->private.msg.header.offset;
+	    d.chunk = LOCAL->buf;
+	    d.chunksize = CHUNKSIZE;
+	    INIT (&st,fd_string,&d,elt->rfc822_size);
+				/* init flag string */
+	    tmp[0] = tmp[1] = '\0';
+	    if (j = elt->user_flags) do
+	      if ((t = stream->user_flags[find_rightmost_bit (&j)]) && *t)
+		strcat (strcat (tmp," "),t);
+	    while (j);
+	    if (elt->seen) strcat (tmp," \\Seen");
+	    if (elt->deleted) strcat (tmp," \\Deleted");
+	    if (elt->flagged) strcat (tmp," \\Flagged");
+	    if (elt->answered) strcat (tmp," \\Answered");
+	    if (elt->draft) strcat (tmp," \\Draft");
+	    tmp[0] = '(';	/* wrap list */
+	    strcat (tmp,")");
+				/* if append OK, add to source set */
+	    if ((ret = mix_append_msg (astream,msgf,tmp,elt,&st,dest,
+				       seq)) &&	source)
+	      mail_append_set (source,mail_uid (stream,i));
+	  }
+	}
+
+				/* finish write if success */
+      if (ret && (ret = !fflush (msgf))) {
+	fclose (msgf);		/* all good, close the msg file now */
+				/* write new metadata, index, and status */
+	local->metaseq = local->indexseq = local->statusseq = seq;
+	if (ret = (mix_meta_update (astream) &&
+		   mix_index_update (astream,idxf,LONGT))) {
+				/* success, delete if doing a move */
+	  if (options & CP_MOVE)
+	    for (i = 1; i <= stream->nmsgs; i++)
+	      if ((elt = mail_elt (stream,i))->sequence) {
+		elt->deleted = T;
+		if (!stream->rdonly) elt->private.mod = LOCAL->statusseq = seq;
+		MM_FLAGS (stream,elt->msgno);
+	      }
+				/* done with status file now */
+	  mix_status_update (astream,statf,LONGT);
+				/* return sets if doing COPYUID */
+	  if (cu) (*cu) (stream,mailbox,astream->uid_validity,source,dest);
+	  source = dest = NIL;	/* don't free these sets now */
+	}
+      }
+      else {			/* error */
+	if (errno) {		/* output error message if system call error */
+	  sprintf (tmp,"Message copy failed: %.80s",strerror (errno));
+	  MM_LOG (tmp,ERROR);
+	}
+	ftruncate (fd,size);	/* revert file */
+	close (fd);		/* make sure that fclose doesn't corrupt us */
+	fclose (msgf);		/* free the stdio resources */
+      }
+				/* flush any sets remaining */
+      mail_free_searchset (&source);
+      mail_free_searchset (&dest);
+    }
+    else {			/* message file open failed */
+      sprintf (tmp,"Error opening copy message file: %.80s",
+	       strerror (errno));
+      MM_LOG (tmp,ERROR);
+      ret = NIL;
+    }
+    MM_NOCRITICAL (stream);
+  }
+  else MM_LOG ("Can't open copy mailbox",ERROR);
+  if (statf) fclose (statf);	/* close status if still open */
+  if (idxf) fclose (idxf);	/* close index if still open */
+				/* finished with append stream */
+  if (astream) mail_close (astream);
+  return ret;			/* return state */
+}
+
+/* MIX mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long mix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  STRING *message;
+  char *flags,*date,tmp[MAILTMPLEN];
+				/* N.B.: can't use LOCAL->buf for tmp */
+  long ret = mix_isvalid (mailbox,tmp);
+				/* default stream to prototype */
+  if (!stream) stream = user_flags (&mixproto);
+  if (!ret) switch (errno) {	/* if not valid mailbox */
+  case ENOENT:			/* no such file? */
+    if (ret = compare_cstring (mailbox,"INBOX") ?
+	NIL : mix_create (NIL,"INBOX"))
+      break;
+    MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+    break;
+  default:
+    sprintf (tmp,"Not a MIX-format mailbox: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    break;
+  }
+
+				/* get first message */
+  if (ret && MM_APPEND (af) (stream,data,&flags,&date,&message)) {
+    MAILSTREAM *astream;
+    FILE *idxf = NIL;
+    FILE *msgf = NIL;
+    FILE *statf = NIL;
+    if (ret = ((astream = mail_open (NIL,mailbox,OP_SILENT)) &&
+	       !astream->rdonly &&
+	       (((MIXLOCAL *) astream->local)->expok = T) &&
+	       (statf = mix_parse (astream,&idxf,LONGT,NIL))) ?
+	LONGT : NIL) {
+      int fd;
+      unsigned long size,hdrsize;
+      MESSAGECACHE elt;
+      MIXLOCAL *local = (MIXLOCAL *) astream->local;
+      unsigned long seq = mix_modseq (local->metaseq);
+				/* make sure new modseq fits */
+      if (local->indexseq > seq) seq = local->indexseq + 1;
+      if (local->statusseq > seq) seq = local->statusseq + 1;
+				/* calculate size of per-message header */
+      sprintf (local->buf,MSRFMT,MSGTOK,0,0,0,0,0,0,0,'+',0,0,0);
+      hdrsize = strlen (local->buf);
+      MM_CRITICAL (astream);	/* go critical */
+      astream->silent = T;	/* no events here */
+				/* open data file */
+      if (msgf = mix_data_open (astream,&fd,&size,hdrsize + SIZE (message))) {
+	appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL);
+	SEARCHSET *dst = au ? mail_newsearchset () : NIL;
+	while (ret && message) {/* while good to go and have messages */
+	  errno = NIL;		/* in case one of these causes failure */
+				/* guard against zero-length */
+	  if (!(ret = SIZE (message)))
+	    MM_LOG ("Append of zero-length message",ERROR);
+	  else if (date && !(ret = mail_parse_date (&elt,date))) {
+	    sprintf (tmp,"Bad date in append: %.80s",date);
+	    MM_LOG (tmp,ERROR);
+	  }
+	  else {
+	    if (!date) {	/* if date not specified, use now */
+	      internal_date (tmp);
+	      mail_parse_date (&elt,tmp);
+	    }
+	    ret = mix_append_msg (astream,msgf,flags,&elt,message,dst,seq) &&
+	      MM_APPEND (af) (stream,data,&flags,&date,&message);
+	  }
+	}
+
+				/* finish write if success */
+	if (ret && (ret = !fflush (msgf))) {
+	  fclose (msgf);	/* all good, close the msg file now */
+				/* write new metadata, index, and status */
+	  local->metaseq = local->indexseq = local->statusseq = seq;
+	  if ((ret = (mix_meta_update (astream) &&
+		      mix_index_update (astream,idxf,LONGT) &&
+		      mix_status_update (astream,statf,LONGT))) && au) {
+	      (*au) (mailbox,astream->uid_validity,dst);
+	      dst = NIL;	/* don't free this set now */
+	  }
+	}
+	else {			/* failure */
+	  if (errno) {		/* output error message if system call error */
+	    sprintf (tmp,"Message append failed: %.80s",strerror (errno));
+	    MM_LOG (tmp,ERROR);
+	  }
+	  ftruncate (fd,size);	/* revert all writes to file*/
+	  close (fd);		/* make sure that fclose doesn't corrupt us */
+	  fclose (msgf);	/* free the stdio resources */
+	}
+				/* flush any set remaining */
+	mail_free_searchset (&dst);
+      }
+      else {			/* message file open failed */
+	sprintf (tmp,"Error opening append message file: %.80s",
+		 strerror (errno));
+	MM_LOG (tmp,ERROR);
+	ret = NIL;
+      }
+      MM_NOCRITICAL (astream);	/* release critical */
+    }
+    else MM_LOG ("Can't open append mailbox",ERROR);
+    if (statf) fclose (statf);	/* close status if still open */
+    if (idxf) fclose (idxf);	/* close index if still open */
+    if (astream) mail_close (astream);
+  }
+  return ret;
+}
+
+/* MIX mail append single message
+ * Accepts: MAIL stream
+ *	    flags for new message if non-NIL
+ *	    elt with source date if non-NIL
+ *	    stringstruct of message text
+ *	    searchset to place UID
+ *	    modseq of message
+ * Returns: T if success, NIL if failure
+ */
+
+long mix_append_msg (MAILSTREAM *stream,FILE *f,char *flags,MESSAGECACHE *delt,
+		     STRING *msg,SEARCHSET *set,unsigned long seq)
+{
+  MESSAGECACHE *elt;
+  int c,cs;
+  unsigned long i,j,k,uf,hoff;
+  long sf;
+  stream->kwd_create = NIL;	/* don't copy unknown keywords */
+  sf = mail_parse_flags (stream,flags,&uf);
+				/* swell the cache */
+  mail_exists (stream,++stream->nmsgs);
+				/* assign new UID from metadata */
+  (elt = mail_elt (stream,stream->nmsgs))->private.uid = ++stream->uid_last;
+  elt->private.mod = seq;	/* set requested modseq in status */
+  elt->rfc822_size = SIZE (msg);/* copy message size and date to index */
+  elt->year = delt->year; elt->month = delt->month; elt->day = delt->day;
+  elt->hours = delt->hours; elt->minutes = delt->minutes;
+  elt->seconds = delt->seconds; elt->zoccident = delt->zoccident;
+  elt->zhours = delt->zhours; elt->zminutes = delt->zminutes;
+  /*
+   * Do NOT set elt->valid here!  mix_status_update() uses it to determine
+   * whether a message should be marked as old.
+   */
+  if (sf&fSEEN) elt->seen = T;	/* copy flags to status */
+  if (sf&fDELETED) elt->deleted = T;
+  if (sf&fFLAGGED) elt->flagged = T;
+  if (sf&fANSWERED) elt->answered = T;
+  if (sf&fDRAFT) elt->draft = T;
+  elt->user_flags |= uf;
+				/* message is in new message file */
+  elt->private.spare.data = LOCAL->newmsg;
+
+				/* offset to message internal header */
+  elt->private.special.offset = ftell (f);
+				/* build header for message */
+  fprintf (f,MSRFMT,MSGTOK,elt->private.uid,
+	   elt->year + BASEYEAR,elt->month,elt->day,
+	   elt->hours,elt->minutes,elt->seconds,
+	   elt->zoccident ? '-' : '+',elt->zhours,elt->zminutes,
+	   elt->rfc822_size);
+				/* offset to header from  internal header */
+  elt->private.msg.header.offset = ftell (f) - elt->private.special.offset;
+  for (cs = 0; SIZE (msg); ) {	/* copy message */
+    if (elt->private.msg.header.text.size) {
+      if (msg->cursize)		/* blat entire chunk if have it */
+	for (j = msg->cursize; j; j -= k)
+	  if (!(k = fwrite (msg->curpos,1,j,f))) return NIL;
+      SETPOS (msg,GETPOS (msg) + msg->cursize);
+    }
+    else {			/* still searching for delimiter */
+      c = 0xff & SNX (msg);	/* get source character */
+      if (putc (c,f) == EOF) return NIL;
+      switch (cs) {		/* decide what to do based on state */
+      case 0:			/* previous char ordinary */
+	if (c == '\015') cs = 1;/* advance if CR */
+	break;
+      case 1:			/* previous CR, advance if LF */
+	cs = (c == '\012') ? 2 : 0;
+	break;
+      case 2:			/* previous CRLF, advance if CR */
+	cs = (c == '\015') ? 3 : 0;
+	break;
+      case 3:			/* previous CRLFCR, done if LF */
+	if (c == '\012') elt->private.msg.header.text.size =
+			   elt->rfc822_size - SIZE (msg);
+	cs = 0;			/* reset mechanism */
+	break;
+      }
+    }
+  }
+				/* if no delimiter, header is entire msg */
+  if (!elt->private.msg.header.text.size)
+    elt->private.msg.header.text.size = elt->rfc822_size;
+				/* add this message to set */
+  mail_append_set (set,elt->private.uid);
+  return LONGT;			/* success */
+}
+
+/* MIX mail read metadata, index, and status
+ * Accepts: MAIL stream
+ *	    returned index file
+ *	    index file flags (non-NIL if want to add/remove messages)
+ *	    status file flags (non-NIL if want to update elt->valid and old)
+ * Returns: open status file, or NIL if failure
+ *
+ * Note that this routine can return an open index file even if it fails!
+ */
+
+static char *shortmsg =
+  "message %lu (UID=%.08lx) truncated by %lu byte(s) (%lu < %lu)";
+
+FILE *mix_parse (MAILSTREAM *stream,FILE **idxf,long iflags,long sflags)
+{
+  int fd;
+  unsigned long i;
+  char *s,*t;
+  struct stat sbuf;
+  FILE *statf = NIL;
+  short metarepairneeded = 0;
+  short indexrepairneeded = 0;
+  short silent = stream->silent;
+  *idxf = NIL;			/* in case error */
+				/* readonly means no updates */
+  if (stream->rdonly) iflags = sflags = NIL;
+				/* open index file */
+  if ((fd = open (LOCAL->index,iflags ? O_RDWR : O_RDONLY,NIL)) < 0)
+    MM_LOG ("Error opening mix index file",ERROR);
+				/* acquire exclusive access and FILE */
+  else if (!flock (fd,iflags ? LOCK_EX : LOCK_SH) &&
+	   !(*idxf = fdopen (fd,iflags ? "r+b" : "rb"))) {
+    MM_LOG ("Error obtaining stream on mix index file",ERROR);
+    flock (fd,LOCK_UN);		/* relinquish lock */
+    close (fd);
+  }
+
+				/* slurp metadata */
+  else if (s = mix_meta_slurp (stream,&i)) {
+    unsigned long j = 0;	/* non-zero if UIDVALIDITY/UIDLAST changed */
+    if (i != LOCAL->metaseq) {	/* metadata changed? */
+      char *t,*k;
+      LOCAL->metaseq = i;	/* note new metadata sequence */
+      while (s && *s) {		/* parse entire metadata file */
+				/* locate end of line */
+	if (s = strstr (t = s,"\015\012")) {
+	  *s = '\0';		/* tie off line */
+	  s += 2;		/* skip past CRLF */
+	  switch (*t++) {	/* parse line */
+	  case 'V':		/* UIDVALIDITY */
+	    if (!isxdigit (*t) || !(i = strtoul (t,&t,16))) {
+	      MM_LOG ("Error in mix metadata file UIDVALIDITY record",ERROR);
+	      return NIL;	/* give up */
+	    }
+	    if (i != stream->uid_validity) j = stream->uid_validity = i;
+	    break;
+	  case 'L':		/* new UIDLAST */
+	    if (!isxdigit (*t)) {
+	      MM_LOG ("Error in mix metadata file UIDLAST record",ERROR);
+	      return NIL;	/* give up */
+	    }
+	    if ((i = strtoul (t,&t,16)) != stream->uid_last)
+	      j = stream->uid_last = i;
+	    break;
+	  case 'N':		/* new message file */
+	    if (!isxdigit (*t)) {
+	      MM_LOG ("Error in mix metadata file new msg record",ERROR);
+	      return NIL;	/* give up */
+	    }
+	    if ((i = strtoul (t,&t,16)) != stream->uid_last)
+	      LOCAL->newmsg = i;
+	    break;
+	  case 'K':		/* new keyword list */
+	    for (i = 0; t && *t && (i < NUSERFLAGS); ++i) {
+	      if (t = strchr (k = t,' ')) *t++ = '\0';
+				/* make sure keyword non-empty */
+	      if (*k && (strlen (k) <= MAXUSERFLAG)) {
+				/* in case value changes (shouldn't happen) */
+		if (stream->user_flags[i] && strcmp (stream->user_flags[i],k)){
+		  char tmp[MAILTMPLEN];
+		  sprintf (tmp,"flag rename old=%.80s new=%.80s",
+			   stream->user_flags[i],k);
+		  MM_LOG (tmp,WARN);
+		  fs_give ((void **) &stream->user_flags[i]);
+		}
+		if (!stream->user_flags[i]) stream->user_flags[i] = cpystr (k);
+	      }
+	      else break;	/* empty keyword */
+	    }
+	    if ((i < NUSERFLAGS) && stream->user_flags[i]) {
+	      MM_LOG ("Error in mix metadata file keyword record",ERROR);
+	      return NIL;	/* give up */
+	    }
+	    else if (i == NUSERFLAGS) stream->kwd_create = NIL;
+	    break;
+	  }
+	}
+	if (t && *t) {		/* junk in line */
+	  MM_LOG ("Error in mix metadata record",ERROR);
+	  return NIL;		/* give up */
+	}
+      }
+    }
+
+				/* get sequence */
+    if (!(i = mix_read_sequence (*idxf)) || (i < LOCAL->indexseq)) {
+      MM_LOG ("Error in mix index file sequence record",ERROR);
+      return NIL;		/* give up */
+    }
+				/* sequence changed from last time? */
+    else if (j || (i > LOCAL->indexseq)) {
+      unsigned long uid,nmsgs,curfile,curfilesize,curpos;
+      char *t,*msg,tmp[MAILTMPLEN];
+				/* start with no messages */
+      curfile = curfilesize = curpos = nmsgs = 0;
+				/* update sequence iff expunging OK */
+      if (LOCAL->expok) LOCAL->indexseq = i;
+				/* get first elt */
+      while ((s = mix_read_record (*idxf,LOCAL->buf,LOCAL->buflen,"index")) &&
+	     *s)
+	switch (*s) {
+	case ':':		/* message record */
+	  if (!(isxdigit (*++s) && (uid = strtoul (s,&t,16)))) msg = "UID";
+	  else if (!((*t++ == ':') && isdigit (*t) && isdigit (t[1]) &&
+		     isdigit (t[2]) && isdigit (t[3]) && isdigit (t[4]) &&
+		     isdigit (t[5]) && isdigit (t[6]) && isdigit (t[7]) &&
+		     isdigit (t[8]) && isdigit (t[9]) && isdigit (t[10]) &&
+		     isdigit (t[11]) && isdigit (t[12]) && isdigit (t[13]) &&
+		     ((t[14] == '+') || (t[14] == '-')) && 
+		     isdigit (t[15]) && isdigit (t[16]) && isdigit (t[17]) &&
+		     isdigit (t[18]))) msg = "internaldate";
+	  else if ((*(s = t+19) != ':') || !isxdigit (*++s)) msg = "size";
+	  else {
+	    unsigned int y = (((*t - '0') * 1000) + ((t[1] - '0') * 100) +
+			      ((t[2] - '0') * 10) + t[3] - '0') - BASEYEAR;
+	    unsigned int m = ((t[4] - '0') * 10) + t[5] - '0';
+	    unsigned int d = ((t[6] - '0') * 10) + t[7] - '0';
+	    unsigned int hh = ((t[8] - '0') * 10) + t[9] - '0';
+	    unsigned int mm = ((t[10] - '0') * 10) + t[11] - '0';
+	    unsigned int ss = ((t[12] - '0') * 10) + t[13] - '0';
+	    unsigned int z = (t[14] == '-') ? 1 : 0;
+	    unsigned int zh = ((t[15] - '0') * 10) + t[16] - '0';
+	    unsigned int zm = ((t[17] - '0') * 10) + t[18] - '0';
+	    unsigned long size = strtoul (s,&s,16);
+	    if ((*s++ == ':') && isxdigit (*s)) {
+	      unsigned long file = strtoul (s,&s,16);
+	      if ((*s++ == ':') && isxdigit (*s)) {
+		unsigned long pos = strtoul (s,&s,16);
+		if ((*s++ == ':') && isxdigit (*s)) {
+		  unsigned long hpos = strtoul (s,&s,16);
+		  if ((*s++ == ':') && isxdigit (*s)) {
+		    unsigned long hsiz = strtoul (s,&s,16);
+		    if (uid > stream->uid_last) {
+		      sprintf (tmp,"mix index invalid UID (%08lx < %08lx)",
+			       uid,stream->uid_last);
+		      if (stream->rdonly) {
+			MM_LOG (tmp,ERROR);
+			return NIL;
+		      }
+		      strcat (tmp,", repaired");
+		      MM_LOG (tmp,WARN);
+		      stream->uid_last = uid;
+		      metarepairneeded = T;
+		    }
+
+				/* ignore expansion values */
+		    if (*s++ == ':') {
+		      MESSAGECACHE *elt;
+		      ++nmsgs;	/* this is another mesage */
+				/* within current known range of messages? */
+		      while (nmsgs <= stream->nmsgs) {
+				/* yes, get corresponding elt */
+			elt = mail_elt (stream,nmsgs);
+				/* existing message with matching data? */
+			if (uid == elt->private.uid) {
+				/* beware of Dracula's resurrection */
+			  if (elt->private.ghost) {
+			    sprintf (tmp,"mix index data unexpunged UID: %lx",
+				     uid);
+			    MM_LOG (tmp,ERROR);
+			    return NIL;
+			  }
+				/* also of static data changing */
+			  if ((size != elt->rfc822_size) ||
+			      (file != elt->private.spare.data) ||
+			      (pos != elt->private.special.offset) ||
+			      (hpos != elt->private.msg.header.offset) ||
+			      (hsiz != elt->private.msg.header.text.size) ||
+			      (y != elt->year) || (m != elt->month) ||
+			      (d != elt->day) || (hh != elt->hours) ||
+			      (mm != elt->minutes) || (ss != elt->seconds) ||
+			      (z != elt->zoccident) || (zh != elt->zhours) ||
+			      (zm != elt->zminutes)) {
+			    sprintf (tmp,"mix index data mismatch: %lx",uid);
+			    MM_LOG (tmp,ERROR);
+			    return NIL;
+			  }
+			  break;
+			}
+				/* existing msg with lower UID is expunged */
+			else if (uid > elt->private.uid) {
+			  if (LOCAL->expok) mail_expunged (stream,nmsgs);
+			  else {/* message expunged, but not yet for us */
+			    ++nmsgs;
+			    elt->private.ghost = T;
+			  }
+			}
+			else {	/* unexpected message record */
+			  sprintf (tmp,"mix index UID mismatch (%lx < %lx)",
+				   uid,elt->private.uid);
+			  MM_LOG (tmp,ERROR);
+			  return NIL;
+			}
+		      }
+
+				/* time to create a new message? */
+		      if (nmsgs > stream->nmsgs) {
+				/* defer announcing until later */
+			stream->silent = T;
+			mail_exists (stream,nmsgs);
+			stream->silent = silent;
+			(elt = mail_elt (stream,nmsgs))->recent = T;
+			elt->private.uid = uid; elt->rfc822_size = size;
+			elt->private.spare.data = file;
+			elt->private.special.offset = pos;
+			elt->private.msg.header.offset = hpos;
+			elt->private.msg.header.text.size = hsiz;
+			elt->year = y; elt->month = m; elt->day = d;
+			elt->hours = hh; elt->minutes = mm;
+			elt->seconds = ss; elt->zoccident = z;
+			elt->zhours = zh; elt->zminutes = zm;
+				/* message in same file? */
+			if (curfile == file) {
+			  if (pos < curpos) {
+			    MESSAGECACHE *plt = mail_elt (stream,elt->msgno-1);
+				/* uh-oh, calculate delta? */
+			    i = curpos - pos;
+			    sprintf (tmp,shortmsg,plt->msgno,plt->private.uid,
+				     i,pos,curpos);
+				/* possible to fix? */
+			    if (!stream->rdonly && LOCAL->expok &&
+				(i < plt->rfc822_size)) {
+			      plt->rfc822_size -= i;
+			      if (plt->rfc822_size <
+				  plt->private.msg.header.text.size)
+				plt->private.msg.header.text.size =
+				  plt->rfc822_size;
+			      strcat (tmp,", repaired");
+			      indexrepairneeded = T;
+			    }
+			    MM_LOG (tmp,WARN);
+			  }
+			}
+			else {	/* new file, restart */
+			  if (stat (mix_file_data (LOCAL->buf,stream->mailbox,
+						   curfile = file),&sbuf)) {
+			    sprintf (tmp,"Missing mix data file: %.500s",
+				     LOCAL->buf);
+			    MM_LOG (tmp,ERROR);
+			    return NIL;
+			  }
+			  curfile = file;
+			  curfilesize = sbuf.st_size;
+			}
+
+				/* position of message in file */
+			curpos = pos + elt->private.msg.header.offset +
+			  elt->rfc822_size;
+				/* short file? */
+			if (curfilesize < curpos) {
+				/* uh-oh, calculate delta? */
+			    i = curpos - curfilesize;
+			    sprintf (tmp,shortmsg,elt->msgno,elt->private.uid,
+				     i,curfilesize,curpos);
+				/* possible to fix? */
+			    if (!stream->rdonly && LOCAL->expok &&
+				(i < elt->rfc822_size)) {
+			      elt->rfc822_size -= i;
+			      if (elt->rfc822_size <
+				  elt->private.msg.header.text.size)
+				elt->private.msg.header.text.size =
+				  elt->rfc822_size;
+			      strcat (tmp,", repaired");
+			      indexrepairneeded = T;
+			    }
+			    MM_LOG (tmp,WARN);
+			}
+		      }
+		      break;
+		    }
+		    else msg = "expansion";
+		  }
+		  else msg = "header size";
+		}
+		else msg = "header position";
+	      }
+	      else msg = "message position";
+	    }
+	    else msg = "file#";
+	  }
+	  sprintf (tmp,"Error in %s in mix index file: %.500s",msg,s);
+	  MM_LOG (tmp,ERROR);
+	  return NIL;
+	default:
+	  sprintf (tmp,"Unknown record in mix index file: %.500s",s);
+	  MM_LOG (tmp,ERROR);
+	  return NIL;
+	}
+      if (!s) return NIL;	/* barfage from mix_read_record() */
+				/* expunge trailing messages not in index */
+      if (LOCAL->expok) while (nmsgs < stream->nmsgs)
+	mail_expunged (stream,stream->nmsgs);
+    }
+
+				/* repair metadata and index if needed */
+    if ((metarepairneeded ? mix_meta_update (stream) : T) &&
+	(indexrepairneeded ? mix_index_update (stream,*idxf,NIL) : T)) {
+      MESSAGECACHE *elt;
+      int fd;
+      unsigned long uid,uf,sf,mod;
+      char *s;
+      int updatep = NIL;
+				/* open status file */
+      if ((fd = open (LOCAL->status,
+		      stream->rdonly ? O_RDONLY : O_RDWR,NIL)) < 0)
+	MM_LOG ("Error opening mix status file",ERROR);
+				/* acquire exclusive access and FILE */
+      else if (!flock (fd,stream->rdonly ? LOCK_SH : LOCK_EX) &&
+	       !(statf = fdopen (fd,stream->rdonly ? "rb" : "r+b"))) {
+	MM_LOG ("Error obtaining stream on mix status file",ERROR);
+	flock (fd,LOCK_UN);	/* relinquish lock */
+	close (fd);
+      }
+				/* get sequence */
+      else if (!(i = mix_read_sequence (statf)) ||
+	       ((i < LOCAL->statusseq) && stream->nmsgs && (i != 1))) {
+	sprintf (LOCAL->buf,
+		 "Error in mix status sequence record, i=%lx, seq=%lx",
+		 i,LOCAL->statusseq);
+	MM_LOG (LOCAL->buf,ERROR);
+      }
+				/* sequence changed from last time? */
+      else if (i != LOCAL->statusseq) {
+				/* update sequence, get first elt */
+	if (i > LOCAL->statusseq) LOCAL->statusseq = i;
+	if (stream->nmsgs) {
+	  elt = mail_elt (stream,i = 1);
+
+				/* read message records */
+	  while ((t = s = mix_read_record (statf,LOCAL->buf,LOCAL->buflen,
+					   "status")) && *s && (*s++ == ':') &&
+		 isxdigit (*s)) {
+	    uid = strtoul (s,&s,16);
+	    if ((*s++ == ':') && isxdigit (*s)) {
+	      uf = strtoul (s,&s,16);
+	      if ((*s++ == ':') && isxdigit (*s)) {
+		sf = strtoul (s,&s,16);
+		if ((*s++ == ':') && isxdigit (*s)) {
+		  mod = strtoul (s,&s,16);
+				/* ignore expansion values */
+		  if (*s++ == ':') {
+				/* need to move ahead to next elt? */
+		    while ((uid > elt->private.uid) && (i < stream->nmsgs))
+		      elt = mail_elt (stream,++i);
+				/* update elt if altered */
+		    if ((uid == elt->private.uid) &&
+			(!elt->valid || (mod != elt->private.mod))) {
+		      elt->user_flags = uf;
+		      elt->private.mod = mod;
+		      elt->seen = (sf & fSEEN) ? T : NIL;
+		      elt->deleted = (sf & fDELETED) ? T : NIL;
+		      elt->flagged = (sf & fFLAGGED) ? T : NIL;
+		      elt->answered = (sf & fANSWERED) ? T : NIL;
+		      elt->draft = (sf & fDRAFT) ? T : NIL;
+				/* announce if altered existing message */
+		      if (elt->valid) MM_FLAGS (stream,elt->msgno);
+				/* first time, is old message? */
+		      else if (sf & fOLD) {
+				/* yes, clear recent and set valid */
+			elt->recent = NIL;
+			elt->valid = T;
+		      }
+				/* recent, allowed to update its status? */
+		      else if (sflags) {
+				/* yes, set valid and check in status */
+			elt->valid = T;
+			elt->private.mod = mix_modseq (elt->private.mod);
+			updatep = T;
+		      }
+		      /* leave valid unset and recent if sflags not set */
+		    }
+		    continue;	/* everything looks good */
+		  }
+		}
+	      }
+	    }
+	    break;		/* error somewhere */
+	  }
+
+	  if (t && *t) {	/* non-null means bogus record */
+	    char msg[MAILTMPLEN];
+	    sprintf (msg,"Error in mix status file message record%s: %.80s",
+		     stream->rdonly ? "" : ", fixing",t);
+	    MM_LOG (msg,WARN);
+				/* update it if not readonly */
+	    if (!stream->rdonly) updatep = T;
+	  }
+	  if (updatep) {		/* need to update? */
+	    LOCAL->statusseq = mix_modseq (LOCAL->statusseq);
+	    mix_status_update (stream,statf,LONGT);
+	  }
+	}
+      }
+    }
+  }
+  if (statf) {			/* still happy? */
+    unsigned long j;
+    stream->silent = silent;	/* now notify upper level */
+    mail_exists (stream,stream->nmsgs);
+    for (i = 1, j = 0; i <= stream->nmsgs; ++i)
+      if (mail_elt (stream,i)->recent) ++j;
+    mail_recent (stream,j);
+  }
+  return statf;
+}
+
+/* MIX metadata file routines */
+
+/* MIX read metadata
+ * Accepts: MAIL stream
+ *	    return pointer for modseq
+ * Returns: pointer to metadata after modseq or NIL if failure
+ */
+
+char *mix_meta_slurp (MAILSTREAM *stream,unsigned long *seq)
+{
+  struct stat sbuf;
+  char *s;
+  char *ret = NIL;
+  if (fstat (LOCAL->mfd,&sbuf))
+    MM_LOG ("Error obtaining size of mix metatdata file",ERROR);
+  if (sbuf.st_size > LOCAL->buflen) {
+				/* should be just a few dozen bytes */
+    if (sbuf.st_size > METAMAX) fatal ("absurd mix metadata file size");
+    fs_give ((void **) &LOCAL->buf);
+    LOCAL->buf = (char *) fs_get ((LOCAL->buflen = sbuf.st_size) + 1);
+  }
+				/* read current metadata file */
+  LOCAL->buf[sbuf.st_size] = '\0';
+  if (lseek (LOCAL->mfd,0,L_SET) ||
+      (read (LOCAL->mfd,s = LOCAL->buf,sbuf.st_size) != sbuf.st_size))
+    MM_LOG ("Error reading mix metadata file",ERROR);
+  else if ((*s != 'S') || !isxdigit (s[1]) ||
+	   ((*seq = strtoul (s+1,&s,16)) < LOCAL->metaseq) ||
+	   (*s++ != '\015') || (*s++ != '\012'))
+    MM_LOG ("Error in mix metadata file sequence record",ERROR);
+  else ret = s;
+  return ret;
+}
+
+/* MIX update metadata
+ * Accepts: MAIL stream
+ * Returns: T on success, NIL if error
+ *
+ * Index MUST be locked!!
+ */
+
+long mix_meta_update (MAILSTREAM *stream)
+{
+  long ret;
+				/* do nothing if stream readonly */
+  if (stream->rdonly) ret = LONGT;
+  else {
+    unsigned char c,*s,*ss,*t;
+    unsigned long i;
+    /* The worst-case metadata is limited to:
+     *    4 * (1 + 8 + 2) + (NUSERFLAGS * (MAXUSERFLAG + 1))
+     * which comes out to 1994 octets.  This is much smaller than the normal
+     * CHUNKSIZE definition of 64K, and CHUNKSIZE is the smallest size of
+     * LOCAL->buf.
+     *
+     * If more stuff gets added to the metadata, or if you change the value
+     * of NUSERFLAGS, MAXUSERFLAG or CHUNKSIZE, be sure to recalculate the
+     * above assertation.
+     */
+    sprintf (LOCAL->buf,SEQFMT,LOCAL->metaseq = mix_modseq (LOCAL->metaseq));
+    sprintf (LOCAL->buf + strlen (LOCAL->buf),MTAFMT,
+	     stream->uid_validity,stream->uid_last,LOCAL->newmsg);
+    for (i = 0, c = 'K', s = ss = LOCAL->buf + strlen (LOCAL->buf);
+	 (i < NUSERFLAGS) && (t = stream->user_flags[i]); ++i) {
+      if (!*t) fatal ("impossible empty keyword");
+      *s++ = c;			/* write delimiter */
+      while (*t) *s++ = *t++;	/* write keyword */
+      c = ' ';			/* delimiter is now space */
+    }
+    if (s != ss) {		/* tie off keywords line */
+      *s++ = '\015'; *s++ = '\012';
+    }
+				/* calculate length of metadata */
+    if ((i = s - LOCAL->buf) > LOCAL->buflen)
+      fatal ("impossible buffer overflow");
+    lseek (LOCAL->mfd,0,L_SET);	/* rewind file */
+				/* write new metadata */
+    ret = (write (LOCAL->mfd,LOCAL->buf,i) == i) ? LONGT : NIL;
+    ftruncate (LOCAL->mfd,i);	/* and tie off at that point */
+  }
+  return ret;
+}
+
+/* MIX index file routines */
+
+
+/* MIX update index
+ * Accepts: MAIL stream
+ *	    open FILE
+ *	    expansion check flag
+ * Returns: T on success, NIL if error
+ */
+
+long mix_index_update (MAILSTREAM *stream,FILE *idxf,long flag)
+{
+  unsigned long i;
+  long ret = LONGT;
+  if (!stream->rdonly) {	/* do nothing if stream readonly */
+    if (flag) {			/* need to do expansion check? */
+      char tmp[MAILTMPLEN];
+      size_t size;
+      struct stat sbuf;
+				/* calculate file size we need */
+      for (i = 1, size = 0; i <= stream->nmsgs; ++i)
+	if (!mail_elt (stream,i)->private.ghost) ++size;
+      if (size) {		/* Winston Smith's first dairy entry */
+	sprintf (tmp,IXRFMT,0,14,4,4,13,0,0,'+',0,0,0,0,0,0,0);
+	size *= strlen (tmp);
+      }
+				/* calculate file size we need */
+      sprintf (tmp,SEQFMT,LOCAL->indexseq);
+      size += strlen (tmp);
+				/* get current file size */
+      if (fstat (fileno (idxf),&sbuf)) {
+	MM_LOG ("Error getting size of mix index file",ERROR);
+	ret = NIL;
+      }
+				/* need to write additional space? */
+      else if (sbuf.st_size < size) {
+	void *buf = fs_get (size -= sbuf.st_size);
+	memset (buf,0,size);
+	if (fseek (idxf,0,SEEK_END) || (fwrite (buf,1,size,idxf) != size) ||
+	    fflush (idxf)) {
+	  fseek (idxf,sbuf.st_size,SEEK_SET);
+	  ftruncate (fileno (idxf),sbuf.st_size);
+	  MM_LOG ("Error extending mix index file",ERROR);
+	  ret = NIL;
+	}
+	fs_give ((void **) &buf);
+      }
+    }
+
+    if (ret) {			/* if still good to go */
+      rewind (idxf);		/* let's start at the very beginning */
+				/* write modseq first */
+      fprintf (idxf,SEQFMT,LOCAL->indexseq);
+				/* then write all messages */
+      for (i = 1; ret && (i <= stream->nmsgs); i++) {
+	MESSAGECACHE *elt = mail_elt (stream,i);
+	if (!elt->private.ghost)/* only write living messages */
+	  fprintf (idxf,IXRFMT,elt->private.uid,
+		   elt->year + BASEYEAR,elt->month,elt->day,
+		   elt->hours,elt->minutes,elt->seconds,
+		   elt->zoccident ? '-' : '+',elt->zhours,elt->zminutes,
+		   elt->rfc822_size,elt->private.spare.data,
+		   elt->private.special.offset,
+		   elt->private.msg.header.offset,
+		   elt->private.msg.header.text.size);
+	if (ferror (idxf)) {
+	  MM_LOG ("Error updating mix index file",ERROR);
+	  ret = NIL;
+	}
+      }
+      if (fflush (idxf)) {
+	MM_LOG ("Error flushing mix index file",ERROR);
+	ret = NIL;
+      }
+      if (ret) ftruncate (fileno (idxf),ftell (idxf));
+    }
+  }
+  return ret;
+}
+
+/* MIX status file routines */
+
+
+/* MIX update status
+ * Accepts: MAIL stream
+ *	    pointer to open FILE
+ *	    expansion check flag
+ * Returns: T on success, NIL if error
+ */
+
+long mix_status_update (MAILSTREAM *stream,FILE *statf,long flag)
+{
+  unsigned long i;
+  char tmp[MAILTMPLEN];
+  long ret = LONGT;
+  if (!stream->rdonly) {	/* do nothing if stream readonly */
+    if (flag) {			/* need to do expansion check? */
+      char tmp[MAILTMPLEN];
+      size_t size;
+      struct stat sbuf;
+				/* calculate file size we need */
+      for (i = 1, size = 0; i <= stream->nmsgs; ++i)
+	if (!mail_elt (stream,i)->private.ghost) ++size;
+      if (size) {		/* number of living messages */
+	sprintf (tmp,STRFMT,0,0,0,0);
+	size *= strlen (tmp);
+      }
+      sprintf (tmp,SEQFMT,LOCAL->statusseq);
+      size += strlen (tmp);
+				/* get current file size */
+      if (fstat (fileno (statf),&sbuf)) {
+	MM_LOG ("Error getting size of mix status file",ERROR);
+	ret = NIL;
+      }
+				/* need to write additional space? */
+      else if (sbuf.st_size < size) {
+	void *buf = fs_get (size -= sbuf.st_size);
+	memset (buf,0,size);
+	if (fseek (statf,0,SEEK_END) || (fwrite (buf,1,size,statf) != size) ||
+	    fflush (statf)) {
+	  fseek (statf,sbuf.st_size,SEEK_SET);
+	  ftruncate (fileno (statf),sbuf.st_size);
+	  MM_LOG ("Error extending mix status file",ERROR);
+	  ret = NIL;
+	}
+	fs_give ((void **) &buf);
+      }
+    }
+
+    if (ret) {			/* if still good to go */
+      rewind (statf);		/* let's start at the very beginning */
+				/* write sequence */
+      fprintf (statf,SEQFMT,LOCAL->statusseq);
+				/* write message status records */
+      for (i = 1; ret && (i <= stream->nmsgs); ++i) {
+	MESSAGECACHE *elt = mail_elt (stream,i);
+				/* make sure all messages have a modseq */
+	if (!elt->private.mod) elt->private.mod = LOCAL->statusseq;
+	if (!elt->private.ghost)/* only write living messages */
+	  fprintf (statf,STRFMT,elt->private.uid,elt->user_flags,
+		   (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
+		   (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
+		   (fDRAFT * elt->draft) + (elt->valid ? fOLD : NIL),
+		   elt->private.mod);
+	if (ferror (statf)) {
+	  sprintf (tmp,"Error updating mix status file: %.80s",
+		   strerror (errno));
+	  MM_LOG (tmp,ERROR);
+	  ret = NIL;
+	}
+      }
+      if (ret && fflush (statf)) {
+	MM_LOG ("Error flushing mix status file",ERROR);
+	ret = NIL;
+      }
+      if (ret) ftruncate (fileno (statf),ftell (statf));
+    }
+  }
+  return ret;
+}
+
+/* MIX data file routines */
+
+
+/* MIX open data file
+ * Accepts: MAIL stream
+ *	    pointer to returned fd if success
+ *	    pointer to returned size if success
+ *	    size of new data to be added
+ * Returns: open FILE, or NIL if failure
+ *
+ * The curend test assumes that the last message of the mailbox is the furthest
+ * point that the current data file extends, and thus that is all that needs to
+ * be tested for short file prevention.
+ */
+
+FILE *mix_data_open (MAILSTREAM *stream,int *fd,long *size,
+		     unsigned long newsize)
+{
+  FILE *msgf = NIL;
+  struct stat sbuf;
+  MESSAGECACHE *elt = stream->nmsgs ? mail_elt (stream,stream->nmsgs) : NIL;
+  unsigned long curend = (elt && (elt->private.spare.data == LOCAL->newmsg)) ?
+    elt->private.special.offset + elt->private.msg.header.offset +
+    elt->rfc822_size : 0;
+				/* allow create if curend 0 */
+  if ((*fd = open (mix_file_data (LOCAL->buf,stream->mailbox,LOCAL->newmsg),
+		   O_RDWR | (curend ? NIL : O_CREAT),NIL)) >= 0) {
+    fstat (*fd,&sbuf);		/* get current file size */
+				/* can we use this file? */
+    if ((curend <= sbuf.st_size) &&
+	(!sbuf.st_size || ((sbuf.st_size + newsize) <= MIXDATAROLL)))
+      *size = sbuf.st_size;	/* yes, return current size */
+    else {			/* short file or becoming too long */
+      if (curend > sbuf.st_size) {
+	char tmp[MAILTMPLEN];
+	sprintf (tmp,"short mix message file %.08lx (%ld > %ld), rolling",
+		 LOCAL->newmsg,curend,sbuf.st_size);
+	MM_LOG (tmp,WARN);	/* shouldn't happen */
+      }
+      close (*fd);		/* roll to a new file */
+      while ((*fd = open (mix_file_data
+			  (LOCAL->buf,stream->mailbox,
+			   LOCAL->newmsg = mix_modseq (LOCAL->newmsg)),
+			  O_RDWR | O_CREAT | O_EXCL,sbuf.st_mode)) < 0);
+      *size = 0;		/* brand new file */
+      fchmod (*fd,sbuf.st_mode);/* with same mode as previous file */
+    }
+  }
+  if (*fd >= 0) {		/* have a data file? */
+				/* yes, get stdio and set position */
+    if (msgf = fdopen (*fd,"r+b")) fseek (msgf,*size,SEEK_SET);
+    else close (*fd);		/* fdopen() failed? */
+  }
+  return msgf;			/* return results */
+}
+
+/* MIX open sortcache
+ * Accepts: MAIL stream
+ * Returns: open FILE, or NIL if failure or could only get readonly sortcache
+ */
+
+FILE *mix_sortcache_open (MAILSTREAM *stream)
+{
+  int fd,refwd;
+  unsigned long i,uid,sentdate,fromlen,tolen,cclen,subjlen,msgidlen,reflen;
+  char *s,*t,*msg,tmp[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  SORTCACHE *sc;
+  STRINGLIST *sl;
+  struct stat sbuf;
+  int rdonly = NIL;
+  FILE *srtcf = NIL;
+  mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL);
+  fstat (LOCAL->mfd,&sbuf);
+  if (!stream->nmsgs);		/* do nothing if mailbox empty */
+				/* open sortcache file */
+  else if (((fd = open (LOCAL->sortcache,O_RDWR|O_CREAT,sbuf.st_mode)) < 0) &&
+	   !(rdonly = ((fd = open (LOCAL->sortcache,O_RDONLY,NIL)) >= 0)))
+    MM_LOG ("Error opening mix sortcache file",WARN);
+				/* acquire lock and FILE */
+  else if (!flock (fd,rdonly ? LOCK_SH : LOCK_EX) &&
+	   !(srtcf = fdopen (fd,rdonly ? "rb" : "r+b"))) {
+    MM_LOG ("Error obtaining stream on mix sortcache file",WARN);
+    flock (fd,LOCK_UN);		/* relinquish lock */
+    close (fd);
+  }
+  else if (!(i = mix_read_sequence (srtcf)) || (i < LOCAL->sortcacheseq))
+    MM_LOG ("Error in mix sortcache file sequence record",WARN);
+				/* sequence changed from last time? */
+  else if (i > LOCAL->sortcacheseq) {
+    LOCAL->sortcacheseq = i;	/* update sequence */
+    while ((s = t = mix_read_record (srtcf,LOCAL->buf,LOCAL->buflen,
+				     "sortcache")) && *s &&
+	   (msg = "uid") && (*s++ == ':') && isxdigit (*s)) {
+      uid = strtoul (s,&s,16);
+      if ((*s++ == ':') && isxdigit (*s)) {
+	sentdate = strtoul (s,&s,16);
+	if ((*s++ == ':') && isxdigit (*s)) {
+	  fromlen = strtoul (s,&s,16);
+	  if ((*s++ == ':') && isxdigit (*s)) {
+	    tolen = strtoul (s,&s,16);
+	    if ((*s++ == ':') && isxdigit (*s)) {
+	      cclen = strtoul (s,&s,16);
+	      if ((*s++ == ':') && ((*s == 'R') || (*s == ' ')) &&
+		  isxdigit (s[1])) {
+		refwd = (*s++ == 'R') ? T : NIL;
+		subjlen = strtoul (s,&s,16);
+		if ((*s++ == ':') && isxdigit (*s)) {
+		  msgidlen = strtoul (s,&s,16);
+		  if ((*s++ == ':') && isxdigit (*s)) {
+		    reflen = strtoul (s,&s,16);
+				/* ignore expansion values */
+		    if (*s++ == ':') {
+
+		      if (i = mail_msgno (stream,uid)) {
+			sc = (SORTCACHE *) (*mc) (stream,i,CH_SORTCACHE);
+			sc->size = (elt = mail_elt (stream,i))->rfc822_size;
+			sc->date = sentdate;
+			sc->arrival = elt->day ? mail_longdate (elt) : 1;
+			if (refwd) sc->refwd = T;
+			if (fromlen) {
+			  if (sc->from) fseek (srtcf,fromlen + 2,SEEK_CUR);
+			  else if ((getc (srtcf) != 'F') ||
+				   (fread (sc->from = (char *) fs_get(fromlen),
+					   1,fromlen-1,srtcf) != (fromlen-1))||
+				   (sc->from[fromlen-1] = '\0') ||
+				   (getc (srtcf) != '\015') ||
+				   (getc (srtcf) != '\012')) {
+			    msg = "from data";
+			    break;
+			  }
+			}
+			if (tolen) {
+			  if (sc->to) fseek (srtcf,tolen + 2,SEEK_CUR);
+			  else if ((getc (srtcf) != 'T') ||
+				   (fread (sc->to = (char *) fs_get (tolen),
+					   1,tolen-1,srtcf) != (tolen - 1)) ||
+				   (sc->to[tolen-1] = '\0') ||
+				   (getc (srtcf) != '\015') ||
+				   (getc (srtcf) != '\012')) {
+			    msg = "to data";
+			    break;
+			  }
+			}
+			if (cclen) {
+			  if (sc->cc) fseek (srtcf,cclen + 2,SEEK_CUR);
+			  else if ((getc (srtcf) != 'C') ||
+				   (fread (sc->cc = (char *) fs_get (cclen),
+					   1,cclen-1,srtcf) != (cclen - 1)) ||
+				   (sc->cc[cclen-1] = '\0') ||
+				   (getc (srtcf) != '\015') ||
+				   (getc (srtcf) != '\012')) {
+			    msg = "cc data";
+			    break;
+			  }
+			}
+			if (subjlen) {
+			  if (sc->subject) fseek (srtcf,subjlen + 2,SEEK_CUR);
+			  else if ((getc (srtcf) != 'S') ||
+				     (fread (sc->subject =
+					     (char *) fs_get (subjlen),1,
+					     subjlen-1,srtcf) != (subjlen-1))||
+				   (sc->subject[subjlen-1] = '\0') ||
+				   (getc (srtcf) != '\015') ||
+				   (getc (srtcf) != '\012')) {
+			    msg = "subject data";
+			    break;
+			  }
+			}
+
+			if (msgidlen) {
+			  if (sc->message_id)
+			    fseek (srtcf,msgidlen + 2,SEEK_CUR);
+			  else if ((getc (srtcf) != 'M') ||
+				   (fread (sc->message_id = 
+					   (char *) fs_get (msgidlen),1,
+					   msgidlen-1,srtcf) != (msgidlen-1))||
+				   (sc->message_id[msgidlen-1] = '\0') ||
+				   (getc (srtcf) != '\015') ||
+				   (getc (srtcf) != '\012')) {
+			    msg = "message-id data";
+			    break;
+			  }
+			}
+			if (reflen) {
+			  if (sc->references) fseek(srtcf,reflen + 2,SEEK_CUR);
+				/* make sure it fits */
+			  else {
+			    if (reflen >= LOCAL->buflen) {
+			      fs_give ((void **) &LOCAL->buf);
+			      LOCAL->buf = (char *)
+				fs_get ((LOCAL->buflen = reflen) + 1);
+			      }
+			    if ((getc (srtcf) != 'R') ||
+				(fread (LOCAL->buf,1,reflen-1,srtcf) !=
+				 (reflen - 1)) ||
+				(LOCAL->buf[reflen-1] = '\0') ||
+				(getc (srtcf) != '\015') ||
+				(getc (srtcf) != '\012')) {
+			      msg = "references data";
+			      break;
+			    }
+			    for (s = LOCAL->buf,sl = NIL,
+				   sc->references = mail_newstringlist ();
+				 s && *s; s += i + 1) {
+			      if ((i = strtoul (s,&s,16)) && (*s++ == ':') &&
+				  (s[i] == ':')) {
+				if (sl) sl = sl->next = mail_newstringlist();
+				else sl = sc->references;
+				s[i] = '\0';
+				sl->text.data = cpystr (s);
+				sl->text.size = i;
+			      }
+			      else s = NIL;
+			    }
+			    if (!s || *s ||
+				(s != ((char *) LOCAL->buf + reflen - 1))) {
+			      msg = "references length consistency check";
+			      break;
+			    }
+			  }
+			}
+		      }
+
+				/* UID not found, ignore this message */
+		      else fseek (srtcf,((fromlen ? fromlen + 2 : 0) +
+					 (tolen ? tolen + 2 : 0) +
+					 (cclen ? cclen + 2 : 0) +
+					 (subjlen ? subjlen + 2 : 0) +
+					 (msgidlen ? msgidlen + 2 : 0) +
+					 (reflen ? reflen + 2 : 0)),
+				  SEEK_CUR);
+		      continue;
+		    }
+		    else msg = "expansion";
+		  }
+		  else msg = "references";
+		}
+		else msg = "message-id";
+	      }
+	      else msg = "subject";
+	    }
+	    else msg = "cc";
+	  }
+	  else msg = "to";
+	}
+	else msg = "from";
+      }
+      else msg = "sentdate";
+      break;			/* error somewhere */
+    }
+    if (!t || *t) {		/* error detected? */
+      if (t) {			/* non-null means bogus record */
+	sprintf (tmp,"Error in %s in mix sortcache record: %.500s",msg,t);
+	MM_LOG (tmp,WARN);
+      }
+      fclose (srtcf);		/* either way, must punt */
+      srtcf = NIL;
+    }
+  }
+  if (rdonly && srtcf) {	/* can't update if readonly */
+    unlink (LOCAL->sortcache);	/* try deleting it */
+    fclose (srtcf);		/* so close it and return as if error */
+    srtcf = NIL;
+  }
+  else fchmod (fd,sbuf.st_mode);
+  return srtcf;
+}
+
+/* MIX update and close sortcache
+ * Accepts: MAIL stream
+ *	    pointer to open FILE (if FILE is NIL, do nothing)
+ * Returns: T on success, NIL on error
+ */
+
+long mix_sortcache_update (MAILSTREAM *stream,FILE **sortcache)
+{
+  FILE *f = *sortcache;
+  long ret = LONGT;
+  if (f) {			/* ignore if no file */
+    unsigned long i,j;
+    mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL);
+    for (i = 1; (i <= stream->nmsgs) &&
+	   !((SORTCACHE *) (*mc) (stream,i,CH_SORTCACHE))->dirty; ++i);
+    if (i <= stream->nmsgs) {	/* only update if some entry is dirty */
+      rewind (f);		/* let's start at the very beginning */
+				/* write sequence */
+      fprintf (f,SEQFMT,LOCAL->sortcacheseq = mix_modseq(LOCAL->sortcacheseq));
+      for (i = 1; ret && (i <= stream->nmsgs); ++i) {
+	MESSAGECACHE *elt = mail_elt (stream,i);
+	SORTCACHE *s = (SORTCACHE *) (*mc) (stream,i,CH_SORTCACHE);
+	STRINGLIST *sl;
+	s->dirty = NIL;		/* no longer dirty */
+	if (sl = s->references)	/* count length of references */
+	  for (j = 1; sl && sl->text.data; sl = sl->next)
+	    j += 10 + sl->text.size;
+	else j = 0;		/* no references yet */
+	fprintf (f,SCRFMT,elt->private.uid,s->date,
+		 s->from ? strlen (s->from) + 1 : 0,
+		 s->to ? strlen (s->to) + 1 : 0,s->cc ? strlen (s->cc) + 1 : 0,
+		 s->refwd ? 'R' : ' ',s->subject ? strlen (s->subject) + 1: 0,
+		 s->message_id ? strlen (s->message_id) + 1 : 0,j);
+	if (s->from) fprintf (f,"F%s\015\012",s->from);
+	if (s->to) fprintf (f,"T%s\015\012",s->to);
+	if (s->cc) fprintf (f,"C%s\015\012",s->cc);
+	if (s->subject) fprintf (f,"S%s\015\012",s->subject);
+	if (s->message_id) fprintf (f,"M%s\015\012",s->message_id);
+	if (j) {		/* any references to write? */
+	  fputc ('R',f);	/* yes, do so */
+	  for (sl = s->references; sl && sl->text.data; sl = sl->next)
+	    fprintf (f,"%08lx:%s:",sl->text.size,sl->text.data);
+	  fputs ("\015\012",f);
+	}
+	if (ferror (f)) {
+	  MM_LOG ("Error updating mix sortcache file",WARN);
+	  ret = NIL;
+	}
+      }
+      if (ret && fflush (f)) {
+	MM_LOG ("Error flushing mix sortcache file",WARN);
+	ret = NIL;
+      }
+      if (ret) ftruncate (fileno (f),ftell (f));
+    }
+    if (fclose (f)) {
+      MM_LOG ("Error closing mix sortcache file",WARN);
+      ret = NIL;
+    }
+  }
+  return ret;
+}
+
+/* MIX generic file routines */
+
+/* MIX read record
+ * Accepts: open FILE
+ *	    buffer
+ *	    buffer length
+ *	    record type
+ * Returns: buffer if success, else NIL (zero-length buffer means EOF)
+ */
+
+char *mix_read_record (FILE *f,char *buf,unsigned long buflen,char *type)
+{
+  char *s,tmp[MAILTMPLEN];
+				/* ensure string tied off */
+  buf[buflen-2] = buf[buflen-1] = '\0';
+  while (fgets (buf,buflen-1,f)) {
+    if (s = strchr (buf,'\012')) {
+      if ((s != buf) && (s[-1] == '\015')) --s;
+      *s = '\0';		/* tie off buffer */
+      if (s != buf) return buf;	/* return if non-empty buffer */
+      sprintf (tmp,"Empty mix %s record",type);
+      MM_LOG (tmp,WARN);
+    }
+    else if (buf[buflen-2]) {	/* overlong record is bad news */
+      sprintf (tmp,"Oversize mix %s record: %.512s",type,buf);
+      MM_LOG (tmp,ERROR);
+      return NIL;
+    }
+    else {
+      sprintf (tmp,"Truncated mix %s record: %.512s",type,buf);
+      MM_LOG (tmp,WARN);
+      return buf;		/* pass to caller anyway */
+    }
+  }
+  buf[0] = '\0';		/* return empty buffer on EOF */
+  return buf;
+}
+
+/* MIX read sequence record
+ * Accepts: open FILE
+ * Returns: sequence value, or NIL if failure
+ */
+
+unsigned long mix_read_sequence (FILE *f)
+{
+  unsigned long ret;
+  char *s,tmp[MAILTMPLEN];
+  if (!mix_read_record (f,tmp,MAILTMPLEN-1,"sequence")) return NIL;
+  switch (tmp[0]) {		/* examine record */
+  case '\0':			/* end of file */
+    ret = 1;			/* start a new sequence regime */
+    break;
+  case 'S':			/* sequence record */
+    if (isxdigit (tmp[1])) {	/* must be followed by hex value */
+      ret = strtoul (tmp+1,&s,16);
+      if (!*s) break;		/* and nothing more */
+    }
+				/* drop into default case */
+  default:			/* anything else is an error */
+    return NIL;			/* return error */
+  }
+  return ret;
+}
+
+/* MIX internal routines */
+
+
+/* MIX mail build directory name
+ * Accepts: destination string
+ *          source
+ * Returns: destination or empty string if error
+ */
+
+char *mix_dir (char *dst,char *name)
+{
+  char *s;
+				/* empty string if mailboxfile fails */
+  if (!mailboxfile (dst,name)) *dst = '\0';
+				/* driver-selected INBOX  */
+  else if (!*dst) mailboxfile (dst,"~/INBOX");
+				/* tie off unnecessary trailing / */
+  else if ((s = strrchr (dst,'/')) && !s[1]) *s = '\0';
+  return dst;
+}
+
+
+/* MIX mail build file name
+ * Accepts: destination string
+ *	    directory name
+ *	    file name
+ * Returns: destination
+ */
+
+char *mix_file (char *dst,char *dir,char *name)
+{
+  sprintf (dst,"%.500s/%.80s%.80s",dir,MIXNAME,name);
+  return dst;
+}
+
+
+/* MIX mail build file name from data file number
+ * Accepts: destination string
+ *	    directory name
+ *	    data file number
+ * Returns: destination
+ */
+
+char *mix_file_data (char *dst,char *dir,unsigned long data)
+{
+  char tmp[MAILTMPLEN];
+  if (data) sprintf (tmp,"%08lx",data);
+  else tmp[0] = '\0';		/* compatibility with experimental version */
+  return mix_file (dst,dir,tmp);
+}
+
+/* MIX mail get new modseq
+ * Accepts: old modseq
+ * Returns: new modseq value
+ */
+
+unsigned long mix_modseq (unsigned long oldseq)
+{
+				/* normally time now */
+  unsigned long ret = (unsigned long) time (NIL);
+				/* ensure that modseq doesn't go backwards */
+  if (ret <= oldseq) ret = oldseq + 1;
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/mkauths	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,40 @@
+#!/bin/sh
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+# Program:	Authenticator Linkage Generator
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		5 December 1995
+# Last Edited:	30 August 2006
+
+# Erase old authenticators list
+rm -f auths.c
+touch auths.c
+
+# Now define the new list
+for authenticator
+ do
+  if [ -f Makefile."$authenticator" ]; then
+    make -f Makefile."$authenticator" `cat SPECIALS`
+  fi
+  echo "extern AUTHENTICATOR auth_"$authenticator";" >> linkage.h
+  echo "  auth_link (&auth_"$authenticator");		/* link in the $authenticator authenticator */" | cat >> linkage.c
+  echo "#include \"auth_"$authenticator".c\"" >> auths.c
+done
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/mmdf.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,2549 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	MMDF mail routines
+ *
+ * Author:	Mark Crispin
+ *		UW Technology
+ *		University of Washington
+ *		Seattle, WA  98195
+ *		Internet: MRC@Washington.EDU
+ *
+ * Date:	20 December 1989
+ * Last Edited:	27 March 2008
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <signal.h>
+#include "mail.h"
+#include "osdep.h"
+#include <time.h>
+#include <sys/stat.h>
+#include "pseudo.h"
+#include "fdstring.h"
+#include "misc.h"
+#include "dummy.h"
+
+/* Supposedly, this page has everything the MMDF driver needs to know about
+ * the MMDF delimiter.  By changing these macros, the MMDF driver should
+ * change with it.  Note that if you change the length of MMDFHDRTXT you
+ * also need to change the ISMMDF and RETIFMMDFWRD macros to reflect the new
+ * size.
+ */
+
+
+/* Useful MMDF constants */
+
+#define MMDFCHR '\01'		/* MMDF character */
+#define MMDFCHRS 0x01010101	/* MMDF header character spread in a word */
+				/* MMDF header text */
+#define MMDFHDRTXT "\01\01\01\01\n"
+				/* length of MMDF header text */
+#define MMDFHDRLEN (sizeof (MMDFHDRTXT) - 1)
+
+
+/* Validate MMDF header
+ * Accepts: pointer to candidate string to validate as an MMDF header
+ * Returns: T if valid; else NIL
+ */
+
+#define ISMMDF(s)							\
+  ((*(s) == MMDFCHR) && ((s)[1] == MMDFCHR) && ((s)[2] == MMDFCHR) &&	\
+   ((s)[3] == MMDFCHR) && ((s)[4] == '\n'))
+
+
+/* Return if a 32-bit word has the start of an MMDF header
+ * Accepts: pointer to word of four bytes to validate as an MMDF header
+ * Returns: pointer to MMDF header, else proceeds
+ */
+
+#define RETIFMMDFWRD(s) {						\
+  if (s[3] == MMDFCHR) {						\
+    if ((s[4] == MMDFCHR) && (s[5] == MMDFCHR) && (s[6] == MMDFCHR) &&	\
+	(s[7] == '\n')) return s + 3;					\
+    else if (s[2] == MMDFCHR) {						\
+      if ((s[4] == MMDFCHR) && (s[5] == MMDFCHR) && (s[6] == '\n'))	\
+	return s + 2;							\
+      else if (s[1] == MMDFCHR) {					\
+	if ((s[4] == MMDFCHR) && (s[5] == '\n')) return s + 1;		\
+	else if ((*s == MMDFCHR) && (s[4] == '\n')) return s;		\
+      }									\
+    }									\
+  }									\
+}
+
+/* Validate line
+ * Accepts: pointer to candidate string to validate as a From header
+ *	    return pointer to end of date/time field
+ *	    return pointer to offset from t of time (hours of ``mmm dd hh:mm'')
+ *	    return pointer to offset from t of time zone (if non-zero)
+ * Returns: t,ti,zn set if valid From string, else ti is NIL
+ */
+
+#define VALID(s,x,ti,zn) {						\
+  ti = 0;								\
+  if ((*s == 'F') && (s[1] == 'r') && (s[2] == 'o') && (s[3] == 'm') &&	\
+      (s[4] == ' ')) {							\
+    for (x = s + 5; *x && *x != '\n'; x++);				\
+    if (*x) {								\
+      if (x - s >= 41) {						\
+	for (zn = -1; x[zn] != ' '; zn--);				\
+	if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') &&	\
+	    (x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') &&	\
+	    (x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') &&	\
+	    (x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))\
+	  x += zn - 12;							\
+      }									\
+      if (x - s >= 27) {						\
+	if (x[-5] == ' ') {						\
+	  if (x[-8] == ':') zn = 0,ti = -5;				\
+	  else if (x[-9] == ' ') ti = zn = -9;				\
+	  else if ((x[-11] == ' ') && ((x[-10]=='+') || (x[-10]=='-')))	\
+	    ti = zn = -11;						\
+	}								\
+	else if (x[-4] == ' ') {					\
+	  if (x[-9] == ' ') zn = -4,ti = -9;				\
+	}								\
+	else if (x[-6] == ' ') {					\
+	  if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-')))	\
+	    zn = -6,ti = -11;						\
+	}								\
+	if (ti && !((x[ti - 3] == ':') &&				\
+		    (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') &&	\
+		    (x[ti - 3] == ' ') && (x[ti - 7] == ' ') &&		\
+		    (x[ti - 11] == ' '))) ti = 0;			\
+      }									\
+    }									\
+  }									\
+}
+
+/* You are not expected to understand this macro, but read the next page if
+ * you are not faint of heart.
+ *
+ * Known formats to the VALID macro are:
+ *		From user Wed Dec  2 05:53 1992
+ * BSD		From user Wed Dec  2 05:53:22 1992
+ * SysV		From user Wed Dec  2 05:53 PST 1992
+ * rn		From user Wed Dec  2 05:53:22 PST 1992
+ *		From user Wed Dec  2 05:53 -0700 1992
+ * emacs	From user Wed Dec  2 05:53:22 -0700 1992
+ *		From user Wed Dec  2 05:53 1992 PST
+ *		From user Wed Dec  2 05:53:22 1992 PST
+ *		From user Wed Dec  2 05:53 1992 -0700
+ * Solaris	From user Wed Dec  2 05:53:22 1992 -0700
+ *
+ * Plus all of the above with `` remote from xxx'' after it. Thank you very
+ * much, smail and Solaris, for making my life considerably more complicated.
+ */
+
+/*
+ * What?  You want to understand the VALID macro anyway?  Alright, since you
+ * insist.  Actually, it isn't really all that difficult, provided that you
+ * take it step by step.
+ *
+ * Line 1	Initializes the return ti value to failure (0);
+ * Lines 2-3	Validates that the 1st-5th characters are ``From ''.
+ * Lines 4-5	Validates that there is an end of line and points x at it.
+ * Lines 6-13	First checks to see if the line is at least 41 characters long.
+ *		If so, it scans backwards to find the rightmost space.  From
+ *		that point, it scans backwards to see if the string matches
+ *		`` remote from''.  If so, it sets x to point to the space at
+ *		the start of the string.
+ * Line 14	Makes sure that there are at least 27 characters in the line.
+ * Lines 15-20	Checks if the date/time ends with the year (there is a space
+ *		five characters back).  If there is a colon three characters
+ *		further back, there is no timezone field, so zn is set to 0
+ *		and ti is set in front of the year.  Otherwise, there must
+ *		either to be a space four characters back for a three-letter
+ *		timezone, or a space six characters back followed by a + or -
+ *		for a numeric timezone; in either case, zn and ti become the
+ *		offset of the space immediately before it.
+ * Lines 21-23	Are the failure case for line 14.  If there is a space four
+ *		characters back, it is a three-letter timezone; there must be a
+ *		space for the year nine characters back.  zn is the zone
+ *		offset; ti is the offset of the space.
+ * Lines 24-27	Are the failure case for line 20.  If there is a space six
+ *		characters back, it is a numeric timezone; there must be a
+ *		space eleven characters back and a + or - five characters back.
+ *		zn is the zone offset; ti is the offset of the space.
+ * Line 28-31	If ti is valid, make sure that the string before ti is of the
+ *		form www mmm dd hh:mm or www mmm dd hh:mm:ss, otherwise
+ *		invalidate ti.  There must be a colon three characters back
+ *		and a space six or nine	characters back (depending upon
+ *		whether or not the character six characters back is a colon).
+ *		There must be a space three characters further back (in front
+ *		of the day), one seven characters back (in front of the month),
+ *		and one eleven characters back (in front of the day of week).
+ *		ti is set to be the offset of the space before the time.
+ *
+ * Why a macro?  It gets invoked a *lot* in a tight loop.  On some of the
+ * newer pipelined machines it is faster being open-coded than it would be if
+ * subroutines are called.
+ *
+ * Why does it scan backwards from the end of the line, instead of doing the
+ * much easier forward scan?  There is no deterministic way to parse the
+ * ``user'' field, because it may contain unquoted spaces!  Yes, I tested it to
+ * see if unquoted spaces were possible.  They are, and I've encountered enough
+ * evil mail to be totally unwilling to trust that ``it will never happen''.
+ */
+
+/* Build parameters */
+
+#define KODRETRY 15		/* kiss-of-death retry in seconds */
+#define LOCKTIMEOUT 5		/* lock timeout in minutes */
+
+
+/* MMDF I/O stream local data */
+
+typedef struct mmdf_local {
+  unsigned int dirty : 1;	/* disk copy needs updating */
+  unsigned int ddirty : 1;	/* double-dirty, ping becomes checkpoint */
+  unsigned int pseudo : 1;	/* uses a pseudo message */
+  unsigned int appending : 1;	/* don't mark new messages as old */
+  int fd;			/* mailbox file descriptor */
+  int ld;			/* lock file descriptor */
+  char *lname;			/* lock file name */
+  off_t filesize;		/* file size parsed */
+  time_t filetime;		/* last file time */
+  unsigned char *buf;		/* temporary buffer */
+  unsigned long buflen;		/* current size of temporary buffer */
+  unsigned long uid;		/* current text uid */
+  SIZEDTEXT text;		/* current text */
+  unsigned long textlen;	/* current text length */
+  char *line;			/* returned line */
+  char *linebuf;		/* line readin buffer */
+  unsigned long linebuflen;	/* current line readin buffer length */
+} MMDFLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((MMDFLOCAL *) stream->local)
+
+
+/* MMDF protected file structure */
+
+typedef struct mmdf_file {
+  MAILSTREAM *stream;		/* current stream */
+  off_t curpos;			/* current file position */
+  off_t protect;		/* protected position */
+  off_t filepos;		/* current last written file position */
+  char *buf;			/* overflow buffer */
+  size_t buflen;		/* current overflow buffer length */
+  char *bufpos;			/* current buffer position */
+} MMDFFILE;
+
+/* Function prototypes */
+
+DRIVER *mmdf_valid (char *name);
+long mmdf_isvalid (char *name,char *tmp);
+long mmdf_isvalid_fd (int fd,char *tmp);
+void *mmdf_parameters (long function,void *value);
+void mmdf_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void mmdf_list (MAILSTREAM *stream,char *ref,char *pat);
+void mmdf_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long mmdf_create (MAILSTREAM *stream,char *mailbox);
+long mmdf_delete (MAILSTREAM *stream,char *mailbox);
+long mmdf_rename (MAILSTREAM *stream,char *old,char *newname);
+MAILSTREAM *mmdf_open (MAILSTREAM *stream);
+void mmdf_close (MAILSTREAM *stream,long options);
+char *mmdf_header (MAILSTREAM *stream,unsigned long msgno,
+		   unsigned long *length,long flags);
+long mmdf_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+char *mmdf_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
+		      unsigned long *length,long flags);
+void mmdf_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
+long mmdf_ping (MAILSTREAM *stream);
+void mmdf_check (MAILSTREAM *stream);
+long mmdf_expunge (MAILSTREAM *stream,char *sequence,long options);
+long mmdf_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long mmdf_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+int mmdf_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
+		     STRING *msg);
+int mmdf_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set);
+
+void mmdf_abort (MAILSTREAM *stream);
+char *mmdf_file (char *dst,char *name);
+int mmdf_lock (char *file,int flags,int mode,DOTLOCK *lock,int op);
+void mmdf_unlock (int fd,MAILSTREAM *stream,DOTLOCK *lock);
+int mmdf_parse (MAILSTREAM *stream,DOTLOCK *lock,int op);
+char *mmdf_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size);
+unsigned long mmdf_pseudo (MAILSTREAM *stream,char *hdr);
+unsigned long mmdf_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt,
+			    unsigned long uid,long flag);
+long mmdf_rewrite (MAILSTREAM *stream,unsigned long *nexp,DOTLOCK *lock,
+		   long flags);
+long mmdf_extend (MAILSTREAM *stream,unsigned long size);
+void mmdf_write (MMDFFILE *f,char *s,unsigned long i);
+void mmdf_phys_write (MMDFFILE *f,char *buf,size_t size);
+
+/* MMDF mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER mmdfdriver = {
+  "mmdf",			/* driver name */
+				/* driver flags */
+  DR_LOCAL|DR_MAIL|DR_LOCKING|DR_NONEWMAILRONLY|DR_XPOINT,
+  (DRIVER *) NIL,		/* next driver */
+  mmdf_valid,			/* mailbox is valid for us */
+  mmdf_parameters,		/* manipulate parameters */
+  mmdf_scan,			/* scan mailboxes */
+  mmdf_list,			/* list mailboxes */
+  mmdf_lsub,			/* list subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  mmdf_create,			/* create mailbox */
+  mmdf_delete,			/* delete mailbox */
+  mmdf_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  mmdf_open,			/* open mailbox */
+  mmdf_close,			/* close mailbox */
+  NIL,				/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  mmdf_header,			/* fetch message header */
+  mmdf_text,			/* fetch message text */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  NIL,				/* modify flags */
+  mmdf_flagmsg,			/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  mmdf_ping,			/* ping mailbox to see if still alive */
+  mmdf_check,			/* check for new messages */
+  mmdf_expunge,			/* expunge deleted messages */
+  mmdf_copy,			/* copy messages to another mailbox */
+  mmdf_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM mmdfproto = {&mmdfdriver};
+
+char *mmdfhdr = MMDFHDRTXT;	/* MMDF header */
+
+/* MMDF mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *mmdf_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+  return mmdf_isvalid (name,tmp) ? &mmdfdriver : NIL;
+}
+
+
+/* MMDF mail test for valid mailbox name
+ * Accepts: mailbox name
+ *	    scratch buffer
+ * Returns: T if valid, NIL otherwise
+ */
+
+long mmdf_isvalid (char *name,char *tmp)
+{
+  int fd;
+  int ret = NIL;
+  char *t,file[MAILTMPLEN];
+  struct stat sbuf;
+  time_t tp[2];
+  errno = EINVAL;		/* assume invalid argument */
+				/* must be non-empty file */
+  if ((t = dummy_file (file,name)) && !stat (t,&sbuf)) {
+    if (!sbuf.st_size)errno = 0;/* empty file */
+    else if ((fd = open (file,O_RDONLY,NIL)) >= 0) {
+				/* error -1 for invalid format */
+      if (!(ret = mmdf_isvalid_fd (fd,tmp))) errno = -1;
+      close (fd);		/* close the file */
+				/* \Marked status? */
+      if ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) {
+	tp[0] = sbuf.st_atime;	/* preserve atime and mtime */
+	tp[1] = sbuf.st_mtime;
+	utime (file,tp);	/* set the times */
+      }
+    }
+  }
+  return ret;			/* return what we should */
+}
+
+/* MMDF mail test for valid mailbox
+ * Accepts: file descriptor
+ *	    scratch buffer
+ * Returns: T if valid, NIL otherwise
+ */
+
+long mmdf_isvalid_fd (int fd,char *tmp)
+{
+  int ret = NIL;
+  memset (tmp,'\0',MAILTMPLEN);
+  if (read (fd,tmp,MAILTMPLEN-1) >= 0) ret = ISMMDF (tmp) ? T : NIL;
+  return ret;			/* return what we should */
+}
+
+
+/* MMDF manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *mmdf_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case GET_INBOXPATH:
+    if (value) ret = dummy_file ((char *) value,"INBOX");
+    break;
+  }
+  return ret;
+}
+
+/* MMDF mail scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void mmdf_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* MMDF mail list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mmdf_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_list (NIL,ref,pat);
+}
+
+
+/* MMDF mail list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mmdf_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_lsub (NIL,ref,pat);
+}
+
+/* MMDF mail create mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long mmdf_create (MAILSTREAM *stream,char *mailbox)
+{
+  char *s,mbx[MAILTMPLEN],tmp[MAILTMPLEN];
+  long ret = NIL;
+  int i,fd;
+  time_t ti = time (0);
+  if (!(s = dummy_file (mbx,mailbox))) {
+    sprintf (tmp,"Can't create %.80s: invalid name",mailbox);
+    MM_LOG (tmp,ERROR);
+  }
+				/* create underlying file */
+  else if (dummy_create_path (stream,s,get_dir_protection (mailbox))) {
+				/* done if dir-only or whiner */
+    if (((s = strrchr (s,'/')) && !s[1]) ||
+	mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) ret = T;
+    else if ((fd = open (mbx,O_WRONLY,
+		    (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0) {
+      sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno));
+      MM_LOG (tmp,ERROR);
+      unlink (mbx);		/* delete the file */
+    }
+    else {			/* initialize header */
+      memset (tmp,'\0',MAILTMPLEN);
+      sprintf (tmp,"%sFrom %s %sDate: ",mmdfhdr,pseudo_from,ctime (&ti));
+      rfc822_date (s = tmp + strlen (tmp));
+      sprintf (s += strlen (s),	/* write the pseudo-header */
+	       "\nFrom: %s <%s@%s>\nSubject: %s\nX-IMAP: %010lu 0000000000",
+	       pseudo_name,pseudo_from,mylocalhost (),pseudo_subject,
+	       (unsigned long) ti);
+      for (i = 0; i < NUSERFLAGS; ++i) if (default_user_flag (i))
+	sprintf (s += strlen (s)," %s",default_user_flag (i));
+      sprintf (s += strlen (s),"\nStatus: RO\n\n%s\n%s",pseudo_msg,mmdfhdr);
+      if (write (fd,tmp,strlen (tmp)) > 0) ret = T;
+      else {
+	sprintf (tmp,"Can't initialize mailbox node %.80s: %s",mbx,
+		 strerror (errno));
+	MM_LOG (tmp,ERROR);
+	unlink (mbx);		/* delete the file */
+      }
+      close (fd);		/* close file */
+    }
+  }
+				/* set proper protections */
+  return ret ? set_mbx_protections (mailbox,mbx) : NIL;
+}
+
+/* MMDF mail delete mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long mmdf_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return mmdf_rename (stream,mailbox,NIL);
+}
+
+
+/* MMDF mail rename mailbox
+ * Accepts: MAIL stream
+ *	    old mailbox name
+ *	    new mailbox name (or NIL for delete)
+ * Returns: T on success, NIL on failure
+ */
+
+long mmdf_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  long ret = NIL;
+  char c,*s = NIL;
+  char tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  DOTLOCK lockx;
+  int fd,ld;
+  long i;
+  struct stat sbuf;
+  MM_CRITICAL (stream);	/* get the c-client lock */
+  if (!dummy_file (file,old) ||
+      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
+		   ((s = strrchr (tmp,'/')) && !s[1]))))
+    sprintf (tmp,newname ?
+	     "Can't rename mailbox %.80s to %.80s: invalid name" :
+	     "Can't delete mailbox %.80s: invalid name",
+	     old,newname);
+				/* lock out other c-clients */
+  else if ((ld = lockname (lock,file,LOCK_EX|LOCK_NB,&i)) < 0)
+    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
+
+  else {
+    if ((fd = mmdf_lock (file,O_RDWR,
+			 (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
+			 &lockx,LOCK_EX)) < 0)
+       sprintf (tmp,"Can't lock mailbox %.80s: %s",old,strerror (errno));
+    else {
+      if (newname) {		/* want rename? */
+				/* found superior to destination name? */
+	if (s = strrchr (s,'/')) {
+	  c = *++s;		/* remember first character of inferior */
+	  *s = '\0';		/* tie off to get just superior */
+				/* name doesn't exist, create it */
+	  if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+	      !dummy_create_path (stream,tmp,get_dir_protection (newname))) {
+	    mmdf_unlock (fd,NIL,&lockx);
+	    mmdf_unlock (ld,NIL,NIL);
+	    unlink (lock);
+	    MM_NOCRITICAL (stream);
+	    return ret;		/* return success or failure */
+	  }
+	  *s = c;		/* restore full name */
+	}
+	if (rename (file,tmp))
+	  sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
+		   strerror (errno));
+	else ret = T;		/* set success */
+      }
+      else if (unlink (file))
+	sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
+      else ret = T;		/* set success */
+      mmdf_unlock (fd,NIL,&lockx);
+    }
+    mmdf_unlock (ld,NIL,NIL);	/* flush the lock */
+    unlink (lock);
+  }
+  MM_NOCRITICAL (stream);	/* no longer critical */
+  if (!ret) MM_LOG (tmp,ERROR);	/* log error */
+  return ret;			/* return success or failure */
+}
+
+/* MMDF mail open
+ * Accepts: Stream to open
+ * Returns: Stream on success, NIL on failure
+ */
+
+MAILSTREAM *mmdf_open (MAILSTREAM *stream)
+{
+  long i;
+  int fd;
+  char tmp[MAILTMPLEN];
+  DOTLOCK lock;
+  long retry;
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return user_flags (&mmdfproto);
+  retry = stream->silent ? 1 : KODRETRY;
+  if (stream->local) fatal ("mmdf recycle stream");
+  stream->local = memset (fs_get (sizeof (MMDFLOCAL)),0,sizeof (MMDFLOCAL));
+				/* note if an INBOX or not */
+  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
+				/* canonicalize the stream mailbox name */
+  if (!dummy_file (tmp,stream->mailbox)) {
+    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+				/* flush old name */
+  fs_give ((void **) &stream->mailbox);
+				/* save canonical name */
+  stream->mailbox = cpystr (tmp);
+  LOCAL->fd = LOCAL->ld = -1;	/* no file or state locking yet */
+  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
+  LOCAL->buflen = CHUNKSIZE - 1;
+  LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE);
+  LOCAL->text.size = CHUNKSIZE - 1;
+  LOCAL->linebuf = (char *) fs_get (CHUNKSIZE);
+  LOCAL->linebuflen = CHUNKSIZE - 1;
+  stream->sequence++;		/* bump sequence number */
+
+				/* make lock for read/write access */
+  if (!stream->rdonly) while (retry) {
+				/* try to lock file */
+    if ((fd = lockname (tmp,stream->mailbox,LOCK_EX|LOCK_NB,&i)) < 0) {
+				/* suppressing kiss-of-death? */
+      if (stream->nokod) retry = 0;
+				/* no, first time through? */
+      else if (retry-- == KODRETRY) {
+				/* learned other guy's PID and can signal? */
+	if (i && !kill ((int) i,SIGUSR2)) {
+	  sprintf (tmp,"Trying to get mailbox lock from process %ld",i);
+	  MM_LOG (tmp,WARN);
+	}
+	else retry = 0;		/* give up */
+      }
+      if (!stream->silent) {	/* nothing if silent stream */
+	if (retry) sleep (1);	/* wait a second before trying again */
+	else MM_LOG ("Mailbox is open by another process, access is readonly",
+		     WARN);
+      }
+    }
+    else {			/* got the lock, nobody else can alter state */
+      LOCAL->ld = fd;		/* note lock's fd and name */
+      LOCAL->lname = cpystr (tmp);
+				/* make sure mode OK (don't use fchmod()) */
+      chmod (LOCAL->lname,(long) mail_parameters (NIL,GET_LOCKPROTECTION,NIL));
+      if (stream->silent) i = 0;/* silent streams won't accept KOD */
+      else {			/* note our PID in the lock */
+	sprintf (tmp,"%d",getpid ());
+	write (fd,tmp,(i = strlen (tmp))+1);
+      }
+      ftruncate (fd,i);		/* make sure tied off */
+      fsync (fd);		/* make sure it's available */
+      retry = 0;		/* no more need to try */
+    }
+  }
+
+				/* parse mailbox */
+  stream->nmsgs = stream->recent = 0;
+				/* will we be able to get write access? */
+  if ((LOCAL->ld >= 0) && access (stream->mailbox,W_OK) && (errno == EACCES)) {
+    MM_LOG ("Can't get write access to mailbox, access is readonly",WARN);
+    flock (LOCAL->ld,LOCK_UN);	/* release the lock */
+    close (LOCAL->ld);		/* close the lock file */
+    LOCAL->ld = -1;		/* no more lock fd */
+    unlink (LOCAL->lname);	/* delete it */
+  }
+				/* reset UID validity */
+  stream->uid_validity = stream->uid_last = 0;
+  if (stream->silent && !stream->rdonly && (LOCAL->ld < 0))
+    mmdf_abort (stream);	/* abort if can't get RW silent stream */
+				/* parse mailbox */
+  else if (mmdf_parse (stream,&lock,LOCK_SH)) {
+    mmdf_unlock (LOCAL->fd,stream,&lock);
+    mail_unlock (stream);
+    MM_NOCRITICAL (stream);	/* done with critical */
+  }
+  if (!LOCAL) return NIL;	/* failure if stream died */
+				/* make sure upper level knows readonly */
+  stream->rdonly = (LOCAL->ld < 0);
+				/* notify about empty mailbox */
+  if (!(stream->nmsgs || stream->silent)) MM_LOG ("Mailbox is empty",NIL);
+  if (!stream->rdonly) {	/* flags stick if readwrite */
+    stream->perm_seen = stream->perm_deleted =
+      stream->perm_flagged = stream->perm_answered = stream->perm_draft = T;
+    if (!stream->uid_nosticky) {/* users with lives get permanent keywords */
+      stream->perm_user_flags = 0xffffffff;
+				/* and maybe can create them too! */
+      stream->kwd_create = stream->user_flags[NUSERFLAGS-1] ? NIL : T;
+    }
+  }
+  return stream;		/* return stream alive to caller */
+}
+
+
+/* MMDF mail close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void mmdf_close (MAILSTREAM *stream,long options)
+{
+  int silent = stream->silent;
+  stream->silent = T;		/* go silent */
+				/* expunge if requested */
+  if (options & CL_EXPUNGE) mmdf_expunge (stream,NIL,NIL);
+				/* else dump final checkpoint */
+  else if (LOCAL->dirty) mmdf_check (stream);
+  stream->silent = silent;	/* restore old silence state */
+  mmdf_abort (stream);		/* now punt the file and local data */
+}
+
+/* MMDF mail fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+				/* lines to filter from header */
+static STRINGLIST *mmdf_hlines = NIL;
+
+char *mmdf_header (MAILSTREAM *stream,unsigned long msgno,
+		   unsigned long *length,long flags)
+{
+  MESSAGECACHE *elt;
+  unsigned char *s,*t,*tl;
+  *length = 0;			/* default to empty */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+  elt = mail_elt (stream,msgno);/* get cache */
+  if (!mmdf_hlines) {		/* once only code */
+    STRINGLIST *lines = mmdf_hlines = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "Status"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-Status"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-Keywords"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-UID"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-IMAP"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-IMAPbase"));
+  }
+				/* go to header position */
+  lseek (LOCAL->fd,elt->private.special.offset +
+	 elt->private.msg.header.offset,L_SET);
+
+  if (flags & FT_INTERNAL) {	/* initial data OK? */
+    if (elt->private.msg.header.text.size > LOCAL->buflen) {
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
+				     elt->private.msg.header.text.size) + 1);
+    }
+				/* read message */
+    read (LOCAL->fd,LOCAL->buf,elt->private.msg.header.text.size);
+				/* got text, tie off string */
+    LOCAL->buf[*length = elt->private.msg.header.text.size] = '\0';
+				/* squeeze out CRs (in case from PC) */
+    for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++)
+      if (*t != '\r') *s++ = *t;
+    *s = '\0';
+    *length = s - LOCAL->buf;	/* adjust length */
+  }
+  else {			/* need to make a CRLF version */
+    read (LOCAL->fd,s = (char *) fs_get (elt->private.msg.header.text.size+1),
+	  elt->private.msg.header.text.size);
+				/* tie off string, and convert to CRLF */
+    s[elt->private.msg.header.text.size] = '\0';
+    *length = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen,s,
+			  elt->private.msg.header.text.size);
+    fs_give ((void **) &s);	/* free readin buffer */
+				/* squeeze out spurious CRs */
+    for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++)
+      if ((*t != '\r') || (t[1] == '\n')) *s++ = *t;
+    *s = '\0';
+    *length = s - LOCAL->buf;	/* adjust length */
+  }
+  *length = mail_filter (LOCAL->buf,*length,mmdf_hlines,FT_NOT);
+  return (char *) LOCAL->buf;	/* return processed copy */
+}
+
+/* MMDF mail fetch message text
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned stringstruct
+ *	    option flags
+ * Returns: T on success, NIL if failure
+ */
+
+long mmdf_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  char *s;
+  unsigned long i;
+  MESSAGECACHE *elt;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+  elt = mail_elt (stream,msgno);/* get cache element */
+				/* if message not seen */
+  if (!(flags & FT_PEEK) && !elt->seen) {
+				/* mark message seen and dirty */
+    elt->seen = elt->private.dirty = LOCAL->dirty = T;
+    MM_FLAGS (stream,msgno);
+  }
+  s = mmdf_text_work (stream,elt,&i,flags);
+  INIT (bs,mail_string,s,i);	/* set up stringstruct */
+  return T;			/* success */
+}
+
+/* MMDF mail fetch message text worker routine
+ * Accepts: MAIL stream
+ *	    message cache element
+ *	    pointer to returned header text length
+ *	    option flags
+ */
+
+char *mmdf_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
+		      unsigned long *length,long flags)
+{
+  FDDATA d;
+  STRING bs;
+  unsigned char c,*s,*t,*tl,tmp[CHUNKSIZE];
+				/* go to text position */
+  lseek (LOCAL->fd,elt->private.special.offset +
+	 elt->private.msg.text.offset,L_SET);
+  if (flags & FT_INTERNAL) {	/* initial data OK? */
+    if (elt->private.msg.text.text.size > LOCAL->buflen) {
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
+				     elt->private.msg.text.text.size) + 1);
+    }
+				/* read message */
+    read (LOCAL->fd,LOCAL->buf,elt->private.msg.text.text.size);
+				/* got text, tie off string */
+    LOCAL->buf[*length = elt->private.msg.text.text.size] = '\0';
+				/* squeeze out CRs (in case from PC) */
+    for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++)
+      if (*t != '\r') *s++ = *t;
+    *s = '\0';
+    *length = s - LOCAL->buf;	/* adjust length */
+    return (char *) LOCAL->buf;
+  }
+
+				/* have it cached already? */
+  if (elt->private.uid != LOCAL->uid) {
+				/* not cached, cache it now */
+    LOCAL->uid = elt->private.uid;
+				/* is buffer big enough? */
+    if (elt->rfc822_size > LOCAL->text.size) {
+      /* excessively conservative, but the right thing is too hard to do */
+      fs_give ((void **) &LOCAL->text.data);
+      LOCAL->text.data = (unsigned char *)
+	fs_get ((LOCAL->text.size = elt->rfc822_size) + 1);
+    }
+    d.fd = LOCAL->fd;		/* yes, set up file descriptor */
+    d.pos = elt->private.special.offset + elt->private.msg.text.offset;
+    d.chunk = tmp;		/* initial buffer chunk */
+    d.chunksize = CHUNKSIZE;	/* file chunk size */
+    INIT (&bs,fd_string,&d,elt->private.msg.text.text.size);
+    for (s = (char *) LOCAL->text.data; SIZE (&bs);) switch (c = SNX (&bs)) {
+    case '\r':			/* carriage return seen */
+      break;
+    case '\n':
+      *s++ = '\r';		/* insert a CR */
+    default:
+      *s++ = c;			/* copy characters */
+    }
+    *s = '\0';			/* tie off buffer */
+				/* calculate length of cached data */
+    LOCAL->textlen = s - LOCAL->text.data;
+  }
+  *length = LOCAL->textlen;	/* return from cache */
+  return (char *) LOCAL->text.data;
+}
+
+/* MMDF per-message modify flag
+ * Accepts: MAIL stream
+ *	    message cache element
+ */
+
+void mmdf_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+				/* only after finishing */
+  if (elt->valid) elt->private.dirty = LOCAL->dirty = T;
+}
+
+
+/* MMDF mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ */
+
+long mmdf_ping (MAILSTREAM *stream)
+{
+  DOTLOCK lock;
+  struct stat sbuf;
+  long reparse;
+				/* big no-op if not readwrite */
+  if (LOCAL && (LOCAL->ld >= 0) && !stream->lock) {
+    if (stream->rdonly) {	/* does he want to give up readwrite? */
+				/* checkpoint if we changed something */
+      if (LOCAL->dirty) mmdf_check (stream);
+      flock (LOCAL->ld,LOCK_UN);/* release readwrite lock */
+      close (LOCAL->ld);	/* close the readwrite lock file */
+      LOCAL->ld = -1;		/* no more readwrite lock fd */
+      unlink (LOCAL->lname);	/* delete the readwrite lock file */
+    }
+    else {			/* see if need to reparse */
+      if (!(reparse = (long) mail_parameters (NIL,GET_NETFSSTATBUG,NIL))) {
+				/* get current mailbox size */
+	if (LOCAL->fd >= 0) fstat (LOCAL->fd,&sbuf);
+	else if (stat (stream->mailbox,&sbuf)) {
+	  sprintf (LOCAL->buf,"Mailbox stat failed, aborted: %s",
+		   strerror (errno));
+	  MM_LOG (LOCAL->buf,ERROR);
+	  mmdf_abort (stream);
+	  return NIL;
+	}
+	reparse = (sbuf.st_size != LOCAL->filesize);
+      }
+				/* parse if mailbox changed */
+      if ((LOCAL->ddirty || reparse) && mmdf_parse (stream,&lock,LOCK_EX)) {
+				/* force checkpoint if double-dirty */
+	if (LOCAL->ddirty) mmdf_rewrite (stream,NIL,&lock,NIL);
+				/* unlock mailbox */
+	else mmdf_unlock (LOCAL->fd,stream,&lock);
+	mail_unlock (stream);	/* and stream */
+				/* done with critical */
+	MM_NOCRITICAL (stream);
+      }
+    }
+  }
+  return LOCAL ? LONGT : NIL;	/* return if still alive */
+}
+
+/* MMDF mail check mailbox
+ * Accepts: MAIL stream
+ */
+
+void mmdf_check (MAILSTREAM *stream)
+{
+  DOTLOCK lock;
+				/* parse and lock mailbox */
+  if (LOCAL && (LOCAL->ld >= 0) && !stream->lock &&
+      mmdf_parse (stream,&lock,LOCK_EX)) {
+				/* any unsaved changes? */
+    if (LOCAL->dirty && mmdf_rewrite (stream,NIL,&lock,NIL)) {
+      if (!stream->silent) MM_LOG ("Checkpoint completed",NIL);
+    }
+				/* no checkpoint needed, just unlock */
+    else mmdf_unlock (LOCAL->fd,stream,&lock);
+    mail_unlock (stream);	/* unlock the stream */
+    MM_NOCRITICAL (stream);	/* done with critical */
+  }
+}
+
+
+/* MMDF mail expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long mmdf_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  long ret;
+  unsigned long i;
+  DOTLOCK lock;
+  char *msg = NIL;
+  if (ret = (sequence ? ((options & EX_UID) ?
+			 mail_uid_sequence (stream,sequence) :
+			 mail_sequence (stream,sequence)) : LONGT) &&
+      LOCAL && (LOCAL->ld >= 0) && !stream->lock &&
+      mmdf_parse (stream,&lock,LOCK_EX)) {
+				/* check expunged messages if not dirty */
+    for (i = 1; !LOCAL->dirty && (i <= stream->nmsgs); i++) {
+      MESSAGECACHE *elt = mail_elt (stream,i);
+      if (mail_elt (stream,i)->deleted) LOCAL->dirty = T;
+    }
+    if (!LOCAL->dirty) {	/* not dirty and no expunged messages */
+      mmdf_unlock (LOCAL->fd,stream,&lock);
+      msg = "No messages deleted, so no update needed";
+    }
+    else if (mmdf_rewrite (stream,&i,&lock,sequence ? LONGT : NIL)) {
+      if (i) sprintf (msg = LOCAL->buf,"Expunged %lu messages",i);
+      else msg = "Mailbox checkpointed, but no messages expunged";
+    }
+				/* rewrite failed */
+    else mmdf_unlock (LOCAL->fd,stream,&lock);
+    mail_unlock (stream);	/* unlock the stream */
+    MM_NOCRITICAL (stream);	/* done with critical */
+    if (msg && !stream->silent) MM_LOG (msg,NIL);
+  }
+  else if (!stream->silent)
+    MM_LOG ("Expunge ignored on readonly mailbox",WARN);
+  return ret;
+}
+
+/* MMDF mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if copy successful, else NIL
+ */
+
+long mmdf_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  struct stat sbuf;
+  int fd;
+  char *s,file[MAILTMPLEN];
+  DOTLOCK lock;
+  time_t tp[2];
+  unsigned long i,j;
+  MESSAGECACHE *elt;
+  long ret = T;
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+  copyuid_t cu = (copyuid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ?
+			      NIL : mail_parameters (NIL,GET_COPYUID,NIL));
+  SEARCHSET *source = cu ? mail_newsearchset () : NIL;
+  SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
+  MAILSTREAM *tstream = NIL;
+  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+	mail_sequence (stream,sequence))) return NIL;
+				/* make sure destination is valid */
+  if (!(mmdf_valid (mailbox) || !errno))
+    switch (errno) {
+    case ENOENT:		/* no such file? */
+      if (compare_cstring (mailbox,"INBOX")) {
+	MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
+	return NIL;
+      }
+      if (pc) return (*pc) (stream,sequence,mailbox,options);
+      mmdf_create (NIL,"INBOX");/* create empty INBOX */
+    case EACCES:		/* file protected */
+      sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
+      MM_LOG (LOCAL->buf,ERROR);
+      return NIL;
+    case EINVAL:
+      if (pc) return (*pc) (stream,sequence,mailbox,options);
+      sprintf (LOCAL->buf,"Invalid MMDF-format mailbox name: %.80s",mailbox);
+      MM_LOG (LOCAL->buf,ERROR);
+      return NIL;
+    default:
+      if (pc) return (*pc) (stream,sequence,mailbox,options);
+      sprintf (LOCAL->buf,"Not a MMDF-format mailbox: %.80s",mailbox);
+      MM_LOG (LOCAL->buf,ERROR);
+      return NIL;
+    }
+
+				/* try to open rewrite for UIDPLUS */
+  if ((tstream = mail_open_work (&mmdfdriver,NIL,mailbox,
+				 OP_SILENT|OP_NOKOD)) && tstream->rdonly)
+    tstream = mail_close (tstream);
+  if (cu && !tstream) {		/* wanted a COPYUID? */
+    sprintf (LOCAL->buf,"Unable to write-open mailbox for COPYUID: %.80s",
+	     mailbox);
+    MM_LOG (LOCAL->buf,WARN);
+    cu = NIL;			/* don't try to do COPYUID */
+  }
+  LOCAL->buf[0] = '\0';
+  MM_CRITICAL (stream);		/* go critical */
+  if ((fd = mmdf_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND,
+		       (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
+		       &lock,LOCK_EX)) < 0) {
+    MM_NOCRITICAL (stream);	/* done with critical */
+    sprintf (LOCAL->buf,"Can't open destination mailbox: %s",strerror (errno));
+    MM_LOG (LOCAL->buf,ERROR);	/* log the error */
+    return NIL;			/* failed */
+  }
+  fstat (fd,&sbuf);		/* get current file size */
+				/* write all requested messages to mailbox */
+  for (i = 1; ret && (i <= stream->nmsgs); i++)
+    if ((elt = mail_elt (stream,i))->sequence) {
+      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
+      read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size);
+      if (write (fd,LOCAL->buf,elt->private.special.text.size) < 0) ret = NIL;
+      else {			/* internal header succeeded */
+	s = mmdf_header (stream,i,&j,FT_INTERNAL);
+				/* header size, sans trailing newline */
+	if (j && (s[j - 2] == '\n')) j--;
+	if (write (fd,s,j) < 0) ret = NIL;
+	else {			/* message header succeeded */
+	  j = tstream ?		/* write UIDPLUS data if have readwrite */
+	    mmdf_xstatus (stream,LOCAL->buf,elt,++(tstream->uid_last),LONGT) :
+	    mmdf_xstatus (stream,LOCAL->buf,elt,NIL,NIL);
+	  if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
+	  else {		/* message status succeeded */
+	    s = mmdf_text_work (stream,elt,&j,FT_INTERNAL);
+	    if ((write (fd,s,j) < 0) || (write (fd,mmdfhdr,MMDFHDRLEN) < 0))
+	      ret = NIL;
+	    else if (cu) {	/* need to pass back new UID? */
+	      mail_append_set (source,mail_uid (stream,i));
+	      mail_append_set (dest,tstream->uid_last);
+	    }
+	  }
+	}
+      }
+    }
+
+  if (!ret || fsync (fd)) {	/* force out the update */
+    sprintf (LOCAL->buf,"Message copy failed: %s",strerror (errno));
+    ftruncate (fd,sbuf.st_size);
+    ret = NIL;
+  }
+				/* force UIDVALIDITY assignment now */
+  if (tstream && !tstream->uid_validity) tstream->uid_validity = time (0);
+				/* return sets if doing COPYUID */
+  if (cu && ret) (*cu) (stream,mailbox,tstream->uid_validity,source,dest);
+  else {			/* flush any sets we may have built */
+    mail_free_searchset (&source);
+    mail_free_searchset (&dest);
+  }
+  tp[1] = time (0);		/* set mtime to now */
+  if (ret) tp[0] = tp[1] - 1;	/* set atime to now-1 if successful copy */
+  else tp[0] =			/* else preserve \Marked status */
+	 ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ?
+	 sbuf.st_atime : tp[1];
+  utime (file,tp);		/* set the times */
+  mmdf_unlock (fd,NIL,&lock);	/* unlock and close mailbox */
+  if (tstream) {		/* update last UID if we can */
+    MMDFLOCAL *local = (MMDFLOCAL *) tstream->local;
+    local->dirty = T;		/* do a rewrite */
+    local->appending = T;	/* but not at the cost of marking as old */
+    tstream = mail_close (tstream);
+  }
+				/* log the error */
+  if (!ret) MM_LOG (LOCAL->buf,ERROR);
+				/* delete if requested message */
+  else if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++)
+    if ((elt = mail_elt (stream,i))->sequence)
+      elt->deleted = elt->private.dirty = LOCAL->dirty = T;
+  MM_NOCRITICAL (stream);	/* release critical */
+  return ret;
+}
+
+/* MMDF mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+#define BUFLEN 8*MAILTMPLEN
+
+long mmdf_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct stat sbuf;
+  int fd;
+  unsigned long i;
+  char *flags,*date,buf[BUFLEN],tmp[MAILTMPLEN],file[MAILTMPLEN];
+  time_t tp[2];
+  FILE *sf,*df;
+  MESSAGECACHE elt;
+  DOTLOCK lock;
+  STRING *message;
+  unsigned long uidlocation = 0;
+  appenduid_t au = (appenduid_t)
+    (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL :
+     mail_parameters (NIL,GET_APPENDUID,NIL));
+  SEARCHSET *dst = au ? mail_newsearchset () : NIL;
+  long ret = LONGT;
+  MAILSTREAM *tstream = NIL;
+				/* default stream to prototype */
+  if (!stream) {		/* stream specified? */
+    stream = &mmdfproto;	/* no, default stream to prototype */
+    for (i = 0; i < NUSERFLAGS && stream->user_flags[i]; ++i)
+      fs_give ((void **) &stream->user_flags[i]);
+  }
+  if (!mmdf_valid (mailbox)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    if (compare_cstring (mailbox,"INBOX")) {
+      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+      return NIL;
+    }
+    mmdf_create (NIL,"INBOX");	/* create empty INBOX */
+  case 0:			/* merely empty file? */
+    tstream = stream;
+    break;
+  case EACCES:			/* file protected */
+    sprintf (tmp,"Can't access destination: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  case EINVAL:
+    sprintf (tmp,"Invalid MMDF-format mailbox name: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  default:
+    sprintf (tmp,"Not a MMDF-format mailbox: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+				/* get sniffing stream for keywords */
+  else if (!(tstream = mail_open (NIL,mailbox,
+				  OP_READONLY|OP_SILENT|OP_NOKOD|OP_SNIFF))) {
+    sprintf (tmp,"Unable to examine mailbox for APPEND: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+
+				/* get first message */
+  if (!MM_APPEND (af) (tstream,data,&flags,&date,&message)) return NIL;
+  if (!(sf = tmpfile ())) {	/* must have scratch file */
+    sprintf (tmp,".%lx.%lx",(unsigned long) time (0),(unsigned long)getpid ());
+    if (!stat (tmp,&sbuf) || !(sf = fopen (tmp,"wb+"))) {
+      sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno));
+      MM_LOG (tmp,ERROR);
+      return NIL;
+    }
+    unlink (tmp);
+  }
+  do {				/* parse date */
+    if (!date) rfc822_date (date = tmp);
+    if (!mail_parse_date (&elt,date)) {
+      sprintf (tmp,"Bad date in append: %.80s",date);
+      MM_LOG (tmp,ERROR);
+    }
+    else {			/* user wants to suppress time zones? */
+      if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) {
+	time_t when = mail_longdate (&elt);
+	date = ctime (&when);	/* use traditional date */
+      }
+				/* use POSIX-style date */
+      else date = mail_cdate (tmp,&elt);
+      if (!SIZE (message)) MM_LOG ("Append of zero-length message",ERROR);
+      else if (!mmdf_collect_msg (tstream,sf,flags,date,message)) {
+	sprintf (tmp,"Error writing scratch file: %.80s",strerror (errno));
+	MM_LOG (tmp,ERROR);
+      }
+				/* get next message */
+      else if (MM_APPEND (af) (tstream,data,&flags,&date,&message)) continue;
+    }
+    fclose (sf);		/* punt scratch file */
+    return NIL;			/* give up */
+  } while (message);		/* until no more messages */
+  if (fflush (sf)) {
+    sprintf (tmp,"Error finishing scratch file: %.80s",strerror (errno));
+    MM_LOG (tmp,ERROR);
+    fclose (sf);		/* punt scratch file */
+    return NIL;			/* give up */
+  }
+  i = ftell (sf);		/* size of scratch file */
+  if (tstream != stream) tstream = mail_close (tstream);
+
+  MM_CRITICAL (stream);		/* go critical */
+				/* try to open readwrite for UIDPLUS */
+  if ((tstream = mail_open_work (&mmdfdriver,NIL,mailbox,
+				 OP_SILENT|OP_NOKOD)) && tstream->rdonly)
+    tstream = mail_close (tstream);
+  if (au && !tstream) {		/* wanted an APPENDUID? */
+    sprintf (tmp,"Unable to re-open mailbox for APPENDUID: %.80s",mailbox);
+    MM_LOG (tmp,WARN);
+    au = NIL;
+  }
+  if (((fd = mmdf_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND,
+			(long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
+			&lock,LOCK_EX)) < 0) ||
+      !(df = fdopen (fd,"ab"))) {
+    MM_NOCRITICAL (stream);	/* done with critical */
+    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+  fstat (fd,&sbuf);		/* get current file size */
+  rewind (sf);
+  tp[1] = time (0);		/* set mtime to now */
+				/* write all messages */
+  if (!mmdf_append_msgs (tstream,sf,df,au ? dst : NIL) ||
+      (fflush (df) == EOF) || fsync (fd)) {
+    sprintf (buf,"Message append failed: %s",strerror (errno));
+    MM_LOG (buf,ERROR);
+    ftruncate (fd,sbuf.st_size);
+    tp[0] =			/* preserve \Marked status */
+      ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ?
+      sbuf.st_atime : tp[1];
+    ret = NIL;			/* return error */
+  }
+  else tp[0] = tp[1] - 1;	/* set atime to now-1 if successful copy */
+  utime (file,tp);		/* set the times */
+  fclose (sf);			/* done with scratch file */
+				/* force UIDVALIDITY assignment now */
+  if (tstream && !tstream->uid_validity) tstream->uid_validity = time (0);
+				/* return sets if doing APPENDUID */
+  if (au && ret) (*au) (mailbox,tstream->uid_validity,dst);
+  else mail_free_searchset (&dst);
+  mmdf_unlock (fd,NIL,&lock);	/* unlock and close mailbox */
+  fclose (df);
+  if (tstream) {		/* update last UID if we can */
+    MMDFLOCAL *local = (MMDFLOCAL *) tstream->local;
+    local->dirty = T;		/* do a rewrite */
+    local->appending = T;	/* but not at the cost of marking as old */
+    tstream = mail_close (tstream);
+  }
+  MM_NOCRITICAL (stream);	/* release critical */
+  return ret;
+}
+
+/* Collect and write single message to append scratch file
+ * Accepts: MAIL stream
+ *	    scratch file
+ *	    flags
+ *	    date
+ *	    message stringstruct
+ * Returns: NIL if write error, else T
+ */
+
+int mmdf_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
+  		     STRING *msg)
+{
+  unsigned char *s,*t;
+  unsigned long uf;
+  long f = mail_parse_flags (stream,flags,&uf);
+				/* write metadata, note date ends with NL */
+  if (fprintf (sf,"%ld %lu %s",f,SIZE (msg) + 1,date) < 0) return NIL;
+  while (uf)			/* write user flags */    
+    if ((s = stream->user_flags[find_rightmost_bit (&uf)]) &&
+	(fprintf (sf," %s",s) < 0)) return NIL;
+  if (putc ('\n',sf) == EOF) return NIL;
+  while (SIZE (msg)) {		/* copy text to scratch file */
+    for (s = (unsigned char *) msg->curpos, t = s + msg->cursize; s < t; ++s)
+      if (!*s) *s = 0x80;	/* disallow NUL */
+				/* write buffered text */
+    if (fwrite (msg->curpos,1,msg->cursize,sf) == msg->cursize)
+      SETPOS (msg,GETPOS (msg) + msg->cursize);
+    else return NIL;		/* failed */
+  }
+				/* write trailing newline and return */
+  return (putc ('\n',sf) == EOF) ? NIL : T;
+}
+
+/* Append messages from scratch file to mailbox
+ * Accepts: MAIL stream
+ *	    source file
+ *	    destination file
+ *	    uidset to update if non-NIL
+ * Returns: T if success, NIL if failure
+ */
+
+int mmdf_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set)
+{
+  int c;
+  long f;
+  unsigned long i,j;
+  char *x,tmp[MAILTMPLEN];
+  int hdrp = T;
+				/* get message metadata line */
+  while (fgets (tmp,MAILTMPLEN,sf)) {
+    if (!(isdigit (tmp[0]) && strchr (tmp,'\n'))) return NIL;
+    f = strtol (tmp,&x,10);	/* get flags */
+    if (!((*x++ == ' ') && isdigit (*x))) return NIL;
+    i = strtoul (x,&x,10);	/* get message size */
+    if ((*x++ != ' ') ||	/* build initial header */
+	(fprintf (df,"%sFrom %s@%s %sStatus: ",mmdfhdr,myusername(),
+		  mylocalhost(),x) < 0) ||
+	(f&fSEEN && (putc ('R',df) == EOF)) ||
+	(fputs ("\nX-Status: ",df) == EOF) ||
+	(f&fDELETED && (putc ('D',df) == EOF)) ||
+	(f&fFLAGGED && (putc ('F',df) == EOF)) ||
+	(f&fANSWERED && (putc ('A',df) == EOF)) ||
+	(f&fDRAFT && (putc ('T',df) == EOF)) ||
+	(fputs ("\nX-Keywords:",df) == EOF)) return NIL;
+				/* copy keywords */
+    while ((c = getc (sf)) != '\n') switch (c) {
+    case EOF:
+      return NIL;
+    default:
+      if (putc (c,df) == EOF) return NIL;
+    }
+    if ((putc ('\n',df) == EOF) ||
+	(set && (fprintf (df,"X-UID: %lu\n",++(stream->uid_last)) < 0)))
+      return NIL;
+
+    for (c = '\n'; i && fgets (tmp,MAILTMPLEN,sf); c = tmp[j-1]) {
+				/* get read line length */
+      if (i < (j = strlen (tmp))) fatal ("mmdf_append_msgs overrun");
+      i -= j;			/* number of bytes left */
+				/* squish out ^A and CRs (note copies NUL) */
+      for (x = tmp; x = strpbrk (x,"\01\r"); --j) memmove (x,x+1,j-(x-tmp));
+      if (!j) continue;		/* do nothing if line emptied */
+				/* start of line? */
+      if ((c == '\n')) switch (tmp[0]) {
+      case 'S': case 's':	/* possible "Status:" */
+	if (hdrp && (j > 6) && ((tmp[1] == 't') || (tmp[1] == 'T')) &&
+	    ((tmp[2] == 'a') || (tmp[2] == 'A')) &&
+	    ((tmp[3] == 't') || (tmp[3] == 'T')) &&
+	    ((tmp[4] == 'u') || (tmp[4] == 'U')) &&
+	    ((tmp[5] == 's') || (tmp[5] == 'S')) && (tmp[6] == ':') &&
+	    (fputs ("X-Original-",df) == EOF)) return NIL;
+	break;
+      case 'X': case 'x':	/* possible X-??? header */
+	if (hdrp && (tmp[1] == '-') &&
+				/* possible X-UID: */
+	    (((j > 5) && ((tmp[2] == 'U') || (tmp[2] == 'u')) &&
+	      ((tmp[3] == 'I') || (tmp[3] == 'i')) &&
+	      ((tmp[4] == 'D') || (tmp[4] == 'd')) && (tmp[5] == ':')) ||
+				/* possible X-IMAP: */
+	     ((j > 6) && ((tmp[2] == 'I') || (tmp[2] == 'i')) &&
+	      ((tmp[3] == 'M') || (tmp[3] == 'm')) &&
+	      ((tmp[4] == 'A') || (tmp[4] == 'a')) &&
+	      ((tmp[5] == 'P') || (tmp[5] == 'p')) &&
+	      ((tmp[6] == ':') ||
+				/* or X-IMAPbase: */
+	       ((j > 10) && ((tmp[6] == 'b') || (tmp[6] == 'B')) &&
+		((tmp[7] == 'a') || (tmp[7] == 'A')) &&
+		((tmp[8] == 's') || (tmp[8] == 'S')) &&
+		((tmp[9] == 'e') || (tmp[9] == 'E')) && (tmp[10] == ':')))) ||
+				/* possible X-Status: */
+	     ((j > 8) && ((tmp[2] == 'S') || (tmp[2] == 's')) &&
+	      ((tmp[3] == 't') || (tmp[3] == 'T')) &&
+	      ((tmp[4] == 'a') || (tmp[4] == 'A')) &&
+	      ((tmp[5] == 't') || (tmp[5] == 'T')) &&
+	      ((tmp[6] == 'u') || (tmp[6] == 'U')) &&
+	      ((tmp[7] == 's') || (tmp[7] == 'S')) && (tmp[8] == ':')) ||
+				/* possible X-Keywords: */
+	     ((j > 10) && ((tmp[2] == 'K') || (tmp[2] == 'k')) &&
+	      ((tmp[3] == 'e') || (tmp[3] == 'E')) &&
+	      ((tmp[4] == 'y') || (tmp[4] == 'Y')) &&
+	      ((tmp[5] == 'w') || (tmp[5] == 'W')) &&
+	      ((tmp[6] == 'o') || (tmp[6] == 'O')) &&
+	      ((tmp[7] == 'r') || (tmp[7] == 'R')) &&
+	      ((tmp[8] == 'd') || (tmp[8] == 'D')) &&
+	      ((tmp[9] == 's') || (tmp[9] == 'S')) && (tmp[10] == ':'))) &&
+	    (fputs ("X-Original-",df) == EOF)) return NIL;
+	break;
+      case '\n':		/* blank line */
+	hdrp = NIL;
+	break;
+      default:			/* nothing to do */
+	break;
+      }
+				/* just write the line */
+      if (fwrite (tmp,1,j,df) != j) return NIL;
+    }
+				/* make sure read entire msg & wrote trailer */
+    if (i || (fputs (mmdfhdr,df) == EOF)) return NIL;
+				/* update set */
+    if (stream) mail_append_set (set,stream->uid_last);
+  }
+  return T;
+}
+
+/* Internal routines */
+
+
+/* MMDF mail abort stream
+ * Accepts: MAIL stream
+ */
+
+void mmdf_abort (MAILSTREAM *stream)
+{
+  if (LOCAL) {			/* only if a file is open */
+    if (LOCAL->fd >= 0) close (LOCAL->fd);
+    if (LOCAL->ld >= 0) {	/* have a mailbox lock? */
+      flock (LOCAL->ld,LOCK_UN);/* yes, release the lock */
+      close (LOCAL->ld);	/* close the lock file */
+      unlink (LOCAL->lname);	/* and delete it */
+    }
+    if (LOCAL->lname) fs_give ((void **) &LOCAL->lname);
+				/* free local text buffers */
+    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+    if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data);
+    if (LOCAL->linebuf) fs_give ((void **) &LOCAL->linebuf);
+    if (LOCAL->line) fs_give ((void **) &LOCAL->line);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+/* MMDF open and lock mailbox
+ * Accepts: file name to open/lock
+ *	    file open mode
+ *	    destination buffer for lock file name
+ *	    type of locking operation (LOCK_SH or LOCK_EX)
+ */
+
+int mmdf_lock (char *file,int flags,int mode,DOTLOCK *lock,int op)
+{
+  int fd;
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  (*bn) (BLOCK_FILELOCK,NIL);
+				/* try locking the easy way */
+  if (dotlock_lock (file,lock,-1)) {
+				/* got dotlock file, easy open */
+    if ((fd = open (file,flags,mode)) >= 0) flock (fd,op);
+    else dotlock_unlock (lock);	/* open failed, free the dotlock */
+  }
+				/* no dot lock file, open file now */
+  else if ((fd = open (file,flags,mode)) >= 0) {
+				/* try paranoid way to make a dot lock file */
+    if (dotlock_lock (file,lock,fd)) {
+      close (fd);		/* get fresh fd in case of timing race */
+      if ((fd = open (file,flags,mode)) >= 0) flock (fd,op);
+				/* open failed, free the dotlock */
+      else dotlock_unlock (lock);
+    }
+    else flock (fd,op);		/* paranoid way failed, just flock() it */
+  }
+  (*bn) (BLOCK_NONE,NIL);
+  return fd;
+}
+
+/* MMDF unlock and close mailbox
+ * Accepts: file descriptor
+ *	    (optional) mailbox stream to check atime/mtime
+ *	    (optional) lock file name
+ */
+
+void mmdf_unlock (int fd,MAILSTREAM *stream,DOTLOCK *lock)
+{
+  if (stream) {			/* need to muck with times? */
+    struct stat sbuf;
+    time_t tp[2];
+    time_t now = time (0);
+    fstat (fd,&sbuf);		/* get file times */
+    if (LOCAL->ld >= 0) {	/* yes, readwrite session? */
+      tp[0] = now;		/* set atime to now */
+				/* set mtime to (now - 1) if necessary */
+      tp[1] = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1;
+    }
+    else if (stream->recent) {	/* readonly with recent messages */
+      if ((sbuf.st_atime >= sbuf.st_mtime) ||
+	  (sbuf.st_atime >= sbuf.st_ctime))
+				/* keep past mtime, whack back atime */
+	tp[0] = (tp[1] = (sbuf.st_mtime < now) ? sbuf.st_mtime : now) - 1;
+      else now = 0;		/* no time change needed */
+    }
+				/* readonly with no recent messages */
+    else if ((sbuf.st_atime < sbuf.st_mtime) ||
+	     (sbuf.st_atime < sbuf.st_ctime)) {
+      tp[0] = now;		/* set atime to now */
+				/* set mtime to (now - 1) if necessary */
+      tp[1] = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1;
+    }
+    else now = 0;		/* no time change needed */
+				/* set the times, note change */
+    if (now && !utime (stream->mailbox,tp)) LOCAL->filetime = tp[1];
+  }
+  flock (fd,LOCK_UN);		/* release flock'ers */
+  if (!stream) close (fd);	/* close the file if no stream */
+  dotlock_unlock (lock);	/* flush the lock file if any */
+}
+
+/* MMDF mail parse and lock mailbox
+ * Accepts: MAIL stream
+ *	    space to write lock file name
+ *	    type of locking operation
+ * Returns: T if parse OK, critical & mailbox is locked shared; NIL if failure
+ */
+
+int mmdf_parse (MAILSTREAM *stream,DOTLOCK *lock,int op)
+{
+  int ti,zn,m;
+  unsigned long i,j,k;
+  unsigned char c,*s,*t,*u,tmp[MAILTMPLEN],date[30];
+  int retain = T;
+  unsigned long nmsgs = stream->nmsgs;
+  unsigned long prevuid = nmsgs ? mail_elt (stream,nmsgs)->private.uid : 0;
+  unsigned long recent = stream->recent;
+  unsigned long oldnmsgs = stream->nmsgs;
+  short silent = stream->silent;
+  short pseudoseen = NIL;
+  struct stat sbuf;
+  STRING bs;
+  FDDATA d;
+  MESSAGECACHE *elt;
+  mail_lock (stream);		/* guard against recursion or pingers */
+				/* toss out previous descriptor */
+  if (LOCAL->fd >= 0) close (LOCAL->fd);
+  MM_CRITICAL (stream);		/* open and lock mailbox (shared OK) */
+  if ((LOCAL->fd = mmdf_lock (stream->mailbox,(LOCAL->ld >= 0) ?
+			      O_RDWR : O_RDONLY,
+			      (long)mail_parameters(NIL,GET_MBXPROTECTION,NIL),
+			      lock,op)) < 0) {
+    sprintf (tmp,"Mailbox open failed, aborted: %s",strerror (errno));
+    MM_LOG (tmp,ERROR);
+    mmdf_abort (stream);
+    mail_unlock (stream);
+    MM_NOCRITICAL (stream);	/* done with critical */
+    return NIL;
+  }
+  fstat (LOCAL->fd,&sbuf);	/* get status */
+				/* validate change in size */
+  if (sbuf.st_size < LOCAL->filesize) {
+    sprintf (tmp,"Mailbox shrank from %lu to %lu bytes, aborted",
+	     (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
+    MM_LOG (tmp,ERROR);		/* this is pretty bad */
+    mmdf_unlock (LOCAL->fd,stream,lock);
+    mmdf_abort (stream);
+    mail_unlock (stream);
+    MM_NOCRITICAL (stream);	/* done with critical */
+    return NIL;
+  }
+
+				/* new data? */
+  else if (i = sbuf.st_size - LOCAL->filesize) {
+    d.fd = LOCAL->fd;		/* yes, set up file descriptor */
+    d.pos = LOCAL->filesize;	/* get to that position in the file */
+    d.chunk = LOCAL->buf;	/* initial buffer chunk */
+    d.chunksize = CHUNKSIZE;	/* file chunk size */
+    INIT (&bs,fd_string,&d,i);	/* initialize stringstruct */
+				/* skip leading whitespace for broken MTAs */
+    while (((c = CHR (&bs)) == '\n') || (c == '\r') ||
+	   (c == ' ') || (c == '\t')) SNX (&bs);
+    if (SIZE (&bs)) {		/* read new data */
+				/* remember internal header position */
+      j = LOCAL->filesize + GETPOS (&bs);
+      s = mmdf_mbxline (stream,&bs,&i);
+      stream->silent = T;	/* quell main program new message events */
+      do {			/* read MMDF header */
+	if (!(i && ISMMDF (s))){/* see if valid MMDF header */
+	  sprintf (tmp,"Unexpected changes to mailbox (try restarting): %.20s",
+		   (char *) s);
+				/* see if we can back up to a line */
+	  if (i && (j > MMDFHDRLEN)) {
+	    SETPOS (&bs,j -= MMDFHDRLEN);
+				/* read previous line */
+	    s = mmdf_mbxline (stream,&bs,&i);
+				/* kill the error if it looks good */
+	    if (i && ISMMDF (s)) tmp[0] = '\0';
+	  }
+	  if (tmp[0]) {
+	    MM_LOG (tmp,ERROR);
+	    mmdf_unlock (LOCAL->fd,stream,lock);
+	    mmdf_abort (stream);
+	    mail_unlock (stream);
+	    MM_NOCRITICAL (stream);
+	    return NIL;
+	  }
+	}
+				/* instantiate first new message */
+	mail_exists (stream,++nmsgs);
+	(elt = mail_elt (stream,nmsgs))->valid = T;
+	recent++;		/* assume recent by default */
+	elt->recent = T;
+				/* note position/size of internal header */
+	elt->private.special.offset = j;
+	elt->private.special.text.size = i;
+
+	s = mmdf_mbxline (stream,&bs,&i);
+	ti = 0;			/* assume not a valid date */
+	zn = 0,t = NIL;
+	if (i) VALID (s,t,ti,zn);
+	if (ti) {		/* generate plausible IMAPish date string */
+				/* this is also part of header */
+	  elt->private.special.text.size += i;
+	  date[2] = date[6] = date[20] = '-'; date[11] = ' ';
+	  date[14] = date[17] = ':';
+				/* dd */
+	  date[0] = t[ti - 2]; date[1] = t[ti - 1];
+				/* mmm */
+	  date[3] = t[ti - 6]; date[4] = t[ti - 5]; date[5] = t[ti - 4];
+				/* hh */
+	  date[12] = t[ti + 1]; date[13] = t[ti + 2];
+				/* mm */
+	  date[15] = t[ti + 4]; date[16] = t[ti + 5];
+	  if (t[ti += 6]==':'){	/* ss */
+	    date[18] = t[++ti]; date[19] = t[++ti];
+	    ti++;		/* move to space */
+	  }
+	  else date[18] = date[19] = '0';
+				/* yy -- advance over timezone if necessary */
+	  if (zn == ti) ti += (((t[zn+1] == '+') || (t[zn+1] == '-')) ? 6 : 4);
+	  date[7] = t[ti + 1]; date[8] = t[ti + 2];
+	  date[9] = t[ti + 3]; date[10] = t[ti + 4];
+				/* zzz */
+	  t = zn ? (t + zn + 1) : (unsigned char *) "LCL";
+	  date[21] = *t++; date[22] = *t++; date[23] = *t++;
+	  if ((date[21] != '+') && (date[21] != '-')) date[24] = '\0';
+	  else {		/* numeric time zone */
+	    date[24] = *t++; date[25] = *t++;
+	    date[26] = '\0'; date[20] = ' ';
+	  }
+				/* set internal date */
+	  if (!mail_parse_date (elt,date)) {
+	    sprintf (tmp,"Unable to parse internal date: %s",(char *) date);
+	    MM_LOG (tmp,WARN);
+	  }
+	}
+	else {			/* make date from file date */
+	  struct tm *tm = gmtime (&sbuf.st_mtime);
+	  elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1;
+	  elt->year = tm->tm_year + 1900 - BASEYEAR;
+	  elt->hours = tm->tm_hour; elt->minutes = tm->tm_min;
+	  elt->seconds = tm->tm_sec;
+	  elt->zhours = 0; elt->zminutes = 0;
+	  t = NIL;		/* suppress line read */
+	}
+				/* header starts here */
+	elt->private.msg.header.offset = elt->private.special.text.size;
+
+	do {			/* look for message body */
+	  j = GETPOS (&bs);	/* note position before line */
+	  if (t) s = t = mmdf_mbxline (stream,&bs,&i);
+	  else t = s;		/* this line read was suppressed */
+	  if (ISMMDF (s)) {	/* found terminator in header? */
+	    SETPOS (&bs,j);	/* oops, back up before line */
+				/* must insert a newline */
+	    elt->private.spare.data++;
+	    break;		/* punt */
+	  }
+				/* this line is part of header */
+	  elt->private.msg.header.text.size += i;
+	  if (i) switch (*s) {	/* check header lines */
+	  case 'X':		/* possible X-???: line */
+	    if (s[1] == '-') {	/* must be immediately followed by hyphen */
+				/* X-Status: becomes Status: in S case */
+	      if (s[2] == 'S' && s[3] == 't' && s[4] == 'a' && s[5] == 't' &&
+		  s[6] == 'u' && s[7] == 's' && s[8] == ':') s += 2;
+				/* possible X-Keywords */
+	      else if (s[2] == 'K' && s[3] == 'e' && s[4] == 'y' &&
+		       s[5] == 'w' && s[6] == 'o' && s[7] == 'r' &&
+		       s[8] == 'd' && s[9] == 's' && s[10] == ':') {
+		SIZEDTEXT uf;
+		retain = NIL;	/* don't retain continuation */
+		s += 11;	/* flush leading whitespace */
+		while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n'))){
+		  while (*s == ' ') s++;
+				/* find end of keyword */
+		  if (!(u = strpbrk (s," \n\r"))) u = s + strlen (s);
+				/* got a keyword? */
+		  if ((k = (u - s)) && (k <= MAXUSERFLAG)) {
+		    uf.data = (unsigned char *) s;
+		    uf.size = k;
+		    for (j = 0; (j < NUSERFLAGS) && stream->user_flags[j]; ++j)
+		      if (!compare_csizedtext (stream->user_flags[j],&uf)) {
+			elt->user_flags |= ((long) 1) << j;
+			break;
+		      }
+		  }
+		  s = u;	/* advance to next keyword */
+		}
+		break;
+	      }
+
+				/* possible X-IMAP */
+	      else if ((s[2] == 'I') && (s[3] == 'M') && (s[4] == 'A') &&
+		       (s[5] == 'P') && ((m = (s[6] == ':')) ||
+					 ((s[6] == 'b') && (s[7] == 'a') &&
+					  (s[8] == 's') && (s[9] == 'e') &&
+					  (s[10] == ':')))) {
+		retain = NIL;	/* don't retain continuation */
+		if ((nmsgs == 1) && !stream->uid_validity) {
+				/* advance to data */
+		  s += m ? 7 : 11;
+				/* flush whitespace */
+		  while (*s == ' ') s++;
+		  j = 0;	/* slurp UID validity */
+				/* found a digit? */
+		  while (isdigit (*s)) {
+		    j *= 10;	/* yes, add it in */
+		    j += *s++ - '0';
+		  }
+				/* flush whitespace */
+		  while (*s == ' ') s++;
+				/* must have valid UID validity and UID last */
+		  if (j && isdigit (*s)) {
+				/* pseudo-header seen if X-IMAP */
+		    if (m) pseudoseen = LOCAL->pseudo = T;
+				/* save UID validity */
+		    stream->uid_validity = j;
+		    j = 0;	/* slurp UID last */
+		    while (isdigit (*s)) {
+		      j *= 10;	/* yes, add it in */
+		      j += *s++ - '0';
+		    }
+				/* save UID last */
+		    stream->uid_last = j;
+				/* process keywords */
+		    for (j = 0; (*s != '\n') && ((*s != '\r')||(s[1] != '\n'));
+			 s = u,j++) {
+				/* flush leading whitespace */
+		      while (*s == ' ') s++;
+		      u = strpbrk (s," \n\r");
+				/* got a keyword? */
+		      if ((j < NUSERFLAGS) && (k = (u - s)) &&
+			  (k <= MAXUSERFLAG)) {
+			if (stream->user_flags[j])
+			  fs_give ((void **) &stream->user_flags[j]);
+			stream->user_flags[j] = (char *) fs_get (k + 1);
+			strncpy (stream->user_flags[j],s,k);
+			stream->user_flags[j][k] = '\0';
+		      }
+		    }
+		  }
+		}
+		break;
+	      }
+
+				/* possible X-UID */
+	      else if (s[2] == 'U' && s[3] == 'I' && s[4] == 'D' &&
+		       s[5] == ':') {
+		retain = NIL;	/* don't retain continuation */
+				/* only believe if have a UID validity */
+		if (stream->uid_validity && ((nmsgs > 1) || !pseudoseen)) {
+		  s += 6;	/* advance to UID value */
+				/* flush whitespace */
+		  while (*s == ' ') s++;
+		  j = 0;
+				/* found a digit? */
+		  while (isdigit (*s)) {
+		    j *= 10;	/* yes, add it in */
+		    j += *s++ - '0';
+		  }
+				/* flush remainder of line */
+		  while (*s != '\n') s++;
+				/* make sure not duplicated */
+		  if (elt->private.uid)
+		    sprintf (tmp,"Message %lu UID %lu already has UID %lu",
+			     pseudoseen ? elt->msgno - 1 : elt->msgno,
+			     j,elt->private.uid);
+				/* make sure UID doesn't go backwards */
+		  else if (j <= prevuid)
+		    sprintf (tmp,"Message %lu UID %lu less than %lu",
+			     pseudoseen ? elt->msgno - 1 : elt->msgno,
+			     j,prevuid + 1);
+#if 0	/* this is currently broken by UIDPLUS */
+				/* or skip by mailbox's recorded last */
+		  else if (j > stream->uid_last)
+		    sprintf (tmp,"Message %lu UID %lu greater than last %lu",
+			     pseudoseen ? elt->msgno - 1 : elt->msgno,
+			     j,stream->uid_last);
+#endif
+		  else {	/* normal UID case */
+		    prevuid = elt->private.uid = j;
+#if 1	/* temporary kludge for UIDPLUS */
+		    if (prevuid > stream->uid_last) {
+		      stream->uid_last = prevuid;
+		      LOCAL->ddirty = LOCAL->dirty = T;
+		    }		    
+#endif
+		    break;	/* exit this cruft */
+		  }
+		  MM_LOG (tmp,WARN);
+				/* invalidate UID validity */
+		  stream->uid_validity = 0;
+		  elt->private.uid = 0;
+		}
+		break;
+	      }
+	    }
+				/* otherwise fall into S case */
+
+	  case 'S':		/* possible Status: line */
+	    if (s[0] == 'S' && s[1] == 't' && s[2] == 'a' && s[3] == 't' &&
+		s[4] == 'u' && s[5] == 's' && s[6] == ':') {
+	      retain = NIL;	/* don't retain continuation */
+	      s += 6;		/* advance to status flags */
+	      do switch (*s++) {/* parse flags */
+	      case 'R':		/* message read */
+		elt->seen = T;
+		break;
+	      case 'O':		/* message old */
+		if (elt->recent) {
+		  elt->recent = NIL;
+		  recent--;	/* it really wasn't recent */
+		}
+		break;
+	      case 'D':		/* message deleted */
+		elt->deleted = T;
+		break;
+	      case 'F':		/* message flagged */
+		elt->flagged = T;
+		break;
+	      case 'A':		/* message answered */
+		elt->answered = T;
+		break;
+	      case 'T':		/* message is a draft */
+		elt->draft = T;
+		break;
+	      default:		/* some other crap */
+		break;
+	      } while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n')));
+	      break;		/* all done */
+	    }
+				/* otherwise fall into default case */
+
+	  default:		/* ordinary header line */
+	    if ((*s == 'S') || (*s == 's') ||
+		(((*s == 'X') || (*s == 'x')) && (s[1] == '-'))) {
+	      unsigned char *e,*v;
+				/* must match what mail_filter() does */
+	      for (u = s,v = tmp,e = u + min (i,MAILTMPLEN - 1);
+		   (u < e) && ((c = (*u ? *u : (*u = ' '))) != ':') &&
+		   ((c > ' ') || ((c != ' ') && (c != '\t') &&
+				  (c != '\r') && (c != '\n')));
+		   *v++ = *u++);
+	      *v = '\0';	/* tie off */
+				/* matches internal header? */
+	      if (!compare_cstring (tmp,"STATUS") ||
+		  !compare_cstring (tmp,"X-STATUS") ||
+		  !compare_cstring (tmp,"X-KEYWORDS") ||
+		  !compare_cstring (tmp,"X-UID") ||
+		  !compare_cstring (tmp,"X-IMAP") ||
+		  !compare_cstring (tmp,"X-IMAPBASE")) {
+		char err[MAILTMPLEN];
+		sprintf (err,"Discarding bogus %s header in message %lu",
+			 (char *) tmp,elt->msgno);
+		MM_LOG (err,WARN);
+		retain = NIL;	/* don't retain continuation */
+		break;		/* different case or something */
+	      }
+	    }
+				/* retain or non-continuation? */
+	    if (retain || ((*s != ' ') && (*s != '\t'))) {
+	      retain = T;	/* retaining continuation now */
+				/* line length in LF format newline */
+	      for (j = k = 0; j < i; ++j) if (s[j] != '\r') ++k;
+				/* "internal" header size */
+	      elt->private.spare.data += k;
+				/* message size */
+	      elt->rfc822_size += k + 1;
+	    }
+	    else {
+	      char err[MAILTMPLEN];
+	      sprintf (err,"Discarding bogus continuation in msg %lu: %.80s",
+		      elt->msgno,(char *) s);
+	      if (u = strpbrk (err,"\r\n")) *u = '\0';
+	      MM_LOG (err,WARN);
+	      break;		/* different case or something */
+	    }
+	    break;
+	  }
+	} while (i && (*t != '\n') && ((*t != '\r') || (t[1] != '\n')));
+				/* "internal" header sans trailing newline */
+	if (i) elt->private.spare.data--;
+				/* assign a UID if none found */
+	if (((nmsgs > 1) || !pseudoseen) && !elt->private.uid) {
+	  prevuid = elt->private.uid = ++stream->uid_last;
+	  elt->private.dirty = T;
+	}
+	else elt->private.dirty = elt->recent;
+
+				/* note size of header, location of text */
+	elt->private.msg.header.text.size =
+	  (elt->private.msg.text.offset =
+	   (LOCAL->filesize + GETPOS (&bs)) - elt->private.special.offset) -
+	     elt->private.special.text.size;
+				/* note current position */
+	j = LOCAL->filesize + GETPOS (&bs);
+	if (i) do {		/* look for next message */
+	  s = mmdf_mbxline (stream,&bs,&i);
+	  if (i) {		/* got new data? */
+	    if (ISMMDF (s)) break;
+	    else {		/* not a header line, add it to message */
+	      elt->rfc822_size += i;
+	      for (j = 0; j < i; ++j) switch (s[j]) {
+	      case '\r':	/* squeeze out CRs */
+		elt->rfc822_size -= 1;
+		break;
+	      case '\n':	/* LF becomes CRLF */
+		elt->rfc822_size += 1;
+		break;
+	      default:
+		break;
+	      }
+				/* update current position */
+	      j = LOCAL->filesize + GETPOS (&bs);
+	    }
+	  }
+	} while (i);		/* until found a header */
+	elt->private.msg.text.text.size = j -
+	  (elt->private.special.offset + elt->private.msg.text.offset);
+	if (i) {		/* get next header line */
+				/* remember first internal header position */
+	  j = LOCAL->filesize + GETPOS (&bs);
+	  s = mmdf_mbxline (stream,&bs,&i);
+	}
+				/* until end of buffer */
+      } while (!stream->sniff && i);
+      if (pseudoseen) {		/* flush pseudo-message if present */
+				/* decrement recent count */
+	if (mail_elt (stream,1)->recent) recent--;
+				/* and the exists count */
+	mail_exists (stream,nmsgs--);
+	mail_expunged(stream,1);/* fake an expunge of that message */
+      }
+				/* need to start a new UID validity? */
+      if (!stream->uid_validity) {
+	stream->uid_validity = time (0);
+				/* in case a whiner with no life */
+	if (mail_parameters (NIL,GET_USERHASNOLIFE,NIL))
+	  stream->uid_nosticky = T;
+	else if (nmsgs) {	/* don't bother if empty file */
+				/* make dirty to restart UID epoch */
+	  LOCAL->ddirty = LOCAL->dirty = T;
+				/* need to rewrite msg 1 if not pseudo */
+	  if (!LOCAL->pseudo) mail_elt (stream,1)->private.dirty = T;
+	  MM_LOG ("Assigning new unique identifiers to all messages",NIL);
+	}
+      }
+      stream->nmsgs = oldnmsgs;	/* whack it back down */
+      stream->silent = silent;	/* restore old silent setting */
+				/* notify upper level of new mailbox sizes */
+      mail_exists (stream,nmsgs);
+      mail_recent (stream,recent);
+				/* mark dirty so O flags are set */
+      if (recent) LOCAL->dirty = T;
+    }
+  }
+				/* no change, don't babble if never got time */
+  else if (LOCAL->filetime && LOCAL->filetime != sbuf.st_mtime)
+    MM_LOG ("New mailbox modification time but apparently no changes",WARN);
+				/* update parsed file size and time */
+  LOCAL->filesize = sbuf.st_size;
+  LOCAL->filetime = sbuf.st_mtime;
+  return T;			/* return the winnage */
+}
+
+/* MMDF read line from mailbox
+ * Accepts: mail stream
+ *	    stringstruct
+ *	    pointer to line size
+ * Returns: pointer to input line
+ */
+
+char *mmdf_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size)
+{
+  unsigned long i,j,k,m;
+  char *s,*t,*te;
+  char *ret = "";
+				/* flush old buffer */
+  if (LOCAL->line) fs_give ((void **) &LOCAL->line);
+				/* if buffer needs refreshing */
+  if (!bs->cursize) SETPOS (bs,GETPOS (bs));
+  if (SIZE (bs)) {		/* find newline */
+				/* end of fast scan */
+    te = (t = (s = bs->curpos) + bs->cursize) - 12;
+    while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) {
+      --s;			/* back up */
+      break;			/* exit loop */
+    }
+				/* final character-at-a-time scan */
+    while ((s < t) && (*s != '\n')) ++s;
+				/* difficult case if line spans buffer */
+    if ((i = s - bs->curpos) == bs->cursize) {
+				/* have space in line buffer? */
+      if (i > LOCAL->linebuflen) {
+	fs_give ((void **) &LOCAL->linebuf);
+	LOCAL->linebuf = (char *) fs_get (LOCAL->linebuflen = i);
+      }
+				/* remember what we have so far */
+      memcpy (LOCAL->linebuf,bs->curpos,i);
+				/* load next buffer */
+      SETPOS (bs,k = GETPOS (bs) + i);
+				/* end of fast scan */
+      te = (t = (s = bs->curpos) + bs->cursize) - 12;
+				/* fast scan in overlap buffer */
+      while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) {
+	--s;			/* back up */
+	break;			/* exit loop */
+      }
+
+				/* final character-at-a-time scan */
+      while ((s < t) && (*s != '\n')) ++s;
+				/* huge line? */
+      if ((j = s - bs->curpos) == bs->cursize) {
+	SETPOS (bs,GETPOS (bs) + j);
+				/* look for end of line (s-l-o-w!!) */
+	for (m = SIZE (bs); m && (SNX (bs) != '\n'); --m,++j);
+	SETPOS (bs,k);		/* go back to where it started */
+      }
+				/* got size of data, make buffer for return */
+      ret = LOCAL->line = (char *) fs_get (i + j + 2);
+				/* copy first chunk */
+      memcpy (ret,LOCAL->linebuf,i);
+      while (j) {		/* copy remainder */
+	if (!bs->cursize) SETPOS (bs,GETPOS (bs));
+	memcpy (ret + i,bs->curpos,k = min (j,bs->cursize));
+	i += k;			/* account for this much read in */
+	j -= k;
+	bs->curpos += k;	/* increment new position */
+	bs->cursize -= k;	/* eat that many bytes */
+      }
+				/* read newline at end */
+      if (SIZE (bs)) ret[i++] = SNX (bs);
+      ret[i] = '\0';		/* makes debugging easier */
+    }
+    else {			/* this is easy */
+      ret = bs->curpos;		/* string it at this position */
+      bs->curpos += ++i;	/* increment new position */
+      bs->cursize -= i;		/* eat that many bytes */
+    }
+    *size = i;			/* return that to user */
+  }
+  else *size = 0;		/* end of data, return empty */
+				/* embedded MMDF header at end of line? */
+  if ((*size > sizeof (MMDFHDRTXT)) &&
+      (s = ret + *size - (i = sizeof (MMDFHDRTXT) - 1)) && ISMMDF (s)) {
+    SETPOS (bs,GETPOS (bs) - i);/* back up to start of MMDF header */
+    *size -= i;			/* reduce length of line */
+    ret[*size - 1] = '\n';	/* force newline at end */
+  }
+  return ret;
+}
+
+/* MMDF make pseudo-header
+ * Accepts: MAIL stream
+ *	    buffer to write pseudo-header
+ * Returns: length of pseudo-header
+ */
+
+unsigned long mmdf_pseudo (MAILSTREAM *stream,char *hdr)
+{
+  int i;
+  char *s,tmp[MAILTMPLEN];
+  time_t now = time (0);
+  rfc822_fixed_date (tmp);
+  sprintf (hdr,"%sFrom %s %.24s\nDate: %s\nFrom: %s <%s@%.80s>\nSubject: %s\nMessage-ID: <%lu@%.80s>\nX-IMAP: %010lu %010lu",
+	   mmdfhdr,pseudo_from,ctime (&now),
+	   tmp,pseudo_name,pseudo_from,mylocalhost (),pseudo_subject,
+	   (unsigned long) now,mylocalhost (),stream->uid_validity,
+	   stream->uid_last);
+  for (s = hdr + strlen (hdr),i = 0; i < NUSERFLAGS; ++i)
+    if (stream->user_flags[i])
+      sprintf (s += strlen (s)," %s",stream->user_flags[i]);
+  sprintf (s += strlen (s),"\nStatus: RO\n\n%s\n%s",pseudo_msg,mmdfhdr);
+  return strlen (hdr);
+}
+
+/* MMDF make status string
+ * Accepts: MAIL stream
+ *	    destination string to write
+ *	    message cache entry
+ *	    UID to write if non-zero (else use elt->private.uid)
+ *	    non-zero flag to write UID (.LT. 0 to write UID base info too)
+ * Returns: length of string
+ */
+
+unsigned long mmdf_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt,
+			    unsigned long uid,long flag)
+{
+  char *t,stack[64];
+  char *s = status;
+  unsigned long n;
+  int pad = 50;
+  int sticky = uid ? T : !stream->uid_nosticky;
+  /* This used to use sprintf(), but thanks to certain cretinous C libraries
+     with horribly slow implementations of sprintf() I had to change it to this
+     mess.  At least it should be fast. */
+  if ((flag < 0) && sticky) {	/* need to write X-IMAPbase: header? */
+    *s++ = 'X'; *s++ = '-'; *s++ = 'I'; *s++ = 'M'; *s++ = 'A'; *s++ = 'P';
+    *s++ = 'b'; *s++ = 'a'; *s++ = 's'; *s++ = 'e'; *s++ = ':'; *s++ = ' ';
+    t = stack;
+    n = stream->uid_validity;	/* push UID validity digits on the stack */
+    do *t++ = (char) (n % 10) + '0';
+    while (n /= 10);
+				/* pop UID validity digits from stack */
+    while (t > stack) *s++ = *--t;
+   *s++ = ' ';
+    n = stream->uid_last;	/* push UID last digits on the stack */
+    do *t++ = (char) (n % 10) + '0';
+    while (n /= 10);
+				/* pop UID last digits from stack */
+    while (t > stack) *s++ = *--t;
+    for (n = 0; n < NUSERFLAGS; ++n) if (t = stream->user_flags[n])
+      for (*s++ = ' '; *t; *s++ = *t++);
+    *s++ = '\n';
+    pad += 30;			/* increased padding if have IMAPbase */
+  }
+  *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't'; *s++ = 'u'; *s++ = 's';
+  *s++ = ':'; *s++ = ' ';
+  if (elt->seen) *s++ = 'R';
+				/* only write O if have a UID */
+  if (flag && (!elt->recent || !LOCAL->appending)) *s++ = 'O';
+  *s++ = '\n';
+  *s++ = 'X'; *s++ = '-'; *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't';
+  *s++ = 'u'; *s++ = 's'; *s++ = ':'; *s++ = ' ';
+  if (elt->deleted) *s++ = 'D';
+  if (elt->flagged) *s++ = 'F';
+  if (elt->answered) *s++ = 'A';
+  if (elt->draft) *s++ = 'T';
+    *s++ = '\n';
+
+  if (sticky) {			/* only do this if UIDs sticky */
+    *s++ = 'X'; *s++ = '-'; *s++ = 'K'; *s++ = 'e'; *s++ = 'y'; *s++ = 'w';
+    *s++ = 'o'; *s++ = 'r'; *s++ = 'd'; *s++ = 's'; *s++ = ':';
+    if (n = elt->user_flags) do {
+      *s++ = ' ';
+      for (t = stream->user_flags[find_rightmost_bit (&n)]; *t; *s++ = *t++);
+    } while (n);
+    n = s - status;		/* get size of stuff so far */
+				/* pad X-Keywords to make size constant */
+    if (n < pad) for (n = pad - n; n > 0; --n) *s++ = ' ';
+    *s++ = '\n';
+    if (flag) {			/* want to include UID? */
+      t = stack;
+				/* push UID digits on the stack */
+      n = uid ? uid : elt->private.uid;
+      do *t++ = (char) (n % 10) + '0';
+      while (n /= 10);
+      *s++ = 'X'; *s++ = '-'; *s++ = 'U'; *s++ = 'I'; *s++ = 'D'; *s++ = ':';
+      *s++ = ' ';
+				/* pop UID from stack */
+      while (t > stack) *s++ = *--t;
+      *s++ = '\n';
+    }
+  }
+  *s++ = '\n'; *s = '\0';	/* end of extended message status */
+  return s - status;		/* return size of resulting string */
+}
+
+/* Rewrite mailbox file
+ * Accepts: MAIL stream, must be critical and locked
+ *	    return pointer to number of expunged messages if want expunge
+ *	    lock file name
+ *	    expunge sequence, not deleted flag
+ * Returns: T if success and mailbox unlocked, NIL if failure
+ */
+
+#define OVERFLOWBUFLEN 8192	/* initial overflow buffer length */
+
+long mmdf_rewrite (MAILSTREAM *stream,unsigned long *nexp,DOTLOCK *lock,
+		   long flags)
+{
+  MESSAGECACHE *elt;
+  MMDFFILE f;
+  char *s;
+  time_t tp[2];
+  long ret,flag;
+  unsigned long i,j;
+  unsigned long recent = stream->recent;
+  unsigned long size = LOCAL->pseudo ? mmdf_pseudo (stream,LOCAL->buf) : 0;
+  if (nexp) *nexp = 0;		/* initially nothing expunged */
+				/* calculate size of mailbox after rewrite */
+  for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs; i++) {
+    elt = mail_elt (stream,i);	/* get cache */
+    if (!(nexp && elt->deleted && (flags ? elt->sequence : T))) {
+				/* add RFC822 size of this message */
+      size += elt->private.special.text.size + elt->private.spare.data +
+	mmdf_xstatus (stream,LOCAL->buf,elt,NIL,flag) +
+	  elt->private.msg.text.text.size + MMDFHDRLEN;
+      flag = 1;			/* only count X-IMAPbase once */
+    }
+  }
+				/* no messages, has a life, and no pseudo */
+  if (!size && !mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) {
+    LOCAL->pseudo = T;		/* so make a pseudo-message now */
+    size = mmdf_pseudo (stream,LOCAL->buf);
+  }
+				/* extend the file as necessary */
+  if (ret = mmdf_extend (stream,size)) {
+    /* Set up buffered I/O file structure
+     * curpos	current position being written through buffering
+     * filepos	current position being written physically to the disk
+     * bufpos	current position being written in the buffer
+     * protect	current maximum position that can be written to the disk
+     *		before buffering is forced
+     * The code tries to buffer so that that disk is written in multiples of
+     * OVERBLOWBUFLEN bytes.
+     */
+    f.stream = stream;		/* note mail stream */
+    f.curpos = f.filepos = 0;	/* start of file */
+    f.protect = stream->nmsgs ?	/* initial protection pointer */
+    mail_elt (stream,1)->private.special.offset : 8192;
+    f.bufpos = f.buf = (char *) fs_get (f.buflen = OVERFLOWBUFLEN);
+
+    if (LOCAL->pseudo)		/* update pseudo-header */
+      mmdf_write (&f,LOCAL->buf,mmdf_pseudo (stream,LOCAL->buf));
+				/* loop through all messages */
+    for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs;) {
+      elt = mail_elt (stream,i);/* get cache */
+				/* expunge this message? */
+      if (nexp && elt->deleted && (flags ? elt->sequence : T)) {
+				/* one less recent message */
+	if (elt->recent) --recent;
+	mail_expunged(stream,i);/* notify upper levels */
+	++*nexp;		/* count up one more expunged message */
+      }
+      else {			/* preserve this message */
+	i++;			/* advance to next message */
+	if ((flag < 0) ||	/* need to rewrite message? */
+	    elt->private.dirty || (f.curpos != elt->private.special.offset) ||
+	    (elt->private.msg.header.text.size !=
+	     (elt->private.spare.data +
+	      mmdf_xstatus (stream,LOCAL->buf,elt,NIL,flag)))) {
+	  unsigned long newoffset = f.curpos;
+				/* yes, seek to internal header */
+	  lseek (LOCAL->fd,elt->private.special.offset,L_SET);
+	  read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size);
+				/* see if need to squeeze out a CR */
+	  if (LOCAL->buf[elt->private.special.text.size - 2] == '\r') {
+	    LOCAL->buf[--elt->private.special.text.size - 1] = '\n';
+	    --size;		/* squeezed out a CR from PC */
+	  }
+				/* protection pointer moves to RFC822 header */
+	  f.protect = elt->private.special.offset +
+	    elt->private.msg.header.offset;
+				/* write internal header */
+	  mmdf_write (&f,LOCAL->buf,elt->private.special.text.size);
+				/* get RFC822 header */
+	  s = mmdf_header (stream,elt->msgno,&j,FT_INTERNAL);
+				/* in case this got decremented */
+	  elt->private.msg.header.offset = elt->private.special.text.size;
+				/* header size, sans trailing newline */
+	  if ((j < 2) || (s[j - 2] == '\n')) j--;
+				/* this can happen if CRs were squeezed */
+	  if (j < elt->private.spare.data) {
+				/* so fix up counts */
+	    size -= elt->private.spare.data - j;
+	    elt->private.spare.data = j;
+	  }
+	  else if (j != elt->private.spare.data)
+	    fatal ("header size inconsistent");
+				/* protection pointer moves to RFC822 text */
+	  f.protect = elt->private.special.offset +
+	    elt->private.msg.text.offset;
+	  mmdf_write (&f,s,j);	/* write RFC822 header */
+				/* write status and UID */
+	  mmdf_write (&f,LOCAL->buf,
+		      j = mmdf_xstatus (stream,LOCAL->buf,elt,NIL,flag));
+	  flag = 1;		/* only write X-IMAPbase once */
+				/* new file header size */
+	  elt->private.msg.header.text.size = elt->private.spare.data + j;
+
+				/* did text move? */
+	  if (f.curpos != f.protect) {
+				/* get message text */
+	    s = mmdf_text_work (stream,elt,&j,FT_INTERNAL);
+				/* this can happen if CRs were squeezed */
+	    if (j < elt->private.msg.text.text.size) {
+				/* so fix up counts */
+	      size -= elt->private.msg.text.text.size - j;
+	      elt->private.msg.text.text.size = j;
+	    }
+				/* can't happen it says here */
+	    else if (j > elt->private.msg.text.text.size)
+	      fatal ("text size inconsistent");
+				/* new text offset, status/UID may change it */
+	    elt->private.msg.text.offset = f.curpos - newoffset;
+				/* protection pointer moves to next message */
+	    f.protect = (i <= stream->nmsgs) ?
+	      mail_elt (stream,i)->private.special.offset :
+		(f.curpos + j + MMDFHDRLEN);
+	    mmdf_write (&f,s,j);/* write text */
+				/* write trailing newline */
+	    mmdf_write (&f,mmdfhdr,MMDFHDRLEN);
+	  }
+	  else {		/* tie off header and status */
+	    mmdf_write (&f,NIL,NIL);
+	    f.curpos = f.protect =/* restart everything at end of message */
+	      f.filepos += elt->private.msg.text.text.size + MMDFHDRLEN;
+	  }
+				/* new internal header offset */
+	  elt->private.special.offset = newoffset;
+	  elt->private.dirty =NIL;/* message is now clean */
+	}
+	else {			/* no need to rewrite this message */
+				/* tie off previous message if needed */
+	  mmdf_write (&f,NIL,NIL);
+	  f.curpos = f.protect =/* restart everything at end of message */
+	    f.filepos += elt->private.special.text.size +
+	      elt->private.msg.header.text.size +
+		elt->private.msg.text.text.size + MMDFHDRLEN;
+	}
+      }
+    }
+
+    mmdf_write (&f,NIL,NIL);	/* tie off final message */
+    if (size != f.filepos) fatal ("file size inconsistent");
+    fs_give ((void **) &f.buf);	/* free buffer */
+				/* make sure tied off */
+    ftruncate (LOCAL->fd,LOCAL->filesize = size);
+    fsync (LOCAL->fd);		/* make sure the updates take */
+    if (size && (flag < 0)) fatal ("lost UID base information");
+				/* no longer dirty */
+    LOCAL->ddirty = LOCAL->dirty = NIL;
+  				/* notify upper level of new mailbox sizes */
+    mail_exists (stream,stream->nmsgs);
+    mail_recent (stream,recent);
+				/* set atime to now, mtime a second earlier */
+    tp[1] = (tp[0] = time (0)) - 1;
+				/* set the times, note change */
+    if (!utime (stream->mailbox,tp)) LOCAL->filetime = tp[1];
+    close (LOCAL->fd);		/* close and reopen file */
+    if ((LOCAL->fd = open (stream->mailbox,O_RDWR,
+			   (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL)))
+	< 0) {
+      sprintf (LOCAL->buf,"Mailbox open failed, aborted: %s",strerror (errno));
+      MM_LOG (LOCAL->buf,ERROR);
+      mmdf_abort (stream);
+    }
+    dotlock_unlock (lock);	/* flush the lock file */
+  }
+  return ret;			/* return state from algorithm */
+}
+
+/* Extend MMDF mailbox file
+ * Accepts: MAIL stream
+ *	    new desired size
+ * Return: T if success, else NIL
+ */
+
+long mmdf_extend (MAILSTREAM *stream,unsigned long size)
+{
+  unsigned long i = (size > LOCAL->filesize) ? size - LOCAL->filesize : 0;
+  if (i) {			/* does the mailbox need to grow? */
+    if (i > LOCAL->buflen) {	/* make sure have enough space */
+				/* this user won the lottery all right */
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get ((LOCAL->buflen = i) + 1);
+    }
+    memset (LOCAL->buf,'\0',i);	/* get a block of nulls */
+    while (T) {			/* until write successful or punt */
+      lseek (LOCAL->fd,LOCAL->filesize,L_SET);
+      if ((write (LOCAL->fd,LOCAL->buf,i) >= 0) && !fsync (LOCAL->fd)) break;
+      else {
+	long e = errno;		/* note error before doing ftruncate */
+	ftruncate (LOCAL->fd,LOCAL->filesize);
+	if (MM_DISKERROR (stream,e,NIL)) {
+	  fsync (LOCAL->fd);	/* user chose to punt */
+	  sprintf (LOCAL->buf,"Unable to extend mailbox: %s",strerror (e));
+	  if (!stream->silent) MM_LOG (LOCAL->buf,ERROR);
+	  return NIL;
+	}
+      }
+    }
+  }
+  return LONGT;
+}
+
+/* Write data to buffered file
+ * Accepts: buffered file pointer
+ *	    file data or NIL to indicate "flush buffer"
+ *	    date size (ignored for "flush buffer")
+ * Does not return until success
+ */
+
+void mmdf_write (MMDFFILE *f,char *buf,unsigned long size)
+{
+  unsigned long i,j,k;
+  if (buf) {			/* doing buffered write? */
+    i = f->bufpos - f->buf;	/* yes, get size of current buffer data */
+				/* yes, have space in current buffer chunk? */
+    if (j = i ? ((f->buflen - i) % OVERFLOWBUFLEN) : f->buflen) {
+				/* yes, fill up buffer as much as we can */
+      memcpy (f->bufpos,buf,k = min (j,size));
+      f->bufpos += k;		/* new buffer position */
+      f->curpos += k;		/* new current position */
+      if (j -= k) return;	/* all done if still have buffer free space */
+      buf += k;			/* full, get new unwritten data pointer */
+      size -= k;		/* new data size */
+      i += k;			/* new buffer data size */
+    }
+    /* This chunk of the buffer is full.  See if can make some space by
+     * writing to the disk, if there's enough unprotected space to do so.
+     * Try to fill out any unaligned chunk, along with any subsequent full
+     * chunks that will fit in unprotected space.
+     */
+				/* any unprotected space we can write to? */
+    if (j = min (i,f->protect - f->filepos)) {
+				/* yes, filepos not at chunk boundary? */
+      if ((k = f->filepos % OVERFLOWBUFLEN) && ((k = OVERFLOWBUFLEN - k) < j))
+	j -= k;			/* yes, and can write out partial chunk */
+      else k = 0;		/* no partial chunk to write */
+				/* if at least a chunk free, write that too */
+      if (j > OVERFLOWBUFLEN) k += j - (j % OVERFLOWBUFLEN);
+      if (k) {			/* write data if there is anything we can */
+	mmdf_phys_write (f,f->buf,k);
+				/* slide buffer */
+	if (i -= k) memmove (f->buf,f->buf + k,i);
+	f->bufpos = f->buf + i;	/* new end of buffer */
+      }
+    }
+
+    /* Have flushed the buffer as best as possible.  All done if no more
+     * data to write.  Otherwise, if the buffer is empty AND if the unwritten
+     * data is larger than a chunk AND the unprotected space is also larger
+     * than a chunk, then write as many chunks as we can directly from the
+     * data.  Buffer the rest, expanding the buffer as needed.
+     */
+    if (size) {			/* have more data that we need to buffer? */
+				/* can write any of it to disk instead? */
+      if ((f->bufpos == f->buf) && 
+	  ((j = min (f->protect - f->filepos,size)) > OVERFLOWBUFLEN)) {
+				/* write as much as we can right now */
+	mmdf_phys_write (f,buf,j -= (j % OVERFLOWBUFLEN));
+	buf += j;		/* new data pointer */
+	size -= j;		/* new data size */
+	f->curpos += j;		/* advance current pointer */
+      }
+      if (size) {		/* still have data that we need to buffer? */
+				/* yes, need to expand the buffer? */
+	if ((i = ((f->bufpos + size) - f->buf)) > f->buflen) {
+				/* note current position in buffer */
+	  j = f->bufpos - f->buf;
+	  i += OVERFLOWBUFLEN;	/* yes, grow another chunk */
+	  fs_resize ((void **) &f->buf,f->buflen = i - (i % OVERFLOWBUFLEN));
+				/* in case buffer relocated */
+	  f->bufpos = f->buf + j;
+	}
+				/* buffer remaining data */
+	memcpy (f->bufpos,buf,size);
+	f->bufpos += size;	/* new end of buffer */
+	f->curpos += size;	/* advance current pointer */
+      }
+    }
+  }
+  else {			/* flush buffer to disk */
+    mmdf_phys_write (f,f->buf,i = f->bufpos - f->buf);
+    f->bufpos = f->buf;		/* reset buffer */
+				/* update positions */
+    f->curpos = f->protect = f->filepos;
+  }
+}
+
+/* Physical disk write
+ * Accepts: buffered file pointer
+ *	    buffer address
+ *	    buffer size
+ * Does not return until success
+ */
+
+void mmdf_phys_write (MMDFFILE *f,char *buf,size_t size)
+{
+  MAILSTREAM *stream = f->stream;
+				/* write data at desired position */
+  while (size && ((lseek (LOCAL->fd,f->filepos,L_SET) < 0) ||
+		  (write (LOCAL->fd,buf,size) < 0))) {
+    int e;
+    char tmp[MAILTMPLEN];
+    sprintf (tmp,"Unable to write to mailbox: %s",strerror (e = errno));
+    MM_LOG (tmp,ERROR);
+    MM_DISKERROR (NIL,e,T);	/* serious problem, must retry */
+  }
+  f->filepos += size;		/* update file position */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/mtx.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1371 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	MTX mail routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	22 May 1990
+ * Last Edited:	11 October 2007
+ */
+
+
+/*				FILE TIME SEMANTICS
+ *
+ * The atime is the last read time of the file.
+ * The mtime is the last flags update time of the file.
+ * The ctime is the last write time of the file.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "mail.h"
+#include "osdep.h"
+#include <pwd.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "misc.h"
+#include "dummy.h"
+#include "fdstring.h"
+
+/* MTX I/O stream local data */
+	
+typedef struct mtx_local {
+  unsigned int shouldcheck: 1;	/* if ping should do a check instead */
+  unsigned int mustcheck: 1;	/* if ping must do a check instead */
+  int fd;			/* file descriptor for I/O */
+  off_t filesize;		/* file size parsed */
+  time_t filetime;		/* last file time */
+  time_t lastsnarf;		/* last snarf time */
+  unsigned char *buf;		/* temporary buffer */
+  unsigned long buflen;		/* current size of temporary buffer */
+} MTXLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((MTXLOCAL *) stream->local)
+
+
+/* Function prototypes */
+
+DRIVER *mtx_valid (char *name);
+int mtx_isvalid (char *name,char *tmp);
+void *mtx_parameters (long function,void *value);
+void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void mtx_list (MAILSTREAM *stream,char *ref,char *pat);
+void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long mtx_create (MAILSTREAM *stream,char *mailbox);
+long mtx_delete (MAILSTREAM *stream,char *mailbox);
+long mtx_rename (MAILSTREAM *stream,char *old,char *newname);
+long mtx_status (MAILSTREAM *stream,char *mbx,long flags);
+MAILSTREAM *mtx_open (MAILSTREAM *stream);
+void mtx_close (MAILSTREAM *stream,long options);
+void mtx_flags (MAILSTREAM *stream,char *sequence,long flags);
+char *mtx_header (MAILSTREAM *stream,unsigned long msgno,
+		  unsigned long *length,long flags);
+long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+void mtx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
+void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
+long mtx_ping (MAILSTREAM *stream);
+void mtx_check (MAILSTREAM *stream);
+void mtx_snarf (MAILSTREAM *stream);
+long mtx_expunge (MAILSTREAM *stream,char *sequence,long options);
+long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+char *mtx_file (char *dst,char *name);
+long mtx_parse (MAILSTREAM *stream);
+MESSAGECACHE *mtx_elt (MAILSTREAM *stream,unsigned long msgno);
+void mtx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt);
+void mtx_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag);
+unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			  unsigned long *size);
+
+/* MTX mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER mtxdriver = {
+  "mtx",			/* driver name */
+				/* driver flags */
+  DR_LOCAL|DR_MAIL|DR_CRLF|DR_NOSTICKY|DR_LOCKING,
+  (DRIVER *) NIL,		/* next driver */
+  mtx_valid,			/* mailbox is valid for us */
+  mtx_parameters,		/* manipulate parameters */
+  mtx_scan,			/* scan mailboxes */
+  mtx_list,			/* list mailboxes */
+  mtx_lsub,			/* list subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  dummy_create,			/* create mailbox */
+  mtx_delete,			/* delete mailbox */
+  mtx_rename,			/* rename mailbox */
+  mtx_status,			/* status of mailbox */
+  mtx_open,			/* open mailbox */
+  mtx_close,			/* close mailbox */
+  mtx_flags,			/* fetch message "fast" attributes */
+  mtx_flags,			/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  mtx_header,			/* fetch message header */
+  mtx_text,			/* fetch message body */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  mtx_flag,			/* modify flags */
+  mtx_flagmsg,			/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  mtx_ping,			/* ping mailbox to see if still alive */
+  mtx_check,			/* check for new messages */
+  mtx_expunge,			/* expunge deleted messages */
+  mtx_copy,			/* copy messages to another mailbox */
+  mtx_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM mtxproto = {&mtxdriver};
+
+/* MTX mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *mtx_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+  return mtx_isvalid (name,tmp) ? &mtxdriver : NIL;
+}
+
+
+/* MTX mail test for valid mailbox
+ * Accepts: mailbox name
+ * Returns: T if valid, NIL otherwise
+ */
+
+int mtx_isvalid (char *name,char *tmp)
+{
+  int fd;
+  int ret = NIL;
+  char *s,file[MAILTMPLEN];
+  struct stat sbuf;
+  time_t tp[2];
+  errno = EINVAL;		/* assume invalid argument */
+				/* if file, get its status */
+  if ((s = mtx_file (file,name)) && !stat (s,&sbuf)) {
+    if (!sbuf.st_size) {	/* allow empty file if INBOX */
+      if ((s = mailboxfile (tmp,name)) && !*s) ret = T;
+      else errno = 0;		/* empty file */
+    }
+    else if ((fd = open (file,O_RDONLY,NIL)) >= 0) {
+      memset (tmp,'\0',MAILTMPLEN);
+      if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\015')) &&
+	  (s[1] == '\012')) {	/* valid format? */
+	*s = '\0';		/* tie off header */
+				/* must begin with dd-mmm-yy" */
+	ret = (((tmp[2] == '-' && tmp[6] == '-') ||
+		(tmp[1] == '-' && tmp[5] == '-')) &&
+	       (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL;
+      }
+      else errno = -1;		/* bogus format */
+      close (fd);		/* close the file */
+				/* \Marked status? */
+      if (sbuf.st_ctime > sbuf.st_atime) {
+	tp[0] = sbuf.st_atime;	/* preserve atime and mtime */
+	tp[1] = sbuf.st_mtime;
+	utime (file,tp);	/* set the times */
+      }
+    }
+  }
+				/* in case INBOX but not mtx format */
+  else if ((errno == ENOENT) && !compare_cstring (name,"INBOX")) errno = -1;
+  return ret;			/* return what we should */
+}
+
+/* MTX manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *mtx_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case GET_INBOXPATH:
+    if (value) ret = mtx_file ((char *) value,"INBOX");
+    break;
+  }
+  return ret;
+}
+
+
+/* MTX mail scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* MTX mail list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mtx_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_list (NIL,ref,pat);
+}
+
+
+/* MTX mail list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_lsub (NIL,ref,pat);
+}
+
+/* MTX mail delete mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long mtx_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return mtx_rename (stream,mailbox,NIL);
+}
+
+
+/* MTX mail rename mailbox
+ * Accepts: MAIL stream
+ *	    old mailbox name
+ *	    new mailbox name (or NIL for delete)
+ * Returns: T on success, NIL on failure
+ */
+
+long mtx_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  long ret = T;
+  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  int fd,ld;
+  struct stat sbuf;
+  if (!mtx_file (file,old) ||
+      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
+		   ((s = strrchr (tmp,'/')) && !s[1])))) {
+    sprintf (tmp,newname ?
+	     "Can't rename mailbox %.80s to %.80s: invalid name" :
+	     "Can't delete mailbox %.80s: invalid name",
+	     old,newname);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+  else if ((fd = open (file,O_RDWR,NIL)) < 0) {
+    sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno));
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+				/* get exclusive parse/append permission */
+  if ((ld = lockfd (fd,lock,LOCK_EX)) < 0) {
+    MM_LOG ("Unable to lock rename mailbox",ERROR);
+    return NIL;
+  }
+				/* lock out other users */
+  if (flock (fd,LOCK_EX|LOCK_NB)) {
+    close (fd);			/* couldn't lock, give up on it then */
+    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
+    MM_LOG (tmp,ERROR);
+    unlockfd (ld,lock);		/* release exclusive parse/append permission */
+    return NIL;
+  }
+
+  if (newname) {		/* want rename? */
+    if (s = strrchr (tmp,'/')) {/* found superior to destination name? */
+      c = *++s;			/* remember first character of inferior */
+      *s = '\0';		/* tie off to get just superior */
+				/* name doesn't exist, create it */
+      if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+	  !dummy_create_path (stream,tmp,get_dir_protection (newname)))
+	ret = NIL;
+      else *s = c;		/* restore full name */
+    }
+				/* rename the file */
+    if (ret && rename (file,tmp)) {
+      sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
+	       strerror (errno));
+      MM_LOG (tmp,ERROR);
+      ret = NIL;		/* set failure */
+    }
+  }
+  else if (unlink (file)) {
+    sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
+    MM_LOG (tmp,ERROR);
+    ret = NIL;			/* set failure */
+  }
+  flock (fd,LOCK_UN);		/* release lock on the file */
+  close (fd);			/* close the file */
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+				/* recreate file if renamed INBOX */
+  if (ret && !compare_cstring (old,"INBOX")) dummy_create (NIL,"INBOX.MTX");
+  return ret;			/* return success */
+}
+
+/* Mtx Mail status
+ * Accepts: mail stream
+ *	    mailbox name
+ *	    status flags
+ * Returns: T on success, NIL on failure
+ */
+
+long mtx_status (MAILSTREAM *stream,char *mbx,long flags)
+{
+  MAILSTATUS status;
+  unsigned long i;
+  MAILSTREAM *tstream = NIL;
+  MAILSTREAM *systream = NIL;
+				/* make temporary stream (unless this mbx) */
+  if (!stream && !(stream = tstream =
+		   mail_open (NIL,mbx,OP_READONLY|OP_SILENT))) return NIL;
+  status.flags = flags;		/* return status values */
+  status.messages = stream->nmsgs;
+  status.recent = stream->recent;
+  if (flags & SA_UNSEEN)	/* must search to get unseen messages */
+    for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++)
+      if (!mail_elt (stream,i)->seen) status.unseen++;
+  status.uidnext = stream->uid_last + 1;
+  status.uidvalidity = stream->uid_validity;
+				/* calculate post-snarf results */
+  if (!status.recent && stream->inbox &&
+      (systream = mail_open (NIL,sysinbox (),OP_READONLY|OP_SILENT))) {
+    status.messages += systream->nmsgs;
+    status.recent += systream->recent;
+    if (flags & SA_UNSEEN)	/* must search to get unseen messages */
+      for (i = 1; i <= systream->nmsgs; i++)
+	if (!mail_elt (systream,i)->seen) status.unseen++;
+				/* kludge but probably good enough */
+    status.uidnext += systream->nmsgs;
+  }
+  MM_STATUS(stream,mbx,&status);/* pass status to main program */
+  if (tstream) mail_close (tstream);
+  if (systream) mail_close (systream);
+  return T;			/* success */
+}
+
+/* MTX mail open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *mtx_open (MAILSTREAM *stream)
+{
+  int fd,ld;
+  char tmp[MAILTMPLEN];
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return user_flags (&mtxproto);
+  if (stream->local) fatal ("mtx recycle stream");
+  user_flags (stream);		/* set up user flags */
+				/* canonicalize the mailbox name */
+  if (!mtx_file (tmp,stream->mailbox)) {
+    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
+    MM_LOG (tmp,ERROR);
+  }
+  if (stream->rdonly ||
+      (fd = open (tmp,O_RDWR,NIL)) < 0) {
+    if ((fd = open (tmp,O_RDONLY,NIL)) < 0) {
+      sprintf (tmp,"Can't open mailbox: %.80s",strerror (errno));
+      MM_LOG (tmp,ERROR);
+      return NIL;
+    }
+    else if (!stream->rdonly) {	/* got it, but readonly */
+      MM_LOG ("Can't get write access to mailbox, access is readonly",WARN);
+      stream->rdonly = T;
+    }
+  }
+  stream->local = fs_get (sizeof (MTXLOCAL));
+  LOCAL->fd = fd;		/* bind the file */
+  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
+  LOCAL->buflen = CHUNKSIZE - 1;
+				/* note if an INBOX or not */
+  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
+  fs_give ((void **) &stream->mailbox);
+  stream->mailbox = cpystr (tmp);
+				/* get shared parse permission */
+  if ((ld = lockfd (fd,tmp,LOCK_SH)) < 0) {
+    MM_LOG ("Unable to lock open mailbox",ERROR);
+    return NIL;
+  }
+  (*bn) (BLOCK_FILELOCK,NIL);
+  flock (LOCAL->fd,LOCK_SH);	/* lock the file */
+  (*bn) (BLOCK_NONE,NIL);
+  unlockfd (ld,tmp);		/* release shared parse permission */
+  LOCAL->filesize = 0;		/* initialize parsed file size */
+				/* time not set up yet */
+  LOCAL->lastsnarf = LOCAL->filetime = 0;
+  LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
+  stream->sequence++;		/* bump sequence number */
+				/* parse mailbox */
+  stream->nmsgs = stream->recent = 0;
+  if (mtx_ping (stream) && !stream->nmsgs)
+    MM_LOG ("Mailbox is empty",(long) NIL);
+  if (!LOCAL) return NIL;	/* failure if stream died */
+  stream->perm_seen = stream->perm_deleted =
+    stream->perm_flagged = stream->perm_answered = stream->perm_draft =
+      stream->rdonly ? NIL : T;
+  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
+  return stream;		/* return stream to caller */
+}
+
+/* MTX mail close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void mtx_close (MAILSTREAM *stream,long options)
+{
+  if (stream && LOCAL) {	/* only if a file is open */
+    int silent = stream->silent;
+    stream->silent = T;		/* note this stream is dying */
+    if (options & CL_EXPUNGE) mtx_expunge (stream,NIL,NIL);
+    stream->silent = silent;	/* restore previous status */
+    flock (LOCAL->fd,LOCK_UN);	/* unlock local file */
+    close (LOCAL->fd);		/* close the local file */
+				/* free local text buffer */
+    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+
+/* MTX mail fetch flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ * Sniffs at file to see if some other process changed the flags
+ */
+
+void mtx_flags (MAILSTREAM *stream,char *sequence,long flags)
+{
+  unsigned long i;
+  if (mtx_ping (stream) && 	/* ping mailbox, get new status for messages */
+      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
+       mail_sequence (stream,sequence)))
+    for (i = 1; i <= stream->nmsgs; i++) 
+      if (mail_elt (stream,i)->sequence) mtx_elt (stream,i);
+}
+
+/* MTX mail fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+char *mtx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
+		  long flags)
+{
+  *length = 0;			/* default to empty */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+				/* get to header position */
+  lseek (LOCAL->fd,mtx_hdrpos (stream,msgno,length),L_SET);
+				/* is buffer big enough? */
+  if (*length > LOCAL->buflen) {
+    fs_give ((void **) &LOCAL->buf);
+    LOCAL->buf = (char *) fs_get ((LOCAL->buflen = *length) + 1);
+  }
+  LOCAL->buf[*length] = '\0';	/* tie off string */
+				/* slurp the data */
+  read (LOCAL->fd,LOCAL->buf,*length);
+  return (char *) LOCAL->buf;
+}
+
+/* MTX mail fetch message text (body only)
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: T, always
+ */
+
+long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  FDDATA d;
+  unsigned long i,j;
+  MESSAGECACHE *elt;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+  elt = mtx_elt (stream,msgno);	/* get message status */
+				/* if message not seen */
+  if (!(flags & FT_PEEK) && !elt->seen) {
+    elt->seen = T;		/* mark message as seen */
+				/* recalculate status */
+    mtx_update_status (stream,msgno,NIL);
+    MM_FLAGS (stream,msgno);
+  }
+				/* find header position */
+  i = mtx_hdrpos (stream,msgno,&j);
+  d.fd = LOCAL->fd;		/* set up file descriptor */
+  d.pos = i + j;
+  d.chunk = LOCAL->buf;		/* initial buffer chunk */
+  d.chunksize = CHUNKSIZE;
+  INIT (bs,fd_string,&d,elt->rfc822_size - j);
+  return T;			/* success */
+}
+
+/* MTX mail modify flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    flag(s)
+ *	    option flags
+ */
+
+void mtx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
+{
+  time_t tp[2];
+  struct stat sbuf;
+  if (!stream->rdonly) {	/* make sure the update takes */
+    fsync (LOCAL->fd);
+    fstat (LOCAL->fd,&sbuf);	/* get current write time */
+    tp[1] = LOCAL->filetime = sbuf.st_mtime;
+    tp[0] = time (0);		/* make sure read comes after all that */
+    utime (stream->mailbox,tp);
+  }
+}
+
+
+/* MTX mail per-message modify flags
+ * Accepts: MAIL stream
+ *	    message cache element
+ */
+
+void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  struct stat sbuf;
+				/* maybe need to do a checkpoint? */
+  if (LOCAL->filetime && !LOCAL->shouldcheck) {
+    fstat (LOCAL->fd,&sbuf);	/* get current write time */
+    if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
+    LOCAL->filetime = 0;	/* don't do this test for any other messages */
+  }
+				/* recalculate status */
+  mtx_update_status (stream,elt->msgno,NIL);
+}
+
+/* MTX mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream still alive, NIL if not
+ */
+
+long mtx_ping (MAILSTREAM *stream)
+{
+  unsigned long i = 1;
+  long r = T;
+  int ld;
+  char lock[MAILTMPLEN];
+  struct stat sbuf;
+  if (stream && LOCAL) {	/* only if stream already open */
+    fstat (LOCAL->fd,&sbuf);	/* get current file poop */
+    if (LOCAL->filetime && !(LOCAL->mustcheck || LOCAL->shouldcheck) &&
+	(LOCAL->filetime < sbuf.st_mtime)) LOCAL->shouldcheck = T;
+				/* check for changed message status */
+    if (LOCAL->mustcheck || LOCAL->shouldcheck) {
+      LOCAL->filetime = sbuf.st_mtime;
+      if (LOCAL->shouldcheck)	/* babble when we do this unilaterally */
+	MM_NOTIFY (stream,"[CHECK] Checking for flag updates",NIL);
+      while (i <= stream->nmsgs) mtx_elt (stream,i++);
+      LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
+    }
+				/* get shared parse/append permission */
+    if ((sbuf.st_size != LOCAL->filesize) &&
+	((ld = lockfd (LOCAL->fd,lock,LOCK_SH)) >= 0)) {
+				/* parse resulting mailbox */
+      r = (mtx_parse (stream)) ? T : NIL;
+      unlockfd (ld,lock);	/* release shared parse/append permission */
+    }
+    if (LOCAL) {		/* stream must still be alive */
+				/* snarf if this is a read-write inbox */
+      if (stream->inbox && !stream->rdonly) {
+	mtx_snarf (stream);
+	fstat (LOCAL->fd,&sbuf);/* see if file changed now */
+	if ((sbuf.st_size != LOCAL->filesize) &&
+	    ((ld = lockfd (LOCAL->fd,lock,LOCK_SH)) >= 0)) {
+				/* parse resulting mailbox */
+	  r = (mtx_parse (stream)) ? T : NIL;
+	  unlockfd (ld,lock);	/* release shared parse/append permission */
+	}
+      }
+    }
+  }
+  return r;			/* return result of the parse */
+}
+
+
+/* MTX mail check mailbox (reparses status too)
+ * Accepts: MAIL stream
+ */
+
+void mtx_check (MAILSTREAM *stream)
+{
+				/* mark that a check is desired */
+  if (LOCAL) LOCAL->mustcheck = T;
+  if (mtx_ping (stream)) MM_LOG ("Check completed",(long) NIL);
+}
+
+/* MTX mail snarf messages from system inbox
+ * Accepts: MAIL stream
+ */
+
+void mtx_snarf (MAILSTREAM *stream)
+{
+  unsigned long i = 0;
+  unsigned long j,r,hdrlen,txtlen;
+  struct stat sbuf;
+  char *hdr,*txt,lock[MAILTMPLEN],tmp[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  MAILSTREAM *sysibx = NIL;
+  int ld;
+				/* give up if can't get exclusive permission */
+  if ((time (0) >= (LOCAL->lastsnarf +
+		    (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL))) &&
+      strcmp (sysinbox (),stream->mailbox) &&
+      ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) >= 0)) {
+    MM_CRITICAL (stream);	/* go critical */
+				/* sizes match and anything in sysinbox? */
+    if (!stat (sysinbox (),&sbuf) && sbuf.st_size &&
+	!fstat (LOCAL->fd,&sbuf) && (sbuf.st_size == LOCAL->filesize) && 
+	(sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) &&
+	(!sysibx->rdonly) && (r = sysibx->nmsgs)) {
+				/* yes, go to end of file in our mailbox */
+      lseek (LOCAL->fd,sbuf.st_size,L_SET);
+				/* for each message in sysibx mailbox */
+      while (r && (++i <= sysibx->nmsgs)) {
+				/* snarf message from system INBOX */
+	hdr = cpystr (mail_fetchheader_full (sysibx,i,NIL,&hdrlen,NIL));
+	txt = mail_fetchtext_full (sysibx,i,&txtlen,FT_PEEK);
+				/* if have a message */
+	if (j = hdrlen + txtlen) {
+				/* calculate header line */
+	  mail_date (LOCAL->buf,elt = mail_elt (sysibx,i));
+	  sprintf (LOCAL->buf + strlen (LOCAL->buf),
+		   ",%lu;0000000000%02o\015\012",j,(unsigned)
+		   ((fSEEN * elt->seen) + (fDELETED * elt->deleted) +
+		    (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
+		    (fDRAFT * elt->draft)));
+				/* copy message */
+	  if ((write (LOCAL->fd,LOCAL->buf,strlen (LOCAL->buf)) < 0) ||
+	      (write (LOCAL->fd,hdr,hdrlen) < 0) ||
+	      (write (LOCAL->fd,txt,txtlen) < 0)) r = 0;
+	}
+	fs_give ((void **) &hdr);
+      }
+
+				/* make sure all the updates take */
+      if (fsync (LOCAL->fd)) r = 0;
+      if (r) {			/* delete all the messages we copied */
+	if (r == 1) strcpy (tmp,"1");
+	else sprintf (tmp,"1:%lu",r);
+	mail_flag (sysibx,tmp,"\\Deleted",ST_SET);
+	mail_expunge (sysibx);	/* now expunge all those messages */
+      }
+      else {
+	sprintf (LOCAL->buf,"Can't copy new mail: %s",strerror (errno));
+	MM_LOG (LOCAL->buf,WARN);
+	ftruncate (LOCAL->fd,sbuf.st_size);
+      }
+      fstat (LOCAL->fd,&sbuf);	/* yes, get current file size */
+      LOCAL->filetime = sbuf.st_mtime;
+    }
+    if (sysibx) mail_close (sysibx);
+    MM_NOCRITICAL (stream);	/* release critical */
+    unlockfd (ld,lock);		/* release exclusive parse/append permission */
+    LOCAL->lastsnarf = time (0);/* note time of last snarf */
+  }
+}
+
+/* MTX mail expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long mtx_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  long ret;
+  time_t tp[2];
+  struct stat sbuf;
+  off_t pos = 0;
+  int ld;
+  unsigned long i = 1;
+  unsigned long j,k,m,recent;
+  unsigned long n = 0;
+  unsigned long delta = 0;
+  char lock[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  if (!(ret = (sequence ? ((options & EX_UID) ?
+			   mail_uid_sequence (stream,sequence) :
+			   mail_sequence (stream,sequence)) : LONGT) &&
+	mtx_ping (stream)));	/* parse sequence if given, ping stream */
+  else if (stream->rdonly) MM_LOG ("Expunge ignored on readonly mailbox",WARN);
+  else {
+    if (LOCAL->filetime && !LOCAL->shouldcheck) {
+      fstat (LOCAL->fd,&sbuf);	/* get current write time */
+      if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
+    }
+  /* The cretins who designed flock() created a window of vulnerability in
+   * upgrading locks from shared to exclusive or downgrading from exclusive
+   * to shared.  Rather than maintain the lock at shared status at a minimum,
+   * flock() actually *releases* the former lock.  Obviously they never talked
+   * to any database guys.  Fortunately, we have the parse/append permission
+   * lock.  If we require this lock before going exclusive on the mailbox,
+   * another process can not sneak in and steal the exclusive mailbox lock on
+   * us, because it will block on trying to get parse/append permission first.
+   */
+				/* get exclusive parse/append permission */
+    if ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) < 0)
+      MM_LOG ("Unable to lock expunge mailbox",ERROR);
+				/* make sure see any newly-arrived messages */
+    else if (!mtx_parse (stream));
+				/* get exclusive access */
+    else if (flock (LOCAL->fd,LOCK_EX|LOCK_NB)) {
+      (*bn) (BLOCK_FILELOCK,NIL);
+      flock (LOCAL->fd,LOCK_SH);/* recover previous lock */
+      (*bn) (BLOCK_NONE,NIL);
+      MM_LOG ("Can't expunge because mailbox is in use by another process",
+	      ERROR);
+      unlockfd (ld,lock);	/* release exclusive parse/append permission */
+    }
+
+    else {
+      MM_CRITICAL (stream);	/* go critical */
+      recent = stream->recent;	/* get recent now that pinged and locked */
+				/* for each message */
+      while (i <= stream->nmsgs) {
+				/* get cache element */
+	elt = mtx_elt (stream,i);
+				/* number of bytes to smash or preserve */
+	k = elt->private.special.text.size + elt->rfc822_size;
+				/* if need to expunge this message */
+	if (elt->deleted && (sequence ? elt->sequence : T)) {
+				/* if recent, note one less recent message */
+	  if (elt->recent) --recent;
+	  delta += k;		/* number of bytes to delete */
+				/* notify upper levels */
+	  mail_expunged (stream,i);
+	  n++;			/* count up one more expunged message */
+	}
+	else if (i++ && delta) {/* preserved message */
+				/* first byte to preserve */
+	  j = elt->private.special.offset;
+	  do {			/* read from source position */
+	    m = min (k,LOCAL->buflen);
+	    lseek (LOCAL->fd,j,L_SET);
+	    read (LOCAL->fd,LOCAL->buf,m);
+	    pos = j - delta;	/* write to destination position */
+	    lseek (LOCAL->fd,pos,L_SET);
+	    while (T) {
+	      lseek (LOCAL->fd,pos,L_SET);
+	      if (write (LOCAL->fd,LOCAL->buf,m) > 0) break;
+	      MM_NOTIFY (stream,strerror (errno),WARN);
+	      MM_DISKERROR (stream,errno,T);
+	    }
+	    pos += m;		/* new position */
+	    j += m;		/* next chunk, perhaps */
+	  } while (k -= m);	/* until done */
+				/* note the new address of this text */
+	  elt->private.special.offset -= delta;
+	}
+				/* preserved but no deleted messages */
+	else pos = elt->private.special.offset + k;
+      }
+      if (n) {			/* truncate file after last message */
+	if (pos != (LOCAL->filesize -= delta)) {
+	  sprintf (LOCAL->buf,
+		   "Calculated size mismatch %lu != %lu, delta = %lu",
+		   (unsigned long) pos,(unsigned long) LOCAL->filesize,delta);
+	  MM_LOG (LOCAL->buf,WARN);
+	  LOCAL->filesize = pos;/* fix it then */
+	}
+	ftruncate (LOCAL->fd,LOCAL->filesize);
+	sprintf (LOCAL->buf,"Expunged %lu messages",n);
+				/* output the news */
+	MM_LOG (LOCAL->buf,(long) NIL);
+      }
+      else MM_LOG ("No messages deleted, so no update needed",(long) NIL);
+      fsync (LOCAL->fd);	/* force disk update */
+      fstat (LOCAL->fd,&sbuf);	/* get new write time */
+      tp[1] = LOCAL->filetime = sbuf.st_mtime;
+      tp[0] = time (0);		/* reset atime to now */
+      utime (stream->mailbox,tp);
+      MM_NOCRITICAL (stream);	/* release critical */
+				/* notify upper level of new mailbox size */
+      mail_exists (stream,stream->nmsgs);
+      mail_recent (stream,recent);
+      (*bn) (BLOCK_FILELOCK,NIL);
+      flock (LOCAL->fd,LOCK_SH);/* allow sharers again */
+      (*bn) (BLOCK_NONE,NIL);
+      unlockfd (ld,lock);	/* release exclusive parse/append permission */
+    }
+  }
+  return ret;
+}
+
+/* MTX mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if success, NIL if failed
+ */
+
+long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  struct stat sbuf;
+  time_t tp[2];
+  MESSAGECACHE *elt;
+  unsigned long i,j,k;
+  long ret = LONGT;
+  int fd,ld;
+  char file[MAILTMPLEN],lock[MAILTMPLEN];
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+				/* make sure valid mailbox */
+  if (!mtx_isvalid (mailbox,LOCAL->buf)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
+    return NIL;
+  case 0:			/* merely empty file? */
+    break;
+  case EACCES:			/* file protected */
+    sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
+    MM_LOG (LOCAL->buf,ERROR);
+    return NIL;
+  case EINVAL:
+    if (pc) return (*pc) (stream,sequence,mailbox,options);
+    sprintf (LOCAL->buf,"Invalid MTX-format mailbox name: %.80s",mailbox);
+    MM_LOG (LOCAL->buf,ERROR);
+    return NIL;
+  default:
+    if (pc) return (*pc) (stream,sequence,mailbox,options);
+    sprintf (LOCAL->buf,"Not a MTX-format mailbox: %.80s",mailbox);
+    MM_LOG (LOCAL->buf,ERROR);
+    return NIL;
+  }
+  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+	mail_sequence (stream,sequence))) return NIL;
+				/* got file? */  
+  if ((fd = open (mtx_file (file,mailbox),O_RDWR,NIL)) < 0) {
+    sprintf (LOCAL->buf,"Unable to open copy mailbox: %s",strerror (errno));
+    MM_LOG (LOCAL->buf,ERROR);
+    return NIL;
+  }
+  MM_CRITICAL (stream);		/* go critical */
+				/* get exclusive parse/append permission */
+  if (flock (fd,LOCK_SH) || ((ld = lockfd (fd,lock,LOCK_EX)) < 0)) {
+    MM_LOG ("Unable to lock copy mailbox",ERROR);
+    MM_NOCRITICAL (stream);
+    return NIL;
+  }
+  fstat (fd,&sbuf);		/* get current file size */
+  lseek (fd,sbuf.st_size,L_SET);/* move to end of file */
+
+				/* for each requested message */
+  for (i = 1; ret && (i <= stream->nmsgs); i++) 
+    if ((elt = mail_elt (stream,i))->sequence) {
+      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
+				/* number of bytes to copy */
+      k = elt->private.special.text.size + elt->rfc822_size;
+      do {			/* read from source position */
+	j = min (k,LOCAL->buflen);
+	read (LOCAL->fd,LOCAL->buf,j);
+	if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
+      } while (ret && (k -= j));/* until done */
+    }
+				/* make sure all the updates take */
+  if (!(ret && (ret = !fsync (fd)))) {
+    sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno));
+    MM_LOG (LOCAL->buf,ERROR);
+    ftruncate (fd,sbuf.st_size);
+  }
+  if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */
+				/* else preserve \Marked status */
+  else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0);
+  tp[1] = sbuf.st_mtime;	/* preserve mtime */
+  utime (file,tp);		/* set the times */
+  close (fd);			/* close the file */
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+  MM_NOCRITICAL (stream);	/* release critical */
+				/* delete all requested messages */
+  if (ret && (options & CP_MOVE)) {
+    for (i = 1; i <= stream->nmsgs; i++)
+      if ((elt = mtx_elt (stream,i))->sequence) {
+	elt->deleted = T;	/* mark message deleted */
+				/* recalculate status */
+	mtx_update_status (stream,i,NIL);
+      }
+    if (!stream->rdonly) {	/* make sure the update takes */
+      fsync (LOCAL->fd);
+      fstat (LOCAL->fd,&sbuf);	/* get current write time */
+      tp[1] = LOCAL->filetime = sbuf.st_mtime;
+      tp[0] = time (0);		/* make sure atime remains greater */
+      utime (stream->mailbox,tp);
+    }
+  }
+  if (ret && mail_parameters (NIL,GET_COPYUID,NIL))
+    MM_LOG ("Can not return meaningful COPYUID with this mailbox format",WARN);
+  return ret;
+}
+
+/* MTX mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct stat sbuf;
+  int fd,ld,c;
+  char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  time_t tp[2];
+  FILE *df;
+  MESSAGECACHE elt;
+  long f;
+  unsigned long i,uf;
+  STRING *message;
+  long ret = LONGT;
+				/* default stream to prototype */
+  if (!stream) stream = user_flags (&mtxproto);
+				/* make sure valid mailbox */
+  if (!mtx_isvalid (mailbox,tmp)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    if (!compare_cstring (mailbox,"INBOX")) dummy_create (NIL,"INBOX.MTX");
+    else {
+      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+      return NIL;
+    }
+				/* falls through */
+  case 0:			/* merely empty file? */
+    break;
+  case EACCES:			/* file protected */
+    sprintf (tmp,"Can't access destination: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  case EINVAL:
+    sprintf (tmp,"Invalid MTX-format mailbox name: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  default:
+    sprintf (tmp,"Not a MTX-format mailbox: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+				/* get first message */
+  if (!MM_APPEND (af) (stream,data,&flags,&date,&message)) return NIL;
+
+				/* open destination mailbox */
+  if (((fd = open (mtx_file (file,mailbox),O_WRONLY|O_APPEND,NIL)) < 0) ||
+      !(df = fdopen (fd,"ab"))) {
+    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+				/* get parse/append permission */
+  if (flock (fd,LOCK_SH) || ((ld = lockfd (fd,lock,LOCK_EX)) < 0)) {
+    MM_LOG ("Unable to lock append mailbox",ERROR);
+    close (fd);
+    return NIL;
+  }
+  MM_CRITICAL (stream);		/* go critical */
+  fstat (fd,&sbuf);		/* get current file size */
+  errno = 0;
+  do {				/* parse flags */
+    if (!SIZE (message)) {	/* guard against zero-length */
+      MM_LOG ("Append of zero-length message",ERROR);
+      ret = NIL;
+      break;
+    }
+    f = mail_parse_flags (stream,flags,&i);
+				/* reverse bits (dontcha wish we had CIRC?) */
+    for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i)));
+    if (date) {			/* parse date if given */
+      if (!mail_parse_date (&elt,date)) {
+	sprintf (tmp,"Bad date in append: %.80s",date);
+	MM_LOG (tmp,ERROR);
+	ret = NIL;		/* mark failure */
+	break;
+      }
+      mail_date (tmp,&elt);	/* write preseved date */
+    }
+    else internal_date (tmp);	/* get current date in IMAP format */
+				/* write header */
+    if (fprintf (df,"%s,%lu;%010lo%02lo\015\012",tmp,i = SIZE (message),uf,
+		 (unsigned long) f) < 0) ret = NIL;
+    else {			/* write message */
+      if (i) do c = 0xff & SNX (message);
+      while ((putc (c,df) != EOF) && --i);
+				/* get next message */
+      if (i || !MM_APPEND (af) (stream,data,&flags,&date,&message)) ret = NIL;
+    }
+  } while (ret && message);
+				/* if error... */
+  if (!ret || (fflush (df) == EOF)) {
+    ftruncate (fd,sbuf.st_size);/* revert file */
+    close (fd);			/* make sure fclose() doesn't corrupt us */
+    if (errno) {
+      sprintf (tmp,"Message append failed: %s",strerror (errno));
+      MM_LOG (tmp,ERROR);
+    }
+    ret = NIL;
+  }
+  if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */
+				/* else preserve \Marked status */
+  else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0);
+  tp[1] = sbuf.st_mtime;	/* preserve mtime */
+  utime (file,tp);		/* set the times */
+  fclose (df);			/* close the file */
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+  MM_NOCRITICAL (stream);	/* release critical */
+  if (ret && mail_parameters (NIL,GET_APPENDUID,NIL))
+    MM_LOG ("Can not return meaningful APPENDUID with this mailbox format",
+	    WARN);
+  return ret;
+}
+
+/* Internal routines */
+
+
+/* MTX mail generate file string
+ * Accepts: temporary buffer to write into
+ *	    mailbox name string
+ * Returns: local file string or NIL if failure
+ */
+
+char *mtx_file (char *dst,char *name)
+{
+  char tmp[MAILTMPLEN];
+  char *s = mailboxfile (dst,name);
+				/* return our standard inbox */
+  return (s && !*s) ? mailboxfile (dst,mtx_isvalid ("~/INBOX",tmp) ?
+				   "~/INBOX" : "INBOX.MTX") : s;
+}
+
+/* MTX mail parse mailbox
+ * Accepts: MAIL stream
+ * Returns: T if parse OK
+ *	    NIL if failure, stream aborted
+ */
+
+long mtx_parse (MAILSTREAM *stream)
+{
+  struct stat sbuf;
+  MESSAGECACHE *elt = NIL;
+  unsigned char c,*s,*t,*x;
+  char tmp[MAILTMPLEN];
+  unsigned long i,j;
+  long curpos = LOCAL->filesize;
+  long nmsgs = stream->nmsgs;
+  long recent = stream->recent;
+  short added = NIL;
+  short silent = stream->silent;
+  fstat (LOCAL->fd,&sbuf);	/* get status */
+  if (sbuf.st_size < curpos) {	/* sanity check */
+    sprintf (tmp,"Mailbox shrank from %lu to %lu!",
+	     (unsigned long) curpos,(unsigned long) sbuf.st_size);
+    MM_LOG (tmp,ERROR);
+    mtx_close (stream,NIL);
+    return NIL;
+  }
+  stream->silent = T;		/* don't pass up exists events yet */
+  while (sbuf.st_size - curpos){/* while there is stuff to parse */
+				/* get to that position in the file */
+    lseek (LOCAL->fd,curpos,L_SET);
+    if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) {
+      sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s",
+	       (unsigned long) curpos,(unsigned long) sbuf.st_size,
+	       i ? strerror (errno) : "no data read");
+      MM_LOG (tmp,ERROR);
+      mtx_close (stream,NIL);
+      return NIL;
+    }
+    LOCAL->buf[i] = '\0';	/* tie off buffer just in case */
+    if (!((s = strchr (LOCAL->buf,'\015')) && (s[1] == '\012'))) {
+      sprintf (tmp,"Unable to find CRLF at %lu in %lu bytes, text: %s",
+	       (unsigned long) curpos,i,(char *) LOCAL->buf);
+      MM_LOG (tmp,ERROR);
+      mtx_close (stream,NIL);
+      return NIL;
+    }
+    *s = '\0';			/* tie off header line */
+    i = (s + 2) - LOCAL->buf;	/* note start of text offset */
+    if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) {
+      sprintf (tmp,"Unable to parse internal header at %lu: %s",
+	       (unsigned long) curpos,(char *) LOCAL->buf);
+      MM_LOG (tmp,ERROR);
+      mtx_close (stream,NIL);
+      return NIL;
+    }
+    *s++ = '\0'; *t++ = '\0';	/* tie off fields */
+
+    added = T;			/* note that a new message was added */
+				/* swell the cache */
+    mail_exists (stream,++nmsgs);
+				/* instantiate an elt for this message */
+    (elt = mail_elt (stream,nmsgs))->valid = T;
+    elt->private.uid = ++stream->uid_last;
+				/* note file offset of header */
+    elt->private.special.offset = curpos;
+				/* in case error */
+    elt->private.special.text.size = 0;
+				/* header size not known yet */
+    elt->private.msg.header.text.size = 0;
+    x = s;			/* parse the header components */
+    if (mail_parse_date (elt,LOCAL->buf) &&
+	(elt->rfc822_size = strtoul (s,(char **) &s,10)) && (!(s && *s)) &&
+	isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) &&
+	isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) &&
+	isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) &&
+	isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12])
+      elt->private.special.text.size = i;
+    else {			/* oops */
+      sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s",
+	       curpos,(char *) LOCAL->buf,(char *) x,(char *) t);
+      MM_LOG (tmp,ERROR);
+      mtx_close (stream,NIL);
+      return NIL;
+    }
+				/* make sure didn't run off end of file */
+    if ((curpos += (elt->rfc822_size + i)) > sbuf.st_size) {
+      sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
+	       elt->private.special.offset,(unsigned long) curpos,
+	       (unsigned long) sbuf.st_size);
+      MM_LOG (tmp,ERROR);
+      mtx_close (stream,NIL);
+      return NIL;
+    }
+    c = t[10];			/* remember first system flags byte */
+    t[10] = '\0';		/* tie off flags */
+    j = strtoul (t,NIL,8);	/* get user flags value */
+    t[10] = c;			/* restore first system flags byte */
+				/* set up all valid user flags (reversed!) */
+    while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
+		  stream->user_flags[i]) elt->user_flags |= 1 << i;
+				/* calculate system flags */
+    if ((j = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T;
+    if (j & fDELETED) elt->deleted = T;
+    if (j & fFLAGGED) elt->flagged = T;
+    if (j & fANSWERED) elt->answered = T;
+    if (j & fDRAFT) elt->draft = T;
+    if (!(j & fOLD)) {		/* newly arrived message? */
+      elt->recent = T;
+      recent++;			/* count up a new recent message */
+				/* mark it as old */
+      mtx_update_status (stream,nmsgs,NIL);
+    }
+  }
+  fsync (LOCAL->fd);		/* make sure all the fOLD flags take */
+				/* update parsed file size and time */
+  LOCAL->filesize = sbuf.st_size;
+  fstat (LOCAL->fd,&sbuf);	/* get status again to ensure time is right */
+  LOCAL->filetime = sbuf.st_mtime;
+  if (added && !stream->rdonly){/* make sure atime updated */
+    time_t tp[2];
+    tp[0] = time (0);
+    tp[1] = LOCAL->filetime;
+    utime (stream->mailbox,tp);
+  }
+  stream->silent = silent;	/* can pass up events now */
+  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
+  mail_recent (stream,recent);	/* and of change in recent messages */
+  return LONGT;			/* return the winnage */
+}
+
+/* MTX get cache element with status updating from file
+ * Accepts: MAIL stream
+ *	    message number
+ * Returns: cache element
+ */
+
+MESSAGECACHE *mtx_elt (MAILSTREAM *stream,unsigned long msgno)
+{
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  struct {			/* old flags */
+    unsigned int seen : 1;
+    unsigned int deleted : 1;
+    unsigned int flagged : 1;
+    unsigned int answered : 1;
+    unsigned int draft : 1;
+    unsigned long user_flags;
+  } old;
+  old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged;
+  old.answered = elt->answered; old.draft = elt->draft;
+  old.user_flags = elt->user_flags;
+  mtx_read_flags (stream,elt);
+  if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
+      (old.flagged != elt->flagged) || (old.answered != elt->answered) ||
+      (old.draft != elt->draft) || (old.user_flags != elt->user_flags))
+    MM_FLAGS (stream,msgno);	/* let top level know */
+  return elt;
+}
+
+/* MTX read flags from file
+ * Accepts: MAIL stream
+ * Returns: cache element
+ */
+
+void mtx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  unsigned long i,j;
+				/* noop if readonly and have valid flags */
+  if (stream->rdonly && elt->valid) return;
+				/* set the seek pointer */
+  lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	 elt->private.special.text.size - 14,L_SET);
+				/* read the new flags */
+  if (read (LOCAL->fd,LOCAL->buf,12) < 0) {
+    sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno));
+    fatal (LOCAL->buf);
+  }
+				/* calculate system flags */
+  i = (((LOCAL->buf[10]-'0') * 8) + LOCAL->buf[11]-'0');
+  elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL;
+  elt->flagged = i & fFLAGGED ? T : NIL;
+  elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL;
+  LOCAL->buf[10] = '\0';	/* tie off flags */
+  j = strtoul(LOCAL->buf,NIL,8);/* get user flags value */
+				/* set up all valid user flags (reversed!) */
+  while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
+		stream->user_flags[i]) elt->user_flags |= 1 << i;
+  elt->valid = T;		/* have valid flags now */
+}
+
+/* MTX update status string
+ * Accepts: MAIL stream
+ *	    message number
+ *	    flag saying whether or not to sync
+ */
+
+void mtx_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag)
+{
+  time_t tp[2];
+  struct stat sbuf;
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  unsigned long j,k = 0;
+				/* readonly */
+  if (stream->rdonly || !elt->valid) mtx_read_flags (stream,elt);
+  else {			/* readwrite */
+    j = elt->user_flags;	/* get user flags */
+				/* reverse bits (dontcha wish we had CIRC?) */
+    while (j) k |= 1 << (29 - find_rightmost_bit (&j));
+				/* print new flag string */
+    sprintf (LOCAL->buf,"%010lo%02o",k,(unsigned)
+	     (fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
+	      (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
+	      (fDRAFT * elt->draft)));
+				/* get to that place in the file */
+    lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	   elt->private.special.text.size - 14,L_SET);
+				/* write new flags */
+    write (LOCAL->fd,LOCAL->buf,12);
+    if (syncflag) {		/* sync if requested */
+      fsync (LOCAL->fd);
+      fstat (LOCAL->fd,&sbuf);	/* get new write time */
+      tp[1] = LOCAL->filetime = sbuf.st_mtime;
+      tp[0] = time (0);		/* make sure read is later */
+      utime (stream->mailbox,tp);
+    }
+  }
+}
+
+/* MTX locate header for a message
+ * Accepts: MAIL stream
+ *	    message number
+ *	    pointer to returned header size
+ * Returns: position of header in file
+ */
+
+unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			  unsigned long *size)
+{
+  unsigned long siz;
+  long i = 0;
+  int q = 0;
+  char *s,tmp[MAILTMPLEN];
+  MESSAGECACHE *elt = mtx_elt (stream,msgno);
+  unsigned long ret = elt->private.special.offset +
+    elt->private.special.text.size;
+				/* is header size known? */
+  if (!(*size = elt->private.msg.header.text.size)) {
+    lseek (LOCAL->fd,ret,L_SET);/* get to header position */
+				/* search message for CRLF CRLF */
+    for (siz = 1,s = tmp; siz <= elt->rfc822_size; siz++) {
+				/* read another buffer as necessary */
+      if ((--i <= 0) &&		/* buffer empty? */
+	  (read (LOCAL->fd,s = tmp,
+		 i = min (elt->rfc822_size - siz,(long) MAILTMPLEN)) < 0))
+	return ret;		/* I/O error? */
+      switch (q) {		/* sniff at buffer */
+      case 0:			/* first character */
+	q = (*s++ == '\015') ? 1 : 0;
+	break;
+      case 1:			/* second character */
+	q = (*s++ == '\012') ? 2 : 0;
+	break;
+      case 2:			/* third character */
+	q = (*s++ == '\015') ? 3 : 0;
+	break;
+      case 3:			/* fourth character */
+	if (*s++ == '\012') {	/* have the sequence? */
+				/* yes, note for later */
+	  elt->private.msg.header.text.size = *size = siz;
+	  return ret;
+	}
+	q = 0;			/* lost... */
+	break;
+      }
+    }
+				/* header consumes entire message */
+    elt->private.msg.header.text.size = *size = elt->rfc822_size;
+  }
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/mx.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1287 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	MX mail routines
+ *
+ * Author(s):	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	3 May 1996
+ * Last Edited:	6 January 2008
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "mail.h"
+#include "osdep.h"
+#include <pwd.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "misc.h"
+#include "dummy.h"
+#include "fdstring.h"
+
+/* Index file */
+
+#define MXINDEXNAME "/.mxindex"
+#define MXINDEX(d,s) strcat (mx_file (d,s),MXINDEXNAME)
+
+
+/* MX I/O stream local data */
+	
+typedef struct mx_local {
+  int fd;			/* file descriptor of open index */
+  unsigned char *buf;		/* temporary buffer */
+  unsigned long buflen;		/* current size of temporary buffer */
+  unsigned long cachedtexts;	/* total size of all cached texts */
+  time_t scantime;		/* last time directory scanned */
+} MXLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((MXLOCAL *) stream->local)
+
+
+/* Function prototypes */
+
+DRIVER *mx_valid (char *name);
+int mx_isvalid (char *name,char *tmp);
+int mx_namevalid (char *name);
+void *mx_parameters (long function,void *value);
+long mx_dirfmttest (char *name);
+void mx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+long mx_scan_contents (char *name,char *contents,unsigned long csiz,
+		       unsigned long fsiz);
+void mx_list (MAILSTREAM *stream,char *ref,char *pat);
+void mx_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long mx_subscribe (MAILSTREAM *stream,char *mailbox);
+long mx_unsubscribe (MAILSTREAM *stream,char *mailbox);
+long mx_create (MAILSTREAM *stream,char *mailbox);
+long mx_delete (MAILSTREAM *stream,char *mailbox);
+long mx_rename (MAILSTREAM *stream,char *old,char *newname);
+int mx_rename_work (char *src,size_t srcl,char *dst,size_t dstl,char *name);
+MAILSTREAM *mx_open (MAILSTREAM *stream);
+void mx_close (MAILSTREAM *stream,long options);
+void mx_fast (MAILSTREAM *stream,char *sequence,long flags);
+char *mx_fast_work (MAILSTREAM *stream,MESSAGECACHE *elt);
+char *mx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
+		 long flags);
+long mx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+void mx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
+void mx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
+long mx_ping (MAILSTREAM *stream);
+void mx_check (MAILSTREAM *stream);
+long mx_expunge (MAILSTREAM *stream,char *sequence,long options);
+long mx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,
+	      long options);
+long mx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+long mx_append_msg (MAILSTREAM *stream,char *flags,MESSAGECACHE *elt,
+		    STRING *st,SEARCHSET *set);
+
+int mx_select (struct direct *name);
+int mx_numsort (const void *d1,const void *d2);
+char *mx_file (char *dst,char *name);
+long mx_lockindex (MAILSTREAM *stream);
+void mx_unlockindex (MAILSTREAM *stream);
+void mx_setdate (char *file,MESSAGECACHE *elt);
+
+
+/* MX mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER mxdriver = {
+  "mx",				/* driver name */
+				/* driver flags */
+  DR_MAIL|DR_LOCAL|DR_NOFAST|DR_CRLF|DR_LOCKING|DR_DIRFMT,
+  (DRIVER *) NIL,		/* next driver */
+  mx_valid,			/* mailbox is valid for us */
+  mx_parameters,		/* manipulate parameters */
+  mx_scan,			/* scan mailboxes */
+  mx_list,			/* find mailboxes */
+  mx_lsub,			/* find subscribed mailboxes */
+  mx_subscribe,			/* subscribe to mailbox */
+  mx_unsubscribe,		/* unsubscribe from mailbox */
+  mx_create,			/* create mailbox */
+  mx_delete,			/* delete mailbox */
+  mx_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  mx_open,			/* open mailbox */
+  mx_close,			/* close mailbox */
+  mx_fast,			/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  mx_header,			/* fetch message header only */
+  mx_text,			/* fetch message body only */
+  NIL,				/* fetch partial message test */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  mx_flag,			/* modify flags */
+  mx_flagmsg,			/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  mx_ping,			/* ping mailbox to see if still alive */
+  mx_check,			/* check for new messages */
+  mx_expunge,			/* expunge deleted messages */
+  mx_copy,			/* copy messages to another mailbox */
+  mx_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM mxproto = {&mxdriver};
+
+/* MX mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *mx_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+  return mx_isvalid (name,tmp) ? &mxdriver : NIL;
+}
+
+
+/* MX mail test for valid mailbox
+ * Accepts: mailbox name
+ *	    temporary buffer to use
+ * Returns: T if valid, NIL otherwise with errno holding dir stat error
+ */
+
+int mx_isvalid (char *name,char *tmp)
+{
+  struct stat sbuf;
+  errno = NIL;			/* zap error */
+  if ((strlen (name) <= NETMAXMBX) && *mx_file (tmp,name) &&
+      !stat (tmp,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) {
+				/* name is directory; is it mx? */
+    if (!stat (MXINDEX (tmp,name),&sbuf) &&
+	((sbuf.st_mode & S_IFMT) == S_IFREG)) return T;
+    errno = NIL;		/* directory but not mx */
+  }
+  else if (!compare_cstring (name,"INBOX")) errno = NIL;
+  return NIL;
+}
+
+
+/* MX mail test for valid mailbox
+ * Accepts: mailbox name
+ * Returns: T if valid, NIL otherwise
+ */
+
+int mx_namevalid (char *name)
+{
+  char *s = (*name == '/') ? name + 1 : name;
+  while (s && *s) {		/* make sure valid name */
+    if (isdigit (*s)) s++;	/* digit, check this node further... */
+    else if (*s == '/') break;	/* all digit node, barf */
+				/* non-digit, skip to next node or return */
+    else if (!((s = strchr (s+1,'/')) && *++s)) return T;
+  }
+  return NIL;			/* all numeric or empty node */
+}
+
+/* MX manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *mx_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case GET_INBOXPATH:
+    if (value) ret = mailboxfile ((char *) value,"~/INBOX");
+    break;
+  case GET_DIRFMTTEST:
+    ret = (void *) mx_dirfmttest;
+    break;
+  case GET_SCANCONTENTS:
+    ret = (void *) mx_scan_contents;
+    break;
+  }
+  return ret;
+}
+
+
+/* MX test for directory format internal node
+ * Accepts: candidate node name
+ * Returns: T if internal name, NIL otherwise
+ */
+
+long mx_dirfmttest (char *name)
+{
+  int c;
+				/* success if index name or all-numberic */
+  if (strcmp (name,MXINDEXNAME+1))
+    while (c = *name++) if (!isdigit (c)) return NIL;
+  return LONGT;
+}
+
+/* MX scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void mx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* MX scan mailbox for contents
+ * Accepts: mailbox name
+ *	    desired contents
+ *	    contents size
+ *	    file size (ignored)
+ * Returns: NIL if contents not found, T if found
+ */
+
+long mx_scan_contents (char *name,char *contents,unsigned long csiz,
+			unsigned long fsiz)
+{
+  long i,nfiles;
+  void *a;
+  char *s;
+  long ret = NIL;
+  size_t namelen = strlen (name);
+  struct stat sbuf;
+  struct direct **names = NIL;
+  if ((nfiles = scandir (name,&names,mx_select,mx_numsort)) > 0)
+    for (i = 0; i < nfiles; ++i) {
+      if (!ret) {
+	sprintf (s = (char *) fs_get (namelen + strlen (names[i]->d_name) + 2),
+		 "%s/%s",name,names[i]->d_name);
+	if (!stat (s,&sbuf) && (csiz <= sbuf.st_size))
+	  ret = dummy_scan_contents (s,contents,csiz,sbuf.st_size);
+	fs_give ((void **) &s);
+      }
+      fs_give ((void **) &names[i]);
+    }
+				/* free directory list */
+  if (a = (void *) names) fs_give ((void **) &a);
+  return ret;
+}
+
+/* MX list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mx_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_list (NIL,ref,pat);
+}
+
+
+/* MX list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mx_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_lsub (NIL,ref,pat);
+}
+
+/* MX mail subscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to add to subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long mx_subscribe (MAILSTREAM *stream,char *mailbox)
+{
+  return sm_subscribe (mailbox);
+}
+
+
+/* MX mail unsubscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to delete from subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long mx_unsubscribe (MAILSTREAM *stream,char *mailbox)
+{
+  return sm_unsubscribe (mailbox);
+}
+
+/* MX mail create mailbox
+ * Accepts: mail stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long mx_create (MAILSTREAM *stream,char *mailbox)
+{
+  DRIVER *test;
+  int fd;
+  char *s,tmp[MAILTMPLEN];
+  int mask = umask (0);
+  long ret = NIL;
+  if (!mx_namevalid (mailbox))	/* validate name */
+    sprintf (tmp,"Can't create mailbox %.80s: invalid MX-format name",mailbox);
+				/* must not already exist */
+  else if ((test = mail_valid (NIL,mailbox,NIL)) &&
+	   strcmp (test->name,"dummy"))
+    sprintf (tmp,"Can't create mailbox %.80s: mailbox already exists",mailbox);
+				/* create directory */
+  else if (!dummy_create_path (stream,MXINDEX (tmp,mailbox),
+			       get_dir_protection (mailbox)))
+    sprintf (tmp,"Can't create mailbox %.80s: %s",mailbox,strerror (errno));
+  else {			/* success */
+				/* set index protection */
+    set_mbx_protections (mailbox,tmp);
+				/* tie off directory name */
+    *(s = strrchr (tmp,'/') + 1) = '\0';
+				/* set directory protection */
+    set_mbx_protections (mailbox,tmp);
+    ret = LONGT;
+  }
+  umask (mask);			/* restore mask */
+  if (!ret) MM_LOG (tmp,ERROR);	/* some error */
+  return ret;
+}
+
+/* MX mail delete mailbox
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long mx_delete (MAILSTREAM *stream,char *mailbox)
+{
+  DIR *dirp;
+  struct direct *d;
+  char *s;
+  char tmp[MAILTMPLEN];
+  if (!mx_isvalid (mailbox,tmp))
+    sprintf (tmp,"Can't delete mailbox %.80s: no such mailbox",mailbox);
+				/* delete index */
+  else if (unlink (MXINDEX (tmp,mailbox)))
+    sprintf (tmp,"Can't delete mailbox %.80s index: %s",
+	     mailbox,strerror (errno));
+  else {			/* get directory name */
+    *(s = strrchr (tmp,'/')) = '\0';
+    if (dirp = opendir (tmp)) {	/* open directory */
+      *s++ = '/';		/* restore delimiter */
+				/* massacre messages */
+      while (d = readdir (dirp)) if (mx_select (d)) {
+	strcpy (s,d->d_name);	/* make path */
+	unlink (tmp);		/* sayonara */
+      }
+      closedir (dirp);		/* flush directory */
+      *(s = strrchr (tmp,'/')) = '\0';
+      if (rmdir (tmp)) {	/* try to remove the directory */
+	sprintf (tmp,"Can't delete name %.80s: %s",mailbox,strerror (errno));
+	MM_LOG (tmp,WARN);
+      }
+    }
+    return T;			/* always success */
+  }
+  MM_LOG (tmp,ERROR);		/* something failed */
+  return NIL;
+}
+
+/* MX mail rename mailbox
+ * Accepts: MX mail stream
+ *	    old mailbox name
+ *	    new mailbox name
+ * Returns: T on success, NIL on failure
+ */
+
+long mx_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  char c,*s,tmp[MAILTMPLEN],tmp1[MAILTMPLEN];
+  struct stat sbuf;
+  if (!mx_isvalid (old,tmp))
+    sprintf (tmp,"Can't rename mailbox %.80s: no such mailbox",old);
+  else if (!mx_namevalid (newname))
+    sprintf (tmp,"Can't rename to mailbox %.80s: invalid MX-format name",
+	     newname);
+				/* new mailbox name must not be valid */
+  else if (mx_isvalid (newname,tmp))
+    sprintf (tmp,"Can't rename to mailbox %.80s: destination already exists",
+	     newname);
+  else {
+    mx_file (tmp,old);		/* build old directory name */
+    mx_file (tmp1,newname);	/* and new directory name */
+				/* easy if not INBOX */
+    if (compare_cstring (old,"INBOX")) {
+				/* found superior to destination name? */
+      if (s = strrchr (mx_file (tmp1,newname),'/')) {
+	c = *++s;	    /* remember first character of inferior */
+	*s = '\0';		/* tie off to get just superior */
+				/* name doesn't exist, create it */
+	if ((stat (tmp1,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+	    !dummy_create_path (stream,tmp1,get_dir_protection (newname)))
+	  return NIL;
+	*s = c;			/* restore full name */
+      }
+      if (!rename (tmp,tmp1)) return LONGT;
+    }
+
+				/* RFC 3501 requires this */
+    else if (dummy_create_path (stream,strcat (tmp1,"/"),
+				get_dir_protection (newname))) {
+      void *a;
+      int i,n,lasterror;
+      struct direct **names = NIL;
+      size_t srcl = strlen (tmp);
+      size_t dstl = strlen (tmp1);
+				/* rename each mx file to new directory */
+      for (i = lasterror = 0,n = scandir (tmp,&names,mx_select,mx_numsort);
+	   i < n; ++i) {
+	if (mx_rename_work (tmp,srcl,tmp1,dstl,names[i]->d_name))
+	  lasterror = errno;
+	fs_give ((void **) &names[i]);
+      }
+				/* free directory list */
+      if (a = (void *) names) fs_give ((void **) &a);
+      if (lasterror || mx_rename_work (tmp,srcl,tmp1,dstl,MXINDEXNAME+1))
+	errno = lasterror;
+      else return mx_create (NIL,"INBOX");
+    }
+    sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",
+	     old,newname,strerror (errno));
+  }
+  MM_LOG (tmp,ERROR);		/* something failed */
+  return NIL;
+}
+
+
+/* MX rename worker routine
+ * Accepts: source directory name
+ *	    source directory name length
+ *	    destination directory name
+ *	    destination directory name length
+ *	    name of node to move
+ * Returns: zero if success, non-zero if error
+ */
+
+int mx_rename_work (char *src,size_t srcl,char *dst,size_t dstl,char *name)
+{
+  int ret;
+  size_t len = strlen (name);
+  char *s = (char *) fs_get (srcl + len + 2);
+  char *d = (char *) fs_get (dstl + len + 1);
+  sprintf (s,"%s/%s",src,name);
+  sprintf (d,"%s%s",dst,name);
+  ret = rename (s,d);
+  fs_give ((void **) &s);
+  fs_give ((void **) &d);
+  return ret;
+}
+
+/* MX mail open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *mx_open (MAILSTREAM *stream)
+{
+  char tmp[MAILTMPLEN];
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return user_flags (&mxproto);
+  if (stream->local) fatal ("mx recycle stream");
+  stream->local = fs_get (sizeof (MXLOCAL));
+				/* note if an INBOX or not */
+  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
+  mx_file (tmp,stream->mailbox);/* get directory name */
+				/* canonicalize mailbox name */
+  fs_give ((void **) &stream->mailbox);
+  stream->mailbox = cpystr (tmp);
+				/* make temporary buffer */
+  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
+  LOCAL->buflen = CHUNKSIZE - 1;
+  LOCAL->scantime = 0;		/* not scanned yet */
+  LOCAL->fd = -1;		/* no index yet */
+  LOCAL->cachedtexts = 0;	/* no cached texts */
+  stream->sequence++;		/* bump sequence number */
+				/* parse mailbox */
+  stream->nmsgs = stream->recent = 0;
+  if (mx_ping (stream) && !(stream->nmsgs || stream->silent))
+    MM_LOG ("Mailbox is empty",(long) NIL);
+  stream->perm_seen = stream->perm_deleted = stream->perm_flagged =
+    stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T;
+  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
+  stream->kwd_create = (stream->user_flags[NUSERFLAGS-1] || stream->rdonly) ?
+    NIL : T;			/* can we create new user flags? */
+  return stream;		/* return stream to caller */
+}
+
+/* MX mail close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void mx_close (MAILSTREAM *stream,long options)
+{
+  if (LOCAL) {			/* only if a file is open */
+    int silent = stream->silent;
+    stream->silent = T;		/* note this stream is dying */
+    if (options & CL_EXPUNGE) mx_expunge (stream,NIL,NIL);
+				/* free local scratch buffer */
+    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+    stream->silent = silent;	/* reset silent state */
+  }
+}
+
+/* MX mail fetch fast information
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ */
+
+void mx_fast (MAILSTREAM *stream,char *sequence,long flags)
+{
+  unsigned long i;
+  MESSAGECACHE *elt;
+  if (stream && LOCAL &&
+      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
+       mail_sequence (stream,sequence)))
+    for (i = 1; i <= stream->nmsgs; i++)
+      if ((elt = mail_elt (stream,i))->sequence) mx_fast_work (stream,elt);
+}
+
+
+/* MX mail fetch fast information
+ * Accepts: MAIL stream
+ *	    message cache element
+ * Returns: name of message file
+ */
+
+char *mx_fast_work (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  struct stat sbuf;
+  struct tm *tm;
+				/* build message file name */
+  sprintf (LOCAL->buf,"%s/%lu",stream->mailbox,elt->private.uid);
+				/* have size yet? */
+  if (!elt->rfc822_size && !stat (LOCAL->buf,&sbuf)) {
+				/* make plausible IMAPish date string */
+    tm = gmtime (&sbuf.st_mtime);
+    elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1;
+    elt->year = tm->tm_year + 1900 - BASEYEAR;
+    elt->hours = tm->tm_hour; elt->minutes = tm->tm_min;
+    elt->seconds = tm->tm_sec;
+    elt->zhours = 0; elt->zminutes = 0; elt->zoccident = 0;
+    elt->rfc822_size = sbuf.st_size;
+  }
+  return (char *) LOCAL->buf;	/* return file name */
+}
+
+/* MX mail fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+char *mx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
+		 long flags)
+{
+  unsigned long i;
+  int fd;
+  MESSAGECACHE *elt;
+  *length = 0;			/* default to empty */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+  elt = mail_elt (stream,msgno);/* get elt */
+  if (!elt->private.msg.header.text.data) {
+				/* purge cache if too big */
+    if (LOCAL->cachedtexts > max (stream->nmsgs * 4096,2097152)) {
+      mail_gc (stream,GC_TEXTS);/* just can't keep that much */
+      LOCAL->cachedtexts = 0;
+    }
+    if ((fd = open (mx_fast_work (stream,elt),O_RDONLY,NIL)) < 0) return "";
+				/* is buffer big enough? */
+    if (elt->rfc822_size > LOCAL->buflen) {
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get ((LOCAL->buflen = elt->rfc822_size) + 1);
+    }
+				/* slurp message */
+    read (fd,LOCAL->buf,elt->rfc822_size);
+				/* tie off file */
+    LOCAL->buf[elt->rfc822_size] = '\0';
+    close (fd);			/* flush message file */
+				/* find end of header */
+    if (elt->rfc822_size < 4) i = 0;
+    else for (i = 4; (i < elt->rfc822_size) &&
+	      !((LOCAL->buf[i - 4] == '\015') &&
+		(LOCAL->buf[i - 3] == '\012') &&
+		(LOCAL->buf[i - 2] == '\015') &&
+		(LOCAL->buf[i - 1] == '\012')); i++);
+				/* copy header */
+    cpytxt (&elt->private.msg.header.text,LOCAL->buf,i);
+    cpytxt (&elt->private.msg.text.text,LOCAL->buf+i,elt->rfc822_size - i);
+				/* add to cached size */
+    LOCAL->cachedtexts += elt->rfc822_size;
+  }
+  *length = elt->private.msg.header.text.size;
+  return (char *) elt->private.msg.header.text.data;
+}
+
+/* MX mail fetch message text (body only)
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned stringstruct
+ *	    option flags
+ * Returns: T on success, NIL on failure
+ */
+
+long mx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  unsigned long i;
+  MESSAGECACHE *elt;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+  elt = mail_elt (stream,msgno);
+				/* snarf message if don't have it yet */
+  if (!elt->private.msg.text.text.data) {
+    mx_header (stream,msgno,&i,flags);
+    if (!elt->private.msg.text.text.data) return NIL;
+  }
+				/* mark as seen */
+  if (!(flags & FT_PEEK) && mx_lockindex (stream)) {
+    elt->seen = T;
+    mx_unlockindex (stream);
+    MM_FLAGS (stream,msgno);
+  }
+  INIT (bs,mail_string,elt->private.msg.text.text.data,
+	elt->private.msg.text.text.size);
+  return T;
+}
+
+/* MX mail modify flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    flag(s)
+ *	    option flags
+ */
+
+void mx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
+{
+  mx_unlockindex (stream);	/* finished with index */
+}
+
+
+/* MX per-message modify flags
+ * Accepts: MAIL stream
+ *	    message cache element
+ */
+
+void mx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  mx_lockindex (stream);	/* lock index if not already locked */
+}
+
+/* MX mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ */
+
+long mx_ping (MAILSTREAM *stream)
+{
+  MAILSTREAM *sysibx = NIL;
+  MESSAGECACHE *elt,*selt;
+  struct stat sbuf;
+  char *s,tmp[MAILTMPLEN];
+  int fd;
+  unsigned long i,j,r,old;
+  long nmsgs = stream->nmsgs;
+  long recent = stream->recent;
+  int silent = stream->silent;
+  if (stat (stream->mailbox,&sbuf)) return NIL;
+  stream->silent = T;		/* don't pass up exists events yet */
+  if (sbuf.st_ctime != LOCAL->scantime) {
+    struct direct **names = NIL;
+    long nfiles = scandir (stream->mailbox,&names,mx_select,mx_numsort);
+    if (nfiles < 0) nfiles = 0;	/* in case error */
+    old = stream->uid_last;
+				/* note scanned now */
+    LOCAL->scantime = sbuf.st_ctime;
+				/* scan directory */
+    for (i = 0; i < nfiles; ++i) {
+				/* if newly seen, add to list */
+      if ((j = atoi (names[i]->d_name)) > old) {
+				/* swell the cache */
+	mail_exists (stream,++nmsgs);
+	stream->uid_last = (elt = mail_elt (stream,nmsgs))->private.uid = j;
+	elt->valid = T;		/* note valid flags */
+	if (old) {		/* other than the first pass? */
+	  elt->recent = T;	/* yup, mark as recent */
+	  recent++;		/* bump recent count */
+	}
+      }
+      fs_give ((void **) &names[i]);
+    }
+				/* free directory */
+    if (s = (void *) names) fs_give ((void **) &s);
+  }
+  stream->nmsgs = nmsgs;	/* don't upset mail_uid() */
+
+				/* if INBOX, snarf from system INBOX  */
+  if (mx_lockindex (stream) && stream->inbox &&
+      !strcmp (sysinbox (),stream->mailbox)) {
+    old = stream->uid_last;
+    MM_CRITICAL (stream);	/* go critical */
+				/* see if anything in system inbox */
+    if (!stat (sysinbox (),&sbuf) && sbuf.st_size &&
+	(sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) &&
+	!sysibx->rdonly && (r = sysibx->nmsgs)) {
+      for (i = 1; i <= r; ++i) {/* for each message in sysinbox mailbox */
+				/* build file name we will use */
+	sprintf (LOCAL->buf,"%s/%lu",stream->mailbox,++old);
+				/* snarf message from Berkeley mailbox */
+	selt = mail_elt (sysibx,i);
+	if (((fd = open (LOCAL->buf,O_WRONLY|O_CREAT|O_EXCL,
+			 (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL)))
+	     >= 0) &&
+	    (s = mail_fetchheader_full (sysibx,i,NIL,&j,FT_PEEK)) &&
+	    (write (fd,s,j) == j) &&
+	    (s = mail_fetchtext_full (sysibx,i,&j,FT_PEEK)) &&
+	    (write (fd,s,j) == j) && !fsync (fd) && !close (fd)) {
+				/* swell the cache */
+	  mail_exists (stream,++nmsgs);
+	  stream->uid_last =	/* create new elt, note its file number */
+	    (elt = mail_elt (stream,nmsgs))->private.uid = old;
+	  recent++;		/* bump recent count */
+				/* set up initial flags and date */
+	  elt->valid = elt->recent = T;
+	  elt->seen = selt->seen;
+	  elt->deleted = selt->deleted;
+	  elt->flagged = selt->flagged;
+	  elt->answered = selt->answered;
+	  elt->draft = selt->draft;
+	  elt->day = selt->day;elt->month = selt->month;elt->year = selt->year;
+	  elt->hours = selt->hours;elt->minutes = selt->minutes;
+	  elt->seconds = selt->seconds;
+	  elt->zhours = selt->zhours; elt->zminutes = selt->zminutes;
+	  elt->zoccident = selt->zoccident;
+	  mx_setdate (LOCAL->buf,elt);
+	  sprintf (tmp,"%lu",i);/* delete it from the sysinbox */
+	  mail_flag (sysibx,tmp,"\\Deleted",ST_SET);
+	}
+	else {			/* failed to snarf */
+	  if (fd) {		/* did it ever get opened? */
+	    close (fd);		/* close descriptor */
+	    unlink (LOCAL->buf);/* flush this file */
+	  }
+	  sprintf (tmp,"Message copy to MX mailbox failed: %.80s",
+		   s,strerror (errno));
+	  MM_LOG (tmp,ERROR);
+	  r = 0;		/* stop the snarf in its tracks */
+	}
+      }
+				/* update scan time */
+      if (!stat (stream->mailbox,&sbuf)) LOCAL->scantime = sbuf.st_ctime;      
+      mail_expunge (sysibx);	/* now expunge all those messages */
+    }
+    if (sysibx) mail_close (sysibx);
+    MM_NOCRITICAL (stream);	/* release critical */
+  }
+  mx_unlockindex (stream);	/* done with index */
+  stream->silent = silent;	/* can pass up events now */
+  mail_exists (stream,nmsgs);	/* notify upper level of mailbox size */
+  mail_recent (stream,recent);
+  return T;			/* return that we are alive */
+}
+
+/* MX mail check mailbox
+ * Accepts: MAIL stream
+ */
+
+void mx_check (MAILSTREAM *stream)
+{
+  if (mx_ping (stream)) MM_LOG ("Check completed",(long) NIL);
+}
+
+
+/* MX mail expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long mx_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  long ret;
+  MESSAGECACHE *elt;
+  unsigned long i = 1;
+  unsigned long n = 0;
+  unsigned long recent = stream->recent;
+  if (ret = (sequence ? ((options & EX_UID) ?
+			 mail_uid_sequence (stream,sequence) :
+			 mail_sequence (stream,sequence)) : LONGT) &&
+      mx_lockindex (stream)) {	/* lock the index */
+    MM_CRITICAL (stream);	/* go critical */
+    while (i <= stream->nmsgs) {/* for each message */
+      elt = mail_elt (stream,i);/* if deleted, need to trash it */
+      if (elt->deleted && (sequence ? elt->sequence : T)) {
+	sprintf (LOCAL->buf,"%s/%lu",stream->mailbox,elt->private.uid);
+	if (unlink (LOCAL->buf)) {/* try to delete the message */
+	  sprintf (LOCAL->buf,"Expunge of message %lu failed, aborted: %s",i,
+		   strerror (errno));
+	  MM_LOG (LOCAL->buf,(long) NIL);
+	  break;
+	}
+				/* note uncached */
+	LOCAL->cachedtexts -= ((elt->private.msg.header.text.data ?
+				elt->private.msg.header.text.size : 0) +
+			       (elt->private.msg.text.text.data ?
+				elt->private.msg.text.text.size : 0));
+	mail_gc_msg (&elt->private.msg,GC_ENV | GC_TEXTS);
+	if(elt->recent)--recent;/* if recent, note one less recent message */
+	mail_expunged(stream,i);/* notify upper levels */
+	n++;			/* count up one more expunged message */
+      }
+      else i++;			/* otherwise try next message */
+    }
+    if (n) {			/* output the news if any expunged */
+      sprintf (LOCAL->buf,"Expunged %lu messages",n);
+      MM_LOG (LOCAL->buf,(long) NIL);
+    }
+    else MM_LOG ("No messages deleted, so no update needed",(long) NIL);
+    MM_NOCRITICAL (stream);	/* release critical */
+    mx_unlockindex (stream);	/* finished with index */
+				/* notify upper level of new mailbox size */
+    mail_exists (stream,stream->nmsgs);
+    mail_recent (stream,recent);
+  }
+  return ret;
+}
+
+/* MX mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if copy successful, else NIL
+ */
+
+long mx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  FDDATA d;
+  STRING st;
+  MESSAGECACHE *elt;
+  MAILSTREAM *astream;
+  struct stat sbuf;
+  int fd;
+  unsigned long i,j,uid,uidv;
+  char *t,tmp[MAILTMPLEN];
+  long ret;
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+				/* make sure valid mailbox */
+  if (!mx_valid (mailbox)) switch (errno) {
+  case NIL:			/* no error in stat() */
+    if (pc) return (*pc) (stream,sequence,mailbox,options);
+    sprintf (LOCAL->buf,"Not a MX-format mailbox: %.80s",mailbox);
+    MM_LOG (LOCAL->buf,ERROR);
+    return NIL;
+  default:			/* some stat() error */
+    MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
+    return NIL;
+  }
+				/* copy the messages */
+  if (!(ret = ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+	       mail_sequence (stream,sequence))));
+				/* acquire stream to append to */
+  else if (!(astream = mail_open (NIL,mailbox,OP_SILENT))) {
+    MM_LOG ("Can't open copy mailbox",ERROR);
+    ret = NIL;
+  }
+  else {
+    MM_CRITICAL (stream);	/* go critical */
+    if (!(ret = mx_lockindex (astream)))
+      MM_LOG ("Message copy failed: unable to lock index",ERROR);
+    else {
+
+      copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL);
+      SEARCHSET *source = cu ? mail_newsearchset () : NIL;
+      SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
+      for (i = 1,uid = uidv = 0; ret && (i <= stream->nmsgs); i++) 
+      if ((elt = mail_elt (stream,i))->sequence) {
+	if (ret = ((fd = open (mx_fast_work (stream,elt),O_RDONLY,NIL))
+		   >= 0)) {
+	  fstat (fd,&sbuf);	/* get size of message */
+	  d.fd = fd;		/* set up file descriptor */
+	  d.pos = 0;		/* start of file */
+	  d.chunk = LOCAL->buf;
+	  d.chunksize = CHUNKSIZE;
+	  INIT (&st,fd_string,&d,sbuf.st_size);
+				/* init flag string */
+	  tmp[0] = tmp[1] = '\0';
+	  if (j = elt->user_flags) do
+	    if (t = stream->user_flags[find_rightmost_bit (&j)])
+	      strcat (strcat (tmp," "),t);
+	  while (j);
+	  if (elt->seen) strcat (tmp," \\Seen");
+	  if (elt->deleted) strcat (tmp," \\Deleted");
+	  if (elt->flagged) strcat (tmp," \\Flagged");
+	  if (elt->answered) strcat (tmp," \\Answered");
+	  if (elt->draft) strcat (tmp," \\Draft");
+	  tmp[0] = '(';		/* open list */
+	  strcat (tmp,")");	/* close list */
+	  if (ret = mx_append_msg (astream,tmp,elt,&st,dest)) {
+				/* add to source set if needed */
+	    if (source) mail_append_set (source,mail_uid (stream,i));
+				/* delete if doing a move */
+	    if (options & CP_MOVE) elt->deleted = T;
+	  }
+	}
+      }
+				/* return sets if doing COPYUID */
+      if (cu && ret) (*cu) (stream,mailbox,astream->uid_validity,source,dest);
+      else {			/* flush any sets we may have built */
+	mail_free_searchset (&source);
+	mail_free_searchset (&dest);
+      }
+      mx_unlockindex (astream);	/* unlock index */
+    }
+    MM_NOCRITICAL (stream);
+    mail_close (astream);	/* finished with append stream */
+  }
+  return ret;			/* return success */
+}
+
+/* MX mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long mx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  MESSAGECACHE elt;
+  MAILSTREAM *astream;
+  char *flags,*date,tmp[MAILTMPLEN];
+  STRING *message;
+  long ret = LONGT;
+				/* default stream to prototype */
+  if (!stream) stream = user_flags (&mxproto);
+				/* N.B.: can't use LOCAL->buf for tmp */
+				/* make sure valid mailbox */
+  if (!mx_isvalid (mailbox,tmp)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    if (!compare_cstring (mailbox,"INBOX")) mx_create (NIL,"INBOX");
+    else {
+      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+      return NIL;
+    }
+				/* falls through */
+  case 0:			/* merely empty file? */
+    break;
+  case EINVAL:
+    sprintf (tmp,"Invalid MX-format mailbox name: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  default:
+    sprintf (tmp,"Not a MX-format mailbox: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+
+				/* get first message */
+  if (!MM_APPEND (af) (stream,data,&flags,&date,&message)) return NIL;
+  if (!(astream = mail_open (NIL,mailbox,OP_SILENT))) {
+    MM_LOG ("Can't open append mailbox",ERROR);
+    return NIL;
+  }
+  MM_CRITICAL (astream);	/* go critical */
+				/* lock the index */
+  if (!(ret = mx_lockindex (astream)))
+    MM_LOG ("Message append failed: unable to lock index",ERROR);
+  else {
+    appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL);
+    SEARCHSET *dst = au ? mail_newsearchset () : NIL;
+    do {
+				/* guard against zero-length */
+      if (!(ret = SIZE (message)))
+	MM_LOG ("Append of zero-length message",ERROR);
+      else if (date && !(ret = mail_parse_date (&elt,date))) {
+	sprintf (tmp,"Bad date in append: %.80s",date);
+	MM_LOG (tmp,ERROR);
+      }
+      else ret = mx_append_msg (astream,flags,date ? &elt : NIL,message,dst)&&
+	     MM_APPEND (af) (stream,data,&flags,&date,&message);
+    } while (ret && message);
+				/* return sets if doing APPENDUID */
+    if (au && ret) (*au) (mailbox,astream->uid_validity,dst);
+    else mail_free_searchset (&dst);
+    mx_unlockindex (astream);	/* unlock index */
+  }
+  MM_NOCRITICAL (astream);	/* release critical */
+  mail_close (astream);
+  return ret;
+}
+
+/* MX mail append single message
+ * Accepts: MAIL stream
+ *	    flags for new message if non-NIL
+ *	    elt with source date if non-NIL
+ *	    stringstruct of message text
+ *	    searchset to place UID
+ * Returns: T if success, NIL if failure
+ */
+
+long mx_append_msg (MAILSTREAM *stream,char *flags,MESSAGECACHE *elt,
+		    STRING *st,SEARCHSET *set)
+{
+  char tmp[MAILTMPLEN];
+  int fd;
+  unsigned long uf;
+  long f = mail_parse_flags (stream,flags,&uf);
+				/* make message file name */
+  sprintf (tmp,"%s/%lu",stream->mailbox,++stream->uid_last);
+  if ((fd = open (tmp,O_WRONLY|O_CREAT|O_EXCL,
+		  (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0) {
+    sprintf (tmp,"Can't create append message: %s",strerror (errno));
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+  while (SIZE (st)) {		/* copy the file */
+    if (st->cursize && (write (fd,st->curpos,st->cursize) < 0)) {
+      unlink (tmp);		/* delete file */
+      close (fd);		/* close the file */
+      sprintf (tmp,"Message append failed: %s",strerror (errno));
+      MM_LOG (tmp,ERROR);
+      return NIL;
+    }
+    SETPOS (st,GETPOS (st) + st->cursize);
+  }
+  close (fd);			/* close the file */
+  if (elt) mx_setdate (tmp,elt);/* set file date */
+				/* swell the cache */
+  mail_exists (stream,++stream->nmsgs);
+				/* copy flags */
+  mail_append_set (set,(elt = mail_elt (stream,stream->nmsgs))->private.uid =
+		   stream->uid_last);
+  if (f&fSEEN) elt->seen = T;
+  if (f&fDELETED) elt->deleted = T;
+  if (f&fFLAGGED) elt->flagged = T;
+  if (f&fANSWERED) elt->answered = T;
+  if (f&fDRAFT) elt->draft = T;
+  elt->user_flags |= uf;
+  return LONGT;
+}
+
+/* Internal routines */
+
+
+/* MX file name selection test
+ * Accepts: candidate directory entry
+ * Returns: T to use file name, NIL to skip it
+ */
+
+int mx_select (struct direct *name)
+{
+  char c;
+  char *s = name->d_name;
+  while (c = *s++) if (!isdigit (c)) return NIL;
+  return T;
+}
+
+
+/* MX file name comparision
+ * Accepts: first candidate directory entry
+ *	    second candidate directory entry
+ * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2
+ */
+
+int mx_numsort (const void *d1,const void *d2)
+{
+  return atoi ((*(struct direct **) d1)->d_name) -
+    atoi ((*(struct direct **) d2)->d_name);
+}
+
+
+/* MX mail build file name
+ * Accepts: destination string
+ *          source
+ * Returns: destination
+ */
+
+char *mx_file (char *dst,char *name)
+{
+  char *s;
+				/* empty string if mailboxfile fails */
+  if (!mailboxfile (dst,name)) *dst = '\0';
+				/* driver-selected INBOX  */
+  else if (!*dst) mailboxfile (dst,"~/INBOX");
+				/* tie off unnecessary trailing / */
+  else if ((s = strrchr (dst,'/')) && !s[1]) *s = '\0';
+  return dst;
+}
+
+/* MX read and lock index
+ * Accepts: MAIL stream
+ * Returns: T if success, NIL if failure
+ */
+
+long mx_lockindex (MAILSTREAM *stream)
+{
+  unsigned long uf,sf,uid;
+  int k = 0;
+  unsigned long msgno = 1;
+  struct stat sbuf;
+  char *s,*t,*idx,tmp[2*MAILTMPLEN];
+  MESSAGECACHE *elt;
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  if ((LOCAL->fd < 0) &&	/* get index file, no-op if already have it */
+      (LOCAL->fd = open (strcat (strcpy (tmp,stream->mailbox),MXINDEXNAME),
+			 O_RDWR|O_CREAT,
+			 (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL)))
+      >= 0) {
+    (*bn) (BLOCK_FILELOCK,NIL);
+    flock (LOCAL->fd,LOCK_EX);	/* get exclusive lock */
+    (*bn) (BLOCK_NONE,NIL);
+    fstat (LOCAL->fd,&sbuf);	/* get size of index */
+				/* slurp index */
+    read (LOCAL->fd,s = idx = (char *) fs_get (sbuf.st_size + 1),sbuf.st_size);
+    idx[sbuf.st_size] = '\0';	/* tie off index */
+				/* parse index */
+    if (sbuf.st_size) while (s && *s) switch (*s) {
+    case 'V':			/* UID validity record */
+      stream->uid_validity = strtoul (s+1,&s,16);
+      break;
+    case 'L':			/* UID last record */
+      stream->uid_last = strtoul (s+1,&s,16);
+      break;
+    case 'K':			/* keyword */
+				/* find end of keyword */
+      if (s = strchr (t = ++s,'\n')) {
+	*s++ = '\0';		/* tie off keyword */
+				/* copy keyword */
+	if ((k < NUSERFLAGS) && !stream->user_flags[k] &&
+	    (strlen (t) <= MAXUSERFLAG)) stream->user_flags[k] = cpystr (t);
+	k++;			/* one more keyword */
+      }
+      break;
+
+    case 'M':			/* message status record */
+      uid = strtoul (s+1,&s,16);/* get UID for this message */
+      if (*s == ';') {		/* get user flags */
+	uf = strtoul (s+1,&s,16);
+	if (*s == '.') {	/* get system flags */
+	  sf = strtoul (s+1,&s,16);
+	  while ((msgno <= stream->nmsgs) && (mail_uid (stream,msgno) < uid))
+	    msgno++;		/* find message number for this UID */
+	  if ((msgno <= stream->nmsgs) && (mail_uid (stream,msgno) == uid)) {
+	    (elt = mail_elt (stream,msgno))->valid = T;
+	    elt->user_flags=uf; /* set user and system flags in elt */
+	    if (sf & fSEEN) elt->seen = T;
+	    if (sf & fDELETED) elt->deleted = T;
+	    if (sf & fFLAGGED) elt->flagged = T;
+	    if (sf & fANSWERED) elt->answered = T;
+	    if (sf & fDRAFT) elt->draft = T;
+	  }
+	  break;
+	}
+      }
+    default:			/* bad news */
+      sprintf (tmp,"Error in index: %.80s",s);
+      MM_LOG (tmp,ERROR);
+      *s = NIL;			/* ignore remainder of index */
+    }
+    else {			/* new index */
+      stream->uid_validity = time (0);
+      user_flags (stream);	/* init stream with default user flags */
+    }
+    fs_give ((void **) &idx);	/* flush index */
+  }
+  return (LOCAL->fd >= 0) ? T : NIL;
+}
+
+/* MX write and unlock index
+ * Accepts: MAIL stream
+ */
+
+#define MXIXBUFLEN 2048
+
+void mx_unlockindex (MAILSTREAM *stream)
+{
+  unsigned long i,j;
+  off_t size = 0;
+  char *s,tmp[MXIXBUFLEN + 64];
+  MESSAGECACHE *elt;
+  if (LOCAL->fd >= 0) {
+    lseek (LOCAL->fd,0,L_SET);	/* rewind file */
+				/* write header */
+    sprintf (s = tmp,"V%08lxL%08lx",stream->uid_validity,stream->uid_last);
+    for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i]; ++i)
+      sprintf (s += strlen (s),"K%s\n",stream->user_flags[i]);
+				/* write messages */
+    for (i = 1; i <= stream->nmsgs; i++) {
+				/* filled buffer? */
+      if (((s += strlen (s)) - tmp) > MXIXBUFLEN) {
+	write (LOCAL->fd,tmp,j = s - tmp);
+	size += j;
+	*(s = tmp) = '\0';	/* dump out and restart buffer */
+      }
+      elt = mail_elt (stream,i);
+      sprintf(s,"M%08lx;%08lx.%04x",elt->private.uid,elt->user_flags,(unsigned)
+	      ((fSEEN * elt->seen) + (fDELETED * elt->deleted) +
+	       (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
+	       (fDRAFT * elt->draft)));
+    }
+				/* write tail end of buffer */
+    if ((s += strlen (s)) != tmp) {
+      write (LOCAL->fd,tmp,j = s - tmp);
+      size += j;
+    }
+    ftruncate (LOCAL->fd,size);
+    flock (LOCAL->fd,LOCK_UN);	/* unlock the index */
+    close (LOCAL->fd);		/* finished with file */
+    LOCAL->fd = -1;		/* no index now */
+  }
+}
+
+/* Set date for message
+ * Accepts: file name
+ *	    elt containing date
+ */
+
+void mx_setdate (char *file,MESSAGECACHE *elt)
+{
+  time_t tp[2];
+  tp[0] = time (0);		/* atime is now */
+  tp[1] = mail_longdate (elt);	/* modification time */
+  utime (file,tp);		/* set the times */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/news.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,738 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	News routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	4 September 1991
+ * Last Edited:	30 January 2007
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "mail.h"
+#include "osdep.h"
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "misc.h"
+#include "newsrc.h"
+#include "fdstring.h"
+
+
+/* news_load_message() flags */
+
+#define NLM_HEADER 0x1		/* load message text */
+#define NLM_TEXT 0x2		/* load message text */
+
+/* NEWS I/O stream local data */
+	
+typedef struct news_local {
+  unsigned int dirty : 1;	/* disk copy of .newsrc needs updating */
+  char *dir;			/* spool directory name */
+  char *name;			/* local mailbox name */
+  unsigned char buf[CHUNKSIZE];	/* scratch buffer */
+  unsigned long cachedtexts;	/* total size of all cached texts */
+} NEWSLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((NEWSLOCAL *) stream->local)
+
+
+/* Function prototypes */
+
+DRIVER *news_valid (char *name);
+DRIVER *news_isvalid (char *name,char *mbx);
+void *news_parameters (long function,void *value);
+void news_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void news_list (MAILSTREAM *stream,char *ref,char *pat);
+void news_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long news_canonicalize (char *ref,char *pat,char *pattern);
+long news_subscribe (MAILSTREAM *stream,char *mailbox);
+long news_unsubscribe (MAILSTREAM *stream,char *mailbox);
+long news_create (MAILSTREAM *stream,char *mailbox);
+long news_delete (MAILSTREAM *stream,char *mailbox);
+long news_rename (MAILSTREAM *stream,char *old,char *newname);
+MAILSTREAM *news_open (MAILSTREAM *stream);
+int news_select (struct direct *name);
+int news_numsort (const void *d1,const void *d2);
+void news_close (MAILSTREAM *stream,long options);
+void news_fast (MAILSTREAM *stream,char *sequence,long flags);
+void news_flags (MAILSTREAM *stream,char *sequence,long flags);
+void news_load_message (MAILSTREAM *stream,unsigned long msgno,long flags);
+char *news_header (MAILSTREAM *stream,unsigned long msgno,
+		   unsigned long *length,long flags);
+long news_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+void news_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
+long news_ping (MAILSTREAM *stream);
+void news_check (MAILSTREAM *stream);
+long news_expunge (MAILSTREAM *stream,char *sequence,long options);
+long news_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long news_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+/* News routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER newsdriver = {
+  "news",			/* driver name */
+				/* driver flags */
+  DR_NEWS|DR_READONLY|DR_NOFAST|DR_NAMESPACE|DR_NONEWMAIL|DR_DIRFMT,
+  (DRIVER *) NIL,		/* next driver */
+  news_valid,			/* mailbox is valid for us */
+  news_parameters,		/* manipulate parameters */
+  news_scan,			/* scan mailboxes */
+  news_list,			/* find mailboxes */
+  news_lsub,			/* find subscribed mailboxes */
+  news_subscribe,		/* subscribe to mailbox */
+  news_unsubscribe,		/* unsubscribe from mailbox */
+  news_create,			/* create mailbox */
+  news_delete,			/* delete mailbox */
+  news_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  news_open,			/* open mailbox */
+  news_close,			/* close mailbox */
+  news_fast,			/* fetch message "fast" attributes */
+  news_flags,			/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  news_header,			/* fetch message header */
+  news_text,			/* fetch message body */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  NIL,				/* modify flags */
+  news_flagmsg,			/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  news_ping,			/* ping mailbox to see if still alive */
+  news_check,			/* check for new messages */
+  news_expunge,			/* expunge deleted messages */
+  news_copy,			/* copy messages to another mailbox */
+  news_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM newsproto = {&newsdriver};
+
+/* News validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *news_valid (char *name)
+{
+  int fd;
+  char *s,*t,*u;
+  struct stat sbuf;
+  if ((name[0] == '#') && (name[1] == 'n') && (name[2] == 'e') &&
+      (name[3] == 'w') && (name[4] == 's') && (name[5] == '.') &&
+      !strchr (name,'/') &&
+      !stat ((char *) mail_parameters (NIL,GET_NEWSSPOOL,NIL),&sbuf) &&
+      ((fd = open ((char *) mail_parameters (NIL,GET_NEWSACTIVE,NIL),O_RDONLY,
+		   NIL)) >= 0)) {
+    fstat (fd,&sbuf);		/* get size of active file */
+				/* slurp in active file */
+    read (fd,t = s = (char *) fs_get (sbuf.st_size+1),sbuf.st_size);
+    s[sbuf.st_size] = '\0';	/* tie off file */
+    close (fd);			/* flush file */
+    while (*t && (u = strchr (t,' '))) {
+      *u++ = '\0';		/* tie off at end of name */
+      if (!strcmp (name+6,t)) {
+	fs_give ((void **) &s);	/* flush data */
+	return &newsdriver;
+      }
+      t = 1 + strchr (u,'\n');	/* next line */
+    }
+    fs_give ((void **) &s);	/* flush data */
+  }
+  return NIL;			/* return status */
+}
+
+/* News manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *news_parameters (long function,void *value)
+{
+  return (function == GET_NEWSRC) ? env_parameters (function,value) : NIL;
+}
+
+
+/* News scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void news_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  char tmp[MAILTMPLEN];
+  if (news_canonicalize (ref,pat,tmp))
+    mm_log ("Scan not valid for news mailboxes",ERROR);
+}
+
+/* News find list of newsgroups
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void news_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  int fd;
+  int i;
+  char *s,*t,*u,*r,pattern[MAILTMPLEN],name[MAILTMPLEN];
+  struct stat sbuf;
+  if (!pat || !*pat) {		/* empty pattern? */
+    if (news_canonicalize (ref,"*",pattern)) {
+				/* tie off name at root */
+      if (s = strchr (pattern,'.')) *++s = '\0';
+      else pattern[0] = '\0';
+      mm_list (stream,'.',pattern,LATT_NOSELECT);
+    }
+  }
+  else if (news_canonicalize (ref,pat,pattern) &&
+	   !stat ((char *) mail_parameters (NIL,GET_NEWSSPOOL,NIL),&sbuf) &&
+	   ((fd = open ((char *) mail_parameters (NIL,GET_NEWSACTIVE,NIL),
+			O_RDONLY,NIL)) >= 0)) {
+    fstat (fd,&sbuf);		/* get file size and read data */
+    read (fd,s = (char *) fs_get (sbuf.st_size + 1),sbuf.st_size);
+    close (fd);			/* close file */
+    s[sbuf.st_size] = '\0';	/* tie off string */
+    strcpy (name,"#news.");	/* write initial prefix */
+    i = strlen (pattern);	/* length of pattern */
+    if (pattern[--i] != '%') i = 0;
+    if (t = strtok_r (s,"\n",&r)) do if (u = strchr (t,' ')) {
+      *u = '\0';		/* tie off at end of name */
+      strcpy (name + 6,t);	/* make full form of name */
+      if (pmatch_full (name,pattern,'.')) mm_list (stream,'.',name,NIL);
+      else if (i && (u = strchr (name + i,'.'))) {
+	*u = '\0';		/* tie off at delimiter, see if matches */
+	if (pmatch_full (name,pattern,'.'))
+	  mm_list (stream,'.',name,LATT_NOSELECT);
+      }
+    } while (t = strtok_r (NIL,"\n",&r));
+    fs_give ((void **) &s);
+  }
+}
+
+/* News find list of subscribed newsgroups
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void news_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  char pattern[MAILTMPLEN];
+				/* return data from newsrc */
+  if (news_canonicalize (ref,pat,pattern)) newsrc_lsub (stream,pattern);
+}
+
+
+/* News canonicalize newsgroup name
+ * Accepts: reference
+ *	    pattern
+ *	    returned single pattern
+ * Returns: T on success, NIL on failure
+ */
+
+long news_canonicalize (char *ref,char *pat,char *pattern)
+{
+  unsigned long i;
+  char *s;
+  if (ref && *ref) {		/* have a reference */
+    strcpy (pattern,ref);	/* copy reference to pattern */
+				/* # overrides mailbox field in reference */
+    if (*pat == '#') strcpy (pattern,pat);
+				/* pattern starts, reference ends, with . */
+    else if ((*pat == '.') && (pattern[strlen (pattern) - 1] == '.'))
+      strcat (pattern,pat + 1);	/* append, omitting one of the period */
+    else strcat (pattern,pat);	/* anything else is just appended */
+  }
+  else strcpy (pattern,pat);	/* just have basic name */
+  if ((pattern[0] == '#') && (pattern[1] == 'n') && (pattern[2] == 'e') &&
+      (pattern[3] == 'w') && (pattern[4] == 's') && (pattern[5] == '.') &&
+      !strchr (pattern,'/')) {	/* count wildcards */
+    for (i = 0, s = pattern; *s; *s++) if ((*s == '*') || (*s == '%')) ++i;
+				/* success if not too many */
+    if (i <= MAXWILDCARDS) return LONGT;
+    MM_LOG ("Excessive wildcards in LIST/LSUB",ERROR);
+  }
+  return NIL;
+}
+
+/* News subscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to add to subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long news_subscribe (MAILSTREAM *stream,char *mailbox)
+{
+  return news_valid (mailbox) ? newsrc_update (stream,mailbox+6,':') : NIL;
+}
+
+
+/* NEWS unsubscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to delete from subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long news_unsubscribe (MAILSTREAM *stream,char *mailbox)
+{
+  return news_valid (mailbox) ? newsrc_update (stream,mailbox+6,'!') : NIL;
+}
+
+/* News create mailbox
+ * Accepts: mail stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long news_create (MAILSTREAM *stream,char *mailbox)
+{
+  return NIL;			/* never valid for News */
+}
+
+
+/* News delete mailbox
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long news_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return NIL;			/* never valid for News */
+}
+
+
+/* News rename mailbox
+ * Accepts: mail stream
+ *	    old mailbox name
+ *	    new mailbox name
+ * Returns: T on success, NIL on failure
+ */
+
+long news_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  return NIL;			/* never valid for News */
+}
+
+/* News open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *news_open (MAILSTREAM *stream)
+{
+  long i,nmsgs;
+  char *s,tmp[MAILTMPLEN];
+  struct direct **names = NIL;
+  				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return &newsproto;
+  if (stream->local) fatal ("news recycle stream");
+				/* build directory name */
+  sprintf (s = tmp,"%s/%s",(char *) mail_parameters (NIL,GET_NEWSSPOOL,NIL),
+	   stream->mailbox + 6);
+  while (s = strchr (s,'.')) *s = '/';
+				/* scan directory */
+  if ((nmsgs = scandir (tmp,&names,news_select,news_numsort)) >= 0) {
+    mail_exists (stream,nmsgs);	/* notify upper level that messages exist */
+    stream->local = fs_get (sizeof (NEWSLOCAL));
+    LOCAL->dirty = NIL;		/* no update to .newsrc needed yet */
+    LOCAL->dir = cpystr (tmp);	/* copy directory name for later */
+    LOCAL->name = cpystr (stream->mailbox + 6);
+    for (i = 0; i < nmsgs; ++i) {
+      stream->uid_last = mail_elt (stream,i+1)->private.uid =
+	atoi (names[i]->d_name);
+      fs_give ((void **) &names[i]);
+    }
+    s = (void *) names;		/* stupid language */
+    fs_give ((void **) &s);	/* free directory */
+    LOCAL->cachedtexts = 0;	/* no cached texts */
+    stream->sequence++;		/* bump sequence number */
+    stream->rdonly = stream->perm_deleted = T;
+				/* UIDs are always valid */
+    stream->uid_validity = 0xbeefface;
+				/* read .newsrc entries */
+    mail_recent (stream,newsrc_read (LOCAL->name,stream));
+				/* notify if empty newsgroup */
+    if (!(stream->nmsgs || stream->silent)) {
+      sprintf (tmp,"Newsgroup %s is empty",LOCAL->name);
+      mm_log (tmp,WARN);
+    }
+  }
+  else mm_log ("Unable to scan newsgroup spool directory",ERROR);
+  return LOCAL ? stream : NIL;	/* if stream is alive, return to caller */
+}
+
+/* News file name selection test
+ * Accepts: candidate directory entry
+ * Returns: T to use file name, NIL to skip it
+ */
+
+int news_select (struct direct *name)
+{
+  char c;
+  char *s = name->d_name;
+  while (c = *s++) if (!isdigit (c)) return NIL;
+  return T;
+}
+
+
+/* News file name comparision
+ * Accepts: first candidate directory entry
+ *	    second candidate directory entry
+ * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2
+ */
+
+int news_numsort (const void *d1,const void *d2)
+{
+  return atoi ((*(struct direct **) d1)->d_name) -
+    atoi ((*(struct direct **) d2)->d_name);
+}
+
+
+/* News close
+ * Accepts: MAIL stream
+ *	    option flags
+ */
+
+void news_close (MAILSTREAM *stream,long options)
+{
+  if (LOCAL) {			/* only if a file is open */
+    news_check (stream);	/* dump final checkpoint */
+    if (LOCAL->dir) fs_give ((void **) &LOCAL->dir);
+    if (LOCAL->name) fs_give ((void **) &LOCAL->name);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+/* News fetch fast information
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ */
+
+void news_fast (MAILSTREAM *stream,char *sequence,long flags)
+{
+  MESSAGECACHE *elt;
+  unsigned long i;
+				/* set up metadata for all messages */
+  if (stream && LOCAL && ((flags & FT_UID) ?
+			  mail_uid_sequence (stream,sequence) :
+			  mail_sequence (stream,sequence)))
+    for (i = 1; i <= stream->nmsgs; i++)
+      if ((elt = mail_elt (stream,i))->sequence &&
+	  !(elt->day && elt->rfc822_size)) news_load_message (stream,i,NIL);
+}
+
+
+/* News fetch flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ */
+
+void news_flags (MAILSTREAM *stream,char *sequence,long flags)
+{
+  unsigned long i;
+  if ((flags & FT_UID) ?	/* validate all elts */
+      mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))
+    for (i = 1; i <= stream->nmsgs; i++) mail_elt (stream,i)->valid = T;
+}
+
+/* News load message into cache
+ * Accepts: MAIL stream
+ *	    message #
+ *	    option flags
+ */
+
+void news_load_message (MAILSTREAM *stream,unsigned long msgno,long flags)
+{
+  unsigned long i,j,nlseen;
+  int fd;
+  unsigned char c,*t;
+  struct stat sbuf;
+  MESSAGECACHE *elt;
+  FDDATA d;
+  STRING bs;
+  elt = mail_elt (stream,msgno);/* get elt */
+				/* build message file name */
+  sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid);
+				/* anything we need not currently cached? */
+  if ((!elt->day || !elt->rfc822_size ||
+       ((flags & NLM_HEADER) && !elt->private.msg.header.text.data) ||
+       ((flags & NLM_TEXT) && !elt->private.msg.text.text.data)) &&
+      ((fd = open (LOCAL->buf,O_RDONLY,NIL)) >= 0)) {
+    fstat (fd,&sbuf);		/* get file metadata */
+    d.fd = fd;			/* set up file descriptor */
+    d.pos = 0;			/* start of file */
+    d.chunk = LOCAL->buf;
+    d.chunksize = CHUNKSIZE;
+    INIT (&bs,fd_string,&d,sbuf.st_size);
+    if (!elt->day) {		/* set internaldate to file date */
+      struct tm *tm = gmtime (&sbuf.st_mtime);
+      elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1;
+      elt->year = tm->tm_year + 1900 - BASEYEAR;
+      elt->hours = tm->tm_hour; elt->minutes = tm->tm_min;
+      elt->seconds = tm->tm_sec;
+      elt->zhours = 0; elt->zminutes = 0;
+    }
+
+    if (!elt->rfc822_size) {	/* know message size yet? */
+      for (i = 0, j = SIZE (&bs), nlseen = 0; j--; ) switch (SNX (&bs)) {
+      case '\015':		/* unlikely carriage return */
+	if (!j || (CHR (&bs) != '\012')) {
+	  i++;			/* ugh, raw CR */
+	  nlseen = NIL;
+	  break;
+	}
+	SNX (&bs);		/* eat the line feed, drop in */
+      case '\012':		/* line feed? */
+	i += 2;			/* count a CRLF */
+				/* header size known yet? */
+	if (!elt->private.msg.header.text.size && nlseen) {
+				/* note position in file */
+	  elt->private.special.text.size = GETPOS (&bs);
+				/* and CRLF-adjusted size */
+	  elt->private.msg.header.text.size = i;
+	}
+	nlseen = T;		/* note newline seen */
+	break;
+      default:			/* ordinary chararacter */
+	i++;
+	nlseen = NIL;
+	break;
+      }
+      SETPOS (&bs,0);		/* restore old position */
+      elt->rfc822_size = i;	/* note that we have size now */
+				/* header is entire message if no delimiter */
+      if (!elt->private.msg.header.text.size)
+	elt->private.msg.header.text.size = elt->rfc822_size;
+				/* text is remainder of message */
+      elt->private.msg.text.text.size =
+	elt->rfc822_size - elt->private.msg.header.text.size;
+    }
+
+				/* need to load cache with message data? */
+    if (((flags & NLM_HEADER) && !elt->private.msg.header.text.data) ||
+	((flags & NLM_TEXT) && !elt->private.msg.text.text.data)) {
+				/* purge cache if too big */
+      if (LOCAL->cachedtexts > max (stream->nmsgs * 4096,2097152)) {
+				/* just can't keep that much */
+	mail_gc (stream,GC_TEXTS);
+	LOCAL->cachedtexts = 0;
+      }
+      if ((flags & NLM_HEADER) && !elt->private.msg.header.text.data) {
+	t = elt->private.msg.header.text.data =
+	  (unsigned char *) fs_get (elt->private.msg.header.text.size + 1);
+	LOCAL->cachedtexts += elt->private.msg.header.text.size;
+				/* read in message header */
+	for (i = 0; i <= elt->private.msg.header.text.size; i++)
+	  switch (c = SNX (&bs)) {
+	  case '\015':		/* unlikely carriage return */
+	    *t++ = c;
+	    if ((CHR (&bs) == '\012')) *t++ = SNX (&bs);
+	    break;
+	  case '\012':		/* line feed? */
+	    *t++ = '\015';
+	  default:
+	    *t++ = c;
+	    break;
+	  }
+	*t = '\0';		/* tie off string */
+      }
+      if ((flags & NLM_TEXT) && !elt->private.msg.text.text.data) {
+	t = elt->private.msg.text.text.data =
+	  (unsigned char *) fs_get (elt->private.msg.text.text.size + 1);
+	SETPOS (&bs,elt->private.msg.header.text.size);
+	LOCAL->cachedtexts += elt->private.msg.text.text.size;
+				/* read in message text */
+	for (i = 0; i <= elt->private.msg.text.text.size; i++)
+	  switch (c = SNX (&bs)) {
+	  case '\015':		/* unlikely carriage return */
+	    *t++ = c;
+	    if ((CHR (&bs) == '\012')) *t++ = SNX (&bs);
+	    break;
+	  case '\012':		/* line feed? */
+	    *t++ = '\015';
+	  default:
+	    *t++ = c;
+	    break;
+	  }
+	*t = '\0';		/* tie off string */
+      }
+    }
+    close (fd);			/* flush message file */
+  }
+}
+
+/* News fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+char *news_header (MAILSTREAM *stream,unsigned long msgno,
+		   unsigned long *length,long flags)
+{
+  MESSAGECACHE *elt;
+  *length = 0;			/* default to empty */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+  elt = mail_elt (stream,msgno);/* get elt */
+  if (!elt->private.msg.header.text.data)
+    news_load_message (stream,msgno,NLM_HEADER);
+  *length = elt->private.msg.header.text.size;
+  return (char *) elt->private.msg.header.text.data;
+}
+
+
+/* News fetch message text (body only)
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned stringstruct
+ *	    option flags
+ * Returns: T on success, NIL on failure
+ */
+
+long news_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  MESSAGECACHE *elt;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+  elt = mail_elt (stream,msgno);/* get elt */
+				/* snarf message if don't have it yet */
+  if (!elt->private.msg.text.text.data) {
+    news_load_message (stream,msgno,NLM_TEXT);
+    if (!elt->private.msg.text.text.data) return NIL;
+  }
+  if (!(flags & FT_PEEK)) {	/* mark as seen */
+    mail_elt (stream,msgno)->seen = T;
+    mm_flags (stream,msgno);
+  }
+  INIT (bs,mail_string,elt->private.msg.text.text.data,
+	elt->private.msg.text.text.size);
+  return T;
+}
+
+/* News per-message modify flag
+ * Accepts: MAIL stream
+ *	    message cache element
+ */
+
+void news_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  if (!LOCAL->dirty) {		/* only bother checking if not dirty yet */
+    if (elt->valid) {		/* if done, see if deleted changed */
+      if (elt->sequence != elt->deleted) LOCAL->dirty = T;
+      elt->sequence = T;	/* leave the sequence set */
+    }
+				/* note current setting of deleted flag */
+    else elt->sequence = elt->deleted;
+  }
+}
+
+
+/* News ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ */
+
+long news_ping (MAILSTREAM *stream)
+{
+  return T;			/* always alive */
+}
+
+
+/* News check mailbox
+ * Accepts: MAIL stream
+ */
+
+void news_check (MAILSTREAM *stream)
+{
+				/* never do if no updates */
+  if (LOCAL->dirty) newsrc_write (LOCAL->name,stream);
+  LOCAL->dirty = NIL;
+}
+
+
+/* News expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T if success, NIL if failure
+ */
+
+long news_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  if (!stream->silent) mm_log ("Expunge ignored on readonly mailbox",NIL);
+  return LONGT;
+}
+
+/* News copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    option flags
+ * Returns: T if copy successful, else NIL
+ */
+
+long news_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+  if (pc) return (*pc) (stream,sequence,mailbox,options);
+  mm_log ("Copy not valid for News",ERROR);
+  return NIL;
+}
+
+
+/* News append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback function
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long news_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  mm_log ("Append not valid for news",ERROR);
+  return NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/nl_ami.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,92 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX/VMS newline routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Copy string with CRLF newlines
+ * Accepts: destination string
+ *	    pointer to size of destination string buffer
+ *	    source string
+ *	    length of source string
+ * Returns: length of copied string
+ */
+
+unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl,
+			  unsigned char *src,unsigned long srcl)
+{
+  long i = srcl * 2,j;
+  unsigned char c,*d = src;
+  if (*dst) {			/* candidate destination provided? */
+				/* count NLs if doesn't fit worst-case */
+    if (i > *dstl) for (i = j = srcl; j; --j) if (*d++ == '\012') i++;
+				/* still too small, must reset destination */
+    if (i > *dstl) fs_give ((void **) dst);
+  }
+				/* make a new buffer if needed */
+  if (!*dst) *dst = (char *) fs_get ((*dstl = i) + 1);
+  d = *dst;			/* destination string */
+  if (srcl) do {		/* main copy loop */
+    if ((c = *src++) < '\016') {
+				/* prepend CR to LF */
+      if (c == '\012') *d++ = '\015';
+				/* unlikely CR */
+      else if ((c == '\015') && (srcl > 1) && (*src == '\012')) {
+	*d++ = c;		/* copy the CR */
+	c = *src++;		/* grab the LF */
+	--srcl;			/* adjust the count */
+      }
+    }
+    *d++ = c;			/* copy character */
+  } while (--srcl);
+  *d = '\0';			/* tie off destination */
+  return d - *dst;		/* return length */
+}
+
+/* Length of string after strcrlfcpy applied
+ * Accepts: source string
+ * Returns: length of string
+ */
+
+unsigned long strcrlflen (STRING *s)
+{
+  unsigned long pos = GETPOS (s);
+  unsigned long i = SIZE (s);
+  unsigned long j = i;
+  while (j--) switch (SNX (s)) {/* search for newlines */
+  case '\015':			/* unlikely carriage return */
+    if (j && (CHR (s) == '\012')) {
+      SNX (s);			/* eat the line feed */
+      j--;
+    }
+    break;
+  case '\012':			/* line feed? */
+    i++;
+  default:			/* ordinary chararacter */
+    break;
+  }
+  SETPOS (s,pos);		/* restore old position */
+  return i;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/os_ami.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,80 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Amiga version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	30 August 2006
+ */
+
+#define PINE		       /* to get full DIR description in <dirent.h> */
+#include "tcp_ami.h"           /* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+#define DIR_SIZE(d) d->d_reclen /* for scandir.c */
+
+#include "fs_ami.c"
+#include "ftl_ami.c"
+#include "nl_ami.c"
+#include "env_ami.c"
+#include "tcp_ami.c"
+#include "log_std.c"
+#include "gr_waitp.c"
+#include "tz_bsd.c"
+#include "scandir.c"
+#include "gethstid.c"
+
+#undef utime
+
+/* Amiga has its own wierd utime() with an incompatible struct utimbuf that
+ * does not match with the traditional time_t [2].
+ */
+
+/* Portable utime() that takes it args like real Unix systems
+ * Accepts: file path
+ *	    traditional utime() argument
+ * Returns: utime() results
+ */
+
+int portable_utime (char *file,time_t timep[2])
+{
+  struct utimbuf times;
+  times.actime = timep[0];	/* copy the portable values */
+  times.modtime = timep[1];
+  return utime (file,&times);	/* now call Amiga's routine */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/os_ami.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,54 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Amiga version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	15 September 2006
+ */
+
+#include <proto/socket.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/file.h>
+
+/* Different names, equivalent things in BSD and SysV */
+
+#define direct dirent
+#define utime portable_utime
+int portable_utime (char *file,time_t timep[2]);
+
+#include "env_ami.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+
+long gethostid (void);
+typedef int (*select_t) (struct direct *name);
+typedef int (*compar_t) (void *d1,void *d2);
+int scandir (char *dirname,struct direct ***namelist,select_t select,
+	     compar_t compar);
+int alphasort (void *d1,void *d2);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/phile.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,553 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	File routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	25 August 1993
+ * Last Edited:	9 May 2006
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <signal.h>
+#include "mail.h"
+#include "osdep.h"
+#include <pwd.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "rfc822.h"
+#include "misc.h"
+#include "dummy.h"
+
+/* Types returned from phile_type() */
+
+#define PTYPEBINARY 0		/* binary data */
+#define PTYPETEXT 1		/* textual data */
+#define PTYPECRTEXT 2		/* textual data with CR */
+#define PTYPE8 4		/* textual 8bit data */
+#define PTYPEISO2022JP 8	/* textual Japanese */
+#define PTYPEISO2022KR 16	/* textual Korean */
+#define PTYPEISO2022CN 32	/* textual Chinese */
+
+
+/* PHILE I/O stream local data */
+	
+typedef struct phile_local {
+  ENVELOPE *env;		/* file envelope */
+  BODY *body;			/* file body */
+  char tmp[MAILTMPLEN];		/* temporary buffer */
+} PHILELOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((PHILELOCAL *) stream->local)
+
+
+/* Function prototypes */
+
+DRIVER *phile_valid (char *name);
+int phile_isvalid (char *name,char *tmp);
+void *phile_parameters (long function,void *value);
+void phile_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void phile_list (MAILSTREAM *stream,char *ref,char *pat);
+void phile_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long phile_create (MAILSTREAM *stream,char *mailbox);
+long phile_delete (MAILSTREAM *stream,char *mailbox);
+long phile_rename (MAILSTREAM *stream,char *old,char *newname);
+long phile_status (MAILSTREAM *stream,char *mbx,long flags);
+MAILSTREAM *phile_open (MAILSTREAM *stream);
+int phile_type (unsigned char *s,unsigned long i,unsigned long *j);
+void phile_close (MAILSTREAM *stream,long options);
+ENVELOPE *phile_structure (MAILSTREAM *stream,unsigned long msgno,BODY **body,
+			   long flags);
+char *phile_header (MAILSTREAM *stream,unsigned long msgno,
+		    unsigned long *length,long flags);
+long phile_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+long phile_ping (MAILSTREAM *stream);
+void phile_check (MAILSTREAM *stream);
+long phile_expunge (MAILSTREAM *stream,char *sequence,long options);
+long phile_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long phile_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+/* File routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER philedriver = {
+  "phile",			/* driver name */
+				/* driver flags */
+  DR_LOCAL|DR_READONLY|DR_NOSTICKY,
+  (DRIVER *) NIL,		/* next driver */
+  phile_valid,			/* mailbox is valid for us */
+  phile_parameters,		/* manipulate parameters */
+  phile_scan,			/* scan mailboxes */
+  phile_list,			/* list mailboxes */
+  phile_lsub,			/* list subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  dummy_create,			/* create mailbox */
+  dummy_delete,			/* delete mailbox */
+  dummy_rename,			/* rename mailbox */
+  phile_status,			/* status of mailbox */
+  phile_open,			/* open mailbox */
+  phile_close,			/* close mailbox */
+  NIL,				/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  phile_structure,		/* fetch message envelopes */
+  phile_header,			/* fetch message header only */
+  phile_text,			/* fetch message body only */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  NIL,				/* modify flags */
+  NIL,				/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  phile_ping,			/* ping mailbox to see if still alive */
+  phile_check,			/* check for new messages */
+  phile_expunge,		/* expunge deleted messages */
+  phile_copy,			/* copy messages to another mailbox */
+  phile_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM phileproto = {&philedriver};
+
+/* File validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *phile_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+  return phile_isvalid (name,tmp) ? &philedriver : NIL;
+}
+
+
+/* File test for valid mailbox
+ * Accepts: mailbox name
+ * Returns: T if valid, NIL otherwise
+ */
+
+int phile_isvalid (char *name,char *tmp)
+{
+  struct stat sbuf;
+  char *s;
+				/* INBOX never accepted, any other name is */
+  return ((s = mailboxfile (tmp,name)) && *s && !stat (s,&sbuf) &&
+	  !(sbuf.st_mode & S_IFDIR) &&
+				/* only allow empty files if no empty proto
+				   or if #ftp */
+	  (sbuf.st_size || !default_proto (T) ||
+	   ((*name == '#') && ((name[1] == 'f') || (name[1] == 'F')) &&
+	    ((name[2] == 't') || (name[2] == 'T')) &&
+	    ((name[3] == 'p') || (name[3] == 'P')) && (name[4] == '/'))));
+}
+
+/* File manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *phile_parameters (long function,void *value)
+{
+  return NIL;
+}
+
+/* File mail scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void phile_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* File list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void phile_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_list (NIL,ref,pat);
+}
+
+
+/* File list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void phile_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_lsub (NIL,ref,pat);
+}
+
+
+/* File status
+ * Accepts: mail stream
+ *	    mailbox name
+ *	    status flags
+ * Returns: T on success, NIL on failure
+ */
+
+long phile_status (MAILSTREAM *stream,char *mbx,long flags)
+{
+  char *s,tmp[MAILTMPLEN];
+  MAILSTATUS status;
+  struct stat sbuf;
+  long ret = NIL;
+  if ((s = mailboxfile (tmp,mbx)) && *s && !stat (s,&sbuf)) {
+    status.flags = flags;	/* return status values */
+    status.unseen = (stream && mail_elt (stream,1)->seen) ? 0 : 1;
+    status.messages = status.recent = status.uidnext = 1;
+    status.uidvalidity = sbuf.st_mtime;
+				/* pass status to main program */
+    mm_status (stream,mbx,&status);
+    ret = LONGT;		/* success */
+  }
+  return ret;
+}
+
+/* File open
+ * Accepts: Stream to open
+ * Returns: Stream on success, NIL on failure
+ */
+
+MAILSTREAM *phile_open (MAILSTREAM *stream)
+{
+  int i,k,fd;
+  unsigned long j,m;
+  char *s,tmp[MAILTMPLEN];
+  struct passwd *pw;
+  struct stat sbuf;
+  struct tm *t;
+  MESSAGECACHE *elt;
+  SIZEDTEXT *buf;
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return &phileproto;
+  if (stream->local) fatal ("phile recycle stream");
+				/* open associated file */
+  if (!mailboxfile (tmp,stream->mailbox) || !tmp[0] || stat (tmp,&sbuf) ||
+      (fd = open (tmp,O_RDONLY,NIL)) < 0) {
+    sprintf (tmp,"Unable to open file %s",stream->mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+  fs_give ((void **) &stream->mailbox);
+  stream->mailbox = cpystr (tmp);
+  stream->local = fs_get (sizeof (PHILELOCAL));
+  mail_exists (stream,1);	/* make sure upper level knows */
+  mail_recent (stream,1);
+  elt = mail_elt (stream,1);	/* instantiate cache element */
+  elt->valid = elt->recent = T;	/* mark valid flags */
+  stream->sequence++;		/* bump sequence number */
+  stream->rdonly = T;		/* make sure upper level knows readonly */
+				/* instantiate a new envelope and body */
+  LOCAL->env = mail_newenvelope ();
+  LOCAL->body = mail_newbody ();
+
+  t = gmtime (&sbuf.st_mtime);	/* get UTC time and Julian day */
+  i = t->tm_hour * 60 + t->tm_min;
+  k = t->tm_yday;
+  t = localtime(&sbuf.st_mtime);/* get local time */
+				/* calculate time delta */
+  i = t->tm_hour * 60 + t->tm_min - i;
+  if (k = t->tm_yday - k) i += ((k < 0) == (abs (k) == 1)) ? -24*60 : 24*60;
+  k = abs (i);			/* time from UTC either way */
+  elt->hours = t->tm_hour; elt->minutes = t->tm_min; elt->seconds = t->tm_sec;
+  elt->day = t->tm_mday; elt->month = t->tm_mon + 1;
+  elt->year = t->tm_year - (BASEYEAR - 1900);
+  elt->zoccident = (k == i) ? 0 : 1;
+  elt->zhours = k/60;
+  elt->zminutes = k % 60;
+  sprintf (tmp,"%s, %d %s %d %02d:%02d:%02d %c%02d%02d",
+	   days[t->tm_wday],t->tm_mday,months[t->tm_mon],t->tm_year+1900,
+	   t->tm_hour,t->tm_min,t->tm_sec,elt->zoccident ? '-' : '+',
+	   elt->zhours,elt->zminutes);
+				/* set up Date field */
+  LOCAL->env->date = cpystr (tmp);
+
+				/* fill in From field from file owner */
+  LOCAL->env->from = mail_newaddr ();
+  if (pw = getpwuid (sbuf.st_uid)) strcpy (tmp,pw->pw_name);
+  else sprintf (tmp,"User-Number-%ld",(long) sbuf.st_uid);
+  LOCAL->env->from->mailbox = cpystr (tmp);
+  LOCAL->env->from->host = cpystr (mylocalhost ());
+				/* set subject to be mailbox name */
+  LOCAL->env->subject = cpystr (stream->mailbox);
+				/* slurp the data */
+  (buf = &elt->private.special.text)->size = sbuf.st_size;
+  read (fd,buf->data = (unsigned char *) fs_get (buf->size + 1),buf->size);
+  buf->data[buf->size] = '\0';
+  close (fd);			/* close the file */
+				/* analyze data type */
+  if (i = phile_type (buf->data,buf->size,&j)) {
+    LOCAL->body->type = TYPETEXT;
+    LOCAL->body->subtype = cpystr ("PLAIN");
+    if (!(i & PTYPECRTEXT)) {	/* change Internet newline format as needed */
+      s = (char *) buf->data;	/* make copy of UNIX-format string */
+      buf->data = NIL;		/* zap the buffer */
+      buf->size = strcrlfcpy (&buf->data,&m,s,buf->size);
+      fs_give ((void **) &s);	/* flush original UNIX-format string */
+    }
+    LOCAL->body->parameter = mail_newbody_parameter ();
+    LOCAL->body->parameter->attribute = cpystr ("charset");
+    LOCAL->body->parameter->value =
+      cpystr ((i & PTYPEISO2022JP) ? "ISO-2022-JP" :
+	      (i & PTYPEISO2022KR) ? "ISO-2022-KR" :
+	      (i & PTYPEISO2022CN) ? "ISO-2022-CN" :
+	      (i & PTYPE8) ? "X-UNKNOWN" : "US-ASCII");
+    LOCAL->body->encoding = (i & PTYPE8) ? ENC8BIT : ENC7BIT;
+    LOCAL->body->size.lines = j;
+  }
+  else {			/* binary data */
+    LOCAL->body->type = TYPEAPPLICATION;
+    LOCAL->body->subtype = cpystr ("OCTET-STREAM");
+    LOCAL->body->parameter = mail_newbody_parameter ();
+    LOCAL->body->parameter->attribute = cpystr ("name");
+    LOCAL->body->parameter->value =
+      cpystr ((s = (strrchr (stream->mailbox,'/'))) ? s+1 : stream->mailbox);
+    LOCAL->body->encoding = ENCBASE64;
+    buf->data = rfc822_binary (s = (char *) buf->data,buf->size,&buf->size);
+    fs_give ((void **) &s);	/* flush originary binary contents */
+  }
+  phile_header (stream,1,&j,NIL);
+  LOCAL->body->size.bytes = LOCAL->body->contents.text.size = buf->size;
+  elt->rfc822_size = j + buf->size;
+				/* only one message ever... */
+  stream->uid_validity = sbuf.st_mtime;
+  stream->uid_last = elt->private.uid = 1;
+  return stream;		/* return stream alive to caller */
+}
+
+/* File determine data type
+ * Accepts: data to examine
+ *	    size of data
+ *	    pointer to line count return
+ * Returns: PTYPE mask of data type
+ */
+
+int phile_type (unsigned char *s,unsigned long i,unsigned long *j)
+{
+  int ret = PTYPETEXT;
+  char *charvec = "bbbbbbbaaalaacaabbbbbbbbbbbebbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
+  *j = 0;			/* no lines */
+				/* check type of every character */
+  while (i--) switch (charvec[*s++]) {
+  case 'A':
+    ret |= PTYPE8;		/* 8bit character */
+    break;
+  case 'a':
+    break;			/* ASCII character */
+  case 'b':
+    return PTYPEBINARY;		/* binary byte seen, stop immediately */
+  case 'c':
+    ret |= PTYPECRTEXT;		/* CR indicates Internet text */
+    break;
+  case 'e':			/* ESC */
+    if (*s == '$') {		/* ISO-2022 sequence? */
+      switch (s[1]) {
+      case 'B': case '@': ret |= PTYPEISO2022JP; break;
+      case ')':
+	switch (s[2]) {
+	case 'A': case 'E': case 'G': ret |= PTYPEISO2022CN; break;
+	case 'C': ret |= PTYPEISO2022KR; break;
+	}
+      case '*':
+	switch (s[2]) {
+	case 'H': ret |= PTYPEISO2022CN; break;
+	}
+      case '+':
+	switch (s[2]) {
+	case 'I': case 'J': case 'K': case 'L': case 'M':
+	  ret |= PTYPEISO2022CN; break;
+	}
+      }
+    }
+    break;
+  case 'l':			/* newline */
+    (*j)++;
+    break;
+  }
+  return ret;			/* return type of data */
+}
+
+/* File close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void phile_close (MAILSTREAM *stream,long options)
+{
+  if (LOCAL) {			/* only if a file is open */
+    fs_give ((void **) &mail_elt (stream,1)->private.special.text.data);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+/* File fetch structure
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to return body
+ *	    option flags
+ * Returns: envelope of this message, body returned in body value
+ *
+ * Fetches the "fast" information as well
+ */
+
+ENVELOPE *phile_structure (MAILSTREAM *stream,unsigned long msgno,BODY **body,
+			   long flags)
+{
+  if (body) *body = LOCAL->body;
+  return LOCAL->env;		/* return the envelope */
+}
+
+
+/* File fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+char *phile_header (MAILSTREAM *stream,unsigned long msgno,
+		    unsigned long *length,long flags)
+{
+  rfc822_header (LOCAL->tmp,LOCAL->env,LOCAL->body);
+  *length = strlen (LOCAL->tmp);
+  return LOCAL->tmp;
+}
+
+
+/* File fetch message text (body only)
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned stringstruct
+ *	    option flags
+ * Returns: T, always
+ */
+
+long phile_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  SIZEDTEXT *buf = &mail_elt (stream,msgno)->private.special.text;
+  if (!(flags &FT_PEEK)) {	/* mark message as seen */
+    mail_elt (stream,msgno)->seen = T;
+    mm_flags (stream,msgno);
+  }
+  INIT (bs,mail_string,buf->data,buf->size);
+  return T;
+}
+
+/* File ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ * No-op for readonly files, since read/writer can expunge it from under us!
+ */
+
+long phile_ping (MAILSTREAM *stream)
+{
+  return T;
+}
+
+/* File check mailbox
+ * Accepts: MAIL stream
+ * No-op for readonly files, since read/writer can expunge it from under us!
+ */
+
+void phile_check (MAILSTREAM *stream)
+{
+  mm_log ("Check completed",NIL);
+}
+
+/* File expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T if success, NIL if failure
+ */
+
+long phile_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  if (!stream->silent) mm_log ("Expunge ignored on readonly mailbox",NIL);
+  return LONGT;
+}
+
+/* File copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if copy successful, else NIL
+ */
+
+long phile_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  char tmp[MAILTMPLEN];
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+  if (pc) return (*pc) (stream,sequence,mailbox,options);
+  sprintf (tmp,"Can't copy - file \"%s\" is not in valid mailbox format",
+	   stream->mailbox);
+  mm_log (tmp,ERROR);
+  return NIL;
+}
+
+
+/* File append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback function
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long phile_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  char tmp[MAILTMPLEN],file[MAILTMPLEN];
+  char *s = mailboxfile (file,mailbox);
+  if (s && *s) 
+    sprintf (tmp,"Can't append - not in valid mailbox format: %.80s",s);
+  else sprintf (tmp,"Can't append - invalid name: %.80s",mailbox);
+  mm_log (tmp,ERROR);
+  return NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/pmatch.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,89 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	IMAP Wildcard Matching Routines (case-dependent)
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	15 June 2000
+ * Last Edited:	30 August 2006
+ */
+
+/* Wildcard pattern match
+ * Accepts: base string
+ *	    pattern string
+ *	    delimiter character
+ * Returns: T if pattern matches base, else NIL
+ */
+
+long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim)
+{
+  switch (*pat) {
+  case '%':			/* non-recursive */
+				/* % at end, OK if no inferiors */
+    if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T;
+                                /* scan remainder of string until delimiter */
+    do if (pmatch_full (s,pat+1,delim)) return T;
+    while ((*s != delim) && *s++);
+    break;
+  case '*':			/* match 0 or more characters */
+    if (!pat[1]) return T;	/* * at end, unconditional match */
+				/* scan remainder of string */
+    do if (pmatch_full (s,pat+1,delim)) return T;
+    while (*s++);
+    break;
+  case '\0':			/* end of pattern */
+    return *s ? NIL : T;	/* success if also end of base */
+  default:			/* match this character */
+    return (*pat == *s) ? pmatch_full (s+1,pat+1,delim) : NIL;
+  }
+  return NIL;
+}
+
+/* Directory pattern match
+ * Accepts: base string
+ *	    pattern string
+ *	    delimiter character
+ * Returns: T if base is a matching directory of pattern, else NIL
+ */
+
+long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim)
+{
+  switch (*pat) {
+  case '%':			/* non-recursive */
+    if (!*s) return T;		/* end of base means have a subset match */
+    if (!*++pat) return NIL;	/* % at end, no inferiors permitted */
+				/* scan remainder of string until delimiter */
+    do if (dmatch (s,pat,delim)) return T;
+    while ((*s != delim) && *s++);
+    if (*s && !s[1]) return T;	/* ends with delimiter, must be subset */
+    return dmatch (s,pat,delim);/* do new scan */
+  case '*':			/* match 0 or more characters */
+    return T;			/* unconditional match */
+  case '\0':			/* end of pattern */
+    break;
+  default:			/* match this character */
+    if (*s) return (*pat == *s) ? dmatch (s+1,pat+1,delim) : NIL;
+				/* end of base, return if at delimiter */
+    else if (*pat == delim) return T;
+    break;
+  }
+  return NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/pseudo.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,36 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Pseudo Header Strings
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	26 September 1996
+ * Last Edited:	30 August 2006
+ */
+
+/* Local sites may wish to alter this text */
+
+char *pseudo_from = "MAILER-DAEMON";
+char *pseudo_name = "Mail System Internal Data";
+char *pseudo_subject = "DON'T DELETE THIS MESSAGE -- FOLDER INTERNAL DATA";
+char *pseudo_msg =
+  "This text is part of the internal format of your mail folder, and is not\na real message.  It is created automatically by the mail system software.\nIf deleted, important folder data will be lost, and it will be re-created\nwith the data reset to initial values."
+  ;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/pseudo.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,30 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Pseudo Header Strings
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	26 September 1996
+ * Last Edited:	30 August 2006
+ */
+
+
+extern char *pseudo_from,*pseudo_name,*pseudo_subject,*pseudo_msg;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/scandir.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,81 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Scan directories
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	15 September 2006
+ */
+ 
+/* Emulator for BSD scandir() call
+ * Accepts: directory name
+ *	    destination pointer of names array
+ *	    selection function
+ *	    comparison function
+ * Returns: number of elements in the array or -1 if error
+ */
+
+int scandir (char *dirname,struct direct ***namelist,select_t select,
+	     compar_t compar)
+{
+  struct direct *p,*d,**names;
+  int nitems;
+  struct stat stb;
+  long nlmax;
+  DIR *dirp = opendir (dirname);/* open directory and get status poop */
+  if ((!dirp) || (fstat (dirp->dd_fd,&stb) < 0)) return -1;
+  nlmax = stb.st_size / 24;	/* guesstimate at number of files */
+  names = (struct direct **) fs_get (nlmax * sizeof (struct direct *));
+  nitems = 0;			/* initially none found */
+  while (d = readdir (dirp)) {	/* read directory item */
+				/* matches select criterion? */
+    if (select && !(*select) (d)) continue;
+				/* get size of direct record for this file */
+    p = (struct direct *) fs_get (DIR_SIZE (d));
+    p->d_ino = d->d_ino;	/* copy the poop */
+    strcpy (p->d_name,d->d_name);
+    if (++nitems >= nlmax) {	/* if out of space, try bigger guesstimate */
+      void *s = (void *) names;	/* stupid language */
+      nlmax *= 2;		/* double it */
+      fs_resize ((void **) &s,nlmax * sizeof (struct direct *));
+      names = (struct direct **) s;
+    }
+    names[nitems - 1] = p;	/* store this file there */
+  }
+  closedir (dirp);		/* done with directory */
+				/* sort if necessary */
+  if (nitems && compar) qsort (names,nitems,sizeof (struct direct *),compar);
+  *namelist = names;		/* return directory */
+  return nitems;		/* and size */
+}
+
+/* Alphabetic file name comparision
+ * Accepts: first candidate directory entry
+ *	    second candidate directory entry
+ * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2
+ */
+
+int alphasort (void *d1,void *d2)
+{
+  return strcmp ((*(struct direct **) d1)->d_name,
+		 (*(struct direct **) d2)->d_name);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/ssl_none.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,141 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Dummy (no SSL) authentication/encryption module
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	7 February 2001
+ * Last Edited:	30 August 2006
+ */
+
+/* Init server for SSL
+ * Accepts: server name
+ */
+
+void ssl_server_init (char *server)
+{
+  syslog (LOG_ERR,"This server does not support SSL");
+  exit (1);			/* punt this program too */
+}
+
+
+/* Start TLS
+ * Accepts: /etc/services service name
+ * Returns: cpystr'd error string if TLS failed, else NIL for success
+ */
+
+char *ssl_start_tls (char *server)
+{
+  return cpystr ("This server does not support TLS");
+}
+
+/* Get character
+ * Returns: character or EOF
+ */
+
+int PBIN (void)
+{
+  return getchar ();
+}
+
+
+/* Get string
+ * Accepts: destination string pointer
+ *	    number of bytes available
+ * Returns: destination string pointer or NIL if EOF
+ */
+
+char *PSIN (char *s,int n)
+{
+  return fgets (s,n,stdin);
+}
+
+
+/* Get record
+ * Accepts: destination string pointer
+ *	    number of bytes to read
+ * Returns: T if success, NIL otherwise
+ */
+
+long PSINR (char *s,unsigned long n)
+{
+  unsigned long i;
+  while (n && ((i = fread (s,1,n,stdin)) || (errno == EINTR))) s += i,n -= i;
+  return n ? NIL : LONGT;
+}
+
+
+/* Wait for input
+ * Accepts: timeout in seconds
+ * Returns: T if have input on stdin, else NIL
+ */
+
+long INWAIT (long seconds)
+{
+  return server_input_wait (seconds);
+}
+
+/* Put character
+ * Accepts: character
+ * Returns: character written or EOF
+ */
+
+int PBOUT (int c)
+{
+  return putchar (c);
+}
+
+
+/* Put string
+ * Accepts: source string pointer
+ * Returns: 0 or EOF if error
+ */
+
+int PSOUT (char *s)
+{
+  return fputs (s,stdout);
+}
+
+
+/* Put record
+ * Accepts: source sized text
+ * Returns: 0 or EOF if error
+ */
+
+int PSOUTR (SIZEDTEXT *s)
+{
+  unsigned char *t;
+  unsigned long i,j;
+  for (t = s->data,i = s->size;
+       (i && ((j = fwrite (t,1,i,stdout)) || (errno == EINTR)));
+       t += j,i -= j);
+  return i ? EOF : NIL;
+}
+
+
+/* Flush output
+ * Returns: 0 or EOF if error
+ */
+
+int PFLUSH (void)
+{
+  return fflush (stdout);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/tcp_ami.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,797 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Amiga TCP/IP routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	13 January 2008
+ */
+
+#undef write			/* don't use redefined write() */
+ 
+static tcptimeout_t tmoh = NIL;	/* TCP timeout handler routine */
+static long ttmo_open = 0;	/* TCP timeouts, in seconds */
+static long ttmo_read = 0;
+static long ttmo_write = 0;
+static long allowreversedns = T;/* allow reverse DNS lookup */
+static long tcpdebug = NIL;	/* extra TCP debugging telemetry */
+
+extern long maxposint;		/* get this from write.c */
+
+/* Local function prototypes */
+
+int tcp_socket_open (struct sockaddr_in *sin,char *tmp,int *ctr,char *hst,
+		     unsigned long port);
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+			       long *contd);
+long tcp_abort (TCPSTREAM *stream);
+char *tcp_name (struct sockaddr_in *sin,long flag);
+char *tcp_name_valid (char *s);
+
+/* TCP/IP manipulate parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *tcp_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case SET_TIMEOUT:
+    tmoh = (tcptimeout_t) value;
+  case GET_TIMEOUT:
+    ret = (void *) tmoh;
+    break;
+  case SET_OPENTIMEOUT:
+    ttmo_open = (long) value;
+  case GET_OPENTIMEOUT:
+    ret = (void *) ttmo_open;
+    break;
+  case SET_READTIMEOUT:
+    ttmo_read = (long) value;
+  case GET_READTIMEOUT:
+    ret = (void *) ttmo_read;
+    break;
+  case SET_WRITETIMEOUT:
+    ttmo_write = (long) value;
+  case GET_WRITETIMEOUT:
+    ret = (void *) ttmo_write;
+    break;
+  case SET_ALLOWREVERSEDNS:
+    allowreversedns = (long) value;
+  case GET_ALLOWREVERSEDNS:
+    ret = (void *) allowreversedns;
+    break;
+  case SET_TCPDEBUG:
+    tcpdebug = (long) value;
+  case GET_TCPDEBUG:
+    ret = (void *) tcpdebug;
+    break;
+  }
+  return ret;
+}
+
+/* TCP/IP open
+ * Accepts: host name
+ *	    contact service name
+ *	    contact port number and optional silent flag
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
+{
+  TCPSTREAM *stream = NIL;
+  int i;
+  int sock = -1;
+  int ctr = 0;
+  int silent = (port & NET_SILENT) ? T : NIL;
+  int *ctrp = (port & NET_NOOPENTIMEOUT) ? NIL : &ctr;
+  char *s;
+  struct sockaddr_in sin;
+  struct hostent *he;
+  char hostname[MAILTMPLEN];
+  char tmp[MAILTMPLEN];
+  struct servent *sv = NIL;
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  void *data;
+  port &= 0xffff;		/* erase flags */
+				/* lookup service */
+  if (service && (sv = getservbyname (service,"tcp")))
+    port = ntohs (sin.sin_port = sv->s_port);
+ 				/* copy port number in network format */
+  else sin.sin_port = htons (port);
+  /* The domain literal form is used (rather than simply the dotted decimal
+     as with other Amiga programs) because it has to be a valid "host name"
+     in mailsystem terminology. */
+				/* look like domain literal? */
+  if (host[0] == '[' && host[(strlen (host))-1] == ']') {
+    strcpy (hostname,host+1);	/* yes, copy number part */
+    hostname[(strlen (hostname))-1] = '\0';
+    if ((sin.sin_addr.s_addr = inet_addr (hostname)) == -1)
+      sprintf (tmp,"Bad format domain-literal: %.80s",host);
+    else {
+      sin.sin_family = AF_INET;	/* family is always Internet */
+      strcpy (hostname,host);	/* hostname is user's argument */
+      (*bn) (BLOCK_TCPOPEN,NIL);
+				/* get an open socket for this system */
+      sock = tcp_socket_open (&sin,tmp,ctrp,hostname,port);
+      (*bn) (BLOCK_NONE,NIL);
+    }
+  }
+
+  else {			/* lookup host name */
+    if (tcpdebug) {
+      sprintf (tmp,"DNS resolution %.80s",host);
+      mm_log (tmp,TCPDEBUG);
+    }
+    (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */
+    data = (*bn) (BLOCK_SENSITIVE,NIL);
+    if (!(he = gethostbyname (lcase (strcpy (hostname,host)))))
+      sprintf (tmp,"No such host as %.80s",host);
+    (*bn) (BLOCK_NONSENSITIVE,data);
+    (*bn) (BLOCK_NONE,NIL);
+    if (he) {			/* DNS resolution won? */
+      if (tcpdebug) mm_log ("DNS resolution done",TCPDEBUG);
+				/* copy address type */
+      sin.sin_family = he->h_addrtype;
+				/* copy host name */
+      strcpy (hostname,he->h_name);
+#ifdef HOST_NOT_FOUND		/* muliple addresses only on DNS systems */
+      for (sock = -1,i = 0; (sock < 0) && (s = he->h_addr_list[i]); i++) {
+	if (i && !silent) mm_log (tmp,WARN);
+	memcpy (&sin.sin_addr,s,he->h_length);
+	(*bn) (BLOCK_TCPOPEN,NIL);
+	sock = tcp_socket_open (&sin,tmp,ctrp,hostname,port);
+	(*bn) (BLOCK_NONE,NIL);
+      }
+#else				/* the one true address then */
+      memcpy (&sin.sin_addr,he->h_addr,he->h_length);
+      (*bn) (BLOCK_TCPOPEN,NIL);
+      sock = tcp_socket_open (&sin,tmp,ctrp,hostname,port);
+      (*bn) (BLOCK_NONE,NIL);
+#endif
+    }
+  }
+  if (sock >= 0)  {		/* won */
+    stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0,
+				   sizeof (TCPSTREAM));
+    stream->port = port;	/* port number */
+				/* init sockets */
+    stream->tcpsi = stream->tcpso = sock;
+				/* stash in the snuck-in byte */
+    if (stream->ictr = ctr) *(stream->iptr = stream->ibuf) = tmp[0];
+				/* copy official host name */
+    stream->host = cpystr (hostname);
+    if (tcpdebug) mm_log ("Stream open and ready for read",TCPDEBUG);
+  }
+  else if (!silent) mm_log (tmp,ERROR);
+  return stream;		/* return success */
+}
+
+/* Open a TCP socket
+ * Accepts: Internet socket address block
+ *	    scratch buffer
+ *	    pointer to "first byte read in" storage or NIL
+ *	    host name for error message
+ *	    port number for error message
+ * Returns: socket if success, else -1 with error string in scratch buffer
+ */
+
+int tcp_socket_open (struct sockaddr_in *sin,char *tmp,int *ctr,char *hst,
+		     unsigned long port)
+{
+  int i,ti,sock,flgs;
+  time_t now;
+  struct protoent *pt = getprotobyname ("tcp");
+  fd_set fds,efds;
+  struct timeval tmo;
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  void *data = (*bn) (BLOCK_SENSITIVE,NIL);
+  sprintf (tmp,"Trying IP address [%s]",inet_ntoa (sin->sin_addr));
+  mm_log (tmp,NIL);
+				/* make a socket */
+  if ((sock = socket (sin->sin_family,SOCK_STREAM,pt ? pt->p_proto : 0)) < 0) {
+    sprintf (tmp,"Unable to create TCP socket: %s",strerror (errno));
+    (*bn) (BLOCK_NONSENSITIVE,data);
+    return -1;
+  }
+  else if (sock >= FD_SETSIZE) {/* unselectable sockets are useless */
+    sprintf (tmp,"Unable to create selectable TCP socket (%d >= %d)",
+	     sock,FD_SETSIZE);
+    (*bn) (BLOCK_NONSENSITIVE,data);
+    close (sock);
+    errno = EMFILE;
+    return -1;
+  }
+  flgs = fcntl (sock,F_GETFL,0);/* get current socket flags */
+				/* set non-blocking if want open timeout */
+  if (ctr) fcntl (sock,F_SETFL,flgs | FNDELAY);
+				/* open connection */
+  while ((i = connect (sock,(struct sockaddr *) sin,
+		       sizeof (struct sockaddr_in))) < 0 && (errno == EINTR));
+  (*bn) (BLOCK_NONSENSITIVE,data);
+  if (i < 0) switch (errno) {	/* failed? */
+  case EAGAIN:			/* DG brain damage */
+  case EINPROGRESS:		/* what we expect to happen */
+  case EALREADY:		/* or another form of it */
+  case EISCONN:			/* restart after interrupt? */
+  case EADDRINUSE:		/* restart after interrupt? */
+    break;			/* well, not really, it was interrupted */
+  default:
+    sprintf (tmp,"Can't connect to %.80s,%lu: %s",hst,port,strerror (errno));
+    close (sock);		/* flush socket */
+    return -1;
+  }
+
+  if (ctr) {			/* want open timeout */
+    now = time (0);		/* open timeout */
+    ti = ttmo_open ? now + ttmo_open : 0;
+    tmo.tv_usec = 0;
+    FD_ZERO (&fds);		/* initialize selection vector */
+    FD_ZERO (&efds);		/* handle errors too */
+    FD_SET (sock,&fds);		/* block for error or readable */
+    FD_SET (sock,&efds);
+    do {			/* block under timeout */
+      tmo.tv_sec = ti ? ti - now : 0;
+      i = select (sock+1,&fds,0,&efds,ti ? &tmo : 0);
+      now = time (0);		/* fake timeout if interrupt & time expired */
+      if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0;
+    } while ((i < 0) && (errno == EINTR));
+    if (i > 0) {		/* success, make sure really connected */
+      fcntl (sock,F_SETFL,flgs);/* restore blocking status */
+      /* This used to be a zero-byte read(), but that crashes Solaris */
+				/* get socket status */
+      while (((i = *ctr = read (sock,tmp,1)) < 0) && (errno == EINTR));
+    }	
+    if (i <= 0) {		/* timeout or error? */
+      i = i ? errno : ETIMEDOUT;/* determine error code */
+      close (sock);		/* flush socket */
+      errno = i;		/* return error code */
+      sprintf (tmp,"Connection failed to %.80s,%lu: %s",hst,port,
+	       strerror (errno));
+      return -1;
+    }
+  }
+  return sock;			/* return the socket */
+}
+  
+/* TCP/IP authenticated open
+ * Accepts: host name
+ *	    service name
+ *	    returned user name buffer
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
+{
+  return NIL;			/* disabled */
+}
+
+/* TCP receive line
+ * Accepts: TCP stream
+ * Returns: text line string or NIL if failure
+ */
+
+char *tcp_getline (TCPSTREAM *stream)
+{
+  unsigned long n,contd;
+  char *ret = tcp_getline_work (stream,&n,&contd);
+  if (ret && contd) {		/* got a line needing continuation? */
+    STRINGLIST *stl = mail_newstringlist ();
+    STRINGLIST *stc = stl;
+    do {			/* collect additional lines */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+      stc = stc->next = mail_newstringlist ();
+      ret = tcp_getline_work (stream,&n,&contd);
+    } while (ret && contd);
+    if (ret) {			/* stash final part of line on list */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+				/* determine how large a buffer we need */
+      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
+      ret = fs_get (n + 1);	/* copy parts into buffer */
+      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
+	memcpy (ret + n,stc->text.data,stc->text.size);
+      ret[n] = '\0';
+    }
+    mail_free_stringlist (&stl);/* either way, done with list */
+  }
+  return ret;
+}
+
+/* TCP receive line or partial line
+ * Accepts: TCP stream
+ *	    pointer to return size
+ *	    pointer to return continuation flag
+ * Returns: text line string, size and continuation flag, or NIL if failure
+ */
+
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+			       long *contd)
+{
+  unsigned long n;
+  char *s,*ret,c,d;
+  *contd = NIL;			/* assume no continuation */
+				/* make sure have data */
+  if (!tcp_getdata (stream)) return NIL;
+  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
+    d = *stream->iptr++;	/* slurp another character */
+    if ((c == '\015') && (d == '\012')) {
+      ret = (char *) fs_get (n--);
+      memcpy (ret,s,*size = n);	/* copy into a free storage string */
+      ret[n] = '\0';		/* tie off string with null */
+      return ret;
+    }
+  }
+				/* copy partial string from buffer */
+  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
+				/* get more data from the net */
+  if (!tcp_getdata (stream)) fs_give ((void **) &ret);
+				/* special case of newline broken by buffer */
+  else if ((c == '\015') && (*stream->iptr == '\012')) {
+    stream->iptr++;		/* eat the line feed */
+    stream->ictr--;
+    ret[*size = --n] = '\0';	/* tie off string with null */
+  }
+  else *contd = LONGT;		/* continuation needed */
+  return ret;
+}
+
+/* TCP/IP receive buffer
+ * Accepts: TCP/IP stream
+ *	    size in bytes
+ *	    buffer to read into
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *s)
+{
+  unsigned long n;
+				/* make sure socket still alive */
+  if (stream->tcpsi < 0) return NIL;
+				/* can transfer bytes from buffer? */
+  if (n = min (size,stream->ictr)) {
+    memcpy (s,stream->iptr,n);	/* yes, slurp as much as we can from it */
+    s += n;			/* update pointer */
+    stream->iptr +=n;
+    size -= n;			/* update # of bytes to do */
+    stream->ictr -=n;
+  }
+  if (size) {
+    int i;
+    fd_set fds,efds;
+    struct timeval tmo;
+    time_t t = time (0);
+    blocknotify_t bn=(blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+    (*bn) (BLOCK_TCPREAD,NIL);
+    while (size > 0) {		/* until request satisfied */
+      time_t tl = time (0);
+      time_t now = tl;
+      time_t ti = ttmo_read ? now + ttmo_read : 0;
+      if (tcpdebug) mm_log ("Reading TCP buffer",TCPDEBUG);
+      tmo.tv_usec = 0;
+      FD_ZERO (&fds);		/* initialize selection vector */
+      FD_ZERO (&efds);		/* handle errors too */
+      FD_SET (stream->tcpsi,&fds);
+      FD_SET (stream->tcpsi,&efds);
+      errno = NIL;		/* block and read */
+      do {			/* block under timeout */
+	tmo.tv_sec = ti ? ti - now : 0;
+	i = select (stream->tcpsi+1,&fds,0,&efds,ti ? &tmo : 0);
+	now = time (0);		/* fake timeout if interrupt & time expired */
+	if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0;
+      } while ((i < 0) && (errno == EINTR));
+      if (i > 0) {		/* select says there's data to read? */
+	while (((i = read (stream->tcpsi,s,(int) min (maxposint,size))) < 0) &&
+	       (errno == EINTR));
+	if (i < 1) return tcp_abort (stream);
+	s += i;			/* point at new place to write */
+	size -= i;		/* reduce byte count */
+	if (tcpdebug) mm_log ("Successfully read TCP buffer",TCPDEBUG);
+      }
+      else if (i || !tmoh || !(*tmoh) (now - t,now - tl))
+	return tcp_abort (stream);
+    }
+    (*bn) (BLOCK_NONE,NIL);
+  }
+  *s = '\0';			/* tie off string */
+  return T;
+}
+
+/* TCP/IP receive data
+ * Accepts: TCP/IP stream
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getdata (TCPSTREAM *stream)
+{
+  int i;
+  fd_set fds,efds;
+  struct timeval tmo;
+  time_t t = time (0);
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  if (stream->tcpsi < 0) return NIL;
+  (*bn) (BLOCK_TCPREAD,NIL);
+  while (stream->ictr < 1) {	/* if nothing in the buffer */
+    time_t tl = time (0);	/* start of request */
+    time_t now = tl;
+    time_t ti = ttmo_read ? now + ttmo_read : 0;
+    if (tcpdebug) mm_log ("Reading TCP data",TCPDEBUG);
+    tmo.tv_usec = 0;
+    FD_ZERO (&fds);		/* initialize selection vector */
+    FD_ZERO (&efds);		/* handle errors too */
+    FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */
+    FD_SET(stream->tcpsi,&efds);/* set bit in error selection vector */
+    errno = NIL;		/* block and read */
+    do {			/* block under timeout */
+      tmo.tv_sec = ti ? ti - now : 0;
+      i = select (stream->tcpsi+1,&fds,0,&efds,ti ? &tmo : 0);
+      now = time (0);		/* fake timeout if interrupt & time expired */
+      if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0;
+    } while ((i < 0) && (errno == EINTR));
+    if (i > 0) {		/* got data? */
+      while (((i = read (stream->tcpsi,stream->ibuf,BUFLEN)) < 0) &&
+	     (errno == EINTR));
+      if (i < 1) return tcp_abort (stream);
+      stream->iptr = stream->ibuf;/* point at TCP buffer */
+      stream->ictr = i;		/* set new byte count */
+      if (tcpdebug) mm_log ("Successfully read TCP data",TCPDEBUG);
+    }
+    else if (i || !tmoh || !(*tmoh) (now - t,now - tl))
+      return tcp_abort (stream);/* error or timeout no-continue */
+  }
+  (*bn) (BLOCK_NONE,NIL);
+  return T;
+}
+
+/* TCP/IP send string as record
+ * Accepts: TCP/IP stream
+ *	    string pointer
+ * Returns: T if success else NIL
+ */
+
+long tcp_soutr (TCPSTREAM *stream,char *string)
+{
+  return tcp_sout (stream,string,(unsigned long) strlen (string));
+}
+
+
+/* TCP/IP send string
+ * Accepts: TCP/IP stream
+ *	    string pointer
+ *	    byte count
+ * Returns: T if success else NIL
+ */
+
+long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
+{
+  int i;
+  fd_set fds,efds;
+  struct timeval tmo;
+  time_t t = time (0);
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  if (stream->tcpso < 0) return NIL;
+  (*bn) (BLOCK_TCPWRITE,NIL);
+  while (size > 0) {		/* until request satisfied */
+    time_t tl = time (0);	/* start of request */
+    time_t now = tl;
+    time_t ti = ttmo_write ? now + ttmo_write : 0;
+    if (tcpdebug) mm_log ("Writing to TCP",TCPDEBUG);
+    tmo.tv_usec = 0;
+    FD_ZERO (&fds);		/* initialize selection vector */
+    FD_ZERO (&efds);		/* handle errors too */
+    FD_SET (stream->tcpso,&fds);/* set bit in selection vector */
+    FD_SET(stream->tcpso,&efds);/* set bit in error selection vector */
+    errno = NIL;		/* block and write */
+    do {			/* block under timeout */
+      tmo.tv_sec = ti ? ti - now : 0;
+      i = select (stream->tcpso+1,0,&fds,&efds,ti ? &tmo : 0);
+      now = time (0);		/* fake timeout if interrupt & time expired */
+      if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0;
+    } while ((i < 0) && (errno == EINTR));
+    if (i > 0) {		/* OK to send data? */
+      while (((i = write (stream->tcpso,string,size)) < 0) &&(errno == EINTR));
+      if (i < 0) return tcp_abort (stream);
+      size -= i;		/* how much we sent */
+      string += i;
+      if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG);
+    }
+    else if (i || !tmoh || !(*tmoh) (now - t,now - tl))
+      return tcp_abort (stream);/* error or timeout no-continue */
+  }
+  (*bn) (BLOCK_NONE,NIL);
+  return T;			/* all done */
+}
+
+/* TCP/IP close
+ * Accepts: TCP/IP stream
+ */
+
+void tcp_close (TCPSTREAM *stream)
+{
+  tcp_abort (stream);		/* nuke the stream */
+				/* flush host names */
+  if (stream->host) fs_give ((void **) &stream->host);
+  if (stream->remotehost) fs_give ((void **) &stream->remotehost);
+  if (stream->localhost) fs_give ((void **) &stream->localhost);
+  fs_give ((void **) &stream);	/* flush the stream */
+}
+
+
+/* TCP/IP abort stream
+ * Accepts: TCP/IP stream
+ * Returns: NIL always
+ */
+
+long tcp_abort (TCPSTREAM *stream)
+{
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  if (stream->tcpsi >= 0) {	/* no-op if no socket */
+    (*bn) (BLOCK_TCPCLOSE,NIL);
+    close (stream->tcpsi);	/* nuke the socket */
+    if (stream->tcpsi != stream->tcpso) close (stream->tcpso);
+    stream->tcpsi = stream->tcpso = -1;
+  }
+  (*bn) (BLOCK_NONE,NIL);
+  return NIL;
+}
+
+/* TCP/IP get host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_host (TCPSTREAM *stream)
+{
+  return stream->host;		/* use tcp_remotehost() if want guarantees */
+}
+
+
+/* TCP/IP get remote host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_remotehost (TCPSTREAM *stream)
+{
+  if (!stream->remotehost) {
+    struct sockaddr_in sin;
+    int sinlen = sizeof (struct sockaddr_in);
+    stream->remotehost =	/* get socket's peer name */
+      (getpeername (stream->tcpsi,(struct sockaddr *) &sin,(void *) &sinlen) ||
+       (sin.sin_family != AF_INET)) ?
+	 cpystr (stream->host) : tcp_name (&sin,NIL);
+  }
+  return stream->remotehost;
+}
+
+
+/* TCP/IP return port for this stream
+ * Accepts: TCP/IP stream
+ * Returns: port number for this stream
+ */
+
+unsigned long tcp_port (TCPSTREAM *stream)
+{
+  return stream->port;		/* return port number */
+}
+
+
+/* TCP/IP get local host name
+ * Accepts: TCP/IP stream
+ * Returns: local host name
+ */
+
+char *tcp_localhost (TCPSTREAM *stream)
+{
+  if (!stream->localhost) {
+    struct sockaddr_in sin;
+    int sinlen = sizeof (struct sockaddr_in);
+    stream->localhost =		/* get socket's name */
+      ((stream->port & 0xffff000) ||
+       getsockname (stream->tcpsi,(struct sockaddr *) &sin,(void *) &sinlen) ||
+       (sin.sin_family != AF_INET)) ?
+	 cpystr (mylocalhost ()) : tcp_name (&sin,NIL);
+  }
+  return stream->localhost;	/* return local host name */
+}
+
+/* TCP/IP get client host address (server calls only)
+ * Returns: client host address
+ */
+
+static char *myClientAddr = NIL;
+
+char *tcp_clientaddr ()
+{
+  if (!myClientAddr) {
+    struct sockaddr_in sin;
+    int sinlen = sizeof (struct sockaddr_in);
+    myClientAddr =		/* get stdin's peer name */
+      cpystr (getpeername (0,(struct sockaddr *) &sin,(void *) &sinlen) ?
+	      "UNKNOWN" : ((sin.sin_family == AF_INET) ?
+			   inet_ntoa (sin.sin_addr) : "NON-IPv4"));
+  }
+  return myClientAddr;
+}
+
+
+/* TCP/IP get client host name (server calls only)
+ * Returns: client host name
+ */
+
+static char *myClientHost = NIL;
+
+char *tcp_clienthost ()
+{
+  if (!myClientHost) {
+    struct sockaddr_in sin;
+    int sinlen = sizeof (struct sockaddr_in);
+    myClientHost =		/* get stdin's peer name */
+      getpeername (0,(struct sockaddr *) &sin,(void *) &sinlen) ?
+	cpystr ("UNKNOWN") : ((sin.sin_family == AF_INET) ?
+			      tcp_name (&sin,T) : cpystr ("NON-IPv4"));
+  }
+  return myClientHost;
+}
+
+/* TCP/IP get server host address (server calls only)
+ * Returns: server host address
+ */
+
+static char *myServerAddr = NIL;
+
+char *tcp_serveraddr ()
+{
+  if (!myServerAddr) {
+    struct sockaddr_in sin;
+    int sinlen = sizeof (struct sockaddr_in);
+    myServerAddr =		/* get stdin's peer name */
+      cpystr (getsockname (0,(struct sockaddr *) &sin,(void *) &sinlen) ?
+	      "UNKNOWN" : ((sin.sin_family == AF_INET) ?
+			   inet_ntoa (sin.sin_addr) : "NON-IPv4"));
+  }
+  return myServerAddr;
+}
+
+
+/* TCP/IP get server host name (server calls only)
+ * Returns: server host name
+ */
+
+static char *myServerHost = NIL;
+static long myServerPort = -1;
+
+char *tcp_serverhost ()
+{
+  if (!myServerHost) {
+    struct sockaddr_in sin;
+    int sinlen = sizeof (struct sockaddr_in);
+				/* get stdin's name */
+    if (getsockname (0,(struct sockaddr *) &sin,(void *) &sinlen) ||
+	(sin.sin_family != AF_INET)) myServerHost = cpystr (mylocalhost ());
+    else {
+      myServerHost = tcp_name (&sin,NIL);
+      myServerPort = ntohs (sin.sin_port);
+    }
+  }
+  return myServerHost;
+}
+
+
+/* TCP/IP get server port number (server calls only)
+ * Returns: server port number
+ */
+
+long tcp_serverport ()
+{
+  if (!myServerHost) tcp_serverhost ();
+  return myServerPort;
+}
+
+/* TCP/IP return canonical form of host name
+ * Accepts: host name
+ * Returns: canonical form of host name
+ */
+
+char *tcp_canonical (char *name)
+{
+  char *ret,host[MAILTMPLEN];
+  struct hostent *he;
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  void *data;
+				/* look like domain literal? */
+  if (name[0] == '[' && name[strlen (name) - 1] == ']') return name;
+  (*bn) (BLOCK_DNSLOOKUP,NIL);	/* quell alarms */
+  data = (*bn) (BLOCK_SENSITIVE,NIL);
+  if (tcpdebug) {
+    sprintf (host,"DNS canonicalization %.80s",name);
+    mm_log (host,TCPDEBUG);
+  }
+				/* note that Amiga requires lowercase! */
+  ret = (he = gethostbyname (lcase (strcpy (host,name)))) ?
+    (char *) he->h_name : name;
+  (*bn) (BLOCK_NONSENSITIVE,data);
+  (*bn) (BLOCK_NONE,NIL);	/* alarms OK now */
+  if (tcpdebug) mm_log ("DNS canonicalization done",TCPDEBUG);
+  return ret;
+}
+
+
+/* TCP/IP return name from socket
+ * Accepts: socket
+ *	    verbose flag
+ * Returns: cpystr name
+ */
+
+char *tcp_name (struct sockaddr_in *sin,long flag)
+{
+  char *ret,*t,adr[MAILTMPLEN],tmp[MAILTMPLEN];
+  sprintf (ret = adr,"[%.80s]",inet_ntoa (sin->sin_addr));
+  if (allowreversedns) {
+    struct hostent *he;
+    blocknotify_t bn = (blocknotify_t)mail_parameters(NIL,GET_BLOCKNOTIFY,NIL);
+    void *data;
+    if (tcpdebug) {
+      sprintf (tmp,"Reverse DNS resolution %s",adr);
+      mm_log (tmp,TCPDEBUG);
+    }
+    (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */
+    data = (*bn) (BLOCK_SENSITIVE,NIL);
+				/* translate address to name */
+    if (t = tcp_name_valid ((he = gethostbyaddr ((char *) &sin->sin_addr,
+						 sizeof (struct in_addr),
+						 sin->sin_family)) ?
+			    (char *) he->h_name : NIL)) {
+				/* produce verbose form if needed */
+      if (flag)	sprintf (ret = tmp,"%s %s",t,adr);
+      else ret = t;
+    }
+    (*bn) (BLOCK_NONSENSITIVE,data);
+    (*bn) (BLOCK_NONE,NIL);	/* alarms OK now */
+    if (tcpdebug) mm_log ("Reverse DNS resolution done",TCPDEBUG);
+  }
+  return cpystr (ret);
+}
+
+
+/* Validate name
+ * Accepts: domain name
+ * Returns: T if valid, NIL otherwise
+ */
+
+char *tcp_name_valid (char *s)
+{
+  int c;
+  char *ret,*tail;
+				/* must be non-empty and not too long */
+  if ((ret = (s && *s) ? s : NIL) && (tail = ret + NETMAXHOST)) {
+				/* must be alnum, dot, or hyphen */
+    while ((c = *s++) && (s <= tail) &&
+	   (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) ||
+	    ((c >= '0') && (c <= '9')) || (c == '-') || (c == '.')));
+    if (c) ret = NIL;
+  }
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/tcp_ami.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,48 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX TCP/IP routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+/* TCP input buffer */
+
+#define BUFLEN 8192
+
+
+/* TCP I/O stream */
+
+#define TCPSTREAM struct tcp_stream
+TCPSTREAM {
+  char *host;			/* host name */
+  unsigned long port;		/* port number */
+  char *localhost;		/* local host name */
+  char *remotehost;		/* remote host name */
+  int tcpsi;			/* input socket */
+  int tcpso;			/* output socket */
+  int ictr;			/* input counter */
+  char *iptr;			/* input pointer */
+  char ibuf[BUFLEN];		/* input buffer */
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/tenex.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1470 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Tenex mail routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	22 May 1990
+ * Last Edited:	11 October 2007
+ */
+
+
+/*				FILE TIME SEMANTICS
+ *
+ * The atime is the last read time of the file.
+ * The mtime is the last flags update time of the file.
+ * The ctime is the last write time of the file.
+ *
+ *				TEXT SIZE SEMANTICS
+ *
+ * Most of the text sizes are in internal (LF-only) form, except for the
+ * msg.text size.  Beware.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "mail.h"
+#include "osdep.h"
+#include <sys/stat.h>
+#include "misc.h"
+#include "dummy.h"
+
+/* TENEX I/O stream local data */
+	
+typedef struct tenex_local {
+  unsigned int shouldcheck: 1;	/* if ping should do a check instead */
+  unsigned int mustcheck: 1;	/* if ping must do a check instead */
+  int fd;			/* file descriptor for I/O */
+  off_t filesize;		/* file size parsed */
+  time_t filetime;		/* last file time */
+  time_t lastsnarf;		/* local snarf time */
+  unsigned char *buf;		/* temporary buffer */
+  unsigned long buflen;		/* current size of temporary buffer */
+  unsigned long uid;		/* current text uid */
+  SIZEDTEXT text;		/* current text */
+} TENEXLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((TENEXLOCAL *) stream->local)
+
+
+/* Function prototypes */
+
+DRIVER *tenex_valid (char *name);
+int tenex_isvalid (char *name,char *tmp);
+void *tenex_parameters (long function,void *value);
+void tenex_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void tenex_list (MAILSTREAM *stream,char *ref,char *pat);
+void tenex_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long tenex_create (MAILSTREAM *stream,char *mailbox);
+long tenex_delete (MAILSTREAM *stream,char *mailbox);
+long tenex_rename (MAILSTREAM *stream,char *old,char *newname);
+long tenex_status (MAILSTREAM *stream,char *mbx,long flags);
+MAILSTREAM *tenex_open (MAILSTREAM *stream);
+void tenex_close (MAILSTREAM *stream,long options);
+void tenex_fast (MAILSTREAM *stream,char *sequence,long flags);
+void tenex_flags (MAILSTREAM *stream,char *sequence,long flags);
+char *tenex_header (MAILSTREAM *stream,unsigned long msgno,
+		    unsigned long *length,long flags);
+long tenex_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+void tenex_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
+void tenex_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
+long tenex_ping (MAILSTREAM *stream);
+void tenex_check (MAILSTREAM *stream);
+void tenex_snarf (MAILSTREAM *stream);
+long tenex_expunge (MAILSTREAM *stream,char *sequence,long options);
+long tenex_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long tenex_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+unsigned long tenex_size (MAILSTREAM *stream,unsigned long m);
+char *tenex_file (char *dst,char *name);
+long tenex_parse (MAILSTREAM *stream);
+MESSAGECACHE *tenex_elt (MAILSTREAM *stream,unsigned long msgno);
+void tenex_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt);
+void tenex_update_status (MAILSTREAM *stream,unsigned long msgno,
+			  long syncflag);
+unsigned long tenex_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			    unsigned long *size);
+
+/* Tenex mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER tenexdriver = {
+  "tenex",			/* driver name */
+  DR_LOCAL|DR_MAIL|DR_NOSTICKY|DR_LOCKING,
+				/* driver flags */
+  (DRIVER *) NIL,		/* next driver */
+  tenex_valid,			/* mailbox is valid for us */
+  tenex_parameters,		/* manipulate parameters */
+  tenex_scan,			/* scan mailboxes */
+  tenex_list,			/* list mailboxes */
+  tenex_lsub,			/* list subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  dummy_create,			/* create mailbox */
+  tenex_delete,			/* delete mailbox */
+  tenex_rename,			/* rename mailbox */
+  tenex_status,			/* status of mailbox */
+  tenex_open,			/* open mailbox */
+  tenex_close,			/* close mailbox */
+  tenex_fast,			/* fetch message "fast" attributes */
+  tenex_flags,			/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  tenex_header,			/* fetch message header */
+  tenex_text,			/* fetch message body */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  tenex_flag,			/* modify flags */
+  tenex_flagmsg,		/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  tenex_ping,			/* ping mailbox to see if still alive */
+  tenex_check,			/* check for new messages */
+  tenex_expunge,		/* expunge deleted messages */
+  tenex_copy,			/* copy messages to another mailbox */
+  tenex_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM tenexproto = {&tenexdriver};
+
+/* Tenex mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *tenex_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+  return tenex_isvalid (name,tmp) ? &tenexdriver : NIL;
+}
+
+
+/* Tenex mail test for valid mailbox
+ * Accepts: mailbox name
+ * Returns: T if valid, NIL otherwise
+ */
+
+int tenex_isvalid (char *name,char *tmp)
+{
+  int fd;
+  int ret = NIL;
+  char *s,file[MAILTMPLEN];
+  struct stat sbuf;
+  time_t tp[2];
+  errno = EINVAL;		/* assume invalid argument */
+				/* if file, get its status */
+  if ((s = tenex_file (file,name)) && !stat (s,&sbuf)) {
+    if (!sbuf.st_size) {	/* allow empty file if INBOX */
+      if ((s = mailboxfile (tmp,name)) && !*s) ret = T;
+      else errno = 0;		/* empty file */
+    }
+    else if ((fd = open (file,O_RDONLY,NIL)) >= 0) {
+      memset (tmp,'\0',MAILTMPLEN);
+      if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\012')) &&
+	  (s[-1] != '\015')) {	/* valid format? */
+	*s = '\0';		/* tie off header */
+				/* must begin with dd-mmm-yy" */
+	ret = (((tmp[2] == '-' && tmp[6] == '-') ||
+		(tmp[1] == '-' && tmp[5] == '-')) &&
+	       (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL;
+      }
+      else errno = -1;		/* bogus format */
+      close (fd);		/* close the file */
+				/* \Marked status? */
+      if (sbuf.st_ctime > sbuf.st_atime) {
+	tp[0] = sbuf.st_atime;	/* preserve atime and mtime */
+	tp[1] = sbuf.st_mtime;
+	utime (file,tp);	/* set the times */
+      }
+    }
+  }
+				/* in case INBOX but not tenex format */
+  else if ((errno == ENOENT) && !compare_cstring (name,"INBOX")) errno = -1;
+  return ret;			/* return what we should */
+}
+
+/* Tenex manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *tenex_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case GET_INBOXPATH:
+    if (value) ret = tenex_file ((char *) value,"INBOX");
+    break;
+  }
+  return ret;
+}
+
+
+/* Tenex mail scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void tenex_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* Tenex mail list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void tenex_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_list (NIL,ref,pat);
+}
+
+
+/* Tenex mail list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void tenex_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_lsub (NIL,ref,pat);
+}
+
+/* Tenex mail delete mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long tenex_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return tenex_rename (stream,mailbox,NIL);
+}
+
+
+/* Tenex mail rename mailbox
+ * Accepts: MAIL stream
+ *	    old mailbox name
+ *	    new mailbox name (or NIL for delete)
+ * Returns: T on success, NIL on failure
+ */
+
+long tenex_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  long ret = T;
+  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  int fd,ld;
+  struct stat sbuf;
+  if (!tenex_file (file,old) ||
+      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
+		   ((s = strrchr (tmp,'/')) && !s[1])))) {
+    sprintf (tmp,newname ?
+	     "Can't rename mailbox %.80s to %.80s: invalid name" :
+	     "Can't delete mailbox %.80s: invalid name",
+	     old,newname);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+  else if ((fd = open (file,O_RDWR,NIL)) < 0) {
+    sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno));
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+				/* get exclusive parse/append permission */
+  if ((ld = lockfd (fd,lock,LOCK_EX)) < 0) {
+    MM_LOG ("Unable to lock rename mailbox",ERROR);
+    return NIL;
+  }
+				/* lock out other users */
+  if (flock (fd,LOCK_EX|LOCK_NB)) {
+    close (fd);			/* couldn't lock, give up on it then */
+    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
+    MM_LOG (tmp,ERROR);
+    unlockfd (ld,lock);		/* release exclusive parse/append permission */
+    return NIL;
+  }
+
+  if (newname) {		/* want rename? */
+    if (s = strrchr (tmp,'/')) {/* found superior to destination name? */
+      c = *++s;			/* remember first character of inferior */
+      *s = '\0';		/* tie off to get just superior */
+				/* name doesn't exist, create it */
+      if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+	  !dummy_create_path (stream,tmp,get_dir_protection (newname)))
+	ret = NIL;
+      else *s = c;		/* restore full name */
+    }
+				/* rename the file */
+    if (ret && rename (file,tmp)) {
+      sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
+	       strerror (errno));
+      MM_LOG (tmp,ERROR);
+      ret = NIL;		/* set failure */
+    }
+  }
+  else if (unlink (file)) {
+    sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
+    MM_LOG (tmp,ERROR);
+    ret = NIL;			/* set failure */
+  }
+  flock (fd,LOCK_UN);		/* release lock on the file */
+  close (fd);			/* close the file */
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+				/* recreate file if renamed INBOX */
+  if (ret && !compare_cstring (old,"INBOX")) dummy_create (NIL,"mail.txt");
+  return ret;			/* return success */
+}
+
+/* Tenex Mail status
+ * Accepts: mail stream
+ *	    mailbox name
+ *	    status flags
+ * Returns: T on success, NIL on failure
+ */
+
+long tenex_status (MAILSTREAM *stream,char *mbx,long flags)
+{
+  MAILSTATUS status;
+  unsigned long i;
+  MAILSTREAM *tstream = NIL;
+  MAILSTREAM *systream = NIL;
+				/* make temporary stream (unless this mbx) */
+  if (!stream && !(stream = tstream =
+		   mail_open (NIL,mbx,OP_READONLY|OP_SILENT))) return NIL;
+  status.flags = flags;		/* return status values */
+  status.messages = stream->nmsgs;
+  status.recent = stream->recent;
+  if (flags & SA_UNSEEN)	/* must search to get unseen messages */
+    for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++)
+      if (!mail_elt (stream,i)->seen) status.unseen++;
+  status.uidnext = stream->uid_last + 1;
+  status.uidvalidity = stream->uid_validity;
+				/* calculate post-snarf results */
+  if (!status.recent && stream->inbox &&
+      (systream = mail_open (NIL,sysinbox (),OP_READONLY|OP_SILENT))) {
+    status.messages += systream->nmsgs;
+    status.recent += systream->recent;
+    if (flags & SA_UNSEEN)	/* must search to get unseen messages */
+      for (i = 1; i <= systream->nmsgs; i++)
+	if (!mail_elt (systream,i)->seen) status.unseen++;
+				/* kludge but probably good enough */
+    status.uidnext += systream->nmsgs;
+  }
+  MM_STATUS(stream,mbx,&status);/* pass status to main program */
+  if (tstream) mail_close (tstream);
+  if (systream) mail_close (systream);
+  return T;			/* success */
+}
+
+/* Tenex mail open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *tenex_open (MAILSTREAM *stream)
+{
+  int fd,ld;
+  char tmp[MAILTMPLEN];
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return user_flags (&tenexproto);
+  if (stream->local) fatal ("tenex recycle stream");
+  user_flags (stream);		/* set up user flags */
+				/* canonicalize the mailbox name */
+  if (!tenex_file (tmp,stream->mailbox)) {
+    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
+    MM_LOG (tmp,ERROR);
+  }
+  if (stream->rdonly ||
+      (fd = open (tmp,O_RDWR,NIL)) < 0) {
+    if ((fd = open (tmp,O_RDONLY,NIL)) < 0) {
+      sprintf (tmp,"Can't open mailbox: %s",strerror (errno));
+      MM_LOG (tmp,ERROR);
+      return NIL;
+    }
+    else if (!stream->rdonly) {	/* got it, but readonly */
+      MM_LOG ("Can't get write access to mailbox, access is readonly",WARN);
+      stream->rdonly = T;
+    }
+  }
+  stream->local = fs_get (sizeof (TENEXLOCAL));
+  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
+  LOCAL->buflen = CHUNKSIZE - 1;
+  LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE);
+  LOCAL->text.size = CHUNKSIZE - 1;
+
+				/* note if an INBOX or not */
+  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
+  LOCAL->fd = fd;		/* bind the file */
+				/* flush old name */
+  fs_give ((void **) &stream->mailbox);
+				/* save canonical name */
+  stream->mailbox = cpystr (tmp);
+				/* get shared parse permission */
+  if ((ld = lockfd (fd,tmp,LOCK_SH)) < 0) {
+    MM_LOG ("Unable to lock open mailbox",ERROR);
+    return NIL;
+  }
+  (*bn) (BLOCK_FILELOCK,NIL);
+  flock (LOCAL->fd,LOCK_SH);	/* lock the file */
+  (*bn) (BLOCK_NONE,NIL);
+  unlockfd (ld,tmp);		/* release shared parse permission */
+  LOCAL->filesize = 0;		/* initialize parsed file size */
+				/* time not set up yet */
+  LOCAL->lastsnarf = LOCAL->filetime = 0;
+  LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
+  stream->sequence++;		/* bump sequence number */
+				/* parse mailbox */
+  stream->nmsgs = stream->recent = 0;
+  if (tenex_ping (stream) && !stream->nmsgs)
+    MM_LOG ("Mailbox is empty",(long) NIL);
+  if (!LOCAL) return NIL;	/* failure if stream died */
+  stream->perm_seen = stream->perm_deleted =
+    stream->perm_flagged = stream->perm_answered = stream->perm_draft =
+      stream->rdonly ? NIL : T;
+  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
+  return stream;		/* return stream to caller */
+}
+
+/* Tenex mail close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void tenex_close (MAILSTREAM *stream,long options)
+{
+  if (stream && LOCAL) {	/* only if a file is open */
+    int silent = stream->silent;
+    stream->silent = T;		/* note this stream is dying */
+    if (options & CL_EXPUNGE) tenex_expunge (stream,NIL,NIL);
+    stream->silent = silent;	/* restore previous status */
+    flock (LOCAL->fd,LOCK_UN);	/* unlock local file */
+    close (LOCAL->fd);		/* close the local file */
+				/* free local text buffer */
+    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+    if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+/* Tenex mail fetch fast data
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ */
+
+void tenex_fast (MAILSTREAM *stream,char *sequence,long flags)
+{
+  STRING bs;
+  MESSAGECACHE *elt;
+  unsigned long i;
+  if (stream && LOCAL &&
+      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
+       mail_sequence (stream,sequence)))
+    for (i = 1; i <= stream->nmsgs; i++)
+      if ((elt = mail_elt (stream,i))->sequence) {
+	if (!elt->rfc822_size) { /* have header size yet? */
+	  lseek (LOCAL->fd,elt->private.special.offset +
+		 elt->private.special.text.size,L_SET);
+				/* resize bigbuf if necessary */
+	  if (LOCAL->buflen < elt->private.msg.full.text.size) {
+	    fs_give ((void **) &LOCAL->buf);
+	    LOCAL->buflen = elt->private.msg.full.text.size;
+	    LOCAL->buf = (char *) fs_get (LOCAL->buflen + 1);
+	  }
+				/* tie off string */
+	  LOCAL->buf[elt->private.msg.full.text.size] = '\0';
+				/* read in the message */
+	  read (LOCAL->fd,LOCAL->buf,elt->private.msg.full.text.size);
+	  INIT (&bs,mail_string,(void *) LOCAL->buf,
+		elt->private.msg.full.text.size);
+				/* calculate its CRLF size */
+	  elt->rfc822_size = strcrlflen (&bs);
+	}
+	tenex_elt (stream,i);	/* get current flags from file */
+      }
+}
+
+
+/* Tenex mail fetch flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ * Sniffs at file to get flags
+ */
+
+void tenex_flags (MAILSTREAM *stream,char *sequence,long flags)
+{
+  unsigned long i;
+  if (stream && LOCAL &&
+      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
+       mail_sequence (stream,sequence)))
+    for (i = 1; i <= stream->nmsgs; i++)
+      if (mail_elt (stream,i)->sequence) tenex_elt (stream,i);
+}
+
+/* TENEX mail fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+char *tenex_header (MAILSTREAM *stream,unsigned long msgno,
+		    unsigned long *length,long flags)
+{
+  char *s;
+  unsigned long i;
+  *length = 0;			/* default to empty */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+				/* get to header position */
+  lseek (LOCAL->fd,tenex_hdrpos (stream,msgno,&i),L_SET);
+  if (flags & FT_INTERNAL) {
+    if (i > LOCAL->buflen) {	/* resize if not enough space */
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get (LOCAL->buflen = i + 1);
+    }
+				/* slurp the data */
+    read (LOCAL->fd,LOCAL->buf,*length = i);
+  }
+  else {
+    s = (char *) fs_get (i + 1);/* get readin buffer */
+    s[i] = '\0';		/* tie off string */
+    read (LOCAL->fd,s,i);	/* slurp the data */
+				/* make CRLF copy of string */
+    *length = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen,s,i);
+    fs_give ((void **) &s);	/* free readin buffer */
+  }
+  return (char *) LOCAL->buf;
+}
+
+/* TENEX mail fetch message text (body only)
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned stringstruct
+ *	    option flags
+ * Returns: T, always
+ */
+
+long tenex_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  char *s;
+  unsigned long i,j;
+  MESSAGECACHE *elt;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+				/* get message status */
+  elt = tenex_elt (stream,msgno);
+				/* if message not seen */
+  if (!(flags & FT_PEEK) && !elt->seen) {
+    elt->seen = T;		/* mark message as seen */
+				/* recalculate status */
+    tenex_update_status (stream,msgno,T);
+    MM_FLAGS (stream,msgno);
+  }
+  if (flags & FT_INTERNAL) {	/* if internal representation wanted */
+				/* find header position */
+    i = tenex_hdrpos (stream,msgno,&j);
+    if (i > LOCAL->buflen) {	/* resize if not enough space */
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get (LOCAL->buflen = i + 1);
+    }
+				/* go to text position */
+    lseek (LOCAL->fd,i + j,L_SET);
+				/* slurp the data */
+    read (LOCAL->fd,LOCAL->buf,i);
+				/* set up stringstruct for internal */
+    INIT (bs,mail_string,LOCAL->buf,i);
+  }
+  else {			/* normal form, previous text cached? */
+    if (elt->private.uid == LOCAL->uid)
+      i = elt->private.msg.text.text.size;
+    else {			/* not cached, cache it now */
+      LOCAL->uid = elt->private.uid;
+				/* find header position */
+      i = tenex_hdrpos (stream,msgno,&j);
+				/* go to text position */
+      lseek (LOCAL->fd,i + j,L_SET);
+      s = (char *) fs_get ((i = tenex_size (stream,msgno) - j) + 1);
+      s[i] = '\0';		/* tie off string */
+      read (LOCAL->fd,s,i);	/* slurp the data */
+				/* make CRLF copy of string */
+      i = elt->private.msg.text.text.size =
+	strcrlfcpy (&LOCAL->text.data,&LOCAL->text.size,s,i);
+      fs_give ((void **) &s);	/* free readin buffer */
+    }
+				/* set up stringstruct */
+    INIT (bs,mail_string,LOCAL->text.data,i);
+  }
+  return T;			/* success */
+}
+
+/* Tenex mail modify flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    flag(s)
+ *	    option flags
+ */
+
+void tenex_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
+{
+  time_t tp[2];
+  struct stat sbuf;
+  if (!stream->rdonly) {	/* make sure the update takes */
+    fsync (LOCAL->fd);
+    fstat (LOCAL->fd,&sbuf);	/* get current write time */
+    tp[1] = LOCAL->filetime = sbuf.st_mtime;
+    tp[0] = time (0);		/* make sure read comes after all that */
+    utime (stream->mailbox,tp);
+  }
+}
+
+
+/* Tenex mail per-message modify flags
+ * Accepts: MAIL stream
+ *	    message cache element
+ */
+
+void tenex_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  struct stat sbuf;
+				/* maybe need to do a checkpoint? */
+  if (LOCAL->filetime && !LOCAL->shouldcheck) {
+    fstat (LOCAL->fd,&sbuf);	/* get current write time */
+    if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
+    LOCAL->filetime = 0;	/* don't do this test for any other messages */
+  }
+				/* recalculate status */
+  tenex_update_status (stream,elt->msgno,NIL);
+}
+
+/* Tenex mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream still alive, NIL if not
+ */
+
+long tenex_ping (MAILSTREAM *stream)
+{
+  unsigned long i = 1;
+  long r = T;
+  int ld;
+  char lock[MAILTMPLEN];
+  struct stat sbuf;
+  if (stream && LOCAL) {	/* only if stream already open */
+    fstat (LOCAL->fd,&sbuf);	/* get current file poop */
+    if (LOCAL->filetime && !(LOCAL->mustcheck || LOCAL->shouldcheck) &&
+	(LOCAL->filetime < sbuf.st_mtime)) LOCAL->shouldcheck = T;
+				/* check for changed message status */
+    if (LOCAL->mustcheck || LOCAL->shouldcheck) {
+      LOCAL->filetime = sbuf.st_mtime;
+      if (LOCAL->shouldcheck)	/* babble when we do this unilaterally */
+	MM_NOTIFY (stream,"[CHECK] Checking for flag updates",NIL);
+      while (i <= stream->nmsgs) tenex_elt (stream,i++);
+      LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
+    }
+				/* get shared parse/append permission */
+    if ((sbuf.st_size != LOCAL->filesize) &&
+	((ld = lockfd (LOCAL->fd,lock,LOCK_SH)) >= 0)) {
+				/* parse resulting mailbox */
+      r = (tenex_parse (stream)) ? T : NIL;
+      unlockfd (ld,lock);	/* release shared parse/append permission */
+    }
+    if (LOCAL) {		/* stream must still be alive */
+				/* snarf if this is a read-write inbox */
+      if (stream->inbox && !stream->rdonly) {
+	tenex_snarf (stream);
+	fstat (LOCAL->fd,&sbuf);/* see if file changed now */
+	if ((sbuf.st_size != LOCAL->filesize) &&
+	    ((ld = lockfd (LOCAL->fd,lock,LOCK_SH)) >= 0)) {
+				/* parse resulting mailbox */
+	  r = (tenex_parse (stream)) ? T : NIL;
+	  unlockfd (ld,lock);	/* release shared parse/append permission */
+	}
+      }
+    }
+  }
+  return r;			/* return result of the parse */
+}
+
+
+/* Tenex mail check mailbox (reparses status too)
+ * Accepts: MAIL stream
+ */
+
+void tenex_check (MAILSTREAM *stream)
+{
+				/* mark that a check is desired */
+  if (LOCAL) LOCAL->mustcheck = T;
+  if (tenex_ping (stream)) MM_LOG ("Check completed",(long) NIL);
+}
+
+/* Tenex mail snarf messages from system inbox
+ * Accepts: MAIL stream
+ */
+
+void tenex_snarf (MAILSTREAM *stream)
+{
+  unsigned long i = 0;
+  unsigned long j,r,hdrlen,txtlen;
+  struct stat sbuf;
+  char *hdr,*txt,lock[MAILTMPLEN],tmp[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  MAILSTREAM *sysibx = NIL;
+  int ld;
+				/* give up if can't get exclusive permission */
+  if ((time (0) >= (LOCAL->lastsnarf +
+		    (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL))) &&
+      strcmp (sysinbox (),stream->mailbox) &&
+      ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) >= 0)) {
+    MM_CRITICAL (stream);	/* go critical */
+				/* sizes match and anything in sysinbox? */
+    if (!stat (sysinbox (),&sbuf) && sbuf.st_size &&
+	!fstat (LOCAL->fd,&sbuf) && (sbuf.st_size == LOCAL->filesize) && 
+	(sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) &&
+	(!sysibx->rdonly) && (r = sysibx->nmsgs)) {
+				/* yes, go to end of file in our mailbox */
+      lseek (LOCAL->fd,sbuf.st_size,L_SET);
+				/* for each message in sysibx mailbox */
+      while (r && (++i <= sysibx->nmsgs)) {
+				/* snarf message from system INBOX */
+	hdr = cpystr (mail_fetchheader_full(sysibx,i,NIL,&hdrlen,FT_INTERNAL));
+	txt = mail_fetchtext_full (sysibx,i,&txtlen,FT_INTERNAL|FT_PEEK);
+				/* if have a message */
+	if (j = hdrlen + txtlen) {
+				/* calculate header line */
+	  mail_date (LOCAL->buf,elt = mail_elt (sysibx,i));
+	  sprintf (LOCAL->buf + strlen (LOCAL->buf),
+		   ",%lu;0000000000%02o\n",j,(unsigned)
+		   ((fSEEN * elt->seen) + (fDELETED * elt->deleted) +
+		    (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
+		    (fDRAFT * elt->draft)));
+				/* copy message */
+	  if ((write (LOCAL->fd,LOCAL->buf,strlen (LOCAL->buf)) < 0) ||
+	      (write (LOCAL->fd,hdr,hdrlen) < 0) ||
+	      (write (LOCAL->fd,txt,txtlen) < 0)) r = 0;
+	}
+	fs_give ((void **) &hdr);
+      }
+
+				/* make sure all the updates take */
+      if (fsync (LOCAL->fd)) r = 0;
+      if (r) {			/* delete all the messages we copied */
+	if (r == 1) strcpy (tmp,"1");
+	else sprintf (tmp,"1:%lu",r);
+	mail_flag (sysibx,tmp,"\\Deleted",ST_SET);
+	mail_expunge (sysibx);	/* now expunge all those messages */
+      }
+      else {
+	sprintf (LOCAL->buf,"Can't copy new mail: %s",strerror (errno));
+	MM_LOG (LOCAL->buf,WARN);
+	ftruncate (LOCAL->fd,sbuf.st_size);
+      }
+      fstat (LOCAL->fd,&sbuf);	/* yes, get current file size */
+      LOCAL->filetime = sbuf.st_mtime;
+    }
+    if (sysibx) mail_close (sysibx);
+    MM_NOCRITICAL (stream);	/* release critical */
+    unlockfd (ld,lock);		/* release exclusive parse/append permission */
+    LOCAL->lastsnarf = time (0);/* note time of last snarf */
+  }
+}
+
+/* Tenex mail expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long tenex_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  long ret;
+  time_t tp[2];
+  struct stat sbuf;
+  off_t pos = 0;
+  int ld;
+  unsigned long i = 1;
+  unsigned long j,k,m,recent;
+  unsigned long n = 0;
+  unsigned long delta = 0;
+  char lock[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  if (!(ret = (sequence ? ((options & EX_UID) ?
+			   mail_uid_sequence (stream,sequence) :
+			   mail_sequence (stream,sequence)) : LONGT) &&
+	tenex_ping (stream)));	/* parse sequence if given, ping stream */
+  else if (stream->rdonly) MM_LOG ("Expunge ignored on readonly mailbox",WARN);
+  else {
+    if (LOCAL->filetime && !LOCAL->shouldcheck) {
+      fstat (LOCAL->fd,&sbuf);	/* get current write time */
+      if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
+    }
+  /* The cretins who designed flock() created a window of vulnerability in
+   * upgrading locks from shared to exclusive or downgrading from exclusive
+   * to shared.  Rather than maintain the lock at shared status at a minimum,
+   * flock() actually *releases* the former lock.  Obviously they never talked
+   * to any database guys.  Fortunately, we have the parse/append permission
+   * lock.  If we require this lock before going exclusive on the mailbox,
+   * another process can not sneak in and steal the exclusive mailbox lock on
+   * us, because it will block on trying to get parse/append permission first.
+   */
+				/* get exclusive parse/append permission */
+    if ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) < 0)
+      MM_LOG ("Unable to lock expunge mailbox",ERROR);
+				/* make sure see any newly-arrived messages */
+    else if (!tenex_parse (stream));
+				/* get exclusive access */
+    else if (flock (LOCAL->fd,LOCK_EX|LOCK_NB)) {
+      (*bn) (BLOCK_FILELOCK,NIL);
+      flock (LOCAL->fd,LOCK_SH);/* recover previous lock */
+      (*bn) (BLOCK_NONE,NIL);
+      MM_LOG ("Can't expunge because mailbox is in use by another process",
+	      ERROR);
+      unlockfd (ld,lock);	/* release exclusive parse/append permission */
+    }
+
+    else {
+      MM_CRITICAL (stream);	/* go critical */
+      recent = stream->recent;	/* get recent now that pinged and locked */
+				/* for each message */
+      while (i <= stream->nmsgs) {
+				/* get cache element */
+	elt = tenex_elt (stream,i);
+				/* number of bytes to smash or preserve */
+	k = elt->private.special.text.size + tenex_size (stream,i);
+				/* if need to expunge this message */
+	if (elt->deleted && (sequence ? elt->sequence : T)) {
+				/* if recent, note one less recent message */
+	  if (elt->recent) --recent;
+	  delta += k;		/* number of bytes to delete */
+				/* notify upper levels */
+	  mail_expunged (stream,i);
+	  n++;			/* count up one more expunged message */
+	}
+	else if (i++ && delta) {/* preserved message */
+				/* first byte to preserve */
+	  j = elt->private.special.offset;
+	  do {			/* read from source position */
+	    m = min (k,LOCAL->buflen);
+	    lseek (LOCAL->fd,j,L_SET);
+	    read (LOCAL->fd,LOCAL->buf,m);
+	    pos = j - delta;	/* write to destination position */
+	    lseek (LOCAL->fd,pos,L_SET);
+	    while (T) {
+	      lseek (LOCAL->fd,pos,L_SET);
+	      if (write (LOCAL->fd,LOCAL->buf,m) > 0) break;
+	      MM_NOTIFY (stream,strerror (errno),WARN);
+	      MM_DISKERROR (stream,errno,T);
+	    }
+	    pos += m;		/* new position */
+	    j += m;		/* next chunk, perhaps */
+	  } while (k -= m);		/* until done */
+				/* note the new address of this text */
+	  elt->private.special.offset -= delta;
+	}
+				/* preserved but no deleted messages */
+	else pos = elt->private.special.offset + k;
+      }
+
+      if (n) {			/* truncate file after last message */
+	if (pos != (LOCAL->filesize -= delta)) {
+	  sprintf (LOCAL->buf,
+		   "Calculated size mismatch %lu != %lu, delta = %lu",
+		   (unsigned long) pos,(unsigned long) LOCAL->filesize,delta);
+	  MM_LOG (LOCAL->buf,WARN);
+	  LOCAL->filesize = pos;/* fix it then */
+	}
+	ftruncate (LOCAL->fd,LOCAL->filesize);
+	sprintf (LOCAL->buf,"Expunged %lu messages",n);
+				/* output the news */
+	MM_LOG (LOCAL->buf,(long) NIL);
+      }
+      else MM_LOG ("No messages deleted, so no update needed",(long) NIL);
+      fsync (LOCAL->fd);		/* force disk update */
+      fstat (LOCAL->fd,&sbuf);	/* get new write time */
+      tp[1] = LOCAL->filetime = sbuf.st_mtime;
+      tp[0] = time (0);		/* reset atime to now */
+      utime (stream->mailbox,tp);
+      MM_NOCRITICAL (stream);	/* release critical */
+				/* notify upper level of new mailbox size */
+      mail_exists (stream,stream->nmsgs);
+      mail_recent (stream,recent);
+      (*bn) (BLOCK_FILELOCK,NIL);
+      flock (LOCAL->fd,LOCK_SH);/* allow sharers again */
+      (*bn) (BLOCK_NONE,NIL);
+      unlockfd (ld,lock);	/* release exclusive parse/append permission */
+    }
+  }
+  return LONGT;
+}
+
+/* Tenex mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if success, NIL if failed
+ */
+
+long tenex_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  struct stat sbuf;
+  time_t tp[2];
+  MESSAGECACHE *elt;
+  unsigned long i,j,k;
+  long ret = LONGT;
+  int fd,ld;
+  char file[MAILTMPLEN],lock[MAILTMPLEN];
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+				/* make sure valid mailbox */
+  if (!tenex_isvalid (mailbox,LOCAL->buf)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
+    return NIL;
+  case 0:			/* merely empty file? */
+    break;
+  case EACCES:			/* file protected */
+    sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
+    MM_LOG (LOCAL->buf,ERROR);
+    return NIL;
+  case EINVAL:
+    if (pc) return (*pc) (stream,sequence,mailbox,options);
+    sprintf (LOCAL->buf,"Invalid Tenex-format mailbox name: %.80s",mailbox);
+    MM_LOG (LOCAL->buf,ERROR);
+    return NIL;
+  default:
+    if (pc) return (*pc) (stream,sequence,mailbox,options);
+    sprintf (LOCAL->buf,"Not a Tenex-format mailbox: %.80s",mailbox);
+    MM_LOG (LOCAL->buf,ERROR);
+    return NIL;
+  }
+  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+	mail_sequence (stream,sequence))) return NIL;
+				/* got file? */  
+  if ((fd = open (tenex_file(file,mailbox),O_RDWR,NIL)) < 0) {
+    sprintf (LOCAL->buf,"Unable to open copy mailbox: %s",strerror (errno));
+    MM_LOG (LOCAL->buf,ERROR);
+    return NIL;
+  }
+  MM_CRITICAL (stream);		/* go critical */
+				/* get exclusive parse/append permission */
+  if (flock (fd,LOCK_SH) || ((ld = lockfd (fd,lock,LOCK_EX)) < 0)) {
+    MM_LOG ("Unable to lock copy mailbox",ERROR);
+    MM_NOCRITICAL (stream);
+    return NIL;
+  }
+  fstat (fd,&sbuf);		/* get current file size */
+  lseek (fd,sbuf.st_size,L_SET);/* move to end of file */
+
+				/* for each requested message */
+  for (i = 1; ret && (i <= stream->nmsgs); i++) 
+    if ((elt = mail_elt (stream,i))->sequence) {
+      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
+				/* number of bytes to copy */
+      k = elt->private.special.text.size + tenex_size (stream,i);
+      do {			/* read from source position */
+	j = min (k,LOCAL->buflen);
+	read (LOCAL->fd,LOCAL->buf,j);
+	if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
+      } while (ret && (k -= j));/* until done */
+    }
+				/* make sure all the updates take */
+  if (!(ret && (ret = !fsync (fd)))) {
+    sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno));
+    MM_LOG (LOCAL->buf,ERROR);
+    ftruncate (fd,sbuf.st_size);
+  }
+  if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */
+				/* else preserve \Marked status */
+  else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0);
+  tp[1] = sbuf.st_mtime;	/* preserve mtime */
+  utime (file,tp);		/* set the times */
+  close (fd);			/* close the file */
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+  MM_NOCRITICAL (stream);	/* release critical */
+				/* delete all requested messages */
+  if (ret && (options & CP_MOVE)) {
+    for (i = 1; i <= stream->nmsgs; i++)
+      if ((elt = tenex_elt (stream,i))->sequence) {
+	elt->deleted = T;	/* mark message deleted */
+				/* recalculate status */
+	tenex_update_status (stream,i,NIL);
+      }
+    if (!stream->rdonly) {	/* make sure the update takes */
+      fsync (LOCAL->fd);
+      fstat (LOCAL->fd,&sbuf);	/* get current write time */
+      tp[1] = LOCAL->filetime = sbuf.st_mtime;
+      tp[0] = time (0);		/* make sure atime remains greater */
+      utime (stream->mailbox,tp);
+    }
+  }
+  if (ret && mail_parameters (NIL,GET_COPYUID,NIL))
+    MM_LOG ("Can not return meaningful COPYUID with this mailbox format",WARN);
+  return ret;
+}
+
+/* Tenex mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long tenex_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct stat sbuf;
+  int fd,ld,c;
+  char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  time_t tp[2];
+  FILE *df;
+  MESSAGECACHE elt;
+  long f;
+  unsigned long i,j,uf,size;
+  STRING *message;
+  long ret = LONGT;
+				/* default stream to prototype */
+  if (!stream) stream = user_flags (&tenexproto);
+				/* make sure valid mailbox */
+  if (!tenex_isvalid (mailbox,tmp)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    if (!compare_cstring (mailbox,"INBOX")) dummy_create (NIL,"mail.txt");
+    else {
+      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+      return NIL;
+    }
+				/* falls through */
+  case 0:			/* merely empty file? */
+    break;
+  case EACCES:			/* file protected */
+    sprintf (tmp,"Can't access destination: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  case EINVAL:
+    sprintf (tmp,"Invalid TENEX-format mailbox name: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  default:
+    sprintf (tmp,"Not a TENEX-format mailbox: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+				/* get first message */
+  if (!MM_APPEND (af) (stream,data,&flags,&date,&message)) return NIL;
+
+				/* open destination mailbox */
+  if (((fd = open (tenex_file (file,mailbox),O_WRONLY|O_APPEND,NIL)) < 0) ||
+      !(df = fdopen (fd,"ab"))) {
+    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+				/* get parse/append permission */
+  if (flock (fd,LOCK_SH) || ((ld = lockfd (fd,lock,LOCK_EX)) < 0)) {
+    MM_LOG ("Unable to lock append mailbox",ERROR);
+    close (fd);
+    return NIL;
+  }
+  MM_CRITICAL (stream);		/* go critical */
+  fstat (fd,&sbuf);		/* get current file size */
+  errno = 0;
+  do {				/* parse flags */ 
+    if (!SIZE (message)) {	/* guard against zero-length */
+      MM_LOG ("Append of zero-length message",ERROR);
+      ret = NIL;
+      break;
+    }
+    f = mail_parse_flags (stream,flags,&i);
+				/* reverse bits (dontcha wish we had CIRC?) */
+    for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i)));
+    if (date) {			/* parse date if given */
+      if (!mail_parse_date (&elt,date)) {
+	sprintf (tmp,"Bad date in append: %.80s",date);
+	MM_LOG (tmp,ERROR);
+	ret = NIL;		/* mark failure */
+	break;
+      }
+      mail_date (tmp,&elt);	/* write preseved date */
+    }
+    else internal_date (tmp);	/* get current date in IMAP format */
+    i = GETPOS (message);	/* remember current position */
+    for (j = SIZE (message), size = 0; j; --j)
+      if (SNX (message) != '\015') ++size;
+    SETPOS (message,i);		/* restore position */
+				/* write header */
+    if (fprintf (df,"%s,%lu;%010lo%02lo\n",tmp,size,uf,(unsigned long) f) < 0)
+      ret = NIL;
+    else {			/* write message */
+      while (size) if ((c = 0xff & SNX (message)) != '\015') {
+	if (putc (c,df) != EOF) --size;
+	else break;
+      }
+				/* get next message */
+      if (size || !MM_APPEND (af) (stream,data,&flags,&date,&message))
+	ret = NIL;
+    }
+  } while (ret && message);
+				/* if error... */
+  if (!ret || (fflush (df) == EOF)) {
+    ftruncate (fd,sbuf.st_size);/* revert file */
+    close (fd);			/* make sure fclose() doesn't corrupt us */
+    if (errno) {
+      sprintf (tmp,"Message append failed: %s",strerror (errno));
+      MM_LOG (tmp,ERROR);
+    }
+    ret = NIL;
+  }
+  if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */
+				/* else preserve \Marked status */
+  else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0);
+  tp[1] = sbuf.st_mtime;	/* preserve mtime */
+  utime (file,tp);		/* set the times */
+  fclose (df);			/* close the file */
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+  MM_NOCRITICAL (stream);	/* release critical */
+  if (ret && mail_parameters (NIL,GET_APPENDUID,NIL))
+    MM_LOG ("Can not return meaningful APPENDUID with this mailbox format",
+	    WARN);
+  return ret;
+}
+
+/* Internal routines */
+
+
+/* Tenex mail return internal message size in bytes
+ * Accepts: MAIL stream
+ *	    message #
+ * Returns: internal size of message
+ */
+
+unsigned long tenex_size (MAILSTREAM *stream,unsigned long m)
+{
+  MESSAGECACHE *elt = mail_elt (stream,m);
+  return ((m < stream->nmsgs) ? mail_elt (stream,m+1)->private.special.offset :
+	  LOCAL->filesize) -
+	    (elt->private.special.offset + elt->private.special.text.size);
+}
+
+
+/* Tenex mail generate file string
+ * Accepts: temporary buffer to write into
+ *	    mailbox name string
+ * Returns: local file string or NIL if failure
+ */
+
+char *tenex_file (char *dst,char *name)
+{
+  char tmp[MAILTMPLEN];
+  char *s = mailboxfile (dst,name);
+				/* return our standard inbox */
+  return (s && !*s) ? mailboxfile (dst,tenex_isvalid ("~/INBOX",tmp) ?
+				   "~/INBOX" : "mail.txt") : s;
+}
+
+/* Tenex mail parse mailbox
+ * Accepts: MAIL stream
+ * Returns: T if parse OK
+ *	    NIL if failure, stream aborted
+ */
+
+long tenex_parse (MAILSTREAM *stream)
+{
+  struct stat sbuf;
+  MESSAGECACHE *elt = NIL;
+  unsigned char c,*s,*t,*x;
+  char tmp[MAILTMPLEN];
+  unsigned long i,j;
+  long curpos = LOCAL->filesize;
+  long nmsgs = stream->nmsgs;
+  long recent = stream->recent;
+  short added = NIL;
+  short silent = stream->silent;
+  fstat (LOCAL->fd,&sbuf);	/* get status */
+  if (sbuf.st_size < curpos) {	/* sanity check */
+    sprintf (tmp,"Mailbox shrank from %lu to %lu!",
+	     (unsigned long) curpos,(unsigned long) sbuf.st_size);
+    MM_LOG (tmp,ERROR);
+    tenex_close (stream,NIL);
+    return NIL;
+  }
+  stream->silent = T;		/* don't pass up exists events yet */
+  while (sbuf.st_size - curpos){/* while there is stuff to parse */
+				/* get to that position in the file */
+    lseek (LOCAL->fd,curpos,L_SET);
+    if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) {
+      sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s",
+	       (unsigned long) curpos,(unsigned long) sbuf.st_size,
+	       i ? strerror (errno) : "no data read");
+      MM_LOG (tmp,ERROR);
+      tenex_close (stream,NIL);
+      return NIL;
+    }
+    LOCAL->buf[i] = '\0';	/* tie off buffer just in case */
+    if (!(s = strchr (LOCAL->buf,'\012'))) {
+      sprintf (tmp,"Unable to find newline at %lu in %lu bytes, text: %s",
+	       (unsigned long) curpos,i,(char *) LOCAL->buf);
+      MM_LOG (tmp,ERROR);
+      tenex_close (stream,NIL);
+      return NIL;
+    }
+    *s = '\0';			/* tie off header line */
+    i = (s + 1) - LOCAL->buf;	/* note start of text offset */
+    if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) {
+      sprintf (tmp,"Unable to parse internal header at %lu: %s",
+	       (unsigned long) curpos,(char *) LOCAL->buf);
+      MM_LOG (tmp,ERROR);
+      tenex_close (stream,NIL);
+      return NIL;
+    }
+    *s++ = '\0'; *t++ = '\0';	/* tie off fields */
+
+    added = T;			/* note that a new message was added */
+				/* swell the cache */
+    mail_exists (stream,++nmsgs);
+				/* instantiate an elt for this message */
+    (elt = mail_elt (stream,nmsgs))->valid = T;
+    elt->private.uid = ++stream->uid_last;
+				/* note file offset of header */
+    elt->private.special.offset = curpos;
+				/* in case error */
+    elt->private.special.text.size = 0;
+				/* header size not known yet */
+    elt->private.msg.header.text.size = 0;
+    x = s;			/* parse the header components */
+    if (mail_parse_date (elt,LOCAL->buf) &&
+	(elt->private.msg.full.text.size = strtoul (s,(char **) &s,10)) &&
+	(!(s && *s)) && isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) &&
+	isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) &&
+	isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) &&
+	isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12])
+      elt->private.special.text.size = i;
+    else {			/* oops */
+      sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s",
+	       curpos,(char *) LOCAL->buf,(char *) x,(char *) t);
+      MM_LOG (tmp,ERROR);
+      tenex_close (stream,NIL);
+      return NIL;
+    }
+				/* make sure didn't run off end of file */
+    if ((curpos += (elt->private.msg.full.text.size + i)) > sbuf.st_size) {
+      sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
+	       elt->private.special.offset,(unsigned long) curpos,
+	       (unsigned long) sbuf.st_size);
+      MM_LOG (tmp,ERROR);
+      tenex_close (stream,NIL);
+      return NIL;
+    }
+    c = t[10];			/* remember first system flags byte */
+    t[10] = '\0';		/* tie off flags */
+    j = strtoul (t,NIL,8);	/* get user flags value */
+    t[10] = c;			/* restore first system flags byte */
+				/* set up all valid user flags (reversed!) */
+    while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
+		  stream->user_flags[i]) elt->user_flags |= 1 << i;
+				/* calculate system flags */
+    if ((j = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T;
+    if (j & fDELETED) elt->deleted = T;
+    if (j & fFLAGGED) elt->flagged = T;
+    if (j & fANSWERED) elt->answered = T;
+    if (j & fDRAFT) elt->draft = T;
+    if (!(j & fOLD)) {		/* newly arrived message? */
+      elt->recent = T;
+      recent++;			/* count up a new recent message */
+				/* mark it as old */
+      tenex_update_status (stream,nmsgs,NIL);
+    }
+  }
+  fsync (LOCAL->fd);		/* make sure all the fOLD flags take */
+				/* update parsed file size and time */
+  LOCAL->filesize = sbuf.st_size;
+  fstat (LOCAL->fd,&sbuf);	/* get status again to ensure time is right */
+  LOCAL->filetime = sbuf.st_mtime;
+  if (added && !stream->rdonly){/* make sure atime updated */
+    time_t tp[2];
+    tp[0] = time (0);
+    tp[1] = LOCAL->filetime;
+    utime (stream->mailbox,tp);
+  }
+  stream->silent = silent;	/* can pass up events now */
+  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
+  mail_recent (stream,recent);	/* and of change in recent messages */
+  return LONGT;			/* return the winnage */
+}
+
+/* Tenex get cache element with status updating from file
+ * Accepts: MAIL stream
+ *	    message number
+ * Returns: cache element
+ */
+
+MESSAGECACHE *tenex_elt (MAILSTREAM *stream,unsigned long msgno)
+{
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  struct {			/* old flags */
+    unsigned int seen : 1;
+    unsigned int deleted : 1;
+    unsigned int flagged : 1;
+    unsigned int answered : 1;
+    unsigned int draft : 1;
+    unsigned long user_flags;
+  } old;
+  old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged;
+  old.answered = elt->answered; old.draft = elt->draft;
+  old.user_flags = elt->user_flags;
+  tenex_read_flags (stream,elt);
+  if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
+      (old.flagged != elt->flagged) || (old.answered != elt->answered) ||
+      (old.draft != elt->draft) || (old.user_flags != elt->user_flags))
+    MM_FLAGS (stream,msgno);	/* let top level know */
+  return elt;
+}
+
+/* Tenex read flags from file
+ * Accepts: MAIL stream
+ * Returns: cache element
+ */
+
+void tenex_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  unsigned long i,j;
+				/* noop if readonly and have valid flags */
+  if (stream->rdonly && elt->valid) return;
+				/* set the seek pointer */
+  lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	 elt->private.special.text.size - 13,L_SET);
+				/* read the new flags */
+  if (read (LOCAL->fd,LOCAL->buf,12) < 0) {
+    sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno));
+    fatal (LOCAL->buf);
+  }
+				/* calculate system flags */
+  i = (((LOCAL->buf[10]-'0') * 8) + LOCAL->buf[11]-'0');
+  elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL;
+  elt->flagged = i & fFLAGGED ? T : NIL;
+  elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL;
+  LOCAL->buf[10] = '\0';	/* tie off flags */
+  j = strtoul(LOCAL->buf,NIL,8);/* get user flags value */
+				/* set up all valid user flags (reversed!) */
+  while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
+		stream->user_flags[i]) elt->user_flags |= 1 << i;
+  elt->valid = T;		/* have valid flags now */
+}
+
+/* Tenex update status string
+ * Accepts: MAIL stream
+ *	    message number
+ *	    flag saying whether or not to sync
+ */
+
+void tenex_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag)
+{
+  time_t tp[2];
+  struct stat sbuf;
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  unsigned long j,k = 0;
+				/* readonly */
+  if (stream->rdonly || !elt->valid) tenex_read_flags (stream,elt);
+  else {			/* readwrite */
+    j = elt->user_flags;	/* get user flags */
+				/* reverse bits (dontcha wish we had CIRC?) */
+    while (j) k |= 1 << (29 - find_rightmost_bit (&j));
+				/* print new flag string */
+    sprintf (LOCAL->buf,"%010lo%02o",k,(unsigned)
+	     (fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
+	      (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
+	      (fDRAFT * elt->draft)));
+				/* get to that place in the file */
+    lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	   elt->private.special.text.size - 13,L_SET);
+				/* write new flags */
+    write (LOCAL->fd,LOCAL->buf,12);
+    if (syncflag) {		/* sync if requested */
+      fsync (LOCAL->fd);
+      fstat (LOCAL->fd,&sbuf);	/* get new write time */
+      tp[1] = LOCAL->filetime = sbuf.st_mtime;
+      tp[0] = time (0);		/* make sure read is later */
+      utime (stream->mailbox,tp);
+    }
+  }
+}
+
+/* Tenex locate header for a message
+ * Accepts: MAIL stream
+ *	    message number
+ *	    pointer to returned header size
+ * Returns: position of header in file
+ */
+
+unsigned long tenex_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			    unsigned long *size)
+{
+  unsigned long siz;
+  long i = 0;
+  char c = '\0';
+  char *s = NIL;
+  MESSAGECACHE *elt = tenex_elt (stream,msgno);
+  unsigned long ret = elt->private.special.offset +
+    elt->private.special.text.size;
+  unsigned long msiz = tenex_size (stream,msgno);
+				/* is header size known? */
+  if (!(*size = elt->private.msg.header.text.size)) {
+    lseek (LOCAL->fd,ret,L_SET);/* get to header position */
+				/* search message for LF LF */
+    for (siz = 0; siz < msiz; siz++) {
+      if (--i <= 0)		/* read another buffer as necessary */
+	read (LOCAL->fd,s = LOCAL->buf,i = min (msiz-siz,(long) MAILTMPLEN));
+				/* two newline sequence? */
+      if ((c == '\012') && (*s == '\012')) {
+				/* yes, note for later */
+	elt->private.msg.header.text.size = (*size = siz + 1);
+		
+	return ret;		/* return to caller */
+      }
+      else c = *s++;		/* next character */
+    }
+				/* header consumes entire message */
+    elt->private.msg.header.text.size = *size = msiz;
+  }
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/tz_bsd.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,38 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	BSD-style Time Zone String
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	30 August 1994
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Append local timezone name
+ * Accepts: destination string
+ */
+
+void rfc822_timezone (char *s,void *t)
+{
+				/* append timezone from tm struct */
+  sprintf (s + strlen (s)," (%.50s)",((struct tm *) t)->tm_zone);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/unix.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,2708 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX mail routines
+ *
+ * Author:	Mark Crispin
+ *		UW Technology
+ *		University of Washington
+ *		Seattle, WA  98195
+ *		Internet: MRC@Washington.EDU
+ *
+ * Date:	20 December 1989
+ * Last Edited:	27 March 2008
+ */
+
+
+/*				DEDICATION
+ *
+ *  This file is dedicated to my dog, Unix, also known as Yun-chan and
+ * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast.  Unix
+ * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after
+ * a two-month bout with cirrhosis of the liver.
+ *
+ *  He was a dear friend, and I miss him terribly.
+ *
+ *  Lift a leg, Yunie.  Luv ya forever!!!!
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <signal.h>
+#include "mail.h"
+#include "osdep.h"
+#include <time.h>
+#include <sys/stat.h>
+#include "unix.h"
+#include "pseudo.h"
+#include "fdstring.h"
+#include "misc.h"
+#include "dummy.h"
+
+/* UNIX I/O stream local data */
+
+typedef struct unix_local {
+  unsigned int dirty : 1;	/* disk copy needs updating */
+  unsigned int ddirty : 1;	/* double-dirty, ping becomes checkpoint */
+  unsigned int pseudo : 1;	/* uses a pseudo message */
+  unsigned int appending : 1;	/* don't mark new messages as old */
+  int fd;			/* mailbox file descriptor */
+  int ld;			/* lock file descriptor */
+  char *lname;			/* lock file name */
+  off_t filesize;		/* file size parsed */
+  time_t filetime;		/* last file time */
+  time_t lastsnarf;		/* last snarf time (for mbox driver) */
+  unsigned char *buf;		/* temporary buffer */
+  unsigned long buflen;		/* current size of temporary buffer */
+  unsigned long uid;		/* current text uid */
+  SIZEDTEXT text;		/* current text */
+  unsigned long textlen;	/* current text length */
+  char *line;			/* returned line */
+  char *linebuf;		/* line readin buffer */
+  unsigned long linebuflen;	/* current line readin buffer length */
+} UNIXLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((UNIXLOCAL *) stream->local)
+
+
+/* UNIX protected file structure */
+
+typedef struct unix_file {
+  MAILSTREAM *stream;		/* current stream */
+  off_t curpos;			/* current file position */
+  off_t protect;		/* protected position */
+  off_t filepos;		/* current last written file position */
+  char *buf;			/* overflow buffer */
+  size_t buflen;		/* current overflow buffer length */
+  char *bufpos;			/* current buffer position */
+} UNIXFILE;
+
+/* Function prototypes */
+
+DRIVER *unix_valid (char *name);
+long unix_isvalid_fd (int fd);
+void *unix_parameters (long function,void *value);
+void unix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void unix_list (MAILSTREAM *stream,char *ref,char *pat);
+void unix_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long unix_create (MAILSTREAM *stream,char *mailbox);
+long unix_delete (MAILSTREAM *stream,char *mailbox);
+long unix_rename (MAILSTREAM *stream,char *old,char *newname);
+MAILSTREAM *unix_open (MAILSTREAM *stream);
+void unix_close (MAILSTREAM *stream,long options);
+char *unix_header (MAILSTREAM *stream,unsigned long msgno,
+		   unsigned long *length,long flags);
+long unix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+char *unix_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
+		      unsigned long *length,long flags);
+void unix_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
+long unix_ping (MAILSTREAM *stream);
+void unix_check (MAILSTREAM *stream);
+long unix_expunge (MAILSTREAM *stream,char *sequence,long options);
+long unix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long unix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+int unix_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
+		     STRING *msg);
+int unix_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set);
+
+void unix_abort (MAILSTREAM *stream);
+char *unix_file (char *dst,char *name);
+int unix_lock (char *file,int flags,int mode,DOTLOCK *lock,int op);
+void unix_unlock (int fd,MAILSTREAM *stream,DOTLOCK *lock);
+int unix_parse (MAILSTREAM *stream,DOTLOCK *lock,int op);
+char *unix_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size);
+unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr);
+unsigned long unix_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt,
+			    unsigned long uid,long flag);
+long unix_rewrite (MAILSTREAM *stream,unsigned long *nexp,DOTLOCK *lock,
+		   long flags);
+long unix_extend (MAILSTREAM *stream,unsigned long size);
+void unix_write (UNIXFILE *f,char *s,unsigned long i);
+void unix_phys_write (UNIXFILE *f,char *buf,size_t size);
+
+/* mbox mail routines */
+
+/* Function prototypes */
+
+DRIVER *mbox_valid (char *name);
+long mbox_create (MAILSTREAM *stream,char *mailbox);
+long mbox_delete (MAILSTREAM *stream,char *mailbox);
+long mbox_rename (MAILSTREAM *stream,char *old,char *newname);
+long mbox_status (MAILSTREAM *stream,char *mbx,long flags);
+MAILSTREAM *mbox_open (MAILSTREAM *stream);
+long mbox_ping (MAILSTREAM *stream);
+void mbox_check (MAILSTREAM *stream);
+long mbox_expunge (MAILSTREAM *stream,char *sequence,long options);
+long mbox_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+
+/* UNIX mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER unixdriver = {
+  "unix",			/* driver name */
+				/* driver flags */
+  DR_LOCAL|DR_MAIL|DR_LOCKING|DR_NONEWMAILRONLY|DR_XPOINT,
+  (DRIVER *) NIL,		/* next driver */
+  unix_valid,			/* mailbox is valid for us */
+  unix_parameters,		/* manipulate parameters */
+  unix_scan,			/* scan mailboxes */
+  unix_list,			/* list mailboxes */
+  unix_lsub,			/* list subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  unix_create,			/* create mailbox */
+  unix_delete,			/* delete mailbox */
+  unix_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  unix_open,			/* open mailbox */
+  unix_close,			/* close mailbox */
+  NIL,				/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  unix_header,			/* fetch message header */
+  unix_text,			/* fetch message text */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  NIL,				/* modify flags */
+  unix_flagmsg,			/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  unix_ping,			/* ping mailbox to see if still alive */
+  unix_check,			/* check for new messages */
+  unix_expunge,			/* expunge deleted messages */
+  unix_copy,			/* copy messages to another mailbox */
+  unix_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM unixproto = {&unixdriver};
+
+				/* driver parameters */
+static long unix_fromwidget = T;
+
+/* UNIX mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *unix_valid (char *name)
+{
+  int fd;
+  DRIVER *ret = NIL;
+  char *t,file[MAILTMPLEN];
+  struct stat sbuf;
+  time_t tp[2];
+  errno = EINVAL;		/* assume invalid argument */
+				/* must be non-empty file */
+  if ((t = dummy_file (file,name)) && !stat (t,&sbuf)) {
+    if (!sbuf.st_size)errno = 0;/* empty file */
+    else if ((fd = open (file,O_RDONLY,NIL)) >= 0) {
+				/* OK if mailbox format good */
+      if (unix_isvalid_fd (fd)) ret = &unixdriver;
+      else errno = -1;		/* invalid format */
+      close (fd);		/* close the file */
+				/* \Marked status? */
+      if ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) {
+	tp[0] = sbuf.st_atime;	/* yes, preserve atime and mtime */
+	tp[1] = sbuf.st_mtime;
+	utime (file,tp);	/* set the times */
+      }
+    }
+  }
+  return ret;			/* return what we should */
+}
+
+/* UNIX mail test for valid mailbox
+ * Accepts: file descriptor
+ *	    scratch buffer
+ * Returns: T if valid, NIL otherwise
+ */
+
+long unix_isvalid_fd (int fd)
+{
+  int zn;
+  int ret = NIL;
+  char tmp[MAILTMPLEN],*s,*t,c = '\n';
+  memset (tmp,'\0',MAILTMPLEN);
+  if (read (fd,tmp,MAILTMPLEN-1) >= 0) {
+    for (s = tmp; (*s == '\r') || (*s == '\n') || (*s == ' ') || (*s == '\t');)
+      c = *s++;
+    if (c == '\n') VALID (s,t,ret,zn);
+  }
+  return ret;			/* return what we should */
+}
+
+
+/* UNIX manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *unix_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case GET_INBOXPATH:
+    if (value) ret = dummy_file ((char *) value,"INBOX");
+    break;
+  case SET_FROMWIDGET:
+    unix_fromwidget = (long) value;
+  case GET_FROMWIDGET:
+    ret = (void *) unix_fromwidget;
+    break;
+  }
+  return ret;
+}
+
+/* UNIX mail scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void unix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* UNIX mail list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void unix_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_list (NIL,ref,pat);
+}
+
+
+/* UNIX mail list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void unix_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_lsub (NIL,ref,pat);
+}
+
+/* UNIX mail create mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long unix_create (MAILSTREAM *stream,char *mailbox)
+{
+  char *s,mbx[MAILTMPLEN],tmp[MAILTMPLEN];
+  long ret = NIL;
+  int i,fd;
+  time_t ti = time (0);
+  if (!(s = dummy_file (mbx,mailbox))) {
+    sprintf (tmp,"Can't create %.80s: invalid name",mailbox);
+    MM_LOG (tmp,ERROR);
+  }
+				/* create underlying file */
+  else if (dummy_create_path (stream,s,get_dir_protection (mailbox))) {
+				/* done if dir-only or whiner */
+    if (((s = strrchr (s,'/')) && !s[1]) ||
+	mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) ret = T;
+    else if ((fd = open (mbx,O_WRONLY,
+		    (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0) {
+      sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno));
+      MM_LOG (tmp,ERROR);
+      unlink (mbx);		/* delete the file */
+    }
+    else {			/* initialize header */
+      memset (tmp,'\0',MAILTMPLEN);
+      sprintf (tmp,"From %s %sDate: ",pseudo_from,ctime (&ti));
+      rfc822_fixed_date (s = tmp + strlen (tmp));
+				/* write the pseudo-header */
+      sprintf (s += strlen (s),
+	       "\nFrom: %s <%s@%s>\nSubject: %s\nX-IMAP: %010lu 0000000000",
+	       pseudo_name,pseudo_from,mylocalhost (),pseudo_subject,
+	       (unsigned long) ti);
+      for (i = 0; i < NUSERFLAGS; ++i) if (default_user_flag (i))
+	sprintf (s += strlen (s)," %s",default_user_flag (i));
+      sprintf (s += strlen (s),"\nStatus: RO\n\n%s\n\n",pseudo_msg);
+      if (write (fd,tmp,strlen (tmp)) > 0) ret = T;
+      else {
+	sprintf (tmp,"Can't initialize mailbox node %.80s: %s",mbx,
+		 strerror (errno));
+	MM_LOG (tmp,ERROR);
+	unlink (mbx);		/* delete the file */
+      }
+      close (fd);		/* close file */
+    }
+  }
+				/* set proper protections */
+  return ret ? set_mbx_protections (mailbox,mbx) : NIL;
+}
+
+/* UNIX mail delete mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long unix_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return unix_rename (stream,mailbox,NIL);
+}
+
+
+/* UNIX mail rename mailbox
+ * Accepts: MAIL stream
+ *	    old mailbox name
+ *	    new mailbox name (or NIL for delete)
+ * Returns: T on success, NIL on failure
+ */
+
+long unix_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  long ret = NIL;
+  char c,*s = NIL;
+  char tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  DOTLOCK lockx;
+  int fd,ld;
+  long i;
+  struct stat sbuf;
+  MM_CRITICAL (stream);		/* get the c-client lock */
+  if (!dummy_file (file,old) ||
+      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
+		   ((s = strrchr (tmp,'/')) && !s[1]))))
+    sprintf (tmp,newname ?
+	     "Can't rename mailbox %.80s to %.80s: invalid name" :
+	     "Can't delete mailbox %.80s: invalid name",
+	     old,newname);
+				/* lock out other c-clients */
+  else if ((ld = lockname (lock,file,LOCK_EX|LOCK_NB,&i)) < 0)
+    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
+
+  else {
+    if ((fd = unix_lock (file,O_RDWR,
+			 (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
+			 &lockx,LOCK_EX)) < 0)
+      sprintf (tmp,"Can't lock mailbox %.80s: %s",old,strerror (errno));
+    else {
+      if (newname) {		/* want rename? */
+				/* found superior to destination name? */
+	if (s = strrchr (s,'/')) {
+	  c = *++s;		/* remember first character of inferior */
+	  *s = '\0';		/* tie off to get just superior */
+				/* name doesn't exist, create it */
+	  if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+	      !dummy_create_path (stream,tmp,get_dir_protection (newname))) {
+	    unix_unlock (fd,NIL,&lockx);
+	    unix_unlock (ld,NIL,NIL);
+	    unlink (lock);
+	    MM_NOCRITICAL (stream);
+	    return ret;		/* return success or failure */
+	  }
+	  *s = c;		/* restore full name */
+	}
+	if (rename (file,tmp))
+	  sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
+		   strerror (errno));
+	else ret = T;		/* set success */
+      }
+      else if (unlink (file))
+	sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
+      else ret = T;		/* set success */
+      unix_unlock (fd,NIL,&lockx);
+    }
+    unix_unlock (ld,NIL,NIL);	/* flush the lock */
+    unlink (lock);
+  }
+  MM_NOCRITICAL (stream);	/* no longer critical */
+  if (!ret) MM_LOG (tmp,ERROR);	/* log error */
+  return ret;			/* return success or failure */
+}
+
+/* UNIX mail open
+ * Accepts: Stream to open
+ * Returns: Stream on success, NIL on failure
+ */
+
+MAILSTREAM *unix_open (MAILSTREAM *stream)
+{
+  long i;
+  int fd;
+  char tmp[MAILTMPLEN];
+  DOTLOCK lock;
+  long retry;
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return user_flags (&unixproto);
+  retry = stream->silent ? 1 : KODRETRY;
+  if (stream->local) fatal ("unix recycle stream");
+  stream->local = memset (fs_get (sizeof (UNIXLOCAL)),0,sizeof (UNIXLOCAL));
+				/* note if an INBOX or not */
+  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
+				/* canonicalize the stream mailbox name */
+  if (!dummy_file (tmp,stream->mailbox)) {
+    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+				/* flush old name */
+  fs_give ((void **) &stream->mailbox);
+				/* save canonical name */
+  stream->mailbox = cpystr (tmp);
+  LOCAL->fd = LOCAL->ld = -1;	/* no file or state locking yet */
+  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
+  LOCAL->buflen = CHUNKSIZE - 1;
+  LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE);
+  LOCAL->text.size = CHUNKSIZE - 1;
+  LOCAL->linebuf = (char *) fs_get (CHUNKSIZE);
+  LOCAL->linebuflen = CHUNKSIZE - 1;
+  stream->sequence++;		/* bump sequence number */
+
+				/* make lock for read/write access */
+  if (!stream->rdonly) while (retry) {
+				/* try to lock file */
+    if ((fd = lockname (tmp,stream->mailbox,LOCK_EX|LOCK_NB,&i)) < 0) {
+				/* suppressing kiss-of-death? */
+      if (stream->nokod) retry = 0;
+				/* no, first time through? */
+      else if (retry-- == KODRETRY) {
+				/* learned other guy's PID and can signal? */
+	if (i && !kill ((int) i,SIGUSR2)) {
+	  sprintf (tmp,"Trying to get mailbox lock from process %ld",i);
+	  MM_LOG (tmp,WARN);
+	}
+	else retry = 0;		/* give up */
+      }
+      if (!stream->silent) {	/* nothing if silent stream */
+	if (retry) sleep (1);	/* wait a second before trying again */
+	else MM_LOG ("Mailbox is open by another process, access is readonly",
+		     WARN);
+      }
+    }
+    else {			/* got the lock, nobody else can alter state */
+      LOCAL->ld = fd;		/* note lock's fd and name */
+      LOCAL->lname = cpystr (tmp);
+				/* make sure mode OK (don't use fchmod()) */
+      chmod (LOCAL->lname,(long) mail_parameters (NIL,GET_LOCKPROTECTION,NIL));
+      if (stream->silent) i = 0;/* silent streams won't accept KOD */
+      else {			/* note our PID in the lock */
+	sprintf (tmp,"%d",getpid ());
+	write (fd,tmp,(i = strlen (tmp))+1);
+      }
+      ftruncate (fd,i);		/* make sure tied off */
+      fsync (fd);		/* make sure it's available */
+      retry = 0;		/* no more need to try */
+    }
+  }
+
+				/* parse mailbox */
+  stream->nmsgs = stream->recent = 0;
+				/* will we be able to get write access? */
+  if ((LOCAL->ld >= 0) && access (stream->mailbox,W_OK) && (errno == EACCES)) {
+    MM_LOG ("Can't get write access to mailbox, access is readonly",WARN);
+    flock (LOCAL->ld,LOCK_UN);	/* release the lock */
+    close (LOCAL->ld);		/* close the lock file */
+    LOCAL->ld = -1;		/* no more lock fd */
+    unlink (LOCAL->lname);	/* delete it */
+  }
+				/* reset UID validity */
+  stream->uid_validity = stream->uid_last = 0;
+  if (stream->silent && !stream->rdonly && (LOCAL->ld < 0))
+    unix_abort (stream);	/* abort if can't get RW silent stream */
+				/* parse mailbox */
+  else if (unix_parse (stream,&lock,LOCK_SH)) {
+    unix_unlock (LOCAL->fd,stream,&lock);
+    mail_unlock (stream);
+    MM_NOCRITICAL (stream);	/* done with critical */
+  }
+  if (!LOCAL) return NIL;	/* failure if stream died */
+				/* make sure upper level knows readonly */
+  stream->rdonly = (LOCAL->ld < 0);
+				/* notify about empty mailbox */
+  if (!(stream->nmsgs || stream->silent)) MM_LOG ("Mailbox is empty",NIL);
+  if (!stream->rdonly) {	/* flags stick if readwrite */
+    stream->perm_seen = stream->perm_deleted =
+      stream->perm_flagged = stream->perm_answered = stream->perm_draft = T;
+    if (!stream->uid_nosticky) {/* users with lives get permanent keywords */
+      stream->perm_user_flags = 0xffffffff;
+				/* and maybe can create them too! */
+      stream->kwd_create = stream->user_flags[NUSERFLAGS-1] ? NIL : T;
+    }
+  }
+  return stream;		/* return stream alive to caller */
+}
+
+
+/* UNIX mail close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void unix_close (MAILSTREAM *stream,long options)
+{
+  int silent = stream->silent;
+  stream->silent = T;		/* go silent */
+				/* expunge if requested */
+  if (options & CL_EXPUNGE) unix_expunge (stream,NIL,NIL);
+				/* else dump final checkpoint */
+  else if (LOCAL->dirty) unix_check (stream);
+  stream->silent = silent;	/* restore old silence state */
+  unix_abort (stream);		/* now punt the file and local data */
+}
+
+/* UNIX mail fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+				/* lines to filter from header */
+static STRINGLIST *unix_hlines = NIL;
+
+char *unix_header (MAILSTREAM *stream,unsigned long msgno,
+		   unsigned long *length,long flags)
+{
+  MESSAGECACHE *elt;
+  unsigned char *s,*t,*tl;
+  *length = 0;			/* default to empty */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+  elt = mail_elt (stream,msgno);/* get cache */
+  if (!unix_hlines) {		/* once only code */
+    STRINGLIST *lines = unix_hlines = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "Status"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-Status"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-Keywords"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-UID"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-IMAP"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-IMAPbase"));
+  }
+				/* go to header position */
+  lseek (LOCAL->fd,elt->private.special.offset +
+	 elt->private.msg.header.offset,L_SET);
+
+  if (flags & FT_INTERNAL) {	/* initial data OK? */
+    if (elt->private.msg.header.text.size > LOCAL->buflen) {
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
+				     elt->private.msg.header.text.size) + 1);
+    }
+				/* read message */
+    read (LOCAL->fd,LOCAL->buf,elt->private.msg.header.text.size);
+				/* got text, tie off string */
+    LOCAL->buf[*length = elt->private.msg.header.text.size] = '\0';
+				/* squeeze out CRs (in case from PC) */
+    for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++)
+      if (*t != '\r') *s++ = *t;
+    *s = '\0';
+    *length = s - LOCAL->buf;	/* adjust length */
+  }
+  else {			/* need to make a CRLF version */
+    read (LOCAL->fd,s = (char *) fs_get (elt->private.msg.header.text.size+1),
+	  elt->private.msg.header.text.size);
+				/* tie off string, and convert to CRLF */
+    s[elt->private.msg.header.text.size] = '\0';
+    *length = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen,s,
+			  elt->private.msg.header.text.size);
+    fs_give ((void **) &s);	/* free readin buffer */
+				/* squeeze out spurious CRs */
+    for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++)
+      if ((*t != '\r') || (t[1] == '\n')) *s++ = *t;
+    *s = '\0';
+    *length = s - LOCAL->buf;	/* adjust length */
+  }
+  *length = mail_filter (LOCAL->buf,*length,unix_hlines,FT_NOT);
+  return (char *) LOCAL->buf;	/* return processed copy */
+}
+
+/* UNIX mail fetch message text
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned stringstruct
+ *	    option flags
+ * Returns: T on success, NIL if failure
+ */
+
+long unix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  char *s;
+  unsigned long i;
+  MESSAGECACHE *elt;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+  elt = mail_elt (stream,msgno);/* get cache element */
+				/* if message not seen */
+  if (!(flags & FT_PEEK) && !elt->seen) {
+				/* mark message seen and dirty */
+    elt->seen = elt->private.dirty = LOCAL->dirty = T;
+    MM_FLAGS (stream,msgno);
+  }
+  s = unix_text_work (stream,elt,&i,flags);
+  INIT (bs,mail_string,s,i);	/* set up stringstruct */
+  return T;			/* success */
+}
+
+/* UNIX mail fetch message text worker routine
+ * Accepts: MAIL stream
+ *	    message cache element
+ *	    pointer to returned header text length
+ *	    option flags
+ */
+
+char *unix_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
+		      unsigned long *length,long flags)
+{
+  FDDATA d;
+  STRING bs;
+  unsigned char c,*s,*t,*tl,tmp[CHUNKSIZE];
+				/* go to text position */
+  lseek (LOCAL->fd,elt->private.special.offset +
+	 elt->private.msg.text.offset,L_SET);
+  if (flags & FT_INTERNAL) {	/* initial data OK? */
+    if (elt->private.msg.text.text.size > LOCAL->buflen) {
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
+				     elt->private.msg.text.text.size) + 1);
+    }
+				/* read message */
+    read (LOCAL->fd,LOCAL->buf,elt->private.msg.text.text.size);
+				/* got text, tie off string */
+    LOCAL->buf[*length = elt->private.msg.text.text.size] = '\0';
+				/* squeeze out CRs (in case from PC) */
+    for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++)
+      if (*t != '\r') *s++ = *t;
+    *s = '\0';
+    *length = s - LOCAL->buf;	/* adjust length */
+    return (char *) LOCAL->buf;
+  }
+
+				/* have it cached already? */
+  if (elt->private.uid != LOCAL->uid) {
+				/* not cached, cache it now */
+    LOCAL->uid = elt->private.uid;
+				/* is buffer big enough? */
+    if (elt->rfc822_size > LOCAL->text.size) {
+      /* excessively conservative, but the right thing is too hard to do */
+      fs_give ((void **) &LOCAL->text.data);
+      LOCAL->text.data = (unsigned char *)
+	fs_get ((LOCAL->text.size = elt->rfc822_size) + 1);
+    }
+    d.fd = LOCAL->fd;		/* yes, set up file descriptor */
+    d.pos = elt->private.special.offset + elt->private.msg.text.offset;
+    d.chunk = tmp;		/* initial buffer chunk */
+    d.chunksize = CHUNKSIZE;	/* file chunk size */
+    INIT (&bs,fd_string,&d,elt->private.msg.text.text.size);
+    for (s = (char *) LOCAL->text.data; SIZE (&bs);) switch (c = SNX (&bs)) {
+    case '\r':			/* carriage return seen */
+      break;
+    case '\n':
+      *s++ = '\r';		/* insert a CR */
+    default:
+      *s++ = c;			/* copy characters */
+    }
+    *s = '\0';			/* tie off buffer */
+				/* calculate length of cached data */
+    LOCAL->textlen = s - LOCAL->text.data;
+  }
+  *length = LOCAL->textlen;	/* return from cache */
+  return (char *) LOCAL->text.data;
+}
+
+/* UNIX per-message modify flag
+ * Accepts: MAIL stream
+ *	    message cache element
+ */
+
+void unix_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+				/* only after finishing */
+  if (elt->valid) elt->private.dirty = LOCAL->dirty = T;
+}
+
+
+/* UNIX mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ */
+
+long unix_ping (MAILSTREAM *stream)
+{
+  DOTLOCK lock;
+  struct stat sbuf;
+  long reparse;
+				/* big no-op if not readwrite */
+  if (LOCAL && (LOCAL->ld >= 0) && !stream->lock) {
+    if (stream->rdonly) {	/* does he want to give up readwrite? */
+				/* checkpoint if we changed something */
+      if (LOCAL->dirty) unix_check (stream);
+      flock (LOCAL->ld,LOCK_UN);/* release readwrite lock */
+      close (LOCAL->ld);	/* close the readwrite lock file */
+      LOCAL->ld = -1;		/* no more readwrite lock fd */
+      unlink (LOCAL->lname);	/* delete the readwrite lock file */
+    }
+    else {			/* see if need to reparse */
+      if (!(reparse = (long) mail_parameters (NIL,GET_NETFSSTATBUG,NIL))) {
+				/* get current mailbox size */
+	if (LOCAL->fd >= 0) fstat (LOCAL->fd,&sbuf);
+	else if (stat (stream->mailbox,&sbuf)) {
+	  sprintf (LOCAL->buf,"Mailbox stat failed, aborted: %s",
+		   strerror (errno));
+	  MM_LOG (LOCAL->buf,ERROR);
+	  unix_abort (stream);
+	  return NIL;
+	}
+	reparse = (sbuf.st_size != LOCAL->filesize);
+      }
+				/* parse if mailbox changed */
+      if ((LOCAL->ddirty || reparse) && unix_parse (stream,&lock,LOCK_EX)) {
+				/* force checkpoint if double-dirty */
+	if (LOCAL->ddirty) unix_rewrite (stream,NIL,&lock,NIL);
+				/* unlock mailbox */
+	else unix_unlock (LOCAL->fd,stream,&lock);
+	mail_unlock (stream);	/* and stream */
+	MM_NOCRITICAL (stream);	/* done with critical */
+      }
+    }
+  }
+  return LOCAL ? LONGT : NIL;	/* return if still alive */
+}
+
+/* UNIX mail check mailbox
+ * Accepts: MAIL stream
+ */
+
+void unix_check (MAILSTREAM *stream)
+{
+  DOTLOCK lock;
+				/* parse and lock mailbox */
+  if (LOCAL && (LOCAL->ld >= 0) && !stream->lock &&
+      unix_parse (stream,&lock,LOCK_EX)) {
+				/* any unsaved changes? */
+    if (LOCAL->dirty && unix_rewrite (stream,NIL,&lock,NIL)) {
+      if (!stream->silent) MM_LOG ("Checkpoint completed",NIL);
+    }
+				/* no checkpoint needed, just unlock */
+    else unix_unlock (LOCAL->fd,stream,&lock);
+    mail_unlock (stream);	/* unlock the stream */
+    MM_NOCRITICAL (stream);	/* done with critical */
+  }
+}
+
+
+/* UNIX mail expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long unix_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  long ret;
+  unsigned long i;
+  DOTLOCK lock;
+  char *msg = NIL;
+				/* parse and lock mailbox */
+  if (ret = (sequence ? ((options & EX_UID) ?
+			 mail_uid_sequence (stream,sequence) :
+			 mail_sequence (stream,sequence)) : LONGT) &&
+      LOCAL && (LOCAL->ld >= 0) && !stream->lock &&
+      unix_parse (stream,&lock,LOCK_EX)) {
+				/* check expunged messages if not dirty */
+    for (i = 1; !LOCAL->dirty && (i <= stream->nmsgs); i++) {
+      MESSAGECACHE *elt = mail_elt (stream,i);
+      if (mail_elt (stream,i)->deleted) LOCAL->dirty = T;
+    }
+    if (!LOCAL->dirty) {	/* not dirty and no expunged messages */
+      unix_unlock (LOCAL->fd,stream,&lock);
+      msg = "No messages deleted, so no update needed";
+    }
+    else if (unix_rewrite (stream,&i,&lock,sequence ? LONGT : NIL)) {
+      if (i) sprintf (msg = LOCAL->buf,"Expunged %lu messages",i);
+      else msg = "Mailbox checkpointed, but no messages expunged";
+    }
+				/* rewrite failed */
+    else unix_unlock (LOCAL->fd,stream,&lock);
+    mail_unlock (stream);	/* unlock the stream */
+    MM_NOCRITICAL (stream);	/* done with critical */
+    if (msg && !stream->silent) MM_LOG (msg,NIL);
+  }
+  else if (!stream->silent) MM_LOG("Expunge ignored on readonly mailbox",WARN);
+  return ret;
+}
+
+/* UNIX mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if copy successful, else NIL
+ */
+
+long unix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  struct stat sbuf;
+  int fd;
+  char *s,file[MAILTMPLEN];
+  DOTLOCK lock;
+  time_t tp[2];
+  unsigned long i,j;
+  MESSAGECACHE *elt;
+  long ret = T;
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+  copyuid_t cu = (copyuid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ?
+			      NIL : mail_parameters (NIL,GET_COPYUID,NIL));
+  SEARCHSET *source = cu ? mail_newsearchset () : NIL;
+  SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
+  MAILSTREAM *tstream = NIL;
+  DRIVER *d;
+  for (d = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL);
+       (d && strcmp (d->name,"mbox") && !(d->flags & DR_DISABLE));
+       d = d->next);		/* see if mbox driver active */
+  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+	mail_sequence (stream,sequence))) return NIL;
+				/* make sure destination is valid */
+  if (!((d && mbox_valid (mailbox) && (mailbox = "mbox")) ||
+	unix_valid (mailbox) || !errno))
+    switch (errno) {
+    case ENOENT:		/* no such file? */
+      if (compare_cstring (mailbox,"INBOX")) {
+	MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
+	return NIL;
+      }
+      if (pc) return (*pc) (stream,sequence,mailbox,options);
+      unix_create (NIL,"INBOX");/* create empty INBOX */
+    case EACCES:		/* file protected */
+      sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
+      MM_LOG (LOCAL->buf,ERROR);
+      return NIL;
+    case EINVAL:
+      if (pc) return (*pc) (stream,sequence,mailbox,options);
+      sprintf (LOCAL->buf,"Invalid UNIX-format mailbox name: %.80s",mailbox);
+      MM_LOG (LOCAL->buf,ERROR);
+      return NIL;
+    default:
+      if (pc) return (*pc) (stream,sequence,mailbox,options);
+      sprintf (LOCAL->buf,"Not a UNIX-format mailbox: %.80s",mailbox);
+      MM_LOG (LOCAL->buf,ERROR);
+      return NIL;
+    }
+
+				/* try to open rewrite for UIDPLUS */
+  if ((tstream = mail_open_work (&unixdriver,NIL,mailbox,
+				 OP_SILENT|OP_NOKOD)) && tstream->rdonly)
+    tstream = mail_close (tstream);
+  if (cu && !tstream) {		/* wanted a COPYUID? */
+    sprintf (LOCAL->buf,"Unable to write-open mailbox for COPYUID: %.80s",
+	     mailbox);
+    MM_LOG (LOCAL->buf,WARN);
+    cu = NIL;			/* don't try to do COPYUID */
+  }
+  LOCAL->buf[0] = '\0';
+  MM_CRITICAL (stream);		/* go critical */
+  if ((fd = unix_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND,
+		       (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
+		       &lock,LOCK_EX)) < 0) {
+    MM_NOCRITICAL (stream);	/* done with critical */
+    sprintf (LOCAL->buf,"Can't open destination mailbox: %s",strerror (errno));
+    MM_LOG (LOCAL->buf,ERROR);/* log the error */
+    return NIL;			/* failed */
+  }
+  fstat (fd,&sbuf);		/* get current file size */
+				/* write all requested messages to mailbox */
+  for (i = 1; ret && (i <= stream->nmsgs); i++)
+    if ((elt = mail_elt (stream,i))->sequence) {
+      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
+      read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size);
+      if (write (fd,LOCAL->buf,elt->private.special.text.size) < 0) ret = NIL;
+      else {			/* internal header succeeded */
+	s = unix_header (stream,i,&j,FT_INTERNAL);
+				/* header size, sans trailing newline */
+	if (j && (s[j - 2] == '\n')) j--;
+	if (write (fd,s,j) < 0) ret = NIL;
+	else {			/* message header succeeded */
+	  j = tstream ?		/* write UIDPLUS data if have readwrite */
+	    unix_xstatus (stream,LOCAL->buf,elt,++(tstream->uid_last),LONGT) :
+	    unix_xstatus (stream,LOCAL->buf,elt,NIL,NIL);
+	  if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
+	  else {		/* message status succeeded */
+	    s = unix_text_work (stream,elt,&j,FT_INTERNAL);
+	    if ((write (fd,s,j) < 0) || (write (fd,"\n",1) < 0)) ret = NIL;
+	    else if (cu) {	/* need to pass back new UID? */
+	      mail_append_set (source,mail_uid (stream,i));
+	      mail_append_set (dest,tstream->uid_last);
+	    }
+	  }
+	}
+      }
+    }
+
+  if (!ret || fsync (fd)) {	/* force out the update */
+    sprintf (LOCAL->buf,"Message copy failed: %s",strerror (errno));
+    ftruncate (fd,sbuf.st_size);
+    ret = NIL;
+  }
+				/* force UIDVALIDITY assignment now */
+  if (tstream && !tstream->uid_validity) tstream->uid_validity = time (0);
+				/* return sets if doing COPYUID */
+  if (cu && ret) (*cu) (stream,mailbox,tstream->uid_validity,source,dest);
+  else {			/* flush any sets we may have built */
+    mail_free_searchset (&source);
+    mail_free_searchset (&dest);
+  }
+  tp[1] = time (0);		/* set mtime to now */
+  if (ret) tp[0] = tp[1] - 1;	/* set atime to now-1 if successful copy */
+  else tp[0] =			/* else preserve \Marked status */
+	 ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ?
+	 sbuf.st_atime : tp[1];
+  utime (file,tp);		/* set the times */
+  unix_unlock (fd,NIL,&lock);	/* unlock and close mailbox */
+  if (tstream) {		/* update last UID if we can */
+    UNIXLOCAL *local = (UNIXLOCAL *) tstream->local;
+    local->dirty = T;		/* do a rewrite */
+    local->appending = T;	/* but not at the cost of marking as old */
+    tstream = mail_close (tstream);
+  }
+				/* log the error */
+  if (!ret) MM_LOG (LOCAL->buf,ERROR);
+				/* delete if requested message */
+  else if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++)
+    if ((elt = mail_elt (stream,i))->sequence)
+      elt->deleted = elt->private.dirty = LOCAL->dirty = T;
+  MM_NOCRITICAL (stream);	/* release critical */
+  return ret;
+}
+
+/* UNIX mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+#define BUFLEN 8*MAILTMPLEN
+
+long unix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct stat sbuf;
+  int fd;
+  unsigned long i;
+  char *flags,*date,buf[BUFLEN],tmp[MAILTMPLEN],file[MAILTMPLEN];
+  time_t tp[2];
+  FILE *sf,*df;
+  MESSAGECACHE elt;
+  DOTLOCK lock;
+  STRING *message;
+  unsigned long uidlocation = 0;
+  appenduid_t au = (appenduid_t)
+    (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL :
+     mail_parameters (NIL,GET_APPENDUID,NIL));
+  SEARCHSET *dst = au ? mail_newsearchset () : NIL;
+  long ret = LONGT;
+  MAILSTREAM *tstream = NIL;
+  if (!stream) {		/* stream specified? */
+    stream = &unixproto;	/* no, default stream to prototype */
+    for (i = 0; i < NUSERFLAGS && stream->user_flags[i]; ++i)
+      fs_give ((void **) &stream->user_flags[i]);
+  }
+  if (!unix_valid (mailbox)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    if (compare_cstring (mailbox,"INBOX")) {
+      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+      return NIL;
+    }
+    unix_create (NIL,"INBOX");	/* create empty INBOX */
+  case 0:			/* merely empty file? */
+    tstream = stream;
+    break;
+  case EACCES:			/* file protected */
+    sprintf (tmp,"Can't access destination: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  case EINVAL:
+    sprintf (tmp,"Invalid UNIX-format mailbox name: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  default:
+    sprintf (tmp,"Not a UNIX-format mailbox: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+				/* get sniffing stream for keywords */
+  else if (!(tstream = mail_open (NIL,mailbox,
+				  OP_READONLY|OP_SILENT|OP_NOKOD|OP_SNIFF))) {
+    sprintf (tmp,"Unable to examine mailbox for APPEND: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+
+				/* get first message */
+  if (!MM_APPEND (af) (tstream,data,&flags,&date,&message)) return NIL;
+  if (!(sf = tmpfile ())) {	/* must have scratch file */
+    sprintf (tmp,".%lx.%lx",(unsigned long) time (0),(unsigned long)getpid ());
+    if (!stat (tmp,&sbuf) || !(sf = fopen (tmp,"wb+"))) {
+      sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno));
+      MM_LOG (tmp,ERROR);
+      return NIL;
+    }
+    unlink (tmp);
+  }
+  do {				/* parse date */
+    if (!date) rfc822_date (date = tmp);
+    if (!mail_parse_date (&elt,date)) {
+      sprintf (tmp,"Bad date in append: %.80s",date);
+      MM_LOG (tmp,ERROR);
+    }
+    else {			/* user wants to suppress time zones? */
+      if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) {
+	time_t when = mail_longdate (&elt);
+	date = ctime (&when);	/* use traditional date */
+      }
+				/* use POSIX-style date */
+      else date = mail_cdate (tmp,&elt);
+      if (!SIZE (message)) MM_LOG ("Append of zero-length message",ERROR);
+      else if (!unix_collect_msg (tstream,sf,flags,date,message)) {
+	sprintf (tmp,"Error writing scratch file: %.80s",strerror (errno));
+	MM_LOG (tmp,ERROR);
+      }
+				/* get next message */
+      else if (MM_APPEND (af) (tstream,data,&flags,&date,&message)) continue;
+    }
+    fclose (sf);		/* punt scratch file */
+    return NIL;			/* give up */
+  } while (message);		/* until no more messages */
+  if (fflush (sf)) {
+    sprintf (tmp,"Error finishing scratch file: %.80s",strerror (errno));
+    MM_LOG (tmp,ERROR);
+    fclose (sf);		/* punt scratch file */
+    return NIL;			/* give up */
+  }
+  i = ftell (sf);		/* size of scratch file */
+				/* close sniffing stream */
+  if (tstream != stream) tstream = mail_close (tstream);
+
+  MM_CRITICAL (stream);		/* go critical */
+				/* try to open readwrite for UIDPLUS */
+  if ((tstream = mail_open_work (&unixdriver,NIL,mailbox,
+				 OP_SILENT|OP_NOKOD)) && tstream->rdonly)
+    tstream = mail_close (tstream);
+  if (au && !tstream) {		/* wanted an APPENDUID? */
+    sprintf (tmp,"Unable to re-open mailbox for APPENDUID: %.80s",mailbox);
+    MM_LOG (tmp,WARN);
+    au = NIL;
+  }
+  if (((fd = unix_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND,
+		       (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
+			&lock,LOCK_EX)) < 0) ||
+      !(df = fdopen (fd,"ab"))) {
+    MM_NOCRITICAL (stream);	/* done with critical */
+    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+  fstat (fd,&sbuf);		/* get current file size */
+  rewind (sf);
+  tp[1] = time (0);		/* set mtime to now */
+				/* write all messages */
+  if (!unix_append_msgs (tstream,sf,df,au ? dst : NIL) ||
+      (fflush (df) == EOF) || fsync (fd)) {
+    sprintf (buf,"Message append failed: %s",strerror (errno));
+    MM_LOG (buf,ERROR);
+    ftruncate (fd,sbuf.st_size);
+    tp[0] =			/* preserve \Marked status */
+      ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ?
+      sbuf.st_atime : tp[1];
+    ret = NIL;			/* return error */
+  }
+  else tp[0] = tp[1] - 1;	/* set atime to now-1 if successful copy */
+  utime (file,tp);		/* set the times */
+  fclose (sf);			/* done with scratch file */
+				/* force UIDVALIDITY assignment now */
+  if (tstream && !tstream->uid_validity) tstream->uid_validity = time (0);
+				/* return sets if doing APPENDUID */
+  if (au && ret) (*au) (mailbox,tstream->uid_validity,dst);
+  else mail_free_searchset (&dst);
+  unix_unlock (fd,NIL,&lock);	/* unlock and close mailbox */
+  fclose (df);			/* note that unix_unlock() released the fd */
+  if (tstream) {		/* update last UID if we can */
+    UNIXLOCAL *local = (UNIXLOCAL *) tstream->local;
+    local->dirty = T;		/* do a rewrite */
+    local->appending = T;	/* but not at the cost of marking as old */
+    tstream = mail_close (tstream);
+  }
+  MM_NOCRITICAL (stream);	/* release critical */
+  return ret;
+}
+
+/* Collect and write single message to append scratch file
+ * Accepts: MAIL stream
+ *	    scratch file
+ *	    flags
+ *	    date
+ *	    message stringstruct
+ * Returns: NIL if write error, else T
+ */
+
+int unix_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
+		     STRING *msg)
+{
+  unsigned char *s,*t;
+  unsigned long uf;
+  long f = mail_parse_flags (stream,flags,&uf);
+				/* write metadata, note date ends with NL */
+  if (fprintf (sf,"%ld %lu %s",f,SIZE (msg) + 1,date) < 0) return NIL;
+  while (uf)			/* write user flags */    
+    if ((s = stream->user_flags[find_rightmost_bit (&uf)]) &&
+	(fprintf (sf," %s",s) < 0)) return NIL;
+  if (putc ('\n',sf) == EOF) return NIL;
+  while (SIZE (msg)) {		/* copy text to scratch file */
+    for (s = (unsigned char *) msg->curpos, t = s + msg->cursize; s < t; ++s)
+      if (!*s) *s = 0x80;	/* disallow NUL */
+				/* write buffered text */
+    if (fwrite (msg->curpos,1,msg->cursize,sf) == msg->cursize)
+      SETPOS (msg,GETPOS (msg) + msg->cursize);
+    else return NIL;		/* failed */
+  }
+				/* write trailing newline and return */
+  return (putc ('\n',sf) == EOF) ? NIL : T;
+}
+
+/* Append messages from scratch file to mailbox
+ * Accepts: MAIL stream
+ *	    source file
+ *	    destination file
+ *	    uidset to update if non-NIL
+ * Returns: T if success, NIL if failure
+ */
+
+int unix_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set)
+{
+  int ti,zn,c;
+  long f;
+  unsigned long i,j;
+  char *x,tmp[MAILTMPLEN];
+  int hdrp = T;
+				/* get message metadata line */
+  while (fgets (tmp,MAILTMPLEN,sf)) {
+    if (!(isdigit (tmp[0]) && strchr (tmp,'\n'))) return NIL;
+    f = strtol (tmp,&x,10);	/* get flags */
+    if (!((*x++ == ' ') && isdigit (*x))) return NIL;
+    i = strtoul (x,&x,10);	/* get message size */
+    if ((*x++ != ' ') ||	/* build initial header */
+	(fprintf (df,"From %s@%s %sStatus: ",myusername(),mylocalhost(),x)<0)||
+	(f&fSEEN && (putc ('R',df) == EOF)) ||
+	(fputs ("\nX-Status: ",df) == EOF) ||
+	(f&fDELETED && (putc ('D',df) == EOF)) ||
+	(f&fFLAGGED && (putc ('F',df) == EOF)) ||
+	(f&fANSWERED && (putc ('A',df) == EOF)) ||
+	(f&fDRAFT && (putc ('T',df) == EOF)) ||
+	(fputs ("\nX-Keywords:",df) == EOF)) return NIL;
+				/* copy keywords */
+    while ((c = getc (sf)) != '\n') switch (c) {
+    case EOF:
+      return NIL;
+    default:
+      if (putc (c,df) == EOF) return NIL;
+    }
+    if ((putc ('\n',df) == EOF) ||
+	(set && (fprintf (df,"X-UID: %lu\n",++(stream->uid_last)) < 0)))
+      return NIL;
+
+    for (c = '\n'; i && fgets (tmp,MAILTMPLEN,sf); c = tmp[j-1]) {
+				/* get read line length */
+      if (i < (j = strlen (tmp))) fatal ("unix_append_msgs overrun");
+      i -= j;			/* number of bytes left */
+				/* squish out CRs (note also copies NUL) */
+      for (x = tmp; x = strchr (x,'\r'); --j) memmove (x,x+1,j-(x-tmp));
+      if (!j) continue;		/* do nothing if line emptied */
+				/* start of line? */
+      if ((c == '\n')) switch (tmp[0]) {
+      case 'F':			/* possible "From " (case counts here) */
+	if ((j > 4) && (tmp[0] == 'F') && (tmp[1] == 'r') && (tmp[2] == 'o') &&
+	    (tmp[3] == 'm') && (tmp[4] == ' ')) {
+	  if (!unix_fromwidget) {
+	    VALID (tmp,x,ti,zn);/* conditional, only write widget if */
+	    if (!ti) break;	/*  it looks like a valid header */
+	  }			/* write the widget */
+	  if (putc ('>',df) == EOF) return NIL;
+	}
+	break;
+      case 'S': case 's':	/* possible "Status:" */
+	if (hdrp && (j > 6) && ((tmp[1] == 't') || (tmp[1] == 'T')) &&
+	    ((tmp[2] == 'a') || (tmp[2] == 'A')) &&
+	    ((tmp[3] == 't') || (tmp[3] == 'T')) &&
+	    ((tmp[4] == 'u') || (tmp[4] == 'U')) &&
+	    ((tmp[5] == 's') || (tmp[5] == 'S')) && (tmp[6] == ':') &&
+	    (fputs ("X-Original-",df) == EOF)) return NIL;
+	break;
+      case 'X': case 'x':	/* possible X-??? header */
+	if (hdrp && (tmp[1] == '-') &&
+				/* possible X-UID: */
+	    (((j > 5) && ((tmp[2] == 'U') || (tmp[2] == 'u')) &&
+	      ((tmp[3] == 'I') || (tmp[3] == 'i')) &&
+	      ((tmp[4] == 'D') || (tmp[4] == 'd')) && (tmp[5] == ':')) ||
+				/* possible X-IMAP: */
+	     ((j > 6) && ((tmp[2] == 'I') || (tmp[2] == 'i')) &&
+	      ((tmp[3] == 'M') || (tmp[3] == 'm')) &&
+	      ((tmp[4] == 'A') || (tmp[4] == 'a')) &&
+	      ((tmp[5] == 'P') || (tmp[5] == 'p')) &&
+	      ((tmp[6] == ':') ||
+				/* or X-IMAPbase: */
+	       ((j > 10) && ((tmp[6] == 'b') || (tmp[6] == 'B')) &&
+		((tmp[7] == 'a') || (tmp[7] == 'A')) &&
+		((tmp[8] == 's') || (tmp[8] == 'S')) &&
+		((tmp[9] == 'e') || (tmp[9] == 'E')) && (tmp[10] == ':')))) ||
+				/* possible X-Status: */
+	     ((j > 8) && ((tmp[2] == 'S') || (tmp[2] == 's')) &&
+	      ((tmp[3] == 't') || (tmp[3] == 'T')) &&
+	      ((tmp[4] == 'a') || (tmp[4] == 'A')) &&
+	      ((tmp[5] == 't') || (tmp[5] == 'T')) &&
+	      ((tmp[6] == 'u') || (tmp[6] == 'U')) &&
+	      ((tmp[7] == 's') || (tmp[7] == 'S')) && (tmp[8] == ':')) ||
+				/* possible X-Keywords: */
+	     ((j > 10) && ((tmp[2] == 'K') || (tmp[2] == 'k')) &&
+	      ((tmp[3] == 'e') || (tmp[3] == 'E')) &&
+	      ((tmp[4] == 'y') || (tmp[4] == 'Y')) &&
+	      ((tmp[5] == 'w') || (tmp[5] == 'W')) &&
+	      ((tmp[6] == 'o') || (tmp[6] == 'O')) &&
+	      ((tmp[7] == 'r') || (tmp[7] == 'R')) &&
+	      ((tmp[8] == 'd') || (tmp[8] == 'D')) &&
+	      ((tmp[9] == 's') || (tmp[9] == 'S')) && (tmp[10] == ':'))) &&
+	    (fputs ("X-Original-",df) == EOF)) return NIL;
+      case '\n':		/* blank line */
+	hdrp = NIL;
+	break;
+      default:			/* nothing to do */
+	break;
+      }
+				/* just write the line */
+      if (fwrite (tmp,1,j,df) != j) return NIL;
+    }
+    if (i) return NIL;		/* didn't read entire message */
+				/* update set */
+    if (stream) mail_append_set (set,stream->uid_last);
+  }
+  return T;
+}
+
+/* Internal routines */
+
+
+/* UNIX mail abort stream
+ * Accepts: MAIL stream
+ */
+
+void unix_abort (MAILSTREAM *stream)
+{
+  if (LOCAL) {			/* only if a file is open */
+    if (LOCAL->fd >= 0) close (LOCAL->fd);
+    if (LOCAL->ld >= 0) {	/* have a mailbox lock? */
+      flock (LOCAL->ld,LOCK_UN);/* yes, release the lock */
+      close (LOCAL->ld);	/* close the lock file */
+      unlink (LOCAL->lname);	/* and delete it */
+    }
+    if (LOCAL->lname) fs_give ((void **) &LOCAL->lname);
+				/* free local text buffers */
+    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+    if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data);
+    if (LOCAL->linebuf) fs_give ((void **) &LOCAL->linebuf);
+    if (LOCAL->line) fs_give ((void **) &LOCAL->line);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+/* UNIX open and lock mailbox
+ * Accepts: file name to open/lock
+ *	    file open mode
+ *	    destination buffer for lock file name
+ *	    type of locking operation (LOCK_SH or LOCK_EX)
+ */
+
+int unix_lock (char *file,int flags,int mode,DOTLOCK *lock,int op)
+{
+  int fd;
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  (*bn) (BLOCK_FILELOCK,NIL);
+				/* try locking the easy way */
+  if (dotlock_lock (file,lock,-1)) {
+				/* got dotlock file, easy open */
+    if ((fd = open (file,flags,mode)) >= 0) flock (fd,op);
+    else dotlock_unlock (lock);	/* open failed, free the dotlock */
+  }
+				/* no dot lock file, open file now */
+  else if ((fd = open (file,flags,mode)) >= 0) {
+				/* try paranoid way to make a dot lock file */
+    if (dotlock_lock (file,lock,fd)) {
+      close (fd);		/* get fresh fd in case of timing race */
+      if ((fd = open (file,flags,mode)) >= 0) flock (fd,op);
+				/* open failed, free the dotlock */
+      else dotlock_unlock (lock);
+    }
+    else flock (fd,op);		/* paranoid way failed, just flock() it */
+  }
+  (*bn) (BLOCK_NONE,NIL);
+  return fd;
+}
+
+/* UNIX unlock and close mailbox
+ * Accepts: file descriptor
+ *	    (optional) mailbox stream to check atime/mtime
+ *	    (optional) lock file name
+ */
+
+void unix_unlock (int fd,MAILSTREAM *stream,DOTLOCK *lock)
+{
+  if (stream) {			/* need to muck with times? */
+    struct stat sbuf;
+    time_t tp[2];
+    time_t now = time (0);
+    fstat (fd,&sbuf);		/* get file times */
+    if (LOCAL->ld >= 0) {	/* yes, readwrite session? */
+      tp[0] = now;		/* set atime to now */
+				/* set mtime to (now - 1) if necessary */
+      tp[1] = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1;
+    }
+    else if (stream->recent) {	/* readonly with recent messages */
+      if ((sbuf.st_atime >= sbuf.st_mtime) ||
+	  (sbuf.st_atime >= sbuf.st_ctime))
+				/* keep past mtime, whack back atime */
+	tp[0] = (tp[1] = (sbuf.st_mtime < now) ? sbuf.st_mtime : now) - 1;
+      else now = 0;		/* no time change needed */
+    }
+				/* readonly with no recent messages */
+    else if ((sbuf.st_atime < sbuf.st_mtime) ||
+	     (sbuf.st_atime < sbuf.st_ctime)) {
+      tp[0] = now;		/* set atime to now */
+				/* set mtime to (now - 1) if necessary */
+      tp[1] = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1;
+    }
+    else now = 0;		/* no time change needed */
+				/* set the times, note change */
+    if (now && !utime (stream->mailbox,tp)) LOCAL->filetime = tp[1];
+  }
+  flock (fd,LOCK_UN);		/* release flock'ers */
+  if (!stream) close (fd);	/* close the file if no stream */
+  dotlock_unlock (lock);	/* flush the lock file if any */
+}
+
+/* UNIX mail parse and lock mailbox
+ * Accepts: MAIL stream
+ *	    space to write lock file name
+ *	    type of locking operation
+ * Returns: T if parse OK, critical & mailbox is locked shared; NIL if failure
+ */
+
+int unix_parse (MAILSTREAM *stream,DOTLOCK *lock,int op)
+{
+  int zn;
+  unsigned long i,j,k,m;
+  unsigned char c,*s,*t,*u,tmp[MAILTMPLEN],date[30];
+  int ti = 0,retain = T;
+  unsigned long nmsgs = stream->nmsgs;
+  unsigned long prevuid = nmsgs ? mail_elt (stream,nmsgs)->private.uid : 0;
+  unsigned long recent = stream->recent;
+  unsigned long oldnmsgs = stream->nmsgs;
+  short silent = stream->silent;
+  short pseudoseen = NIL;
+  struct stat sbuf;
+  STRING bs;
+  FDDATA d;
+  MESSAGECACHE *elt;
+  mail_lock (stream);		/* guard against recursion or pingers */
+				/* toss out previous descriptor */
+  if (LOCAL->fd >= 0) close (LOCAL->fd);
+  MM_CRITICAL (stream);		/* open and lock mailbox (shared OK) */
+  if ((LOCAL->fd = unix_lock (stream->mailbox,(LOCAL->ld >= 0) ?
+			      O_RDWR : O_RDONLY,
+			      (long)mail_parameters(NIL,GET_MBXPROTECTION,NIL),
+			      lock,op)) < 0) {
+    sprintf (tmp,"Mailbox open failed, aborted: %s",strerror (errno));
+    MM_LOG (tmp,ERROR);
+    unix_abort (stream);
+    mail_unlock (stream);
+    MM_NOCRITICAL (stream);	/* done with critical */
+    return NIL;
+  }
+  fstat (LOCAL->fd,&sbuf);	/* get status */
+				/* validate change in size */
+  if (sbuf.st_size < LOCAL->filesize) {
+    sprintf (tmp,"Mailbox shrank from %lu to %lu bytes, aborted",
+	     (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
+    MM_LOG (tmp,ERROR);		/* this is pretty bad */
+    unix_unlock (LOCAL->fd,stream,lock);
+    unix_abort (stream);
+    mail_unlock (stream);
+    MM_NOCRITICAL (stream);	/* done with critical */
+    return NIL;
+  }
+
+				/* new data? */
+  else if (i = sbuf.st_size - LOCAL->filesize) {
+    d.fd = LOCAL->fd;		/* yes, set up file descriptor */
+    d.pos = LOCAL->filesize;	/* get to that position in the file */
+    d.chunk = LOCAL->buf;	/* initial buffer chunk */
+    d.chunksize = CHUNKSIZE;	/* file chunk size */
+    INIT (&bs,fd_string,&d,i);	/* initialize stringstruct */
+				/* skip leading whitespace for broken MTAs */
+    while (((c = CHR (&bs)) == '\n') || (c == '\r') ||
+	   (c == ' ') || (c == '\t')) SNX (&bs);
+    if (SIZE (&bs)) {		/* read new data */
+				/* remember internal header position */
+      j = LOCAL->filesize + GETPOS (&bs);
+      s = unix_mbxline (stream,&bs,&i);
+      t = NIL,zn = 0;
+      if (i) VALID (s,t,ti,zn);	/* see if valid From line */
+      if (!ti) {		/* someone pulled the rug from under us */
+	sprintf (tmp,"Unexpected changes to mailbox (try restarting): %.20s",
+		 (char *) s);
+	MM_LOG (tmp,ERROR);
+	unix_unlock (LOCAL->fd,stream,lock);
+	unix_abort (stream);
+	mail_unlock (stream);
+				/* done with critical */
+	MM_NOCRITICAL (stream);
+	return NIL;
+      }
+      stream->silent = T;	/* quell main program new message events */
+      do {			/* found a message */
+				/* instantiate first new message */
+	mail_exists (stream,++nmsgs);
+	(elt = mail_elt (stream,nmsgs))->valid = T;
+	recent++;		/* assume recent by default */
+	elt->recent = T;
+				/* note position/size of internal header */
+	elt->private.special.offset = j;
+	elt->private.msg.header.offset = elt->private.special.text.size = i;
+
+				/* generate plausible IMAPish date string */
+	date[2] = date[6] = date[20] = '-'; date[11] = ' ';
+	date[14] = date[17] = ':';
+				/* dd */
+	date[0] = t[ti - 2]; date[1] = t[ti - 1];
+				/* mmm */
+	date[3] = t[ti - 6]; date[4] = t[ti - 5]; date[5] = t[ti - 4];
+				/* hh */
+	date[12] = t[ti + 1]; date[13] = t[ti + 2];
+				/* mm */
+	date[15] = t[ti + 4]; date[16] = t[ti + 5];
+	if (t[ti += 6] == ':') {/* ss */
+	  date[18] = t[++ti]; date[19] = t[++ti];
+	  ti++;			/* move to space */
+	}
+	else date[18] = date[19] = '0';
+				/* yy -- advance over timezone if necessary */
+	if (zn == ti) ti += (((t[zn+1] == '+') || (t[zn+1] == '-')) ? 6 : 4);
+	date[7] = t[ti + 1]; date[8] = t[ti + 2];
+	date[9] = t[ti + 3]; date[10] = t[ti + 4];
+				/* zzz */
+	t = zn ? (t + zn + 1) : (unsigned char *) "LCL";
+	date[21] = *t++; date[22] = *t++; date[23] = *t++;
+	if ((date[21] != '+') && (date[21] != '-')) date[24] = '\0';
+	else {			/* numeric time zone */
+	  date[24] = *t++; date[25] = *t++;
+	  date[26] = '\0'; date[20] = ' ';
+	}
+				/* set internal date */
+	if (!mail_parse_date (elt,date)) {
+	  sprintf (tmp,"Unable to parse internal date: %s",(char *) date);
+	  MM_LOG (tmp,WARN);
+	}
+
+	do {			/* look for message body */
+	  s = t = unix_mbxline (stream,&bs,&i);
+	  if (i) switch (*s) {	/* check header lines */
+	  case 'X':		/* possible X-???: line */
+	    if (s[1] == '-') {	/* must be immediately followed by hyphen */
+				/* X-Status: becomes Status: in S case */
+	      if (s[2] == 'S' && s[3] == 't' && s[4] == 'a' && s[5] == 't' &&
+		  s[6] == 'u' && s[7] == 's' && s[8] == ':') s += 2;
+				/* possible X-Keywords */
+	      else if (s[2] == 'K' && s[3] == 'e' && s[4] == 'y' &&
+		       s[5] == 'w' && s[6] == 'o' && s[7] == 'r' &&
+		       s[8] == 'd' && s[9] == 's' && s[10] == ':') {
+		SIZEDTEXT uf;
+		retain = NIL;	/* don't retain continuation */
+		s += 11;	/* flush leading whitespace */
+		while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n'))){
+		  while (*s == ' ') s++;
+				/* find end of keyword */
+		  if (!(u = strpbrk (s," \n\r"))) u = s + strlen (s);
+				/* got a keyword? */
+		  if ((k = (u - s)) && (k <= MAXUSERFLAG)) {
+		    uf.data = (unsigned char *) s;
+		    uf.size = k;
+		    for (j = 0; (j < NUSERFLAGS) && stream->user_flags[j]; ++j)
+		      if (!compare_csizedtext (stream->user_flags[j],&uf)) {
+			elt->user_flags |= ((long) 1) << j;
+			break;
+		      }
+ 		  }
+		  s = u;	/* advance to next keyword */
+		}
+		break;
+	      }
+
+				/* possible X-IMAP */
+	      else if ((s[2] == 'I') && (s[3] == 'M') && (s[4] == 'A') &&
+		       (s[5] == 'P') && ((m = (s[6] == ':')) ||
+					 ((s[6] == 'b') && (s[7] == 'a') &&
+					  (s[8] == 's') && (s[9] == 'e') &&
+					  (s[10] == ':')))) {
+		retain = NIL;	/* don't retain continuation */
+		if ((nmsgs == 1) && !stream->uid_validity) {
+				/* advance to data */
+		  s += m ? 7 : 11;
+				/* flush whitespace */
+		  while (*s == ' ') s++;
+		  j = 0;	/* slurp UID validity */
+				/* found a digit? */
+		  while (isdigit (*s)) {
+		    j *= 10;	/* yes, add it in */
+		    j += *s++ - '0';
+		  }
+				/* flush whitespace */
+		  while (*s == ' ') s++;
+				/* must have valid UID validity and UID last */
+		  if (j && isdigit (*s)) {
+				/* pseudo-header seen if X-IMAP */
+		    if (m) pseudoseen = LOCAL->pseudo = T;
+				/* save UID validity */
+		    stream->uid_validity = j;
+		    j = 0;	/* slurp UID last */
+		    while (isdigit (*s)) {
+		      j *= 10;	/* yes, add it in */
+		      j += *s++ - '0';
+		    }
+				/* save UID last */
+		    stream->uid_last = j;
+				/* process keywords */
+		    for (j = 0; (*s != '\n') && ((*s != '\r')||(s[1] != '\n'));
+			 s = u,j++) {
+				/* flush leading whitespace */
+		      while (*s == ' ') s++;
+		      u = strpbrk (s," \n\r");
+				/* got a keyword? */
+		      if ((j < NUSERFLAGS) && (k = (u - s)) &&
+			  (k <= MAXUSERFLAG)) {
+			if (stream->user_flags[j])
+			  fs_give ((void **) &stream->user_flags[j]);
+			stream->user_flags[j] = (char *) fs_get (k + 1);
+			strncpy (stream->user_flags[j],s,k);
+			stream->user_flags[j][k] = '\0';
+		      }
+		    }
+		  }
+		}
+		break;
+	      }
+
+				/* possible X-UID */
+	      else if (s[2] == 'U' && s[3] == 'I' && s[4] == 'D' &&
+		       s[5] == ':') {
+		retain = NIL;	/* don't retain continuation */
+				/* only believe if have a UID validity */
+		if (stream->uid_validity && ((nmsgs > 1) || !pseudoseen)) {
+		  s += 6;	/* advance to UID value */
+				/* flush whitespace */
+		  while (*s == ' ') s++;
+		  j = 0;
+				/* found a digit? */
+		  while (isdigit (*s)) {
+		    j *= 10;	/* yes, add it in */
+		    j += *s++ - '0';
+		  }
+				/* flush remainder of line */
+		  while (*s != '\n') s++;
+				/* make sure not duplicated */
+		  if (elt->private.uid)
+		    sprintf (tmp,"Message %lu UID %lu already has UID %lu",
+			     pseudoseen ? elt->msgno - 1 : elt->msgno,
+			     j,elt->private.uid);
+				/* make sure UID doesn't go backwards */
+		  else if (j <= prevuid)
+		    sprintf (tmp,"Message %lu UID %lu less than %lu",
+			     pseudoseen ? elt->msgno - 1 : elt->msgno,
+			     j,prevuid + 1);
+#if 0	/* this is currently broken by UIDPLUS */
+				/* or skip by mailbox's recorded last */
+		  else if (j > stream->uid_last)
+		    sprintf (tmp,"Message %lu UID %lu greater than last %lu",
+			     pseudoseen ? elt->msgno - 1 : elt->msgno,
+			     j,stream->uid_last);
+#endif
+		  else {	/* normal UID case */
+		    prevuid = elt->private.uid = j;
+#if 1	/* temporary kludge for UIDPLUS */
+		    if (prevuid > stream->uid_last) {
+		      stream->uid_last = prevuid;
+		      LOCAL->ddirty = LOCAL->dirty = T;
+		    }		    
+#endif
+		    break;	/* exit this cruft */
+		  }
+		  MM_LOG (tmp,WARN);
+				/* invalidate UID validity */
+		  stream->uid_validity = 0;
+		  elt->private.uid = 0;
+		}
+		break;
+	      }
+	    }
+				/* otherwise fall into S case */
+
+	  case 'S':		/* possible Status: line */
+	    if (s[0] == 'S' && s[1] == 't' && s[2] == 'a' && s[3] == 't' &&
+		s[4] == 'u' && s[5] == 's' && s[6] == ':') {
+	      retain = NIL;	/* don't retain continuation */
+	      s += 6;		/* advance to status flags */
+	      do switch (*s++) {/* parse flags */
+	      case 'R':		/* message read */
+		elt->seen = T;
+		break;
+	      case 'O':		/* message old */
+		if (elt->recent) {
+		  elt->recent = NIL;
+		  recent--;	/* it really wasn't recent */
+		}
+		break;
+	      case 'D':		/* message deleted */
+		elt->deleted = T;
+		break;
+	      case 'F':		/* message flagged */
+		elt->flagged = T;
+		break;
+	      case 'A':		/* message answered */
+		elt->answered = T;
+		break;
+	      case 'T':		/* message is a draft */
+		elt->draft = T;
+		break;
+	      default:		/* some other crap */
+		break;
+	      } while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n')));
+	      break;		/* all done */
+	    }
+				/* otherwise fall into default case */
+
+	  default:		/* ordinary header line */
+	    if ((*s == 'S') || (*s == 's') ||
+		(((*s == 'X') || (*s == 'x')) && (s[1] == '-'))) {
+	      unsigned char *e,*v;
+				/* must match what mail_filter() does */
+	      for (u = s,v = tmp,e = u + min (i,MAILTMPLEN - 1);
+		   (u < e) && ((c = (*u ? *u : (*u = ' '))) != ':') &&
+		   ((c > ' ') || ((c != ' ') && (c != '\t') &&
+				  (c != '\r') && (c != '\n')));
+		   *v++ = *u++);
+	      *v = '\0';	/* tie off */
+				/* matches internal header? */
+	      if (!compare_cstring (tmp,"STATUS") ||
+		  !compare_cstring (tmp,"X-STATUS") ||
+		  !compare_cstring (tmp,"X-KEYWORDS") ||
+		  !compare_cstring (tmp,"X-UID") ||
+		  !compare_cstring (tmp,"X-IMAP") ||
+		  !compare_cstring (tmp,"X-IMAPBASE")) {
+		char err[MAILTMPLEN];
+		sprintf (err,"Discarding bogus %s header in message %lu",
+			 (char *) tmp,elt->msgno);
+		MM_LOG (err,WARN);
+		retain = NIL;	/* don't retain continuation */
+		break;		/* different case or something */
+	      }
+	    }
+				/* retain or non-continuation? */
+	    if (retain || ((*s != ' ') && (*s != '\t'))) {
+	      retain = T;	/* retaining continuation now */
+				/* line length in LF format newline */
+	      for (j = k = 0; j < i; ++j) if (s[j] != '\r') ++k;
+				/* "internal" header size */
+	      elt->private.spare.data += k;
+				/* message size */
+	      elt->rfc822_size += k + 1;
+	    }
+	    else {
+	      char err[MAILTMPLEN];
+	      sprintf (err,"Discarding bogus continuation in msg %lu: %.80s",
+		      elt->msgno,(char *) s);
+	      if (u = strpbrk (err,"\r\n")) *u = '\0';
+	      MM_LOG (err,WARN);
+	      break;		/* different case or something */
+	    }
+	    break;
+	  }
+	} while (i && (*t != '\n') && ((*t != '\r') || (t[1] != '\n')));
+				/* "internal" header sans trailing newline */
+	if (i) elt->private.spare.data--;
+				/* assign a UID if none found */
+	if (((nmsgs > 1) || !pseudoseen) && !elt->private.uid) {
+	  prevuid = elt->private.uid = ++stream->uid_last;
+	  elt->private.dirty = T;
+	  LOCAL->ddirty = T;	/* force update */
+	}
+	else elt->private.dirty = elt->recent;
+
+				/* note size of header, location of text */
+	elt->private.msg.header.text.size = 
+	  (elt->private.msg.text.offset =
+	   (LOCAL->filesize + GETPOS (&bs)) - elt->private.special.offset) -
+	     elt->private.special.text.size;
+	k = m = 0;		/* no previous line size yet */
+				/* note current position */
+	j = LOCAL->filesize + GETPOS (&bs);
+	if (i) do {		/* look for next message */
+	  s = unix_mbxline (stream,&bs,&i);
+	  if (i) {		/* got new data? */
+	    VALID (s,t,ti,zn);	/* yes, parse line */
+	    if (!ti) {		/* not a header line, add it to message */
+	      elt->rfc822_size += i;
+	      for (j = 0; j < i; ++j) switch (s[j]) {
+	      case '\r':	/* squeeze out CRs */
+		elt->rfc822_size -= 1;
+		break;
+	      case '\n':	/* LF becomes CRLF */
+		elt->rfc822_size += 1;
+		break;
+	      default:
+		break;
+	      }
+	      if ((i == 1) && (*s == '\n')) {
+		k = 2;
+		m = 1;
+	      }
+	      else if ((i == 2) && (*s == '\r') && (s[1] == '\n'))
+		k = m = 2;
+	      else k = m = 0;	/* file does not end with newline! */
+				/* update current position */
+	      j = LOCAL->filesize + GETPOS (&bs);
+	    }
+	  }
+	} while (i && !ti);	/* until found a header */
+	elt->private.msg.text.text.size = j -
+	  (elt->private.special.offset + elt->private.msg.text.offset);
+				/* flush ending blank line */
+	elt->private.msg.text.text.size -= m;
+	elt->rfc822_size -= k;
+				/* until end of buffer */
+      } while (!stream->sniff && i);
+      if (pseudoseen) {		/* flush pseudo-message if present */
+				/* decrement recent count */
+	if (mail_elt (stream,1)->recent) recent--;
+				/* and the exists count */
+	mail_exists (stream,nmsgs--);
+	mail_expunged(stream,1);/* fake an expunge of that message */
+      }
+				/* need to start a new UID validity? */
+      if (!stream->uid_validity) {
+	stream->uid_validity = time (0);
+				/* in case a whiner with no life */
+	if (mail_parameters (NIL,GET_USERHASNOLIFE,NIL))
+	  stream->uid_nosticky = T;
+	else if (nmsgs) {	/* don't bother if empty file */
+				/* make dirty to restart UID epoch */
+	  LOCAL->ddirty = LOCAL->dirty = T;
+				/* need to rewrite msg 1 if not pseudo */
+	  if (!LOCAL->pseudo) mail_elt (stream,1)->private.dirty = T;
+	  MM_LOG ("Assigning new unique identifiers to all messages",NIL);
+	}
+      }
+      stream->nmsgs = oldnmsgs;	/* whack it back down */
+      stream->silent = silent;	/* restore old silent setting */
+				/* notify upper level of new mailbox sizes */
+      mail_exists (stream,nmsgs);
+      mail_recent (stream,recent);
+				/* mark dirty so O flags are set */
+      if (recent) LOCAL->dirty = T;
+    }
+  }
+				/* no change, don't babble if never got time */
+  else if (LOCAL->filetime && LOCAL->filetime != sbuf.st_mtime)
+    MM_LOG ("New mailbox modification time but apparently no changes",WARN);
+				/* update parsed file size and time */
+  LOCAL->filesize = sbuf.st_size;
+  LOCAL->filetime = sbuf.st_mtime;
+  return T;			/* return the winnage */
+}
+
+/* UNIX read line from mailbox
+ * Accepts: mail stream
+ *	    stringstruct
+ *	    pointer to line size
+ * Returns: pointer to input line
+ */
+
+char *unix_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size)
+{
+  unsigned long i,j,k,m;
+  char *s,*t,*te;
+  char *ret = "";
+				/* flush old buffer */
+  if (LOCAL->line) fs_give ((void **) &LOCAL->line);
+				/* if buffer needs refreshing */
+  if (!bs->cursize) SETPOS (bs,GETPOS (bs));
+  if (SIZE (bs)) {		/* find newline */
+				/* end of fast scan */
+    te = (t = (s = bs->curpos) + bs->cursize) - 12;
+    while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) {
+      --s;			/* back up */
+      break;			/* exit loop */
+    }
+				/* final character-at-a-time scan */
+    while ((s < t) && (*s != '\n')) ++s;
+				/* difficult case if line spans buffer */
+    if ((i = s - bs->curpos) == bs->cursize) {
+				/* have space in line buffer? */
+      if (i > LOCAL->linebuflen) {
+	fs_give ((void **) &LOCAL->linebuf);
+	LOCAL->linebuf = (char *) fs_get (LOCAL->linebuflen = i);
+      }
+				/* remember what we have so far */
+      memcpy (LOCAL->linebuf,bs->curpos,i);
+				/* load next buffer */
+      SETPOS (bs,k = GETPOS (bs) + i);
+				/* end of fast scan */
+      te = (t = (s = bs->curpos) + bs->cursize) - 12;
+				/* fast scan in overlap buffer */
+      while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) {
+	--s;			/* back up */
+	break;			/* exit loop */
+      }
+
+				/* final character-at-a-time scan */
+      while ((s < t) && (*s != '\n')) ++s;
+				/* huge line? */
+      if ((j = s - bs->curpos) == bs->cursize) {
+	SETPOS (bs,GETPOS (bs) + j);
+				/* look for end of line (s-l-o-w!!) */
+	for (m = SIZE (bs); m && (SNX (bs) != '\n'); --m,++j);
+	SETPOS (bs,k);		/* go back to where it started */
+      }
+				/* got size of data, make buffer for return */
+      ret = LOCAL->line = (char *) fs_get (i + j + 2);
+				/* copy first chunk */
+      memcpy (ret,LOCAL->linebuf,i);
+      while (j) {		/* copy remainder */
+	if (!bs->cursize) SETPOS (bs,GETPOS (bs));
+	memcpy (ret + i,bs->curpos,k = min (j,bs->cursize));
+	i += k;			/* account for this much read in */
+	j -= k;
+	bs->curpos += k;	/* increment new position */
+	bs->cursize -= k;	/* eat that many bytes */
+      }
+      if (!bs->cursize) SETPOS (bs,GETPOS (bs));
+				/* read newline at end */
+      if (SIZE (bs)) ret[i++] = SNX (bs);
+      ret[i] = '\0';		/* makes debugging easier */
+    }
+    else {			/* this is easy */
+      ret = bs->curpos;		/* string it at this position */
+      bs->curpos += ++i;	/* increment new position */
+      bs->cursize -= i;		/* eat that many bytes */
+    }
+    *size = i;			/* return that to user */
+  }
+  else *size = 0;		/* end of data, return empty */
+  return ret;
+}
+
+/* UNIX make pseudo-header
+ * Accepts: MAIL stream
+ *	    buffer to write pseudo-header
+ * Returns: length of pseudo-header
+ */
+
+unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr)
+{
+  int i;
+  char *s,tmp[MAILTMPLEN];
+  time_t now = time (0);
+  rfc822_fixed_date (tmp);
+  sprintf (hdr,"From %s %.24s\nDate: %s\nFrom: %s <%s@%.80s>\nSubject: %s\nMessage-ID: <%lu@%.80s>\nX-IMAP: %010lu %010lu",
+	   pseudo_from,ctime (&now),
+	   tmp,pseudo_name,pseudo_from,mylocalhost (),pseudo_subject,
+	   (unsigned long) now,mylocalhost (),stream->uid_validity,
+	   stream->uid_last);
+  for (s = hdr + strlen (hdr),i = 0; i < NUSERFLAGS; ++i)
+    if (stream->user_flags[i])
+      sprintf (s += strlen (s)," %s",stream->user_flags[i]);
+  sprintf (s += strlen (s),"\nStatus: RO\n\n%s\n\n",pseudo_msg);
+  return strlen (hdr);		/* return header length */
+}
+
+/* UNIX make status string
+ * Accepts: MAIL stream
+ *	    destination string to write
+ *	    message cache entry
+ *	    UID to write if non-zero (else use elt->private.uid)
+ *	    non-zero flag to write UID (.LT. 0 to write UID base info too)
+ * Returns: length of string
+ */
+
+unsigned long unix_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt,
+			    unsigned long uid,long flag)
+{
+  char *t,stack[64];
+  char *s = status;
+  unsigned long n;
+  int pad = 50;
+  int sticky = uid ? T : !stream->uid_nosticky;
+  /* This used to use sprintf(), but thanks to certain cretinous C libraries
+     with horribly slow implementations of sprintf() I had to change it to this
+     mess.  At least it should be fast. */
+  if ((flag < 0) && sticky) {	/* need to write X-IMAPbase: header? */
+    *s++ = 'X'; *s++ = '-'; *s++ = 'I'; *s++ = 'M'; *s++ = 'A'; *s++ = 'P';
+    *s++ = 'b'; *s++ = 'a'; *s++ = 's'; *s++ = 'e'; *s++ = ':'; *s++ = ' ';
+    t = stack;
+    n = stream->uid_validity;	/* push UID validity digits on the stack */
+    do *t++ = (char) (n % 10) + '0';
+    while (n /= 10);
+				/* pop UID validity digits from stack */
+    while (t > stack) *s++ = *--t;
+    *s++ = ' ';
+    n = stream->uid_last;	/* push UID last digits on the stack */
+    do *t++ = (char) (n % 10) + '0';
+    while (n /= 10);
+				/* pop UID last digits from stack */
+    while (t > stack) *s++ = *--t;
+    for (n = 0; n < NUSERFLAGS; ++n) if (t = stream->user_flags[n])
+      for (*s++ = ' '; *t; *s++ = *t++);
+    *s++ = '\n';
+    pad += 30;			/* increased padding if have IMAPbase */
+  }
+  *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't'; *s++ = 'u'; *s++ = 's';
+  *s++ = ':'; *s++ = ' ';
+  if (elt->seen) *s++ = 'R';
+				/* only write O if have a UID */
+  if (flag && (!elt->recent || !LOCAL->appending)) *s++ = 'O';
+  *s++ = '\n';
+  *s++ = 'X'; *s++ = '-'; *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't';
+  *s++ = 'u'; *s++ = 's'; *s++ = ':'; *s++ = ' ';
+  if (elt->deleted) *s++ = 'D';
+  if (elt->flagged) *s++ = 'F';
+  if (elt->answered) *s++ = 'A';
+  if (elt->draft) *s++ = 'T';
+  *s++ = '\n';
+
+  if (sticky) {			/* only do this if UIDs sticky */
+    *s++ = 'X'; *s++ = '-'; *s++ = 'K'; *s++ = 'e'; *s++ = 'y'; *s++ = 'w';
+    *s++ = 'o'; *s++ = 'r'; *s++ = 'd'; *s++ = 's'; *s++ = ':';
+    if (n = elt->user_flags) do {
+      *s++ = ' ';
+      for (t = stream->user_flags[find_rightmost_bit (&n)]; *t; *s++ = *t++);
+    } while (n);
+    n = s - status;		/* get size of stuff so far */
+				/* pad X-Keywords to make size constant */
+    if (n < pad) for (n = pad - n; n > 0; --n) *s++ = ' ';
+    *s++ = '\n';
+    if (flag) {			/* want to include UID? */
+      t = stack;
+				/* push UID digits on the stack */
+      n = uid ? uid : elt->private.uid;
+      do *t++ = (char) (n % 10) + '0';
+      while (n /= 10);
+      *s++ = 'X'; *s++ = '-'; *s++ = 'U'; *s++ = 'I'; *s++ = 'D'; *s++ = ':';
+      *s++ = ' ';
+				/* pop UID from stack */
+      while (t > stack) *s++ = *--t;
+      *s++ = '\n';
+    }
+  }
+  *s++ = '\n'; *s = '\0';	/* end of extended message status */
+  return s - status;		/* return size of resulting string */
+}
+
+/* Rewrite mailbox file
+ * Accepts: MAIL stream, must be critical and locked
+ *	    return pointer to number of expunged messages if want expunge
+ *	    lock file name
+ *	    expunge sequence, not deleted flag
+ * Returns: T if success and mailbox unlocked, NIL if failure
+ */
+
+#define OVERFLOWBUFLEN 8192	/* initial overflow buffer length */
+
+long unix_rewrite (MAILSTREAM *stream,unsigned long *nexp,DOTLOCK *lock,
+		   long flags)
+{
+  MESSAGECACHE *elt;
+  UNIXFILE f;
+  char *s;
+  time_t tp[2];
+  long ret,flag;
+  unsigned long i,j;
+  unsigned long recent = stream->recent;
+  unsigned long size = LOCAL->pseudo ? unix_pseudo (stream,LOCAL->buf) : 0;
+  if (nexp) *nexp = 0;		/* initially nothing expunged */
+				/* calculate size of mailbox after rewrite */
+  for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs; i++) {
+    elt = mail_elt (stream,i);	/* get cache */
+    if (!(nexp && elt->deleted && (flags ? elt->sequence : T))) {
+				/* add RFC822 size of this message */
+      size += elt->private.special.text.size + elt->private.spare.data +
+	unix_xstatus (stream,LOCAL->buf,elt,NIL,flag) +
+	  elt->private.msg.text.text.size + 1;
+      flag = 1;			/* only count X-IMAPbase once */
+    }
+  }
+				/* no messages, has a life, and no pseudo */
+  if (!size && !mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) {
+    LOCAL->pseudo = T;		/* so make a pseudo-message now */
+    size = unix_pseudo (stream,LOCAL->buf);
+  }
+				/* extend the file as necessary */
+  if (ret = unix_extend (stream,size)) {
+    /* Set up buffered I/O file structure
+     * curpos	current position being written through buffering
+     * filepos	current position being written physically to the disk
+     * bufpos	current position being written in the buffer
+     * protect	current maximum position that can be written to the disk
+     *		before buffering is forced
+     * The code tries to buffer so that that disk is written in multiples of
+     * OVERBLOWBUFLEN bytes.
+     */
+    f.stream = stream;		/* note mail stream */
+    f.curpos = f.filepos = 0;	/* start of file */
+    f.protect = stream->nmsgs ?	/* initial protection pointer */
+    mail_elt (stream,1)->private.special.offset : 8192;
+    f.bufpos = f.buf = (char *) fs_get (f.buflen = OVERFLOWBUFLEN);
+
+    if (LOCAL->pseudo)		/* update pseudo-header */
+      unix_write (&f,LOCAL->buf,unix_pseudo (stream,LOCAL->buf));
+				/* loop through all messages */
+    for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs;) {
+      elt = mail_elt (stream,i);/* get cache */
+				/* expunge this message? */
+      if (nexp && elt->deleted && (flags ? elt->sequence : T)) {
+				/* one less recent message */
+	if (elt->recent) --recent;
+	mail_expunged(stream,i);/* notify upper levels */
+	++*nexp;		/* count up one more expunged message */
+      }
+      else {			/* preserve this message */
+	i++;			/* advance to next message */
+	if ((flag < 0) ||	/* need to rewrite message? */
+	    elt->private.dirty || (f.curpos != elt->private.special.offset) ||
+	    (elt->private.msg.header.text.size !=
+	     (elt->private.spare.data +
+	      unix_xstatus (stream,LOCAL->buf,elt,NIL,flag)))) {
+	  unsigned long newoffset = f.curpos;
+				/* yes, seek to internal header */
+	  lseek (LOCAL->fd,elt->private.special.offset,L_SET);
+	  read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size);
+				/* see if need to squeeze out a CR */
+	  if (LOCAL->buf[elt->private.special.text.size - 2] == '\r') {
+	    LOCAL->buf[--elt->private.special.text.size - 1] = '\n';
+	    --size;		/* squeezed out a CR from PC */
+	  }
+				/* protection pointer moves to RFC822 header */
+	  f.protect = elt->private.special.offset +
+	    elt->private.msg.header.offset;
+				/* write internal header */
+	  unix_write (&f,LOCAL->buf,elt->private.special.text.size);
+				/* get RFC822 header */
+	  s = unix_header (stream,elt->msgno,&j,FT_INTERNAL);
+				/* in case this got decremented */
+	  elt->private.msg.header.offset = elt->private.special.text.size;
+				/* header size, sans trailing newline */
+	  if ((j < 2) || (s[j - 2] == '\n')) j--;
+				/* this can happen if CRs were squeezed */
+	  if (j < elt->private.spare.data) {
+				/* so fix up counts */
+	    size -= elt->private.spare.data - j;
+	    elt->private.spare.data = j;
+	  }
+	  else if (j != elt->private.spare.data)
+	    fatal ("header size inconsistent");
+				/* protection pointer moves to RFC822 text */
+	  f.protect = elt->private.special.offset +
+	    elt->private.msg.text.offset;
+	  unix_write (&f,s,j);	/* write RFC822 header */
+				/* write status and UID */
+	  unix_write (&f,LOCAL->buf,
+		      j = unix_xstatus (stream,LOCAL->buf,elt,NIL,flag));
+	  flag = 1;		/* only write X-IMAPbase once */
+				/* new file header size */
+	  elt->private.msg.header.text.size = elt->private.spare.data + j;
+
+				/* did text move? */
+	  if (f.curpos != f.protect) {
+				/* get message text */
+	    s = unix_text_work (stream,elt,&j,FT_INTERNAL);
+				/* this can happen if CRs were squeezed */
+	    if (j < elt->private.msg.text.text.size) {
+				/* so fix up counts */
+	      size -= elt->private.msg.text.text.size - j;
+	      elt->private.msg.text.text.size = j;
+	    }
+				/* can't happen it says here */
+	    else if (j > elt->private.msg.text.text.size)
+	      fatal ("text size inconsistent");
+				/* new text offset, status/UID may change it */
+	    elt->private.msg.text.offset = f.curpos - newoffset;
+				/* protection pointer moves to next message */
+	    f.protect = (i <= stream->nmsgs) ?
+	      mail_elt (stream,i)->private.special.offset : (f.curpos + j + 1);
+	    unix_write (&f,s,j);/* write text */
+				/* write trailing newline */
+	    unix_write (&f,"\n",1);
+	  }
+	  else {		/* tie off header and status */
+	    unix_write (&f,NIL,NIL);
+				/* protection pointer moves to next message */
+	    f.protect = (i <= stream->nmsgs) ?
+	      mail_elt (stream,i)->private.special.offset : size;
+				/* locate end of message text */
+	    j = f.filepos + elt->private.msg.text.text.size;
+				/* trailing newline already there? */
+	    if (f.protect == (j + 1)) f.curpos = f.filepos = f.protect;
+	    else {		/* trailing newline missing, write it */
+	      f.curpos = f.filepos = j;
+	      unix_write (&f,"\n",1);
+	    }
+	  }
+				/* new internal header offset */
+	  elt->private.special.offset = newoffset;
+	  elt->private.dirty =NIL;/* message is now clean */
+	}
+	else {			/* no need to rewrite this message */
+				/* tie off previous message if needed */
+	  unix_write (&f,NIL,NIL);
+				/* protection pointer moves to next message */
+	  f.protect = (i <= stream->nmsgs) ?
+	    mail_elt (stream,i)->private.special.offset : size;
+				/* locate end of message text */
+	  j = f.filepos + elt->private.special.text.size +
+	    elt->private.msg.header.text.size +
+	      elt->private.msg.text.text.size;
+				/* trailing newline already there? */
+	  if (f.protect == (j + 1)) f.curpos = f.filepos = f.protect;
+	  else {		/* trailing newline missing, write it */
+	    f.curpos = f.filepos = j;
+	    unix_write (&f,"\n",1);
+	  }
+	}
+      }
+    }
+
+    unix_write (&f,NIL,NIL);	/* tie off final message */
+    if (size != f.filepos) fatal ("file size inconsistent");
+    fs_give ((void **) &f.buf);	/* free buffer */
+				/* make sure tied off */
+    ftruncate (LOCAL->fd,LOCAL->filesize = size);
+    fsync (LOCAL->fd);		/* make sure the updates take */
+    if (size && (flag < 0)) fatal ("lost UID base information");
+				/* no longer dirty */
+    LOCAL->ddirty = LOCAL->dirty = NIL;
+  				/* notify upper level of new mailbox sizes */
+    mail_exists (stream,stream->nmsgs);
+    mail_recent (stream,recent);
+				/* set atime to now, mtime a second earlier */
+    tp[1] = (tp[0] = time (0)) - 1;
+				/* set the times, note change */
+    if (!utime (stream->mailbox,tp)) LOCAL->filetime = tp[1];
+    close (LOCAL->fd);		/* close and reopen file */
+    if ((LOCAL->fd = open (stream->mailbox,O_RDWR,
+			   (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL)))
+	< 0) {
+      sprintf (LOCAL->buf,"Mailbox open failed, aborted: %s",strerror (errno));
+      MM_LOG (LOCAL->buf,ERROR);
+      unix_abort (stream);
+    }
+    dotlock_unlock (lock);	/* flush the lock file */
+  }
+  return ret;			/* return state from algorithm */
+}
+
+/* Extend UNIX mailbox file
+ * Accepts: MAIL stream
+ *	    new desired size
+ * Return: T if success, else NIL
+ */
+
+long unix_extend (MAILSTREAM *stream,unsigned long size)
+{
+  unsigned long i = (size > LOCAL->filesize) ? size - LOCAL->filesize : 0;
+  if (i) {			/* does the mailbox need to grow? */
+    if (i > LOCAL->buflen) {	/* make sure have enough space */
+				/* this user won the lottery all right */
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get ((LOCAL->buflen = i) + 1);
+    }
+    memset (LOCAL->buf,'\0',i);	/* get a block of nulls */
+    while (T) {			/* until write successful or punt */
+      lseek (LOCAL->fd,LOCAL->filesize,L_SET);
+      if ((write (LOCAL->fd,LOCAL->buf,i) >= 0) && !fsync (LOCAL->fd)) break;
+      else {
+	long e = errno;		/* note error before doing ftruncate */
+	ftruncate (LOCAL->fd,LOCAL->filesize);
+	if (MM_DISKERROR (stream,e,NIL)) {
+	  fsync (LOCAL->fd);	/* user chose to punt */
+	  sprintf (LOCAL->buf,"Unable to extend mailbox: %s",strerror (e));
+	  if (!stream->silent) MM_LOG (LOCAL->buf,ERROR);
+	  return NIL;
+	}
+      }
+    }
+  }
+  return LONGT;
+}
+
+/* Write data to buffered file
+ * Accepts: buffered file pointer
+ *	    file data or NIL to indicate "flush buffer"
+ *	    date size (ignored for "flush buffer")
+ * Does not return until success
+ */
+
+void unix_write (UNIXFILE *f,char *buf,unsigned long size)
+{
+  unsigned long i,j,k;
+  if (buf) {			/* doing buffered write? */
+    i = f->bufpos - f->buf;	/* yes, get size of current buffer data */
+				/* yes, have space in current buffer chunk? */
+    if (j = i ? ((f->buflen - i) % OVERFLOWBUFLEN) : f->buflen) {
+				/* yes, fill up buffer as much as we can */
+      memcpy (f->bufpos,buf,k = min (j,size));
+      f->bufpos += k;		/* new buffer position */
+      f->curpos += k;		/* new current position */
+      if (j -= k) return;	/* all done if still have buffer free space */
+      buf += k;			/* full, get new unwritten data pointer */
+      size -= k;		/* new data size */
+      i += k;			/* new buffer data size */
+    }
+    /* This chunk of the buffer is full.  See if can make some space by
+     * writing to the disk, if there's enough unprotected space to do so.
+     * Try to fill out any unaligned chunk, along with any subsequent full
+     * chunks that will fit in unprotected space.
+     */
+				/* any unprotected space we can write to? */
+    if (j = min (i,f->protect - f->filepos)) {
+				/* yes, filepos not at chunk boundary? */
+      if ((k = f->filepos % OVERFLOWBUFLEN) && ((k = OVERFLOWBUFLEN - k) < j))
+	j -= k;			/* yes, and can write out partial chunk */
+      else k = 0;		/* no partial chunk to write */
+				/* if at least a chunk free, write that too */
+      if (j > OVERFLOWBUFLEN) k += j - (j % OVERFLOWBUFLEN);
+      if (k) {			/* write data if there is anything we can */
+	unix_phys_write (f,f->buf,k);
+				/* slide buffer */
+	if (i -= k) memmove (f->buf,f->buf + k,i);
+	f->bufpos = f->buf + i;	/* new end of buffer */
+      }
+    }
+
+    /* Have flushed the buffer as best as possible.  All done if no more
+     * data to write.  Otherwise, if the buffer is empty AND if the unwritten
+     * data is larger than a chunk AND the unprotected space is also larger
+     * than a chunk, then write as many chunks as we can directly from the
+     * data.  Buffer the rest, expanding the buffer as needed.
+     */
+    if (size) {			/* have more data that we need to buffer? */
+				/* can write any of it to disk instead? */
+      if ((f->bufpos == f->buf) && 
+	  ((j = min (f->protect - f->filepos,size)) > OVERFLOWBUFLEN)) {
+				/* write as much as we can right now */
+	unix_phys_write (f,buf,j -= (j % OVERFLOWBUFLEN));
+	buf += j;		/* new data pointer */
+	size -= j;		/* new data size */
+	f->curpos += j;		/* advance current pointer */
+      }
+      if (size) {		/* still have data that we need to buffer? */
+				/* yes, need to expand the buffer? */
+	if ((i = ((f->bufpos + size) - f->buf)) > f->buflen) {
+				/* note current position in buffer */
+	  j = f->bufpos - f->buf;
+	  i += OVERFLOWBUFLEN;	/* yes, grow another chunk */
+	  fs_resize ((void **) &f->buf,f->buflen = i - (i % OVERFLOWBUFLEN));
+				/* in case buffer relocated */
+	  f->bufpos = f->buf + j;
+	}
+				/* buffer remaining data */
+	memcpy (f->bufpos,buf,size);
+	f->bufpos += size;	/* new end of buffer */
+	f->curpos += size;	/* advance current pointer */
+      }
+    }
+  }
+  else {			/* flush buffer to disk */
+    unix_phys_write (f,f->buf,i = f->bufpos - f->buf);
+    f->bufpos = f->buf;		/* reset buffer */
+				/* update positions */
+    f->curpos = f->protect = f->filepos;
+  }
+}
+
+/* Physical disk write
+ * Accepts: buffered file pointer
+ *	    buffer address
+ *	    buffer size
+ * Does not return until success
+ */
+
+void unix_phys_write (UNIXFILE *f,char *buf,size_t size)
+{
+  MAILSTREAM *stream = f->stream;
+				/* write data at desired position */
+  while (size && ((lseek (LOCAL->fd,f->filepos,L_SET) < 0) ||
+		  (write (LOCAL->fd,buf,size) < 0))) {
+    int e;
+    char tmp[MAILTMPLEN];
+    sprintf (tmp,"Unable to write to mailbox: %s",strerror (e = errno));
+    MM_LOG (tmp,ERROR);
+    MM_DISKERROR (NIL,e,T);	/* serious problem, must retry */
+  }
+  f->filepos += size;		/* update file position */
+}
+
+/* MBOX mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER mboxdriver = {
+  "mbox",			/* driver name */
+				/* driver flags */
+  DR_LOCAL|DR_MAIL|DR_LOCKING|DR_NONEWMAILRONLY,
+  (DRIVER *) NIL,		/* next driver */
+  mbox_valid,			/* mailbox is valid for us */
+  unix_parameters,		/* manipulate parameters */
+  unix_scan,			/* scan mailboxes */
+  unix_list,			/* find mailboxes */
+  unix_lsub,			/* find subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  mbox_create,			/* create mailbox */
+  mbox_delete,			/* delete mailbox */
+  mbox_rename,			/* rename mailbox */
+  mbox_status,			/* status of mailbox */
+  mbox_open,			/* open mailbox */
+  unix_close,			/* close mailbox */
+  NIL,				/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message structure */
+  unix_header,			/* fetch message header */
+  unix_text,			/* fetch message body */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  NIL,				/* modify flags */
+  unix_flagmsg,			/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  mbox_ping,			/* ping mailbox to see if still alive */
+  mbox_check,			/* check for new messages */
+  mbox_expunge,			/* expunge deleted messages */
+  unix_copy,			/* copy messages to another mailbox */
+  mbox_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM mboxproto = {&mboxdriver};
+
+/* MBOX mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *mbox_valid (char *name)
+{
+				/* only INBOX, mbox must exist */
+  if (!compare_cstring (name,"INBOX") && (unix_valid ("mbox") || !errno) &&
+      (unix_valid (sysinbox()) || !errno || (errno == ENOENT)))
+    return &mboxdriver;
+  return NIL;			/* can't win (yet, anyway) */
+}
+
+/* MBOX mail create mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long mbox_create (MAILSTREAM *stream,char *mailbox)
+{
+  char tmp[MAILTMPLEN];
+  if (!compare_cstring (mailbox,"INBOX")) return unix_create (NIL,"mbox");
+  sprintf (tmp,"Can't create non-INBOX name as mbox: %.80s",mailbox);
+  MM_LOG (tmp,ERROR);
+  return NIL;
+}
+
+
+/* MBOX mail delete mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long mbox_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return mbox_rename (stream,mailbox,NIL);
+}
+
+
+/* MBOX mail rename mailbox
+ * Accepts: MAIL stream
+ *	    old mailbox name
+ *	    new mailbox name (or NIL for delete)
+ * Returns: T on success, NIL on failure
+ */
+
+long mbox_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  char tmp[MAILTMPLEN];
+  long ret = unix_rename (stream,"~/mbox",newname);
+				/* recreate file if renamed INBOX */
+  if (ret) unix_create (NIL,"mbox");
+  else MM_LOG (tmp,ERROR);	/* log error */
+  return ret;			/* return success */
+}
+
+/* MBOX Mail status
+ * Accepts: mail stream
+ *	    mailbox name
+ *	    status flags
+ * Returns: T on success, NIL on failure
+ */
+
+long mbox_status (MAILSTREAM *stream,char *mbx,long flags)
+{
+  MAILSTATUS status;
+  unsigned long i;
+  MAILSTREAM *tstream = NIL;
+  MAILSTREAM *systream = NIL;
+				/* make temporary stream (unless this mbx) */
+  if (!stream && !(stream = tstream =
+		   mail_open (NIL,mbx,OP_READONLY|OP_SILENT))) return NIL;
+  status.flags = flags;		/* return status values */
+  status.messages = stream->nmsgs;
+  status.recent = stream->recent;
+  if (flags & SA_UNSEEN)	/* must search to get unseen messages */
+    for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++)
+      if (!mail_elt (stream,i)->seen) status.unseen++;
+  status.uidnext = stream->uid_last + 1;
+  status.uidvalidity = stream->uid_validity;
+  if (!status.recent &&		/* calculate post-snarf results */
+      (systream = mail_open (NIL,sysinbox (),OP_READONLY|OP_SILENT))) {
+    status.messages += systream->nmsgs;
+    status.recent += systream->recent;
+    if (flags & SA_UNSEEN)	/* must search to get unseen messages */
+      for (i = 1; i <= systream->nmsgs; i++)
+	if (!mail_elt (systream,i)->seen) status.unseen++;
+				/* kludge but probably good enough */
+    status.uidnext += systream->nmsgs;
+  }
+  MM_STATUS(stream,mbx,&status);/* pass status to main program */
+  if (tstream) mail_close (tstream);
+  if (systream) mail_close (systream);
+  return T;			/* success */
+}
+
+/* MBOX mail open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *mbox_open (MAILSTREAM *stream)
+{
+  unsigned long i = 1;
+  unsigned long recent = 0;
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return &mboxproto;
+				/* change mailbox file name */
+  fs_give ((void **) &stream->mailbox);
+  stream->mailbox = cpystr ("mbox");
+				/* open mailbox, snarf new mail */
+  if (!(unix_open (stream) && mbox_ping (stream))) return NIL;
+  stream->inbox = T;		/* mark that this is an INBOX */
+				/* notify upper level of mailbox sizes */
+  mail_exists (stream,stream->nmsgs);
+  while (i <= stream->nmsgs) if (mail_elt (stream,i++)->recent) ++recent;
+  mail_recent (stream,recent);	/* including recent messages */
+  return stream;
+}
+
+/* MBOX mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ * No-op for readonly files, since read/writer can expunge it from under us!
+ */
+
+static int snarfed = 0;		/* number of snarfs */
+
+long mbox_ping (MAILSTREAM *stream)
+{
+  int sfd;
+  unsigned long size;
+  struct stat sbuf;
+  char *s;
+  DOTLOCK lock,lockx;
+				/* time to try snarf and sysinbox non-empty? */
+  if (LOCAL && !stream->rdonly && !stream->lock &&
+      (time (0) >= (LOCAL->lastsnarf +
+		    (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL))) &&
+      !stat (sysinbox (),&sbuf) && sbuf.st_size) {
+    MM_CRITICAL (stream);	/* yes, go critical */
+				/* open and lock sysinbox */
+    if ((sfd = unix_lock (sysinbox (),O_RDWR,
+			  (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
+			  &lockx,LOCK_EX)) >= 0) {
+				/* locked sysinbox in good format? */
+      if (fstat (sfd,&sbuf) || !(size = sbuf.st_size) ||
+	  !unix_isvalid_fd (sfd)) {
+	sprintf (LOCAL->buf,"Mail drop %s is not in standard Unix format",
+		 sysinbox ());
+	MM_LOG (LOCAL->buf,ERROR);
+      }
+				/* sysinbox good, parse and excl-lock mbox */
+      else if (unix_parse (stream,&lock,LOCK_EX)) {
+	lseek (sfd,0,L_SET);	/* read entire sysinbox into memory */
+	read (sfd,s = (char *) fs_get (size + 1),size);
+	s[size] = '\0';		/* tie it off */
+				/* append to end of mbox */
+	lseek (LOCAL->fd,LOCAL->filesize,L_SET);
+
+				/* copy to mbox */
+	if ((write (LOCAL->fd,s,size) < 0) || fsync (LOCAL->fd)) {
+	  sprintf (LOCAL->buf,"New mail move failed: %s",strerror (errno));
+	  MM_LOG (LOCAL->buf,WARN);
+				/* revert mbox to previous size */
+	  ftruncate (LOCAL->fd,LOCAL->filesize);
+	}
+				/* sysinbox better not have changed */
+	else if (fstat (sfd,&sbuf) || (size != sbuf.st_size)) {
+	  sprintf (LOCAL->buf,"Mail drop %s lock failure, old=%lu now=%lu",
+		   sysinbox (),size,(unsigned long) sbuf.st_size);
+	  MM_LOG (LOCAL->buf,ERROR);
+				/* revert mbox to previous size */
+	  ftruncate (LOCAL->fd,LOCAL->filesize);
+	  /* Believe it or not, a Singaporean government system actually had
+	   * symlinks from /var/mail/user to ~user/mbox.  To compound this
+	   * error, they used an SVR4 system; BSD and OSF locks would have
+	   * prevented it but not SVR4 locks.
+	   */
+	  if (!fstat (sfd,&sbuf) && (size == sbuf.st_size))
+	    syslog (LOG_ALERT,"File %s and %s are the same file!",
+		    sysinbox (),stream->mailbox);
+	}
+	else {			/* data copied OK */
+	  ftruncate (sfd,0);	/* truncate sysinbox to zero bytes */
+	  if (!snarfed++) {	/* have we snarfed before? */
+				/* syslog if server, else user log */
+	    sprintf (LOCAL->buf,"Moved %lu bytes of new mail to %s from %s",
+		     size,stream->mailbox,sysinbox ());
+	    if (strcmp ((char *) mail_parameters (NIL,GET_SERVICENAME,NIL),
+			"unknown"))
+	      syslog (LOG_INFO,"%s host= %s",LOCAL->buf,tcp_clienthost ());
+	    else MM_LOG (LOCAL->buf,WARN);
+	  }
+	}
+				/* done with sysinbox text */
+	fs_give ((void **) &s);
+				/* all done with mbox */
+	unix_unlock (LOCAL->fd,stream,&lock);
+	mail_unlock (stream);	/* unlock the stream */
+	MM_NOCRITICAL (stream);	/* done with critical */
+      }
+				/* all done with sysinbox */
+      unix_unlock (sfd,NIL,&lockx);
+    }
+    MM_NOCRITICAL (stream);	/* done with critical */
+    LOCAL->lastsnarf = time (0);/* note time of last snarf */
+  }
+  return unix_ping (stream);	/* do the unix routine now */
+}
+
+/* MBOX mail check mailbox
+ * Accepts: MAIL stream
+ */
+
+void mbox_check (MAILSTREAM *stream)
+{
+				/* do local ping, then do unix routine */
+  if (mbox_ping (stream)) unix_check (stream);
+}
+
+
+/* MBOX mail expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long mbox_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  long ret = unix_expunge (stream,sequence,options);
+  mbox_ping (stream);		/* do local ping */
+  return ret;
+}
+
+
+/* MBOX mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long mbox_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  char tmp[MAILTMPLEN];
+  if (mbox_valid (mailbox)) return unix_append (stream,"mbox",af,data);
+  sprintf (tmp,"Can't append to that name: %.80s",mailbox);
+  MM_LOG (tmp,ERROR);
+  return NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/unix.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,219 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX mail routines, Amiga version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	20 December 1989
+ * Last Edited:	30 August 2006
+ */
+
+
+/*				DEDICATION
+ *
+ *  This file is dedicated to my dog, Unix, also known as Yun-chan and
+ * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast.  Unix
+ * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after
+ * a two-month bout with cirrhosis of the liver.
+ *
+ *  He was a dear friend, and I miss him terribly.
+ *
+ *  Lift a leg, Yunie.  Luv ya forever!!!!
+ */
+
+/* Validate line
+ * Accepts: pointer to candidate string to validate as a From header
+ *	    return pointer to end of date/time field
+ *	    return pointer to offset from t of time (hours of ``mmm dd hh:mm'')
+ *	    return pointer to offset from t of time zone (if non-zero)
+ * Returns: t,ti,zn set if valid From string, else ti is NIL
+ */
+
+#define VALID(s,x,ti,zn) {						\
+  int remote = 0;							\
+  ti = 0;								\
+  if ((*s == 'F') && (s[1] == 'r') && (s[2] == 'o') && (s[3] == 'm') &&	\
+      (s[4] == ' ')) {							\
+    for (x = s + 5; *x && *x != '\012'; x++);				\
+    if (*x) {								\
+      if (x[-1] == '\015') --x;						\
+      if (x - s >= 41) {						\
+	for (zn = -1; x[zn] != ' '; zn--);				\
+	if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') &&	\
+	    (x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') &&	\
+	    (x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') &&	\
+	    (x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))\
+	  {								\
+	    while (x[zn-13] == ' ') zn--;				\
+	    x += zn - 12;						\
+	    remote = 1;							\
+	  }								\
+      }									\
+      if (x - s >= 27) {						\
+	if (x[-5] == ' ') {						\
+	  if (x[-8] == ':') zn = 0,ti = -5;				\
+	  else if (x[-9] == ' ') ti = zn = -9;				\
+	  else if ((x[-11] == ' ') && ((x[-10]=='+') || (x[-10]=='-')))	\
+	    ti = zn = -11;						\
+	}								\
+	else if (x[-4] == ' ') {					\
+	  if (x[-9] == ' ') zn = -4,ti = -9;				\
+	  else if ( (x[-13] == ' ') && (x[-16] == ' ')			\
+		&& (x[-20] ==' ') &&					\
+		( ((x[-22] == ' ') && (x[-23] == ',')) ||		\
+		  ((x[-23] == ' ') && (x[-24] == ',')) ) ) {		\
+	    char weekday[4]={0,}, month[4]={0,}, time[11]={0,};		\
+	    char tzone[4]={0,}; 					\
+	    char realtime[80];						\
+	    int day,year,start=-26;					\
+	    if (x[-23] == ' ') x--;					\
+	      sscanf(&x[start],"%3c, %d %s %d %s %s",			\
+		weekday,&day,month,&year,time,tzone);			\
+	      sprintf(realtime,"%s %s %2d %s %d %s",			\
+		weekday,month,day,time, 				\
+		( (year < 100) ? year+1900 : year),tzone);		\
+	      if (remote)						\
+		strcat(realtime," remote from ");			\
+	      else							\
+		strcat(realtime,"\n");					\
+	      strncpy(&x[start],realtime,strlen(realtime));		\
+	      zn = -2;							\
+	      ti = -7;							\
+	  }								\
+	}								\
+	else if (x[-6] == ' ') {					\
+	  if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-')))	\
+	    zn = -6,ti = -11;						\
+	}								\
+	else if (x[-9] == ' ') {					\
+	    if ( ( (x[-12] == ' ') && (x[-16] == ' ') &&		\
+		  ( ((x[-18] == ' ') && (x[-19] == ',') )  ||		\
+		    ((x[-19] == ' ') && (x[-20] == ',')) )		\
+		||							\
+		((x[-14] == ' ') && (x[-18] == ' ') &&			\
+		  ( ((x[-20] == ' ') && (x[-21] == ',') )  ||		\
+		    ((x[-21] == ' ') && (x[-22] == ',')) ) ) ) ) {	\
+	      char weekday[4]={0,}, month[4]={0,},time[11]={0,};	\
+	      int day,year,start=-24;					\
+	      char realtime[80];					\
+	      if (x[-12] == ' ') x++;					\
+	      if (x[-19] == ' ') x++;					\
+	      sscanf(&x[start],"%3c, %d %3c %d %s",weekday,		\
+		     &day,month,&year,time);				\
+	      sprintf(realtime,"%s %s %2d %s %d",weekday,month,day,time,\
+		 ( (year < 100) ? year+1900 : year));			\
+	      if (remote)						\
+		strcat(realtime," remote from ");			\
+	      else							\
+		strcat(realtime,"\n");					\
+	      strncpy(&x[start],realtime,strlen(realtime));		\
+	      ti=-5;							\
+	      zn=0;							\
+	    }								\
+	}								\
+	if (ti && !((x[ti - 3] == ':') &&				\
+		    (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') &&	\
+		    (x[ti - 3] == ' ') && (x[ti - 7] == ' ') &&		\
+		    (x[ti - 11] == ' '))) ti = 0;			\
+      }									\
+    }									\
+  }									\
+}
+
+/* You are not expected to understand this macro, but read the next page if
+ * you are not faint of heart.
+ *
+ * Known formats to the VALID macro are:
+ *		From user Wed Dec  2 05:53 1992
+ * BSD		From user Wed Dec  2 05:53:22 1992
+ * SysV		From user Wed Dec  2 05:53 PST 1992
+ * rn		From user Wed Dec  2 05:53:22 PST 1992
+ *		From user Wed Dec  2 05:53 -0700 1992
+ * emacs	From user Wed Dec  2 05:53:22 -0700 1992
+ *		From user Wed Dec  2 05:53 1992 PST
+ *		From user Wed Dec  2 05:53:22 1992 PST
+ *		From user Wed Dec  2 05:53 1992 -0700
+ * Solaris	From user Wed Dec  2 05:53:22 1992 -0700
+ *
+ * Amiga	From user Wed, 6 Dec 92 05:53:22 who did this !!!
+ *		CHANGED in place to
+ *		From user Wed Dec  2 05:53:22 1992
+ *
+ * Plus all of the above with `` remote from xxx'' after it. Thank you very
+ * much, smail and Solaris, for making my life considerably more complicated.
+ */
+
+/*
+ * What?  You want to understand the VALID macro anyway?  Alright, since you
+ * insist.  Actually, it isn't really all that difficult, provided that you
+ * take it step by step.
+ *
+ * Line 1	Initializes the return ti value to failure (0);
+ * Lines 2-3	Validates that the 1st-5th characters are ``From ''.
+ * Lines 4-6	Validates that there is an end of line and points x at it.
+ * Lines 7-14	First checks to see if the line is at least 41 characters long.
+ *		If so, it scans backwards to find the rightmost space.  From
+ *		that point, it scans backwards to see if the string matches
+ *		`` remote from''.  If so, it sets x to point to the space at
+ *		the start of the string.
+ * Line 15	Makes sure that there are at least 27 characters in the line.
+ * Lines 16-21	Checks if the date/time ends with the year (there is a space
+ *		five characters back).  If there is a colon three characters
+ *		further back, there is no timezone field, so zn is set to 0
+ *		and ti is set in front of the year.  Otherwise, there must
+ *		either to be a space four characters back for a three-letter
+ *		timezone, or a space six characters back followed by a + or -
+ *		for a numeric timezone; in either case, zn and ti become the
+ *		offset of the space immediately before it.
+ * Lines 22-24	Are the failure case for line 14.  If there is a space four
+ *		characters back, it is a three-letter timezone; there must be a
+ *		space for the year nine characters back.  zn is the zone
+ *		offset; ti is the offset of the space.
+ * Lines 25-28	Are the failure case for line 20.  If there is a space six
+ *		characters back, it is a numeric timezone; there must be a
+ *		space eleven characters back and a + or - five characters back.
+ *		zn is the zone offset; ti is the offset of the space.
+ * Line 29-32	If ti is valid, make sure that the string before ti is of the
+ *		form www mmm dd hh:mm or www mmm dd hh:mm:ss, otherwise
+ *		invalidate ti.  There must be a colon three characters back
+ *		and a space six or nine	characters back (depending upon
+ *		whether or not the character six characters back is a colon).
+ *		There must be a space three characters further back (in front
+ *		of the day), one seven characters back (in front of the month),
+ *		and one eleven characters back (in front of the day of week).
+ *		ti is set to be the offset of the space before the time.
+ *
+ * Why a macro?  It gets invoked a *lot* in a tight loop.  On some of the
+ * newer pipelined machines it is faster being open-coded than it would be if
+ * subroutines are called.
+ *
+ * Why does it scan backwards from the end of the line, instead of doing the
+ * much easier forward scan?  There is no deterministic way to parse the
+ * ``user'' field, because it may contain unquoted spaces!  Yes, I tested it to
+ * see if unquoted spaces were possible.  They are, and I've encountered enough
+ * evil mail to be totally unwilling to trust that ``it will never happen''.
+ */
+
+/* Build parameters */
+
+#define KODRETRY 15		/* kiss-of-death retry in seconds */
+#define LOCKTIMEOUT 5		/* lock timeout in minutes */
+#define CHUNK 16384		/* read-in chunk size */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/amiga/write.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,59 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Write data, treating partial writes as an error
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	26 May 1995
+ * Last Edited:	30 August 2006
+ */
+
+/*  The whole purpose of this unfortunate routine is to deal with DOS and
+ * certain cretinous versions of UNIX which decided that the "bytes actually
+ * written" return value from write() gave them license to use that for things
+ * that are really errors, such as disk quota exceeded, maximum file size
+ * exceeded, disk full, etc.
+ * 
+ *  BSD won't screw us this way on the local filesystem, but who knows what
+ * some NFS-mounted filesystem will do.
+ */
+
+#undef write
+
+/* Write data to file
+ * Accepts: file descriptor
+ *	    I/O vector structure
+ *	    number of vectors in structure
+ * Returns: number of bytes written if successful, -1 if failure
+ */
+
+long maxposint = (long)((((unsigned long) 1) << ((sizeof(int) * 8) - 1)) - 1);
+
+long safe_write (int fd,char *buf,long nbytes)
+{
+  long i,j;
+  if (nbytes > 0) for (i = nbytes; i; i -= j,buf += j) {
+    while (((j = write (fd,buf,(int) min (maxposint,i))) < 0) &&
+	   (errno == EINTR));
+    if (j < 0) return j;
+  }
+  return nbytes;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/bezrkdos.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,901 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Berkeley mail routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	24 June 1992
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Dedication:
+ *  This file is dedicated with affection to those Merry Marvels of Musical
+ * Madness . . .
+ *  ->  The Incomparable Leland Stanford Junior University Marching Band  <-
+ * who entertain, awaken, and outrage Stanford fans in the fact of repeated
+ * losing seasons and shattered Rose Bowl dreams [Cardinal just don't have
+ * HUSKY FEVER!!!].
+ *
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include "mail.h"
+#include "osdep.h"
+#include <time.h>
+#include <sys\stat.h>
+#include <dos.h>
+#include "rfc822.h"
+#include "dummy.h"
+#include "misc.h"
+#include "fdstring.h"
+
+/* Berkeley I/O stream local data */
+	
+typedef struct bezerk_local {
+  int fd;			/* file descriptor for I/O */
+  off_t filesize;		/* file size parsed */
+  char *buf;			/* temporary buffer */
+} BEZERKLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((BEZERKLOCAL *) stream->local)
+
+/* Function prototypes */
+
+DRIVER *bezerk_valid (char *name);
+long bezerk_isvalid (char *name,char *tmp);
+int bezerk_valid_line (char *s,char **rx,int *rzn);
+void *bezerk_parameters (long function,void *value);
+void bezerk_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void bezerk_list (MAILSTREAM *stream,char *ref,char *pat);
+void bezerk_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long bezerk_create (MAILSTREAM *stream,char *mailbox);
+long bezerk_delete (MAILSTREAM *stream,char *mailbox);
+long bezerk_rename (MAILSTREAM *stream,char *old,char *newname);
+MAILSTREAM *bezerk_open (MAILSTREAM *stream);
+void bezerk_close (MAILSTREAM *stream,long options);
+char *bezerk_header (MAILSTREAM *stream,unsigned long msgno,
+		     unsigned long *length,long flags);
+long bezerk_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,
+		  long flags);
+long bezerk_ping (MAILSTREAM *stream);
+void bezerk_check (MAILSTREAM *stream);
+long bezerk_expunge (MAILSTREAM *stream,char *sequence,long options);
+long bezerk_copy (MAILSTREAM *stream,char *sequence,char *mailbox,
+		  long options);
+long bezerk_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+int bezerk_append_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
+		     STRING *msg);
+void bezerk_gc (MAILSTREAM *stream,long gcflags);
+char *bezerk_file (char *dst,char *name);
+long bezerk_badname (char *tmp,char *s);
+long bezerk_parse (MAILSTREAM *stream);
+unsigned long bezerk_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			     unsigned long *size);
+
+/* Berkeley mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER bezerkdriver = {
+  "bezerk",			/* driver name */
+				/* driver flags */
+  DR_LOCAL|DR_MAIL|DR_LOWMEM|DR_CRLF|DR_NOSTICKY,
+  (DRIVER *) NIL,		/* next driver */
+  bezerk_valid,			/* mailbox is valid for us */
+  bezerk_parameters,		/* manipulate parameters */
+  bezerk_scan,			/* scan mailboxes */
+  bezerk_list,			/* list mailboxes */
+  bezerk_lsub,			/* list subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  bezerk_create,		/* create mailbox */
+  bezerk_delete,		/* delete mailbox */
+  bezerk_rename,		/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  bezerk_open,			/* open mailbox */
+  bezerk_close,			/* close mailbox */
+  NIL,				/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  bezerk_header,		/* fetch message header */
+  bezerk_text,			/* fetch message text */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  NIL,				/* modify flags */
+  NIL,				/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  bezerk_ping,			/* ping mailbox to see if still alive */
+  bezerk_check,			/* check for new messages */
+  bezerk_expunge,		/* expunge deleted messages */
+  bezerk_copy,			/* copy messages to another mailbox */
+  bezerk_append,		/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM bezerkproto = {&bezerkdriver};
+
+/* Berkeley mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *bezerk_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+  return bezerk_isvalid (name,tmp) ? &bezerkdriver : (DRIVER *) NIL;
+}
+
+
+/* Berkeley mail test for valid mailbox
+ * Accepts: mailbox name
+ * Returns: T if valid, NIL otherwise
+ */
+
+long bezerk_isvalid (char *name,char *tmp)
+{
+  int fd;
+  long ret = NIL;
+  struct stat sbuf;
+  errno = EINVAL;		/* assume invalid argument */
+				/* if file, get its status */
+  if ((*name != '{') && mailboxfile (tmp,name) && !stat (tmp,&sbuf)) {
+    if (!sbuf.st_size)errno = 0;/* empty file */
+    else if ((fd = open (tmp,O_BINARY|O_RDONLY,NIL)) >= 0) {
+      memset (tmp,'\0',MAILTMPLEN);
+      errno = -1;		/* in case bezerk_valid_line fails */
+      if (read (fd,tmp,MAILTMPLEN-1) >= 0)
+	ret = bezerk_valid_line (tmp,NIL,NIL);
+      close (fd);		/* close the file */
+    }
+  }
+				/* in case INBOX but not bezerk format */
+  else if ((errno == ENOENT) && ((name[0] == 'I') || (name[0] == 'i')) &&
+	   ((name[1] == 'N') || (name[1] == 'n')) &&
+	   ((name[2] == 'B') || (name[2] == 'b')) &&
+	   ((name[3] == 'O') || (name[3] == 'o')) &&
+	   ((name[4] == 'X') || (name[4] == 'x')) && !name[5]) errno = -1;
+  return ret;			/* return what we should */
+}
+
+/* Validate line
+ * Accepts: pointer to candidate string to validate as a From header
+ *	    return pointer to end of date/time field
+ *	    return pointer to offset from t of time (hours of ``mmm dd hh:mm'')
+ *	    return pointer to offset from t of time zone (if non-zero)
+ * Returns: t,ti,zn set if valid From string, else ti is NIL
+ */
+
+int bezerk_valid_line (char *s,char **rx,int *rzn)
+{
+  char *x;
+  int zn;
+  int ti = 0;
+				/* line must begin with "From " */
+  if ((*s != 'F') || (s[1] != 'r') || (s[2] != 'o') || (s[3] != 'm') ||
+	(s[4] != ' ')) return NIL;
+				/* find end of line */
+  for (x = s + 5; *x && *x != '\012'; x++);
+  if (!x) return NIL;		/* end of line not found */
+  if (x[-1] == '\015') x--;	/* ignore CR */
+  if ((x - s < 27)) return NIL;	/* line too short */
+  if (x - s >= 41) {		/* possible search for " remote from " */
+    for (zn = -1; x[zn] != ' '; zn--);
+    if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') &&
+	(x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') &&
+	(x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') &&
+	(x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))
+      x += zn - 12;
+  }
+  if (x[-5] == ' ') {		/* ends with year? */
+				/* no timezone? */
+    if (x[-8] == ':') zn = 0,ti = -5;
+				/* three letter timezone? */
+    else if (x[-9] == ' ') ti = zn = -9;
+				/* numeric timezone? */
+    else if ((x[-11]==' ') && ((x[-10]=='+') || (x[-10]=='-'))) ti = zn = -11;
+  }
+  else if (x[-4] == ' ') {	/* no year and three leter timezone? */
+    if (x[-9] == ' ') zn = -4,ti = -9;
+  }
+  else if (x[-6] == ' ') {	/* no year and numeric timezone? */
+    if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-')))
+      zn = -6,ti = -11;
+  }
+				/* time must be www mmm dd hh:mm[:ss] */
+  if (ti && !((x[ti - 3] == ':') &&
+	      (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') &&
+	      (x[ti - 3] == ' ') && (x[ti - 7] == ' ') &&
+	      (x[ti - 11] == ' '))) return NIL;
+  if (rx) *rx = x;		/* set return values */
+  if (rzn) *rzn = zn;
+  return ti;
+}
+
+/* Berkeley manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *bezerk_parameters (long function,void *value)
+{
+  return NIL;
+}
+
+
+/* Berkeley mail scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void bezerk_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* Berkeley mail list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void bezerk_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_list (stream,ref,pat);
+}
+
+
+/* Berkeley mail list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void bezerk_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_lsub (stream,ref,pat);
+}
+
+/* Berkeley mail create mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long bezerk_create (MAILSTREAM *stream,char *mailbox)
+{
+  return dummy_create (stream,mailbox);
+}
+
+
+/* Berkeley mail delete mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long bezerk_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return dummy_delete (stream,mailbox);
+}
+
+
+/* Berkeley mail rename mailbox
+ * Accepts: MAIL stream
+ *	    old mailbox name
+ *	    new mailbox name (or NIL for delete)
+ * Returns: T on success, NIL on failure
+ */
+
+long bezerk_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  return dummy_rename (stream,old,newname);
+}
+
+/* Berkeley mail open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *bezerk_open (MAILSTREAM *stream)
+{
+  long i;
+  int fd;
+  char *s;
+  char tmp[MAILTMPLEN];
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return &bezerkproto;
+  if (stream->local) fatal ("bezerk recycle stream");
+  if (!mailboxfile (tmp,stream->mailbox))
+    return (MAILSTREAM *) bezerk_badname (tmp,stream->mailbox);
+  if (((fd = open (tmp,O_BINARY|O_RDONLY,NIL)) < 0)) {
+    sprintf (tmp,"Can't open mailbox: %s",strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+  stream->rdonly = T;		/* this driver is readonly */
+  stream->local = fs_get (sizeof (BEZERKLOCAL));
+				/* canonicalize the stream mailbox name */
+  fs_give ((void **) &stream->mailbox);
+  if (s = strchr ((s = strrchr (tmp,'\\')) ? s : tmp,'.')) *s = '\0';
+  stream->mailbox = cpystr (tmp);
+  LOCAL->fd = fd;		/* note the file */
+  LOCAL->filesize = 0;		/* initialize parsed file size */
+  LOCAL->buf = NIL;		/* initially no local buffer */
+  stream->sequence++;		/* bump sequence number */
+  stream->uid_validity = time (0);
+				/* parse mailbox */
+  stream->nmsgs = stream->recent = 0;
+  if (!bezerk_ping (stream)) return NIL;
+  if (!stream->nmsgs) mm_log ("Mailbox is empty",(long) NIL);
+  stream->perm_seen = stream->perm_deleted =
+    stream->perm_flagged = stream->perm_answered = stream->perm_draft = NIL;
+  stream->perm_user_flags = NIL;
+  return stream;		/* return stream to caller */
+}
+
+/* Berkeley mail close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void bezerk_close (MAILSTREAM *stream,long options)
+{
+  if (stream && LOCAL) {	/* only if a file is open */
+    int silent = stream->silent;
+    stream->silent = T;
+    if (options & CL_EXPUNGE) bezerk_expunge (stream,NIL,NIL);
+    close (LOCAL->fd);		/* close the local file */
+    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+/* Berkeley mail fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+char *bezerk_header (MAILSTREAM *stream,unsigned long msgno,
+		     unsigned long *length,long flags)
+{
+  char tmp[MAILTMPLEN];
+  *length = 0;			/* default to empty */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+				/* get to header position */
+  lseek (LOCAL->fd,bezerk_hdrpos (stream,msgno,length),L_SET);
+				/* is buffer big enough? */
+  if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+  LOCAL->buf = (char *) fs_get ((size_t) *length + 1);
+  LOCAL->buf[*length] = '\0';	/* tie off string */
+				/* slurp the data */
+  read (LOCAL->fd,LOCAL->buf,(size_t) *length);
+  return LOCAL->buf;
+}
+
+
+/* Berkeley mail fetch message text (body only)
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: T, always
+ */
+
+long bezerk_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  MESSAGECACHE *elt;
+  FDDATA d;
+  unsigned long hdrsize,hdrpos;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+  elt = mail_elt (stream,msgno);/* if message not seen */
+				/* mark message as seen */
+  if (elt->seen && !(flags & FT_PEEK)) {
+    elt->seen = T;
+    mm_flags (stream,msgno);
+  }
+				/* get location of text data */
+  hdrpos = bezerk_hdrpos (stream,msgno,&hdrsize);
+  d.fd = LOCAL->fd;		/* set initial stringstruct */
+  d.pos = hdrpos + hdrsize;
+				/* flush old buffer */
+  if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+  d.chunk = LOCAL->buf = (char *) fs_get ((size_t) d.chunksize = CHUNKSIZE);
+  INIT (bs,fd_string,(void *) &d,elt->rfc822_size - hdrsize);
+  return T;			/* success */
+}
+
+/* Berkeley mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream still alive, NIL if not
+ */
+
+long bezerk_ping (MAILSTREAM *stream)
+{
+				/* punt if stream no longer alive */
+  if (!(stream && LOCAL)) return NIL;
+				/* parse mailbox, punt if parse dies */
+  return (bezerk_parse (stream)) ? T : NIL;
+}
+
+
+/* Berkeley mail check mailbox (reparses status too)
+ * Accepts: MAIL stream
+ */
+
+void bezerk_check (MAILSTREAM *stream)
+{
+  unsigned long i = 1;
+  if (bezerk_ping (stream)) {	/* ping mailbox */
+				/* get new message status */
+    while (i <= stream->nmsgs) mail_elt (stream,i++);
+    mm_log ("Check completed",(long) NIL);
+  }
+}
+
+/* Berkeley mail expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long bezerk_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  if (!stream->silent) mm_log ("Expunge ignored on readonly mailbox",WARN);
+  return LONGT;
+}
+
+/* Berkeley mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if success, NIL if failed
+ */
+
+long bezerk_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  char tmp[MAILTMPLEN];
+  struct stat sbuf;
+  MESSAGECACHE *elt;
+  unsigned long i,j,k;
+  int fd;
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+	mail_sequence (stream,sequence))) return NIL;
+				/* make sure valid mailbox */
+  if (!bezerk_isvalid (mailbox,tmp) && errno) {
+    if (errno == ENOENT)
+      mm_notify (stream,"[TRYCREATE] Must create mailbox before append",
+		 (long) NIL);
+    else if (pc) return (*pc) (stream,sequence,mailbox,options);
+    else if (mailboxfile (tmp,mailbox)) {
+      sprintf (tmp,"Not a Bezerk-format mailbox: %s",mailbox);
+      mm_log (tmp,ERROR);
+    }
+    else bezerk_badname (tmp,mailbox);
+    return NIL;
+  }
+				/* open the destination */
+  if (!mailboxfile (tmp,mailbox) ||
+      (fd = open (tmp,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,
+		  S_IREAD|S_IWRITE)) < 0) {
+    sprintf (tmp,"Unable to open copy mailbox: %s",strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+
+  mm_critical (stream);		/* go critical */
+  fstat (fd,&sbuf);		/* get current file size */
+				/* for each requested message */
+  for (i = 1; i <= stream->nmsgs; i++)
+    if ((elt = mail_elt (stream,i))->sequence) {
+      lseek (LOCAL->fd,elt->private.special.offset,SEEK_SET);
+				/* number of bytes to copy */
+      j = elt->private.msg.full.offset + elt->rfc822_size;
+      do {			/* read from source position */
+	k = min (j,(unsigned long) MAILTMPLEN);
+	read (LOCAL->fd,tmp,(unsigned int) k);
+	if (write (fd,tmp,(unsigned int) k) < 0) {
+	  sprintf (tmp,"Unable to write message: %s",strerror (errno));
+	  mm_log (tmp,ERROR);
+	  chsize (fd,sbuf.st_size);
+	  close (fd);		/* punt */
+	  mm_nocritical (stream);
+	  return NIL;
+	}
+      } while (j -= k);		/* until done */
+    }
+  close (fd);			/* close the file */
+  mm_nocritical (stream);	/* release critical */
+				/* delete all requested messages */
+  if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++)
+    if ((elt = mail_elt (stream,i))->sequence) elt->deleted = T;
+  if (mail_parameters (NIL,GET_COPYUID,NIL))
+    mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN);
+  return T;
+}
+
+/* Berkeley mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+#define BUFLEN MAILTMPLEN
+
+long bezerk_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct stat sbuf;
+  int fd;
+  unsigned long i,j;
+  char *flags,*date,buf[BUFLEN],tmp[MAILTMPLEN],file[MAILTMPLEN];
+  FILE *sf,*df;
+  MESSAGECACHE elt;
+  STRING *message;
+  long ret = LONGT;
+				/* default stream to prototype */
+  if (!stream) stream = &bezerkproto;
+				/* make sure valid mailbox */
+  if (!bezerk_isvalid (mailbox,tmp) && errno) {
+    if (errno == ENOENT) {
+      if (((mailbox[0] == 'I') || (mailbox[0] == 'i')) &&
+	  ((mailbox[1] == 'N') || (mailbox[1] == 'n')) &&
+	  ((mailbox[2] == 'B') || (mailbox[2] == 'b')) &&
+	  ((mailbox[3] == 'O') || (mailbox[3] == 'o')) &&
+	  ((mailbox[4] == 'X') || (mailbox[4] == 'x')) && !mailbox[5])
+	bezerk_create (NIL,"INBOX");
+      else {
+	mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+	return NIL;
+      }
+    }
+    else if (mailboxfile (tmp,mailbox)) {
+      sprintf (tmp,"Not a Bezerk-format mailbox: %.80ss",mailbox);
+      mm_log (tmp,ERROR);
+    }
+    else bezerk_badname (tmp,mailbox);
+    return NIL;
+  }
+  tzset ();			/* initialize timezone stuff */
+				/* get first message */
+  if (!(*af) (stream,data,&flags,&date,&message)) return NIL;
+  if (!(sf = tmpfile ())) {	/* must have scratch file */
+    sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno));
+    mm_log (tmp,ERROR);
+  }
+
+  do {				/* parse date */
+    if (!date) rfc822_date (date = tmp);
+    if (!mail_parse_date (&elt,date)) {
+      sprintf (tmp,"Bad date in append: %.80s",date);
+      mm_log (tmp,ERROR);
+    }
+    else {			/* user wants to suppress time zones? */
+      if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) {
+	time_t when = mail_longdate (&elt);
+	date = ctime (&when);	/* use traditional date */
+      }
+				/* use POSIX-style date */
+      else date = mail_cdate (tmp,&elt);
+      if (!SIZE (message)) mm_log ("Append of zero-length message",ERROR);
+      else if (!bezerk_append_msg (stream,sf,flags,date,message)) {
+	sprintf (tmp,"Error writing scratch file: %.80s",strerror (errno));
+	mm_log (tmp,ERROR);
+      }
+				/* get next message */
+      else if ((*af) (stream,data,&flags,&date,&message)) continue;
+    }
+    fclose (sf);		/* punt scratch file */
+    return NIL;			/* give up */
+  } while (message);		/* until no more messages */
+  if (fflush (sf) || fstat (fileno (sf),&sbuf)) {
+    sprintf (tmp,"Error finishing scratch file: %.80s",strerror (errno));
+    mm_log (tmp,ERROR);
+    fclose (sf);		/* punt scratch file */
+    return NIL;			/* give up */
+  }
+  i = sbuf.st_size;		/* size of scratch file */
+
+  mm_critical (stream);		/* go critical */
+				/* open the destination */
+  if (!mailboxfile (tmp,mailbox) || 
+      ((fd = open (tmp,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,
+		   S_IREAD|S_IWRITE)) < 0) ||
+      !(df = fdopen (fd,"ab"))) {
+    mm_nocritical (stream);	/* done with critical */
+    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+  fstat (fd,&sbuf);		/* get current file size */
+  while (i)			/* until written all bytes */
+    if ((j = fread (buf,1,min ((long) BUFLEN,i),sf)) &&
+	(fwrite (buf,1,j,df) == j)) i -= j;
+  fclose (sf);			/* done with scratch file */
+				/* make sure append wins */
+  if (i || (fflush (df) == EOF)) {
+    chsize (fd,sbuf.st_size);	/* revert file */
+    close (fd);			/* make sure fclose() doesn't corrupt us */
+    sprintf (buf,"Message append failed: %s",strerror (errno));
+    mm_log (buf,ERROR);
+    ret = NIL;			/* return error */
+  }
+  fclose (df);
+  mm_nocritical (stream);	/* release critical */
+  if (ret && mail_parameters (NIL,GET_APPENDUID,NIL))
+    mm_log ("Can not return meaningful APPENDUID with this mailbox format",
+	    WARN);
+  return ret;
+}
+
+/* Write single message to append scratch file
+ * Accepts: MAIL stream
+ *	    scratch file
+ *	    flags
+ *	    message stringstruct
+ * Returns: NIL if write error, else T
+ */
+
+int bezerk_append_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
+		     STRING *msg)
+{
+  int c;
+  unsigned long i,uf;
+  char tmp[MAILTMPLEN];
+  long f = mail_parse_flags (stream,flags,&uf);
+				/* build initial header */
+  if ((fprintf (sf,"From %s@%s %sStatus: ",
+		myusername (),mylocalhost (),date) < 0) ||
+      (f&fSEEN && (putc ('R',sf) == EOF)) ||
+      (fputs ("\nX-Status: ",sf) == EOF) ||
+      (f&fDELETED && (putc ('D',sf) == EOF)) ||
+      (f&fFLAGGED && (putc ('F',sf) == EOF)) ||
+      (f&fANSWERED && (putc ('A',sf) == EOF)) ||
+      (f&fDRAFT && (putc ('T',sf) == EOF)) ||
+      (fputs ("\nX-Keywords:",sf) == EOF)) return NIL;
+  while (uf)			/* write user flags */
+    if (fprintf (sf," %s",stream->user_flags[find_rightmost_bit (&uf)]) < 0)
+      return NIL;
+				/* tie off flags */
+  if (putc ('\n',sf) == EOF) return NIL;
+  while (SIZE (msg)) {		/* copy text to scratch file */
+				/* possible delimiter if line starts with F */
+    if ((c = 0xff & SNX (msg)) == 'F') {
+				/* copy line to buffer */
+      for (i = 1,tmp[0] = c; SIZE (msg) && (c != '\n') && (i < MAILTMPLEN);)
+	if (((c = 0xff & SNX (msg)) != '\r') || !(SIZE (msg)) ||
+	    (CHR (msg) != '\n')) tmp[i++] = c;
+      if ((i > 4) && (tmp[1] == 'r') && (tmp[2] == 'o') && (tmp[3] == 'm') &&
+	  (tmp[4] == ' ')) {	/* possible "From " line? */
+				/* yes, see if need to write a widget */
+	if (((c != '\n') || bezerk_valid_line (tmp,NIL,NIL)) &&
+	    (putc ('>',sf) == EOF)) return NIL;
+      }
+				/* write buffered text */
+      if (fwrite (tmp,1,i,sf) != i) return NIL;
+      if (c == '\n') continue;	/* all done if got a complete line */
+    }
+				/* copy line, toss out CR from CRLF */
+    do if (((c == '\r') && SIZE (msg) && ((c = 0xff & SNX (msg)) != '\n') &&
+	    (putc ('\r',sf) == EOF)) || (putc (c,sf) == EOF)) return NIL;
+    while ((c != '\n') && SIZE (msg) && ((c = 0xff & SNX (msg)) ? c : T));
+  }
+				/* write trailing newline and return */
+  return (putc ('\n',sf) == EOF) ? NIL : T;
+}
+
+
+/* Return bad file name error message
+ * Accepts: temporary buffer
+ *	    file name
+ * Returns: long NIL always
+ */
+
+long bezerk_badname (char *tmp,char *s)
+{
+  sprintf (tmp,"Invalid mailbox name: %s",s);
+  mm_log (tmp,ERROR);
+  return (long) NIL;
+}
+
+/* Parse mailbox
+ * Accepts: MAIL stream
+ * Returns: T if parse OK
+ *	    NIL if failure, stream aborted
+ */
+
+long bezerk_parse (MAILSTREAM *stream)
+{
+  struct stat sbuf;
+  MESSAGECACHE *elt;
+  char *s,*t,tmp[MAILTMPLEN + 1],*db,datemsg[100];
+  long i;
+  int j,ti,zn;
+  long curpos = LOCAL->filesize;
+  long nmsgs = stream->nmsgs;
+  long recent = stream->recent;
+  short silent = stream->silent;
+  fstat (LOCAL->fd,&sbuf);	/* get status */
+  if (sbuf.st_size < curpos) {	/* sanity check */
+    sprintf (tmp,"Mailbox shrank from %ld to %ld!",curpos,sbuf.st_size);
+    mm_log (tmp,ERROR);
+    bezerk_close (stream,NIL);
+    return NIL;
+  }
+  stream->silent = T;		/* don't pass up mm_exists() events yet */
+  db = datemsg + strlen (strcpy (datemsg,"Unparsable date: "));
+				/* while there is data to read */
+  while (i = sbuf.st_size - curpos){
+				/* get to that position in the file */
+    lseek (LOCAL->fd,curpos,SEEK_SET);
+				/* read first buffer's worth */
+    read (LOCAL->fd,tmp,j = (int) min (i,(long) MAILTMPLEN));
+    tmp[j] = '\0';		/* tie off buffer */
+    if (!(ti = bezerk_valid_line (tmp,&t,&zn))) {
+      mm_log ("Mailbox format invalidated (consult an expert), aborted",ERROR);
+      bezerk_close (stream,NIL);
+      return NIL;
+    }
+
+				/* swell the cache */
+    mail_exists (stream,++nmsgs);
+				/* instantiate an elt for this message */
+    (elt = mail_elt (stream,nmsgs))->valid = T;
+    elt->private.uid = ++stream->uid_last;
+				/* note file offset of header */
+    elt->private.special.offset = curpos;
+				/* note offset of message */
+    elt->private.msg.full.offset =
+      (s = ((*t == '\015') ? (t + 2) : (t + 1))) - tmp;
+				/* generate plausable IMAPish date string */
+    db[2] = db[6] = db[20] = '-'; db[11] = ' '; db[14] = db[17] = ':';
+				/* dd */
+    db[0] = t[ti - 2]; db[1] = t[ti - 1];
+				/* mmm */
+    db[3] = t[ti - 6]; db[4] = t[ti - 5]; db[5] = t[ti - 4];
+				/* hh */
+    db[12] = t[ti + 1]; db[13] = t[ti + 2];
+				/* mm */
+    db[15] = t[ti + 4]; db[16] = t[ti + 5];
+    if (t[ti += 6] == ':') {	/* ss if present */
+      db[18] = t[++ti]; db[19] = t[++ti];
+      ti++;			/* move to space */
+    }
+    else db[18] = db[19] = '0';	/* assume 0 seconds */
+				/* yy -- advance over timezone if necessary */
+    if (++zn == ++ti) ti += (((t[zn] == '+') || (t[zn] == '-')) ? 6 : 4);
+    db[7] = t[ti]; db[8] = t[ti + 1]; db[9] = t[ti + 2]; db[10] = t[ti + 3];
+    t = zn ? (t + zn) : "LCL";	/* zzz */
+    db[21] = *t++; db[22] = *t++; db[23] = *t++;
+    if ((db[21] != '+') && (db[21] != '-')) db[24] = '\0';
+    else {			/* numeric time zone */
+      db[20] = ' '; db[24] = *t++; db[25] = *t++; db[26] = '\0';
+    }
+				/* set internal date */
+    if (!mail_parse_date (elt,db)) mm_log (datemsg,WARN);
+
+    curpos += s - tmp;		/* advance position after header */
+    t = strchr (s,'\012');	/* start of next line */
+				/* find start of next message */
+    while (!(bezerk_valid_line (s,NIL,NIL))) {
+      if (t) {			/* have next line? */
+	t++;			/* advance to new line */
+	curpos += t - s;	/* update position and size */
+	elt->rfc822_size += ((t - s) + ((t[-2] == '\015') ? 0 : 1));
+	s = t;			/* move to next line */
+	t = strchr (s,'\012');
+      }
+      else {			/* try next buffer */
+	j = strlen (s);		/* length of unread data in buffer */
+	if ((i = sbuf.st_size - curpos) && (i != j)) {
+				/* get to that position in the file */
+	  lseek (LOCAL->fd,curpos,SEEK_SET);
+				/* read another buffer's worth */
+	  read (LOCAL->fd,s = tmp,j = (int) min (i,(long) MAILTMPLEN));
+	  tmp[j] = '\0';	/* tie off buffer */
+	  if (!(t = strchr (s,'\012'))) fatal ("Line too long in mailbox");
+	}
+	else {
+	  curpos += j;		/* last bit of data */
+	  elt->rfc822_size += j;
+	  break;
+	}
+      }
+    }
+  }
+				/* update parsed file size */
+  LOCAL->filesize = sbuf.st_size;
+  stream->silent = silent;	/* can pass up events now */
+  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
+  mail_recent (stream,recent);	/* and of change in recent messages */
+  return T;			/* return the winnage */
+}
+
+/* Berkeley locate header for a message
+ * Accepts: MAIL stream
+ *	    message number
+ *	    pointer to returned header size
+ * Returns: position of header in file
+ */
+
+unsigned long bezerk_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			     unsigned long *size)
+{
+  long siz;
+  size_t i = 0;
+  char c = '\0';
+  char *s;
+  char tmp[MAILTMPLEN];
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  long pos = elt->private.special.offset + elt->private.msg.full.offset;
+				/* is size known? */
+  if (!(*size = elt->private.msg.header.text.size)) {
+				/* get to header position */
+    lseek (LOCAL->fd,pos,SEEK_SET);
+				/* search message for CRLF CRLF */
+    for (siz = 1; siz <= elt->rfc822_size; siz++) {
+      if (!i &&			/* buffer empty? */
+	  (read (LOCAL->fd,s = tmp,
+		 i = (size_t) min(elt->rfc822_size-siz,(long)MAILTMPLEN))<= 0))
+	return pos;
+      else i--;
+				/* two newline sequence? */
+      if ((c == '\012') && (*s == '\012')) {
+				/* yes, note for later */
+	elt->private.msg.header.text.size = (*size = siz);
+	return pos;		/* return to caller */
+      }
+      else if ((c == '\012') && (*s == '\015')) {
+				/* yes, note for later */
+	elt->private.msg.header.text.size = (*size = siz + 1);
+	return pos;		/* return to caller */
+      }
+      else c = *s++;		/* next character */
+    }
+  }
+  return pos;			/* have position */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/drivers.bat	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,33 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM     http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM 
+REM ========================================================================
+
+REM Program:	Driver Linkage Generator for DOS/NT
+REM
+REM Author:	Mark Crispin
+REM		Networks and Distributed Computing
+REM		Computing & Communications
+REM		University of Washington
+REM		Administration Building, AG-44
+REM		Seattle, WA  98195
+REM		Internet: MRC@CAC.Washington.EDU
+REM
+REM Date:	11 October 1989
+REM Last Edited:30 August 2006
+
+REM Erase old driver linkage
+IF EXIST LINKAGE.* DEL LINKAGE.*
+
+REM Now define the new list
+FOR %%D IN (%1 %2 %3 %4 %5 %6 %7 %8 %9) DO CALL DRIVRAUX %%D
+
+EXIT 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/drivraux.bat	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,28 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM     http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM 
+REM ========================================================================
+
+REM Program:	Driver Linkage Generator auxillary for DOS
+REM
+REM Author:	Mark Crispin
+REM		Networks and Distributed Computing
+REM		Computing & Communications
+REM		University of Washington
+REM		Administration Building, AG-44
+REM		Seattle, WA  98195
+REM		Internet: MRC@CAC.Washington.EDU
+REM
+REM Date:	11 October 1989
+REM Last Edited:30 August 2006
+
+ECHO extern DRIVER %1driver; >> LINKAGE.H
+ECHO   mail_link (&%1driver);	/* link in the %1 driver */ >> LINKAGE.C
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/dummy.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,43 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Dummy routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	9 May 1991
+ * Last Edited:	30 August 2006
+ */
+
+/* Exported function prototypes */
+
+void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void dummy_list (MAILSTREAM *stream,char *ref,char *pat);
+void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long scan_contents (DRIVER *dtb,char *name,char *contents,
+		    unsigned long csiz,unsigned long fsiz);
+long dummy_scan_contents (char *name,char *contents,unsigned long csiz,
+			  unsigned long fsiz);
+long dummy_create (MAILSTREAM *stream,char *mailbox);
+long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode);
+long dummy_delete (MAILSTREAM *stream,char *mailbox);
+long dummy_rename (MAILSTREAM *stream,char *old,char *newname);
+char *dummy_file (char *dst,char *name);
+long dummy_canonicalize (char *tmp,char *ref,char *pat);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/dummydos.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,689 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Dummy routines for DOS
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	24 May 1993
+ * Last Edited:	30 August 2006
+ */
+
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include "mail.h"
+#include "osdep.h"
+#include <sys\stat.h>
+#include <dos.h>
+#include "dummy.h"
+#include "misc.h"
+
+/* Function prototypes */
+
+DRIVER *dummy_valid (char *name);
+void *dummy_parameters (long function,void *value);
+void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents,
+		      long level);
+long dummy_listed (MAILSTREAM *stream,char delimiter,char *name,
+		   long attributes,char *contents);
+long dummy_subscribe (MAILSTREAM *stream,char *mailbox);
+MAILSTREAM *dummy_open (MAILSTREAM *stream);
+void dummy_close (MAILSTREAM *stream,long options);
+long dummy_ping (MAILSTREAM *stream);
+void dummy_check (MAILSTREAM *stream);
+long dummy_expunge (MAILSTREAM *stream,char *sequence,long options);
+long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+long dummy_badname (char *tmp,char *s);
+
+/* Dummy routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER dummydriver = {
+  "dummy",			/* driver name */
+  DR_LOCAL|DR_MAIL,		/* driver flags */
+  (DRIVER *) NIL,		/* next driver */
+  dummy_valid,			/* mailbox is valid for us */
+  dummy_parameters,		/* manipulate parameters */
+  dummy_scan,			/* scan mailboxes */
+  dummy_list,			/* list mailboxes */
+  dummy_lsub,			/* list subscribed mailboxes */
+  dummy_subscribe,		/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  dummy_create,			/* create mailbox */
+  dummy_delete,			/* delete mailbox */
+  dummy_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  dummy_open,			/* open mailbox */
+  dummy_close,			/* close mailbox */
+  NIL,				/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message structure */
+  NIL,				/* fetch header */
+  NIL,				/* fetch text */
+  NIL,				/* fetch message data */
+  NIL,				/* unique identifier */
+  NIL,				/* message number from UID */
+  NIL,				/* modify flags */
+  NIL,				/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  dummy_ping,			/* ping mailbox to see if still alive */
+  dummy_check,			/* check for new messages */
+  dummy_expunge,		/* expunge deleted messages */
+  dummy_copy,			/* copy messages to another mailbox */
+  dummy_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+
+				/* prototype stream */
+MAILSTREAM dummyproto = {&dummydriver};
+
+				/* driver parameters */
+static char *file_extension = NIL;
+
+/* Dummy validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *dummy_valid (char *name)
+{
+  char *s,tmp[MAILTMPLEN];
+  struct stat sbuf;
+				/* must be valid local mailbox */
+  return (name && *name && (*name != '{') &&
+	  (s = mailboxfile (tmp,name)) && (!*s || !stat (s,&sbuf))) ?
+	    &dummydriver : NIL;
+}
+
+
+/* Dummy manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *dummy_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case SET_EXTENSION:
+    if (file_extension) fs_give ((void **) &file_extension);
+    if (*(char *) value) file_extension = cpystr ((char *) value);
+  case GET_EXTENSION:
+    ret = (void *) file_extension;
+  }
+  return ret;
+}
+
+/* Dummy scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+#define LISTTMPLEN 128
+
+void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  char *s,test[LISTTMPLEN],file[LISTTMPLEN];
+  long i = 0;
+  if (!pat || !*pat) {		/* empty pattern? */
+    if (dummy_canonicalize (test,ref,"*")) {
+				/* tie off name at root */
+      if (s = strchr (test,'\\')) *++s = '\0';
+      else test[0] = '\0';
+      dummy_listed (stream,'\\',test,LATT_NOINFERIORS,NIL);
+    }
+  }
+				/* get canonical form of name */
+  else if (dummy_canonicalize (test,ref,pat)) {
+				/* found any wildcards? */
+    if (s = strpbrk (test,"%*")) {
+				/* yes, copy name up to that point */
+      strncpy (file,test,(size_t) (i = s - test));
+      file[i] = '\0';		/* tie off */
+    }
+    else strcpy (file,test);	/* use just that name then */
+				/* find directory name */
+    if (s = strrchr (file,'\\')) {
+      *++s = '\0';		/* found, tie off at that point */
+      s = file;
+    }
+				/* silly case */
+    else if (file[0] == '#') s = file;
+				/* do the work */
+    dummy_list_work (stream,s,test,contents,0);
+    if (pmatch ("INBOX",test))	/* always an INBOX */
+      dummy_listed (stream,NIL,"INBOX",LATT_NOINFERIORS,contents);
+  }
+}
+
+/* Dummy list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void dummy_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  dummy_scan (stream,ref,pat,NIL);
+}
+
+
+/* Dummy list subscribed mailboxes
+ * Accepts: mail stream
+ *	    pattern to search
+ */
+
+void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  void *sdb = NIL;
+  char *s,*t,test[MAILTMPLEN];
+  int showuppers = pat[strlen (pat) - 1] == '%';
+				/* get canonical form of name */
+  if (dummy_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) do
+    if (*s != '{') {
+      if (pmatch_full (s,test,'\\')) {
+	if (pmatch (s,"INBOX")) mm_lsub (stream,NIL,s,LATT_NOINFERIORS);
+	else mm_lsub (stream,'\\',s,NIL);
+      }
+      else while (showuppers && (t = strrchr (s,'\\'))) {
+	*t = '\0';		/* tie off the name */
+	if (pmatch_full (s,test,'\\')) mm_lsub (stream,'\\',s,LATT_NOSELECT);
+      }
+    }
+  while (s = sm_read (&sdb));	/* until no more subscriptions */
+}
+
+
+/* Dummy subscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to add to subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_subscribe (MAILSTREAM *stream,char *mailbox)
+{
+  char *s,tmp[MAILTMPLEN];
+  struct stat sbuf;
+				/* must be valid local mailbox */
+  if ((s = mailboxfile (tmp,mailbox)) && *s && !stat (s,&sbuf) &&
+      ((sbuf.st_mode & S_IFMT) == S_IFREG)) return sm_subscribe (mailbox);
+  sprintf (tmp,"Can't subscribe %s: not a mailbox",mailbox);
+  mm_log (tmp,ERROR);
+  return NIL;
+}
+
+/* Dummy list mailboxes worker routine
+ * Accepts: mail stream
+ *	    directory name to search
+ *	    search pattern
+ *	    string to scan
+ *	    search level
+ */
+
+void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents,
+		      long level)
+{
+  struct find_t f;
+  struct stat sbuf;
+  char *s,tmp[LISTTMPLEN],tmpx[LISTTMPLEN];
+  char *base = (dir && (dir[0] == '\\')) ? NIL : myhomedir ();
+				/* build name */
+  if (base) sprintf (tmpx,"%s\\",base);
+  else tmpx[0] = '\0';
+  if (dir) strcat (tmpx,dir);
+				/* punt if bogus name */
+  if (!mailboxfile (tmp,tmpx)) return;
+				/* make directory wildcard */
+  strcat (tmp,(tmp[strlen (tmp) -1] == '\\') ? "*." : "\\*.");
+  strcat (tmp,file_extension ? file_extension : "*");
+				/* do nothing if can't open directory */
+  if (!_dos_findfirst (tmp,_A_NORMAL|_A_SUBDIR,&f)) {
+				/* list it if at top-level */
+    if (!level && dir && pmatch_full (dir,pat,'\\'))
+      dummy_listed (stream,'\\',dir,LATT_NOSELECT,contents);
+				/* scan directory */
+    if (tmpx[strlen (tmpx) - 1] == '\\') do if (*f.name != '.') {
+      if (base) sprintf (tmpx,"%s\\",base);
+      else tmpx[0] = '\0';
+      if (dir) sprintf (tmpx + strlen (tmpx),"%s%s",dir,f.name);
+      else strcat (tmpx,f.name);
+      if (mailboxfile (tmp,tmpx) && !stat (tmp,&sbuf)) {
+				/* suppress extension */
+	if (file_extension && (s = strchr (f.name,'.'))) *s = '\0';
+				/* now make name we'd return */
+	if (dir) sprintf (tmp,"%s%s",dir,f.name);
+	else strcpy (tmp,f.name);
+				/* only interested in file type */
+	switch (sbuf.st_mode & S_IFMT) {
+	case S_IFDIR:		/* directory? */
+	  if (pmatch_full (tmp,pat,'\\')) {
+	    dummy_listed (stream,'\\',tmp,LATT_NOSELECT,contents);
+	    strcat (tmp,"\\");	/* set up for dmatch call */
+	  }
+				/* try again with trailing / */
+	  else if (pmatch_full (strcat (tmp,"\\"),pat,'\\'))
+	    dummy_listed (stream,'\\',tmp,LATT_NOSELECT,contents);
+	  if (dmatch (tmp,pat,'\\') &&
+	      (level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL)))
+	    dummy_list_work (stream,tmp,pat,contents,level+1);
+	  break;
+	case S_IFREG:		/* ordinary name */
+	  if (pmatch_full (tmp,pat,'\\') && !pmatch ("INBOX",tmp))
+	    dummy_listed (stream,'\\',tmp,LATT_NOINFERIORS,contents);
+	  break;
+	}
+      }
+    }
+    while (!_dos_findnext (&f));
+  }
+}
+
+/* Mailbox found
+ * Accepts: hierarchy delimiter
+ *	    mailbox name
+ *	    attributes
+ *	    contents to search before calling mm_list()
+ * Returns: T, always
+ */
+
+#define BUFSIZE MAILTMPLEN
+
+long dummy_listed (MAILSTREAM *stream,char delimiter,char *name,
+		   long attributes,char *contents)
+{
+  struct stat sbuf;
+  int fd;
+  size_t csiz,ssiz,bsiz;
+  char *buf,tmp[MAILTMPLEN];
+  if (contents) {		/* want to search contents? */
+				/* forget it if can't select or open */
+    if ((attributes & LATT_NOSELECT) || !(csiz = strlen (contents)) ||
+	!mailboxfile (tmp,name) || stat (tmp,&sbuf) || (csiz > sbuf.st_size) ||
+	((fd = open (tmp,O_RDONLY,NIL)) < 0)) return T;
+				/* get buffer including slop */    
+    buf = (char *) fs_get (BUFSIZE + (ssiz = 4 * ((csiz / 4) + 1)) + 1);
+    memset (buf,'\0',ssiz);	/* no slop area the first time */
+    while (sbuf.st_size) {	/* until end of file */
+      read (fd,buf+ssiz,bsiz = min (sbuf.st_size,BUFSIZE));
+      if (search ((unsigned char *) buf,bsiz+ssiz,
+		  (unsigned char *) contents,csiz)) break;
+      memcpy (buf,buf+BUFSIZE,ssiz);
+      sbuf.st_size -= bsiz;	/* note that we read that much */
+    }
+    fs_give ((void **) &buf);	/* flush buffer */
+    close (fd);			/* finished with file */
+    if (!sbuf.st_size) return T;/* not found */
+  }
+				/* notify main program */
+  mm_list (stream,delimiter,name,attributes);
+  return T;
+}
+
+/* Dummy create mailbox
+ * Accepts: mail stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_create (MAILSTREAM *stream,char *mailbox)
+{
+  char tmp[MAILTMPLEN];
+  return (compare_cstring (mailbox,"INBOX") && mailboxfile (tmp,mailbox)) ?
+    dummy_create_path (stream,tmp,NIL) : dummy_badname (tmp,mailbox);
+}
+
+
+/* Dummy create path
+ * Accepts: mail stream
+ *	    path name to create
+ *	    directory mode
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode)
+{
+  struct stat sbuf;
+  char c,*s,tmp[MAILTMPLEN];
+  int fd;
+  long ret = NIL;
+  char *t = strrchr (path,'\\');
+  char *pt = (path[1] == ':') ? path + 2 : path;
+  int wantdir = t && !t[1];
+  if (wantdir) *t = '\0';	/* flush trailing delimiter for directory */
+				/* found superior to this name? */
+  if ((s = strrchr (pt,'\\')) && (s != pt)) {
+    strncpy (tmp,path,(size_t) (s - path));
+    tmp[s - path] = '\0';	/* make directory name for stat */
+    c = *++s;			/* tie off in case need to recurse */
+    *s = '\0';
+				/* name doesn't exist, create it */
+    if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+	!dummy_create_path (stream,path,dirmode)) return NIL;
+    *s = c;			/* restore full name */
+  }
+  if (wantdir) {		/* want to create directory? */
+    ret = !mkdir (path);
+    *t = '\\';			/* restore directory delimiter */
+  }
+				/* create file */
+  else if ((fd = open (path,O_WRONLY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE)) >= 0)
+    ret = !close (fd);		/* close file */
+  if (!ret) {			/* error? */
+    sprintf (tmp,"Can't create mailbox node %s: %s",path,strerror (errno));
+    mm_log (tmp,ERROR);
+  }
+  return ret;			/* return status */
+}
+
+/* Dummy delete mailbox
+ * Accepts: mail stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_delete (MAILSTREAM *stream,char *mailbox)
+{
+  struct stat sbuf;
+  char *s,tmp[MAILTMPLEN];
+  if (!mailboxfile (tmp,mailbox)) return dummy_badname (tmp,mailbox);
+				/* no trailing \ */
+  if ((s = strrchr (tmp,'\\')) && !s[1]) *s = '\0';
+  if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) == S_IFDIR) ?
+      rmdir (tmp) : unlink (tmp)) {
+    sprintf (tmp,"Can't delete mailbox %s: %s",mailbox,strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+  return T;			/* return success */
+}
+
+
+/* Mail rename mailbox
+ * Accepts: mail stream
+ *	    old mailbox name
+ *	    new mailbox name
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  struct stat sbuf;
+  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN];
+				/* make file name */
+  if (!mailboxfile (file,old)) return dummy_badname (tmp,old);
+				/* no trailing \ allowed */
+  if (!(s = mailboxfile (tmp,newname)) || ((s = strrchr (s,'\\')) && !s[1]))
+    return dummy_badname (tmp,newname);
+  if (s) {			/* found superior to destination name? */
+    c = *++s;			/* remember first character of inferior */
+    *s = '\0';			/* tie off to get just superior */
+				/* name doesn't exist, create it */
+    if ((stat (file,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+	!dummy_create (stream,file)) return NIL;
+    *s = c;			/* restore full name */
+  }
+  if (rename (file,tmp)) {
+    sprintf (tmp,"Can't rename mailbox %s to %s: %s",old,newname,
+	     strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+  return LONGT;			/* return success */
+}
+
+/* Dummy open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *dummy_open (MAILSTREAM *stream)
+{
+  char tmp[MAILTMPLEN];
+  struct stat sbuf;
+  int fd = -1;
+				/* OP_PROTOTYPE call or silence */
+  if (!stream || stream->silent) return NIL;
+  if (!mailboxfile (tmp,stream->mailbox))
+    sprintf (tmp,"Can't open this name: %.80s",stream->mailbox);
+  else if (compare_cstring (stream->mailbox,"INBOX") &&
+      ((fd = open (tmp,O_RDONLY,NIL)) < 0))
+    sprintf (tmp,"%s: %s",strerror (errno),stream->mailbox);
+  else {
+    if (fd >= 0) {		/* if got a file */
+      fstat (fd,&sbuf);		/* sniff at its size */
+      close (fd);
+      if (sbuf.st_size) sprintf (tmp,"Not a mailbox: %s",stream->mailbox);
+      else fd = -1;		/* a-OK */
+    }
+    if (fd < 0) {		/* no file, right? */
+      if (!stream->silent) {	/* only if silence not requested */
+				/* say there are 0 messages */
+	mail_exists (stream,(long) 0);
+	mail_recent (stream,(long) 0);
+	stream->uid_validity = time (0);
+      }
+      stream->inbox = T;	/* note that it's an INBOX */
+      return stream;		/* return success */
+    }
+  }
+  mm_log (tmp,stream->silent ? WARN: ERROR);
+  return NIL;			/* always fails */
+}
+
+
+/* Dummy close
+ * Accepts: MAIL stream
+ *	    options
+ */
+
+void dummy_close (MAILSTREAM *stream,long options)
+{
+				/* return silently */
+}
+
+/* Dummy ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ * No-op for readonly files, since read/writer can expunge it from under us!
+ */
+
+long dummy_ping (MAILSTREAM *stream)
+{
+  MAILSTREAM *test;
+				/* time to do another test? */
+  if (time (0) >= ((time_t) (stream->gensym + 30))) {
+				/* has mailbox format changed? */
+    if ((test = mail_open (NIL,stream->mailbox,OP_PROTOTYPE)) &&
+	(test->dtb != stream->dtb) &&
+	(test = mail_open (NIL,stream->mailbox,NIL))) {
+				/* preserve some resources */
+      test->original_mailbox = stream->original_mailbox;
+      stream->original_mailbox = NIL;
+      test->sparep = stream->sparep;
+      stream->sparep = NIL;
+      test->sequence = stream->sequence;
+      mail_close ((MAILSTREAM *) /* flush resources used by dummy stream */
+		  memcpy (fs_get (sizeof (MAILSTREAM)),stream,
+			  sizeof (MAILSTREAM)));
+				/* swap the streams */
+      memcpy (stream,test,sizeof (MAILSTREAM));
+      fs_give ((void **) &test);/* flush test now that copied */
+				/* make sure application knows */
+      mail_exists (stream,stream->recent = stream->nmsgs);
+    }
+				/* still hasn't changed */
+    else stream->gensym = time (0);
+  }
+  return T;
+}
+
+
+/* Dummy check mailbox
+ * Accepts: MAIL stream
+ * No-op for readonly files, since read/writer can expunge it from under us!
+ */
+
+void dummy_check (MAILSTREAM *stream)
+{
+  dummy_ping (stream);		/* invoke ping */
+}
+
+
+/* Dummy expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long dummy_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  return LONGT;
+}
+
+/* Dummy copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    options
+ * Returns: T if copy successful, else NIL
+ */
+
+long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+      mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy");
+  return NIL;
+}
+
+
+/* Dummy append message string
+ * Accepts: mail stream
+ *	    destination mailbox
+ *	    append callback function
+ *	    data for callback
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct stat sbuf;
+  int fd = -1;
+  int e;
+  char tmp[MAILTMPLEN];
+  MAILSTREAM *ts = default_proto (T);
+  if (compare_cstring (mailbox,"INBOX") && mailboxfile (tmp,mailbox) &&
+      ((fd = open (tmp,O_RDONLY,NIL)) < 0)) {
+    if ((e = errno) == ENOENT)	/* failed, was it no such file? */
+      mm_notify (stream,"[TRYCREATE] Must create mailbox before append",
+		 (long) NIL);
+    sprintf (tmp,"%s: %s",strerror (e),mailbox);
+    mm_log (tmp,ERROR);		/* pass up error */
+    return NIL;			/* always fails */
+  }
+  if (fd >= 0) {		/* found file? */
+    fstat (fd,&sbuf);		/* get its size */
+    close (fd);			/* toss out the fd */
+    if (sbuf.st_size) ts = NIL;	/* non-empty file? */
+  }
+  if (ts) return (*ts->dtb->append) (stream,mailbox,af,data);
+  sprintf (tmp,"Indeterminate mailbox format: %s",mailbox);
+  mm_log (tmp,ERROR);
+  return NIL;
+}
+
+/* Return bad file name error message
+ * Accepts: temporary buffer
+ *	    file name
+ * Returns: long NIL always
+ */
+
+long dummy_badname (char *tmp,char *s)
+{
+  sprintf (tmp,"Invalid mailbox name: %s",s);
+  mm_log (tmp,ERROR);
+  return (long) NIL;
+}
+
+
+/* Dummy canonicalize name
+ * Accepts: buffer to write name
+ *	    reference
+ *	    pattern
+ * Returns: T if success, NIL if failure
+ */
+
+long dummy_canonicalize (char *tmp,char *ref,char *pat)
+{
+  unsigned long i;
+  char *s,dev[4];
+				/* initially no device */
+  dev[0] = dev[1] = dev[2] = dev[3] = '\0';
+  if (ref) switch (*ref) {	/* preliminary reference check */
+  case '{':			/* remote names not allowed */
+    return NIL;			/* disallowed */
+  case '\0':			/* empty reference string */
+    break;
+  default:			/* all other names */
+    if (ref[1] == ':') {	/* start with device name? */
+      dev[0] = *ref++; dev[1] = *ref++;
+    }
+    break;
+  }
+  if (pat[1] == ':') {		/* device name in pattern? */
+    dev[0] = *pat++; dev[1] = *pat++;
+    ref = NIL;			/* ignore reference */
+  }
+  switch (*pat) {
+  case '#':			/* namespace names */
+    if (mailboxfile (tmp,pat)) strcpy (tmp,pat);
+    else return NIL;		/* unknown namespace */
+    break;
+  case '{':			/* remote names not allowed */
+    return NIL;
+  case '\\':			/* rooted name */
+    ref = NIL;			/* ignore reference */
+    break;
+  }
+				/* make sure device names are rooted */
+  if (dev[0] && (*(ref ? ref : pat) != '\\')) dev[2] = '\\';
+				/* build name */
+  sprintf (tmp,"%s%s%s",dev,ref ? ref : "",pat);
+  ucase (tmp);			/* force upper case */
+				/* count wildcards */
+  for (i = 0, s = tmp; *s; *s++) if ((*s == '*') || (*s == '%')) ++i;
+  if (i > MAXWILDCARDS) {	/* ridiculous wildcarding? */
+    MM_LOG ("Excessive wildcards in LIST/LSUB",ERROR);
+    return NIL;
+  }
+  return T;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/env_dos.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,300 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	DOS environment routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+static char *myLocalHost = NIL;	/* local host name */
+static char *myClientAddr = NIL;/* client host address */
+static char *myClientHost = NIL;/* client host name */
+static char *myServerAddr = NIL;/* server host address */
+static char *myServerHost = NIL;/* server host name */
+static char *myHomeDir = NIL;	/* home directory name */
+static char *myNewsrc = NIL;	/* newsrc file name */
+static long list_max_level = 5;	/* maximum level of list recursion */
+static short no822tztext = NIL;	/* disable RFC [2]822 timezone text */
+				/* home namespace */
+static NAMESPACE nshome = {"",'\\',NIL,NIL};
+				/* namespace list */
+static NAMESPACE *nslist[3] = {&nshome,NIL,NIL};
+
+#include "write.c"		/* include safe writing routines */
+#include "pmatch.c"		/* include wildcard pattern matcher */
+
+
+/* Dummy definitions to prevent errors */
+
+#define server_login(user,pass,authuser,argc,argv) NIL
+#define authserver_login(user,authuser,argc,argv) NIL
+#define myusername() ""
+#define MD5ENABLE "\\.nosuch.."
+
+
+/* Get all authenticators */
+
+#include "auths.c"
+
+/* Environment manipulate parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *env_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case GET_NAMESPACE:
+    ret = (void *) nslist;
+    break;
+  case SET_HOMEDIR:
+    myHomeDir = cpystr ((char *) value);
+  case GET_HOMEDIR:
+    ret = (void *) myHomeDir;
+    break;
+  case SET_LOCALHOST:
+    myLocalHost = cpystr ((char *) value);
+  case GET_LOCALHOST:
+    ret = (void *) myLocalHost;
+    break;
+  case SET_NEWSRC:
+    if (myNewsrc) fs_give ((void **) &myNewsrc);
+    myNewsrc = cpystr ((char *) value);
+  case GET_NEWSRC:
+    if (!myNewsrc) {		/* set news file name if not defined */
+      char tmp[MAILTMPLEN];
+      sprintf (tmp,"%s\\NEWSRC",myhomedir ());
+      myNewsrc = cpystr (tmp);
+    }
+    ret = (void *) myNewsrc;
+    break;
+  case SET_LISTMAXLEVEL:
+    list_max_level = (long) value;
+  case GET_LISTMAXLEVEL:
+    ret = (void *) list_max_level;
+    break;
+  case SET_DISABLE822TZTEXT:
+    no822tztext = value ? T : NIL;
+  case GET_DISABLE822TZTEXT:
+    ret = (void *) (no822tztext ? VOIDT : NIL);
+    break;
+  }
+  return ret;
+}
+
+/* Write current time
+ * Accepts: destination string
+ *	    optional format of day-of-week prefix
+ *	    format of date and time
+ *	    flag whether to append symbolic timezone
+ */
+
+static void do_date (char *date,char *prefix,char *fmt,int suffix)
+{
+  time_t tn = time (0);
+  struct tm *t = gmtime (&tn);
+  int zone = t->tm_hour * 60 + t->tm_min;
+  int julian = t->tm_yday;
+  t = localtime (&tn);		/* get local time now */
+				/* minus UTC minutes since midnight */
+  zone = t->tm_hour * 60 + t->tm_min - zone;
+  /* julian can be one of:
+   *  36x  local time is December 31, UTC is January 1, offset -24 hours
+   *    1  local time is 1 day ahead of UTC, offset +24 hours
+   *    0  local time is same day as UTC, no offset
+   *   -1  local time is 1 day behind UTC, offset -24 hours
+   * -36x  local time is January 1, UTC is December 31, offset +24 hours
+   */
+  if (julian = t->tm_yday -julian)
+    zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
+  if (prefix) {			/* want day of week? */
+    sprintf (date,prefix,days[t->tm_wday]);
+    date += strlen (date);	/* make next sprintf append */
+  }
+				/* output the date */
+  sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
+	   t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
+  if (suffix) {			/* append timezone suffix if desired */
+    tzset ();			/* get timezone from TZ environment stuff */
+    sprintf (date + strlen (date)," (%.50s)",
+	     tzname[daylight ? (((struct tm *) t)->tm_isdst > 0) : 0]);
+  }
+}
+
+
+/* Write current time in RFC 822 format
+ * Accepts: destination string
+ */
+
+void rfc822_date (char *date)
+{
+  do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d",
+	   no822tztext ? NIL : T);
+}
+
+
+/* Write current time in internal format
+ * Accepts: destination string
+ */
+
+void internal_date (char *date)
+{
+  do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL);
+}
+
+/* Return my home directory name
+ * Returns: my home directory name
+ */
+
+char *myhomedir ()
+{
+  int i;
+  char *s;
+  if (!myHomeDir) {		/* get home directory name if not yet known */
+    i = strlen (myHomeDir = cpystr ((s = getenv ("HOME")) ? s : ""));
+    if (i && ((myHomeDir[i-1] == '\\') || (myHomeDir[i-1]=='/')))
+      myHomeDir[i-1] = '\0';	/* tie off trailing directory delimiter */
+  }
+  return myHomeDir;
+}
+
+
+/* Return mailbox file name
+ * Accepts: destination buffer
+ *	    mailbox name
+ * Returns: file name
+ */
+
+char *mailboxfile (char *dst,char *name)
+{
+  char *s;
+  char *ext = (char *) mail_parameters (NIL,GET_EXTENSION,NIL);
+				/* forbid extraneous extensions */
+  if ((s = strchr ((s = strrchr (name,'\\')) ? s : name,'.')) &&
+      ((ext = (char *) mail_parameters (NIL,GET_EXTENSION,NIL)) ||
+       strchr (s+1,'.'))) return NIL;
+				/* absolute path name? */
+  if ((*name == '\\') || (name[1] == ':')) strcpy (dst,name);
+  else sprintf (dst,"%s\\%s",myhomedir (),name);
+  if (ext) sprintf (dst + strlen (dst),".%s",ext);
+  return ucase (dst);
+}
+
+
+/* Determine default prototype stream to user
+ * Accepts: type (NIL for create, T for append)
+ * Returns: default prototype stream
+ */
+
+MAILSTREAM *default_proto (long type)
+{
+  extern MAILSTREAM DEFAULTPROTO;
+  return &DEFAULTPROTO;		/* return default driver's prototype */
+}
+
+/* Global data */
+
+static unsigned rndm = 0;	/* initial `random' number */
+
+
+/* Return random number
+ */
+
+long random ()
+{
+  if (!rndm) srand (rndm = (unsigned) time (0L));
+  return (long) rand ();
+}
+
+/* Default mailgets routine on DOS
+ * Accepts: readin function pointer
+ *	    stream to use
+ *	    number of bytes
+ *	    identifier data
+ * Returns: string read in, truncated if necessary
+ *
+ * This is a sample mailgets routine.  It simply truncates any data larger
+ * than 63K.  On most systems, you generally don't use a mailgets
+ * routine at all, but on DOS it's required to prevent the application from
+ * crashing.
+ */
+
+static char *dos_gets_buf = NIL;
+
+char *dos_default_gets (readfn_t f,void *stream,unsigned long size,
+			GETS_DATA *md)
+{
+  readprogress_t *rp = mail_parameters (NIL,GET_READPROGRESS,NIL);
+  char *ret,tmp[MAILTMPLEN+1];
+  unsigned long i,j,dsc,rdi = 0;
+  unsigned long dos_max = 63 * 1024;
+  if (!dos_gets_buf)		/* one-time initialization */
+    dos_gets_buf = (char *) fs_get ((size_t) dos_max + 1);
+  ret = (md->flags & MG_COPY) ?
+    ((char *) fs_get ((size_t) size + 1)) : dos_gets_buf;
+  if (size > dos_max) {
+    sprintf (tmp,"Mailbox %s, %s %lu[%.80s], %lu octets truncated to %ld",
+	     md->stream->mailbox,(md->flags & MG_UID) ? "UID" : "#",
+	     md->msgno,md->what,size,(long) dos_max);
+    mm_log (tmp,WARN);		/* warn user */
+    dsc = size - dos_max;	/* number of bytes to discard */
+    size = dos_max;		/* maximum length string we can read */
+  }
+  else dsc = 0;			/* nothing to discard */
+  dos_gets_buf[size] = '\0';	/* tie off string */
+  if (rp) for (i = size; j = min ((long) MAILTMPLEN,(long) i); i -= j) {
+    (*f) (stream,j,ret + rdi);
+    (*rp) (md,rdi += j);
+  }
+  else (*f) (stream,size,dos_gets_buf);
+				/* toss out everything after that */
+  for (i = dsc; j = min ((long) MAILTMPLEN,(long) i); i -= j) {
+    (*f) (stream,j,tmp);
+    if (rp) (*rp) (md,rdi += j);
+  }
+  return ret;
+}
+
+/* Emulator for BSD syslog() routine
+ * Accepts: priority
+ *	    message
+ *	    parameters
+ */
+
+void syslog (int priority,const char *message,...)
+{
+}
+
+
+/* Emulator for BSD openlog() routine
+ * Accepts: identity
+ *	    options
+ *	    facility
+ */
+
+void openlog (const char *ident,int logopt,int facility)
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/env_dos.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,68 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	DOS environment routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+#define SUBSCRIPTIONFILE(t) sprintf (t,"%s/MAILBOX.LST",myhomedir ())
+#define SUBSCRIPTIONTEMP(t) sprintf (t,"%s/MAILBOX.TMP",myhomedir ())
+
+#define L_SET SEEK_SET
+
+/* Function prototypes */
+
+#include "env.h"
+
+char *dos_default_gets (readfn_t f,void *stream,unsigned long size,
+			GETS_DATA *md);
+long safe_write (int fd,char *buf,long nbytes);
+long random ();
+#if _MSC_VER < 700
+#define getpid random
+#endif
+
+
+/* syslog() emulation */
+
+#define LOG_MAIL	(2<<3)	/* mail system */
+#define LOG_DAEMON	(3<<3)	/* system daemons */
+#define LOG_AUTH	(4<<3)	/* security/authorization messages */
+#define LOG_EMERG	0	/* system is unusable */
+#define LOG_ALERT	1	/* action must be taken immediately */
+#define LOG_CRIT	2	/* critical conditions */
+#define LOG_ERR		3	/* error conditions */
+#define LOG_WARNING	4	/* warning conditions */
+#define LOG_NOTICE	5	/* normal but signification condition */
+#define LOG_INFO	6	/* informational */
+#define LOG_DEBUG	7	/* debug-level messages */
+#define LOG_PID		0x01	/* log the pid with each message */
+#define LOG_CONS	0x02	/* log on the console if errors in sending */
+#define LOG_ODELAY	0x04	/* delay open until syslog() is called */
+#define LOG_NDELAY	0x08	/* don't delay open */
+#define LOG_NOWAIT	0x10	/* if forking to log on console, don't wait() */
+
+void openlog (const char *ident,int logopt,int facility);
+void syslog (int priority,const char *message,...);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/fdstring.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,99 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	File descriptor string routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	15 April 1997
+ * Last Edited:	4 April 2007
+ */
+
+#include "mail.h"
+#include "osdep.h"
+#include "misc.h"
+#include "fdstring.h"
+
+/* String driver for fd stringstructs */
+
+static void fd_string_init (STRING *s,void *data,unsigned long size);
+static char fd_string_next (STRING *s);
+static void fd_string_setpos (STRING *s,unsigned long i);
+
+STRINGDRIVER fd_string = {
+  fd_string_init,		/* initialize string structure */
+  fd_string_next,		/* get next byte in string structure */
+  fd_string_setpos		/* set position in string structure */
+};
+
+
+/* Initialize string structure for fd stringstruct
+ * Accepts: string structure
+ *	    pointer to string
+ *	    size of string
+ */
+
+static void fd_string_init (STRING *s,void *data,unsigned long size)
+{
+  FDDATA *d = (FDDATA *) data;
+				/* note fd */
+  s->data = (void *) (unsigned long) d->fd;
+  s->data1 = d->pos;		/* note file offset */
+  s->size = size;		/* note size */
+  s->curpos = s->chunk = d->chunk;
+  s->chunksize = (unsigned long) d->chunksize;
+  s->offset = 0;		/* initial position */
+				/* and size of data */
+  s->cursize = min (s->chunksize,size);
+				/* move to that position in the file */
+  lseek (d->fd,d->pos,L_SET);
+  read (d->fd,s->chunk,(size_t) s->cursize);
+}
+
+/* Get next character from fd stringstruct
+ * Accepts: string structure
+ * Returns: character, string structure chunk refreshed
+ */
+
+static char fd_string_next (STRING *s)
+{
+  char c = *s->curpos++;	/* get next byte */
+  SETPOS (s,GETPOS (s));	/* move to next chunk */
+  return c;			/* return the byte */
+}
+
+
+/* Set string pointer position for fd stringstruct
+ * Accepts: string structure
+ *	    new position
+ */
+
+static void fd_string_setpos (STRING *s,unsigned long i)
+{
+  if (i > s->size) i = s->size;	/* don't permit setting beyond EOF */
+  s->offset = i;		/* set new offset */
+  s->curpos = s->chunk;		/* reset position */
+				/* set size of data */
+  if (s->cursize = min (s->chunksize,SIZE (s))) {
+				/* move to that position in the file */
+    lseek ((long) s->data,s->data1 + s->offset,L_SET);
+    read ((long) s->data,s->curpos,(size_t) s->cursize);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/fdstring.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,39 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	File descriptor string routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	15 April 1997
+ * Last Edited:	30 August 2006
+ */
+
+/* Driver-dependent data passed to init method */
+
+typedef struct fd_data {
+  int fd;			/* file descriptor */
+  unsigned long pos;		/* initial position */
+  char *chunk;			/* I/O buffer chunk */
+  unsigned long chunksize;	/* I/O buffer chunk length */
+} FDDATA;
+
+
+extern STRINGDRIVER fd_string;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/fs_dos.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,62 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Free storage management routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Get a block of free storage
+ * Accepts: size of desired block
+ * Returns: free storage block
+ */
+
+void *fs_get (size_t size)
+{
+  void *block = malloc (size ? size : (size_t) 1);
+  if (!block) fatal ("Out of memory");
+  return (block);
+}
+
+
+/* Resize a block of free storage
+ * Accepts: ** pointer to current block
+ *	    new size
+ */
+
+void fs_resize (void **block,size_t size)
+{
+  if (!(*block = realloc (*block,size ? size : (size_t) 1)))
+    fatal ("Can't resize memory");
+}
+
+
+/* Return a block of free storage
+ * Accepts: ** pointer to free storage block
+ */
+
+void fs_give (void **block)
+{
+  free (*block);
+  *block = NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/ftl_dos.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,38 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	DOS/VMS/TOPS-20 crash management routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Report a fatal error
+ * Accepts: string to output
+ */
+
+void fatal (char *string)
+{
+  mm_fatal (string);		/* pass up the string */
+  abort ();			/* die horribly */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/makefile	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,98 @@
+# ========================================================================
+# Copyright 1988-2007 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+
+# Program:	Portable C client makefile -- MS-DOS version
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		11 May 1989
+# Last Edited:	23 May 2007
+
+
+OS = wsk
+EXTRAAUTHENTICATORS=
+DEFAULTAUTHENTICATORS= ext md5 pla log
+EXTRADRIVERS = 
+DRIVERS = imap nntp pop3 mtx bezerk
+DEFAULTDRIVER = mtx
+CFLAGS= -AL /DCHUNKSIZE=4096 -nologo $(EXTRACFLAGS)
+CC = cl
+
+all:	mtest.exe
+
+.c.obj:
+	$(CC) -c $(CFLAGS) $*.c
+
+osdep.h: os_$(OS).h
+	copy os_$(OS).h osdep.h
+	drivers $(EXTRADRIVERS) $(DRIVERS) dummy
+	mkauths $(EXTRAAUTHENTICATORS) $(DEFAULTAUTHENTICATORS)
+	ECHO #define DEFAULTPROTO $(DEFAULTDRIVER)proto >> LINKAGE.H
+	ECHO   if (!mail_parameters (NIL,GET_GETS)) >> LINKAGE.C
+	ECHO     mail_parameters (NIL,SET_GETS,(void *) dos_default_gets); >> LINKAGE.C
+	ECHO mail_versioncheck (CCLIENTVERSION); >> LINKAGE.C
+
+mtest.obj: mail.h smtp.h misc.h osdep.h mtest.c
+
+mail.obj: mail.h misc.h osdep.h mail.c
+
+misc.obj: mail.h misc.h misc.c
+
+fdstring.obj: mail.h misc.h osdep.h fdstring.h fdstring.c
+
+flstring.obj: mail.h misc.h osdep.h flstring.h flstring.c
+
+netmsg.obj: mail.h misc.h netmsg.h osdep.h netmsg.c
+
+newsrc.obj: mail.h misc.h newsrc.h osdep.h newsrc.c
+
+rfc822.obj: mail.h rfc822.h misc.h rfc822.c
+
+smanager.obj: mail.h misc.h smanager.c
+
+utf8.obj: mail.h misc.h osdep.h utf8.h
+
+utf8aux.obj: mail.h misc.h osdep.h utf8.h
+
+imap4r1.obj: mail.h imap4r1.h misc.h osdep.h imap4r1.c
+
+nntp.obj: mail.h nntp.h smtp.h rfc822.h misc.h osdep.h nntp.c
+
+pop3.obj: mail.h rfc822.h misc.h osdep.h pop3.c
+
+smtp.obj: mail.h smtp.h rfc822.h misc.h osdep.h smtp.c
+
+os_$(OS).obj: mail.h osdep.h env_dos.h fs.h ftl.h nl.h tcp.h \
+	os_$(OS).c fs_dos.c ftl_dos.c nl_dos.c env_dos.c pmatch.c write.c
+
+mtxdos.obj: mail.h misc.h osdep.h mtxdos.c
+
+bezrkdos.obj: mail.h misc.h osdep.h bezrkdos.c
+
+dummydos.obj: mail.h dummy.h misc.h osdep.h dummydos.c
+
+cclient.lib: mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \
+	newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
+	imap4r1.obj nntp.obj pop3.obj smtp.obj os_$(OS).obj \
+	mtxdos.obj bezrkdos.obj dummydos.obj
+	erase cclient.lib
+	lib cclient +mail+misc+fdstring+flstring+netmsg+newsrc+rfc822+smanager+utf8+utf8aux+imap4r1+nntp+pop3+smtp+os_$(OS)+mtxdos+bezrkdos+dummydos;
+
+mtest.exe: cclient.lib mtest.obj
+	mtest$(OS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/mkautaux.bat	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,29 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM     http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM 
+REM ========================================================================
+
+REM Program:	Authenticator Linkage Generator auxillary for DOS
+REM
+REM Author:	Mark Crispin
+REM		Networks and Distributed Computing
+REM		Computing & Communications
+REM		University of Washington
+REM		Administration Building, AG-44
+REM		Seattle, WA  98195
+REM		Internet: MRC@CAC.Washington.EDU
+REM
+REM Date:	7 December 1995
+REM Last Edited:30 August 2006
+
+ECHO extern AUTHENTICATOR auth_%1; >> LINKAGE.H
+ECHO   auth_link (&auth_%1);		/* link in the %1 authenticator */ >> LINKAGE.C
+ECHO #include "auth_%1.c" >> AUTHS.C
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/mkauths.bat	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,33 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM     http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM 
+REM ========================================================================
+
+REM Program:	Authenticator Linkage Generator for DOS and Windows
+REM
+REM Author:	Mark Crispin
+REM		Networks and Distributed Computing
+REM		Computing & Communications
+REM		University of Washington
+REM		Administration Building, AG-44
+REM		Seattle, WA  98195
+REM		Internet: MRC@CAC.Washington.EDU
+REM
+REM Date:	6 December 1995
+REM Last Edited:30 August 2006
+
+REM Erase old authenticators list
+IF EXIST AUTHS.C DEL AUTHS.C
+
+REM Now define the new list
+FOR %%D IN (%1 %2 %3 %4 %5 %6 %7 %8 %9) DO CALL MKAUTAUX %%D
+
+EXIT 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/mtestdbw.bat	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,27 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM     http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM 
+REM ========================================================================
+
+REM Program:	Portable C client makefile -- MS-DOS B&W link
+REM
+REM Author:	Mark Crispin
+REM		Networks and Distributed Computing
+REM		Computing & Communications
+REM		University of Washington
+REM		Administration Building, AG-44
+REM		Seattle, WA  98195
+REM		Internet: MRC@CAC.Washington.EDU
+REM
+REM Date:	26 June 1994
+REM Last Edited:30 August 2006
+
+link /NOI /stack:32767 mtest.obj,mtest.exe,,cclient.lib llbwtcp.lib llibce.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/mtestdnf.bat	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,27 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM     http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM 
+REM ========================================================================
+
+REM Program:	Portable C client makefile -- MS-DOS PC-NFS link
+REM
+REM Author:	Mark Crispin
+REM		Networks and Distributed Computing
+REM		Computing & Communications
+REM		University of Washington
+REM		Administration Building, AG-44
+REM		Seattle, WA  98195
+REM		Internet: MRC@CAC.Washington.EDU
+REM
+REM Date:	26 June 1994
+REM Last Edited:30 August 2006
+
+link /NOI /stack:32767 mtest.obj,mtest.exe,,cclient.lib ltklib.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/mtestdnv.bat	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,27 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM     http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM 
+REM ========================================================================
+
+REM Program:	Portable C client makefile -- MS-DOS Novell link
+REM
+REM Author:	Mark Crispin
+REM		Networks and Distributed Computing
+REM		Computing & Communications
+REM		University of Washington
+REM		Administration Building, AG-44
+REM		Seattle, WA  98195
+REM		Internet: MRC@CAC.Washington.EDU
+REM
+REM Date:	26 June 1994
+REM Last Edited:30 August 2006
+
+link /NOI /stack:32767 mtest.obj,mtest.exe,,cclient.lib llibsock.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/mtestdpc.bat	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,27 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM     http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM 
+REM ========================================================================
+
+REM Program:	Portable C client makefile -- MS-DOS PC/TCP link
+REM
+REM Author:	Mark Crispin
+REM		Networks and Distributed Computing
+REM		Computing & Communications
+REM		University of Washington
+REM		Administration Building, AG-44
+REM		Seattle, WA  98195
+REM		Internet: MRC@CAC.Washington.EDU
+REM
+REM Date:	26 June 1994
+REM Last Edited:30 August 2006
+
+link /NOI /stack:32767 mtest.obj,mtest.exe,,cclient.lib lsocket.lib lnetlib.lib lpc.lib lconfig.lib llibce.lib;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/mtestdwa.bat	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,27 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM     http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM 
+REM ========================================================================
+
+REM Program:	Portable C client makefile -- MS-DOS Waterloo link
+REM
+REM Author:	Mark Crispin
+REM		Networks and Distributed Computing
+REM		Computing & Communications
+REM		University of Washington
+REM		Administration Building, AG-44
+REM		Seattle, WA  98195
+REM		Internet: MRC@CAC.Washington.EDU
+REM
+REM Date:	26 June 1994
+REM Last Edited:30 August 2006
+
+link /NOI /stack:32767 mtest.obj,mtest.exe,,cclient.lib wattcplg.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/mtestwsk.bat	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,27 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM     http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM 
+REM ========================================================================
+
+REM Program:	Portable C client makefile -- MS-DOS Winsock link
+REM
+REM Author:	Mark Crispin
+REM		Networks and Distributed Computing
+REM		Computing & Communications
+REM		University of Washington
+REM		Administration Building, AG-44
+REM		Seattle, WA  98195
+REM		Internet: MRC@CAC.Washington.EDU
+REM
+REM Date:	26 June 1994
+REM Last Edited:30 August 2006
+
+link /NOD:llibce mtest.obj,mtest.exe,,cclient.lib winsock.lib llibcewq.lib libw.lib, mtest
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/mtxdos.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,875 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	MTX mail routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	24 June 1992
+ * Last Edited:	30 August 2006
+ */
+
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include "mail.h"
+#include "osdep.h"
+#include <time.h>
+#include <sys\stat.h>
+#include <dos.h>
+#include "rfc822.h"
+#include "dummy.h"
+#include "misc.h"
+#include "fdstring.h"
+
+/* MTX I/O stream local data */
+	
+typedef struct mtx_local {
+  int fd;			/* file descriptor for I/O */
+  off_t filesize;		/* file size parsed */
+  unsigned char *buf;		/* temporary buffer */
+} MTXLOCAL;
+
+
+/* Drive-dependent data passed to init method */
+
+typedef struct mtx_data {
+  int fd;			/* file data */
+  unsigned long pos;		/* initial position */
+} MTXDATA;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((MTXLOCAL *) stream->local)
+
+
+/* Function prototypes */
+
+DRIVER *mtx_valid (char *name);
+long mtx_isvalid (char *name,char *tmp);
+void *mtx_parameters (long function,void *value);
+void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void mtx_list (MAILSTREAM *stream,char *ref,char *pat);
+void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long mtx_create (MAILSTREAM *stream,char *mailbox);
+long mtx_delete (MAILSTREAM *stream,char *mailbox);
+long mtx_rename (MAILSTREAM *stream,char *old,char *newname);
+MAILSTREAM *mtx_open (MAILSTREAM *stream);
+void mtx_close (MAILSTREAM *stream,long options);
+char *mtx_header (MAILSTREAM *stream,unsigned long msgno,
+		  unsigned long *length,long flags);
+long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
+long mtx_ping (MAILSTREAM *stream);
+void mtx_check (MAILSTREAM *stream);
+long mtx_expunge (MAILSTREAM *stream,char *sequence,long options);
+long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+char *mtx_file (char *dst,char *name);
+long mtx_badname (char *tmp,char *s);
+long mtx_parse (MAILSTREAM *stream);
+void mtx_update_status (MAILSTREAM *stream,unsigned long msgno);
+unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			  unsigned long *size);
+
+/* MTX mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER mtxdriver = {
+  "mtx",			/* driver name */
+				/* driver flags */
+  DR_LOCAL|DR_MAIL|DR_LOWMEM|DR_CRLF|DR_NOSTICKY,
+  (DRIVER *) NIL,		/* next driver */
+  mtx_valid,			/* mailbox is valid for us */
+  mtx_parameters,		/* manipulate parameters */
+  mtx_scan,			/* scan mailboxes */
+  mtx_list,			/* list mailboxes */
+  mtx_lsub,			/* list subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  mtx_create,			/* create mailbox */
+  mtx_delete,			/* delete mailbox */
+  mtx_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  mtx_open,			/* open mailbox */
+  mtx_close,			/* close mailbox */
+  NIL,				/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  mtx_header,			/* fetch message header */
+  mtx_text,			/* fetch message body */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  NIL,				/* modify flags */
+  mtx_flagmsg,			/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  mtx_ping,			/* ping mailbox to see if still alive */
+  mtx_check,			/* check for new messages */
+  mtx_expunge,			/* expunge deleted messages */
+  mtx_copy,			/* copy messages to another mailbox */
+  mtx_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM mtxproto = {&mtxdriver};
+
+/* MTX mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *mtx_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+  return mtx_isvalid (name,tmp) ? &mtxdriver : (DRIVER *) NIL;
+}
+
+
+/* MTX mail test for valid mailbox
+ * Accepts: mailbox name
+ * Returns: T if valid, NIL otherwise
+ */
+
+long mtx_isvalid (char *name,char *tmp)
+{
+  int fd;
+  long ret = NIL;
+  char *s;
+  struct stat sbuf;
+  errno = EINVAL;		/* assume invalid argument */
+				/* if file, get its status */
+  if ((*name != '{') && mailboxfile (tmp,name) && !stat (tmp,&sbuf)) {
+    if (!sbuf.st_size)errno = 0;/* empty file */
+    else if ((fd = open (tmp,O_BINARY|O_RDONLY,NIL)) >= 0) {
+      memset (tmp,'\0',MAILTMPLEN);
+      if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\015')) &&
+	  (s[1] == '\012')) {	/* valid format? */
+	*s = '\0';		/* tie off header */
+				/* must begin with dd-mmm-yy" */
+	ret = (((tmp[2] == '-' && tmp[6] == '-') ||
+		(tmp[1] == '-' && tmp[5] == '-')) &&
+	       (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL;
+      }
+      else errno = -1;		/* bogus format */
+      close (fd);		/* close the file */
+    }
+  }
+				/* in case INBOX but not mtx format */
+  else if ((errno == ENOENT) && ((name[0] == 'I') || (name[0] == 'i')) &&
+	   ((name[1] == 'N') || (name[1] == 'n')) &&
+	   ((name[2] == 'B') || (name[2] == 'b')) &&
+	   ((name[3] == 'O') || (name[3] == 'o')) &&
+	   ((name[4] == 'X') || (name[4] == 'x')) && !name[5]) errno = -1;
+  return ret;			/* return what we should */
+}
+
+
+/* MTX manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *mtx_parameters (long function,void *value)
+{
+  return NIL;
+}
+
+/* MTX mail scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* MTX mail list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mtx_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_list (stream,ref,pat);
+}
+
+
+/* MTX mail list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_lsub (stream,ref,pat);
+}
+
+/* MTX mail create mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long mtx_create (MAILSTREAM *stream,char *mailbox)
+{
+  return dummy_create (stream,mailbox);
+}
+
+
+/* MTX mail delete mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long mtx_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return dummy_delete (stream,mailbox);
+}
+
+
+/* MTX mail rename mailbox
+ * Accepts: MAIL stream
+ *	    old mailbox name
+ *	    new mailbox name (or NIL for delete)
+ * Returns: T on success, NIL on failure
+ */
+
+long mtx_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  return dummy_rename (stream,old,newname);
+}
+
+/* MTX mail open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *mtx_open (MAILSTREAM *stream)
+{
+  long i;
+  int fd;
+  char *s;
+  char tmp[MAILTMPLEN];
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return &mtxproto;
+  if (stream->local) fatal ("mtx recycle stream");
+  if (!mailboxfile (tmp,stream->mailbox))
+    return (MAILSTREAM *) mtx_badname (tmp,stream->mailbox);
+				/* open, possibly creating INBOX */
+  if (((fd = open (tmp,O_BINARY|(stream->rdonly ? O_RDONLY:O_RDWR),NIL)) < 0)&&
+      (compare_cstring (stream->mailbox,"INBOX") ||
+       ((fd = open (tmp,O_BINARY|O_RDWR|O_CREAT|O_EXCL,S_IREAD|S_IWRITE))<0))){
+    sprintf (tmp,"Can't open mailbox: %s",strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+  stream->local = fs_get (sizeof (MTXLOCAL));
+				/* canonicalize the stream mailbox name */
+  fs_give ((void **) &stream->mailbox);
+  if (s = strchr ((s = strrchr (tmp,'\\')) ? s : tmp,'.')) *s = '\0';
+  stream->mailbox = cpystr (tmp);
+  LOCAL->fd = fd;		/* note the file */
+  LOCAL->filesize = 0;		/* initialize parsed file size */
+  LOCAL->buf = NIL;		/* initially no local buffer */
+  stream->sequence++;		/* bump sequence number */
+  stream->uid_validity = time (0);
+				/* parse mailbox */
+  stream->nmsgs = stream->recent = 0;
+  if (!mtx_ping (stream)) return NIL;
+  if (!stream->nmsgs) mm_log ("Mailbox is empty",(long) NIL);
+  stream->perm_seen = stream->perm_deleted =
+    stream->perm_flagged = stream->perm_answered = stream->perm_draft =
+      stream->rdonly ? NIL : T;
+  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
+  return stream;		/* return stream to caller */
+}
+
+/* MTX mail close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void mtx_close (MAILSTREAM *stream,long options)
+{
+  if (stream && LOCAL) {	/* only if a file is open */
+    int silent = stream->silent;
+    stream->silent = T;
+    if (options & CL_EXPUNGE) mtx_expunge (stream,NIL,NIL);
+    close (LOCAL->fd);		/* close the local file */
+    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+/* MTX mail fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+char *mtx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
+		  long flags)
+{
+  *length = 0;			/* default to empty */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+				/* get to header position */
+  lseek (LOCAL->fd,mtx_hdrpos (stream,msgno,length),L_SET);
+				/* is buffer big enough? */
+  if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+  LOCAL->buf = (char *) fs_get ((size_t) *length + 1);
+  LOCAL->buf[*length] = '\0';	/* tie off string */
+				/* slurp the data */
+  read (LOCAL->fd,LOCAL->buf,(size_t) *length);
+  return LOCAL->buf;
+}
+
+
+/* MTX mail fetch message text (body only)
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: T, always
+ */
+
+long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  MESSAGECACHE *elt;
+  FDDATA d;
+  unsigned long hdrsize,hdrpos;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+  elt = mail_elt (stream,msgno);/* if message not seen */
+  if (elt->seen && !(flags & FT_PEEK)) {
+    elt->seen = T;		/* mark message as seen */
+				/* recalculate status */
+    mtx_update_status (stream,msgno);
+    mm_flags (stream,msgno);
+  }
+				/* get location of text data */
+  hdrpos = mtx_hdrpos (stream,msgno,&hdrsize);
+  d.fd = LOCAL->fd;		/* set initial stringstruct */
+  d.pos = hdrpos + hdrsize;
+				/* flush old buffer */
+  if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+  d.chunk = LOCAL->buf = (char *) fs_get ((size_t) d.chunksize = CHUNKSIZE);
+  INIT (bs,fd_string,(void *) &d,elt->rfc822_size - hdrsize);
+  return T;			/* success */
+}
+
+/* MTX mail per-message modify flags
+ * Accepts: MAIL stream
+ *	    message cache element
+ */
+
+void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+				/* recalculate status */
+  mtx_update_status (stream,elt->msgno);
+}
+
+
+/* MTX mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream still alive, NIL if not
+ */
+
+long mtx_ping (MAILSTREAM *stream)
+{
+				/* punt if stream no longer alive */
+  if (!(stream && LOCAL)) return NIL;
+				/* parse mailbox, punt if parse dies */
+  return (mtx_parse (stream)) ? T : NIL;
+}
+
+
+/* MTX mail check mailbox (reparses status too)
+ * Accepts: MAIL stream
+ */
+
+void mtx_check (MAILSTREAM *stream)
+{
+  unsigned long i = 1;
+  if (mtx_ping (stream)) {	/* ping mailbox */
+				/* get new message status */
+    while (i <= stream->nmsgs) mail_elt (stream,i++);
+    mm_log ("Check completed",(long) NIL);
+  }
+}
+
+/* MTX mail expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long mtx_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  long ret;
+  unsigned long i = 1;
+  unsigned long j,k,m,recent;
+  unsigned long n = 0;
+  unsigned long delta = 0;
+  MESSAGECACHE *elt;
+  char tmp[MAILTMPLEN];
+  if (!(ret = (sequence ? ((options & EX_UID) ?
+			   mail_uid_sequence (stream,sequence) :
+			   mail_sequence (stream,sequence)) : LONGT) &&
+	mtx_ping (stream)));	/* parse sequence if given, ping stream */
+  else if (stream->rdonly) mm_log ("Expunge ignored on readonly mailbox",WARN);
+  else {
+    mm_critical (stream);	/* go critical */
+    recent = stream->recent;	/* get recent now that pinged */ 
+    while (i <= stream->nmsgs) {/* for each message */
+      elt = mail_elt (stream,i);/* get cache element */
+				/* number of bytes to smash or preserve */
+      k = elt->private.special.text.size + elt->rfc822_size;
+				/* if need to expunge this message */
+      if (elt->deleted && (sequence ? elt->sequence : T)) {
+				/* if recent, note one less recent message */
+	if (elt->recent) --recent;
+	delta += k;		/* number of bytes to delete */
+				/* notify upper levels */
+	mail_expunged (stream,i);
+	n++;			/* count up one more deleted message */
+      }
+      else if (i++ && delta) {	/* preserved message */
+				/* first byte to preserve */
+	j = elt->private.special.offset;
+	do {			/* read from source position */
+	  m = min (k,(unsigned long) MAILTMPLEN);
+	  lseek (LOCAL->fd,j,SEEK_SET);
+	  read (LOCAL->fd,tmp,(size_t) m);
+				/* write to destination position */
+	  lseek (LOCAL->fd,j - delta,SEEK_SET);
+	  write (LOCAL->fd,tmp,(size_t) m);
+	  j += m;		/* next chunk, perhaps */
+	} while (k -= m);	/* until done */
+	elt->private.special.offset -= delta;
+      }
+    }
+    if (n) {			/* truncate file after last message */
+      chsize (LOCAL->fd,LOCAL->filesize -= delta);
+      sprintf (tmp,"Expunged %ld messages",n);
+      mm_log (tmp,(long) NIL);	/* output the news */
+    }
+    else mm_log ("No messages deleted, so no update needed",(long) NIL);
+    mm_nocritical (stream);	/* release critical */
+				/* notify upper level of new mailbox size */
+    mail_exists (stream,stream->nmsgs);
+    mail_recent (stream,recent);
+  }
+  return ret;
+}
+
+/* MTX mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if success, NIL if failed
+ */
+
+long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  char tmp[MAILTMPLEN];
+  struct stat sbuf;
+  MESSAGECACHE *elt;
+  unsigned long i,j,k;
+  long ret = LONGT;
+  int fd;
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+	mail_sequence (stream,sequence))) return NIL;
+  if (!mtx_isvalid (mailbox,tmp)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    mm_notify (stream,"[TRYCREATE] Must create mailbox before append",
+	       (long) NIL);
+    return NIL;
+  case 0:			/* merely empty file? */
+    break;
+  case EINVAL:			/* name is bogus */
+    if (pc) return (*pc) (stream,sequence,mailbox,options);
+    return mtx_badname (tmp,mailbox);
+  default:			/* file exists, but not valid format */
+    if (pc) return (*pc) (stream,sequence,mailbox,options);
+    sprintf (tmp,"Not a MTX-format mailbox: %s",mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* open the destination */
+  if (!mailboxfile (tmp,mailbox) ||
+      (fd = open (tmp,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,
+		  S_IREAD|S_IWRITE)) < 0) {
+    sprintf (tmp,"Unable to open copy mailbox: %s",strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+
+  mm_critical (stream);		/* go critical */
+  fstat (fd,&sbuf);		/* get current file size */
+				/* for each requested message */
+  for (i = 1; ret && (i <= stream->nmsgs); i++)
+    if ((elt = mail_elt (stream,i))->sequence) {
+      lseek (LOCAL->fd,elt->private.special.offset,SEEK_SET);
+				/* number of bytes to copy */
+      k = elt->private.special.text.size + elt->rfc822_size;
+      do {			/* read from source position */
+	j = min (k,(long) MAILTMPLEN);
+	read (LOCAL->fd,tmp,(size_t) j);
+	if (write (fd,tmp,(size_t) j) < 0) {
+	  sprintf (tmp,"Unable to write message: %s",strerror (errno));
+	  mm_log (tmp,ERROR);
+	  chsize (fd,sbuf.st_size);
+	  j = k;
+	  ret = NIL;		/* note error */
+	  break;
+	}
+      } while (k -= j);		/* until done */
+    }
+  close (fd);			/* close the file */
+  mm_nocritical (stream);	/* release critical */
+				/* delete all requested messages */
+  if (ret && (options & CP_MOVE)) for (i = 1; i <= stream->nmsgs; i++)
+    if ((elt = mail_elt (stream,i))->sequence) {
+      elt->deleted = T;		/* mark message deleted */
+				/* recalculate status */
+      mtx_update_status (stream,i);
+    }
+  if (ret && mail_parameters (NIL,GET_COPYUID,NIL))
+    mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN);
+  return ret;
+}
+
+/* MTX mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct stat sbuf;
+  int fd,ld,c;
+  char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN];
+  FILE *df;
+  MESSAGECACHE elt;
+  long f;
+  unsigned long i,uf;
+  STRING *message;
+  long ret = LONGT;
+				/* default stream to prototype */
+  if (!stream) stream = &mtxproto;
+				/* make sure valid mailbox */
+  if (!mtx_isvalid (mailbox,tmp)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    if (((mailbox[0] == 'I') || (mailbox[0] == 'i')) &&
+	((mailbox[1] == 'N') || (mailbox[1] == 'n')) &&
+	((mailbox[2] == 'B') || (mailbox[2] == 'b')) &&
+	((mailbox[3] == 'O') || (mailbox[3] == 'o')) &&
+	((mailbox[4] == 'X') || (mailbox[4] == 'x')) && !mailbox[5])
+      dummy_create (NIL,"INBOX.MTX");
+    else {
+      mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+      return NIL;
+    }
+				/* falls through */
+  case 0:			/* merely empty file? */
+    break;
+  case EINVAL:
+    return mtx_badname (tmp,mailbox);
+  default:
+    sprintf (tmp,"Not a MTX-format mailbox: %.80s",mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* get first message */
+  if (!(*af) (stream,data,&flags,&date,&message)) return NIL;
+				/* open destination mailbox */
+  if (!mailboxfile (file,mailbox) ||
+      ((fd = open (file,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,
+		   S_IREAD|S_IWRITE)) < 0) || !(df = fdopen (fd,"ab"))) {
+    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+  mm_critical (stream);		/* go critical */
+  fstat (fd,&sbuf);		/* get current file size */
+
+  errno = 0;
+  do {				/* parse flags */
+    if (!SIZE (message)) {	/* guard against zero-length */
+      mm_log ("Append of zero-length message",ERROR);
+      ret = NIL;
+      break;
+    }
+    f = mail_parse_flags (stream,flags,&i);
+				/* reverse bits (dontcha wish we had CIRC?) */
+    for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i)));
+    if (date) {			/* parse date if given */
+      if (!mail_parse_date (&elt,date)) {
+	sprintf (tmp,"Bad date in append: %.80s",date);
+	mm_log (tmp,ERROR);
+	ret = NIL;		/* mark failure */
+	break;
+      }
+      mail_date (tmp,&elt);	/* write preseved date */
+    }
+    else internal_date (tmp);	/* get current date in IMAP format */
+				/* write header */
+    if (fprintf (df,"%s,%lu;%010lo%02lo\015\012",tmp,i = SIZE (message),uf,
+		 (unsigned long) f) < 0) ret = NIL;
+    else {			/* write message */
+      if (i) do c = 0xff & SNX (message);
+      while ((putc (c,df) != EOF) && --i);
+				/* get next message */
+      if (i || !(*af) (stream,data,&flags,&date,&message)) ret = NIL;
+    }
+  } while (ret && message);
+				/* revert file if failure */
+  if (!ret || (fflush (df) == EOF)) {
+    chsize (fd,sbuf.st_size);	/* revert file */
+    close (fd);			/* make sure fclose() doesn't corrupt us */
+    if (errno) {
+      sprintf (tmp,"Message append failed: %s",strerror (errno));
+      mm_log (tmp,ERROR);
+    }
+    ret = NIL;
+  }
+  fclose (df);			/* close the file */ 
+  mm_nocritical (stream);	/* release critical */
+  if (ret && mail_parameters (NIL,GET_APPENDUID,NIL))
+    mm_log ("Can not return meaningful APPENDUID with this mailbox format",
+	    WARN);
+  return ret;
+}
+
+
+/* Return bad file name error message
+ * Accepts: temporary buffer
+ *	    file name
+ * Returns: long NIL always
+ */
+
+long mtx_badname (char *tmp,char *s)
+{
+  sprintf (tmp,"Invalid mailbox name: %s",s);
+  mm_log (tmp,ERROR);
+  return (long) NIL;
+}
+
+/* Parse mailbox
+ * Accepts: MAIL stream
+ * Returns: T if parse OK
+ *	    NIL if failure, stream aborted
+ */
+
+long mtx_parse (MAILSTREAM *stream)
+{
+  struct stat sbuf;
+  MESSAGECACHE *elt = NIL;
+  unsigned char *s,*t,*x,lbuf[65];
+  char tmp[MAILTMPLEN];
+  long i;
+  long curpos = LOCAL->filesize;
+  long nmsgs = stream->nmsgs;
+  long recent = stream->recent;
+  fstat (LOCAL->fd,&sbuf);	/* get status */
+  if (sbuf.st_size < curpos) {	/* sanity check */
+    sprintf (tmp,"Mailbox shrank from %ld to %ld!",curpos,sbuf.st_size);
+    mm_log (tmp,ERROR);
+    mtx_close (stream,NIL);
+    return NIL;
+  }
+				/* while there is stuff to parse */
+  while (i = sbuf.st_size - curpos) {
+				/* get to that position in the file */
+    lseek (LOCAL->fd,curpos,SEEK_SET);
+    if ((i = read (LOCAL->fd,lbuf,64)) <= 0) {
+      sprintf (tmp,"Unable to read internal header at %ld, size = %ld: %s",
+	       curpos,sbuf.st_size,i ? strerror (errno) : "no data read");
+      mm_log (tmp,ERROR);
+      mtx_close (stream,NIL);
+      return NIL;
+    }
+    lbuf[i] = '\0';		/* tie off buffer just in case */
+    if (!((s = strchr (lbuf,'\015')) && (s[1] == '\012'))) {
+      sprintf (tmp,"Unable to find end of line at %ld in %ld bytes, text: %s",
+	       curpos,i,(char *) lbuf);
+      mm_log (tmp,ERROR);
+      mtx_close (stream,NIL);
+      return NIL;
+    }
+    *s = '\0';			/* tie off header line */
+    i = (s + 2) - lbuf;		/* note start of text offset */
+    if (!((s = strchr (lbuf,',')) && (t = strchr (s+1,';')))) {
+      sprintf (tmp,"Unable to parse internal header at %ld: %s",curpos,
+	       (char *) lbuf);
+      mm_log (tmp,ERROR);
+      mtx_close (stream,NIL);
+      return NIL;
+    }
+
+    *s++ = '\0'; *t++ = '\0';	/* tie off fields */
+				/* intantiate an elt for this message */
+    (elt = mail_elt (stream,++nmsgs))->valid = T;
+    elt->private.uid = ++stream->uid_last;
+				/* note file offset of header */
+    elt->private.special.offset = curpos;
+				/* as well as offset from header of message */
+    elt->private.special.text.size = i;
+				/* header size not known yet */
+    elt->private.msg.header.text.size = 0;
+				/* parse the header components */
+    if (!(mail_parse_date (elt,lbuf) &&
+	  (elt->rfc822_size = strtol (x = s,(char **) &s,10)) && (!(s && *s))&&
+	  isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) &&
+	  isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) &&
+	  isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) &&
+	  isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12])) {
+      sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s",
+	       curpos,(char *) lbuf,(char *) x,(char *) t);
+      mtx_close (stream,NIL);
+      return NIL;
+    }
+				/* update current position to next header */
+    curpos += i + elt->rfc822_size;
+				/* calculate system flags */
+    if ((i = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T;
+    if (i & fDELETED) elt->deleted = T;
+    if (i & fFLAGGED) elt->flagged = T;
+    if (i & fANSWERED) elt->answered = T;
+    if (i & fDRAFT) elt->draft = T;
+    if (curpos > sbuf.st_size) {
+      sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
+	       elt->private.special.offset,curpos,sbuf.st_size);
+      mm_log (tmp,ERROR);
+      mtx_close (stream,NIL);
+      return NIL;
+    }
+  }
+				/* update parsed file size */
+  LOCAL->filesize = sbuf.st_size;
+  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
+  mail_recent (stream,recent);	/* and of change in recent messages */
+  return T;			/* return the winnage */
+}
+
+/* Update status string
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void mtx_update_status (MAILSTREAM *stream,unsigned long msgno)
+{
+  char tmp[MAILTMPLEN];
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  unsigned long j,k = 0;
+				/* not if readonly you don't */
+  if (stream->rdonly || !elt->valid) return;
+  j = elt->user_flags;		/* get user flags */
+				/* reverse bits (dontcha wish we had CIRC?) */
+  while (j) k |= 1 << 29 - find_rightmost_bit (&j);
+  sprintf (tmp,"%010lo%02o",k,	/* print new flag string */
+	   fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
+	   (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
+	   (fDRAFT * elt->draft));
+				/* get to that place in the file */
+  lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	 elt->private.special.text.size - 14,SEEK_SET);
+  write (LOCAL->fd,tmp,12);	/* write new flags */
+}
+
+/* MTX locate header for a message
+ * Accepts: MAIL stream
+ *	    message number
+ *	    pointer to returned header size
+ * Returns: position of header in file
+ */
+
+unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			  unsigned long *size)
+{
+  unsigned long siz;
+  size_t i = 0;
+  int q = 0;
+  char *s,tmp[MAILTMPLEN];
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  long pos = elt->private.special.offset + elt->private.special.text.size;
+				/* is header size known? */
+  if (!(*size = elt->private.msg.header.text.size)) {
+				/* get to header position */
+    lseek (LOCAL->fd,pos,SEEK_SET);
+				/* search message for CRLF CRLF */
+    for (siz = 1; siz <= elt->rfc822_size; siz++) {
+      if (!i &&			/* buffer empty? */
+	  (read (LOCAL->fd,s = tmp,
+		 i = (size_t) min(elt->rfc822_size-siz,(long)MAILTMPLEN))<= 0))
+	return pos;
+      else i--;
+      switch (q) {		/* sniff at buffer */
+      case 0:			/* first character */
+	q = (*s++ == '\015') ? 1 : 0;
+	break;
+      case 1:			/* second character */
+	q = (*s++ == '\012') ? 2 : 0;
+	break;
+      case 2:			/* third character */
+	q = (*s++ == '\015') ? 3 : 0;
+	break;
+      case 3:			/* fourth character */
+	if (*s++ == '\012') {	/* have the sequence? */
+				/* yes, note for later */
+	  elt->private.msg.header.text.size = (*size = siz);
+	  return pos;		/* return to caller */
+	}
+	q = 0;			/* lost... */
+	break;
+      }
+    }
+  }
+  return pos;			/* have position */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/nl_dos.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,61 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Windows/TOPS-20 newline routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Copy string with CRLF newlines
+ * Accepts: destination string
+ *	    pointer to size of destination string buffer
+ *	    source string
+ *	    length of source string
+ * Returns: length of copied string
+ */
+
+unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl,
+			  unsigned char *src,unsigned long srcl)
+{
+				/* flush destination buffer if too small */
+  if (*dst && (srcl > *dstl)) fs_give ((void **) dst);
+  if (!*dst) {			/* make a new buffer if needed */
+    *dst = (char *) fs_get ((size_t) (*dstl = srcl) + 1);
+    if (dstl) *dstl = srcl;	/* return new buffer length to main program */
+  }
+				/* copy strings */
+  if (srcl) memcpy (*dst,src,(size_t) srcl);
+  *(*dst + srcl) = '\0';	/* tie off destination */
+  return srcl;			/* return length */
+}
+
+
+/* Length of string after strcrlfcpy applied
+ * Accepts: source string
+ * Returns: length of string
+ */
+
+unsigned long strcrlflen (STRING *s)
+{
+  return SIZE (s);		/* no-brainer on DOS! */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/os_dbw.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,91 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- MS-DOS (B&W) version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 April 1989
+ * Last Edited:	30 August 2006
+ */
+
+/* Private function prototypes */
+
+#include "tcp_dos.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys\stat.h>
+#include <sys\timeb.h>
+#include "misc.h"
+#include "stdlib.h"
+#include "bwtcp.h"
+
+
+#include "fs_dos.c"
+#include "ftl_dos.c"
+#include "nl_dos.c"
+#include "env_dos.c"
+#undef write
+#define read soread
+#define write sowrite
+#define close soclose 
+#include "tcp_dos.c"
+
+
+/* Return my local host name
+ * Returns: my local host name
+ */
+
+char *mylocalhost (void)
+{
+  char *s;
+  if (!myLocalHost) {		/* known yet? */
+				/* get local host name from DISPLAY env var */
+    if (!((s = getenv ("DISPLAY")) || (s = getenv ("display")))) {
+      mm_log ("Environment variable 'DISPLAY' is not set", ERROR);
+      s = "random-pc";
+    }
+    myLocalHost = cpystr (s);
+  }
+  return myLocalHost;
+}
+
+
+/* Look up host address
+ * Accepts: pointer to pointer to host name
+ *	    socket address block
+ * Returns: non-zero with host address in socket, official host name in host;
+ *	    else NIL
+ */
+
+long lookuphost (char **host,struct sockaddr_in *sin)
+{
+  char *s = *host;		/* in case of error */
+  sin->sin_addr.s_addr = rhost (host);
+  if (sin->sin_addr.s_addr == -1) {
+    *host = s;			/* error, restore old host name */
+    return NIL;
+  }
+  *host = cpystr (*host);	/* make permanent copy of name */
+  return T;			/* success */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/os_dbw.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,43 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- DOS (B&W/Novell) version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	30 August 2006
+ */
+
+#define INADEQUATE_MEMORY
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys\types.h>
+#include <io.h>
+
+#define gethostid clock
+
+#include "env_dos.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/os_dnf.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,95 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- MS-DOS (PC-NFS) version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 April 1989
+ * Last Edited:	30 August 2006
+ */
+
+/* Private function prototypes */
+
+#include "tcp_dos.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys\stat.h>
+#include <sys\timeb.h>
+#include <sys\nfs_time.h>
+#include <sys\tk_types.h>
+#include <sys\socket.h>
+#include <netinet\in.h>
+#include <tk_errno.h>
+#include <sys\uio.h>
+#include <netdb.h>
+#include "misc.h"
+
+
+#include "fs_dos.c"
+#include "ftl_dos.c"
+#include "nl_dos.c"
+#include "env_dos.c"
+#undef write
+#include "tcp_dos.c"
+
+
+/* Return my local host name
+ * Returns: my local host name
+ */
+
+char *mylocalhost (void)
+{
+  if (!myLocalHost) {		/* known yet? */
+    char *s,tmp[MAILTMPLEN];
+    unsigned long myip;
+				/* see if known host name */
+    if (!gethostname (tmp,MAILTMPLEN-1)) s = tmp;
+				/* no, try host address */
+    else if (get_myipaddr ((char *) &myip))
+      sprintf (s = tmp,"[%s]",inet_ntoa (myip));
+    else s = "random-pc";	/* say what? */
+    myLocalHost = cpystr (s);	/* record for subsequent use */
+  }
+  return myLocalHost;
+}
+
+
+/* Look up host address
+ * Accepts: pointer to pointer to host name
+ *	    socket address block
+ * Returns: non-zero with host address in socket, official host name in host;
+ *	    else NIL
+ */
+
+long lookuphost (char **host,struct sockaddr_in *sin)
+{
+  long ret = -1;
+  char tmp[MAILTMPLEN];
+  struct hostent *hn = gethostbyname (lcase (strcpy (tmp,*host)));
+  if (!hn) return NIL;		/* got a host name? */
+  *host = cpystr (hn->h_name);	/* set official name */
+				/* copy host addresses */
+  memcpy (&sin->sin_addr,hn->h_addr,hn->h_length);
+  return T;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/os_dnf.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,44 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- DOS (PC-NFS) version
+ *
+ * Author:	Mike Seibel from Novell version by Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MikeS@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	30 August 2006
+ */
+
+#define INADEQUATE_MEMORY
+
+#include <tklib.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys\types.h>
+#include <io.h>
+
+#define gethostid clock
+
+#include "env_dos.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/os_dnv.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,95 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- MS-DOS (Novell) version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 April 1989
+ * Last Edited:	30 August 2006
+ */
+
+/* Private function prototypes */
+
+#include "tcp_dos.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys\stat.h>
+#include <sys\timeb.h>
+#include <sys\socket.h>
+#include <netinet\in.h>
+#include <netdb.h>
+#include "misc.h"
+
+
+#include "fs_dos.c"
+#include "ftl_dos.c"
+#include "nl_dos.c"
+#include "env_dos.c"
+#undef write
+#define read soread
+#define write sowrite
+#define close soclose 
+#include "tcp_dos.c"
+
+
+/* Return my local host name
+ * Returns: my local host name
+ */
+
+char *mylocalhost (void)
+{
+  if (!myLocalHost) {		/* known yet? */
+    char *s,tmp[MAILTMPLEN];
+    struct hostent *he;
+    struct in_addr in;
+				/* could we get local id? */
+    if ((in.s_addr = getmyipaddr ()) != -1) {
+      if (he = gethostbyaddr ((char *) &in.s_addr,4,PF_INET)) s = he->h_name;
+      else sprintf (s = tmp,"[%s]",inet_ntoa (in));
+    }
+    else s = "random-pc";	/* say what? */
+    myLocalHost = cpystr (s);	/* record for subsequent use */
+  }
+  return myLocalHost;
+}
+
+
+/* Look up host address
+ * Accepts: pointer to pointer to host name
+ *	    socket address block
+ * Returns: non-zero with host address in socket, official host name in host;
+ *	    else NIL
+ */
+
+long lookuphost (char **host,struct sockaddr_in *sin)
+{
+  char *s = *host;		/* in case of error */
+  sin->sin_addr.s_addr = rhost (host);
+  if (sin->sin_addr.s_addr == -1) {
+    *host = s;			/* error, restore old host name */
+    return NIL;
+  }
+  *host = cpystr (*host);	/* make permanent copy of name */
+  return T;			/* success */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/os_dnv.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,43 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- DOS (B&W/Novell) version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	30 August 2006
+ */
+
+#define INADEQUATE_MEMORY
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys\types.h>
+#include <io.h>
+
+#define gethostid clock
+
+#include "env_dos.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/os_dpc.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,102 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- MS-DOS (PC/TCP) version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 April 1989
+ * Last Edited:	30 August 2006
+ */
+
+/* Private function prototypes */
+
+#include "tcp_dos.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys\stat.h>
+#include <sys\timeb.h>
+#include <4bsddefs.h>
+#include <sys\socket.h>
+#include <errno.h>
+#include <arpa\inet.h>
+#include <netinet\in.h>
+#include <netdb.h>
+#include "misc.h"
+
+
+#include "fs_dos.c"
+#include "ftl_dos.c"
+#include "nl_dos.c"
+#include "env_dos.c"
+#undef write
+#include "tcp_dos.c"
+
+
+/* Return my local host name
+ * Returns: my local host name
+ */
+
+char *mylocalhost (void)
+{
+  if (!myLocalHost) {		/* known yet */
+    char *s,tmp[MAILTMPLEN];
+    long myip;
+				/* see if known host name */
+    if (!gethostname (tmp,MAILTMPLEN-1)) s = tmp;
+				/* no, try IP address */
+    else if (myip = gethostid ()) {
+      struct in_addr in;
+      in.s_addr = myip;
+      sprintf (s = tmp,"[%s]",inet_ntoa (in));
+    }
+				/* older kernel, look harder. */
+    else if (getconf ("ifcust","ip-address",tmp+1,MAILTMPLEN-2)) {
+      *(s = tmp) = '[';		/* wrap the brackets around it */
+      strcat (tmp,"]");
+    }
+    else s = "random-pc";	/* say what? */
+    myLocalHost = cpystr (s);	/* record for subsequent use */
+  }
+  return myLocalHost;
+}
+
+
+/* Look up host address
+ * Accepts: pointer to pointer to host name
+ *	    socket address block
+ * Returns: non-zero with host address in socket, official host name in host;
+ *	    else NIL
+ */
+
+long lookuphost (char **host,struct sockaddr_in *sin)
+{
+  long ret = -1;
+  char tmp[MAILTMPLEN];
+  struct hostent *hn = gethostbyname (lcase (strcpy (tmp,*host)));
+  if (!hn) return NIL;		/* got a host name? */
+  *host = cpystr (hn->h_name);	/* set official name */
+				/* copy host addresses */
+  memcpy (&sin->sin_addr,hn->h_addr,hn->h_length);
+  return T;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/os_dpc.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,41 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- DOS (PC/TCP) version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	30 August 2006
+ */
+
+#define INADEQUATE_MEMORY
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys\types.h>
+#include <io.h>
+
+#include "env_dos.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/os_dwa.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,72 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- DOS (Waterloo) version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 April 1989
+ * Last Edited:	30 August 2006
+ */
+
+#include <tcp.h>		/* must be before TCPSTREAM definition */
+#include "tcp_dwa.h"		/* must be before osdep include our tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys\stat.h>
+#include <sys\timeb.h>
+#include "misc.h"
+
+/* Undo compatibility definition */
+
+#undef tcp_open
+
+#include "fs_dos.c"
+#include "ftl_dos.c"
+#include "nl_dos.c"
+#include "env_dos.c"
+#include "tcp_dwa.c"
+
+
+/* Return my local host name
+ * Returns: my local host name
+ */
+
+char *mylocalhost (void)
+{
+  if (!myLocalHost) {
+    char *s,hname[32],tmp[MAILTMPLEN];
+    long myip;
+
+    if (!sock_initted++) sock_init();
+    tcp_cbrk (0x01);		/* turn off ctrl-break catching */
+    /*
+     * haven't discovered a way to find out the local host's 
+     * name with wattcp yet.
+     */
+    if (myip = gethostid ()) sprintf (s = tmp,"[%s]",inet_ntoa (hname,myip));
+    else s = "random-pc";
+    myLocalHost = cpystr (s);
+  }
+  return myLocalHost;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/os_dwa.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,43 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- DOS (Waterloo) version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	30 August 2006
+ */
+
+#define INADEQUATE_MEMORY
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys\types.h>
+#include <io.h>
+
+#define tcp_open TCP_open
+
+#include "env_dos.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/os_wsk.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,45 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Winsock version
+ *
+ * Author:	Mike Seibel from Unix version by Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MikeS@CAC.Washington.EDU
+ *
+ * Date:	11 April 1989
+ * Last Edited:	30 August 2006
+ */
+
+#include "tcp_wsk.h"		/* must be before osdep includes tcp.h */
+#undef	ERROR			/* quell conflicting def warning */
+#include "mail.h"
+#include "osdep.h"
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys\stat.h>
+#include <sys\timeb.h>
+#include "misc.h"
+
+
+#include "fs_dos.c"
+#include "ftl_dos.c"
+#include "nl_dos.c"
+#include "env_dos.c"
+#include "tcp_wsk.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/os_wsk.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,48 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- 16-bit Winsock version
+ *
+ * Author:	Mike Seibel from Novell version by Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MikeS@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	30 August 2006
+ */
+
+#define INADEQUATE_MEMORY
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys\types.h>
+#include <io.h>
+
+#define gethostid clock
+#define	WSA_VERSION	((1 << 8) | 1)
+
+#include "env_dos.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+
+
+#undef noErr
+#undef MAC
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/pmatch.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,89 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	IMAP Wildcard Matching Routines (case-independent)
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	15 June 2000
+ * Last Edited:	30 August 2006
+ */
+
+/* Wildcard pattern match
+ * Accepts: base string
+ *	    pattern string
+ *	    delimiter character
+ * Returns: T if pattern matches base, else NIL
+ */
+
+long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim)
+{
+  switch (*pat) {
+  case '%':			/* non-recursive */
+				/* % at end, OK if no inferiors */
+    if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T;
+                                /* scan remainder of string until delimiter */
+    do if (pmatch_full (s,pat+1,delim)) return T;
+    while ((*s != delim) && *s++);
+    break;
+  case '*':			/* match 0 or more characters */
+    if (!pat[1]) return T;	/* * at end, unconditional match */
+				/* scan remainder of string */
+    do if (pmatch_full (s,pat+1,delim)) return T;
+    while (*s++);
+    break;
+  case '\0':			/* end of pattern */
+    return *s ? NIL : T;	/* success if also end of base */
+  default:			/* match this character */
+    return compare_uchar (*pat,*s) ? NIL : pmatch_full (s+1,pat+1,delim);
+  }
+  return NIL;
+}
+
+/* Directory pattern match
+ * Accepts: base string
+ *	    pattern string
+ *	    delimiter character
+ * Returns: T if base is a matching directory of pattern, else NIL
+ */
+
+long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim)
+{
+  switch (*pat) {
+  case '%':			/* non-recursive */
+    if (!*s) return T;		/* end of base means have a subset match */
+    if (!*++pat) return NIL;	/* % at end, no inferiors permitted */
+				/* scan remainder of string until delimiter */
+    do if (dmatch (s,pat,delim)) return T;
+    while ((*s != delim) && *s++);
+    if (*s && !s[1]) return T;	/* ends with delimiter, must be subset */
+    return dmatch (s,pat,delim);/* do new scan */
+  case '*':			/* match 0 or more characters */
+    return T;			/* unconditional match */
+  case '\0':			/* end of pattern */
+    break;
+  default:			/* match this character */
+    if (*s) return compare_uchar (*pat,*s) ? NIL : dmatch (s+1,pat+1,delim);
+				/* end of base, return if at delimiter */
+    else if (*pat == delim) return T;
+    break;
+  }
+  return NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/tcp_dos.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,434 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	MS-DOS TCP/IP routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 April 1989
+ * Last Edited:	13 January 2008
+ */
+
+static tcptimeout_t tmoh = NIL;	/* TCP timeout handler routine */
+static long ttmo_read = 0;	/* TCP timeouts, in seconds */
+static long ttmo_write = 0;
+
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+			       long *contd);
+
+/* TCP/IP manipulate parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *tcp_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case SET_TIMEOUT:
+    tmoh = (tcptimeout_t) value;
+  case GET_TIMEOUT:
+    ret = (void *) tmoh;
+    break;
+  case SET_READTIMEOUT:
+    ttmo_read = (long) value;
+  case GET_READTIMEOUT:
+    ret = (void *) ttmo_read;
+    break;
+  case SET_WRITETIMEOUT:
+    ttmo_write = (long) value;
+  case GET_WRITETIMEOUT:
+    ret = (void *) ttmo_write;
+    break;
+  }
+  return ret;
+}
+
+/* TCP/IP open
+ * Accepts: host name
+ *	    contact service name
+ *	    contact port number
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
+{
+  TCPSTREAM *stream = NIL;
+  struct sockaddr_in sin;
+  int sock;
+  char *s,tmp[MAILTMPLEN];
+  port &= 0xffff;		/* erase flags */
+  /* The domain literal form is used (rather than simply the dotted decimal
+     as with other Unix programs) because it has to be a valid "host name"
+     in mailsystem terminology. */
+  sin.sin_family = AF_INET;	/* family is always Internet */
+				/* look like domain literal? */
+  if (host[0] == '[' && host[(strlen (host))-1] == ']') {
+    strcpy (tmp,host+1);	/* yes, copy number part */
+    tmp[strlen (tmp)-1] = '\0';
+    if ((sin.sin_addr.s_addr = inet_addr (tmp)) == -1) {
+      sprintf (tmp,"Bad format domain-literal: %.80s",host);
+      mm_log (tmp,ERROR);
+      return NIL;
+    }
+  }
+				/* look up host name */
+  else if (!lookuphost (&host,&sin)) {
+    sprintf (tmp,"Host not found: %s",host);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+
+				/* copy port number in network format */
+  if (!(sin.sin_port = htons (port))) fatal ("Bad port argument to tcp_open");
+				/* get a TCP stream */
+  if ((sock = socket (sin.sin_family,SOCK_STREAM,0)) < 0) {
+    sprintf (tmp,"Unable to create TCP socket (%d)",errno);
+    mm_log (tmp,ERROR);
+    fs_give ((void **) &host);
+    return NIL;
+  }
+#if 0
+  /* needed? */
+  else if (sock >= FD_SETSIZE) {/* unselectable sockets are useless */
+    sprintf (tmp,"Unable to create selectable TCP socket (%d >= %d)",
+	     sock,FD_SETSIZE);
+    close (sock);
+    errno = ENOBUFS;		/* just in case */
+    return NIL;
+  }
+#endif
+				/* open connection */
+  if (connect (sock,(struct sockaddr *) &sin,sizeof (sin)) < 0) {
+    switch (errno) {		/* analyze error */
+    case ECONNREFUSED:
+      s = "Refused";
+      break;
+    case ENOBUFS:
+      s = "Insufficient system resources";
+      break;
+    case ETIMEDOUT:
+      s = "Timed out";
+      break;
+    default:
+      s = "Unknown error";
+      break;
+    }
+    sprintf (tmp,"Can't connect to %.80s,%ld: %s (%d)",host,port,s,errno);
+    mm_log (tmp,ERROR);
+    close (sock);
+    fs_give ((void **) &host);
+    return NIL;
+  }
+				/* create TCP/IP stream */
+  stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
+  stream->host = host;		/* official host name */
+  stream->localhost = cpystr (mylocalhost ());
+  stream->port = port;		/* port number */
+  stream->tcps = sock;		/* init socket */
+  stream->ictr = 0;		/* init input counter */
+  return stream;		/* return success */
+}
+  
+/* TCP/IP authenticated open
+ * Accepts: NETMBX specifier
+ *	    service name
+ *	    returned user name buffer
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
+{
+  return NIL;			/* always NIL on DOS */
+}
+
+/* TCP receive line
+ * Accepts: TCP stream
+ * Returns: text line string or NIL if failure
+ */
+
+char *tcp_getline (TCPSTREAM *stream)
+{
+  unsigned long n,contd;
+  char *ret = tcp_getline_work (stream,&n,&contd);
+  if (ret && contd) {		/* got a line needing continuation? */
+    STRINGLIST *stl = mail_newstringlist ();
+    STRINGLIST *stc = stl;
+    do {			/* collect additional lines */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+      stc = stc->next = mail_newstringlist ();
+      ret = tcp_getline_work (stream,&n,&contd);
+    } while (ret && contd);
+    if (ret) {			/* stash final part of line on list */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+				/* determine how large a buffer we need */
+      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
+      ret = fs_get (n + 1);	/* copy parts into buffer */
+      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
+	memcpy (ret + n,stc->text.data,stc->text.size);
+      ret[n] = '\0';
+    }
+    mail_free_stringlist (&stl);/* either way, done with list */
+  }
+  return ret;
+}
+
+/* TCP receive line or partial line
+ * Accepts: TCP stream
+ *	    pointer to return size
+ *	    pointer to return continuation flag
+ * Returns: text line string, size and continuation flag, or NIL if failure
+ */
+
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+			       long *contd)
+{
+  unsigned long n;
+  char *s,*ret,c,d;
+  *contd = NIL;			/* assume no continuation */
+				/* make sure have data */
+  if (!tcp_getdata (stream)) return NIL;
+  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
+    d = *stream->iptr++;	/* slurp another character */
+    if ((c == '\015') && (d == '\012')) {
+      ret = (char *) fs_get (n--);
+      memcpy (ret,s,*size = n);	/* copy into a free storage string */
+      ret[n] = '\0';		/* tie off string with null */
+      return ret;
+    }
+  }
+				/* copy partial string from buffer */
+  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
+				/* get more data from the net */
+  if (!tcp_getdata (stream)) fs_give ((void **) &ret);
+				/* special case of newline broken by buffer */
+  else if ((c == '\015') && (*stream->iptr == '\012')) {
+    stream->iptr++;		/* eat the line feed */
+    stream->ictr--;
+    ret[*size = --n] = '\0';	/* tie off string with null */
+  }
+  else *contd = LONGT;		/* continuation needed */
+  return ret;
+}
+
+/* TCP/IP receive buffer
+ * Accepts: TCP/IP stream
+ *	    size in bytes
+ *	    buffer to read into
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
+{
+  unsigned long n;
+  char *bufptr = buffer;
+  while (size > 0) {		/* until request satisfied */
+    if (!tcp_getdata (stream)) return NIL;
+    n = min (size,stream->ictr);/* number of bytes to transfer */
+				/* do the copy */
+    memcpy (bufptr,stream->iptr,n);
+    bufptr += n;		/* update pointer */
+    stream->iptr +=n;
+    size -= n;			/* update # of bytes to do */
+    stream->ictr -=n;
+  }
+  bufptr[0] = '\0';		/* tie off string */
+  return T;
+}
+
+/* TCP/IP receive data
+ * Accepts: TCP/IP stream
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getdata (TCPSTREAM *stream)
+{
+  int i;
+  fd_set fds,efds;
+  struct timeval tmo;
+  time_t t = time (0);
+  if (stream->tcps < 0) return NIL;
+  while (stream->ictr < 1) {	/* if nothing in the buffer */
+    time_t tl = time (0);	/* start of request */
+    tmo.tv_sec = ttmo_read;	/* read timeout */
+    tmo.tv_usec = 0;
+    FD_ZERO (&fds);		/* initialize selection vector */
+    FD_ZERO (&efds);		/* handle errors too */
+    FD_SET (stream->tcps,&fds);/* set bit in selection vector */
+    FD_SET(stream->tcps,&efds);/* set bit in error selection vector */
+    errno = NIL;		/* block and read */
+    while (((i = select (stream->tcps+1,&fds,0,&efds,ttmo_read ? &tmo : 0))<0)
+	   && (errno == EINTR));
+    if (!i) {			/* timeout? */
+      time_t tc = time (0);
+      if (tmoh && ((*tmoh) (tc - t,tc - tl))) continue;
+      else return tcp_abort (stream);
+    }
+    else if (i < 0) return tcp_abort (stream);
+    while (((i = read (stream->tcps,stream->ibuf,BUFLEN)) < 0) &&
+	   (errno == EINTR));
+    if (i < 1) return tcp_abort (stream);
+    stream->iptr = stream->ibuf;/* point at TCP buffer */
+    stream->ictr = i;		/* set new byte count */
+  }
+  return T;
+}
+
+/* TCP/IP send string as record
+ * Accepts: TCP/IP stream
+ *	    string pointer
+ * Returns: T if success else NIL
+ */
+
+long tcp_soutr (TCPSTREAM *stream,char *string)
+{
+  return tcp_sout (stream,string,(unsigned long) strlen (string));
+}
+
+
+/* TCP/IP send string
+ * Accepts: TCP/IP stream
+ *	    string pointer
+ *	    byte count
+ * Returns: T if success else NIL
+ */
+
+long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
+{
+  int i;
+  fd_set fds;
+  struct timeval tmo;
+  time_t t = time (0);
+  if (stream->tcps < 0) return NIL;
+  while (size > 0) {		/* until request satisfied */
+    time_t tl = time (0);	/* start of request */
+    tmo.tv_sec = ttmo_write;	/* write timeout */
+    tmo.tv_usec = 0;
+    FD_ZERO (&fds);		/* initialize selection vector */
+    FD_SET (stream->tcps,&fds);/* set bit in selection vector */
+    errno = NIL;		/* block and write */
+    while (((i = select (stream->tcps+1,0,&fds,0,ttmo_write ? &tmo : 0)) < 0)
+	   && (errno == EINTR));
+    if (!i) {			/* timeout? */
+      time_t tc = time (0);
+      if (tmoh && ((*tmoh) (tc - t,tc - tl))) continue;
+      else return tcp_abort (stream);
+    }
+    else if (i < 0) return tcp_abort (stream);
+    while (((i = write (stream->tcps,string,size)) < 0) && (errno == EINTR));
+    if (i < 0) return tcp_abort (stream);
+    size -= i;			/* how much we sent */
+    string += i;
+  }
+  return T;			/* all done */
+}
+
+/* TCP/IP close
+ * Accepts: TCP/IP stream
+ */
+
+void tcp_close (TCPSTREAM *stream)
+{
+  tcp_abort (stream);		/* nuke the socket */
+				/* flush host names */
+  fs_give ((void **) &stream->host);
+  fs_give ((void **) &stream->localhost);
+  fs_give ((void **) &stream);	/* flush the stream */
+}
+
+
+/* TCP/IP abort stream
+ * Accepts: TCP/IP stream
+ * Returns: NIL always
+ */
+
+long tcp_abort (TCPSTREAM *stream)
+{
+  if (stream->tcps >= 0) close (stream->tcps);
+  stream->tcps = -1;
+  return NIL;
+}
+
+/* TCP/IP get host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_host (TCPSTREAM *stream)
+{
+  return stream->host;		/* return host name */
+}
+
+
+/* TCP/IP get remote host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_remotehost (TCPSTREAM *stream)
+{
+  return stream->host;		/* all we can do for now */
+}
+
+
+/* TCP/IP return port for this stream
+ * Accepts: TCP/IP stream
+ * Returns: port number for this stream
+ */
+
+unsigned long tcp_port (TCPSTREAM *stream)
+{
+  return stream->port;		/* return port number */
+}
+
+
+/* TCP/IP get local host name
+ * Accepts: TCP/IP stream
+ * Returns: local host name
+ */
+
+char *tcp_localhost (TCPSTREAM *stream)
+{
+  return stream->localhost;	/* return local host name */
+}
+
+
+/* TCP/IP return canonical form of host name
+ * Accepts: host name
+ * Returns: canonical form of host name
+ */
+
+char *tcp_canonical (char *name)
+{
+  return name;
+}
+
+
+/* TCP/IP get client host name (server calls only)
+ * Returns: client host name
+ */
+
+char *tcp_clienthost ()
+{
+  return "UNKNOWN";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/tcp_dos.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,51 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	OS2 routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 April 1989
+ * Last Edited:	30 August 2006
+ */
+
+/* TCP input buffer -- must be large enough to prevent overflow */
+
+#define BUFLEN 8192
+
+
+/* TCP I/O stream (must be before osdep.h is included) */
+
+#define TCPSTREAM struct tcp_stream
+TCPSTREAM {
+  char *host;			/* host name */
+  unsigned long port;		/* port number */
+  char *localhost;		/* local host name */
+  int tcps;			/* tcp socket */
+  long ictr;			/* input counter */
+  char *iptr;			/* input pointer */
+  char ibuf[BUFLEN];		/* input buffer */
+};
+
+
+/* Local function prototypes */
+
+long lookuphost (char **host,struct sockaddr_in *sin);
+long tcp_abort (TCPSTREAM *stream);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/tcp_dwa.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,344 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Waterloo DOS TCP/IP routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 April 1989
+ * Last Edited:	13 January 2008
+ */
+
+
+/* Global data */
+
+short sock_initted = 0;		/* global so others using net can see it */
+
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+			       long *contd);
+
+/* TCP/IP manipulate parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *tcp_parameters (long function,void *value)
+{
+  return NIL;
+}
+
+/* TCP/IP open
+ * Accepts: host name
+ *	    contact service name
+ *	    contact port number
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *TCP_open (char *host,char *service,unsigned long port)
+{
+  TCPSTREAM *stream = NIL;
+  tcp_Socket *sock;
+  char *s,tmp[MAILTMPLEN];
+  unsigned long adr,i,j,k,l;
+  port &= 0xffff;		/* erase flags */
+				/* initialize if first time here */
+  if (!sock_initted++) sock_init();
+  /* The domain literal form is used (rather than simply the dotted decimal
+     as with other Unix programs) because it has to be a valid "host name"
+     in mailsystem terminology. */
+				/* look like domain literal? */
+  if (host[0] == '[' && host[strlen (host)-1] == ']') {
+    if (((i = strtoul (s = host+1,&s,10)) <= 255) && *s++ == '.' &&
+	((j = strtoul (s,&s,10)) <= 255) && *s++ == '.' &&
+	((k = strtoul (s,&s,10)) <= 255) && *s++ == '.' &&
+	((l = strtoul (s,&s,10)) <= 255) && *s++ == ']' && !*s)
+      adr = (i << 24) + (j << 16) + (k << 8) + l;
+    else {
+      sprintf (tmp,"Bad format domain-literal: %.80s",host);
+      mm_log (tmp,ERROR);
+      return NIL;
+    }
+  }
+  else {			/* lookup host name */
+    if (!(adr = resolve (host))) {
+      sprintf (tmp,"Host not found: %s",host);
+      mm_log (tmp,ERROR);
+      return NIL;
+    }
+  }
+
+				/* OK to instantiate socket now */
+  sock = (tcp_Socket *) fs_get (sizeof (tcp_Socket));
+				/* open connection */
+  if (!tcp_open (sock,(word) 0,adr,(word) port,NULL)) {
+    sprintf (tmp,"Can't connect to %.80s,%ld",host,port);
+    mm_log (tmp,ERROR);
+    fs_give ((void **) &sock);
+    return NIL;
+  }
+				/* create TCP/IP stream */
+  stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
+  stream->host = cpystr (host);	/* official host name */
+  stream->localhost = cpystr (mylocalhost ());
+  stream->port = port;		/* port number */
+  stream->tcps = sock;		/* init socket */
+  stream->ictr = 0;		/* init input counter */
+  return stream;		/* return success */
+}
+  
+/* TCP/IP authenticated open
+ * Accepts: NETMBX specifier
+ *	    service name
+ *	    returned user name buffer
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
+{
+  return NIL;			/* always NIL on DOS */
+}
+
+/* TCP receive line
+ * Accepts: TCP stream
+ * Returns: text line string or NIL if failure
+ */
+
+char *tcp_getline (TCPSTREAM *stream)
+{
+  unsigned long n,contd;
+  char *ret = tcp_getline_work (stream,&n,&contd);
+  if (ret && contd) {		/* got a line needing continuation? */
+    STRINGLIST *stl = mail_newstringlist ();
+    STRINGLIST *stc = stl;
+    do {			/* collect additional lines */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+      stc = stc->next = mail_newstringlist ();
+      ret = tcp_getline_work (stream,&n,&contd);
+    } while (ret && contd);
+    if (ret) {			/* stash final part of line on list */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+				/* determine how large a buffer we need */
+      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
+      ret = fs_get (n + 1);	/* copy parts into buffer */
+      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
+	memcpy (ret + n,stc->text.data,stc->text.size);
+      ret[n] = '\0';
+    }
+    mail_free_stringlist (&stl);/* either way, done with list */
+  }
+  return ret;
+}
+
+/* TCP receive line or partial line
+ * Accepts: TCP stream
+ *	    pointer to return size
+ *	    pointer to return continuation flag
+ * Returns: text line string, size and continuation flag, or NIL if failure
+ */
+
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+			       long *contd)
+{
+  unsigned long n;
+  char *s,*ret,c,d;
+  *contd = NIL;			/* assume no continuation */
+				/* make sure have data */
+  if (!tcp_getdata (stream)) return NIL;
+  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
+    d = *stream->iptr++;	/* slurp another character */
+    if ((c == '\015') && (d == '\012')) {
+      ret = (char *) fs_get (n--);
+      memcpy (ret,s,*size = n);	/* copy into a free storage string */
+      ret[n] = '\0';		/* tie off string with null */
+      return ret;
+    }
+  }
+				/* copy partial string from buffer */
+  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
+				/* get more data from the net */
+  if (!tcp_getdata (stream)) fs_give ((void **) &ret);
+				/* special case of newline broken by buffer */
+  else if ((c == '\015') && (*stream->iptr == '\012')) {
+    stream->iptr++;		/* eat the line feed */
+    stream->ictr--;
+    ret[*size = --n] = '\0';	/* tie off string with null */
+  }
+  else *contd = LONGT;		/* continuation needed */
+  return ret;
+}
+
+/* TCP/IP receive buffer
+ * Accepts: TCP/IP stream
+ *	    size in bytes
+ *	    buffer to read into
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
+{
+  unsigned long n;
+  char *bufptr = buffer;
+  while (size > 0) {		/* until request satisfied */
+    if (!tcp_getdata (stream)) return NIL;
+    n = min (size,stream->ictr);/* number of bytes to transfer */
+				/* do the copy */
+    memcpy (bufptr,stream->iptr,(size_t) n);
+    bufptr += n;		/* update pointer */
+    stream->iptr +=n;
+    size -= n;			/* update # of bytes to do */
+    stream->ictr -=n;
+  }
+  bufptr[0] = '\0';		/* tie off string */
+  return T;
+}
+
+
+/* TCP/IP receive data
+ * Accepts: TCP/IP stream
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getdata (TCPSTREAM *stream)
+{
+  int status;
+  if (!stream->tcps) return NIL;/* no-no nuked socket */
+  while (stream->ictr < 1) {	/* if buffer empty, block for input and read */
+    if (!_ip_delay1 (stream->tcps,600,NULL,&status))
+      stream->ictr = sock_fastread (stream->tcps,
+				    stream->iptr = stream->ibuf,BUFLEN);
+    else if (status == 1) {	/* nuke the socket if closed */
+      sock_close (stream->tcps);
+      fs_give ((void **) &stream->tcps);
+      return NIL;
+    }
+  }
+  return T;
+}
+
+/* TCP/IP send string as record
+ * Accepts: TCP/IP stream
+ * Returns: T if success else NIL
+ */
+
+long tcp_soutr (TCPSTREAM *stream,char *string)
+{
+				/* output the cruft */
+  sock_puts (stream->tcps,string);
+  return T;			/* all done */
+}
+
+
+/* TCP/IP send string
+ * Accepts: TCP/IP stream
+ *	    string pointer
+ *	    byte count
+ * Returns: T if success else NIL
+ */
+
+long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
+{
+  sock_write (stream->tcps,string,(int) size);
+  return T;
+}
+
+
+/* TCP/IP close
+ * Accepts: TCP/IP stream
+ */
+
+void tcp_close (TCPSTREAM *stream)
+{
+  if (stream->tcps){ 		/* nuke the socket */
+    sock_close (stream->tcps);
+    _ip_delay2 (stream->tcps,0,NULL,NULL);
+  }
+  fs_give ((void **) &stream->tcps);
+				/* flush host names */
+  fs_give ((void **) &stream->host);
+  fs_give ((void **) &stream->localhost);
+  fs_give ((void **) &stream);	/* flush the stream */
+}
+
+/* TCP/IP get host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_host (TCPSTREAM *stream)
+{
+  return stream->host;		/* return host name */
+}
+
+
+/* TCP/IP get remote host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_remotehost (TCPSTREAM *stream)
+{
+  return stream->host;		/* return host name */
+}
+
+
+/* TCP/IP return port for this stream
+ * Accepts: TCP/IP stream
+ * Returns: port number for this stream
+ */
+
+unsigned long tcp_port (TCPSTREAM *stream)
+{
+  return stream->port;		/* return port number */
+}
+
+
+/* TCP/IP get local host name
+ * Accepts: TCP/IP stream
+ * Returns: local host name
+ */
+
+char *tcp_localhost (TCPSTREAM *stream)
+{
+  return stream->localhost;	/* return local host name */
+}
+
+
+/* TCP/IP return canonical form of host name
+ * Accepts: host name
+ * Returns: canonical form of host name
+ */
+
+char *tcp_canonical (char *name)
+{
+  return name;
+}
+
+
+/* TCP/IP get client host name (server calls only)
+ * Returns: client host name
+ */
+
+char *tcp_clienthost ()
+{
+  return "UNKNOWN";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/tcp_dwa.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,45 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Waterloo DOS TCP/IP routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 April 1989
+ * Last Edited:	30 August 2006
+ */
+
+/* TCP input buffer -- must be large enough to prevent overflow */
+
+#define BUFLEN 8192
+
+
+/* TCP I/O stream (must be before osdep.h is included) */
+
+#define TCPSTREAM struct tcp_stream
+TCPSTREAM {
+  char *host;			/* host name */
+  unsigned long port;		/* port number */
+  char *localhost;		/* local host name */
+  tcp_Socket *tcps;		/* tcp socket */
+  long ictr;			/* input counter */
+  char *iptr;			/* input pointer */
+  char ibuf[BUFLEN];		/* input buffer */
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/tcp_wsk.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,818 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Winsock TCP/IP routines
+ *
+ * Author:	Mark Crispin from Mike Seibel's Winsock code
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 April 1989
+ * Last Edited:	13 January 2008
+ */
+
+
+#define TCPMAXSEND 32768
+
+/* Private functions */
+
+int tcp_socket_open (struct sockaddr_in *sin,char *tmp,char *hst,
+		     unsigned long port);
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+			       long *contd);
+long tcp_abort (TCPSTREAM *stream);
+long tcp_close_socket (SOCKET *sock);
+char *tcp_name (struct sockaddr_in *sin,long flag);
+char *tcp_name_valid (char *s);
+
+
+/* Private data */
+
+int wsa_initted = 0;		/* init ? */
+static int wsa_sock_open = 0;	/* keep track of open sockets */
+static tcptimeout_t tmoh = NIL;	/* TCP timeout handler routine */
+static long ttmo_read = 0;	/* TCP timeouts, in seconds */
+static long ttmo_write = 0;
+static long allowreversedns = T;/* allow reverse DNS lookup */
+static long tcpdebug = NIL;	/* extra TCP debugging telemetry */
+
+/* TCP/IP manipulate parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *tcp_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case SET_TIMEOUT:
+    tmoh = (tcptimeout_t) value;
+  case GET_TIMEOUT:
+    ret = (void *) tmoh;
+    break;
+  case SET_READTIMEOUT:
+    ttmo_read = (long) value;
+  case GET_READTIMEOUT:
+    ret = (void *) ttmo_read;
+    break;
+  case SET_WRITETIMEOUT:
+    ttmo_write = (long) value;
+  case GET_WRITETIMEOUT:
+    ret = (void *) ttmo_write;
+    break;
+  case SET_ALLOWREVERSEDNS:
+    allowreversedns = (long) value;
+  case GET_ALLOWREVERSEDNS:
+    ret = (void *) allowreversedns;
+    break;
+  case SET_TCPDEBUG:
+    tcpdebug = (long) value;
+  case GET_TCPDEBUG:
+    ret = (void *) tcpdebug;
+    break;
+  }
+  return ret;
+}
+
+/* TCP/IP open
+ * Accepts: host name
+ *	    contact service name
+ *	    contact port number and optional silent flag
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
+{
+  TCPSTREAM *stream = NIL;
+  int i;
+  SOCKET sock = INVALID_SOCKET;
+  int silent = (port & NET_SILENT) ? T : NIL;
+  char *s;
+  struct sockaddr_in sin;
+  struct hostent *he;
+  char hostname[MAILTMPLEN];
+  char tmp[MAILTMPLEN];
+  struct servent *sv = NIL;
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  if (!wsa_initted++) {		/* init Windows Sockets */
+    WSADATA wsock;
+    if (i = (int) WSAStartup (WSA_VERSION,&wsock)) {
+      wsa_initted = 0;		/* in case we try again */
+      sprintf (tmp,"Unable to start Windows Sockets (%d)",i);
+      mm_log (tmp,ERROR);
+      return NIL;
+    }
+  }
+  port &= 0xffff;		/* erase flags */
+				/* lookup service */
+  if (service && (sv = getservbyname (service,"tcp")))
+    port = ntohs (sin.sin_port = sv->s_port);
+ 				/* copy port number in network format */
+  else sin.sin_port = htons ((u_short) port);
+  /* The domain literal form is used (rather than simply the dotted decimal
+     as with other Windows programs) because it has to be a valid "host name"
+     in mailsystem terminology. */
+  sin.sin_family = AF_INET;	/* family is always Internet */
+				/* look like domain literal? */
+  if (host[0] == '[' && host[(strlen (host))-1] == ']') {
+    strcpy (tmp,host+1);	/* yes, copy number part */
+    tmp[strlen (tmp)-1] = '\0';
+    if ((sin.sin_addr.s_addr = inet_addr (tmp)) == INADDR_NONE) {
+      sprintf (tmp,"Bad format domain-literal: %.80s",host);
+      mm_log (tmp,ERROR);
+      return NIL;
+    }
+    else {
+      sin.sin_family = AF_INET;	/* family is always Internet */
+      strcpy (hostname,host);
+      (*bn) (BLOCK_TCPOPEN,NIL);
+      sock = tcp_socket_open (&sin,tmp,hostname,port);
+      (*bn) (BLOCK_NONE,NIL);
+    }
+  }
+
+  else {			/* lookup host name */
+    if (tcpdebug) {
+      sprintf (tmp,"DNS resolution %.80s",host);
+      mm_log (tmp,TCPDEBUG);
+    }
+    (*bn) (BLOCK_DNSLOOKUP,NIL);/* look up name */
+    if (!(he = gethostbyname (lcase (strcpy (tmp,host)))))
+      sprintf (tmp,"Host not found (#%d): %s",WSAGetLastError(),host);
+    (*bn) (BLOCK_NONE,NIL);
+    if (he) {			/* DNS resolution won? */
+      if (tcpdebug) mm_log ("DNS resolution done",TCPDEBUG);
+				/* copy address type */
+      sin.sin_family = he->h_addrtype;
+				/* copy host name */
+      strcpy (hostname,he->h_name);
+      wsa_sock_open++;		/* prevent tcp_close_socket() from freeing in
+				   loop */
+      for (i = 0; (sock == INVALID_SOCKET) && (s = he->h_addr_list[i]); i++) {
+	if (i && !silent) mm_log (tmp,WARN);
+	memcpy (&sin.sin_addr,s,he->h_length);
+	(*bn) (BLOCK_TCPOPEN,NIL);
+	sock = tcp_socket_open (&sin,tmp,hostname,port);
+	(*bn) (BLOCK_NONE,NIL);
+      }
+      wsa_sock_open--;		/* undo protection */
+    }
+  }
+  if (sock == INVALID_SOCKET) {	/* error? */
+    if (!silent) mm_log (tmp,ERROR);
+    tcp_close_socket (&sock);	/* do possible cleanup action */
+  }
+  else {			/* got a socket, create TCP/IP stream */
+    stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0,
+				   sizeof (TCPSTREAM));
+    stream->port = port;	/* port number */
+				/* init socket */
+    stream->tcpsi = stream->tcpso = sock;
+    stream->ictr = 0;		/* init input counter */
+				/* copy official host name */
+    stream->host = cpystr (hostname);
+    if (tcpdebug) mm_log ("Stream open and ready for read",TCPDEBUG);
+  }
+  return stream;		/* return success */
+}
+
+/* Open a TCP socket
+ * Accepts: Internet socket address block
+ *	    scratch buffer
+ *	    host name for error message
+ *	    port number for error message
+ * Returns: socket if success, else -1 with error string in scratch buffer
+ */
+
+int tcp_socket_open (struct sockaddr_in *sin,char *tmp,char *hst,
+		     unsigned long port)
+{
+  int sock;
+  char *s;
+  sprintf (tmp,"Trying IP address [%s]",inet_ntoa (sin->sin_addr));
+  mm_log (tmp,NIL);
+				/* get a TCP stream */
+  if ((sock = socket (sin->sin_family,SOCK_STREAM,0)) == INVALID_SOCKET) {
+    sprintf (tmp,"Unable to create TCP socket (%d)",WSAGetLastError());
+    return -1;
+  }
+  wsa_sock_open++;		/* count this socket as open */
+				/* open connection */
+  if (connect (sock,(struct sockaddr *) sin,sizeof (struct sockaddr_in)) ==
+      SOCKET_ERROR) {
+    switch (WSAGetLastError ()){/* analyze error */
+    case WSAECONNREFUSED:
+      s = "Refused";
+      break;
+    case WSAENOBUFS:
+      s = "Insufficient system resources";
+      break;
+    case WSAETIMEDOUT:
+      s = "Timed out";
+      break;
+    case WSAEHOSTUNREACH:
+      s = "Host unreachable";
+      break;
+    default:
+      s = "Unknown error";
+      break;
+    }
+    sprintf (tmp,"Can't connect to %.80s,%ld: %s (%d)",hst,port,s,
+	     WSAGetLastError ());
+    tcp_close_socket (&sock);	/* flush socket */
+    sock = INVALID_SOCKET;
+  }
+  return sock;			/* return the socket */
+}
+  
+/* TCP/IP authenticated open
+ * Accepts: NETMBX specifier
+ *	    service name
+ *	    returned user name buffer
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
+{
+  return NIL;			/* always NIL on Windows */
+}
+
+/* TCP receive line
+ * Accepts: TCP stream
+ * Returns: text line string or NIL if failure
+ */
+
+char *tcp_getline (TCPSTREAM *stream)
+{
+  unsigned long n,contd;
+  char *ret = tcp_getline_work (stream,&n,&contd);
+  if (ret && contd) {		/* got a line needing continuation? */
+    STRINGLIST *stl = mail_newstringlist ();
+    STRINGLIST *stc = stl;
+    do {			/* collect additional lines */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+      stc = stc->next = mail_newstringlist ();
+      ret = tcp_getline_work (stream,&n,&contd);
+    } while (ret && contd);
+    if (ret) {			/* stash final part of line on list */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+				/* determine how large a buffer we need */
+      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
+      ret = fs_get (n + 1);	/* copy parts into buffer */
+      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
+	memcpy (ret + n,stc->text.data,stc->text.size);
+      ret[n] = '\0';
+    }
+    mail_free_stringlist (&stl);/* either way, done with list */
+  }
+  return ret;
+}
+
+/* TCP receive line or partial line
+ * Accepts: TCP stream
+ *	    pointer to return size
+ *	    pointer to return continuation flag
+ * Returns: text line string, size and continuation flag, or NIL if failure
+ */
+
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+			       long *contd)
+{
+  unsigned long n;
+  char *s,*ret,c,d;
+  *contd = NIL;			/* assume no continuation */
+				/* make sure have data */
+  if (!tcp_getdata (stream)) return NIL;
+  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
+    d = *stream->iptr++;	/* slurp another character */
+    if ((c == '\015') && (d == '\012')) {
+      ret = (char *) fs_get (n--);
+      memcpy (ret,s,*size = n);	/* copy into a free storage string */
+      ret[n] = '\0';		/* tie off string with null */
+      return ret;
+    }
+  }
+				/* copy partial string from buffer */
+  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
+				/* get more data from the net */
+  if (!tcp_getdata (stream)) fs_give ((void **) &ret);
+				/* special case of newline broken by buffer */
+  else if ((c == '\015') && (*stream->iptr == '\012')) {
+    stream->iptr++;		/* eat the line feed */
+    stream->ictr--;
+    ret[*size = --n] = '\0';	/* tie off string with null */
+  }
+  else *contd = LONGT;		/* continuation needed */
+  return ret;
+}
+
+/* TCP/IP receive buffer
+ * Accepts: TCP/IP stream
+ *	    size in bytes
+ *	    buffer to read into
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *s)
+{
+  unsigned long n;
+				/* make sure socket still alive */
+  if (stream->tcpsi == INVALID_SOCKET) return NIL;
+				/* can transfer bytes from buffer? */
+  if (n = min (size,stream->ictr)) {
+    memcpy (s,stream->iptr,n);	/* yes, slurp as much as we can from it */
+    s += n;			/* update pointer */
+    stream->iptr +=n;
+    size -= n;			/* update # of bytes to do */
+    stream->ictr -=n;
+  }
+  if (size) {
+    int i;
+    fd_set fds;
+    struct timeval tmo;
+    time_t tc,t = time (0);
+    blocknotify_t bn=(blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+    (*bn) (BLOCK_TCPREAD,NIL);
+    while (size > 0) {		/* until request satisfied */
+      time_t tl = time (0);
+      if (tcpdebug) mm_log ("Reading TCP buffer",TCPDEBUG);
+      FD_ZERO (&fds);		/* initialize selection vector */
+      FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */
+      tmo.tv_sec = ttmo_read;
+      tmo.tv_usec = 0;
+				/* block and read */
+      switch ((stream->tcpsi == stream->tcpso) ?
+	      select (stream->tcpsi+1,&fds,0,0,
+		      ttmo_read ? &tmo : (struct timeval *) 0) : 1) {
+      case SOCKET_ERROR:		/* error */
+	if (WSAGetLastError () != WSAEINTR) return tcp_abort (stream);
+	break;
+      case 0:			/* timeout */
+	tc = time (0);
+	if (tmoh && ((*tmoh) (tc - t,tc - tl))) break;
+	return tcp_abort (stream);
+      default:
+	if (stream->tcpsi == stream->tcpso)
+	  while (((i = recv (stream->tcpsi,s,(int) min (maxposint,size),0)) ==
+		  SOCKET_ERROR) && (WSAGetLastError () == WSAEINTR));
+	else while (((i = read (stream->tcpsi,s,(int) min (maxposint,size))) <
+		     0) && (errno == EINTR));
+	switch (i) {
+	case SOCKET_ERROR:	/* error */
+	case 0:			/* no data read */
+	  return tcp_abort (stream);
+	default:
+	  s += i;		/* point at new place to write */
+	  size -= i;		/* reduce byte count */
+	  if (tcpdebug) mm_log ("Successfully read TCP buffer",TCPDEBUG);
+	}
+      }
+    }
+    (*bn) (BLOCK_NONE,NIL);
+  }
+  *s = '\0';			/* tie off string */
+  return T;
+}
+
+/* TCP/IP receive data
+ * Accepts: TCP/IP stream
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getdata (TCPSTREAM *stream)
+{
+  struct timeval tmo;
+  int i;
+  fd_set fds;
+  time_t tc,t = time (0);
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  FD_ZERO (&fds);		/* initialize selection vector */
+  if (stream->tcpsi == INVALID_SOCKET) return NIL;
+  (*bn) (BLOCK_TCPREAD,NIL);
+  tmo.tv_sec = ttmo_read;
+  tmo.tv_usec = 0;
+  while (stream->ictr < 1) {	/* if nothing in the buffer */
+    time_t tl = time (0);
+    if (tcpdebug) mm_log ("Reading TCP data",TCPDEBUG);
+    FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */
+				/* block and read */
+    switch ((stream->tcpsi == stream->tcpso) ?
+	    select (stream->tcpsi+1,&fds,0,0,
+		    ttmo_read ? &tmo : (struct timeval *) 0) : 1) {
+    case SOCKET_ERROR:		/* error */
+      if (WSAGetLastError () != WSAEINTR) return tcp_abort (stream);
+      break;
+    case 0:			/* timeout */
+      tc = time (0);
+      if (tmoh && ((*tmoh) (tc - t,tc - tl))) break;
+      return tcp_abort (stream);
+    default:
+      if (stream->tcpsi == stream->tcpso)
+	while (((i = recv (stream->tcpsi,stream->ibuf,BUFLEN,0)) ==
+		SOCKET_ERROR) && (WSAGetLastError () == WSAEINTR));
+      else while (((i = read (stream->tcpsi,stream->ibuf,BUFLEN)) < 0) &&
+		  (errno == EINTR));
+      switch (i) {
+      case SOCKET_ERROR:	/* error */
+      case 0:			/* no data read */
+	return tcp_abort (stream);
+      default:
+	stream->ictr = i;	/* set new byte count */
+				/* point at TCP buffer */
+	stream->iptr = stream->ibuf;
+	if (tcpdebug) mm_log ("Successfully read TCP data",TCPDEBUG);
+      }
+    }
+  }
+  (*bn) (BLOCK_NONE,NIL);
+  return T;
+}
+
+/* TCP/IP send string as record
+ * Accepts: TCP/IP stream
+ *	    string pointer
+ * Returns: T if success else NIL
+ */
+
+long tcp_soutr (TCPSTREAM *stream,char *string)
+{
+  return tcp_sout (stream,string,(unsigned long) strlen (string));
+}
+
+
+/* TCP/IP send string
+ * Accepts: TCP/IP stream
+ *	    string pointer
+ *	    byte count
+ * Returns: T if success else NIL
+ */
+
+long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
+{
+  int i;
+  struct timeval tmo;
+  fd_set fds;
+  time_t tc,t = time (0);
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  tmo.tv_sec = ttmo_write;
+  tmo.tv_usec = 0;
+  FD_ZERO (&fds);		/* initialize selection vector */
+  if (stream->tcpso == INVALID_SOCKET) return NIL;
+  (*bn) (BLOCK_TCPWRITE,NIL);
+  while (size > 0) {		/* until request satisfied */
+    time_t tl = time (0);
+    if (tcpdebug) mm_log ("Writing to TCP",TCPDEBUG);
+    FD_SET (stream->tcpso,&fds);/* set bit in selection vector */
+				/* block and write */
+    switch ((stream->tcpsi == stream->tcpso) ?
+	    select (stream->tcpso+1,NULL,&fds,NULL,
+		    tmo.tv_sec ? &tmo : (struct timeval *) 0) : 1) {
+    case SOCKET_ERROR:		/* error */
+      if (WSAGetLastError () != WSAEINTR) return tcp_abort (stream);
+      break;
+    case 0:			/* timeout */
+      tc = time (0);
+      if (tmoh && ((*tmoh) (tc - t,tc - tl))) break;
+      return tcp_abort (stream);
+    default:
+      if (stream->tcpsi == stream->tcpso)
+	while (((i = send (stream->tcpso,string,
+			   (int) min (size,TCPMAXSEND),0)) == SOCKET_ERROR) &&
+	       (WSAGetLastError () == WSAEINTR));
+      else while (((i = write (stream->tcpso,string,
+			       min (size,TCPMAXSEND))) < 0) &&
+		  (errno == EINTR));
+      if (i == SOCKET_ERROR) return tcp_abort (stream);
+      size -= i;		/* count this size */
+      if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG);
+      string += i;
+    }
+  }
+  (*bn) (BLOCK_NONE,NIL);
+  return T;			/* all done */
+}
+
+
+/* TCP/IP close
+ * Accepts: TCP/IP stream
+ */
+
+void tcp_close (TCPSTREAM *stream)
+{
+  tcp_abort (stream);		/* nuke the sockets */
+				/* flush host names */
+  if (stream->host) fs_give ((void **) &stream->host);
+  if (stream->remotehost) fs_give ((void **) &stream->remotehost);
+  if (stream->localhost) fs_give ((void **) &stream->localhost);
+  fs_give ((void **) &stream);	/* flush the stream */
+}
+
+
+/* TCP/IP abort sockets
+ * Accepts: TCP/IP stream
+ * Returns: NIL, always
+ */
+
+long tcp_abort (TCPSTREAM *stream)
+{
+  if (stream->tcpsi != stream->tcpso) tcp_close_socket (&stream->tcpso);
+  else stream->tcpso = INVALID_SOCKET;
+  return tcp_close_socket (&stream->tcpsi);
+}
+
+
+/* TCP/IP abort stream
+ * Accepts: WinSock socket
+ * Returns: NIL, always
+ */
+
+long tcp_close_socket (SOCKET *sock)
+{
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+				/* something to close? */
+  if (sock && (*sock != INVALID_SOCKET)) {
+    (*bn) (BLOCK_TCPCLOSE,NIL);
+    closesocket (*sock);	/* WinSock socket close */
+    *sock = INVALID_SOCKET;
+    (*bn) (BLOCK_NONE,NIL);
+    wsa_sock_open--;		/* drop this socket */
+  }
+				/* no more open streams? */
+  if (wsa_initted && !wsa_sock_open) {
+    mm_log ("Winsock cleanup",NIL);
+    wsa_initted = 0;		/* no more sockets, so... */
+    WSACleanup ();		/* free up resources until needed */
+  }
+  return NIL;
+}
+
+/* TCP/IP get host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_host (TCPSTREAM *stream)
+{
+  return stream->host;		/* use tcp_remotehost() if want guarantees */
+}
+
+
+/* TCP/IP get remote host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_remotehost (TCPSTREAM *stream)
+{
+  if (!stream->remotehost) {
+    struct sockaddr_in sin;
+    int sinlen = sizeof (struct sockaddr_in);
+    stream->remotehost =	/* get socket's peer name */
+      ((getpeername (stream->tcpsi,(struct sockaddr *) &sin,&sinlen) ==
+	SOCKET_ERROR) || (sinlen <= 0)) ?
+	  cpystr (stream->host) : tcp_name (&sin,NIL);
+  }
+  return stream->remotehost;
+}
+
+
+/* TCP/IP return port for this stream
+ * Accepts: TCP/IP stream
+ * Returns: port number for this stream
+ */
+
+unsigned long tcp_port (TCPSTREAM *stream)
+{
+  return stream->port;		/* return port number */
+}
+
+
+/* TCP/IP get local host name
+ * Accepts: TCP/IP stream
+ * Returns: local host name
+ */
+
+char *tcp_localhost (TCPSTREAM *stream)
+{
+  if (!stream->localhost) {
+    struct sockaddr_in sin;
+    int sinlen = sizeof (struct sockaddr_in);
+    stream->localhost =		/* get socket's name */
+      ((stream->port & 0xffff000) ||
+       ((getsockname (stream->tcpsi,(struct sockaddr *) &sin,&sinlen) ==
+	 SOCKET_ERROR) || (sinlen <= 0))) ?
+	   cpystr (mylocalhost ()) : tcp_name (&sin,NIL);
+  }
+  return stream->localhost;	/* return local host name */
+}
+
+/* TCP/IP get client host address (server calls only)
+ * Returns: client host address
+ */
+
+char *tcp_clientaddr ()
+{
+  if (!myClientAddr) {
+    struct sockaddr_in sin;
+    int sinlen = sizeof (struct sockaddr_in);
+    myClientAddr =		/* get stdin's peer name */
+      ((getpeername (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) ||
+       (sinlen <= 0)) ? cpystr ("UNKNOWN") : cpystr (inet_ntoa (sin.sin_addr));
+  }
+  return myClientAddr;
+}
+
+
+/* TCP/IP get client host name (server calls only)
+ * Returns: client host name
+ */
+
+char *tcp_clienthost ()
+{
+  if (!myClientHost) {
+    struct sockaddr_in sin;
+    int sinlen = sizeof (struct sockaddr_in);
+    myClientHost =		/* get stdin's peer name */
+      ((getpeername (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) ||
+       (sinlen <= 0)) ? cpystr ("UNKNOWN") : tcp_name (&sin,T);
+  }
+  return myClientHost;
+}
+
+/* TCP/IP get server host address (server calls only)
+ * Returns: server host address
+ */
+
+char *tcp_serveraddr ()
+{
+  if (!myServerAddr) {
+    struct sockaddr_in sin;
+    int sinlen = sizeof (struct sockaddr_in);
+    myServerAddr =		/* get stdin's peer name */
+      ((getsockname (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) ||
+       (sinlen <= 0)) ? cpystr ("UNKNOWN") : cpystr (inet_ntoa (sin.sin_addr));
+  }
+  return myServerAddr;
+}
+
+
+/* TCP/IP get server host name (server calls only)
+ * Returns: server host name
+ */
+
+static long myServerPort = -1;
+
+char *tcp_serverhost ()
+{
+  if (!myServerHost) {
+    struct sockaddr_in sin;
+    int sinlen = sizeof (struct sockaddr_in);
+    if (!wsa_initted++) {	/* init Windows Sockets */
+      WSADATA wsock;
+      if (WSAStartup (WSA_VERSION,&wsock)) {
+	wsa_initted = 0;
+	return "random-pc";	/* try again later? */
+      }
+    }
+				/* get stdin's name */
+    if ((getsockname (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) ||
+	(sinlen <= 0)) myServerHost = cpystr (mylocalhost ());
+    else {
+      myServerHost = tcp_name (&sin,NIL);
+      myServerPort = ntohs (sin.sin_port);
+    }
+  }
+  return myServerHost;
+}
+
+
+/* TCP/IP get server port number (server calls only)
+ * Returns: server port number
+ */
+
+long tcp_serverport ()
+{
+  if (!myServerHost) tcp_serverhost ();
+  return myServerPort;
+}
+
+/* TCP/IP return canonical form of host name
+ * Accepts: host name
+ * Returns: canonical form of host name
+ */
+
+char *tcp_canonical (char *name)
+{
+  char *ret,host[MAILTMPLEN];
+  struct hostent *he;
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+				/* look like domain literal? */
+  if (name[0] == '[' && name[strlen (name) - 1] == ']') return name;
+  (*bn) (BLOCK_DNSLOOKUP,NIL);
+  if (tcpdebug) {
+    sprintf (host,"DNS canonicalization %.80s",name);
+    mm_log (host,TCPDEBUG);
+  }
+				/* note that NT requires lowercase! */
+  ret = (he = gethostbyname (lcase (strcpy (host,name)))) ? he->h_name : name;
+  (*bn) (BLOCK_NONE,NIL);
+  if (tcpdebug) mm_log ("DNS canonicalization done",TCPDEBUG);
+  return ret;
+}
+
+
+/* TCP/IP return name from socket
+ * Accepts: socket
+ *	    verbose flag
+ * Returns: cpystr name
+ */
+
+char *tcp_name (struct sockaddr_in *sin,long flag)
+{
+  char *ret,*t,adr[MAILTMPLEN],tmp[MAILTMPLEN];
+  sprintf (ret = adr,"[%.80s]",inet_ntoa (sin->sin_addr));
+  if (allowreversedns) {
+    struct hostent *he;
+    blocknotify_t bn = (blocknotify_t)mail_parameters(NIL,GET_BLOCKNOTIFY,NIL);
+    void *data;
+    if (tcpdebug) {
+      sprintf (tmp,"Reverse DNS resolution %s",adr);
+      mm_log (tmp,TCPDEBUG);
+    }
+    (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */
+    data = (*bn) (BLOCK_SENSITIVE,NIL);
+				/* translate address to name */
+    if (t = tcp_name_valid ((he = gethostbyaddr ((char *) &sin->sin_addr,
+						 sizeof (struct in_addr),
+						 sin->sin_family)) ?
+			    (char *) he->h_name : NIL)) {
+				/* produce verbose form if needed */
+      if (flag)	sprintf (ret = tmp,"%s %s",t,adr);
+      else ret = t;
+    }
+    (*bn) (BLOCK_NONSENSITIVE,data);
+    (*bn) (BLOCK_NONE,NIL);	/* alarms OK now */
+    if (tcpdebug) mm_log ("Reverse DNS resolution done",TCPDEBUG);
+  }
+  return cpystr (ret);
+}
+
+/* Return my local host name
+ * Returns: my local host name
+ */
+
+char *mylocalhost (void)
+{
+  if (!myLocalHost) {
+    char tmp[MAILTMPLEN];
+    if (!wsa_initted++) {	/* init Windows Sockets */
+      WSADATA wsock;
+      if (WSAStartup (WSA_VERSION,&wsock)) {
+	wsa_initted = 0;
+	return "random-pc";	/* try again later? */
+      }
+    }
+    myLocalHost = cpystr ((gethostname (tmp,MAILTMPLEN-1) == SOCKET_ERROR) ?
+			  "random-pc" : tcp_canonical (tmp));
+  }
+  return myLocalHost;
+}
+
+
+/* Validate name
+ * Accepts: domain name
+ * Returns: T if valid, NIL otherwise
+ */
+
+char *tcp_name_valid (char *s)
+{
+  int c;
+  char *ret,*tail;
+				/* must be non-empty and not too long */
+  if ((ret = (s && *s) ? s : NIL) && (tail = ret + NETMAXHOST)) {
+				/* must be alnum, dot, or hyphen */
+    while ((c = *s++) && (s <= tail) &&
+	   (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) ||
+	    ((c >= '0') && (c <= '9')) || (c == '-') || (c == '.')));
+    if (c) ret = NIL;
+  }
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/tcp_wsk.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,50 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Winsock TCP/IP routines
+ *
+ * Author:	Mike Seibel from Unix version by Mark Crispin
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 April 1989
+ * Last Edited:	30 August 2006
+ */
+
+/* TCP input buffer -- must be large enough to prevent overflow */
+
+#define BUFLEN 16384		/* 32768 causes stdin read() to barf */
+
+#include <windows.h>
+#define _INC_WINDOWS
+#include <winsock.h>
+
+
+/* TCP I/O stream (must be before osdep.h is included) */
+
+#define TCPSTREAM struct tcp_stream
+TCPSTREAM {
+  char *host;			/* host name */
+  char *remotehost;		/* remote host name */
+  unsigned long port;		/* port number */
+  char *localhost;		/* local host name */
+  SOCKET tcpsi;			/* tcp socket */
+  SOCKET tcpso;			/* tcp socket */
+  long ictr;			/* input counter */
+  char *iptr;			/* input pointer */
+  char ibuf[BUFLEN];		/* input buffer */
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/dos/write.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,59 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Write data, treating partial writes as an error
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	26 May 1995
+ * Last Edited:	30 August 2006
+ */
+
+/*  The whole purpose of this unfortunate routine is to deal with DOS and
+ * certain cretinous versions of UNIX which decided that the "bytes actually
+ * written" return value from write() gave them license to use that for things
+ * that are really errors, such as disk quota exceeded, maximum file size
+ * exceeded, disk full, etc.
+ * 
+ *  BSD won't screw us this way on the local filesystem, but who knows what
+ * some NFS-mounted filesystem will do.
+ */
+
+#undef write
+
+/* Write data to file
+ * Accepts: file descriptor
+ *	    I/O vector structure
+ *	    number of vectors in structure
+ * Returns: number of bytes written if successful, -1 if failure
+ */
+
+long maxposint = (long)((((unsigned long) 1) << ((sizeof(int) * 8) - 1)) - 1);
+
+long safe_write (int fd,char *buf,long nbytes)
+{
+  long i,j;
+  if (nbytes > 0) for (i = nbytes; i; i -= j,buf += j) {
+    while (((j = write (fd,buf,(int) min (maxposint,i))) < 0) &&
+	   (errno == EINTR));
+    if (j < 0) return j;
+  }
+  return nbytes;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/mac/dummy.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,43 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Dummy routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	9 May 1991
+ * Last Edited:	30 August 2006
+ */
+
+/* Exported function prototypes */
+
+void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void dummy_list (MAILSTREAM *stream,char *ref,char *pat);
+void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long scan_contents (DRIVER *dtb,char *name,char *contents,
+		    unsigned long csiz,unsigned long fsiz);
+long dummy_scan_contents (char *name,char *contents,unsigned long csiz,
+			  unsigned long fsiz);
+long dummy_create (MAILSTREAM *stream,char *mailbox);
+long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode);
+long dummy_delete (MAILSTREAM *stream,char *mailbox);
+long dummy_rename (MAILSTREAM *stream,char *old,char *newname);
+char *dummy_file (char *dst,char *name);
+long dummy_canonicalize (char *tmp,char *ref,char *pat);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/mac/dummymac.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,295 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Dummy routines for Mac
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	24 May 1993
+ * Last Edited:	30 August 2006
+ */
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include "mail.h"
+#include "osdep.h"
+#include "dummy.h"
+#include "misc.h"
+
+/* Function prototypes */
+
+DRIVER *dummy_valid (char *name);
+void *dummy_parameters (long function,void *value);
+MAILSTREAM *dummy_open (MAILSTREAM *stream);
+void dummy_close (MAILSTREAM *stream,long options);
+long dummy_ping (MAILSTREAM *stream);
+void dummy_check (MAILSTREAM *stream);
+long dummy_expunge (MAILSTREAM *stream,char *sequence,long options);
+long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+/* Dummy routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER dummydriver = {
+  "dummy",			/* driver name */
+  DR_LOCAL|DR_MAIL,		/* driver flags */
+  (DRIVER *) NIL,		/* next driver */
+  dummy_valid,			/* mailbox is valid for us */
+  dummy_parameters,		/* manipulate parameters */
+  dummy_scan,			/* scan mailboxes */
+  dummy_list,			/* list mailboxes */
+  dummy_lsub,			/* list subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  dummy_create,			/* create mailbox */
+  dummy_delete,			/* delete mailbox */
+  dummy_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  dummy_open,			/* open mailbox */
+  dummy_close,			/* close mailbox */
+  NIL,				/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message structure */
+  NIL,				/* fetch header */
+  NIL,				/* fetch text */
+  NIL,				/* fetch message data */
+  NIL,				/* unique identifier */
+  NIL,				/* message number from UID */
+  NIL,				/* modify flags */
+  NIL,				/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  dummy_ping,			/* ping mailbox to see if still alive */
+  dummy_check,			/* check for new messages */
+  dummy_expunge,		/* expunge deleted messages */
+  dummy_copy,			/* copy messages to another mailbox */
+  dummy_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+
+				/* prototype stream */
+MAILSTREAM dummyproto = {&dummydriver};
+
+/* Dummy validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *dummy_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+				/* must be valid local mailbox */
+  return (name && *name && (*name != '{') && !compare_cstring (name,"INBOX")) ?
+    &dummydriver : NIL;
+}
+
+
+/* Dummy manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *dummy_parameters (long function,void *value)
+{
+  return NIL;
+}
+
+/* Dummy scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+				/* return silently */
+}
+
+
+/* Dummy list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void dummy_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+				/* return silently */
+}
+
+
+/* Dummy list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+				/* return silently */
+}
+
+/* Dummy create mailbox
+ * Accepts: mail stream
+ *	    mailbox name to create
+ *	    driver type to use
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_create (MAILSTREAM *stream,char *mailbox)
+{
+  return NIL;			/* always fails */
+}
+
+
+/* Dummy delete mailbox
+ * Accepts: mail stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return NIL;			/* always fails */
+}
+
+
+/* Mail rename mailbox
+ * Accepts: mail stream
+ *	    old mailbox name
+ *	    new mailbox name
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  return NIL;			/* always fails */
+}
+
+/* Dummy open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *dummy_open (MAILSTREAM *stream)
+{
+  char tmp[MAILTMPLEN];
+				/* OP_PROTOTYPE call or silence */
+  if (!stream || stream->silent) return NIL;
+  if (compare_cstring (stream->mailbox,"INBOX")) {
+    sprintf (tmp,"Not a mailbox: %s",stream->mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;			/* always fails */
+  }
+  if (!stream->silent) {	/* only if silence not requested */
+    mail_exists (stream,0);	/* say there are 0 messages */
+    mail_recent (stream,0);
+    stream->uid_validity = time (0);
+  }
+  stream->inbox = T;		/* note that it's an INBOX */
+  return stream;		/* return success */
+}
+
+
+/* Dummy close
+ * Accepts: MAIL stream
+ *	    options
+ */
+
+void dummy_close (MAILSTREAM *stream,long options)
+{
+				/* return silently */
+}
+
+/* Dummy ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ * No-op for readonly files, since read/writer can expunge it from under us!
+ */
+
+long dummy_ping (MAILSTREAM *stream)
+{
+  return T;
+}
+
+
+/* Dummy check mailbox
+ * Accepts: MAIL stream
+ * No-op for readonly files, since read/writer can expunge it from under us!
+ */
+
+void dummy_check (MAILSTREAM *stream)
+{
+  dummy_ping (stream);		/* invoke ping */
+}
+
+
+/* Dummy expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long dummy_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  return LONGT;
+}
+
+/* Dummy copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    options
+ * Returns: T if copy successful, else NIL
+ */
+
+long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+      mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy");
+  return NIL;
+}
+
+
+/* Dummy append message string
+ * Accepts: mail stream
+ *	    destination mailbox
+ *	    append callback function
+ *	    data for callback
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  char tmp[MAILTMPLEN];
+  sprintf (tmp,"Can't append to %s",mailbox);
+  mm_log (tmp,ERROR);		/* pass up error */
+  return NIL;			/* always fails */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/mac/env_mac.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,236 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Mac environment routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	26 January 1992
+ * Last Edited:	30 August 2006
+ */
+
+
+static char *myHomeDir = NIL;	/* home directory name */
+static char *myLocalHost = NIL;	/* local host name */
+static char *myNewsrc = NIL;	/* newsrc file name */
+
+#include "pmatch.c"		/* include wildcard pattern matcher */
+
+/* Environment manipulate parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *env_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  char tmp[MAILTMPLEN];
+  switch ((int) function) {
+  case SET_HOMEDIR:
+    if (myHomeDir) fs_give ((void **) &myHomeDir);
+    myHomeDir = cpystr ((char *) value);
+  case GET_HOMEDIR:
+				/* set home directory if not defined */
+    if (!myHomeDir) myHomeDir = cpystr ("");
+    ret = (void *) myHomeDir;
+    break;
+  case SET_LOCALHOST:
+    myLocalHost = cpystr ((char *) value);
+  case GET_LOCALHOST:
+    ret = (void *) myLocalHost ? myLocalHost : "random-mac";
+    break;
+  case SET_NEWSRC:
+    if (myNewsrc) fs_give ((void **) &myNewsrc);
+    myNewsrc = cpystr ((char *) value);
+  case GET_NEWSRC:
+    if (!myNewsrc) {		/* set news file name if not defined */
+      sprintf (tmp,"%s:News State",myhomedir ());
+      myNewsrc = cpystr (tmp);
+    }
+    ret = (void *) myNewsrc;
+    break;
+  }
+  return ret;
+}
+
+/* Write current time
+ * Accepts: destination string
+ *	    format of date and time
+ *
+ * This depends upon the ReadLocation() call in System 7 and the
+ * user properly setting his location/timezone in the Map control
+ * panel.
+ * Nothing is done about the gmtFlags.dlsDelta byte yet, since I
+ * don't know how it's supposed to work.
+ */
+
+static void do_date (char *date,char *fmt)
+{
+  long tz,tzm;
+  time_t ti = time (0);
+  struct tm *t = localtime (&ti);
+  MachineLocation loc;
+  ReadLocation (&loc);		/* get location/timezone poop */
+				/* get sign-extended time zone */
+  tz = (loc.gmtFlags.gmtDelta & 0x00ffffff) |
+    ((loc.gmtFlags.gmtDelta & 0x00800000) ? 0xff000000 : 0);
+  tz /= 60;			/* get timezone in minutes */
+  tzm = tz % 60;		/* get minutes from the hour */
+				/* output time */
+  strftime (date,MAILTMPLEN,fmt,t);
+				/* now output time zone */
+  sprintf (date += strlen (date),"%+03ld%02ld",tz/60,tzm >= 0 ? tzm : -tzm);
+}
+
+
+/* Write current time in RFC 822 format
+ * Accepts: destination string
+ */
+
+void rfc822_date (char *date)
+{
+  do_date (date,"%a, %d %b %Y %H:%M:%S ");
+}
+
+
+/* Write current time in internal format
+ * Accepts: destination string
+ */
+
+void internal_date (char *date)
+{
+  do_date (date,"%2d-%b-%Y %H:%M:%S ");
+}
+
+/* Return my local host name
+ * Returns: my local host name
+ */
+
+char *mylocalhost (void)
+{
+  return (char *) mail_parameters (NIL,GET_LOCALHOST,NIL);
+}
+
+
+/* Return my home directory name
+ * Returns: my home directory name
+ */
+
+char *myhomedir ()
+{
+  return (char *) mail_parameters (NIL,GET_HOMEDIR,NIL);
+}
+
+
+/* Determine default prototype stream to user
+ * Accepts: type (NIL for create, T for append)
+ * Returns: default prototype stream
+ */
+
+MAILSTREAM *default_proto (long type)
+{
+  extern MAILSTREAM dummyproto;
+  return &dummyproto;		/* return default driver's prototype */
+}
+
+/* Block until event satisfied
+ * Called as: while (wait_condition && wait ());
+ * Returns T if OK, NIL if user wants to abort
+ *
+ * Allows user to run a desk accessory, select a different window, or go
+ * to another application while waiting for the event to finish.  COMMAND/.
+ * will abort the wait.
+ * Assumes the Apple menu has the apple character as its first character,
+ * and that the main program has disabled all other menus.
+ */
+
+long wait ()
+{
+  EventRecord event;
+  WindowPtr window;
+  MenuInfo **m;
+  long r;
+  Str255 tmp;
+				/* wait for an event */
+  WaitNextEvent (everyEvent,&event,(long) 6,NIL);
+  switch (event.what) {		/* got one -- what is it? */
+  case mouseDown:		/* mouse clicked */
+    switch (FindWindow (event.where,&window)) {
+    case inMenuBar:		/* menu bar item? */
+				/* yes, interesting event? */	
+      if (r = MenuSelect (event.where)) {
+				/* round-about test for Apple menu */
+	  if ((*(m = GetMHandle (HiWord (r))))->menuData[1] == appleMark) {
+				/* get desk accessory name */ 
+	  GetItem (m,LoWord (r),tmp);
+	  OpenDeskAcc (tmp);	/* fire it up */
+	  SetPort (window);	/* put us back at our window */
+	}
+	else SysBeep (60);	/* the fool forgot to disable it! */
+      }
+      HiliteMenu (0);		/* unhighlight it */
+      break;
+    case inContent:		/* some window was selected */
+      if (window != FrontWindow ()) SelectWindow (window);
+      break;
+    default:			/* ignore all others */
+      break;
+    }
+    break;
+  case keyDown:			/* key hit - if COMMAND/. then punt */
+    if ((event.modifiers & cmdKey) && (event.message & charCodeMask) == '.')
+      return NIL;
+    break;
+  default:			/* ignore all others */
+    break;
+  }
+  return T;			/* try wait test again */
+}
+
+/* Return random number
+ */
+
+long random ()
+{
+  return (long) rand () << 16 + rand ();
+}
+
+
+/* Emulator for BSD syslog() routine
+ * Accepts: priority
+ *	    message
+ *	    parameters
+ */
+
+void syslog (int priority,const char *message,...)
+{
+}
+
+
+/* Emulator for BSD openlog() routine
+ * Accepts: identity
+ *	    options
+ *	    facility
+ */
+
+void openlog (const char *ident,int logopt,int facility)
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/mac/env_mac.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,58 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Macintosh environment routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	25 May 1995
+ * Last Edited:	30 August 2006
+ */
+
+
+#define SUBSCRIPTIONFILE(t) sprintf (t,"%s:Mailbox List",myhomedir ())
+#define SUBSCRIPTIONTEMP(t) sprintf (t,"%s:Mailbox List Temp",myhomedir ())
+
+/* Function prototypes */
+
+#include "env.h"
+
+
+/* syslog() emulation */
+
+#define LOG_MAIL	(2<<3)	/* mail system */
+#define LOG_DAEMON	(3<<3)	/* system daemons */
+#define LOG_AUTH	(4<<3)	/* security/authorization messages */
+#define LOG_EMERG	0	/* system is unusable */
+#define LOG_ALERT	1	/* action must be taken immediately */
+#define LOG_CRIT	2	/* critical conditions */
+#define LOG_ERR		3	/* error conditions */
+#define LOG_WARNING	4	/* warning conditions */
+#define LOG_NOTICE	5	/* normal but signification condition */
+#define LOG_INFO	6	/* informational */
+#define LOG_DEBUG	7	/* debug-level messages */
+#define LOG_PID		0x01	/* log the pid with each message */
+#define LOG_CONS	0x02	/* log on the console if errors in sending */
+#define LOG_ODELAY	0x04	/* delay open until syslog() is called */
+#define LOG_NDELAY	0x08	/* don't delay open */
+#define LOG_NOWAIT	0x10	/* if forking to log on console, don't wait() */
+
+void openlog (const char *ident,int logopt,int facility);
+void syslog (int priority,const char *message,...);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/mac/fs_mac.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,62 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Free storage management routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Get a block of free storage
+ * Accepts: size of desired block
+ * Returns: free storage block
+ */
+
+void *fs_get (size_t size)
+{
+  void *block = malloc (size ? size : (size_t) 1);
+  if (!block) fatal ("Out of memory");
+  return (block);
+}
+
+
+/* Resize a block of free storage
+ * Accepts: ** pointer to current block
+ *	    new size
+ */
+
+void fs_resize (void **block,size_t size)
+{
+  if (!(*block = realloc (*block,size ? size : (size_t) 1)))
+    fatal ("Can't resize memory");
+}
+
+
+/* Return a block of free storage
+ * Accepts: ** pointer to free storage block
+ */
+
+void fs_give (void **block)
+{
+  free (*block);
+  *block = NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/mac/ftl_mac.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,39 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Mac crash management routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	26 January 1992
+ * Last Edited:	30 August 2006
+ */
+
+/* Report a fatal error
+ * Accepts: string to output
+ */
+
+void fatal (char *string)
+{
+  mm_fatal (string);		/* pass up the string */
+				/* nuke the resolver */
+  if (resolveropen) CloseResolver ();
+  abort ();			/* die horribly */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/mac/linkage.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,37 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Default driver linkage
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	13 June 1995
+ * Last Edited:	23 May 2007
+ */
+
+  mail_link (&imapdriver);		/* link in the imap driver */
+  mail_link (&nntpdriver);		/* link in the nntp driver */
+  mail_link (&pop3driver);		/* link in the pop3 driver */
+  mail_link (&dummydriver);		/* link in the dummy driver */
+  auth_link (&auth_ext);		/* link in the ext authenticator */
+  auth_link (&auth_md5);		/* link in the md5 authenticator */
+  auth_link (&auth_pla);		/* link in the plain authenticator */
+  auth_link (&auth_log);		/* link in the log authenticator */
+  mail_versioncheck (CCLIENTVERSION);	/* validate version */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/mac/linkage.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,36 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Default driver linkage
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	13 June 1995
+ * Last Edited:	30 August 2006
+ */
+
+extern DRIVER imapdriver;
+extern DRIVER nntpdriver;
+extern DRIVER pop3driver;
+extern DRIVER dummydriver;
+extern AUTHENTICATOR auth_ext;
+extern AUTHENTICATOR auth_log;
+extern AUTHENTICATOR auth_md5;
+extern AUTHENTICATOR auth_pla;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/mac/mtest.sit.hqx	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,171 @@
+(This file must be converted with BinHex 4.0)
+:#@edCA0d,R0TG!"6594%8dP8)3#3""l`!!!"4[4p8dP8)3!#!!!Hm(*-BA8#bJ#
+3!aB"#Jd!$'edCA0d,VNZFR0bB`#3%j@,!*!8"h-!N!6rN!4bFh*M8P0&4!%!TFk
+UMDPEIVJ!!"f3!!#3"JEY!*!%`hJ!N!KIY3c!q+l(4rK4`['9YjP(D"GY*FH1(-X
+cXLBR0(,Fbb2([#i[,dqCK"rKGS3@iEFb3JQeji4&VeZ[1Tp``PGTPS4GCi46F[`
+)*dr*J*-T2h+-c2N46VMfC-$*Vi46-Z(N'*P4`L5F(#G2#5GiGT&MK"*'9LD!erG
+CjLAcHUq9(@&*RN@fj0Ne))``F[c)XC9`B,`kD)!("P!!B+%+X!"Ij9MdF'6TDbk
+eDS@rkBHYZjA")jZhqKjc,5mCd(FTrHqIGj@qeG-@lI&rjBp%)kdK&fVILa2,2T2
+)Nrd4Q1G"rm8Y@pe%8-SkIQSGk2H@qIe3dIJcJrAH1R9c&i2J#HpTbZ[82H$e3hN
+Gr+r1$kAiHS*IpmchqmF6`GH$qi)l!%)YfjZ9XS-II05ZY0Hd[$N205VQN@SCP1m
+)Y64Y8k#VBqraRH@Q)09I"'0XA!G`I`Z`"YrDNrJL[SBi1UackpVJ'9h60qKDB,'
+ZI9HZ+l((G5@JIUk!US1Z-MDXaLiE+K4V$)T"`eF&6AH$4eI`"F3!(Y2Kj)ABCH6
+#b6&ffHN-mSr[[a($&e6dMmla&Iiep%rHVrQhHi#(0JaJe+#i-PJ&%!J"P1Cl!ep
+YQ2T$jSEJi2Z0c+hDh!RbcmB"'fT`%@-'kLB+!r6'c4USMFh0fb68Y(llUk)VPLr
+Ed,hR3+5c[D2(piA[kG@V9rTHlZTmZbd5lH`ji1X1qelC&HhSl'V[kHkL2X*kMAQ
+aAlcJMXYmY&+R(%SV"d9HaYKaMM2'05VCQ-Q6Z-8I6HNNK$jrP@'C#fhdRG$`*Iq
+%&@Cib6p[RSd[23pm09LaTDQaQHE,TKFhEZ)8(AZN&j&$@cB%&dm`1'D23KiA`i4
+k2MCcJkB$!`hclN6Fi$P,$&'1lZ1NTbALF5'11FV9NaR+!fJ,m`$QQX5KhSi!*8i
+0H"P%&KpL"M!d&Sm2'A1eSI*J(ND+Nh2H4CbM[(`bCJHJ,N8-+K58K!`YM1)PBC(
+MF0C+`KM%5qDK'9kBG#fF$!KI)Lr"'SQFp+A[c%U3!1a*+dC(4bhbb%J@6`TE[35
+MM(Nm(X4XR"M-a)90**KqZ"l(V4#iN!!lHpDXM)NM`EB,Cr%6K!Nq4h*KmA)pB*I
+)`FD3!b4&J$+3!2'`Cjcj!bJL9'E`T&l56UjPreMAX3FQ,GJZd#hK9K%451'Ll4J
+[Q!K6EaUrTfIlcI)Grdj,Q,L8F($6rf6,&2hjQq2Ql%alc$FQUj8Y-F8G'4R*miZ
+6r#N"Nhme6(qhkM0Gm4bIGkdBkR++CrL5,4D&DElPi!UIMbP,)&-ICUi63Q#+l`6
+Mr0435I-cJc8P-0hc+6l8CL,C!fPlFU@j0YHYP5HlVH6iFMqck@,jbDiKPVai*iE
+U$Ik%rBbr0$p6)-ka&c4LTeHf'r90kr2kc1PIL8)!1m$[-EHZbBe6E*MC$6#jJ*S
+D5ADDE#fUXfa6S4$,$R1GEqqVFra(qSj!BB$kcE6AAIeme%lY-+NSX$"!#a3%h`&
+Q*k"SP1XGG*8[q[)kriiqr[N`q606mMGrMr6Ym@A(IIpC!`re#`28larr"3,URqc
+[!JVpml$rlr*6*KrShqr[f3f'4hk$ZAhbP(CPb2rrCL3-m3pHa&&p!ZrP1,mSX("
+(RI3Qr550fhJiM2F2G!"KiYhmHX("5F#`F3Cii$"NqG''q!Q&BH'NM`)*!fm-NMJ
+G#iK#50`+6KKLT8)))B%,06GHI$PV%q'LL"-iAR[``!-0+5$5!(j#))h,X24N"1M
+Z3b$mh!-#ETlA5jqQAj-I-'p$,*iGIjfpb3C00LpePpdq'U&fJp!9LaP)F'!L&(#
+B-5QFhja-i,Ii3Z#f[f4jF[adr42@M*(aS%(r(cJ$V%XHH6)M*j%XNB0M090iPKm
+LA!c@+El%Er(aKNG'k+Uq'6Iie,4jIhRpArhcH[pGRlRkjh#kDmVcVp8l0@+3!*-
+C-3dda3h982@pIFIkIZcpjA`I1q0HjqjcpETeZPLFAMG*`Fd9K!Ihi0Vp`bA5LG*
+hUZq8VJ`VcUpGcBK0cMcR"h&$E,bKHRr0IYFEPf+ABZGi0Kklp*kV`G9iZ[%FBMH
+rb60J'$JdYQJ98C5$i*'hHLqX$cj("j*GmUV[S,cU1p,C'LAqPjfYZeGLrMhLP&p
+!I"@iP2Q)8riXB-@A8,d'p(lS*8`T3Z`S(+*+ZVBKKRHdK,Ph`N#[r#[[UN(HZi,
+RmL$f+@NM9SlBFD(YENEXX0#SAS2B+U&4(82X+D&4I3Da#U&48BGBJp#BAipB3'K
+82B2B3PQ$$a&l6QJ8DBJY%4T&Rb$Q&4UHaBLY&4UP5a&E)65mYBK9#BhL5X4@#Sf
+5"BMjK)Dk#,(5*lDrdp8@m8ADSYhl)UeYr`%0!!GYG'9cG#kj3)#D#J&2H#J!&c6
++!*!$J!#3"!&EEhJT,!#3%4B!N!MrN!438Np+5d&)6!%!UKPEcE$CcD)!!(*+!*!
+'&`d!N!3HUJ#3#1[c$J#9qCRFXlGVCEICCSIR+lY0&eVRAMZqXX[00PXS2r@Df1A
+KkHA*"VNBTjER*iZH[pFm&Z8ZE"qcfblm[',l@,%Y@BlrBZI+'dRENNhB`TG6`U+
+%rm+qcS9IXHh##19fLpl##EGFH-DfXHfjAGJq`Xl0#&Z"UN(Pee&qXHelQ@6(IQ(
+lb#E,Nrd4YNmb@CI$RfG![9r(Q-!B#jFc&X+DS8F3ArE,60Kl5)j0,',#3EXF'lA
+Ff"lcGF6XpqJ3VDZ[VCVRG&G6"[,RPeil*ApGbRl6q$rjPKb*9Y(1D'@k1jk56ib
+Eb(5E,A,-M0L$VA*XbY0-Yr-@1CBlLqRfhkE85@)CT[d855D6KeK',QTi*XDBC34
+L5e$cI81&5RrqMB2Q!HmIb'5XY(jK24d42+cfld3SK%*fYiD6QclP6#EAG(r)aeP
+A9eeCik`c3H*Pl-%"%f1(rd'SBd9bYr%[Ke#EaC*,Y$c-`"ZCB(aPl&BS5Mh,BLD
+N0[#0c'FQ[EfTSphSF9G+mm35REeC$@ABQb1@KQ[EQd)a(q9fL4i("NpNfN2KQ-m
+SrQ-S(2)pT,1(,a$YBE%N(&VZLmCm8CdpQL8R8qpEN@Q2GN5E4pEl1X,aD,-2+*'
+J,iSDk,LB&@mhVGUh%i%T`9"c@lc&*aE90$@hqTTDI0'15bkj3XE)'FC`$f"%"*l
+1P"DI2aMbLE&Sh#I+hk8AU)Im6@dGbUP#l9$8Yd)"kNG#BZUa&")[D50+5NM)&9b
+(+Q,e$K1L)[VIr25C($[MAIaX"HGhq)+1&j!!e[2jJj+Bi9hm,'b0jr&KUjKP@[a
+prP3lUX&jI')FUX(jqP([8`qIabF--RE1iir'PSMXGrLk$$B+fa(Rm6-0[2G([SX
+r"YZFmrJ'bKlZfl[ie([83qIV4le(06c22e6lh(IaUAI([SY2[8XIeB'afAb9Ir$
+Df*FU$RcS#1"L*RJ,Ea'm-fRG)RJrZ&A`AVj,m,SFJVIm#X%lcb9ikpb#ep-PH+p
+#E1P2"'r!,RL[ALpi`bm+hXK8V%Z`hSce%F(lBEhJM4F*hQXl"Hp(eQ,G*(MAbRj
+Q$[XD'T2@ZpNUa&HaZ`@Ri-$UI+HX[rmZrkFkaRE&f&5@+e`QI%6A4AYGekUNX",
+a$f$r%H%$&&q992!JbRG&K)XDRZXL%808*$F5I@jPT8B8j'B8aRlIb[FAeAq55dH
+1L1MQrZMBlqI#N6heG3RbIm0h"PIj6mS9SQrVVEIZf)'ii2IIHL[fZKNcr(lX)9e
+Qc0LaJqPIj*p+"@Tqh$jQE2+q8I`V51f,88$DMjNaBmC[idIcNIFrX['[3-eISDr
+,(liA2GB#PGG%M!Y$j0I99(,S4!lH0"+9j69jk$RX1"[J-k&q&K)M!KJPmk2bp!&
+6A(i)A$f%aJ9#mk**M)h2!k&-a+NY%$!d(f"'9ic!cqF$K"F86-V-6b31L6b5G`0
+1M&'($4C$r*(IEi'!bf%jZAp2)MJRAj%!m+V!I53X6@!NNPIi-M$VJ*EN'9#9N!"
+a&YKjY(!C*kkY+8YVm&1V[[Q*Em&G4"8%*T5f,[#88kD'H-`rfpl-l%cSlTfdA9f
+"JHN(J%eSm*4@)PpM4k`P',DM)A3i[eTGJ6&"`DPF8NCpe"&Fi@Z-%4"P0#'KVZJ
+[*D-5cj9JHF(B(,XfiL-JBI-6ph@T+dUX9+M'@9P0&@T[#VEaI(3iraee4Fp0i$M
+,UZ%S8Bqf"80A0`@dM*j99r5IR0'bfSC5UT%ah0(LLr"D$Z!BeBaU'aTVU*EKMXE
+fTQDHHdChlq40kSUZ9+[Z+8@0""1kSbfiP#2TZlpQQDfZk&!&D9'*Qh46eMA0V8e
+4Z8%STi[9&If[j942(BHFSX&33-Rq5%lCFLGG'%BMSCk#N4UTJi!'FlG!4h'FNPU
+T&$KMB#kf"'2"F+LT$GjI0$b-H3($G!YKeP3ZTYbbDi+G[TDDF![[Um`"V"&D(HU
+G[+-pdDB)cfQ`AL29cPmJ9B,h"%-m&1`FlT@F&1Fi2G6j(E%QQ8Nbd5%AUL[i8-(
+a90C32aYL`ACH(TD"2Rj'AF'05MqA53XEUIGmSH9U3qZ"%&GA'!MMC-i"%Nd8C3+
+*ea'RPkXVE!)&TEc"6VT5lqI&(N)CUk&iURNZrKLR,d,jQ,S#3d'4UZ9F3M,(%FV
+(eC9GU+*i5ZTi,V&QcP[%Ek[9&GfJ-QCP3`PRc'!(&4QFM[2Ve*@09rUKYEkmK,M
+I&28hchBiC+i'`RTe"FjV+U%9HSK`lP&ApKk`"H%%+aYUUF2-`Bj`iqcCPhd3LN,
+1kAje"C+FIA"HE5A2rZT`F(CM&%M03dM[I4dTVL&p3ehC*"A*8pR!1c`@l'LFj5M
+NkEqTJp$a'"p6ZV5kJEM'l'p6q*CA,Zf!&T,VPY)iT)9HdcLY3aT(IdlMC*l91)C
+c'SI8d"Q0SkQK8aT(8d1R0)ljV-E*rSh'XIa+iea`9Z-S@ZL8aY'dd%Q0SfQKNaT
+Re$Q0-rUdaY'8d!Q0Ne*#ac@1TS41D"a0#Ch31"HHd$LTbPMIi(A9bcQQ#EB&8Yl
+)!#XVHU$IbG$d`+Y1aS"Zd*h9$4RRG-22[C'MZL&GXcGbh(&BhDmZMP6LeqTL3!Z
+3!,Vi$jq8e-8C,D#ULhHdJ+BZ6QN"FK[He!*(0&$+EAM94dkhicBF8D$pEJ-T8*C
+5S1Q2e-9E@Z!"ZL1#F*R4@q-TDk#qP#q[J"K)kc#&J8b@U#Yh(T@-+R"h"VJc'!$
+*DASST808jr%G6d*c(NrT%10C(8*+i)`1k9F#*cd*c@NiT5kbckN,bePeFF&[e-@
+)AkN,43fF8KHD'MMT5@KUi+4U'(e@0B`jTaSd2A"#0D6d`((9S1Q"%kT"d`-R9)2
+e,GA`5krK4R90H3d004jd,$UX28B*bA-BIkkZQ-03F#4*aJQ&9*b"MU8C$*NYbQT
+ULE0UI1hKk,9DjLPPmpjMbNE12-AUkJ6'+kcqpJ6'YQ$+$aQS@ATZYc@P3c3rC%L
+(r,IEQY)KQJ*kABHNU[JH051TE"%j+UD3!1mDA*QLCE4'AE8j0#"j1,H'I,(f$TR
+G"QG*hRYLPQ63&Cjdc"@QUC)hAH(GfKcDXY)&0930FdZm[4fha2bA-j`f@JNpVDk
+D%P*jhFKjr98(HI`aII2fr1Uc#2q-&rQ-E(I[HlDS+e!8$X09@*c$fS,Y`4Ke#8I
+Ulf&00mJp,+Jp$*ErT@iB8#+N'hkQ4)5[k"mS9eIS"Xk+eVdecK+`M$!'9)Mf+JQ
+hYiG$(T9*G32-C$M0T,SlD`pZ89GYbZ3(5TiQ18m!03haSqNSRfY91+SPIXR0U5Q
+6YlNj@mf*lLqMR*b45*[2dp4fp@Yk3R(dDKX@8%@cX)m&fhK@`PHZkhT%AD%LE(+
+218Y,FEHFN!$ME'Q*qMSk&VFe8G2)+KhG1%eGY5Q6[@J4Z9lBZf5pqEU[A&V@!08
+R'%Tp(Ea83afESpCerS*+F*f3!$dr(QbqZLADG-fV26#+L30B)c8XMkq6#j!!`6i
+BVH*95KlUQC'9S9LEHPrD-(Z3!0I-mFS@P[(jKV,P[K"RaHK3GA09T0+bKF4K@D@
+qjF(AFaUVpN&jC6ARM2*JQi`c@0YaDNB0C498Uk`'Ak!kh06bDNBADVPA1MP5DE#
+T,4`BcXQU)LfUj'bBY5JBDJPI-maBip8Z"'m5BjM"Ql&SQ&1'EiLab(e4r'*T!9@
+daKH+$fG2p`$)c&DfQ1G%69S'0ZBj(I1JbqVVZ3GG&Sf'Sj688EHD2'LjRq4+'FY
+4+CRC"R$)JjElU84@k3h0d@#%FMqDd@5Y6V@eR&NpiA#EaTH$[5F1e65EDRS-kb+
+e!Z@9Lk('K+cbB'G08ka9eA[2U5Xi@0&Yi&,jaS,QL+Tr"cfA+FFm&rZ3!1FbpCc
+RmVkcRN[H1FrPMmjj,[RR2*GTjcbALpr`A!Ca,MRVG8ar`qXBp$$HIml$X*rf-!T
+1HaL&Tcf-5dpl')l6dfdc6Xc1lPCA0[2Rr8$cE!1GFjQ+9+i`Lepe,BiLcG+3!$c
+92#G8qdK1+IllJ)SN9FXjK63JM[4[kSUEPBjaVj*6bVhjS-U8cJ8HkL*M8cc@fN%
+ia*3TR$QUHk[JQ!QR%3VYpI'A)`l1pDRjPlVDZKR8AC&`C)CfadP+"j!!krZD$QJ
+HdJ%d!hK'"kLhMlbM!l6E4dlT!2*pcmcjTLD#hjRce5D#6bQ'IZIhT',)1Z[5QRr
+MdQUZc5qFS04%i0Y1N!!b$haUcPHE"cijjjY@jrD4JFN,ZRhNcCRmkp8e0Imb`1R
+UY%JkJ[QAe&4,rrc,bDQ@LHG[5,P[VHBk(kfEiMUREjK9'H!ZcA0qaF91KcHhR&j
+P9L@P4XJl2U0'IMkYm[EG*cHQ[)k"1HDd$kSK6Hq%@qTZ!XhV',UE)$h"V1raQ`6
+)D98bT,FH8-F&fjXL-k1A+[HTT'R3&cbMY,bZa!Te6EN54eRpIqj6qBA#+(a$B@b
+kmKXdUc'1pqCiTp4!rVUHliGR2&681hq`KVK@4[e"U962kp`5LYV[HFYMj6a!DSC
+ij9rP'9A'Ce5*@SlRqcTbPSVXk,m8rjAkMQrm6UUq-NFa2A%8CQ+2ZcSI5qQZS6X
+AdR2l1[pjBfBUCdee$GqiFP`hV$QL'`CQ9G)6h,apG+SfrI$0fkN*0-f[16@"4MF
+3r1m%fMVY[L5icNlFfm$-(AK4$hLChK'3!+EJh[idd'qB`$I%#2,M6%akN!"U#)p
+,qVqSJrqI(QlqArf8"brKC8[r3[T,rV)Hf6b-Jjj%IZ`a#hm3'K2Um0BX["Z+ap$
+2Zr*CM(8*&HaQi4RX+i@2#jm4RXC,X&B,EKjG,r`9R4"fim`DS3+ReJZI%'l$UGh
+#-cLcFIM-TiHaEdlPTV`c5hk9dfmr[*XU$F&(6`f,+$&b4N3QcX9E+,[hCEiSl`d
+kC6p1f6Z8IDZbAk[X0bRlEmVlV&*j6hbLj(GfRl83'pkeaclq0#PATlRUVaq4HPJ
+VeXlT4ELUF,(8Bj3UqT)2jUh(lZYjeq&NPp56FEI8Bc)JpM,@ql(QZ3,ZcQ65(@C
+kpb*h*a0XFj+ET*l-Uk5[@CRBcYUNQlVhimaY!401ZHQ8&*pr`(a9K%NpqJF$KUU
+E!VT%T43ACjXlr51Q&bfTPFUN(N1[D2%DmSV&5jL)r0ejA9*mHP'Tdq2%fE[&DPY
+RPNR8*qbSdM+F,mblERS4&(8$6Yq#q-5mp8#V,kY'I+eB,HS$&UP(pe8pNCl&[er
+U-mk8&LDIG"l)bV(94X5%25,X(,9N91p@CamE(FP-f"GX3%9ehAmTA5A&q4[r@%@
+Im5Gj@m`Va8jcjprbPfi'6$McI0iGE&c"E(1AAlGiJa4I[-(p[H5"+`VBE+Uaehc
+PKJ*6paI&bBRL3L1kjr&!@dAIiH[ceSSjJHGXa9@ImYX6da+9diY+H+dbR`j8%lC
+D-IDN9V%H`aT8F+@iiV!l%F56bSaqID)P-3eRRVH&fF`rA9G3b@C9ljkFp'bSQLf
+m2k$V6NVab-MZKaG[%0'EPMVTS(p%SBJDe!If*#i'ETIpXe)FrB-B'd&p`k-6dBP
+cM$Pi)*G$l04p+@,CHG2Q,ET0IK[U[MIa2V(1jVCC[@ER(QD+#GGCGfkIrh"brde
+VGklckk5iM5AXK#-+LDQfZYUANP[&@YFGE25P3I$4Z-4BejIG3@B4DlYIGPK4J4H
+R,RjXfdbVc4Uk)Q#VG`C'BmeEk-69h&p&K$&8a*'I41eeKakYef)lqQ1pMfj+(UD
+kk6BkTM&,94!c+k,(Y5bRhZA[M$4h2icp!F)$`Xfph@b%%VZ6BKCAmP"JDAXV-24
+dVZ6(9Yhpmrdl,%ecLr`2iT6"[)aGQ$cXZ'LadlELd-lH6ffXkXqpYIF6F[C+I+B
+D4bbImP2MkPl*Ear2l`ANPT%mj,MS3j4EV2G6[F$B@(@C-hPijVh5Kj%91N4iTZc
+(9[EBYfGD!`jdbG6!L(UR2eI19pMMY5U4(Zm)*E,G#fi@RNA''p'0P-(M9$&aa8m
+2Lh0qHVMU$V"@[L1Ij3GX8r1Cp8TAb3pCcU0lQ2ka+af(jKDjaSrH`bjh(1VH0pr
+ThiXH,qEm8qarN!$Rd)-FHU,*'10j6,JrRehZcjf&E0`2"#bl2REA(8c[dp[biF+
+QN!"h!IF[a,T)cXDZjpF9ER[q4ZEUBSAEN8pGP$QXK9CGmDVNppDK0m5CSlbMEG1
+BIZ0DacDUKQ-lVm4$bEhH@@*1BS&BI"64%T31-Ph!1K1Sk)&4lNJ1)e6TS'dhF2H
+*FjKC,2EVQJ`5[E#4&4BPl[YmZFe8@(6(ClpFIYIDJ!&m2pdV`R[3#`8qLYUmSa(
+9+9'V9irGT*+qj(EE@LQHZ%q+lcq!$Pr"G+DY,%2k-`E@!mFAPG5@PXePh3QaX3k
+m,jUNH2k+[SffkNr[qZlU*lBpZS[(9f`ra)TY-ke@a0EdhXc2q*8cTSdpIF[i#Bp
+b)UHhTmr$6lL8%hS$[9BQKaJQq6Q0lp$ab5eH2AD2%qZJXaSGeTR@cBXA2CcXUh)
+&$N[la%2+Q9[kcr3TCe`Kmdh1GX21BZFqTL[-SE13!+i&6&rJC(TE!6-90%,EIDm
+)0Q1Hi(CprB&mGV(J,R[S'lY+h5kADqZfR@ZUGl-Lff4NrJVUT9"jl$-i[rkYmbY
+&i56#p*2R,DN-UVU@6DaD[Fa5fP@k'LG&l1+P8+jX($m4aeNc2fR!UEJG,mj-*Zr
+UDMEB)0fPq1BEPPUkYVQ,(Fa9l#k@iRIGX(5#RFISP,[L#ZDZq15f3U1l`Q'8iY3
+4ckjpGKe3$R4YfhU$)f2l9RZ'Zq+4VHk+hKYmTSeVPZSTjiCLlh-ICD3)`4@'Z8E
+`a'451AR&L'GhIc&[XTLGRe&Im9*&IF8FShIF!-VDqJV$GAMQhq%&'`TBpjF+*d2
+pCIUI)Tljjl,E+[`6aBa%-E,iR$J'D%X3fCMI)-j,6)X)k"IplC0%%mkjmYdDaLa
+aRTMKY3jNDDZ[%)Y&G-1U``8QU,cU*lBQl0fIRrqYj*1hIMf[QZFbVkS-UR-+H""
+pjLMUhPI5Gc!(RE3CXCF4ZaHa,b$f)m4Z41`@a2iGX5rdDqBF-Cq0#jLaQaM)PIT
+B$$J4i1`(6Jca&X5p5Mb+Z!I9#+2A-4H!Phl1BFZK6)X'P1Pd)2UT'YLl+([Xje"
+&X(G3"E#rQ$,#hLBf5[&#iIEbUHk)jIC*K8+LS[#3!(52q$"f"m9[bQGYVFb8Q&`
+SL*@*#SPH*-BrdXA*r3'p@1bk+AAU$prJ+hU&X5pX[UJ04bEU2XP'ZCd0j"eZ*#m
+%qlqCaqq1CTX@9GH5ZhFh`M30XVe"RY0mK03(jKUH*(m%QFdK*`6lFR*!X+p[Z,+
+'iPH95189,&0B*NpR#(H9ZJKIZ,r848kam%eb)A$qm9,A!Z$S*TAMdQVBIhjH,+V
+Cf"I`*%GkTjmP&c&i6"6,f)mBhYe(XFaka1!98Xc`AF4!9K6,rL&HEiKhr9'XaBT
+c5)ZK9LdVF@iPjNB`#p&b(@+GF!U3!(2,HX3LQ2j!R9YZ4Lb'qBkPL(d'X6E8'Vh
+5mJA%FKKHG*M,@Zj%E)HFAmL!'0L'amb)i9Q$2$B#X30+E$4Lqr*I3PE--!@a2EB
+rTZG''UC4RA1R`,YMKKUFHkCM*Hi9CKB"XDFQ2B@EFTRK`iKpQePi[Dp(,5Nb&l&
+1a(*B&krhpi'a5ijPASAB6UEMHBp$V"$+Rf)6%)0DjV&*r!@-Q6aQ3mc%$$b@KaM
+F(Kkl'$',NSGG',YRVj+(!qHQ+RR-3LaAb@-1BK192+j!6&6bF!(lN!"F'`YHeEK
+RIfEle8fYEB2[A-fZ#erMLpD9d*0B"pl(UMkP0I8+9U()@"I&&&Md@Mh0K'A94F1
+aF$0Z,XqLDlNaF1$Vb#S4Ui0,Si#Ji5H4$`Vm2`!5FJ!!!3#3!`%8!*!$&!#3!c)
+U9*!(+LVX!!!U+P53#Z`!!#T8N!-*EA4PFh3ZFfPd!J#3!e0*9%46593K!3!!T!)
+-!*!$!3!!8dP84&0*9#%"!!#N!J`!N"+`fEpN!!!Hm!!!!8C892q3"953!q`!N!4
+8N!Er9*!&l!!!+P53"Iq3!e53!q`!N!-U9*!+l1`!N!-Ul&53"qcX!*!&l!$X9*!
+$l*!$!*!+l*!$!*!,!3#3!rq3#J#3#"!!+!!@!48#!3#3"J-!N!-"!*!$!43!N!-
+8!*!$-J&20H`KbJ#3!a`!-J!!8f9dC`#3!`S!!2rr!*!%!8pi(2'-:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/mac/nl_mac.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,74 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Mac newline routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	26 January 1992
+ * Last Edited:	30 August 2006
+ */
+
+/* Copy string with CRLF newlines
+ * Accepts: destination string
+ *	    pointer to size of destination string buffer
+ *	    source string
+ *	    length of source string
+ * Returns: length of copied string
+ */
+
+unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl,
+			  unsigned char *src,unsigned long srcl)
+{
+  long i,j;
+  unsigned char c,*d = src;
+  if (*dst) {			/* destination provided? */
+    if ((i = srcl * 2) > *dstl)	/* calculate worst-case situation */
+      for (i = j = srcl; j; --j) if (*d++ == '\015') i++;
+				/* flush destination buffer if too small */
+    if (i > *dstl) fs_give ((void **) dst);
+  }
+				/* make a new buffer if needed */
+  if (!*dst) *dst = (char *) fs_get ((*dstl = i) + 1);
+  d = *dst;			/* destination string */
+  if (srcl) do {		/* copy string */
+    c = *d++ = *src++;		/* copy character */
+				/* append line feed to bare CR */
+    if ((c == '\015') && (*src != '\012')) *d++ = '\012';
+  } while (--srcl);
+  *d = '\0';			/* tie off destination */
+  return d - *dst;		/* return length */
+}
+
+
+/* Length of string after strcrlfcpy applied
+ * Accepts: source string
+ * Returns: length of string
+ */
+
+unsigned long strcrlflen (STRING *s)
+{
+  unsigned long pos = GETPOS (s);
+  unsigned long i = SIZE (s);
+  unsigned long j = i;
+  while (j--) if ((SNX (s) == '\015') && ((CHR (s) != '\012') || !j)) i++;
+  SETPOS (s,pos);		/* restore old position */
+  return i;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/mac/os_mac.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,82 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Macintosh version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	26 January 1992
+ * Last Edited:	30 August 2006
+ */
+
+
+/*  This is a totally new operating-system dependent module for the Macintosh,
+ * written using THINK C on my Mac PowerBook-100 in my free time.
+ * Unlike earlier efforts, this version requires no external TCP library.  It
+ * also takes advantage of the Map panel in System 7 for the timezone.
+ */
+
+/* PPC cretins broke the MachineLocation struct */
+
+#define gmtFlags u
+
+#include <limits.h>
+#include <time.h>
+#include <stdio.h>
+#include <fcntl.h>
+#define tcp_port MacTCP_port
+#include <MacTCPCommonTypes.h>
+#include <AddressXlation.h>
+#include <TCPPB.h>
+#include <Desk.h>
+#include <Devices.h>
+#include <Errors.h>
+#include <Files.h>
+#include <Fonts.h>
+#include <Menus.h>
+#include <Script.h>
+#include <ToolUtils.h>
+#include <Windows.h>
+#undef tcp_port
+
+#include "tcp_mac.h"		/* must be before osdep.h */
+#include "mail.h"
+#include "osdep.h"
+#include "misc.h"
+
+static short TCPdriver = 0;	/* MacTCP's reference number */
+short resolveropen = 0;		/* TCP's resolver open */
+
+
+#include "env_mac.c"
+#include "fs_mac.c"
+#include "ftl_mac.c"
+#include "nl_mac.c"
+#include "tcp_mac.c"
+
+#define open(a,b,c) open (a,b)
+#define server_login(user,pass,authuser,argc,argv) NIL
+#define authserver_login(user,authuser,argc,argv) NIL
+#define myusername() ""		/* dummy definition to prevent build errors */
+#define MD5ENABLE ""
+
+#include "auth_md5.c"
+#include "auth_pla.c"
+#include "auth_log.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/mac/os_mac.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,69 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Macintosh version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	26 January 1992
+ * Last Edited:	30 August 2006
+ */
+
+
+/*  This is a totally new operating-system dependent module for the Macintosh,
+ * written using THINK C on my Mac PowerBook-100 in my free time.
+ * Unlike earlier efforts, this version requires no external TCP library.  It
+ * also takes advantage of the Map panel in System 7 for the timezone.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <types.h>
+#include <unix.h>
+#ifndef noErr
+#include <Desk.h>
+#include <Devices.h>
+#include <Errors.h>
+#include <Events.h>
+#include <Fonts.h>
+#include <Memory.h>
+#include <Menus.h>
+#include <ToolUtils.h>
+#include <Windows.h>
+#endif
+
+#define L_SET SEEK_SET
+#define L_INCR SEEK_CUR
+#define L_XTND SEEK_END
+
+extern short resolveropen;	/* make this global so caller can sniff */
+
+#include "env_mac.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+
+#define TCPDRIVER "\p.IPP"
+
+#define gethostid clock
+
+long wait (void);
+long random (void);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/mac/osdep.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,29 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Macintosh version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	13 June 1995
+ * Last Edited:	30 August 2006
+ */
+
+#include "os_mac.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/mac/pmatch.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,89 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	IMAP Wildcard Matching Routines (case-independent)
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	15 June 2000
+ * Last Edited:	30 August 2006
+ */
+
+/* Wildcard pattern match
+ * Accepts: base string
+ *	    pattern string
+ *	    delimiter character
+ * Returns: T if pattern matches base, else NIL
+ */
+
+long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim)
+{
+  switch (*pat) {
+  case '%':			/* non-recursive */
+				/* % at end, OK if no inferiors */
+    if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T;
+                                /* scan remainder of string until delimiter */
+    do if (pmatch_full (s,pat+1,delim)) return T;
+    while ((*s != delim) && *s++);
+    break;
+  case '*':			/* match 0 or more characters */
+    if (!pat[1]) return T;	/* * at end, unconditional match */
+				/* scan remainder of string */
+    do if (pmatch_full (s,pat+1,delim)) return T;
+    while (*s++);
+    break;
+  case '\0':			/* end of pattern */
+    return *s ? NIL : T;	/* success if also end of base */
+  default:			/* match this character */
+    return compare_uchar (*pat,*s) ? NIL : pmatch_full (s+1,pat+1,delim);
+  }
+  return NIL;
+}
+
+/* Directory pattern match
+ * Accepts: base string
+ *	    pattern string
+ *	    delimiter character
+ * Returns: T if base is a matching directory of pattern, else NIL
+ */
+
+long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim)
+{
+  switch (*pat) {
+  case '%':			/* non-recursive */
+    if (!*s) return T;		/* end of base means have a subset match */
+    if (!*++pat) return NIL;	/* % at end, no inferiors permitted */
+				/* scan remainder of string until delimiter */
+    do if (dmatch (s,pat,delim)) return T;
+    while ((*s != delim) && *s++);
+    if (*s && !s[1]) return T;	/* ends with delimiter, must be subset */
+    return dmatch (s,pat,delim);/* do new scan */
+  case '*':			/* match 0 or more characters */
+    return T;			/* unconditional match */
+  case '\0':			/* end of pattern */
+    break;
+  default:			/* match this character */
+    if (*s) return compare_uchar (*pat,*s) ? NIL : dmatch (s+1,pat+1,delim);
+				/* end of base, return if at delimiter */
+    else if (*pat == delim) return T;
+    break;
+  }
+  return NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/mac/tcp_mac.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,557 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Macintosh TCP/IP routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	26 January 1992
+ * Last Edited:	13 January 2008
+ */
+
+
+/*  This is a totally new operating-system dependent module for the Macintosh,
+ * written using THINK C on my Mac PowerBook-100 in my free time.
+ * Unlike earlier efforts, this version requires no external TCP library.  It
+ * also takes advantage of the Map panel in System 7 for the timezone.
+ */
+
+static tcptimeout_t tmoh = NIL;	/* TCP timeout handler routine */
+static long ttmo_open = 75;	/* TCP timeouts, in seconds */
+static long ttmo_read = 0;
+static long ttmo_write = 0;
+static long ttmo_close = 0;
+
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+			       long *contd);
+
+/* TCP/IP manipulate parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *tcp_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case SET_TIMEOUT:
+    tmoh = (tcptimeout_t) value;
+  case GET_TIMEOUT:
+    ret = (void *) tmoh;
+    break;
+  case SET_OPENTIMEOUT:
+    ttmo_open = (long) value;
+  case GET_OPENTIMEOUT:
+    ret = (void *) ttmo_open;
+    break;
+  case SET_READTIMEOUT:
+    ttmo_read = (long) value;
+  case GET_READTIMEOUT:
+    ret = (void *) ttmo_read;
+    break;
+  case SET_WRITETIMEOUT:
+    ttmo_write = (long) value;
+  case GET_WRITETIMEOUT:
+    ret = (void *) ttmo_write;
+    break;
+  case SET_CLOSETIMEOUT:
+    ttmo_close = (long) value;
+  case GET_CLOSETIMEOUT:
+    ret = (void *) ttmo_close;
+    break;
+  }
+  return ret;
+}
+
+/* TCP/IP open
+ * Accepts: host name
+ *	    contact service name
+ *	    contact port number
+ * Returns: TCP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
+{
+  TCPSTREAM *stream;
+  struct hostInfo hst;
+  struct TCPCreatePB *createpb;
+  struct TCPOpenPB *openpb;
+  char *s;
+  unsigned long i,j,k,l;
+  char tmp[MAILTMPLEN];
+  port &= 0xffff;		/* erase flags */
+				/* init MacTCP */
+  if (!TCPdriver && OpenDriver (TCPDRIVER,&TCPdriver)) {
+    mm_log ("Can't init MacTCP",ERROR);
+    return NIL;
+  }
+  if (!resolveropen && OpenResolver (NIL)) {
+    mm_log ("Can't init domain resolver",ERROR);
+    return NIL;
+  }
+  resolveropen = T;		/* note resolver open now */
+				/* domain literal? */
+  if (host[0] == '[' && host[strlen (host)-1] == ']') {
+    if (((i = strtoul (s = host+1,&s,10)) <= 255) && *s++ == '.' &&
+	((j = strtoul (s,&s,10)) <= 255) && *s++ == '.' &&
+	((k = strtoul (s,&s,10)) <= 255) && *s++ == '.' &&
+	((l = strtoul (s,&s,10)) <= 255) && *s++ == ']' && !*s) {
+      hst.addr[0] = (i << 24) + (j << 16) + (k << 8) + l;
+      hst.addr[1] = 0;		/* only one address to try! */
+      sprintf (hst.cname,"[%ld.%ld.%ld.%ld]",i,j,k,l);
+    }
+    else {
+      sprintf (tmp,"Bad format domain-literal: %.80s",host);
+      mm_log (tmp,ERROR);
+      return NIL;
+    }
+  }
+
+  else {			/* look up host name */
+    if (!tcp_dns_upp) tcp_dns_upp = NewResultProc (tcp_dns_result);
+    if (StrToAddr (host,&hst,tcp_dns_upp,NIL)) {
+      while (hst.rtnCode == cacheFault && wait ());
+				/* kludge around MacTCP bug */
+      if (hst.rtnCode == outOfMemory) {
+	mm_log ("Re-initializing domain resolver",WARN);
+	CloseResolver ();	/* bop it on the head and try again */
+	OpenResolver (NIL);	/* note this will leak 12K */
+	StrToAddr (host,&hst,tcp_dns_upp,NIL);
+	while (hst.rtnCode == cacheFault && wait ());
+      }
+      if (hst.rtnCode) {	/* still have error status? */
+	switch (hst.rtnCode) {	/* analyze return */
+	case nameSyntaxErr:
+	  s = "Syntax error in name";
+	  break;
+	case noResultProc:
+	  s = "No result procedure";
+	  break;
+	case noNameServer:
+	  s = "No name server found";
+	  break;
+	case authNameErr:
+	  s = "Host does not exist";
+	  break;
+	case noAnsErr:
+	  s = "No name servers responding";
+	  break;
+	case dnrErr:
+	  s = "Name server returned an error";
+	  break;
+	case outOfMemory:
+	  s = "Not enough memory to resolve name";
+	  break;
+	case notOpenErr:
+	  s = "Driver not open";
+	  break;
+	default:
+	  s = NIL;
+	  break;
+	}
+	if (s) sprintf (tmp,"%s: %.80s",s,host);
+	else sprintf (tmp,"Unknown resolver error (%ld): %.80s",
+		      hst.rtnCode,host);
+	mm_log (tmp,ERROR);
+	return NIL;
+      }
+    }
+  }
+
+				/* create local TCP/IP stream */
+  stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
+  stream->ictr = 0;		/* initialize input */
+  stream->pb.ioCRefNum = TCPdriver;
+  createpb = &stream->pb.csParam.create;
+  openpb = &stream->pb.csParam.open;
+  stream->pb.csCode = TCPCreate;/* create a TCP stream */
+				/* set up buffer for TCP */
+  createpb->rcvBuffLen = 4*BUFLEN;
+  createpb->rcvBuff = fs_get (createpb->rcvBuffLen);
+  createpb->notifyProc = NIL;	/* no special notify procedure */
+  createpb->userDataPtr = NIL;
+  if (PBControlSync ((ParmBlkPtr) &stream->pb))
+    fatal ("Can't create TCP stream");
+  				/* open TCP connection */
+  stream->pb.csCode = TCPActiveOpen;
+  openpb->ulpTimeoutValue = (int) ttmo_open;
+  openpb->ulpTimeoutAction = T;
+  openpb->validityFlags = timeoutValue|timeoutAction;
+				/* remote host (should try all) */
+  openpb->remoteHost = hst.addr[0];
+  openpb->remotePort = port;	/* caller specified remote port */
+  openpb->localPort = 0;	/* generate a local port */
+  openpb->tosFlags = 0;		/* no special TOS */
+  openpb->precedence = 0;	/* no special precedence */
+  openpb->dontFrag = 0;		/* allow fragmentation */
+  openpb->timeToLive = 255;	/* standards say 60, UNIX uses 255 */
+  openpb->security = 0;		/* no special security */
+  openpb->optionCnt = 0;	/* no IP options */
+  openpb->options[0] = 0;
+  openpb->userDataPtr = NIL;	/* no special data pointer */
+  PBControlAsync ((ParmBlkPtr) &stream->pb);
+  while (stream->pb.ioResult == inProgress && wait ());
+  if (stream->pb.ioResult) {	/* got back error status? */
+    sprintf (tmp,"Can't connect to %.80s,%ld",hst.cname,port);
+    mm_log (tmp,ERROR);
+				/* nuke the buffer */
+    stream->pb.csCode = TCPRelease;
+    createpb->userDataPtr = NIL;
+    if (PBControlSync ((ParmBlkPtr) &stream->pb)) fatal ("TCPRelease lossage");
+				/* free its buffer */
+    fs_give ((void **) &createpb->rcvBuff);
+    fs_give ((void **) &stream);/* and the local stream */
+    return NIL;
+  }
+
+				/* copy host names for later use */
+  stream->host = cpystr (hst.cname);
+				/* tie off trailing dot */
+  stream->host[strlen (stream->host) - 1] = '\0';
+				/* the open gave us our address */
+  i = (openpb->localHost >> 24) & 0xff;
+  j = (openpb->localHost >> 16) & 0xff;
+  k = (openpb->localHost >> 8) & 0xff;
+  l = openpb->localHost & 0xff;
+  sprintf (tmp,"[%ld.%ld.%ld.%ld]",i,j,k,l);
+  stream->localhost = cpystr (tmp);
+  if (!myLocalHost) myLocalHost = cpystr (tmp);
+  stream->port = port;		/* copy port number */
+  return stream;
+}
+
+
+/* Called when have return from DNS
+ * Accepts: host info pointer
+ *	    user data pointer
+ */
+
+ResultUPP tcp_dns_upp = NIL;
+
+pascal void tcp_dns_result (struct hostInfo *hostInfoPtr,char *userDataPtr)
+{
+  /* dummy routine */
+}
+
+/* TCP/IP authenticated open
+ * Accepts: NETMBX specifier
+ *	    service name
+ *	    returned user name buffer
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
+{
+  return NIL;			/* no authenticated opens on Mac */
+}
+
+/* TCP receive line
+ * Accepts: TCP stream
+ * Returns: text line string or NIL if failure
+ */
+
+char *tcp_getline (TCPSTREAM *stream)
+{
+  unsigned long n,contd;
+  char *ret = tcp_getline_work (stream,&n,&contd);
+  if (ret && contd) {		/* got a line needing continuation? */
+    STRINGLIST *stl = mail_newstringlist ();
+    STRINGLIST *stc = stl;
+    do {			/* collect additional lines */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+      stc = stc->next = mail_newstringlist ();
+      ret = tcp_getline_work (stream,&n,&contd);
+    } while (ret && contd);
+    if (ret) {			/* stash final part of line on list */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+				/* determine how large a buffer we need */
+      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
+      ret = fs_get (n + 1);	/* copy parts into buffer */
+      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
+	memcpy (ret + n,stc->text.data,stc->text.size);
+      ret[n] = '\0';
+    }
+    mail_free_stringlist (&stl);/* either way, done with list */
+  }
+  return ret;
+}
+
+/* TCP receive line or partial line
+ * Accepts: TCP stream
+ *	    pointer to return size
+ *	    pointer to return continuation flag
+ * Returns: text line string, size and continuation flag, or NIL if failure
+ */
+
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+			       long *contd)
+{
+  unsigned long n;
+  char *s,*ret,c,d;
+  *contd = NIL;			/* assume no continuation */
+				/* make sure have data */
+  if (!tcp_getdata (stream)) return NIL;
+  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
+    d = *stream->iptr++;	/* slurp another character */
+    if ((c == '\015') && (d == '\012')) {
+      ret = (char *) fs_get (n--);
+      memcpy (ret,s,*size = n);	/* copy into a free storage string */
+      ret[n] = '\0';		/* tie off string with null */
+      return ret;
+    }
+  }
+				/* copy partial string from buffer */
+  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
+				/* get more data from the net */
+  if (!tcp_getdata (stream)) fs_give ((void **) &ret);
+				/* special case of newline broken by buffer */
+  else if ((c == '\015') && (*stream->iptr == '\012')) {
+    stream->iptr++;		/* eat the line feed */
+    stream->ictr--;
+    ret[*size = --n] = '\0';	/* tie off string with null */
+  }
+  else *contd = LONGT;		/* continuation needed */
+  return ret;
+}
+
+/* TCP/IP receive buffer
+ * Accepts: TCP/IP stream
+ *	    size in bytes
+ *	    buffer to read into
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
+{
+  unsigned long n;
+  char *bufptr = buffer;
+  while (size > 0) {		/* until request satisfied */
+    if (!tcp_getdata (stream)) return NIL;
+    n = min (size,stream->ictr);/* number of bytes to transfer */
+				/* do the copy */
+    memcpy (bufptr,stream->iptr,n);
+    bufptr += n;		/* update pointer */
+    stream->iptr +=n;
+    size -= n;			/* update # of bytes to do */
+    stream->ictr -=n;
+  }
+  bufptr[0] = '\0';		/* tie off string */
+  return T;
+}
+
+
+/* TCP/IP receive data
+ * Accepts: TCP/IP stream
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getdata (TCPSTREAM *stream)
+{
+  time_t t = time (0);
+  struct TCPReceivePB *receivepb = &stream->pb.csParam.receive;
+  struct TCPAbortPB *abortpb = &stream->pb.csParam.abort;
+  while (stream->ictr < 1) {	/* if nothing in the buffer */
+    time_t tl = time (0);
+    stream->pb.csCode = TCPRcv;	/* receive TCP data */
+    receivepb->commandTimeoutValue = (int) ttmo_read;
+    receivepb->rcvBuff = stream->ibuf;
+    receivepb->rcvBuffLen = BUFLEN;
+    receivepb->secondTimeStamp = 0;
+    receivepb->userDataPtr = NIL;
+    PBControlAsync ((ParmBlkPtr) &stream->pb);
+    while (stream->pb.ioResult == inProgress && wait ());
+    if (stream->pb.ioResult) {	/* punt if got an error */
+      time_t tc = time (0);
+      if ((stream->pb.ioResult == commandTimeout) && tmoh &&
+	  ((*tmoh) (tc - t,tc - tl))) continue;
+    				/* nuke connection */
+      stream->pb.csCode = TCPAbort;
+      abortpb->userDataPtr = NIL;
+      PBControlSync ((ParmBlkPtr) &stream->pb);
+      return NIL;
+    }
+    stream->iptr = stream->ibuf;/* point at TCP buffer */
+    stream->ictr = receivepb->rcvBuffLen;
+  }
+  return T;
+}
+
+/* TCP/IP send string as record
+ * Accepts: TCP/IP stream
+ *	    string pointer
+ * Returns: T if success else NIL
+ */
+
+long tcp_soutr (TCPSTREAM *stream,char *string)
+{
+  return tcp_sout (stream,string,(unsigned long) strlen (string));
+}
+
+
+/* TCP/IP send string
+ * Accepts: TCP/IP stream
+ *	    string pointer
+ *	    byte count
+ * Returns: T if success else NIL
+ */
+
+long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
+{
+  struct TCPSendPB *sendpb = &stream->pb.csParam.send;
+  struct TCPAbortPB *abortpb = &stream->pb.csParam.abort;
+  struct {
+    unsigned short length;
+    Ptr buffer;
+    unsigned short trailer;
+  } wds;
+  while (wds.length = (size > (unsigned long) 32768) ? 32768 : size) {
+    wds.buffer = string;	/* buffer */
+    wds.trailer = 0;		/* tie off buffer */
+    size -= wds.length;		/* this many words will be output */
+    string += wds.length;
+    stream->pb.csCode = TCPSend;/* send TCP data */
+    sendpb->ulpTimeoutValue = (int) ttmo_write;
+    sendpb->ulpTimeoutAction = 0;
+    sendpb->validityFlags = timeoutValue|timeoutAction;
+    sendpb->pushFlag = T;	/* send the data now */
+    sendpb->urgentFlag = NIL;	/* non-urgent data */
+    sendpb->wdsPtr = (Ptr) &wds;
+    sendpb->userDataPtr = NIL;
+    PBControlAsync ((ParmBlkPtr) &stream->pb);
+    while (stream->pb.ioResult == inProgress && wait ());
+    if (stream->pb.ioResult) {	/* punt if got an error */
+				/* nuke connection */
+      stream->pb.csCode =TCPAbort;
+      abortpb->userDataPtr = NIL;
+      PBControlSync ((ParmBlkPtr) &stream->pb);
+      return NIL;
+    }
+  }
+  return T;			/* success */
+}
+
+/* TCP/IP close
+ * Accepts: TCP/IP stream
+ */
+
+void tcp_close (TCPSTREAM *stream)
+{
+  struct TCPClosePB *closepb = &stream->pb.csParam.close;
+  struct TCPCreatePB *createpb = &stream->pb.csParam.create;
+  stream->pb.csCode = TCPClose;	/* close TCP stream */
+  closepb->ulpTimeoutValue = (int) ttmo_close;
+  closepb->ulpTimeoutAction = 0;
+  closepb->validityFlags = timeoutValue|timeoutAction;
+  closepb->userDataPtr = NIL;
+  PBControlAsync ((ParmBlkPtr) &stream->pb);
+  while (stream->pb.ioResult == inProgress && wait ());
+  stream->pb.csCode =TCPRelease;/* flush the buffers */
+  createpb->userDataPtr = NIL;
+  if (PBControlSync ((ParmBlkPtr) &stream->pb)) fatal ("TCPRelease lossage");
+				/* free its buffer */
+  fs_give ((void **) &createpb->rcvBuff);
+				/* flush host names */
+  fs_give ((void **) &stream->host);
+  fs_give ((void **) &stream->localhost);
+  fs_give ((void **) &stream);	/* flush the stream */
+}
+
+/* TCP/IP return host for this stream
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_host (TCPSTREAM *stream)
+{
+  return stream->host;		/* return host name */
+}
+
+
+/* TCP/IP return remote host for this stream
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_remotehost (TCPSTREAM *stream)
+{
+  return stream->host;		/* return host name */
+}
+
+
+/* TCP/IP return port for this stream
+ * Accepts: TCP/IP stream
+ * Returns: port number for this stream
+ */
+
+unsigned long tcp_port (TCPSTREAM *stream)
+{
+  return stream->port;		/* return port number */
+}
+
+
+/* TCP/IP return local host for this stream
+ * Accepts: TCP/IP stream
+ * Returns: local host name for this stream
+ */
+
+char *tcp_localhost (TCPSTREAM *stream)
+{
+  return stream->localhost;	/* return local host name */
+}
+
+/* TCP/IP return canonical form of host name
+ * Accepts: host name
+ * Returns: canonical form of host name
+ */
+
+char *tcp_canonical (char *name)
+{
+  int i;
+  struct hostInfo hst;
+				/* look like domain literal? */
+  if (name[0] == '[' && name[i = (strlen (name))-1] == ']') return name;
+  if (StrToAddr (name,&hst,tcp_dns_upp,NIL)) {
+    while (hst.rtnCode == cacheFault && wait ());
+				/* kludge around MacTCP bug */
+    if (hst.rtnCode == outOfMemory) {
+      mm_log ("Re-initializing domain resolver",WARN);
+      CloseResolver ();		/* bop it on the head and try again */
+      OpenResolver (NIL);	/* note this will leak 12K */
+      StrToAddr (name,&hst,tcp_dns_upp,NIL);
+      while (hst.rtnCode == cacheFault && wait ());
+    }
+				/* still have error status? */
+    if (hst.rtnCode) return name;
+  }
+  return hst.cname;		/* success */
+}
+
+
+/* TCP/IP get client host name (server calls only)
+ * Returns: client host name
+ */
+
+char *tcp_clienthost ()
+{
+  return "UNKNOWN";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/mac/tcp_mac.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,49 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Macintosh TCP/IP routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	26 January 1992
+ * Last Edited:	30 August 2006
+ */
+
+
+/* TCP input buffer */
+
+#define BUFLEN (size_t) 8192	/* TCP input buffer */
+
+
+/* TCP I/O stream */
+
+#define TCPSTREAM struct tcp_stream
+TCPSTREAM {
+  char *host;			/* host name */
+  unsigned long port;		/* port number */
+  char *localhost;		/* local host name */
+  struct TCPiopb pb;		/* MacTCP parameter block */
+  long ictr;			/* input counter */
+  char *iptr;			/* input pointer */
+  char ibuf[BUFLEN];		/* input buffer */
+};
+
+extern ResultUPP tcp_dns_upp;
+pascal void tcp_dns_result (struct hostInfo *hostInfoPtr,char *userDataPtr);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/drivers.bat	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,33 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM     http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM 
+REM ========================================================================
+
+REM Program:	Driver Linkage Generator for DOS/NT
+REM
+REM Author:	Mark Crispin
+REM		Networks and Distributed Computing
+REM		Computing & Communications
+REM		University of Washington
+REM		Administration Building, AG-44
+REM		Seattle, WA  98195
+REM		Internet: MRC@CAC.Washington.EDU
+REM
+REM Date:	11 October 1989
+REM Last Edited:30 August 2006
+
+REM Erase old driver linkage
+IF EXIST LINKAGE.* DEL LINKAGE.*
+
+REM Now define the new list
+FOR %%D IN (%1 %2 %3 %4 %5 %6 %7 %8 %9) DO CALL DRIVRAUX %%D
+
+EXIT 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/drivraux.bat	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,30 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM     http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM 
+REM ========================================================================
+
+REM Program:	Driver Linkage Generator auxillary for NT/Win9x
+REM
+REM Author:	Mark Crispin
+REM		Networks and Distributed Computing
+REM		Computing & Communications
+REM		University of Washington
+REM		Administration Building, AG-44
+REM		Seattle, WA  98195
+REM		Internet: MRC@CAC.Washington.EDU
+REM
+REM Date:	11 October 1989
+REM Last Edited:30 August 2006
+
+ECHO extern DRIVER %1driver; >> LINKAGE.H
+REM Note the introduction of the caret to quote the ampersand in NT
+if "%OS%" == "Windows_NT" ECHO   mail_link (^&%1driver);	/* link in the %1 driver */ >> LINKAGE.C
+if "%OS%" == "" ECHO   mail_link (&%1driver);	/* link in the %1 driver */ >> LINKAGE.C
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/dummy.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,43 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Dummy routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	9 May 1991
+ * Last Edited:	30 August 2006
+ */
+
+/* Exported function prototypes */
+
+void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void dummy_list (MAILSTREAM *stream,char *ref,char *pat);
+void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long scan_contents (DRIVER *dtb,char *name,char *contents,
+		    unsigned long csiz,unsigned long fsiz);
+long dummy_scan_contents (char *name,char *contents,unsigned long csiz,
+			  unsigned long fsiz);
+long dummy_create (MAILSTREAM *stream,char *mailbox);
+long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode);
+long dummy_delete (MAILSTREAM *stream,char *mailbox);
+long dummy_rename (MAILSTREAM *stream,char *old,char *newname);
+char *dummy_file (char *dst,char *name);
+long dummy_canonicalize (char *tmp,char *ref,char *pat);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/dummynt.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,724 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Dummy routines for NT
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	24 May 1993
+ * Last Edited:	1 June 2007
+ */
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <direct.h>
+#include "mail.h"
+#include "osdep.h"
+#include <sys\stat.h>
+#include <dos.h>
+#include "dummy.h"
+#include "misc.h"
+
+/* Function prototypes */
+
+DRIVER *dummy_valid (char *name);
+void *dummy_parameters (long function,void *value);
+void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents,
+		      long level);
+long dummy_listed (MAILSTREAM *stream,char delimiter,char *name,
+		   long attributes,char *contents);
+long dummy_subscribe (MAILSTREAM *stream,char *mailbox);
+MAILSTREAM *dummy_open (MAILSTREAM *stream);
+void dummy_close (MAILSTREAM *stream,long options);
+long dummy_ping (MAILSTREAM *stream);
+void dummy_check (MAILSTREAM *stream);
+long dummy_expunge (MAILSTREAM *stream,char *sequence,long options);
+long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+/* Dummy routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER dummydriver = {
+  "dummy",			/* driver name */
+  DR_LOCAL|DR_MAIL,		/* driver flags */
+  (DRIVER *) NIL,		/* next driver */
+  dummy_valid,			/* mailbox is valid for us */
+  dummy_parameters,		/* manipulate parameters */
+  dummy_scan,			/* scan mailboxes */
+  dummy_list,			/* list mailboxes */
+  dummy_lsub,			/* list subscribed mailboxes */
+  dummy_subscribe,		/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  dummy_create,			/* create mailbox */
+  dummy_delete,			/* delete mailbox */
+  dummy_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  dummy_open,			/* open mailbox */
+  dummy_close,			/* close mailbox */
+  NIL,				/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message structure */
+  NIL,				/* fetch header */
+  NIL,				/* fetch text */
+  NIL,				/* fetch message data */
+  NIL,				/* unique identifier */
+  NIL,				/* message number from UID */
+  NIL,				/* modify flags */
+  NIL,				/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  dummy_ping,			/* ping mailbox to see if still alive */
+  dummy_check,			/* check for new messages */
+  dummy_expunge,		/* expunge deleted messages */
+  dummy_copy,			/* copy messages to another mailbox */
+  dummy_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+
+				/* prototype stream */
+MAILSTREAM dummyproto = {&dummydriver};
+
+/* Dummy validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *dummy_valid (char *name)
+{
+  char *s,*t,tmp[MAILTMPLEN];
+  struct stat sbuf;
+				/* must be valid local mailbox */
+  if (name && *name && (*name != '{') && (s = mailboxfile (tmp,name))) {
+				/* indeterminate INBOX */
+    if (!*s) return &dummydriver;
+				/* remove trailing \ */
+    if ((t = strrchr (s,'\\')) && !t[1]) *t = '\0';
+    if (!stat (s,&sbuf)) switch (sbuf.st_mode & S_IFMT) {
+    case S_IFREG:		/* file */
+    case S_IFDIR:		/* future use */
+      return &dummydriver;
+    }
+  }
+  return NIL;
+}
+
+
+/* Dummy manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *dummy_parameters (long function,void *value)
+{
+  return NIL;
+}
+
+/* Dummy scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  char *s,test[MAILTMPLEN],file[MAILTMPLEN];
+  long i = 0;
+  if (!pat || !*pat) {		/* empty pattern? */
+    if (dummy_canonicalize (test,ref,"*")) {
+				/* tie off name at root */
+      if (s = strchr (test,'\\')) *++s = '\0';
+      else test[0] = '\0';
+      dummy_listed (stream,'\\',test,LATT_NOSELECT,NIL);
+    }
+  }
+				/* get canonical form of name */
+  else if (dummy_canonicalize (test,ref,pat)) {
+				/* found any wildcards? */
+    if (s = strpbrk (test,"%*")) {
+				/* yes, copy name up to that point */
+      strncpy (file,test,(size_t) (i = s - test));
+      file[i] = '\0';		/* tie off */
+    }
+    else strcpy (file,test);	/* use just that name then */
+				/* find directory name */
+    if (s = strrchr (file,'\\')) {
+      *++s = '\0';		/* found, tie off at that point */
+      s = file;
+    }
+				/* silly case */
+    else if (file[0] == '#') s = file;
+				/* do the work */
+    dummy_list_work (stream,s,test,contents,0);
+    if (pmatch ("INBOX",test))	/* always an INBOX */
+      dummy_listed (stream,NIL,"INBOX",LATT_NOINFERIORS,contents);
+  }
+}
+
+/* Dummy list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void dummy_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  dummy_scan (stream,ref,pat,NIL);
+}
+
+
+/* Dummy list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  void *sdb = NIL;
+  char *s,*t,test[MAILTMPLEN];
+  int showuppers = pat[strlen (pat) - 1] == '%';
+				/* get canonical form of name */
+  if (dummy_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) do
+    if (*s != '{') {
+      if (pmatch_full (s,test,'\\')) {
+	if (pmatch (s,"INBOX")) mm_lsub (stream,NIL,s,LATT_NOINFERIORS);
+	else mm_lsub (stream,'\\',s,NIL);
+      }
+      else while (showuppers && (t = strrchr (s,'\\'))) {
+	*t = '\0';		/* tie off the name */
+	if (pmatch_full (s,test,'\\')) mm_lsub (stream,'\\',s,LATT_NOSELECT);
+      }
+    }
+  while (s = sm_read (&sdb));	/* until no more subscriptions */
+}
+
+
+/* Dummy subscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to add to subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_subscribe (MAILSTREAM *stream,char *mailbox)
+{
+  char *s,tmp[MAILTMPLEN];
+  struct stat sbuf;
+				/* must be valid local mailbox */
+  if ((s = mailboxfile (tmp,mailbox)) && *s && !stat (s,&sbuf) &&
+      ((sbuf.st_mode & S_IFMT) == S_IFREG)) return sm_subscribe (mailbox);
+  sprintf (tmp,"Can't subscribe %.80s: not a mailbox",mailbox);
+  mm_log (tmp,ERROR);
+  return NIL;
+}
+
+/* Dummy list mailboxes worker routine
+ * Accepts: mail stream
+ *	    directory name to search
+ *	    search pattern
+ *	    string to scan
+ *	    search level
+ */
+
+void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents,
+		      long level)
+{
+  struct _finddata_t f;
+  struct stat sbuf;
+  long fhandle;
+  char tmp[MAILTMPLEN];
+  size_t len = 0;
+				/* punt if bogus name */
+  if (!mailboxdir (tmp,dir,NIL)) return;
+				/* make directory wildcard */
+  strcat (tmp,(tmp[strlen (tmp) -1] == '\\') ? "*.*" : "\\*.*");
+				/* do nothing if can't open directory */
+  if ((fhandle = _findfirst (tmp,&f)) >= 0) {  
+				/* list it if at top-level */
+    if (!level && dir && pmatch_full (dir,pat,'\\'))
+      dummy_listed (stream,'\\',dir,LATT_NOSELECT,contents);
+				/* scan directory */
+    if (!dir || dir[(len = strlen (dir)) - 1] == '\\') do
+      if (((f.name[0] != '.') ||
+	   (f.name[1] && ((f.name[1] != '.') || f.name[2]))) &&
+	  ((len + strlen (f.name)) <= NETMAXMBX)) {
+				/* see if name is useful */
+	if (dir) sprintf (tmp,"%s%s",dir,f.name);
+	else strcpy (tmp,f.name);
+				/* make sure useful and can get info */
+	if ((pmatch_full (tmp,pat,'\\') ||
+	     pmatch_full (strcat (tmp,"\\"),pat,'\\') ||
+	     dmatch (tmp,pat,'\\')) &&
+	    mailboxdir (tmp,dir,f.name) && tmp[0] && !stat (tmp,&sbuf)) {
+				/* now make name we'd return */
+	  if (dir) sprintf (tmp,"%s%s",dir,f.name);
+	  else strcpy (tmp,f.name);
+				/* only interested in file type */
+	  switch (sbuf.st_mode & S_IFMT) {
+	  case S_IFDIR:		/* directory? */
+	    if (pmatch_full (tmp,pat,'\\')) {
+	      if (!dummy_listed (stream,'\\',tmp,LATT_NOSELECT,contents))break;
+	      strcat (tmp,"\\");/* set up for dmatch call */
+	    }
+				/* try again with trailing \ */
+	    else if (pmatch_full (strcat (tmp,"\\"),pat,'\\') &&
+		     !dummy_listed (stream,'\\',tmp,LATT_NOSELECT,contents))
+	      break;
+	    if (dmatch (tmp,pat,'\\') &&
+		(level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL)))
+	      dummy_list_work (stream,tmp,pat,contents,level+1);
+	    break;
+	  case S_IFREG:		/* ordinary name */
+	    if (pmatch_full (tmp,pat,'\\') && !pmatch ("INBOX",tmp))
+	      dummy_listed (stream,'\\',tmp,LATT_NOINFERIORS,contents);
+	    break;
+	  }
+	}
+      }
+    while (!_findnext (fhandle,&f));
+    _findclose(fhandle);
+  }
+}
+
+/* Mailbox found
+ * Accepts: hierarchy delimiter
+ *	    mailbox name
+ *	    attributes
+ *	    contents to search before calling mm_list()
+ * Returns: T, always
+ */
+
+#define BUFSIZE 4*MAILTMPLEN
+
+long dummy_listed (MAILSTREAM *stream,char delimiter,char *name,
+		   long attributes,char *contents)
+{
+  struct stat sbuf;
+  struct _finddata_t f;
+  int fd,nochild;
+  long fhandle,csiz,ssiz,bsiz;
+  char *s,*buf,tmp[MAILTMPLEN];
+				/* if not \NoInferiors */
+  if (!(attributes & LATT_NOINFERIORS) && mailboxdir (tmp,name,NIL) &&
+      strcat (tmp,(tmp[strlen (tmp) -1] == '\\') ? "*.*" : "\\*.*") &&
+      ((fhandle = _findfirst (tmp,&f)) >= 0)) {
+    nochild = T;
+    do if ((f.name[0] != '.') || (f.name[1] && ((f.name[1] != '.') ||
+						f.name[2]))) nochild = NIL;
+    while (nochild && !_findnext (fhandle,&f));
+    attributes |= nochild ? LATT_HASNOCHILDREN : LATT_HASCHILDREN;
+    _findclose (fhandle);	/* all done, flush directory */
+  }
+  if (contents) {		/* want to search contents? */
+				/* forget it if can't select or open */
+    if ((attributes & LATT_NOSELECT) || !(csiz = strlen (contents)) ||
+	!(s = dummy_file (tmp,name)) || stat (s,&sbuf) ||
+	(csiz > sbuf.st_size) || ((fd = open (tmp,O_RDONLY,NIL)) < 0))
+      return T;
+				/* get buffer including slop */    
+    buf = (char *) fs_get (BUFSIZE + (ssiz = 4 * ((csiz / 4) + 1)) + 1);
+    memset (buf,'\0',ssiz);	/* no slop area the first time */
+    while (sbuf.st_size) {	/* until end of file */
+      read (fd,buf+ssiz,bsiz = min (sbuf.st_size,BUFSIZE));
+      if (search ((unsigned char *) buf,bsiz+ssiz,
+		  (unsigned char *) contents,csiz)) break;
+      memcpy (buf,buf+BUFSIZE,ssiz);
+      sbuf.st_size -= bsiz;	/* note that we read that much */
+    }
+    fs_give ((void **) &buf);	/* flush buffer */
+    close (fd);			/* finished with file */
+    if (!sbuf.st_size) return T;/* not found */
+  }
+				/* notify main program */
+  mm_list (stream,delimiter,name,attributes);
+  return T;
+}
+
+/* Dummy create mailbox
+ * Accepts: mail stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_create (MAILSTREAM *stream,char *mailbox)
+{
+  char tmp[MAILTMPLEN];
+  if (compare_cstring (mailbox,"INBOX") && dummy_file (tmp,mailbox))
+    return dummy_create_path (stream,tmp,NIL);
+  sprintf (tmp,"Can't create %.80s: invalid name",mailbox);
+  mm_log (tmp,ERROR);
+  return NIL;
+}
+
+
+/* Dummy create path
+ * Accepts: mail stream
+ *	    path name to create
+ *	    directory mode
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode)
+{
+  struct stat sbuf;
+  char c,*s,tmp[MAILTMPLEN];
+  int fd;
+  long ret = NIL;
+  char *t = strrchr (path,'\\');
+  char *pt = (path[1] == ':') ? path + 2 : path;
+  int wantdir = t && !t[1];
+  if (wantdir) *t = '\0';	/* flush trailing delimiter for directory */
+				/* found superior to this name? */
+  if ((s = strrchr (pt,'\\')) && (s != pt)) {
+    strncpy (tmp,path,(size_t) (s - path));
+    tmp[s - path] = '\0';	/* make directory name for stat */
+    c = *++s;			/* tie off in case need to recurse */
+    *s = '\0';
+				/* name doesn't exist, create it */
+    if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+	!dummy_create_path (stream,path,dirmode)) return NIL;
+    *s = c;			/* restore full name */
+  }
+  if (wantdir) {		/* want to create directory? */
+    ret = !mkdir (path);
+    *t = '\\';			/* restore directory delimiter */
+  }
+				/* create file */
+  else if ((fd = open (path,O_WRONLY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE)) >= 0)
+    ret = !close (fd);		/* close file */
+  if (!ret) {			/* error? */
+    sprintf (tmp,"Can't create mailbox node %.80s: %.80s",path,
+	     strerror (errno));
+    mm_log (tmp,ERROR);
+  }
+  return ret;			/* return status */
+}
+
+/* Dummy delete mailbox
+ * Accepts: mail stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_delete (MAILSTREAM *stream,char *mailbox)
+{
+  struct stat sbuf;
+  char *s,tmp[MAILTMPLEN];
+  if (!(s = dummy_file (tmp,mailbox))) {
+    sprintf (tmp,"Can't delete - invalid name: %.80s",s);
+    mm_log (tmp,ERROR);
+  }
+				/* no trailing \ */
+  if ((s = strrchr (tmp,'\\')) && !s[1]) *s = '\0';
+  if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) == S_IFDIR) ?
+      rmdir (tmp) : unlink (tmp)) {
+    sprintf (tmp,"Can't delete mailbox %.80s: %.80s",mailbox,strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+  return T;			/* return success */
+}
+
+
+/* Mail rename mailbox
+ * Accepts: mail stream
+ *	    old mailbox name
+ *	    new mailbox name
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  struct stat sbuf;
+  char c,*s,tmp[MAILTMPLEN],mbx[MAILTMPLEN],oldname[MAILTMPLEN];
+  long ret = NIL;
+				/* no trailing \ allowed */
+  if (!dummy_file (oldname,old) || !(s = dummy_file (mbx,newname)) ||
+      stat (oldname,&sbuf) || ((s = strrchr (s,'\\')) && !s[1] &&
+			       ((sbuf.st_mode & S_IFMT) != S_IFDIR))) {
+    sprintf (mbx,"Can't rename %.80s to %.80s: invalid name",old,newname);
+    mm_log (mbx,ERROR);
+    return NIL;
+  }
+  if (s) {			/* found a directory delimiter? */
+    if (!s[1]) *s = '\0';	/* ignore trailing delimiter */
+				/* found superior to destination name? */
+    else if ((s != mbx) && ((mbx[1] != ':') || (s != mbx + 2))) {
+      c = s[1];			/* remember character after delimiter */
+      *s = s[1] = '\0';		/* tie off name at delimiter */
+				/* name doesn't exist, create it */
+      if (stat (mbx,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) {
+	*s = '\\';		/* restore delimiter */
+	if (!dummy_create (stream,mbx)) return NIL;
+      }
+      else *s = '\\';		/* restore delimiter */
+      s[1] = c;			/* restore character after delimiter */
+    }
+  }
+				/* rename of non-ex INBOX creates dest */
+  if (!compare_cstring (old,"INBOX") && stat (oldname,&sbuf))
+    return dummy_create (NIL,mbx);
+  if (rename (oldname,mbx)) {
+    sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %.80s",old,newname,
+	     strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+  return LONGT;			/* return success */
+}
+
+/* Dummy open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *dummy_open (MAILSTREAM *stream)
+{
+  int fd;
+  char err[MAILTMPLEN],tmp[MAILTMPLEN];
+  struct stat sbuf;
+				/* OP_PROTOTYPE call */
+  if (!stream) return &dummyproto;
+  err[0] = '\0';		/* no error message yet */
+				/* can we open the file? */
+  if (!dummy_file (tmp,stream->mailbox))
+    sprintf (err,"Can't open this name: %.80s",stream->mailbox);
+  else if ((fd = open (tmp,O_RDONLY,NIL)) < 0) {
+				/* no, error unless INBOX */
+    if (compare_cstring (stream->mailbox,"INBOX"))
+      sprintf (err,"%.80s: %.80s",strerror (errno),stream->mailbox);
+  }
+  else {			/* file had better be empty then */
+    fstat (fd,&sbuf);		/* sniff at its size */
+    close (fd);
+    if (sbuf.st_size)		/* bogus format if non-empty */
+      sprintf (err,"%.80s (file %.80s) is not in valid mailbox format",
+	       stream->mailbox,tmp);
+  }
+  if (err[0]) {			/* if an error happened */
+    mm_log (err,stream->silent ? WARN : ERROR);
+    return NIL;
+  }
+  else if (!stream->silent) {	/* only if silence not requested */
+    mail_exists (stream,0);	/* say there are 0 messages */
+    mail_recent (stream,0);	/* and certainly no recent ones! */
+    stream->uid_validity = (unsigned long) time (0);
+  }
+  stream->inbox = T;		/* note that it's an INBOX */
+  return stream;		/* return success */
+}
+
+
+/* Dummy close
+ * Accepts: MAIL stream
+ *	    options
+ */
+
+void dummy_close (MAILSTREAM *stream,long options)
+{
+				/* return silently */
+}
+
+/* Dummy ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ */
+
+long dummy_ping (MAILSTREAM *stream)
+{
+  MAILSTREAM *test;
+				/* time to do another test? */
+  if (time (0) >= ((time_t) (stream->gensym + 30))) {
+				/* has mailbox format changed? */
+    if ((test = mail_open (NIL,stream->mailbox,OP_PROTOTYPE)) &&
+	(test->dtb != stream->dtb) &&
+	(test = mail_open (NIL,stream->mailbox,NIL))) {
+				/* preserve some resources */
+      test->original_mailbox = stream->original_mailbox;
+      stream->original_mailbox = NIL;
+      test->sparep = stream->sparep;
+      stream->sparep = NIL;
+      test->sequence = stream->sequence;
+      mail_close ((MAILSTREAM *) /* flush resources used by dummy stream */
+		  memcpy (fs_get (sizeof (MAILSTREAM)),stream,
+			  sizeof (MAILSTREAM)));
+				/* swap the streams */
+      memcpy (stream,test,sizeof (MAILSTREAM));
+      fs_give ((void **) &test);/* flush test now that copied */
+				/* make sure application knows */
+      mail_exists (stream,stream->recent = stream->nmsgs);
+    }
+				/* still hasn't changed */
+    else stream->gensym = (unsigned long) time (0);
+  }
+  return T;
+}
+
+
+/* Dummy check mailbox
+ * Accepts: MAIL stream
+ * No-op for readonly files, since read/writer can expunge it from under us!
+ */
+
+void dummy_check (MAILSTREAM *stream)
+{
+  dummy_ping (stream);		/* invoke ping */
+}
+
+
+/* Dummy expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long dummy_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  return LONGT;
+}
+
+/* Dummy copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    options
+ * Returns: T if copy successful, else NIL
+ */
+
+long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+      mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy");
+  return NIL;
+}
+
+
+/* Dummy append message string
+ * Accepts: mail stream
+ *	    destination mailbox
+ *	    append callback function
+ *	    data for callback
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct stat sbuf;
+  int fd = -1;
+  int e;
+  char tmp[MAILTMPLEN];
+  MAILSTREAM *ts = default_proto (T);
+  if (compare_cstring (mailbox,"INBOX") && dummy_file (tmp,mailbox) &&
+      ((fd = open (tmp,O_RDONLY,NIL)) < 0)) {
+    if ((e = errno) == ENOENT)	/* failed, was it no such file? */
+      mm_notify (stream,"[TRYCREATE] Must create mailbox before append",
+		 (long) NIL);
+    sprintf (tmp,"%.80s: %.80s",strerror (e),mailbox);
+    mm_log (tmp,ERROR);		/* pass up error */
+    return NIL;			/* always fails */
+  }
+  if (fd >= 0) {		/* found file? */
+    fstat (fd,&sbuf);		/* get its size */
+    close (fd);			/* toss out the fd */
+    if (sbuf.st_size) ts = NIL;	/* non-empty file? */
+  }
+  if (ts) return (*ts->dtb->append) (stream,mailbox,af,data);
+  sprintf (tmp,"Indeterminate mailbox format: %.80s",mailbox);
+  mm_log (tmp,ERROR);
+  return NIL;
+}
+
+/* Dummy mail generate file string
+ * Accepts: temporary buffer to write into
+ *	    mailbox name string
+ * Returns: local file string or NIL if failure
+ */
+
+char *dummy_file (char *dst,char *name)
+{
+  char *s = mailboxfile (dst,name);
+				/* return our standard inbox */
+  return (s && !*s) ? strcpy (dst,sysinbox ()) : s;
+}
+
+
+/* Dummy canonicalize name
+ * Accepts: buffer to write name
+ *	    reference
+ *	    pattern
+ * Returns: T if success, NIL if failure
+ */
+
+long dummy_canonicalize (char *tmp,char *ref,char *pat)
+{
+  unsigned long i;
+  char *s,dev[4];
+				/* initially no device */
+  dev[0] = dev[1] = dev[2] = dev[3] = '\0';
+  if (ref) switch (*ref) {	/* preliminary reference check */
+  case '{':			/* remote names not allowed */
+    return NIL;			/* disallowed */
+  case '\0':			/* empty reference string */
+    break;
+  default:			/* all other names */
+    if (ref[1] == ':') {	/* start with device name? */
+      dev[0] = *ref++; dev[1] = *ref++;
+    }
+    break;
+  }
+  if (pat[1] == ':') {		/* device name in pattern? */
+    dev[0] = *pat++; dev[1] = *pat++;
+    ref = NIL;			/* ignore reference */
+  }
+  switch (*pat) {
+  case '#':			/* namespace names */
+    if (mailboxfile (tmp,pat)) strcpy (tmp,pat);
+    else return NIL;		/* unknown namespace */
+    break;
+  case '{':			/* remote names not allowed */
+    return NIL;
+  case '\\':			/* rooted name */
+    ref = NIL;			/* ignore reference */
+    break;
+  }
+				/* make sure device names are rooted */
+  if (dev[0] && (*(ref ? ref : pat) != '\\')) dev[2] = '\\';
+				/* build name */
+  sprintf (tmp,"%s%s%s",dev,ref ? ref : "",pat);
+  ucase (tmp);			/* force upper case */
+				/* count wildcards */
+  for (i = 0, s = tmp; *s; *s++) if ((*s == '*') || (*s == '%')) ++i;
+  if (i > MAXWILDCARDS) {	/* ridiculous wildcarding? */
+    MM_LOG ("Excessive wildcards in LIST/LSUB",ERROR);
+    return NIL;
+  }
+  return T;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/env_nt.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,774 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	NT environment routines
+ *
+ * Author:	Mark Crispin
+ *		UW Technology
+ *		University of Washington
+ *		Seattle, WA  98195
+ *		Internet: MRC@Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	15 February 2008
+ */
+
+static char *myUserName = NIL;	/* user name */
+static char *myLocalHost = NIL;	/* local host name */
+static char *myHomeDir = NIL;	/* home directory name */
+static char *myNewsrc = NIL;	/* newsrc file name */
+static char *sysInbox = NIL;	/* system inbox name */
+static long list_max_level = 5;	/* maximum level of list recursion */
+				/* block environment init */
+static short block_env_init = NIL;
+static short no822tztext = NIL;	/* disable RFC [2]822 timezone text */
+				/* home namespace */
+static NAMESPACE nshome = {"",'\\',NIL,NIL};
+				/* UNIX other user namespace */
+static NAMESPACE nsother = {"#user.",'\\',NIL,NIL};
+				/* namespace list */
+static NAMESPACE *nslist[3] = {&nshome,&nsother,NIL};
+static long alarm_countdown = 0;/* alarm count down */
+static void (*alarm_rang) ();	/* alarm interrupt function */
+static unsigned int rndm = 0;	/* initial `random' number */
+static int server_nli = 0;	/* server and not logged in */
+static int logtry = 3;		/* number of login tries */
+				/* block notification */
+static blocknotify_t mailblocknotify = mm_blocknotify;
+				/* callback to get username */
+static userprompt_t mailusername = NIL;
+static long is_nt = -1;		/* T if NT, NIL if not NT, -1 unknown */
+static HINSTANCE netapi = NIL;
+typedef NET_API_STATUS (CALLBACK *GETINFO) (LPCWSTR,LPCWSTR,DWORD,LPBYTE *);
+static GETINFO getinfo = NIL;
+
+#include "write.c"		/* include safe writing routines */
+#include "pmatch.c"		/* include wildcard pattern matcher */
+
+
+/* Get all authenticators */
+
+#include "auths.c"
+
+/* Environment manipulate parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *env_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case GET_NAMESPACE:
+    ret = (void *) nslist;
+    break;
+  case SET_USERPROMPT :
+    mailusername = (userprompt_t) value;
+  case GET_USERPROMPT :
+    ret = (void *) mailusername;
+    break;
+  case SET_HOMEDIR:
+    if (myHomeDir) fs_give ((void **) &myHomeDir);
+    myHomeDir = cpystr ((char *) value);
+  case GET_HOMEDIR:
+    ret = (void *) myHomeDir;
+    break;
+  case SET_LOCALHOST:
+    myLocalHost = cpystr ((char *) value);
+  case GET_LOCALHOST:
+    if (myLocalHost) fs_give ((void **) &myLocalHost);
+    ret = (void *) myLocalHost;
+    break;
+  case SET_NEWSRC:
+    if (myNewsrc) fs_give ((void **) &myNewsrc);
+    myNewsrc = cpystr ((char *) value);
+  case GET_NEWSRC:
+    if (!myNewsrc) {		/* set news file name if not defined */
+      char tmp[MAILTMPLEN];
+      sprintf (tmp,"%s\\NEWSRC",myhomedir ());
+      myNewsrc = cpystr (tmp);
+    }
+    ret = (void *) myNewsrc;
+    break;
+  case SET_SYSINBOX:
+    if (sysInbox) fs_give ((void **) &sysInbox);
+    sysInbox = cpystr ((char *) value);
+  case GET_SYSINBOX:
+    ret = (void *) sysInbox;
+    break;
+  case SET_LISTMAXLEVEL:
+    list_max_level = (long) value;
+  case GET_LISTMAXLEVEL:
+    ret = (void *) list_max_level;
+    break;
+  case SET_DISABLE822TZTEXT:
+    no822tztext = value ? T : NIL;
+  case GET_DISABLE822TZTEXT:
+    ret = (void *) (no822tztext ? VOIDT : NIL);
+    break;
+  case SET_BLOCKENVINIT:
+    block_env_init = value ? T : NIL;
+  case GET_BLOCKENVINIT:
+    ret = (void *) (block_env_init ? VOIDT : NIL);
+    break;
+  case SET_BLOCKNOTIFY:
+    mailblocknotify = (blocknotify_t) value;
+  case GET_BLOCKNOTIFY:
+    ret = (void *) mailblocknotify;
+    break;
+  }
+  return ret;
+}
+
+/* Write current time
+ * Accepts: destination string
+ *	    optional format of day-of-week prefix
+ *	    format of date and time
+ *	    flag whether to append symbolic timezone
+ */
+
+static void do_date (char *date,char *prefix,char *fmt,int suffix)
+{
+  time_t tn = time (0);
+  struct tm *t = gmtime (&tn);
+  int zone = t->tm_hour * 60 + t->tm_min;
+  int julian = t->tm_yday;
+  t = localtime (&tn);		/* get local time now */
+				/* minus UTC minutes since midnight */
+  zone = t->tm_hour * 60 + t->tm_min - zone;
+  /* julian can be one of:
+   *  36x  local time is December 31, UTC is January 1, offset -24 hours
+   *    1  local time is 1 day ahead of UTC, offset +24 hours
+   *    0  local time is same day as UTC, no offset
+   *   -1  local time is 1 day behind UTC, offset -24 hours
+   * -36x  local time is January 1, UTC is December 31, offset +24 hours
+   */
+  if (julian = t->tm_yday -julian)
+    zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
+  if (prefix) {			/* want day of week? */
+    sprintf (date,prefix,days[t->tm_wday]);
+    date += strlen (date);	/* make next sprintf append */
+  }
+				/* output the date */
+  sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
+	   t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
+  if (suffix) {			/* append timezone suffix if desired */
+    char *tz;
+    tzset ();			/* get timezone from TZ environment stuff */
+    tz = tzname[daylight ? (((struct tm *) t)->tm_isdst > 0) : 0];
+    if (tz && tz[0]) {
+      char *s;
+      for (s = tz; *s; s++) if (*s & 0x80) return;
+      sprintf (date + strlen (date)," (%.50s)",tz);
+    }
+  }
+}
+
+
+/* Write current time in RFC 822 format
+ * Accepts: destination string
+ */
+
+void rfc822_date (char *date)
+{
+  do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d",
+	   no822tztext ? NIL : T);
+}
+
+
+/* Write current time in fixed-width RFC 822 format
+ * Accepts: destination string
+ */
+
+void rfc822_fixed_date (char *date)
+{
+  do_date (date,NIL,"%02d %s %4d %02d:%02d:%02d %+03d%02d",NIL);
+}
+
+
+/* Write current time in internal format
+ * Accepts: destination string
+ */
+
+void internal_date (char *date)
+{
+  do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL);
+}
+
+/* Return random number
+ */
+
+long random (void)
+{
+  if (!rndm) srand (rndm = (unsigned) time (0L));
+  return (long) rand ();
+}
+
+
+/* Set alarm timer
+ * Accepts: new value
+ * Returns: old alarm value
+ */
+
+long alarm (long seconds)
+{
+  long ret = alarm_countdown;
+  alarm_countdown = seconds;
+  return ret;
+}
+
+
+/* The clock ticked
+ */
+
+void CALLBACK clock_ticked (UINT IDEvent,UINT uReserved,DWORD dwUser,
+			    DWORD dwReserved1,DWORD dwReserved2)
+{
+  if (alarm_rang && !--alarm_countdown) (*alarm_rang) ();
+}
+
+/* Initialize server
+ * Accepts: server name for syslog or NIL
+ *	    /etc/services service name or NIL
+ *	    alternate /etc/services service name or NIL
+ *	    clock interrupt handler
+ *	    kiss-of-death interrupt handler
+ *	    hangup interrupt handler
+ *	    termination interrupt handler
+ */
+
+void server_init (char *server,char *service,char *sslservice,
+		  void *clkint,void *kodint,void *hupint,void *trmint,
+		  void *staint)
+{
+  if (!check_nt ()) {
+    if (!auth_md5.server) fatal ("Can't run on Windows without MD5 database");
+    server_nli = T;		/* Windows server not logged in */
+  }
+				/* only do this if for init call */
+  if (server && service && sslservice) {
+    long port;
+    struct servent *sv;
+				/* set server name in syslog */
+    openlog (server,LOG_PID,LOG_MAIL);
+    fclose (stderr);		/* possibly save a process ID */
+    /* Use SSL if SSL service, or if server starts with "s" and not service */
+    if (((port = tcp_serverport ()) >= 0)) {
+      if ((sv = getservbyname (service,"tcp")) && (port == ntohs (sv->s_port)))
+	syslog (LOG_DEBUG,"%s service init from %s",service,tcp_clientaddr ());
+      else if ((sv = getservbyname (sslservice,"tcp")) &&
+	       (port == ntohs (sv->s_port))) {
+	syslog (LOG_DEBUG,"%s SSL service init from %s",sslservice,
+		tcp_clientaddr ());
+	ssl_server_init (server);
+      }
+      else {			/* not service or SSL service port */
+	syslog (LOG_DEBUG,"port %ld service init from %s",port,
+		tcp_clientaddr ());
+	if (*server == 's') ssl_server_init (server);
+      }
+    }
+				/* make sure stdout does binary */
+    setmode (fileno (stdin),O_BINARY);
+    setmode (fileno (stdout),O_BINARY);
+  }
+  alarm_rang = clkint;		/* note the clock interrupt */
+  timeBeginPeriod (1000);	/* set the timer interval */
+  timeSetEvent (1000,1000,clock_ticked,NIL,TIME_PERIODIC);
+}
+
+
+/* Wait for stdin input
+ * Accepts: timeout in seconds
+ * Returns: T if have input on stdin, else NIL
+ */
+
+long server_input_wait (long seconds)
+{
+  fd_set rfd,efd;
+  struct timeval tmo;
+  FD_ZERO (&rfd);
+  FD_ZERO (&efd);
+  FD_SET (0,&rfd);
+  FD_SET (0,&efd);
+  tmo.tv_sec = seconds; tmo.tv_usec = 0;
+  return select (1,&rfd,0,&efd,&tmo) ? LONGT : NIL;
+}
+
+/* Server log in
+ * Accepts: user name string
+ *	    password string
+ *	    authenticating user name string
+ *	    argument count
+ *	    argument vector
+ * Returns: T if password validated, NIL otherwise
+ */
+
+static int gotprivs = NIL;	/* once-only flag to grab privileges */
+
+long server_login (char *user,char *pass,char *authuser,int argc,char *argv[])
+{
+  HANDLE hdl;
+  LUID tcbpriv;
+  TOKEN_PRIVILEGES tkp;
+  char *s;
+				/* need to get privileges? */
+  if (!gotprivs++ && check_nt ()) {
+				/* hack for inetlisn */
+    if (argc >= 2) myClientHost = argv[1];
+				/* get process token and TCB priv value */
+    if (!(OpenProcessToken (GetCurrentProcess (),
+			    TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,&hdl) &&
+	  LookupPrivilegeValue ((LPSTR) NIL,SE_TCB_NAME,&tcbpriv)))
+      return NIL;
+    tkp.PrivilegeCount = 1;	/* want to enable this privilege */
+    tkp.Privileges[0].Luid = tcbpriv;
+    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+				/* enable it */
+    AdjustTokenPrivileges (hdl,NIL,&tkp,sizeof (TOKEN_PRIVILEGES),
+			   (PTOKEN_PRIVILEGES) NIL,(PDWORD) NIL);
+				/* make sure it won */
+    if (GetLastError() != ERROR_SUCCESS) return NIL;
+  }
+
+				/* cretins still haven't given up */
+  if ((strlen (user) >= MAILTMPLEN) ||
+      (authuser && (strlen (authuser) >= MAILTMPLEN)))
+    syslog (LOG_ALERT,"SYSTEM BREAK-IN ATTEMPT, host=%.80s",tcp_clienthost ());
+  else if (logtry > 0) {	/* still have available logins? */
+				/* authentication user not supported */
+    if (authuser && *authuser && compare_cstring (authuser,user))
+      mm_log ("Authentication id must match authorization id",ERROR);
+    if (check_nt ()) {		/* NT: authserver_login() call not supported */
+      if (!pass) mm_log ("Unsupported authentication mechanism",ERROR);
+      else if ((		/* try to login and impersonate the guy */
+#ifdef LOGIN32_LOGON_NETWORK
+		LogonUser (user,".",pass,LOGON32_LOGON_NETWORK,
+			   LOGON32_PROVIDER_DEFAULT,&hdl) ||
+#endif
+		LogonUser (user,".",pass,LOGON32_LOGON_INTERACTIVE,
+			   LOGON32_PROVIDER_DEFAULT,&hdl) ||
+		LogonUser (user,".",pass,LOGON32_LOGON_BATCH,
+			   LOGON32_PROVIDER_DEFAULT,&hdl) ||
+		LogonUser (user,".",pass,LOGON32_LOGON_SERVICE,
+			   LOGON32_PROVIDER_DEFAULT,&hdl)) &&
+	       ImpersonateLoggedOnUser (hdl)) return env_init (user,NIL);
+    }
+    else {			/* Win9x: done if from authserver_login() */
+      if (!pass) server_nli = NIL;
+				/* otherwise check MD5 database */
+      else if (s = auth_md5_pwd (user)) {
+				/* change NLI state based on pwd match */
+	server_nli = strcmp (s,pass);
+	memset (s,0,strlen (s));/* erase sensitive information */
+	fs_give ((void **) &s);	/* flush erased password */
+      }
+				/* success if no longer NLI */
+      if (!server_nli) return env_init (user,NIL);
+    }
+  }
+  s = (logtry-- > 0) ? "Login failure" : "Excessive login attempts";
+				/* note the failure in the syslog */
+  syslog (LOG_INFO,"%s user=%.80s host=%.80s",s,user,tcp_clienthost ());
+  sleep (3);			/* slow down possible cracker */
+  return NIL;
+}
+
+/* Authenticated server log in
+ * Accepts: user name string
+ *	    authentication user name string
+ *	    argument count
+ *	    argument vector
+ * Returns: T if password validated, NIL otherwise
+ */
+
+long authserver_login (char *user,char *authuser,int argc,char *argv[])
+{
+  return server_login (user,NIL,authuser,argc,argv);
+}
+
+
+/* Log in as anonymous daemon
+ * Accepts: argument count
+ *	    argument vector
+ * Returns: T if successful, NIL if error
+ */
+
+long anonymous_login (int argc,char *argv[])
+{
+  return server_login ("Guest",NIL,NIL,argc,argv);
+}
+
+
+/* Initialize environment
+ * Accepts: user name
+ *          home directory, or NIL to use default
+ * Returns: T, always
+ */
+
+long env_init (char *user,char *home)
+{
+				/* don't init if blocked */
+  if (block_env_init) return LONGT;
+  if (myUserName) fatal ("env_init called twice!");
+  myUserName = cpystr (user);	/* remember user name */
+  if (!myHomeDir)		/* only if home directory not set up yet */
+    myHomeDir = (home && *home) ? cpystr (home) : win_homedir (user);
+  return T;
+}
+
+/* Check if NT
+ * Returns: T if NT, NIL if Win9x
+ */
+
+int check_nt (void)
+{
+  if (is_nt < 0) {		/* not yet set up? */
+    OSVERSIONINFO ver;
+    ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
+    GetVersionEx (&ver);
+    is_nt = (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) ? T : NIL;
+  }
+  return is_nt;
+}
+
+
+/* Return Windows home directory
+ * Accepts: user name
+ * Returns: home directory
+ */
+
+char *win_homedir (char *user)
+{
+  char *s,*t,tmp[MAILTMPLEN];
+  PUSER_INFO_1 ui;
+				/* Win9x default */
+  if (!check_nt ()) sprintf (tmp,"%s\\My Documents",defaultDrive ());
+				/* get from user info on NT */
+  else if ((netapi || (netapi = LoadLibrary ("netapi32.dll"))) &&
+	   (getinfo ||
+	    (getinfo = (GETINFO) GetProcAddress (netapi,"NetUserGetInfo"))) &&
+	   MultiByteToWideChar (CP_ACP,0,user,strlen (user) + 1,
+				(WCHAR *) tmp,MAILTMPLEN) &&
+	   !(*getinfo) (NIL,(LPWSTR) &tmp,1,(LPBYTE *) &ui) &&
+	   WideCharToMultiByte (CP_ACP,0,ui->usri1_home_dir,-1,
+				tmp,MAILTMPLEN,NIL,NIL) && tmp[0]) {
+				/* make sure doesn't end with delimiter */
+    if ((*(s = tmp + strlen (tmp) - 1) == '\\') || (*s == '/')) *s = '\0';
+  }
+				/* no home dir, found Win2K user profile? */
+  else if ((s = getenv ("USERPROFILE")) && (t = strrchr (s,'\\'))) {      
+    strncpy (tmp,s,t-s);	/* copy up to user name */
+    sprintf (tmp+(t-s),"\\%.100s\\My Documents",user);
+  }
+				/* last resort NT default */
+  else sprintf (tmp,"%s\\users\\default",defaultDrive ());
+  return cpystr (tmp);
+}
+
+
+/* Return default drive
+ * Returns: default drive
+ */
+
+static char *defaultDrive (void)
+{
+  char *s = getenv ("SystemDrive");
+  return (s && *s) ? s : "C:";
+}
+
+/* Return my user name
+ * Accepts: pointer to optional flags
+ * Returns: my user name
+ */
+
+char *myusername_full (unsigned long *flags)
+{
+  UCHAR usr[MAILTMPLEN];
+  DWORD len = MAILTMPLEN;
+  char *user,*path,*d,*p,pth[MAILTMPLEN];
+  char *ret = "SYSTEM";
+				/* get user name if don't have it yet */
+  if (!myUserName && !server_nli &&
+				/* use callback, else logon name */
+      ((mailusername && (user = (char *) (*mailusername) ())) ||
+       (GetUserName (usr,&len) && _stricmp (user = (char *) usr,"SYSTEM")))) {
+    if (block_env_init) {	/* don't env_init if blocked */
+      if (flags) *flags = MU_LOGGEDIN;
+      return user;
+    }
+				/* try HOMEPATH, then HOME */
+    if (p = getenv ("HOMEPATH"))
+      sprintf (path = pth,"%s%s",
+	       (d = getenv ("HOMEDRIVE")) ? d : defaultDrive (),p);
+    else if (!(path = getenv ("HOME")))
+      sprintf (path = pth,"%s\\My Documents",defaultDrive ());
+				/* make sure doesn't end with delimiter */
+    if ((*(p = path + strlen (path) -1) == '\\') || (*p == '/')) *p = '\0';
+    env_init (user,path);	/* initialize environment */
+  }
+  if (myUserName) {		/* logged in? */
+    if (flags)			/* Guest is an anonymous user */
+      *flags = _stricmp (myUserName,"Guest") ? MU_LOGGEDIN : MU_ANONYMOUS;
+    ret = myUserName;		/* return user name */
+  }
+  else if (flags) *flags = MU_NOTLOGGEDIN;
+  return ret;
+}
+
+/* Return my local host name
+ * Returns: my local host name
+ */
+
+char *mylocalhost (void)
+{
+  if (!myLocalHost) {
+    char tmp[MAILTMPLEN];
+    if (!wsa_initted++) {	/* init Windows Sockets */
+      WSADATA wsock;
+      if (WSAStartup (WINSOCK_VERSION,&wsock)) {
+	wsa_initted = 0;
+	return "random-pc";	/* try again later? */
+      }
+    }
+    myLocalHost = cpystr ((gethostname (tmp,MAILTMPLEN-1) == SOCKET_ERROR) ?
+			  "random-pc" : tcp_canonical (tmp));
+  }
+  return myLocalHost;
+}
+
+/* Return my home directory name
+ * Returns: my home directory name
+ */
+
+char *myhomedir ()
+{
+  if (!myHomeDir) myusername ();/* initialize if first time */
+  return myHomeDir ? myHomeDir : "";
+}
+
+
+/* Return system standard INBOX
+ * Accepts: buffer string
+ */
+
+char *sysinbox ()
+{
+  char tmp[MAILTMPLEN];
+  if (!sysInbox) {		/* initialize if first time */
+    if (check_nt ()) sprintf (tmp,MAILFILE,myUserName);
+    else sprintf (tmp,"%s\\INBOX",myhomedir ());
+    sysInbox = cpystr (tmp);	/* system inbox is from mail spool */
+  }
+  return sysInbox;
+}
+
+
+/* Return mailbox directory name
+ * Accepts: destination buffer
+ *	    directory prefix
+ *	    name in directory
+ * Returns: file name or NIL if error
+ */
+
+char *mailboxdir (char *dst,char *dir,char *name)
+{
+  char tmp[MAILTMPLEN];
+  if (dir || name) {		/* if either argument provided */
+    if (dir) {
+      if (strlen (dir) > NETMAXMBX) return NIL;
+      strcpy (tmp,dir);		/* write directory prefix */
+    }
+    else tmp[0] = '\0';		/* otherwise null string */
+    if (name) {
+      if (strlen (name) > NETMAXMBX) return NIL;
+      strcat (tmp,name);	/* write name in directory */
+    }
+				/* validate name, return its name */
+    if (!mailboxfile (dst,tmp)) return NIL;
+  }
+  else strcpy (dst,myhomedir());/* no arguments, wants home directory */
+  return dst;			/* return the name */
+}
+
+/* Return mailbox file name
+ * Accepts: destination buffer
+ *	    mailbox name
+ * Returns: file name or empty string for driver-selected INBOX or NIL if error
+ */
+
+char *mailboxfile (char *dst,char *name)
+{
+  char homedev[3];
+  char *dir = myhomedir ();
+  if (dir[0] && isalpha (dir[0]) && (dir[1] == ':')) {
+    homedev[0] = dir[0];	/* copy home device */
+    homedev[1] = dir[1];
+    homedev[2] = '\0';
+  }
+  else homedev[0] = '\0';	/* ??no home device?? */
+  *dst = '\0';			/* default to empty string */
+				/* check for INBOX */
+  if (!compare_cstring (name,"INBOX"));
+				/* reject names with / */
+  else if (strchr (name,'/')) dst = NIL;
+  else switch (*name) {
+  case '#':			/* namespace names */
+    if (((name[1] == 'u') || (name[1] == 'U')) &&
+	((name[2] == 's') || (name[2] == 'S')) &&
+	((name[3] == 'e') || (name[3] == 'E')) &&
+	((name[4] == 'r') || (name[4] == 'R')) && (name[5] == '.')) {
+				/* copy user name to destination buffer */
+      for (dir = dst,name += 6; *name && (*name != '\\'); *dir++ = *name++);
+      *dir++ = '\0';		/* tie off user name */
+				/* look up homedir for user name */
+      if (dir = win_homedir (dst)) {
+				/* build resulting name */
+	sprintf (dst,"%s\\%s",dir,name);
+	fs_give ((void **) &dir);
+      }
+      else dst = NIL;
+    }
+    else dst = NIL;		/* unknown namespace name */
+    break;
+  case '\\':			/* absolute path on default drive? */
+    sprintf (dst,"%s%s",homedev,name);
+    break;
+  default:			/* any other name */
+    if (name[1] == ':') {	/* some other drive? */
+      if (name[2] == '\\') strcpy (dst,name);
+      else sprintf (dst,"%c:\\%s",name[0],name+2);
+    }
+				/* build home-directory relative name */
+    else sprintf (dst,"%s\\%s",dir,name);
+  }
+  return dst;			/* return it */
+}
+
+/* Lock file name
+ * Accepts: return buffer for file name
+ *	    file name
+ *	    locking to be placed on file if non-NIL
+ * Returns: file descriptor of lock or -1 if error
+ */
+
+int lockname (char *lock,char *fname,int op)
+{
+  int ld;
+  char c,*s;
+				/* Win2K and Win98 have TEMP under windir */
+  if (!((s = lockdir (lock,getenv ("windir"),"TEMP")) ||
+				/* NT4, NT3.x and Win95 use one of these */
+	(s = lockdir (lock,getenv ("TEMP"),NIL)) ||
+	(s = lockdir (lock,getenv ("TMP"),NIL)) ||
+	(s = lockdir (lock,getenv ("TMPDIR"),NIL)) ||
+				/* try one of these */
+	(s = lockdir (lock,defaultDrive (),"WINNT\\TEMP")) ||
+	(s = lockdir (lock,defaultDrive (),"WINDOWS\\TEMP")) ||
+				/* C:\TEMP is last resort */
+	(s = lockdir (lock,defaultDrive (),"TEMP")))) {
+    mm_log ("Unable to find temporary directory",ERROR);
+    return -1;
+  }
+				/* generate file name */
+  while (c = *fname++) switch (c) {
+  case '/': case '\\': case ':':
+    *s++ = '!';			/* convert bad chars to ! */
+    break;
+  default:
+    *s++ = c;
+    break;
+  }
+  *s++ = c;			/* tie off name */
+				/* get the lock */
+  if (((ld = open (lock,O_BINARY|O_RDWR|O_CREAT,S_IREAD|S_IWRITE)) >= 0) && op)
+    flock (ld,op);		/* apply locking function */
+  return ld;			/* return locking file descriptor */
+}
+
+/* Build lock directory, check to see if it exists
+ * Accepts: return buffer for lock directory
+ *	    first part of possible name
+ *	    optional second part
+ * Returns: pointer to end of buffer if buffer has a good name, else NIL
+ */
+
+char *lockdir (char *lock,char *first,char *last)
+{
+  struct stat sbuf;
+  char c,*s;
+  if (first && *first) {	/* first part must be non-NIL */
+				/* copy first part */
+    for (s = lock; c = *first++; *s++ = (c == '/') ? '\\' : c);
+    if (last && *last) {	/* copy last part if specified */
+				/* write trailing \ in case not in first */
+      if (s[-1] != '\\') *s++ = '\\';
+      while (c = *last++) *s++ = (c == '/') ? '\\' : c;
+    }
+    if (s[-1] == '\\') --s;	/* delete trailing \ if any */
+    *s = s[1] = '\0';		/* tie off name at this point */
+    if (!stat (lock,&sbuf)) {	/* does the name exist? */
+      *s++ = '\\';		/* yes, reinstall trailing \ */
+      return s;			/* return the name */
+    }
+  }
+  return NIL;			/* failed */
+}
+
+
+/* Unlock file descriptor
+ * Accepts: file descriptor
+ *	    lock file name from lockfd()
+ */
+
+void unlockfd (int fd,char *lock)
+{
+  flock (fd,LOCK_UN);		/* unlock it */
+  close (fd);			/* close it */
+}
+
+
+/* Determine default prototype stream to user
+ * Accepts: type (NIL for create, T for append)
+ * Returns: default prototype stream
+ */
+
+MAILSTREAM *default_proto (long type)
+{
+  extern MAILSTREAM CREATEPROTO,APPENDPROTO;
+  return type ? &APPENDPROTO : &CREATEPROTO;
+}
+
+/* Default block notify routine
+ * Accepts: reason for calling
+ *	    data
+ * Returns: data
+ */
+
+void *mm_blocknotify (int reason,void *data)
+{
+  void *ret = data;
+  switch (reason) {
+  case BLOCK_SENSITIVE:		/* entering sensitive code */
+    ret = (void *) alarm (0);
+    break;
+  case BLOCK_NONSENSITIVE:	/* exiting sensitive code */
+    if ((unsigned int) data) alarm ((unsigned int) data);
+    break;
+  default:			/* ignore all other reasons */
+    break;
+  }
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/env_nt.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,68 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	NT environment routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+#define SUBSCRIPTIONFILE(t) sprintf (t,"%s\\MAILBOX.LST",myhomedir ())
+#define SUBSCRIPTIONTEMP(t) sprintf (t,"%s\\MAILBOX.TMP",myhomedir ())
+
+/* Note: the \CRAM-MD5.PWD file only works on DOS-based Windows (Win9x/Me)
+ * and not on NT-based Windows (WinNT/2K/XP).  If installed on NT-based
+ * Windows, servers will advertise CRAM-MD5 authentication but it will
+ * never succeed.
+ */
+
+#define MD5ENABLE "\\cram-md5.pwd"
+
+#define L_SET SEEK_SET
+
+/* Function prototypes */
+
+#include "env.h"
+
+void rfc822_fixed_date (char *date);
+long env_init (char *user,char *home);
+int check_nt (void);
+char *win_homedir (char *user);
+static char *defaultDrive (void);
+char *myusername_full (unsigned long *flags);
+#define MU_LOGGEDIN 0
+#define MU_NOTLOGGEDIN 1
+#define MU_ANONYMOUS 2
+#define myusername() \
+  myusername_full (NIL)
+char *sysinbox ();
+char *mailboxdir (char *dst,char *dir,char *name);
+int lockname (char *lock,char *fname,int op);
+char *lockdir (char *lock,char *first,char *last);
+void unlockfd (int fd,char *lock);
+long safe_write (int fd,char *buf,long nbytes);
+void *mm_blocknotify (int reason,void *data);
+long random ();
+#if _MSC_VER < 700
+#define getpid random
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/fdstring.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,99 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	File descriptor string routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	15 April 1997
+ * Last Edited:	4 April 2007
+ */
+
+#include "mail.h"
+#include "osdep.h"
+#include "misc.h"
+#include "fdstring.h"
+
+/* String driver for fd stringstructs */
+
+static void fd_string_init (STRING *s,void *data,unsigned long size);
+static char fd_string_next (STRING *s);
+static void fd_string_setpos (STRING *s,unsigned long i);
+
+STRINGDRIVER fd_string = {
+  fd_string_init,		/* initialize string structure */
+  fd_string_next,		/* get next byte in string structure */
+  fd_string_setpos		/* set position in string structure */
+};
+
+
+/* Initialize string structure for fd stringstruct
+ * Accepts: string structure
+ *	    pointer to string
+ *	    size of string
+ */
+
+static void fd_string_init (STRING *s,void *data,unsigned long size)
+{
+  FDDATA *d = (FDDATA *) data;
+				/* note fd */
+  s->data = (void *) (unsigned long) d->fd;
+  s->data1 = d->pos;		/* note file offset */
+  s->size = size;		/* note size */
+  s->curpos = s->chunk = d->chunk;
+  s->chunksize = (unsigned long) d->chunksize;
+  s->offset = 0;		/* initial position */
+				/* and size of data */
+  s->cursize = min (s->chunksize,size);
+				/* move to that position in the file */
+  lseek (d->fd,d->pos,L_SET);
+  read (d->fd,s->chunk,(size_t) s->cursize);
+}
+
+/* Get next character from fd stringstruct
+ * Accepts: string structure
+ * Returns: character, string structure chunk refreshed
+ */
+
+static char fd_string_next (STRING *s)
+{
+  char c = *s->curpos++;	/* get next byte */
+  SETPOS (s,GETPOS (s));	/* move to next chunk */
+  return c;			/* return the byte */
+}
+
+
+/* Set string pointer position for fd stringstruct
+ * Accepts: string structure
+ *	    new position
+ */
+
+static void fd_string_setpos (STRING *s,unsigned long i)
+{
+  if (i > s->size) i = s->size;	/* don't permit setting beyond EOF */
+  s->offset = i;		/* set new offset */
+  s->curpos = s->chunk;		/* reset position */
+				/* set size of data */
+  if (s->cursize = min (s->chunksize,SIZE (s))) {
+				/* move to that position in the file */
+    lseek ((long) s->data,s->data1 + s->offset,L_SET);
+    read ((long) s->data,s->curpos,(size_t) s->cursize);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/fdstring.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,39 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	File descriptor string routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	15 April 1997
+ * Last Edited:	30 August 2006
+ */
+
+/* Driver-dependent data passed to init method */
+
+typedef struct fd_data {
+  int fd;			/* file descriptor */
+  unsigned long pos;		/* initial position */
+  char *chunk;			/* I/O buffer chunk */
+  unsigned long chunksize;	/* I/O buffer chunk length */
+} FDDATA;
+
+
+extern STRINGDRIVER fd_string;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/fs_nt.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,62 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Free storage management routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Get a block of free storage
+ * Accepts: size of desired block
+ * Returns: free storage block
+ */
+
+void *fs_get (size_t size)
+{
+  void *block = malloc (size ? size : (size_t) 1);
+  if (!block) fatal ("Out of memory");
+  return (block);
+}
+
+
+/* Resize a block of free storage
+ * Accepts: ** pointer to current block
+ *	    new size
+ */
+
+void fs_resize (void **block,size_t size)
+{
+  if (!(*block = realloc (*block,size ? size : (size_t) 1)))
+    fatal ("Can't resize memory");
+}
+
+
+/* Return a block of free storage
+ * Accepts: ** pointer to free storage block
+ */
+
+void fs_give (void **block)
+{
+  free (*block);
+  *block = NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/ftl_nt.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,38 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	DOS/VMS/TOPS-20 crash management routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Report a fatal error
+ * Accepts: string to output
+ */
+
+void fatal (char *string)
+{
+  mm_fatal (string);		/* pass up the string */
+  abort ();			/* die horribly */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/ip4_nt.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,184 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX IPv4 routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	18 December 2003
+ * Last Edited:	30 August 2006
+ */
+
+#define SADRLEN sizeof (struct sockaddr)
+
+#define SADR4(sadr) ((struct sockaddr_in *) sadr)
+#define SADR4LEN sizeof (struct sockaddr_in)
+#define SADR4ADR(sadr) SADR4 (sadr)->sin_addr
+#define ADR4LEN sizeof (struct in_addr)
+#define SADR4PORT(sadr) SADR4 (sadr)->sin_port
+
+
+/* IP abstraction layer */
+
+char *ip_sockaddrtostring (struct sockaddr *sadr);
+long ip_sockaddrtoport (struct sockaddr *sadr);
+void *ip_stringtoaddr (char *text,size_t *len,int *family);
+struct sockaddr *ip_newsockaddr (size_t *len);
+struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen,
+			      unsigned short port,size_t *len);
+char *ip_sockaddrtoname (struct sockaddr *sadr);
+void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical,
+		     void **next);
+
+/* Return IP address string from socket address
+ * Accepts: socket address
+ * Returns: IP address as name string
+ */
+
+char *ip_sockaddrtostring (struct sockaddr *sadr)
+{
+  return (sadr->sa_family == PF_INET) ?
+    inet_ntoa (SADR4ADR (sadr)) : "NON-IPv4";
+}
+
+
+/* Return port from socket address
+ * Accepts: socket address
+ * Returns: port number or -1 if can't determine it
+ */
+
+long ip_sockaddrtoport (struct sockaddr *sadr)
+{
+  return (sadr->sa_family == PF_INET) ? ntohs (SADR4PORT (sadr)) : -1;
+}
+
+
+/* Return IP address from string
+ * Accepts: name string
+ *	    pointer to returned length
+ *	    pointer to returned address family
+ * Returns: address if valid, length and family updated, or NIL
+ */
+
+void *ip_stringtoaddr (char *text,size_t *len,int *family)
+{
+  unsigned long adr;
+  struct in_addr *ret;
+				/* get address */
+  if ((adr = inet_addr (text)) == -1) ret = NIL;
+  else {			/* make in_addr */
+    ret = (struct in_addr *) fs_get (*len = ADR4LEN);
+    *family = AF_INET;		/* IPv4 */
+    ret->s_addr = adr;		/* set address */
+  }
+  return (void *) ret;
+}
+
+/* Create a maximum-size socket address
+ * Accepts: pointer to return maximum socket address length
+ * Returns: new, empty socket address of maximum size
+ */
+
+struct sockaddr *ip_newsockaddr (size_t *len)
+{
+  return (struct sockaddr *) memset (fs_get (SADRLEN),0,*len = SADRLEN);
+}
+
+
+/* Stuff a socket address
+ * Accepts: address family
+ *	    IPv4 address
+ *	    length of address (always 4 in IPv4)
+ *	    port number
+ *	    pointer to return socket address length
+ * Returns: socket address or NIL if error
+ */
+
+struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen,
+			      unsigned short port,size_t *len)
+{
+  struct sockaddr *sadr = ip_newsockaddr (len);
+  switch (family) {		/* build socket address based upon family */
+  case AF_INET:			/* IPv4 */
+    sadr->sa_family = PF_INET;
+				/* copy host address */
+    memcpy (&SADR4ADR (sadr),adr,adrlen);
+				/* copy port number in network format */
+    SADR4PORT (sadr) = htons (port);
+    *len = SADR4LEN;
+    break;
+  default:			/* non-IP?? */
+    sadr->sa_family = PF_UNSPEC;
+    break;
+  }
+  return sadr;
+}
+
+/* Return name from socket address
+ * Accepts: socket address
+ * Returns: canonical name for that address or NIL if none
+ */
+
+char *ip_sockaddrtoname (struct sockaddr *sadr)
+{
+  struct hostent *he;
+  return ((sadr->sa_family == PF_INET) &&
+	  (he = gethostbyaddr ((char *) &SADR4ADR (sadr),ADR4LEN,AF_INET))) ?
+    (char *) he->h_name : NIL;
+}
+
+
+/* Return address from name
+ * Accepts: name or NIL to return next address
+ *	    pointer to previous/returned length
+ *	    pointer to previous/returned address family
+ *	    pointer to previous/returned canonical name
+ *	    pointer to previous/return state for next-address calls
+ * Returns: address with length/family/canonical updated if needed, or NIL
+ */
+
+void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical,
+		     void **next)
+{
+  char **adl,tmp[MAILTMPLEN];
+  struct hostent *he;
+  if (name) {			/* first lookup? */
+				/* yes, do case-independent lookup */
+    if ((strlen (name) < MAILTMPLEN) &&
+	(he = gethostbyname (lcase (strcpy (tmp,name))))) {
+      adl = he->h_addr_list;
+      if (len) *len = he->h_length;
+      if (family) *family = he->h_addrtype;
+      if (canonical) *canonical = (char *) he->h_name;
+      if (next) *next = (void *) adl;
+    }
+    else {			/* error */
+      adl = NIL;
+      if (len) *len = 0;
+      if (family) *family = 0;
+      if (canonical) *canonical = NIL;
+      if (next) *next = NIL;
+    }
+  }
+				/* return next in series */
+  else if (next && (adl = (char **) *next)) *next = ++adl;
+  else adl = NIL;		/* failure */
+  return adl ? (void *) *adl : NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/ip6_nt.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,288 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX IPv6 routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	18 December 2003
+ * Last Edited:	30 August 2006
+ */
+
+
+/*
+ * There is some amazingly bad design in IPv6 sockets.
+ *
+ * Supposedly, the new getnameinfo() and getaddrinfo() functions create an
+ * abstraction that is not dependent upon IPv4 or IPv6.  However, the
+ * definition of getnameinfo() requires that the caller pass the length of
+ * the sockaddr instead of deriving it from sa_family.  The man page says
+ * that there's an sa_len member in the sockaddr, but actually there isn't.
+ * This means that any caller to getnameinfo() and getaddrinfo() has to know
+ * the size for the protocol family used by that sockaddr.
+ *
+ * The new sockaddr_in6 is bigger than the generic sockaddr (which is what
+ * connect(), accept(), bind(), getpeername(), getsockname(), etc. expect).
+ * Rather than increase the size of sockaddr, there's a new sockaddr_storage
+ * which is only usable for allocating space.
+ */
+
+#define SADRLEN sizeof (struct sockaddr_storage)
+
+#define SADR4(sadr) ((struct sockaddr_in *) sadr)
+#define SADR4LEN sizeof (struct sockaddr_in)
+#define SADR4ADR(sadr) SADR4 (sadr)->sin_addr
+#define ADR4LEN sizeof (struct in_addr)
+#define SADR4PORT(sadr) SADR4 (sadr)->sin_port
+
+#define SADR6(sadr) ((struct sockaddr_in6 *) sadr)
+#define SADR6LEN sizeof (struct sockaddr_in6)
+#define SADR6ADR(sadr) SADR6 (sadr)->sin6_addr
+#define ADR6LEN sizeof (struct in6_addr)
+#define SADR6PORT(sadr) SADR6 (sadr)->sin6_port
+
+
+/* IP abstraction layer */
+
+char *ip_sockaddrtostring (struct sockaddr *sadr);
+long ip_sockaddrtoport (struct sockaddr *sadr);
+void *ip_stringtoaddr (char *text,size_t *len,int *family);
+struct sockaddr *ip_newsockaddr (size_t *len);
+struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen,
+			      unsigned short port,size_t *len);
+char *ip_sockaddrtoname (struct sockaddr *sadr);
+void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical,
+		     void **next);
+
+/* Return IP address string from socket address
+ * Accepts: socket address
+ * Returns: IP address as name string
+ */
+
+char *ip_sockaddrtostring (struct sockaddr *sadr)
+{
+  static char tmp[NI_MAXHOST];
+  switch (sadr->sa_family) {
+  case PF_INET:			/* IPv4 */
+    if (!getnameinfo (sadr,SADR4LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NUMERICHOST))
+      return tmp;
+    break;
+  case PF_INET6:		/* IPv6 */
+    if (!getnameinfo (sadr,SADR6LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NUMERICHOST))
+      return tmp;
+    break;
+  }
+  return "NON-IP";
+}
+
+
+/* Return port from socket address
+ * Accepts: socket address
+ * Returns: port number or -1 if can't determine it
+ */
+
+long ip_sockaddrtoport (struct sockaddr *sadr)
+{
+  switch (sadr->sa_family) {
+  case PF_INET:
+    return ntohs (SADR4PORT (sadr));
+  case PF_INET6:
+    return ntohs (SADR6PORT (sadr));
+  }
+  return -1;
+}
+
+/* Return IP address from string
+ * Accepts: name string
+ *	    pointer to returned length
+ *	    pointer to returned address family
+ * Returns: address if valid, length and family updated, or NIL
+ */
+
+void *ip_stringtoaddr (char *text,size_t *len,int *family)
+
+{
+  char tmp[MAILTMPLEN];
+  static struct addrinfo *hints;
+  struct addrinfo *ai;
+  void *adr = NIL;
+  if (!hints) {			/* hints set up yet? */
+    hints = (struct addrinfo *) /* one-time setup */
+      memset (fs_get (sizeof (struct addrinfo)),0,sizeof (struct addrinfo));
+    hints->ai_family = AF_UNSPEC;/* allow any address family */
+    hints->ai_socktype = SOCK_STREAM;
+				/* numeric name only */
+    hints->ai_flags = AI_NUMERICHOST;
+  }
+				/* case-independent lookup */
+  if (text && (strlen (text) < MAILTMPLEN) &&
+      (!getaddrinfo (lcase (strcpy (tmp,text)),NIL,hints,&ai))) {
+    switch (*family = ai->ai_family) {
+    case AF_INET:		/* IPv4 */
+      adr = fs_get (*len = ADR4LEN);
+      memcpy (adr,(void *) &SADR4ADR (ai->ai_addr),*len);
+      break;
+    case AF_INET6:		/* IPv6 */
+      adr = fs_get (*len = ADR6LEN);
+      memcpy (adr,(void *) &SADR6ADR (ai->ai_addr),*len);
+      break;
+    }
+    freeaddrinfo (ai);		/* free addrinfo */
+  }
+  return adr;
+}
+
+/* Create a maximum-size socket address
+ * Accepts: pointer to return maximum socket address length
+ * Returns: new, empty socket address of maximum size
+ */
+
+struct sockaddr *ip_newsockaddr (size_t *len)
+{
+  return (struct sockaddr *) memset (fs_get (SADRLEN),0,*len = SADRLEN);
+}
+
+
+/* Stuff a socket address
+ * Accepts: address family
+ *	    IPv4 address
+ *	    length of address
+ *	    port number
+ *	    pointer to return socket address length
+ * Returns: socket address
+ */
+
+struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen,
+			      unsigned short port,size_t *len)
+{
+  struct sockaddr *sadr = ip_newsockaddr (len);
+  switch (family) {		/* build socket address based upon family */
+  case AF_INET:			/* IPv4 */
+    sadr->sa_family = PF_INET;
+				/* copy host address */
+    memcpy (&SADR4ADR (sadr),adr,adrlen);
+				/* copy port number in network format */
+    SADR4PORT (sadr) = htons (port);
+    *len = SADR4LEN;
+    break;
+  case AF_INET6:		/* IPv6 */
+    sadr->sa_family = PF_INET6;
+				/* copy host address */
+    memcpy (&SADR6ADR (sadr),adr,adrlen);
+				/* copy port number in network format */
+    SADR6PORT (sadr) = htons (port);
+    *len = SADR6LEN;
+    break;
+  default:			/* non-IP?? */
+    sadr->sa_family = PF_UNSPEC;
+    break;
+  }
+  return sadr;
+}
+
+/* Return name from socket address
+ * Accepts: socket address
+ * Returns: canonical name for that address or NIL if none
+ */
+
+char *ip_sockaddrtoname (struct sockaddr *sadr)
+{
+  static char tmp[NI_MAXHOST];
+  switch (sadr->sa_family) {
+  case PF_INET:			/* IPv4 */
+    if (!getnameinfo (sadr,SADR4LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NAMEREQD))
+      return tmp;
+    break;
+  case PF_INET6:		/* IPv6 */
+    if (!getnameinfo (sadr,SADR6LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NAMEREQD))
+      return tmp;
+    break;
+  }
+  return NIL;
+}
+
+/* Return address from name
+ * Accepts: name or NIL to return next address
+ *	    pointer to previous/returned length
+ *	    pointer to previous/returned address family
+ *	    pointer to previous/returned canonical name
+ *	    pointer to previous/return state for next-address calls
+ * Returns: address with length/family/canonical updated if needed, or NIL
+ */
+
+void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical,
+		     void **next)
+{
+  struct addrinfo *cur = NIL;
+  static struct addrinfo *hints;
+  static struct addrinfo *ai = NIL;
+  static char lcname[MAILTMPLEN];
+  if (!hints) {			/* hints set up yet? */
+    hints = (struct addrinfo *) /* one-time setup */
+      memset (fs_get (sizeof (struct addrinfo)),0,sizeof (struct addrinfo));
+				/* allow any address family */
+    hints->ai_family = AF_UNSPEC;
+    hints->ai_socktype = SOCK_STREAM;
+				/* need canonical name */
+    hints->ai_flags = AI_CANONNAME;
+  }
+  if (name) {			/* name supplied? */
+    if (ai) {
+      freeaddrinfo (ai);	/* free old addrinfo */
+      ai = NIL;
+    }
+				/* case-independent lookup */
+    if ((strlen (name) < MAILTMPLEN) &&
+	(!getaddrinfo (lcase (strcpy (lcname,name)),NIL,hints,&ai))) {
+      cur = ai;			/* current block */
+      if (canonical)		/* set canonical name */
+	*canonical = cur->ai_canonname ? cur->ai_canonname : lcname;
+				/* remember as next block */
+      if (next) *next = (void *) ai;
+    }
+    else {			/* error */
+      cur = NIL;
+      if (len) *len = 0;
+      if (family) *family = 0;
+      if (canonical) *canonical = NIL;
+      if (next) *next = NIL;
+    }
+  }
+				/* return next in series */
+  else if (next && (cur = ((struct addrinfo *) *next)->ai_next)) {
+    *next = cur;		/* set as last address */
+				/* set canonical in case changed */
+    if (canonical && cur->ai_canonname) *canonical = cur->ai_canonname;
+  }
+
+  if (cur) {			/* got data? */
+    if (family) *family = cur->ai_family;
+    switch (cur->ai_family) {
+    case AF_INET:
+      if (len) *len = ADR4LEN;
+      return (void *) &SADR4ADR (cur->ai_addr);
+    case AF_INET6:
+      if (len) *len = ADR6LEN;
+      return (void *) &SADR6ADR (cur->ai_addr);
+    }
+  }
+  if (len) *len = 0;		/* error return */
+  return NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/kerb_mit.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,74 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	MIT Kerberos routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	4 March 2003
+ * Last Edited:	30 August 2006
+ */
+
+#define PROTOTYPE(x) x
+#include <gssapi/gssapi_generic.h>
+#include <gssapi/gssapi_krb5.h>
+
+
+long kerberos_server_valid (void);
+long kerberos_try_kinit (OM_uint32 error);
+char *kerberos_login (char *user,char *authuser,int argc,char *argv[]);
+
+/* Kerberos server valid check
+ * Returns: T if have keytab, NIL otherwise
+ */
+
+long kerberos_server_valid ()
+{
+  return NIL;
+}
+
+
+/* Kerberos check for missing or expired credentials
+ * Returns: T if should suggest running kinit, NIL otherwise
+ */
+
+long kerberos_try_kinit (OM_uint32 error)
+{
+  switch (error) {
+  case KRB5KRB_AP_ERR_TKT_EXPIRED:
+  case KRB5_FCC_NOFILE:		/* MIT */
+  case KRB5_CC_NOTFOUND:	/* Heimdal */
+    return LONGT;
+  }
+  return NIL;
+}
+
+/* Kerberos server log in
+ * Accepts: authorization ID as user name
+ *	    authentication ID as Kerberos principal
+ *	    argument count
+ *	    argument vector
+ * Returns: logged in user name if logged in, NIL otherwise
+ */
+
+char *kerberos_login (char *user,char *authuser,int argc,char *argv[])
+{
+  return NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/kerb_w2k.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,699 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	GSSAPI Kerberos Shim 5 for Windows 2000/XP IMAP Toolkit
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	6 March 2000
+ * Last Edited:	30 August 2006
+ */
+
+/*  The purpose of this module is to be a shim, so that the auth_gss.c module
+ * (written for MIT Kerberos) will compile, link, and run with SSPI Kerberos
+ * on Windows 2000 systems.
+ *  There is no attempt whatsoever to make this be a complete implementation
+ * of GSSAPI.  A number of shortcuts were taken that a real GSSAPI
+ * implementation for SSPI can't do.
+ *  Nor is there any attempt to make the types identical with MIT Kerberos;
+ * you can't link this library with object files compiled with the MIT
+ * Kerberos .h files.
+ */
+
+
+/* GSSAPI generic definitions */
+
+
+#define SECURITY_WIN32
+#include <security.h>
+
+
+/* GSSAPI types for which we use SSPI equivalent types */
+
+typedef ULONG OM_uint32;
+typedef PCredHandle gss_cred_id_t;
+typedef ULONG gss_cred_usage_t;
+typedef PCtxtHandle gss_ctx_id_t;
+typedef SEC_CHAR * gss_name_t;
+typedef ULONG gss_qop_t;
+
+
+/* Major status codes */
+
+#define GSS_S_COMPLETE SEC_E_OK
+#define GSS_S_BAD_MECH SEC_E_SECPKG_NOT_FOUND
+#define GSS_S_CONTINUE_NEEDED SEC_I_CONTINUE_NEEDED
+#define GSS_S_CREDENTIALS_EXPIRED SEC_E_CERT_EXPIRED
+#define GSS_S_FAILURE SEC_E_INTERNAL_ERROR
+#define GSS_S_NO_CRED SEC_E_NO_CREDENTIALS
+#define GSS_S_NO_CONTEXT SEC_E_INVALID_HANDLE
+
+
+/* Flag bits for context-level services */
+
+#define GSS_C_DELEG_FLAG ISC_REQ_DELEGATE
+#define GSS_C_MUTUAL_FLAG ISC_REQ_MUTUAL_AUTH
+#define GSS_C_REPLAY_FLAG ISC_REQ_REPLAY_DETECT
+#define GSS_C_SEQUENCE_FLAG ISC_REQ_SEQUENCE_DETECT
+#define GSS_C_CONF_FLAG ISC_REQ_CONFIDENTIALITY
+#define GSS_C_INTEG_FLAG ISC_REQ_INTEGRITY
+
+
+/* Credential usage options */
+
+#define GSS_C_BOTH SECPKG_CRED_BOTH
+#define GSS_C_INITIATE SECPKG_CRED_OUTBOUND
+#define GSS_C_ACCEPT SECPKG_CRED_INBOUND
+
+
+/* Major status codes defined by shim */
+
+#define GSS_S_BAD_BINDINGS 100
+#define GSS_S_BAD_NAME 101
+#define GSS_S_BAD_NAMETYPE 102
+#define GSS_S_BAD_STATUS 103
+
+/* GSSAPI types as used in GSSAPI */
+
+
+/* Buffer */
+
+typedef struct gss_buffer_desc_struct {
+  size_t length;
+  void *value;
+} gss_buffer_desc,*gss_buffer_t;
+
+
+/* Object identifier */
+
+typedef struct gss_OID_desc_struct {
+  OM_uint32 length;
+  void *elements;
+} gss_OID_desc,*gss_OID;
+
+typedef struct gss_OID_set_desc_struct {
+  size_t count;
+  gss_OID elements;
+} gss_OID_set_desc,*gss_OID_set;
+
+
+/* Unused, but needed in prototypes */
+
+typedef void * gss_channel_bindings_t;
+
+
+/* Default constants */
+
+#define GSS_C_EMPTY_BUFFER {0,NIL}
+#define GSS_C_NO_BUFFER ((gss_buffer_t) NIL)
+#define GSS_C_NO_OID ((gss_OID) NIL)
+#define GSS_C_NO_CONTEXT ((gss_ctx_id_t) NIL)
+#define GSS_C_NO_CREDENTIAL ((gss_cred_id_t) NIL)
+#define GSS_C_NO_CHANNEL_BINDINGS ((gss_channel_bindings_t) NIL)
+#define GSS_C_QOP_DEFAULT NIL
+
+
+/* Status code types for gss_display_status */
+
+#define GSS_C_GSS_CODE 1
+#define GSS_C_MECH_CODE 2
+
+
+/* GSSAPI constants */
+
+const gss_OID gss_nt_service_name;
+#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
+const gss_OID gss_mech_krb5;
+const gss_OID_set gss_mech_set_krb5;
+
+/* GSSAPI prototypes */
+
+
+OM_uint32 gss_accept_sec_context (OM_uint32 *minor_status,
+				  gss_ctx_id_t *context_handle,
+				  gss_cred_id_t acceptor_cred_handle,
+				  gss_buffer_t input_token_buffer,
+				  gss_channel_bindings_t input_chan_bindings,
+				  gss_name_t *src_name,gss_OID *mech_type,
+				  gss_buffer_t output_token,
+				  OM_uint32 *ret_flags,OM_uint32 *time_rec,
+				  gss_cred_id_t *delegated_cred_handle);
+OM_uint32 gss_acquire_cred (OM_uint32 *minor_status,gss_name_t desired_name,
+			    OM_uint32 time_req,gss_OID_set desired_mechs,
+			    gss_cred_usage_t cred_usage,
+			    gss_cred_id_t *output_cred_handle,
+			    gss_OID_set *actual_mechs,OM_uint32 *time_rec);
+OM_uint32 gss_delete_sec_context (OM_uint32 *minor_status,
+				  gss_ctx_id_t *context_handle,
+				  gss_buffer_t output_token);
+OM_uint32 gss_display_name (OM_uint32 *minor_status,gss_name_t input_name,
+			    gss_buffer_t output_name_buffer,
+			    gss_OID *output_name_type);
+OM_uint32 gss_display_status (OM_uint32 *minor_status,OM_uint32 status_value,
+			      int status_type,gss_OID mech_type,
+			      OM_uint32 *message_context,
+			      gss_buffer_t status_string);
+OM_uint32 gss_import_name (OM_uint32 *minor_status,
+			   gss_buffer_t input_name_buffer,
+			   gss_OID input_name_type,gss_name_t *output_name);
+OM_uint32 gss_init_sec_context (OM_uint32 *minor_status,
+				gss_cred_id_t claimant_cred_handle,
+				gss_ctx_id_t *context_handle,
+				gss_name_t target_name,gss_OID mech_type,
+				OM_uint32 req_flags,OM_uint32 time_req,
+				gss_channel_bindings_t input_chan_bindings,
+				gss_buffer_t input_token,
+				gss_OID *actual_mech_type,
+				gss_buffer_t output_token,OM_uint32 *ret_flags,
+				OM_uint32 *time_rec);
+OM_uint32 gss_release_buffer (OM_uint32 *minor_status,gss_buffer_t buffer);
+OM_uint32 gss_release_cred (OM_uint32 *minor_status,gss_cred_id_t *cred_handle);
+OM_uint32 gss_release_name (OM_uint32 *minor_status,gss_name_t *input_name);
+OM_uint32 gss_wrap (OM_uint32 *minor_status,gss_ctx_id_t context_handle,
+		    int conf_req_flag,gss_qop_t qop_req,
+		    gss_buffer_t input_message_buffer,int *conf_state,
+		    gss_buffer_t output_message_buffer);
+OM_uint32 gss_unwrap (OM_uint32 *minor_status,gss_ctx_id_t context_handle,
+		      gss_buffer_t input_message_buffer,
+		      gss_buffer_t output_message_buffer,int *conf_state,
+		      gss_qop_t *qop_state);
+
+/* Kerberos definitions */
+
+long kerberos_server_valid (void);
+long kerberos_try_kinit (OM_uint32 error);
+char *kerberos_login (char *user,char *authuser,int argc,char *argv[]);
+
+
+#define STRING WINSTRING	/* conflict with mail.h */
+#include <NTSecAPI.h>
+
+/* GSSAPI build-in object identifiers */
+
+static gss_OID_desc oids[] = {	/* stupid C language makes this necessary */
+  {10,"\052\206\110\206\367\022\001\002\001\004"},
+  {9,"\052\206\110\206\367\022\001\002\002"}
+};
+
+				/* stupid C language ditto */
+static gss_OID_set_desc oidsets[] = {
+  {1,(gss_OID) oids+1}
+};
+
+				/* these are the real OIDs */
+const gss_OID gss_nt_service_name = oids+0;
+const gss_OID gss_mech_krb5 = oids+1;
+const gss_OID_set gss_mech_set_krb5 = oidsets+0;
+
+
+/* Other globals */
+
+				/* substitute for GSS_C_NO_CREDENTIAL */
+static gss_cred_id_t gss_default_cred = NIL;
+
+/* GSSAPI import name (convert to full service principal name)
+ * Accepts: pointer to return minor status
+ *	    buffer containining input name
+ *	    type of input name
+ *	    pointer to return output internal name
+ * Returns: major status, always
+ */
+
+OM_uint32 gss_import_name (OM_uint32 *minor_status,
+			   gss_buffer_t input_name_buffer,
+			   gss_OID input_name_type,gss_name_t *output_name)
+{
+  OM_uint32 major_status = GSS_S_COMPLETE;
+  TimeStamp expiry;
+  static CredHandle gss_cred;
+  char *s,tmp[MAILTMPLEN];
+  *minor_status = 0;		/* never any minor status */
+  if (!gss_default_cred) {	/* default credentials set up yet? */
+    if (AcquireCredentialsHandle/* no, acquire them now */
+	(NIL,MICROSOFT_KERBEROS_NAME_A,SECPKG_CRED_OUTBOUND,NIL,NIL,NIL,NIL,
+	 &gss_cred,&expiry) != SEC_E_OK) return GSS_S_FAILURE;
+				/* have default credentials now */
+    gss_default_cred = &gss_cred;
+  }
+				/* must be the gss_nt_service_name format */
+  if (input_name_type != gss_nt_service_name)
+    major_status = GSS_S_BAD_NAMETYPE;
+				/* name must be of sane length */
+  else if (input_name_buffer->length > (MAILTMPLEN/2))
+    major_status = GSS_S_BAD_NAME;
+  else {			/* copy name */
+    memcpy (tmp,input_name_buffer->value,input_name_buffer->length);
+    tmp[input_name_buffer->length] = '\0';
+    if (s = strchr (tmp,'@')) {	/* find service/host/delimiter */
+      *s = '/';			/* convert to full service principal name */
+      *output_name = cpystr (tmp);
+    }
+    else major_status = GSS_S_BAD_NAME;
+  }
+  return major_status;
+}
+
+/* GSSAPI Initialize security context
+ * Accepts: pointer to return minor status
+ *	    claimant credential handle
+ *	    context (NIL means "none assigned yet")
+ *	    desired principal
+ *	    desired mechanisms
+ *	    required context attributes
+ *	    desired lifetime
+ *	    input channel bindings
+ *	    input token buffer
+ *	    pointer to return mechanism type
+ *	    buffer to return output token
+ *	    pointer to return flags
+ *	    pointer to return context lifetime
+ * Returns: major status, always
+ */
+
+OM_uint32 gss_init_sec_context (OM_uint32 *minor_status,
+				gss_cred_id_t claimant_cred_handle,
+				gss_ctx_id_t *context_handle,
+				gss_name_t target_name,gss_OID mech_type,
+				OM_uint32 req_flags,OM_uint32 time_req,
+				gss_channel_bindings_t input_chan_bindings,
+				gss_buffer_t input_token,
+				gss_OID *actual_mech_type,
+				gss_buffer_t output_token,OM_uint32 *ret_flags,
+				OM_uint32 *time_rec)
+{
+  OM_uint32 i;
+  OM_uint32 major_status;
+  TimeStamp expiry;
+  SecBuffer ibuf[1],obuf[1];
+  SecBufferDesc ibufs,obufs;
+  *minor_status = 0;		/* never any minor status */
+				/* error if non-default time requested */
+  if (time_req) return GSS_S_FAILURE;
+  if (mech_type && memcmp (mech_type,gss_mech_krb5,sizeof (gss_OID)))
+    return GSS_S_BAD_MECH;
+				/* ditto if any channel bindings */
+  if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS)
+    return GSS_S_BAD_BINDINGS;
+
+				/* apply default credential if necessary */
+  if (claimant_cred_handle == GSS_C_NO_CREDENTIAL)
+    claimant_cred_handle = gss_default_cred;
+				/* create output buffer storage as needed */
+  req_flags |= ISC_REQ_ALLOCATE_MEMORY;
+				/* make output buffer */
+  obuf[0].BufferType = SECBUFFER_TOKEN;
+  obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NIL;
+				/* output buffer descriptor */
+  obufs.ulVersion = SECBUFFER_VERSION;
+  obufs.cBuffers = 1;
+  obufs.pBuffers = obuf;
+				/* first time caller? */
+  if (*context_handle == GSS_C_NO_CONTEXT) {
+				/* yes, set up output context handle */
+    PCtxtHandle ctx = (PCtxtHandle) fs_get (sizeof (CtxtHandle));
+    major_status = InitializeSecurityContext (claimant_cred_handle,NIL,
+					      target_name,req_flags,0,
+					      SECURITY_NETWORK_DREP,NIL,0,ctx,
+					      &obufs,
+					      ret_flags ? ret_flags : &i,
+					      &expiry);
+    *context_handle = ctx;	/* return updated context */
+  }
+  else {			/* no, make SSPI buffer from GSSAPI buffer */
+    ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN;
+    ibuf[0].cbBuffer = input_token->length;
+    ibuf[0].pvBuffer = input_token->value;
+				/* input buffer descriptor */
+    ibufs.ulVersion = SECBUFFER_VERSION;
+    ibufs.cBuffers = 1;
+    ibufs.pBuffers = ibuf;
+    major_status = InitializeSecurityContext (claimant_cred_handle,
+					      *context_handle,target_name,
+					      req_flags,0,
+					      SECURITY_NETWORK_DREP,&ibufs,0,
+					      *context_handle,&obufs,
+					      ret_flags ? ret_flags : &i,
+					      &expiry);
+  }
+				/* return output */
+  output_token->value = obuf[0].pvBuffer;
+  output_token->length = obuf[0].cbBuffer;
+				/* in case client wanted lifetime returned */
+  if (time_rec) *time_rec = expiry.LowPart;
+  return major_status;
+}
+
+/* GSSAPI display status text
+ * Accepts: pointer to return minor status
+ *	    status to display
+ *	    status type
+ *	    message context for continuation
+ *	    buffer to write status string
+ * Returns: major status, always
+ */
+
+OM_uint32 gss_display_status (OM_uint32 *minor_status,OM_uint32 status_value,
+			      int status_type,gss_OID mech_type,
+			      OM_uint32 *message_context,
+			      gss_buffer_t status_string)
+{
+  char *s,tmp[MAILTMPLEN];
+  *minor_status = 0;		/* never any minor status */
+  if (*message_context) return GSS_S_FAILURE;
+  switch (status_type) {	/* what type of status code? */
+  case GSS_C_GSS_CODE:		/* major_status */
+    switch (status_value) {	/* analyze status value */
+    case GSS_S_FAILURE:
+      s = "Unspecified failure"; break;
+    case GSS_S_CREDENTIALS_EXPIRED:
+      s = "Credentials expired"; break;
+    case GSS_S_BAD_BINDINGS:
+      s = "Bad bindings"; break;
+    case GSS_S_BAD_MECH:
+      s = "Bad mechanism type"; break;
+    case GSS_S_BAD_NAME:
+      s = "Bad name"; break;
+    case GSS_S_BAD_NAMETYPE:
+      s = "Bad name type"; break;
+    case GSS_S_BAD_STATUS:
+      s = "Bad status"; break;
+    case GSS_S_NO_CONTEXT:
+      s = "Invalid context handle"; break;
+    case GSS_S_NO_CRED:
+      s = "Unable to authenticate to Kerberos service";
+      mail_parameters (NIL,DISABLE_AUTHENTICATOR,"GSSAPI");
+      break;
+    case SEC_E_NO_AUTHENTICATING_AUTHORITY:
+      s = "No authenticating authority"; break;
+    case SEC_E_TARGET_UNKNOWN:
+      s = "Destination server unknown to Kerberos service"; break;
+    default:
+      sprintf (s = tmp,"SSPI code %lx",status_value);
+    }
+    break;
+  case GSS_C_MECH_CODE:		/* minor status - drop into default */
+  default:
+    return GSS_S_BAD_STATUS;	/* bad status type */
+  }
+				/* return status string */
+  status_string->length = strlen (status_string->value = cpystr (s));
+  return GSS_S_COMPLETE;
+}
+
+/* GSSAPI delete security context
+ * Accepts: pointer to return minor status
+ *	    context to delete
+ *	    output context token
+ * Returns: major status, always
+ */
+
+OM_uint32 gss_delete_sec_context (OM_uint32 *minor_status,
+				  gss_ctx_id_t *context_handle,
+				  gss_buffer_t output_token)
+{
+  OM_uint32 major_status;
+  *minor_status = 0;		/* never any minor status */
+				/* output token not supported */
+  major_status = output_token ? GSS_S_FAILURE :
+    DeleteSecurityContext (*context_handle);
+  fs_give ((void **) context_handle);
+  return major_status;
+}
+
+
+/* GSSAPI release buffer
+ * Accepts: pointer to return minor status
+ *	    buffer to release
+ * Returns: GSS_S_COMPLETE, always
+ */
+
+OM_uint32 gss_release_buffer (OM_uint32 *minor_status,gss_buffer_t buffer)
+{
+  *minor_status = 0;		/* never any minor status */
+  fs_give (&buffer->value);
+  return GSS_S_COMPLETE;
+}
+
+
+/* GSSAPI release name
+ * Accepts: pointer to return minor status
+ *	    pointer to name to release
+ * Returns: GSS_S_COMPLETE, always
+ */
+
+OM_uint32 gss_release_name (OM_uint32 *minor_status,gss_name_t *input_name)
+{
+  *minor_status = 0;		/* never any minor status */
+  fs_give (input_name);
+  return GSS_S_COMPLETE;
+}
+
+/* GSSAPI wrap data
+ * Accepts: pointer to return minor status
+ *	    context handle
+ *	    requested confidentiality
+ *	    requested quality of protection
+ *	    input message buffer
+ *	    pointer to return confidentiality state
+ *	    output message buffer
+ * Returns: major status, always
+ */
+
+OM_uint32 gss_wrap (OM_uint32 *minor_status,gss_ctx_id_t context_handle,
+		    int conf_req_flag,gss_qop_t qop_req,
+		    gss_buffer_t input_message_buffer,int *conf_state,
+		    gss_buffer_t output_message_buffer)
+{
+  OM_uint32 major_status;
+  SecBuffer buf[3];
+  SecBufferDesc bufs;
+  SecPkgContext_Sizes sizes;
+  *minor_status = NIL;		/* never any minor status */
+  *conf_state = conf_req_flag;	/* same as requested */
+  if ((major_status =		/* get trailer and padding sizes */
+       QueryContextAttributes (context_handle,SECPKG_ATTR_SIZES,&sizes)) ==
+      SEC_E_OK) {
+				/* create big enough output buffer */
+    output_message_buffer->value =
+      fs_get (sizes.cbSecurityTrailer + input_message_buffer->length +
+	      sizes.cbBlockSize);
+    /* MSDN claims that for EncryptMessage() in Kerberos, you need an
+     * uninitialized SECBUFFER_STREAM_HEADER; a SECBUFFER_DATA that "contains
+     * the message to be encrypted.  The message is encrypted in place,
+     * overwriting the original contents of its buffer"; an uninitialized
+     * SECBUFFER_STREAM_TRAILER, and an uninitialized SECBUFFER_EMPTY.  I've
+     * never been able to get it to work that way.
+     */
+    bufs.cBuffers = 3;		/* set up buffer descriptor */
+    bufs.pBuffers = buf;
+    bufs.ulVersion = SECBUFFER_VERSION;
+    buf[0].BufferType = SECBUFFER_TOKEN;
+    buf[0].pvBuffer = output_message_buffer->value;
+    buf[0].cbBuffer = sizes.cbSecurityTrailer;
+				/* I/O buffer */
+    buf[1].BufferType = SECBUFFER_DATA;
+    buf[1].pvBuffer = ((char *) buf[0].pvBuffer) + buf[0].cbBuffer;
+    buf[1].cbBuffer = input_message_buffer->length;
+    memcpy (buf[1].pvBuffer,input_message_buffer->value,buf[1].cbBuffer);
+    buf[2].BufferType = SECBUFFER_PADDING;
+    buf[2].pvBuffer = ((char *) buf[1].pvBuffer) + buf[1].cbBuffer;
+    buf[2].cbBuffer = sizes.cbBlockSize;
+    if ((major_status = EncryptMessage (context_handle,qop_req,&bufs,0)) ==
+	GSS_S_COMPLETE) {
+				/* slide data as necessary (how annoying!) */
+      unsigned long i = sizes.cbSecurityTrailer - buf[0].cbBuffer;
+      if (i) buf[1].pvBuffer =
+	       memmove (((char *) buf[0].pvBuffer) + buf[0].cbBuffer,
+			buf[1].pvBuffer,buf[1].cbBuffer);
+      if (i += (input_message_buffer->length - buf[1].cbBuffer))
+	buf[1].pvBuffer = memmove (((char *)buf[1].pvBuffer) + buf[1].cbBuffer,
+		   buf[2].pvBuffer,buf[2].cbBuffer);
+      output_message_buffer->length = buf[0].cbBuffer + buf[1].cbBuffer +
+	buf[2].cbBuffer;
+    }
+    else fs_give (&output_message_buffer->value);
+  }
+  return major_status;		/* return status */
+}
+
+/* GSSAPI unwrap data
+ * Accepts: pointer to return minor status
+ *	    context handle
+ *	    input message buffer
+ *	    output message buffer
+ *	    pointer to return confidentiality state
+ *	    pointer to return quality of protection
+ * Returns: major status, always
+ */
+
+OM_uint32 gss_unwrap (OM_uint32 *minor_status,gss_ctx_id_t context_handle,
+		      gss_buffer_t input_message_buffer,
+		      gss_buffer_t output_message_buffer,int *conf_state,
+		      gss_qop_t *qop_state)
+{
+  OM_uint32 major_status;
+  SecBuffer buf[2];
+  SecBufferDesc bufs;
+  *minor_status = NIL;		/* never any minor status */
+  *conf_state = NIL;		/* or confidentiality state */
+  /* MSDN implies that all that is needed for DecryptMessage() in Kerberos
+   * is a single SECBUFFER_DATA which "contains the encrypted message.  The
+   * encrypted message is decrypted in place, overwriting the original
+   * contents of its buffer."  I've never been able to get it to work without
+   * using a SECBUFFER_STREAM for input and an uninitialized SECBUFFER_DATA
+   * for output.
+   * It *does* overwrite the input buffer, but not at the same point; e.g.
+   * with an input pointer of 0xa140a8 and size of 53, the output ends up
+   * at 0xa140d5 and size of 4.
+   */
+  bufs.cBuffers = 2;		/* set up buffer descriptor */
+  bufs.pBuffers = buf;
+  bufs.ulVersion = SECBUFFER_VERSION;
+				/* input buffer */
+  buf[0].BufferType = SECBUFFER_STREAM;
+  buf[0].pvBuffer = input_message_buffer->value;
+  buf[0].cbBuffer = input_message_buffer->length;
+				/* output buffer */
+  buf[1].BufferType = SECBUFFER_DATA;
+  buf[1].pvBuffer = NIL;
+  buf[1].cbBuffer = 0;
+				/* decrypt and copy to output buffer */
+  if ((major_status = DecryptMessage (context_handle,&bufs,0,qop_state)) ==
+      SEC_E_OK)
+   memcpy (output_message_buffer->value = fs_get (buf[1].cbBuffer),
+	   buf[1].pvBuffer,output_message_buffer->length = buf[1].cbBuffer);
+  return major_status;		/* return status */
+}
+
+/* From here on are server-only functions, currently unused */
+
+
+/* GSSAPI acquire credentials
+ * Accepts: pointer to return minor status
+ *	    desired principal
+ *	    desired lifetime
+ *	    desired mechanisms
+ *	    credentials usage
+ *	    pointer to return credentials handle
+ *	    pointer to return mechanisms
+ *	    pointer to return lifetime
+ * Returns: GSS_S_FAILURE, always
+ */
+
+OM_uint32 gss_acquire_cred (OM_uint32 *minor_status,gss_name_t desired_name,
+			    OM_uint32 time_req,gss_OID_set desired_mechs,
+			    gss_cred_usage_t cred_usage,
+			    gss_cred_id_t *output_cred_handle,
+			    gss_OID_set *actual_mechs,OM_uint32 *time_rec)
+{
+  *minor_status = 0;		/* never any minor status */
+  return GSS_S_FAILURE;		/* server only */
+}
+
+
+/* GSSAPI release credentials
+ * Accepts: pointer to return minor status
+ *	    credentials handle to free
+ * Returns: GSS_S_COMPLETE, always
+ */
+
+OM_uint32 gss_release_cred (OM_uint32 *minor_status,gss_cred_id_t *cred_handle)
+{
+  *minor_status = 0;		/* never any minor status */
+  return GSS_S_FAILURE;		/* server only */
+}
+
+/* GSSAPI Accept security context
+ * Accepts: pointer to return minor status
+ *	    context
+ *	    acceptor credentials
+ *	    input token buffer
+ *	    input channel bindings
+ *	    pointer to return source name
+ *	    pointer to return mechanism type
+ *	    buffer to return output token
+ *	    pointer to return flags
+ *	    pointer to return context lifetime
+ *	    pointer to return delegated credentials
+ * Returns: GSS_S_FAILURE, always
+ */
+
+OM_uint32 gss_accept_sec_context (OM_uint32 *minor_status,
+				  gss_ctx_id_t *context_handle,
+				  gss_cred_id_t acceptor_cred_handle,
+				  gss_buffer_t input_token_buffer,
+				  gss_channel_bindings_t input_chan_bindings,
+				  gss_name_t *src_name,gss_OID *mech_type,
+				  gss_buffer_t output_token,
+				  OM_uint32 *ret_flags,OM_uint32 *time_rec,
+				  gss_cred_id_t *delegated_cred_handle)
+{
+  *minor_status = 0;		/* never any minor status */
+  return GSS_S_FAILURE;		/* server only */
+}
+
+
+/* GSSAPI return printable name
+ * Accepts: pointer to return minor status
+ *	    internal name
+ *	    buffer to return output name
+ *	    output name type
+ * Returns: GSS_S_FAILURE, always
+ */
+
+OM_uint32 gss_display_name (OM_uint32 *minor_status,gss_name_t input_name,
+			    gss_buffer_t output_name_buffer,
+			    gss_OID *output_name_type)
+{
+  *minor_status = 0;		/* never any minor status */
+  return GSS_S_FAILURE;		/* server only */
+}
+
+/* Kerberos server valid check
+ * Returns: T if have keytab, NIL otherwise
+ */
+
+long kerberos_server_valid ()
+{
+  return NIL;
+}
+
+
+/* Kerberos check for missing or expired credentials
+ * Returns: T if should suggest running kinit, NIL otherwise
+ */
+
+long kerberos_try_kinit (OM_uint32 error)
+{
+  return NIL;
+}
+
+/* Kerberos server log in
+ * Accepts: authorization ID as user name
+ *	    authentication ID as Kerberos principal
+ *	    argument count
+ *	    argument vector
+ * Returns: logged in user name if logged in, NIL otherwise
+ */
+
+char *kerberos_login (char *user,char *authuser,int argc,char *argv[])
+{
+  return NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/mailfile.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,29 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Mail Spool file name
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	8 February 1996
+ * Last Edited:	30 August 2006
+ */
+
+#define MAILFILE "C:\\WINSMTP\\%s.MBX"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/makefile.nt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,118 @@
+# ========================================================================
+# Copyright 1988-2007 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+# Program:	Portable C client makefile -- NT version
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		11 May 1989
+# Last Edited:	23 May 2007
+
+
+EXTRAAUTHENTICATORS =
+EXTRADRIVERS = 
+EXTRACFLAGS =
+AUTHENTICATORS = ext md5 pla log
+DRIVERS = imap nntp pop3 mbx mtx tenex unix
+CREATEDRIVER = mbx
+APPENDDRIVER = unix
+OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
+VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
+CFLAGS = /MT /W3 /Ox /DCHUNKSIZE=65536 $(OSCOMPAT) $(VSCOMPAT) -nologo /I.. $(EXTRACFLAGS)
+CC = cl
+CCLIENTLIB = cclient.lib
+
+all:	$(CCLIENTLIB)
+
+.c.obj:
+	$(CC) -c $(CFLAGS) $*.c
+
+osdep.h: os_nt.h
+	copy os_nt.h osdep.h
+	drivers $(EXTRADRIVERS) $(DRIVERS) dummy
+	setproto $(CREATEDRIVER) $(APPENDDRIVER)
+	echo ssl_onceonlyinit (); >> linkage.c
+	mkauths $(EXTRAAUTHENTICATORS) $(AUTHENTICATORS)
+	echo mail_versioncheck (CCLIENTVERSION); >> linkage.c
+
+ip_nt.c: ip4_nt.c
+	copy ip4_nt.c ip_nt.c
+
+mail.obj: mail.h misc.h osdep.h mail.c
+
+misc.obj: mail.h misc.h misc.c
+
+fdstring.obj: mail.h misc.h osdep.h fdstring.h fdstring.c
+
+flstring.obj: mail.h misc.h osdep.h flstring.h flstring.c
+
+netmsg.obj: mail.h misc.h netmsg.h osdep.h netmsg.c
+
+newsrc.obj: mail.h misc.h newsrc.h osdep.h newsrc.c
+
+rfc822.obj: mail.h rfc822.h misc.h rfc822.c
+
+smanager.obj: mail.h misc.h smanager.c
+
+utf8.obj: mail.h misc.h osdep.h utf8.h
+
+utf8aux.obj: mail.h misc.h osdep.h utf8.h
+
+imap4r1.obj: mail.h imap4r1.h misc.h osdep.h imap4r1.c
+
+nntp.obj: mail.h nntp.h smtp.h rfc822.h misc.h osdep.h nntp.c
+
+pop3.obj: mail.h rfc822.h misc.h osdep.h pop3.c
+
+smtp.obj: mail.h smtp.h rfc822.h misc.h osdep.h smtp.c
+
+os_nt.obj: mail.h osdep.h env_nt.h fs.h ftl.h nl.h tcp.h tcp_nt.h yunchan.h \
+	os_nt.c fs_nt.c ftl_nt.c nl_nt.c env_nt.c ssl_nt.c ssl_none.c \
+	ip_nt.c tcp_nt.c yunchan.c pmatch.c write.c \
+	mailfile.h auth_md5.c auth_pla.c auth_log.c
+
+mbxnt.obj: mail.h misc.h osdep.h mbxnt.c
+
+mtxnt.obj: mail.h misc.h osdep.h mtxnt.c
+
+tenexnt.obj: mail.h misc.h osdep.h tenexnt.c
+
+unixnt.obj: mail.h unixnt.h pseudo.h misc.h osdep.h unixnt.c
+
+dummynt.obj: mail.h dummy.h misc.h osdep.h dummynt.c
+
+pseudo.obj: pseudo.h
+
+$(CCLIENTLIB): mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \
+	newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
+	imap4r1.obj nntp.obj pop3.obj smtp.obj os_nt.obj \
+	mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj
+	if exist $(CCLIENTLIB) del $(CCLIENTLIB)
+	LIB /NOLOGO /OUT:cclient.lib \
+	mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \
+	newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
+	imap4r1.obj nntp.obj pop3.obj smtp.obj os_nt.obj \
+	mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj
+
+clean:
+	del *.lib *.obj linkage.* osdep.* ip_nt.c auths.c *.exe *.exp || rem
+
+# A monument to a hack of long ago and far away...
+
+love:
+	@echo not war?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/makefile.ntk	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,118 @@
+# ========================================================================
+# Copyright 1988-2007 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+# Program:	Portable C client makefile -- NT version + Kerberos
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		11 May 1989
+# Last Edited:	23 May 2007
+
+
+EXTRAAUTHENTICATORS =
+EXTRADRIVERS = 
+EXTRACFLAGS =
+AUTHENTICATORS = ext gss md5 pla log
+DRIVERS = imap nntp pop3 mbx mtx tenex unix
+CREATEDRIVER = mbx
+APPENDDRIVER = unix
+OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400 /I\k5\include
+VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
+CFLAGS = /MT /W3 /Ox /DCHUNKSIZE=65536 $(OSCOMPAT) $(VSCOMPAT) -nologo /I.. $(EXTRACFLAGS)
+CC = cl
+CCLIENTLIB = cclient.lib
+
+all:	$(CCLIENTLIB)
+
+.c.obj:
+	$(CC) -c $(CFLAGS) $*.c
+
+osdep.h: os_nt.h
+	copy os_nt.h osdep.h
+	drivers $(EXTRADRIVERS) $(DRIVERS) dummy
+	setproto $(CREATEDRIVER) $(APPENDDRIVER)
+	echo ssl_onceonlyinit (); >> linkage.c
+	mkauths $(EXTRAAUTHENTICATORS) $(AUTHENTICATORS)
+	echo mail_versioncheck (CCLIENTVERSION); >> linkage.c
+
+ip_nt.c: ip4_nt.c
+	copy ip4_nt.c ip_nt.c
+
+mail.obj: mail.h misc.h osdep.h mail.c
+
+misc.obj: mail.h misc.h misc.c
+
+fdstring.obj: mail.h misc.h osdep.h fdstring.h fdstring.c
+
+flstring.obj: mail.h misc.h osdep.h flstring.h flstring.c
+
+netmsg.obj: mail.h misc.h netmsg.h osdep.h netmsg.c
+
+newsrc.obj: mail.h misc.h newsrc.h osdep.h newsrc.c
+
+rfc822.obj: mail.h rfc822.h misc.h rfc822.c
+
+smanager.obj: mail.h misc.h smanager.c
+
+utf8.obj: mail.h misc.h osdep.h utf8.h
+
+utf8aux.obj: mail.h misc.h osdep.h utf8.h
+
+imap4r1.obj: mail.h imap4r1.h misc.h osdep.h imap4r1.c
+
+nntp.obj: mail.h nntp.h smtp.h rfc822.h misc.h osdep.h nntp.c
+
+pop3.obj: mail.h rfc822.h misc.h osdep.h pop3.c
+
+smtp.obj: mail.h smtp.h rfc822.h misc.h osdep.h smtp.c
+
+os_ntk.obj: mail.h osdep.h env_nt.h fs.h ftl.h nl.h tcp.h tcp_nt.h yunchan.h \
+	os_ntk.c fs_nt.c ftl_nt.c nl_nt.c env_nt.c ssl_nt.c ssl_none.c \
+	ip_nt.c tcp_nt.c yunchan.c pmatch.c write.c \
+	mailfile.h auth_gss.c auth_md5.c auth_pla.c auth_log.c kerb_mit.c
+
+mbxnt.obj: mail.h misc.h osdep.h mbxnt.c
+
+mtxnt.obj: mail.h misc.h osdep.h mtxnt.c
+
+tenexnt.obj: mail.h misc.h osdep.h tenexnt.c
+
+unixnt.obj: mail.h unixnt.h pseudo.h misc.h osdep.h unixnt.c
+
+dummynt.obj: mail.h dummy.h misc.h osdep.h dummynt.c
+
+pseudo.obj: pseudo.h
+
+$(CCLIENTLIB): mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \
+	newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
+	imap4r1.obj nntp.obj pop3.obj smtp.obj os_ntk.obj \
+	mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj
+	if exist $(CCLIENTLIB) del $(CCLIENTLIB)
+	LIB /NOLOGO /OUT:cclient.lib \
+	mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \
+	newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
+	imap4r1.obj nntp.obj pop3.obj smtp.obj os_ntk.obj \
+	mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj
+
+clean:
+	del *.lib *.obj linkage.* osdep.* ip_nt.c auths.c *.exe *.exp || rem
+
+# A monument to a hack of long ago and far away...
+
+love:
+	@echo not war?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/makefile.old	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,118 @@
+# ========================================================================
+# Copyright 1988-2007 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+# Program:	Portable C client makefile -- old NT version
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		11 May 1989
+# Last Edited:	23 May 2007
+
+
+EXTRAAUTHENTICATORS =
+EXTRADRIVERS = 
+EXTRACFLAGS =
+AUTHENTICATORS = ext md5 pla log
+DRIVERS = imap nntp pop3 mbx mtx tenex unix
+CREATEDRIVER = mbx
+APPENDDRIVER = unix
+OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
+VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
+CFLAGS = /MT /W3 /Ox /DCHUNKSIZE=65536 $(OSCOMPAT) $(VSCOMPAT) -nologo /I.. $(EXTRACFLAGS)
+CC = cl
+CCLIENTLIB = cclient.lib
+
+all:	$(CCLIENTLIB)
+
+.c.obj:
+	$(CC) -c $(CFLAGS) $*.c
+
+osdep.h: os_nt.h
+	copy os_nt.h osdep.h
+	drivers $(EXTRADRIVERS) $(DRIVERS) dummy
+	setproto $(CREATEDRIVER) $(APPENDDRIVER)
+	echo ssl_onceonlyinit (); >> linkage.c
+	mkauths $(EXTRAAUTHENTICATORS) $(AUTHENTICATORS)
+	echo mail_versioncheck (CCLIENTVERSION); >> linkage.c
+
+ip_nt.c: ip4_nt.c
+	copy ip4_nt.c ip_nt.c
+
+mail.obj: mail.h misc.h osdep.h mail.c
+
+misc.obj: mail.h misc.h misc.c
+
+fdstring.obj: mail.h misc.h osdep.h fdstring.h fdstring.c
+
+flstring.obj: mail.h misc.h osdep.h flstring.h flstring.c
+
+netmsg.obj: mail.h misc.h netmsg.h osdep.h netmsg.c
+
+newsrc.obj: mail.h misc.h newsrc.h osdep.h newsrc.c
+
+rfc822.obj: mail.h rfc822.h misc.h rfc822.c
+
+smanager.obj: mail.h misc.h smanager.c
+
+utf8.obj: mail.h misc.h osdep.h utf8.h
+
+utf8aux.obj: mail.h misc.h osdep.h utf8.h
+
+imap4r1.obj: mail.h imap4r1.h misc.h osdep.h imap4r1.c
+
+nntp.obj: mail.h nntp.h smtp.h rfc822.h misc.h osdep.h nntp.c
+
+pop3.obj: mail.h rfc822.h misc.h osdep.h pop3.c
+
+smtp.obj: mail.h smtp.h rfc822.h misc.h osdep.h smtp.c
+
+os_old.obj: mail.h osdep.h env_nt.h fs.h ftl.h nl.h tcp.h tcp_nt.h yunchan.h \
+	os_old.c fs_nt.c ftl_nt.c nl_nt.c env_nt.c ssl_nt.c ssl_none.c \
+	ip_nt.c tcp_nt.c yunchan.c pmatch.c write.c \
+	mailfile.h auth_md5.c auth_pla.c auth_log.c
+
+mbxnt.obj: mail.h misc.h osdep.h mbxnt.c
+
+mtxnt.obj: mail.h misc.h osdep.h mtxnt.c
+
+tenexnt.obj: mail.h misc.h osdep.h tenexnt.c
+
+unixnt.obj: mail.h unixnt.h pseudo.h misc.h osdep.h unixnt.c
+
+dummynt.obj: mail.h dummy.h misc.h osdep.h dummynt.c
+
+pseudo.obj: pseudo.h
+
+$(CCLIENTLIB): mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \
+	newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
+	imap4r1.obj nntp.obj pop3.obj smtp.obj os_old.obj \
+	mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj
+	if exist $(CCLIENTLIB) del $(CCLIENTLIB)
+	LIB /NOLOGO /OUT:cclient.lib \
+	mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \
+	newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
+	imap4r1.obj nntp.obj pop3.obj smtp.obj os_old.obj \
+	mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj
+
+clean:
+	del *.lib *.obj linkage.* osdep.* ip_nt.c auths.c *.exe *.exp || rem
+
+# A monument to a hack of long ago and far away...
+
+love:
+	@echo not war?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/makefile.w2k	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,119 @@
+# ========================================================================
+# Copyright 1988-2007 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+# Program:	Portable C client makefile -- Windows 2000/XP version
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		11 May 1989
+# Last Edited:	23 May 2007
+
+
+IP=6
+EXTRAAUTHENTICATORS =
+EXTRADRIVERS = 
+EXTRACFLAGS =
+AUTHENTICATORS = ext gss md5 pla log
+DRIVERS = imap nntp pop3 mbx mtx tenex unix
+CREATEDRIVER = mbx
+APPENDDRIVER = unix
+OSCOMPAT = /DWIN32
+VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
+CFLAGS = /MT /W3 /Ox /DCHUNKSIZE=65536 $(OSCOMPAT) $(VSCOMPAT) -nologo /I.. $(EXTRACFLAGS)
+CC = cl
+CCLIENTLIB = cclient.lib
+
+all:	$(CCLIENTLIB)
+
+.c.obj:
+	$(CC) -c $(CFLAGS) $*.c
+
+osdep.h: os_nt.h
+	copy os_nt.h osdep.h
+	drivers $(EXTRADRIVERS) $(DRIVERS) dummy
+	setproto $(CREATEDRIVER) $(APPENDDRIVER)
+	echo ssl_onceonlyinit (); >> linkage.c
+	mkauths $(EXTRAAUTHENTICATORS) $(AUTHENTICATORS)
+	echo mail_versioncheck (CCLIENTVERSION); >> linkage.c
+
+ip_nt.c: ip$(IP)_nt.c
+	copy ip$(IP)_nt.c ip_nt.c
+
+mail.obj: mail.h misc.h osdep.h mail.c
+
+misc.obj: mail.h misc.h misc.c
+
+fdstring.obj: mail.h misc.h osdep.h fdstring.h fdstring.c
+
+flstring.obj: mail.h misc.h osdep.h flstring.h flstring.c
+
+netmsg.obj: mail.h misc.h netmsg.h osdep.h netmsg.c
+
+newsrc.obj: mail.h misc.h newsrc.h osdep.h newsrc.c
+
+rfc822.obj: mail.h rfc822.h misc.h rfc822.c
+
+smanager.obj: mail.h misc.h smanager.c
+
+utf8.obj: mail.h misc.h osdep.h utf8.h
+
+utf8aux.obj: mail.h misc.h osdep.h utf8.h
+
+imap4r1.obj: mail.h imap4r1.h misc.h osdep.h imap4r1.c
+
+nntp.obj: mail.h nntp.h smtp.h rfc822.h misc.h osdep.h nntp.c
+
+pop3.obj: mail.h rfc822.h misc.h osdep.h pop3.c
+
+smtp.obj: mail.h smtp.h rfc822.h misc.h osdep.h smtp.c
+
+os_w2k.obj: mail.h osdep.h env_nt.h fs.h ftl.h nl.h tcp.h tcp_nt.h yunchan.h \
+	os_w2k.c fs_nt.c ftl_nt.c nl_nt.c env_nt.c ssl_w2k.c ssl_none.c \
+	ip_nt.c tcp_nt.c yunchan.c pmatch.c write.c \
+	mailfile.h auth_gss.c auth_md5.c auth_pla.c auth_log.c kerb_w2k.c
+
+mbxnt.obj: mail.h misc.h osdep.h mbxnt.c
+
+mtxnt.obj: mail.h misc.h osdep.h mtxnt.c
+
+tenexnt.obj: mail.h misc.h osdep.h tenexnt.c
+
+unixnt.obj: mail.h unixnt.h pseudo.h misc.h osdep.h unixnt.c
+
+dummynt.obj: mail.h dummy.h misc.h osdep.h dummynt.c
+
+pseudo.obj: pseudo.h
+
+$(CCLIENTLIB): mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \
+	newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
+	imap4r1.obj nntp.obj pop3.obj smtp.obj os_w2k.obj \
+	mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj
+	if exist $(CCLIENTLIB) del $(CCLIENTLIB)
+	LIB /NOLOGO /OUT:cclient.lib \
+	mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \
+	newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
+	imap4r1.obj nntp.obj pop3.obj smtp.obj os_w2k.obj \
+	mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj
+
+clean:
+	del *.lib *.obj linkage.* osdep.* ip_nt.c auths.c *.exe *.exp || rem
+
+# A monument to a hack of long ago and far away...
+
+love:
+	@echo not war?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/mbxnt.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1694 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	MBX mail routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	3 October 1995
+ * Last Edited:	28 September 2007
+ */
+
+
+/*				FILE TIME SEMANTICS
+ *
+ * The atime is the last read time of the file.
+ * The mtime is the last flags update time of the file.
+ * The ctime is the last write time of the file.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "mail.h"
+#include "osdep.h"
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/utime.h>
+#include "misc.h"
+#include "dummy.h"
+#include "fdstring.h"
+
+
+/* Build parameters */
+
+#define HDRSIZE 2048
+
+/* MBX I/O stream local data */
+	
+typedef struct mbx_local {
+  unsigned int flagcheck: 1;	/* if ping should sweep for flags */
+  unsigned int expok: 1;	/* if expunging OK in ping */
+  unsigned int expunged : 1;	/* if one or more expunged messages */
+  int fd;			/* file descriptor for I/O */
+  int ld;			/* lock file descriptor */
+  int ffuserflag;		/* first free user flag */
+  off_t filesize;		/* file size parsed */
+  time_t filetime;		/* last file time */
+  time_t lastsnarf;		/* last snarf time */
+  unsigned char *buf;		/* temporary buffer */
+  unsigned long buflen;		/* current size of temporary buffer */
+  char lock[MAILTMPLEN];	/* buffer to write lock name */
+} MBXLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((MBXLOCAL *) stream->local)
+
+/* Function prototypes */
+
+DRIVER *mbx_valid (char *name);
+int mbx_isvalid (MAILSTREAM **stream,char *name,char *file,int *ld,char *lock,
+		 long flags);
+void *mbx_parameters (long function,void *value);
+void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void mbx_list (MAILSTREAM *stream,char *ref,char *pat);
+void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long mbx_create (MAILSTREAM *stream,char *mailbox);
+long mbx_delete (MAILSTREAM *stream,char *mailbox);
+long mbx_rename (MAILSTREAM *stream,char *old,char *newname);
+long mbx_status (MAILSTREAM *stream,char *mbx,long flags);
+MAILSTREAM *mbx_open (MAILSTREAM *stream);
+void mbx_close (MAILSTREAM *stream,long options);
+void mbx_abort (MAILSTREAM *stream);
+void mbx_flags (MAILSTREAM *stream,char *sequence,long flags);
+char *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
+		  long flags);
+long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
+void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
+long mbx_ping (MAILSTREAM *stream);
+void mbx_check (MAILSTREAM *stream);
+long mbx_expunge (MAILSTREAM *stream,char *sequence,long options);
+void mbx_snarf (MAILSTREAM *stream);
+long mbx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long mbx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+long mbx_parse (MAILSTREAM *stream);
+MESSAGECACHE *mbx_elt (MAILSTREAM *stream,unsigned long msgno,long expok);
+unsigned long mbx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt);
+void mbx_update_header (MAILSTREAM *stream);
+void mbx_update_status (MAILSTREAM *stream,unsigned long msgno,long flags);
+unsigned long mbx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			  unsigned long *size,char **hdr);
+unsigned long mbx_rewrite (MAILSTREAM *stream,unsigned long *reclaimed,
+			   long flags);
+long mbx_flaglock (MAILSTREAM *stream);
+
+/* MBX mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER mbxdriver = {
+  "mbx",			/* driver name */
+  DR_LOCAL|DR_MAIL|DR_CRLF|DR_LOCKING,
+				/* driver flags */
+  (DRIVER *) NIL,		/* next driver */
+  mbx_valid,			/* mailbox is valid for us */
+  mbx_parameters,		/* manipulate parameters */
+  mbx_scan,			/* scan mailboxes */
+  mbx_list,			/* list mailboxes */
+  mbx_lsub,			/* list subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  mbx_create,			/* create mailbox */
+  mbx_delete,			/* delete mailbox */
+  mbx_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  mbx_open,			/* open mailbox */
+  mbx_close,			/* close mailbox */
+  mbx_flags,			/* fetch message "fast" attributes */
+  mbx_flags,			/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  mbx_header,			/* fetch message header */
+  mbx_text,			/* fetch message body */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  mbx_flag,			/* modify flags */
+  mbx_flagmsg,			/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  mbx_ping,			/* ping mailbox to see if still alive */
+  mbx_check,			/* check for new messages */
+  mbx_expunge,			/* expunge deleted messages */
+  mbx_copy,			/* copy messages to another mailbox */
+  mbx_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM mbxproto = {&mbxdriver};
+
+/* MBX mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *mbx_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+  int fd = mbx_isvalid (NIL,name,tmp,NIL,NIL,NIL);
+  if (fd < 0) return NIL;
+  close (fd);			/* don't need the fd now */
+  return &mbxdriver;
+}
+
+
+/* MBX mail test for valid mailbox
+ * Accepts: returned stream with valid mailbox keywords
+ *	    mailbox name
+ *	    buffer to write file name
+ *	    returned lock fd
+ *	    returned lock name
+ *	    RW flags or NIL for readonly
+ * Returns: file descriptor if valid, NIL otherwise
+ */
+
+#define MBXISVALIDNOUID 0x1	/* RW, don't do UID action */
+#define MBXISVALIDUID 0x2	/* RW, do UID action */
+
+int mbx_isvalid (MAILSTREAM **stream,char *name,char *file,int *ld,char *lock,
+		 long flags)
+{
+  int fd,upd;
+  int ret = -1;
+  unsigned long i;
+  long j,k;
+  off_t pos;
+  char c,*s,*t,hdr[HDRSIZE];
+  struct stat sbuf;
+  struct utimbuf times;
+  int error = EINVAL;		/* assume invalid argument */
+  if (ld) *ld = -1;		/* initially no lock */
+				/* if file, get its status */
+  if ((s = dummy_file (file,name)) && !stat (s,&sbuf) &&
+      ((sbuf.st_mode & S_IFMT) == S_IFREG) &&
+      ((fd = open (file,(flags ? O_RDWR : O_RDONLY)|O_BINARY,NIL)) >= 0)) {
+    error = -1;			/* assume bogus format */
+    if (((((j = read (fd,hdr,HDRSIZE)) == HDRSIZE) && (hdr[0] == '*')) ||
+				/* locked, set byte 0 to "*", read rest */
+	 ((j < 0) && (lseek (fd,1,L_SET) == 1) &&
+	  (read (fd,hdr+1,HDRSIZE-1) == (HDRSIZE-1)) && (hdr[0] = '*'))) &&
+	(hdr[1] == 'm') && (hdr[2] == 'b') && (hdr[3] == 'x') &&
+	(hdr[4] == '*') && (hdr[5] == '\015') && (hdr[6] == '\012') &&
+	isxdigit (hdr[7]) && isxdigit (hdr[8]) && isxdigit (hdr[9]) &&
+	isxdigit (hdr[10]) && isxdigit (hdr[11]) && isxdigit (hdr[12]) &&
+	isxdigit (hdr[13]) && isxdigit (hdr[14]) && isxdigit (c = hdr[15]) &&
+	isxdigit (hdr[16]) && isxdigit (hdr[17]) && isxdigit (hdr[18]) &&
+	isxdigit (hdr[19]) && isxdigit (hdr[20]) && isxdigit (hdr[21]) &&
+	isxdigit (hdr[22]) && (hdr[23] == '\015') && (hdr[24] == '\012')) {
+      ret = fd;			/* mbx format */
+
+      if (stream) {		/* lock if making a mini-stream */
+	if (flock (fd,LOCK_SH) ||
+	    (flags && ((*ld = lockname (lock,file,LOCK_EX)) < 0))) ret = -1;
+				/* reread data now that locked */
+	else if (lseek (fd,0,L_SET) ||
+		 (read (fd,hdr+1,HDRSIZE-1) != (HDRSIZE-1))) ret = -1;
+	else {
+	  *stream = (MAILSTREAM *) memset (fs_get (sizeof (MAILSTREAM)),0,
+					   sizeof (MAILSTREAM));
+	  hdr[15] = '\0';	/* tie off UIDVALIDITY */
+	  (*stream)->uid_validity = strtoul (hdr+7,NIL,16);
+	  hdr[15] = c;		/* now get UIDLAST */
+	  (*stream)->uid_last = strtoul (hdr+15,NIL,16);
+				/* parse user flags */
+	  for (i = 0, s = hdr + 25;
+	       (i < NUSERFLAGS) && (t = strchr (s,'\015')) && (t - s);
+	       i++, s = t + 2) {
+	    *t = '\0';		/* tie off flag */
+	    if (strlen (s) <= MAXUSERFLAG)
+	      (*stream)->user_flags[i] = cpystr (s);
+	  }
+				/* make sure have true UIDLAST */
+	  if (flags & MBXISVALIDUID) {
+	    for (upd = NIL,pos = 2048, k = 0; pos < sbuf.st_size;
+		 pos += (j + k)) {
+				/* read header for this message */
+	      lseek (fd,pos,L_SET);
+	      if ((j = read (fd,hdr,64)) >= 0) {
+		hdr[j] = '\0';
+		if ((s = strchr (hdr,'\015')) && (s[1] == '\012')) {
+		  *s = '\0';
+		  k = s + 2 - hdr;
+		  if ((s = strchr (hdr,',')) && (j = strtol (s+1,&s,10)) &&
+		      (*s == ';') && (s = strchr (s+1,'-'))) {
+				/* get UID if there is any */
+		    i = strtoul (++s,&t,16);
+		    if (!*t && (t == (s + 8)) && (i <= (*stream)->uid_last)) {
+		      if (!i) {
+			lseek (fd,pos + s - hdr,L_SET);
+			sprintf (hdr,"%08lx",++(*stream)->uid_last);
+			write (fd,hdr,8);
+			upd = T;
+		      }
+		      continue;
+		    }
+		  }
+		}
+		ret = -1;	/* error, give up */
+		*stream = mail_close (*stream);
+		pos = sbuf.st_size + 1;
+		j = k = 0;
+	      }
+	    }
+
+	    if (upd) {	    /* need to update hdr with new UIDLAST? */
+	      lseek (fd,15,L_SET);
+	      sprintf (hdr,"%08lx",(*stream)->uid_last);
+	      write (fd,hdr,8);
+	    }
+	  }
+	}
+      }
+    }
+    if (ret != fd) close (fd);	/* close the file */
+    else lseek (fd,0,L_SET);	/* else rewind to start */
+				/* \Marked status? */
+    if (sbuf.st_ctime > sbuf.st_atime) {
+				/* preserve atime and mtime */
+      times.actime = sbuf.st_atime;
+      times.modtime = sbuf.st_mtime;
+      utime (file,&times);	/* set the times */
+    }
+  }
+				/* in case INBOX but not mbx format */
+  else if (((error = errno) == ENOENT) && !compare_cstring (name,"INBOX"))
+    error = -1;
+  if ((ret < 0) && ld && (*ld >= 0)) {
+    unlockfd (*ld,lock);
+    *ld = -1;
+  }
+  errno = error;		/* return as last error */
+  return ret;			/* return what we should */
+}
+
+/* MBX manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *mbx_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case SET_ONETIMEEXPUNGEATPING:
+    if (value) ((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expok = T;
+  case GET_ONETIMEEXPUNGEATPING:
+    if (value) ret = (void *)
+      (((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expok ? VOIDT : NIL);
+    break;
+  }
+  return ret;
+}
+
+
+/* MBX mail scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* MBX mail list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mbx_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_list (NIL,ref,pat);
+}
+
+
+/* MBX mail list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_lsub (NIL,ref,pat);
+}
+
+/* MBX mail create mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long mbx_create (MAILSTREAM *stream,char *mailbox)
+{
+  char *s,mbx[MAILTMPLEN],tmp[HDRSIZE];
+  long ret = NIL;
+  int i,fd;
+  if (!(s = dummy_file (mbx,mailbox))) {
+    sprintf (mbx,"Can't create %.80s: invalid name",mailbox);
+    mm_log (mbx,ERROR);
+  }
+				/* create underlying file */
+  else if (dummy_create (stream,s)) {
+				/* done if made directory */
+    if ((s = strrchr (s,'\\')) && !s[1]) return T;
+    if ((fd = open (mbx,O_WRONLY|O_BINARY,NIL)) < 0) {
+      sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno));
+      mm_log (tmp,ERROR);
+      unlink (mbx);		/* delete the file */
+    }
+    else {
+      memset (tmp,'\0',HDRSIZE);/* initialize header */
+      sprintf (s = tmp,"*mbx*\015\012%08lx00000000\015\012",
+	       (unsigned long) time (0));
+      for (i = 0; i < NUSERFLAGS; ++i)
+	sprintf (s += strlen (s),"%s\015\012",
+		 (stream && stream->user_flags[i]) ? stream->user_flags[i] :
+		 "");
+      if (write (fd,tmp,HDRSIZE) != HDRSIZE) {
+	sprintf (tmp,"Can't initialize mailbox node %.80s: %s",
+		 mbx,strerror (errno));
+	mm_log (tmp,ERROR);
+	unlink (mbx);		/* delete the file */
+      }
+      else ret = T;		/* success */
+      close (fd);		/* close file */
+    }
+  }
+  return ret;
+}
+
+
+/* MBX mail delete mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long mbx_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return mbx_rename (stream,mailbox,NIL);
+}
+
+/* MBX mail rename mailbox
+ * Accepts: MAIL stream
+ *	    old mailbox name
+ *	    new mailbox name (or NIL for delete)
+ * Returns: T on success, NIL on failure
+ */
+
+long mbx_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  long ret = LONGT;
+  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  int fd,ld;
+  struct stat sbuf;
+  if (!dummy_file (file,old) ||
+      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
+		   ((s = strrchr (tmp,'\\')) && !s[1])))) {
+    sprintf (tmp,newname ?
+	     "Can't rename mailbox %.80s to %.80s: invalid name" :
+	     "Can't delete mailbox %.80s: invalid name",
+	     old,newname);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+  else if ((fd = open (file,O_RDWR|O_BINARY,NIL)) < 0) {
+    sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* get parse/append permission */
+  if ((ld = lockname (lock,file,LOCK_EX)) < 0) {
+    mm_log ("Unable to lock rename mailbox",ERROR);
+    return NIL;
+  }
+				/* lock out other users */
+  if (flock (fd,LOCK_EX|LOCK_NB)) {
+    close (fd);			/* couldn't lock, give up on it then */
+    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
+    mm_log (tmp,ERROR);
+    unlockfd (ld,lock);		/* release exclusive parse/append permission */
+    return NIL;
+  }
+
+  if (newname) {		/* want rename? */
+				/* found superior to destination name? */
+    if ((s = strrchr (tmp,'\\')) && (s != tmp) &&
+	((tmp[1] != ':') || (s != tmp + 2))) {
+      c = s[1];			/* remember character after delimiter */
+      *s = s[1] = '\0';		/* tie off name at delimiter */
+				/* name doesn't exist, create it */
+      if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) {
+	*s = '\\';		/* restore delimiter */
+	if (!dummy_create (stream,tmp)) ret = NIL;
+      }
+      else *s = '\\';		/* restore delimiter */
+      s[1] = c;			/* restore character after delimiter */
+    }
+    flock (fd,LOCK_UN);		/* release lock on the file */
+    close (fd);			/* pacify NTFS */
+				/* rename the file */
+    if (ret && rename (file,tmp)) {
+      sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
+	       strerror (errno));
+      mm_log (tmp,ERROR);
+      ret = NIL;		/* set failure */
+    }
+  }
+  else {
+    flock (fd,LOCK_UN);		/* release lock on the file */
+    close (fd);			/* pacify NTFS */
+    if (unlink (file)) {
+      sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
+      mm_log (tmp,ERROR);
+      ret = NIL;		/* set failure */
+    }
+  }
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+				/* recreate file if renamed INBOX */
+  if (ret && !compare_cstring (old,"INBOX")) mbx_create (NIL,"INBOX");
+  return ret;			/* return success */
+}
+
+/* MBX mail open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *mbx_open (MAILSTREAM *stream)
+{
+  int fd,ld;
+  short silent;
+  char tmp[MAILTMPLEN];
+  if (!stream) return &mbxproto;/* return prototype for OP_PROTOTYPE call */
+  if (stream->local) fatal ("mbx recycle stream");
+				/* canonicalize the mailbox name */
+  if (!dummy_file (tmp,stream->mailbox)) {
+    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
+    mm_log (tmp,ERROR);
+  }
+  if (stream->rdonly ||
+      (fd = open (tmp,O_RDWR|O_BINARY,NIL)) < 0) {
+    if ((fd = open (tmp,O_RDONLY|O_BINARY,NIL)) < 0) {
+      sprintf (tmp,"Can't open mailbox: %s",strerror (errno));
+      mm_log (tmp,ERROR);
+      return NIL;
+    }
+    else if (!stream->rdonly) {	/* got it, but readonly */
+      mm_log ("Can't get write access to mailbox, access is readonly",WARN);
+      stream->rdonly = T;
+    }
+  }
+
+  stream->local = memset (fs_get (sizeof (MBXLOCAL)),NIL,sizeof (MBXLOCAL));
+  LOCAL->fd = fd;		/* bind the file */
+  LOCAL->ld = -1;		/* no flaglock */
+  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
+  LOCAL->buflen = CHUNKSIZE - 1;
+				/* note if an INBOX or not */
+  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
+  fs_give ((void **) &stream->mailbox);
+  stream->mailbox = cpystr (tmp);
+				/* get parse/append permission */
+  if ((ld = lockname (tmp,stream->mailbox,LOCK_EX)) < 0) {
+    mm_log ("Unable to lock open mailbox",ERROR);
+    return NIL;
+  }
+  flock (LOCAL->fd,LOCK_SH);	/* lock the file */
+  unlockfd (ld,tmp);		/* release shared parse permission */
+  LOCAL->filesize = HDRSIZE;	/* initialize parsed file size */
+  LOCAL->filetime = 0;		/* time not set up yet */
+  LOCAL->expok = LOCAL->flagcheck = NIL;
+  stream->sequence++;		/* bump sequence number */
+				/* parse mailbox */
+  stream->nmsgs = stream->recent = 0;
+  silent = stream->silent;	/* defer events */
+  stream->silent = T;
+  if (mbx_ping (stream) && !stream->nmsgs)
+    mm_log ("Mailbox is empty",(long) NIL);
+  stream->silent = silent;	/* now notify upper level */
+  mail_exists (stream,stream->nmsgs);
+  mail_recent (stream,stream->recent);
+  if (!LOCAL) return NIL;	/* failure if stream died */
+  stream->perm_seen = stream->perm_deleted = stream->perm_flagged =
+    stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T;
+  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
+  stream->kwd_create = (stream->user_flags[NUSERFLAGS-1] || stream->rdonly) ?
+    NIL : T;			/* can we create new user flags? */
+  return stream;		/* return stream to caller */
+}
+
+/* MBX mail close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void mbx_close (MAILSTREAM *stream,long options)
+{
+  if (stream && LOCAL) {	/* only if a file is open */
+    int silent = stream->silent;
+    stream->silent = T;		/* note this stream is dying */
+				/* do an expunge if requested */
+    if (options & CL_EXPUNGE) mbx_expunge (stream,NIL,NIL);
+    else {			/* otherwise do a checkpoint to purge */
+      LOCAL->expok = T;		/*  possible expunged messages */
+      mbx_ping (stream);
+    }
+    stream->silent = silent;	/* restore previous status */
+    mbx_abort (stream);
+  }
+}
+
+
+/* MBX mail abort stream
+ * Accepts: MAIL stream
+ */
+
+void mbx_abort (MAILSTREAM *stream)
+{
+  if (stream && LOCAL) {	/* only if a file is open */
+    flock (LOCAL->fd,LOCK_UN);	/* unlock local file */
+    close (LOCAL->fd);		/* close the local file */
+				/* free local text buffer */
+    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+
+/* MBX mail fetch flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ * Sniffs at file to see if some other process changed the flags
+ */
+
+void mbx_flags (MAILSTREAM *stream,char *sequence,long flags)
+{
+  MESSAGECACHE *elt;
+  unsigned long i;
+  if (mbx_ping (stream) &&	/* ping mailbox, get new status for messages */
+      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
+       mail_sequence (stream,sequence)))
+    for (i = 1; i <= stream->nmsgs; i++) 
+      if ((elt = mail_elt (stream,i))->sequence && !elt->valid)
+	mbx_elt (stream,i,NIL);
+}
+
+/* MBX mail fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+char *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
+		  long flags)
+{
+  unsigned long i;
+  char *s;
+  *length = 0;			/* default to empty */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+				/* get header position, possibly header */
+  i = mbx_hdrpos (stream,msgno,length,&s);
+  if (!s) {			/* mbx_hdrpos() returned header? */
+    lseek (LOCAL->fd,i,L_SET);	/* no, get to header position */
+				/* is buffer big enough? */
+    if (*length > LOCAL->buflen) {
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get ((LOCAL->buflen = *length) + 1);
+    }
+				/* slurp the data */
+    read (LOCAL->fd,s = LOCAL->buf,*length);
+  }
+  s[*length] = '\0';		/* tie off string */
+  return s;
+}
+
+/* MBX mail fetch message text (body only)
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: T on success, NIL on failure
+ */
+
+long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  FDDATA d;
+  unsigned long i,j;
+  MESSAGECACHE *elt;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+				/* get message status */
+  elt = mbx_elt (stream,msgno,NIL);
+				/* if message not seen */
+  if (!(flags & FT_PEEK) && !elt->seen && mbx_flaglock (stream)) {
+    elt->seen = T;		/* mark message as seen */
+				/* recalculate status */
+    mbx_update_status (stream,msgno,NIL);
+    mm_flags (stream,msgno);
+				/* update flags */
+    mbx_flag (stream,NIL,NIL,NIL);
+  }
+  if (!LOCAL) return NIL;	/* mbx_flaglock() could have aborted */
+				/* find header position */
+  i = mbx_hdrpos (stream,msgno,&j,NIL);
+  d.fd = LOCAL->fd;		/* set up file descriptor */
+  d.pos = i + j;
+  d.chunk = LOCAL->buf;	/* initial buffer chunk */
+  d.chunksize = CHUNKSIZE;
+  INIT (bs,fd_string,&d,elt->rfc822_size - j);
+  return LONGT;			/* success */
+}
+
+/* MBX mail modify flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    flag(s)
+ *	    option flags
+ * Unlocks flag lock
+ */
+
+void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
+{
+  struct utimbuf times;
+  struct stat sbuf;
+				/* make sure the update takes */
+  if (!stream->rdonly && LOCAL && (LOCAL->fd >= 0) && (LOCAL->ld >= 0)) {
+    fsync (LOCAL->fd);
+    fstat (LOCAL->fd,&sbuf);	/* get current write time */
+    times.modtime = LOCAL->filetime = sbuf.st_mtime;
+				/* update header */
+    if ((LOCAL->ffuserflag < NUSERFLAGS) &&
+	stream->user_flags[LOCAL->ffuserflag]) mbx_update_header (stream);
+    times.actime = time (0);	/* make sure read comes after all that */
+    utime (stream->mailbox,&times);
+  }
+  if (LOCAL->ld >= 0) {		/* unlock now */
+    unlockfd (LOCAL->ld,LOCAL->lock);
+    LOCAL->ld = -1;
+  }
+}
+
+
+/* MBX mail per-message modify flags
+ * Accepts: MAIL stream
+ *	    message cache element
+ */
+
+void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  if (mbx_flaglock (stream)) mbx_update_status (stream,elt->msgno,NIL);
+}
+
+/* MBX mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream still alive, NIL if not
+ */
+
+long mbx_ping (MAILSTREAM *stream)
+{
+  unsigned long i,pos;
+  long ret = NIL;
+  int ld;
+  char lock[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  struct stat sbuf;
+  if (stream && LOCAL) {	/* only if stream already open */
+    ret = LONGT;		/* assume OK */
+    fstat (LOCAL->fd,&sbuf);	/* get current file poop */
+				/* allow expunge if permitted at ping */
+    if (mail_parameters (NIL,GET_EXPUNGEATPING,NIL)) LOCAL->expok = T;
+				/* if external modification */
+    if (LOCAL->filetime && (LOCAL->filetime < sbuf.st_mtime))
+      LOCAL->flagcheck = T;	/* upgrade to flag checking */
+				/* new mail or flagcheck handling needed? */
+    if (((sbuf.st_size - LOCAL->filesize) || LOCAL->flagcheck ||
+	 !stream->nmsgs) &&
+	((ld = lockname (lock,stream->mailbox,LOCK_EX)) >= 0)) {
+      if (!LOCAL->flagcheck) ret = mbx_parse (stream);
+				/* sweep mailbox for changed message status */
+      else if (ret = mbx_parse (stream)) {
+	unsigned long recent = 0;
+	LOCAL->filetime = sbuf.st_mtime;
+	for (i = 1; i <= stream->nmsgs; )
+	  if (elt = mbx_elt (stream,i,LOCAL->expok)) {
+	    if (elt->recent) ++recent;
+	    ++i;
+	  }
+	mail_recent (stream,recent);
+	LOCAL->flagcheck = NIL;	/* got all the updates */
+      }
+      unlockfd (ld,lock);	/* release shared parse/append permission */
+    }
+    if (ret) {			/* must still be alive */
+      if (!LOCAL->expunged)	/* look for holes if none known yet */
+	for (i = 1, pos = HDRSIZE;
+	     !LOCAL->expunged && (i <= stream->nmsgs);
+	     i++, pos += elt->private.special.text.size + elt->rfc822_size)
+	  if ((elt = mail_elt (stream,i))->private.special.offset != pos)
+	    LOCAL->expunged = T;/* found a hole */
+				/* burp any holes */
+      if (LOCAL->expunged && !stream->rdonly) {
+	if (mbx_rewrite (stream,&i,NIL)) fatal ("expunge on check");
+	if (i) {		/* any space reclaimed? */
+	  LOCAL->expunged = NIL;/* no more pending expunge */
+	  sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",i);
+	  mm_log (LOCAL->buf,(long) NIL);
+	}
+      }
+      LOCAL->expok = NIL;	/* no more expok */
+    }
+  }
+  return ret;			/* return result of the parse */
+}
+
+/* MBX mail check mailbox (reparses status too)
+ * Accepts: MAIL stream
+ */
+
+void mbx_check (MAILSTREAM *stream)
+{
+  if (LOCAL) LOCAL->expok = T;	/* mark that a check is desired */
+  if (mbx_ping (stream)) mm_log ("Check completed",(long) NIL);
+}
+
+
+/* MBX mail expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T if success, NIL if failure
+ */
+
+long mbx_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  long ret;
+  unsigned long nexp,reclaimed;
+  if (ret = sequence ? ((options & EX_UID) ?
+			mail_uid_sequence (stream,sequence) :
+			mail_sequence (stream,sequence)) : LONGT) {
+    if (!mbx_ping (stream));	/* do nothing if stream dead */
+    else if (stream->rdonly)	/* won't do on readonly files! */
+      mm_log ("Expunge ignored on readonly mailbox",WARN);
+				/* if expunged any messages */
+    else if (nexp = mbx_rewrite (stream,&reclaimed,sequence ? -1 : 1)) {
+      sprintf (LOCAL->buf,"Expunged %lu messages",nexp);
+      mm_log (LOCAL->buf,(long) NIL);
+    }
+    else if (reclaimed) {	 /* or if any prior expunged space reclaimed */
+      sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",reclaimed);
+      mm_log (LOCAL->buf,(long) NIL);
+    }
+    else mm_log ("No messages deleted, so no update needed",(long) NIL);
+  }
+  return ret;
+}
+
+/* MBX mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if success, NIL if failed
+ */
+
+long mbx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  struct stat sbuf;
+  struct utimbuf times;
+  MESSAGECACHE *elt;
+  unsigned long i,j,k,m;
+  long ret = LONGT;
+  int fd,ld;
+  char *s,*t,file[MAILTMPLEN],lock[MAILTMPLEN];
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+  copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL);
+  SEARCHSET *source = cu ? mail_newsearchset () : NIL;
+  SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
+  MAILSTREAM *dstream = NIL;
+  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+	mail_sequence (stream,sequence))) return NIL;
+				/* make sure valid mailbox */
+  if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock,
+			 cu ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0)
+    switch (errno) {
+    case ENOENT:		/* no such file? */
+      mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
+      return NIL;
+    case EACCES:		/* file protected */
+      sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
+      MM_LOG (LOCAL->buf,ERROR);
+      return NIL;
+    case EINVAL:
+      if (pc) return (*pc) (stream,sequence,mailbox,options);
+      sprintf (LOCAL->buf,"Invalid MBX-format mailbox name: %.80s",mailbox);
+      mm_log (LOCAL->buf,ERROR);
+      return NIL;
+    default:
+      if (pc) return (*pc) (stream,sequence,mailbox,options);
+      sprintf (LOCAL->buf,"Not a MBX-format mailbox: %.80s",mailbox);
+      mm_log (LOCAL->buf,ERROR);
+      return NIL;
+    }
+				/* got file? */  
+  if ((fd = open (dummy_file (file,mailbox),O_RDWR|O_CREAT|O_BINARY,
+		  S_IREAD|S_IWRITE)) < 0) {
+    sprintf (LOCAL->buf,"Unable to open copy mailbox: %s",strerror (errno));
+    mm_log (LOCAL->buf,ERROR);
+    return NIL;
+  }
+  mm_critical (stream);		/* go critical */
+  fstat (fd,&sbuf);		/* get current file size */
+  lseek (fd,sbuf.st_size,L_SET);/* move to end of file */
+
+				/* for each requested message */
+  for (i = 1; ret && (i <= stream->nmsgs); i++) 
+    if ((elt = mail_elt (stream,i))->sequence) {
+      lseek (LOCAL->fd,elt->private.special.offset +
+	     elt->private.special.text.size,L_SET);
+      mail_date(LOCAL->buf,elt);/* build target header */
+				/* get target keyword mask */
+      for (j = elt->user_flags, k = 0; j; )
+	if (s = stream->user_flags[find_rightmost_bit (&j)])
+	  for (m = 0; (m < NUSERFLAGS) && (t = dstream->user_flags[m]); m++)
+	    if (!compare_cstring (s,t) && (k |= 1 << m)) break;
+      sprintf (LOCAL->buf+strlen(LOCAL->buf),",%lu;%08lx%04x-%08lx\015\012",
+	       elt->rfc822_size,k,(unsigned)
+	       ((fSEEN * elt->seen) + (fDELETED * elt->deleted) +
+		(fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
+		(fDRAFT * elt->draft)),cu ? ++dstream->uid_last : 0);
+				/* write target header */
+      if (ret = (write (fd,LOCAL->buf,strlen (LOCAL->buf)) > 0)) {
+	for (k = elt->rfc822_size; ret && (j = min (k,LOCAL->buflen)); k -= j){
+	  read (LOCAL->fd,LOCAL->buf,j);
+	  ret = write (fd,LOCAL->buf,j) >= 0;
+	}
+	if (cu) {		/* need to pass back new UID? */
+	  mail_append_set (source,mail_uid (stream,i));
+	  mail_append_set (dest,dstream->uid_last);
+	}
+      }
+    }
+
+				/* make sure all the updates take */
+  if (!(ret && (ret = !fsync (fd)))) {
+    sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno));
+    mm_log (LOCAL->buf,ERROR);
+    ftruncate (fd,sbuf.st_size);
+  }
+  if (cu && ret) {		/* return sets if doing COPYUID */
+    (*cu) (stream,mailbox,dstream->uid_validity,source,dest);
+    lseek (fd,15,L_SET);	/* update UIDLAST */
+    sprintf (LOCAL->buf,"%08lx",dstream->uid_last);
+    write (fd,LOCAL->buf,8);
+  }
+  else {			/* flush any sets we may have built */
+    mail_free_searchset (&source);
+    mail_free_searchset (&dest);
+  }
+				/* set atime to now-1 if successful copy */
+  if (ret) times.actime = time (0) - 1;
+				/* else preserved \Marked status */
+  else times.actime = (sbuf.st_ctime > sbuf.st_atime) ?
+	 sbuf.st_atime : time (0);
+  times.modtime = sbuf.st_mtime;/* preserve mtime */
+  utime (file,&times);		/* set the times */
+  close (fd);			/* close the file */
+  mm_nocritical (stream);	/* release critical */
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+				/* delete all requested messages */
+  if (ret && (options & CP_MOVE) && mbx_flaglock (stream)) {
+    for (i = 1; i <= stream->nmsgs; i++) if (mail_elt (stream,i)->sequence) {
+				/* mark message deleted */
+      mbx_elt (stream,i,NIL)->deleted = T;
+				/* recalculate status */
+      mbx_update_status (stream,i,NIL);
+    }
+				/* update flags */
+    mbx_flag (stream,NIL,NIL,NIL);
+  }
+  if (dstream != stream) mail_close (dstream);
+  return ret;
+}
+
+/* MBX mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long mbx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct stat sbuf;
+  int fd,ld;
+  char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  struct utimbuf times;
+  FILE *df;
+  MESSAGECACHE elt;
+  long f;
+  unsigned long i,uf;
+  STRING *message;
+  long ret = NIL;
+  MAILSTREAM *dstream = NIL;
+  appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL);
+  SEARCHSET *dst = au ? mail_newsearchset () : NIL;
+				/* make sure valid mailbox */
+				/* make sure valid mailbox */
+  if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock,
+			 au ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0)
+    switch (errno) {
+    case ENOENT:		/* no such file? */
+      if (compare_cstring (mailbox,"INBOX")) {
+	mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+	return NIL;
+      }
+				/* can create INBOX here */
+      mbx_create (dstream = stream ? stream : &mbxproto,"INBOX");
+      if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock,
+			     au ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0)
+	break;
+    case EACCES:		/* file protected */
+      sprintf (tmp,"Can't access destination: %.80s",mailbox);
+      MM_LOG (tmp,ERROR);
+      return NIL;
+    case EINVAL:
+      sprintf (tmp,"Invalid MBX-format mailbox name: %.80s",mailbox);
+      mm_log (tmp,ERROR);
+      return NIL;
+    default:
+      sprintf (tmp,"Not a MBX-format mailbox: %.80s",mailbox);
+      mm_log (tmp,ERROR);
+      return NIL;
+    }
+
+				/* get first message */
+  if (!(*af) (dstream,data,&flags,&date,&message)) close (fd);
+  else if (!(df = fdopen (fd,"r+b"))) {
+    MM_LOG ("Unable to reopen append mailbox",ERROR);
+    close (fd);
+  }
+  else {
+    mm_critical (dstream);	/* go critical */
+    fstat (fd,&sbuf);		/* get current file size */
+    fseek (df,sbuf.st_size,SEEK_SET);
+    errno = 0;
+    for (ret = LONGT; ret && message; ) {
+      if (!SIZE (message)) {	/* guard against zero-length */
+	mm_log ("Append of zero-length message",ERROR);
+	ret = NIL;
+	break;
+      }
+      f = mail_parse_flags (dstream,flags,&uf);
+      if (date) {		/* parse date if given */
+	if (!mail_parse_date (&elt,date)) {
+	  sprintf (tmp,"Bad date in append: %.80s",date);
+	  mm_log (tmp,ERROR);
+	  ret = NIL;		/* mark failure */
+	  break;
+	}
+	mail_date (tmp,&elt);	/* write preseved date */
+      }
+      else internal_date (tmp);	/* get current date in IMAP format */
+				/* write header */
+      if (fprintf (df,"%s,%lu;%08lx%04lx-%08lx\015\012",tmp,i = SIZE (message),
+		   uf,(unsigned long) f,au ? ++dstream->uid_last : 0) < 0)
+	ret = NIL;
+      else {			/* write message */
+	size_t j;
+	if (!message->cursize) SETPOS (message,GETPOS (message));
+	while (i && (j = fwrite (message->curpos,1,message->cursize,df))) {
+	  i -= j;
+	  SETPOS (message,GETPOS (message) + j);
+	}
+				/* get next message */
+	if (i || !(*af) (dstream,data,&flags,&date,&message)) ret = NIL;
+	else if (au) mail_append_set (dst,dstream->uid_last);
+      }
+    }
+
+				/* if error... */
+    if (!ret || (fflush (df) == EOF)) {
+				/* revert file */
+      ftruncate (fd,sbuf.st_size);
+      close (fd);		/* make sure fclose() doesn't corrupt us */
+      if (errno) {
+	sprintf (tmp,"Message append failed: %s",strerror (errno));
+	mm_log (tmp,ERROR);
+      }
+      ret = NIL;
+    }
+    if (au && ret) {		/* return sets if doing APPENDUID */
+      (*au) (mailbox,dstream->uid_validity,dst);
+      fseek (df,15,SEEK_SET);	/* update UIDLAST */
+      fprintf (df,"%08lx",dstream->uid_last);
+    }
+    else mail_free_searchset (&dst);
+    if (ret) times.actime = time (0) - 1;
+				/* else preserve \Marked status */
+    else times.actime = (sbuf.st_ctime > sbuf.st_atime) ?
+	   sbuf.st_atime : time (0);
+				/* preserve mtime */
+    times.modtime = sbuf.st_mtime;
+    utime (file,&times);	/* set the times */
+    fclose (df);		/* close the file */
+    mm_nocritical (dstream);	/* release critical */
+  }
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+  if (dstream != stream) mail_close (dstream);
+  return ret;
+}
+
+/* Internal routines */
+
+
+/* MBX mail parse mailbox
+ * Accepts: MAIL stream
+ * Returns: T if parse OK
+ *	    NIL if failure, stream aborted
+ */
+
+long mbx_parse (MAILSTREAM *stream)
+{
+  struct stat sbuf;
+  MESSAGECACHE *elt = NIL;
+  unsigned char c,*s,*t,*x;
+  char tmp[MAILTMPLEN];
+  unsigned long i,j,k,m;
+  off_t curpos = LOCAL->filesize;
+  unsigned long nmsgs = stream->nmsgs;
+  unsigned long recent = stream->recent;
+  unsigned long lastuid = 0;
+  short dirty = NIL;
+  short added = NIL;
+  short silent = stream->silent;
+  short uidwarn = T;
+  fstat (LOCAL->fd,&sbuf);	/* get status */
+  if (sbuf.st_size < curpos) {	/* sanity check */
+    sprintf (tmp,"Mailbox shrank from %lu to %lu!",
+	     (unsigned long) curpos,(unsigned long) sbuf.st_size);
+    mm_log (tmp,ERROR);
+    mbx_abort (stream);
+    return NIL;
+  }
+  lseek (LOCAL->fd,0,L_SET);	/* rewind file */
+				/* read internal header */
+  read (LOCAL->fd,LOCAL->buf,HDRSIZE);
+  LOCAL->buf[HDRSIZE] = '\0';	/* tie off header */
+  c = LOCAL->buf[15];		/* save first character of last UID */
+  LOCAL->buf[15] = '\0';
+				/* parse UID validity */
+  stream->uid_validity = strtoul (LOCAL->buf + 7,NIL,16);
+  LOCAL->buf[15] = c;		/* restore first character of last UID */
+				/* parse last UID */
+  i = strtoul (LOCAL->buf + 15,NIL,16);
+  stream->uid_last = stream->rdonly ? max (i,stream->uid_last) : i;
+				/* parse user flags */
+  for (i = 0, s = LOCAL->buf + 25;
+       (i < NUSERFLAGS) && (t = strchr (s,'\015')) && (t - s);
+       i++, s = t + 2) {
+    *t = '\0';			/* tie off flag */
+    if (!stream->user_flags[i] && (strlen (s) <= MAXUSERFLAG))
+      stream->user_flags[i] = cpystr (s);
+  }
+  LOCAL->ffuserflag = (int) i;	/* first free user flag */
+
+  stream->silent = T;		/* don't pass up mm_exists() events yet */
+  while (sbuf.st_size - curpos){/* while there is stuff to parse */
+				/* get to that position in the file */
+    lseek (LOCAL->fd,curpos,L_SET);
+    if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) {
+      sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s",
+	       (unsigned long) curpos,(unsigned long) sbuf.st_size,
+	       i ? strerror (errno) : "no data read");
+      mm_log (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+    LOCAL->buf[i] = '\0';	/* tie off buffer just in case */
+    if (!((s = strchr (LOCAL->buf,'\015')) && (s[1] == '\012'))) {
+      sprintf (tmp,"Unable to find CRLF at %lu in %lu bytes, text: %.80s",
+	       (unsigned long) curpos,i,(char *) LOCAL->buf);
+      mm_log (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+    *s = '\0';			/* tie off header line */
+    i = (s + 2) - LOCAL->buf;	/* note start of text offset */
+    if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) {
+      sprintf (tmp,"Unable to parse internal header at %lu: %.80s",
+	       (unsigned long) curpos,(char *) LOCAL->buf);
+      mm_log (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+    if (!(isxdigit (t[1]) && isxdigit (t[2]) && isxdigit (t[3]) &&
+	  isxdigit (t[4]) && isxdigit (t[5]) && isxdigit (t[6]) &&
+	  isxdigit (t[7]) && isxdigit (t[8]) && isxdigit (t[9]) &&
+	  isxdigit (t[10]) && isxdigit (t[11]) && isxdigit (t[12]))) {
+      sprintf (tmp,"Unable to parse message flags at %lu: %.80s",
+	       (unsigned long) curpos,(char *) LOCAL->buf);
+      mm_log (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+    if ((t[13] != '-') || t[22] ||
+	!(isxdigit (t[14]) && isxdigit (t[15]) && isxdigit (t[16]) &&
+	  isxdigit (t[17]) && isxdigit (t[18]) && isxdigit (t[19]) &&
+	  isxdigit (t[20]) && isxdigit (t[21]))) {
+      sprintf (tmp,"Unable to parse message UID at %lu: %.80s",
+	       (unsigned long) curpos,(char *) LOCAL->buf);
+      mm_log (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+
+    *s++ = '\0'; *t++ = '\0';	/* break up fields */
+				/* get message size */
+    if (!(j = strtoul (s,(char **) &x,10)) && (!(x && *x))) {
+      sprintf (tmp,"Unable to parse message size at %lu: %.80s,%.80s;%.80s",
+	       (unsigned long) curpos,(char *) LOCAL->buf,(char *) s,
+	       (char *) t);
+      mm_log (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+				/* make sure didn't run off end of file */
+    if (((off_t) (curpos + i + j)) > sbuf.st_size) {
+      sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
+	       (unsigned long) curpos,(unsigned long) (curpos + i + j),
+	       (unsigned long) sbuf.st_size);
+      mm_log (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+				/* parse UID */
+    if ((m = strtoul (t+13,NIL,16)) &&
+	((m <= lastuid) || (m > stream->uid_last))) {
+      if (uidwarn) {
+	sprintf (tmp,"Invalid UID %08lx in message %lu, rebuilding UIDs",
+		 m,nmsgs+1);
+	mm_log (tmp,WARN);
+	uidwarn = NIL;
+				/* restart UID validity */
+	stream->uid_validity = (unsigned long) time (0);
+      }
+      m = 0;			/* lose this UID */
+      dirty = T;		/* mark dirty, set new lastuid */
+      stream->uid_last = lastuid;
+    }
+
+    t[12] = '\0';		/* parse system flags */
+    if ((k = strtoul (t+8,NIL,16)) & fEXPUNGED) {
+      if (m) lastuid = m;	/* expunge message, update last UID seen */
+      else {			/* no UID assigned? */
+	lastuid = ++stream->uid_last;
+	dirty = T;
+      }
+    }
+    else {			/* not expunged, swell the cache */
+      added = T;		/* note that a new message was added */
+      mail_exists (stream,++nmsgs);
+				/* instantiate an elt for this message */
+      (elt = mail_elt (stream,nmsgs))->valid = T;
+				/* parse the date */
+      if (!mail_parse_date (elt,LOCAL->buf)) {
+	sprintf (tmp,"Unable to parse message date at %lu: %.80s",
+		 (unsigned long) curpos,(char *) LOCAL->buf);
+	mm_log (tmp,ERROR);
+	mbx_abort (stream);
+	return NIL;
+      }
+				/* note file offset of header */
+      elt->private.special.offset = curpos;
+				/* and internal header size */
+      elt->private.special.text.size = i;
+				/* header size not known yet */
+      elt->private.msg.header.text.size = 0;
+      elt->rfc822_size = j;	/* note message size */
+				/* calculate system flags */
+      if (k & fSEEN) elt->seen = T;
+      if (k & fDELETED) elt->deleted = T;
+      if (k & fFLAGGED) elt->flagged = T;
+      if (k & fANSWERED) elt->answered = T;
+      if (k & fDRAFT) elt->draft = T;
+      t[8] = '\0';		/* get user flags value */
+      elt->user_flags = strtoul (t,NIL,16);
+				/* UID already assigned? */
+      if (!(elt->private.uid = m) || !(k & fOLD)) {
+	elt->recent = T;	/* no, mark as recent */
+	++recent;		/* count up a new recent message */
+	dirty = T;		/* and must rewrite header */
+				/* assign new UID */
+	if (!elt->private.uid) elt->private.uid = ++stream->uid_last;
+	mbx_update_status (stream,elt->msgno,NIL);
+      }
+				/* update last parsed UID */
+      lastuid = elt->private.uid;
+    }
+    curpos += i + j;		/* update position */
+  }
+
+  if (dirty && !stream->rdonly){/* update header */
+    mbx_update_header (stream);
+    fsync (LOCAL->fd);		/* make sure all the UID updates take */
+  }
+				/* update parsed file size and time */
+  LOCAL->filesize = sbuf.st_size;
+  fstat (LOCAL->fd,&sbuf);	/* get status again to ensure time is right */
+  LOCAL->filetime = sbuf.st_mtime;
+  if (added && !stream->rdonly){/* make sure atime updated */
+    struct utimbuf times;
+    times.actime = time (0);
+    times.modtime = LOCAL->filetime;
+    utime (stream->mailbox,&times);
+  }
+  stream->silent = silent;	/* can pass up events now */
+  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
+  mail_recent (stream,recent);	/* and of change in recent messages */
+  return LONGT;			/* return the winnage */
+}
+
+/* MBX get cache element with status updating from file
+ * Accepts: MAIL stream
+ *	    message number
+ *	    expunge OK flag
+ * Returns: cache element
+ */
+
+MESSAGECACHE *mbx_elt (MAILSTREAM *stream,unsigned long msgno,long expok)
+{
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  struct {			/* old flags */
+    unsigned int seen : 1;
+    unsigned int deleted : 1;
+    unsigned int flagged : 1;
+    unsigned int answered : 1;
+    unsigned int draft : 1;
+    unsigned long user_flags;
+  } old;
+  old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged;
+  old.answered = elt->answered; old.draft = elt->draft;
+  old.user_flags = elt->user_flags;
+				/* get new flags */
+  if (mbx_read_flags (stream,elt) && expok) {
+    mail_expunged (stream,elt->msgno);
+    return NIL;			/* return this message was expunged */
+  }
+  if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
+      (old.flagged != elt->flagged) || (old.answered != elt->answered) ||
+      (old.draft != elt->draft) || (old.user_flags != elt->user_flags))
+    mm_flags (stream,msgno);	/* let top level know */
+  return elt;
+}
+
+/* MBX read flags from file
+ * Accepts: MAIL stream
+ *	    cache element
+ * Returns: non-NIL if message expunged
+ */
+
+unsigned long mbx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  unsigned long i;
+  struct stat sbuf;
+  fstat (LOCAL->fd,&sbuf);	/* get status */
+				/* make sure file size is good */
+  if (sbuf.st_size < LOCAL->filesize) {
+    sprintf (LOCAL->buf,"Mailbox shrank from %lu to %lu in flag read!",
+	     (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
+    fatal (LOCAL->buf);
+  }
+				/* set the seek pointer */
+  lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	 elt->private.special.text.size - 24,L_SET);
+				/* read the new flags */
+  if (read (LOCAL->fd,LOCAL->buf,14) < 0) {
+    sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno));
+    fatal (LOCAL->buf);
+  }
+  if ((LOCAL->buf[0] != ';') || (LOCAL->buf[13] != '-')) {
+    LOCAL->buf[14] = '\0';	/* tie off buffer for error message */
+    sprintf (LOCAL->buf+50,"Invalid flags for message %lu (%lu %lu): %s",
+	     elt->msgno,elt->private.special.offset,
+	     elt->private.special.text.size,(char *) LOCAL->buf);
+    fatal (LOCAL->buf+50);
+  }
+  LOCAL->buf[13] = '\0';	/* tie off buffer */
+				/* calculate system flags */
+  i = strtoul (LOCAL->buf+9,NIL,16);
+  elt->seen = i & fSEEN ? T : NIL;
+  elt->deleted = i & fDELETED ? T : NIL;
+  elt->flagged = i & fFLAGGED ? T : NIL;
+  elt->answered = i & fANSWERED ? T : NIL;
+  elt->draft = i & fDRAFT ? T : NIL;
+  LOCAL->expunged |= i & fEXPUNGED ? T : NIL;
+  LOCAL->buf[9] = '\0';		/* tie off flags */
+				/* get user flags value */
+  elt->user_flags = strtoul (LOCAL->buf+1,NIL,16);
+  elt->valid = T;		/* have valid flags now */
+  return i & fEXPUNGED;
+}
+
+/* MBX update header
+ * Accepts: MAIL stream
+ */
+
+#define NTKLUDGEOFFSET 7
+
+void mbx_update_header (MAILSTREAM *stream)
+{
+  int i;
+  char *s = LOCAL->buf;
+  memset (s,'\0',HDRSIZE);	/* initialize header */
+  sprintf (s,"*mbx*\015\012%08lx%08lx\015\012",
+	   stream->uid_validity,stream->uid_last);
+  for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i]; ++i)
+    sprintf (s += strlen (s),"%s\015\012",stream->user_flags[i]);
+  LOCAL->ffuserflag = i;	/* first free user flag */
+				/* can we create more user flags? */
+  stream->kwd_create = (i < NUSERFLAGS) ? T : NIL;
+				/* write reserved lines */
+  while (i++ < NUSERFLAGS) strcat (s,"\015\012");
+  while (T) {			/* rewind file */
+    lseek (LOCAL->fd,NTKLUDGEOFFSET,L_SET);
+				/* write new header */
+    if (write (LOCAL->fd,LOCAL->buf + NTKLUDGEOFFSET,
+	       HDRSIZE - NTKLUDGEOFFSET) > 0) break;
+    mm_notify (stream,strerror (errno),WARN);
+    mm_diskerror (stream,errno,T);
+  }
+}
+
+/* MBX update status string
+ * Accepts: MAIL stream
+ *	    message number
+ *	    flags
+ */
+
+void mbx_update_status (MAILSTREAM *stream,unsigned long msgno,long flags)
+{
+  struct stat sbuf;
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+				/* readonly */
+  if (stream->rdonly || !elt->valid) mbx_read_flags (stream,elt);
+  else {			/* readwrite */
+    fstat (LOCAL->fd,&sbuf);	/* get status */
+				/* make sure file size is good */
+    if (sbuf.st_size < LOCAL->filesize) {
+      sprintf (LOCAL->buf,"Mailbox shrank from %lu to %lu in flag update!",
+	       (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
+      fatal (LOCAL->buf);
+    }
+				/* set the seek pointer */
+    lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	   elt->private.special.text.size - 24,L_SET);
+				/* read the new flags */
+    if (read (LOCAL->fd,LOCAL->buf,14) < 0) {
+      sprintf (LOCAL->buf,"Unable to read old status: %s",strerror (errno));
+      fatal (LOCAL->buf);
+    }
+    if ((LOCAL->buf[0] != ';') || (LOCAL->buf[13] != '-')) {
+      LOCAL->buf[14] = '\0';	/* tie off buffer for error message */
+      sprintf (LOCAL->buf+50,"Invalid flags for message %lu (%lu %lu): %s",
+	       elt->msgno,elt->private.special.offset,
+	       elt->private.special.text.size,(char *) LOCAL->buf);
+      fatal (LOCAL->buf+50);
+    }
+				/* print new flag string */
+    sprintf (LOCAL->buf,"%08lx%04x-%08lx",elt->user_flags,(unsigned)
+	     (((elt->deleted && flags) ?
+	       fEXPUNGED : (strtoul (LOCAL->buf+9,NIL,16)) & fEXPUNGED) +
+	      (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
+	      (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
+	      (fDRAFT * elt->draft) + fOLD),elt->private.uid);
+    while (T) {			/* get to that place in the file */
+      lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	     elt->private.special.text.size - 23,L_SET);
+				/* write new flags and UID */
+      if (write (LOCAL->fd,LOCAL->buf,21) > 0) break;
+      mm_notify (stream,strerror (errno),WARN);
+      mm_diskerror (stream,errno,T);
+    }
+  }
+}
+
+/* MBX locate header for a message
+ * Accepts: MAIL stream
+ *	    message number
+ *	    pointer to returned header size
+ *	    pointer to possible returned header
+ * Returns: position of header in file
+ */
+
+#define HDRBUFLEN 16384		/* good enough for most headers */
+#define SLOP 4			/* CR LF CR LF */
+
+unsigned long mbx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			  unsigned long *size,char **hdr)
+{
+  unsigned long siz,done;
+  long i;
+  unsigned char *s,*t,*te;
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  unsigned long ret = elt->private.special.offset +
+    elt->private.special.text.size;
+  if (hdr) *hdr = NIL;		/* assume no header returned */
+				/* is header size known? */ 
+  if (*size = elt->private.msg.header.text.size) return ret;
+				/* paranoia check */
+  if (LOCAL->buflen < (HDRBUFLEN + SLOP))
+    fatal ("LOCAL->buf smaller than HDRBUFLEN");
+  lseek (LOCAL->fd,ret,L_SET);	/* get to header position */
+				/* read HDRBUFLEN chunks with 4 byte slop */
+  for (done = siz = 0, s = LOCAL->buf;
+       (i = min ((long) (elt->rfc822_size - done),(long) HDRBUFLEN)) &&
+       (read (LOCAL->fd,s,i) == i);
+       done += i, siz += (t - LOCAL->buf) - SLOP, s = LOCAL->buf + SLOP) {
+    te = (t = s + i) - 12;	/* calculate end of fast scan */
+				/* fast scan for CR */
+    for (s = LOCAL->buf; s < te;)
+      if (((*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') ||
+	   (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') ||
+	   (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') ||
+	   (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015')) &&
+	  (*s == '\012') && (*++s == '\015') && (*++s == '\012')) {
+	*size = elt->private.msg.header.text.size = siz + (++s - LOCAL->buf);
+	if (hdr) *hdr = LOCAL->buf;
+	return ret;
+      }
+    for (te = t - 3; (s < te);)	/* final character-at-a-time scan */
+      if ((*s++ == '\015') && (*s == '\012') && (*++s == '\015') &&
+	  (*++s == '\012')) {
+	*size = elt->private.msg.header.text.size = siz + (++s - LOCAL->buf);
+	if (hdr) *hdr = LOCAL->buf;
+	return ret;
+      }
+    if (i <= SLOP) break;	/* end of data */
+				/* slide over last 4 bytes */
+    memmove (LOCAL->buf,t - SLOP,SLOP);
+    hdr = NIL;			/* can't return header this way */
+  }
+				/* not found: header consumes entire message */
+  elt->private.msg.header.text.size = *size = elt->rfc822_size;
+  if (hdr) *hdr = LOCAL->buf;	/* possibly return header too */
+  return ret;
+}
+
+/* MBX mail rewrite mailbox
+ * Accepts: MAIL stream
+ *	    pointer to return reclaimed size
+ *	    flags (0 = no expunge, 1 = expunge deleted, -1 = expunge sequence)
+ * Returns: number of expunged messages
+ */
+
+unsigned long mbx_rewrite (MAILSTREAM *stream,unsigned long *reclaimed,
+			   long flags)
+{
+  struct utimbuf times;
+  struct stat sbuf;
+  off_t pos,ppos;
+  int ld;
+  unsigned long i,j,k,m,delta;
+  unsigned long n = *reclaimed = 0;
+  unsigned long recent = 0;
+  char lock[MAILTMPLEN];
+  MESSAGECACHE *elt;
+				/* get parse/append permission */
+  if ((ld = lockname (lock,stream->mailbox,LOCK_EX)) < 0) {
+    mm_log ("Unable to lock expunge mailbox",ERROR);
+    return 0;
+  }
+  fstat (LOCAL->fd,&sbuf);	/* get current write time */
+  if (LOCAL->filetime && !LOCAL->flagcheck &&
+      (LOCAL->filetime < sbuf.st_mtime)) LOCAL->flagcheck = T;
+  if (!mbx_parse (stream)) {	/* make sure see any newly-arrived messages */
+    unlockfd (ld,lock);		/* failed?? */
+    return 0;
+  }
+  if (LOCAL->flagcheck) {	/* sweep flags if need flagcheck */
+    LOCAL->filetime = sbuf.st_mtime;
+    for (i = 1; i <= stream->nmsgs; ++i) mbx_elt (stream,i,NIL);
+    LOCAL->flagcheck = NIL;
+  }
+
+				/* get exclusive access */
+  if (!flock (LOCAL->fd,LOCK_EX|LOCK_NB)) {
+    mm_critical (stream);	/* go critical */
+    for (i = 1,delta = 0,pos = ppos = HDRSIZE; i <= stream->nmsgs; ) {
+				/* note if message not at predicted location */
+      if (m = (elt = mbx_elt (stream,i,NIL))->private.special.offset - ppos) {
+	ppos = elt->private.special.offset;
+	*reclaimed += m;	/* note reclaimed message space */
+	delta += m;		/* and as expunge delta  */
+      }
+				/* number of bytes to smash or preserve */
+      ppos += (k = elt->private.special.text.size + elt->rfc822_size);
+				/* if need to expunge this message*/
+      if (flags && elt->deleted && ((flags > 0) || elt->sequence)) {
+	delta += k;		/* number of bytes to delete */
+	mail_expunged(stream,i);/* notify upper levels */
+	n++;			/* count up one more expunged message */
+      }
+      else {			/* preserved message */
+	i++;			/* count this message */
+	if (elt->recent) ++recent;
+	if (delta) {		/* moved, note first byte to preserve */
+	  j = elt->private.special.offset;
+	  do {			/* read from source position */
+	    m = min (k,LOCAL->buflen);
+	    lseek (LOCAL->fd,j,L_SET);
+	    read (LOCAL->fd,LOCAL->buf,m);
+	    pos = j - delta;	/* write to destination position */
+	    while (T) {
+	      lseek (LOCAL->fd,pos,L_SET);
+	      if (write (LOCAL->fd,LOCAL->buf,m) > 0) break;
+	      mm_notify (stream,strerror (errno),WARN);
+	      mm_diskerror (stream,errno,T);
+	    }
+	    pos += m;		/* new position */
+	    j += m;		/* next chunk, perhaps */
+	  } while (k -= m);	/* until done */
+				/* note the new address of this text */
+	  elt->private.special.offset -= delta;
+	}
+				/* preserved but no deleted messages yet */
+	else pos = elt->private.special.offset + k;
+      }
+    }
+				/* deltaed file size match position? */
+    if (m = (LOCAL->filesize -= delta) - pos) {
+      *reclaimed += m;		/* probably an fEXPUNGED msg */
+      LOCAL->filesize = pos;	/* set correct size */
+    }
+				/* truncate file after last message */
+    ftruncate (LOCAL->fd,LOCAL->filesize);
+    fsync (LOCAL->fd);		/* force disk update */
+    mm_nocritical (stream);	/* release critical */
+    flock (LOCAL->fd,LOCK_SH);	/* allow sharers again */
+  }
+
+  else {			/* can't get exclusive */
+    flock (LOCAL->fd,LOCK_SH);	/* recover previous shared mailbox lock */
+				/* do hide-expunge when shared */
+    if (flags) for (i = 1; i <= stream->nmsgs; ) {
+      if (elt = mbx_elt (stream,i,T)) {
+				/* make the message invisible */
+	if (elt->deleted && ((flags > 0) || elt->sequence)) {
+	  mbx_update_status (stream,elt->msgno,LONGT);
+				/* notify upper levels */
+	  mail_expunged (stream,i);
+	  n++;			/* count up one more expunged message */
+	}
+	else {
+	  i++;			/* preserved message */
+	  if (elt->recent) ++recent;
+	}
+      }
+      else n++;			/* count up one more expunged message */
+    }
+    fsync (LOCAL->fd);		/* force disk update */
+  }
+  fstat (LOCAL->fd,&sbuf);	/* get new write time */
+  times.modtime = LOCAL->filetime = sbuf.st_mtime;
+  times.actime = time (0);	/* reset atime to now */
+  utime (stream->mailbox,&times);
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+				/* notify upper level of new mailbox size */
+  mail_exists (stream,stream->nmsgs);
+  mail_recent (stream,recent);
+  return n;			/* return number of expunged messages */
+}
+
+/* MBX mail lock for flag updating
+ * Accepts: stream
+ * Returns: T if successful, NIL if failure
+ */
+
+long mbx_flaglock (MAILSTREAM *stream)
+{
+  struct stat sbuf;
+  unsigned long i;
+  int ld;
+  char lock[MAILTMPLEN];
+				/* no-op if readonly or already locked */
+  if (!stream->rdonly && LOCAL && (LOCAL->fd >= 0) && (LOCAL->ld < 0)) {
+				/* lock now */
+    if ((ld = lockname (lock,stream->mailbox,LOCK_EX)) < 0) return NIL;
+    if (!LOCAL->flagcheck) {	/* don't do this if flagcheck already needed */
+      if (LOCAL->filetime) {	/* know previous time? */
+	fstat (LOCAL->fd,&sbuf);/* get current write time */
+	if (LOCAL->filetime < sbuf.st_mtime) LOCAL->flagcheck = T;
+	LOCAL->filetime = 0;	/* don't do this test for any other messages */
+      }
+      if (!mbx_parse (stream)) {/* parse mailbox */
+	unlockfd (ld,lock);	/* shouldn't happen */
+	return NIL;
+      }
+      if (LOCAL->flagcheck)	/* invalidate cache if flagcheck */
+	for (i = 1; i <= stream->nmsgs; ++i) mail_elt (stream,i)->valid = NIL;
+    }
+    LOCAL->ld = ld;		/* copy to stream for subsequent calls */
+    memcpy (LOCAL->lock,lock,MAILTMPLEN);
+  }
+  return LONGT;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/mkautaux.bat	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,31 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM     http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM 
+REM ========================================================================
+
+REM Program:	Authenticator Linkage Generator auxillary for NT/Win9x
+REM
+REM Author:	Mark Crispin
+REM		Networks and Distributed Computing
+REM		Computing & Communications
+REM		University of Washington
+REM		Administration Building, AG-44
+REM		Seattle, WA  98195
+REM		Internet: MRC@CAC.Washington.EDU
+REM
+REM Date:	6 December 1995
+REM Last Edited:30 August 2006
+
+ECHO extern AUTHENTICATOR auth_%1; >> LINKAGE.H
+REM Note the introduction of the caret to quote the ampersand in NT
+if "%OS%" == "Windows_NT" ECHO   auth_link (^&auth_%1);		/* link in the %1 authenticator */ >> LINKAGE.C
+if "%OS%" == "" ECHO   auth_link (&auth_%1);		/* link in the %1 authenticator */ >> LINKAGE.C
+ECHO #include "auth_%1.c" >> AUTHS.C
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/mkauths.bat	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,33 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM     http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM 
+REM ========================================================================
+
+REM Program:	Authenticator Linkage Generator for DOS and Windows
+REM
+REM Author:	Mark Crispin
+REM		Networks and Distributed Computing
+REM		Computing & Communications
+REM		University of Washington
+REM		Administration Building, AG-44
+REM		Seattle, WA  98195
+REM		Internet: MRC@CAC.Washington.EDU
+REM
+REM Date:	6 December 1995
+REM Last Edited:30 August 2006
+
+REM Erase old authenticators list
+IF EXIST AUTHS.C DEL AUTHS.C
+
+REM Now define the new list
+FOR %%D IN (%1 %2 %3 %4 %5 %6 %7 %8 %9) DO CALL MKAUTAUX %%D
+
+EXIT 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/mtxnt.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1232 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	MTX mail routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	22 May 1990
+ * Last Edited:	15 June 2007
+ */
+
+
+/*				FILE TIME SEMANTICS
+ *
+ * The atime is the last read time of the file.
+ * The mtime is the last flags update time of the file.
+ * The ctime is the last write time of the file.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "mail.h"
+#include "osdep.h"
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/utime.h>
+#include "misc.h"
+#include "dummy.h"
+#include "fdstring.h"
+
+/* MTX I/O stream local data */
+	
+typedef struct mtx_local {
+  unsigned int shouldcheck: 1;	/* if ping should do a check instead */
+  unsigned int mustcheck: 1;	/* if ping must do a check instead */
+  int fd;			/* file descriptor for I/O */
+  off_t filesize;		/* file size parsed */
+  time_t filetime;		/* last file time */
+  time_t lastsnarf;		/* last snarf time */
+  unsigned char *buf;		/* temporary buffer */
+  unsigned long buflen;		/* current size of temporary buffer */
+} MTXLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((MTXLOCAL *) stream->local)
+
+
+/* Function prototypes */
+
+DRIVER *mtx_valid (char *name);
+int mtx_isvalid (char *name,char *file);
+void *mtx_parameters (long function,void *value);
+void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void mtx_list (MAILSTREAM *stream,char *ref,char *pat);
+void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long mtx_create (MAILSTREAM *stream,char *mailbox);
+long mtx_delete (MAILSTREAM *stream,char *mailbox);
+long mtx_rename (MAILSTREAM *stream,char *old,char *newname);
+long mtx_status (MAILSTREAM *stream,char *mbx,long flags);
+MAILSTREAM *mtx_open (MAILSTREAM *stream);
+void mtx_close (MAILSTREAM *stream,long options);
+void mtx_flags (MAILSTREAM *stream,char *sequence,long flags);
+char *mtx_header (MAILSTREAM *stream,unsigned long msgno,
+		  unsigned long *length,long flags);
+long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+void mtx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
+void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
+long mtx_ping (MAILSTREAM *stream);
+void mtx_check (MAILSTREAM *stream);
+void mtx_snarf (MAILSTREAM *stream);
+long mtx_expunge (MAILSTREAM *stream,char *sequence,long options);
+long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+long mtx_parse (MAILSTREAM *stream);
+MESSAGECACHE *mtx_elt (MAILSTREAM *stream,unsigned long msgno);
+void mtx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt);
+void mtx_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag);
+unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			  unsigned long *size);
+
+
+/* MTX mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER mtxdriver = {
+  "mtx",			/* driver name */
+				/* driver flags */
+  DR_LOCAL|DR_MAIL|DR_CRLF|DR_NOSTICKY,
+  (DRIVER *) NIL,		/* next driver */
+  mtx_valid,			/* mailbox is valid for us */
+  mtx_parameters,		/* manipulate parameters */
+  mtx_scan,			/* scan mailboxes */
+  mtx_list,			/* list mailboxes */
+  mtx_lsub,			/* list subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  mtx_create,			/* create mailbox */
+  mtx_delete,			/* delete mailbox */
+  mtx_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  mtx_open,			/* open mailbox */
+  mtx_close,			/* close mailbox */
+  mtx_flags,			/* fetch message "fast" attributes */
+  mtx_flags,			/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  mtx_header,			/* fetch message header */
+  mtx_text,			/* fetch message body */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  mtx_flag,			/* modify flags */
+  mtx_flagmsg,			/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  mtx_ping,			/* ping mailbox to see if still alive */
+  mtx_check,			/* check for new messages */
+  mtx_expunge,			/* expunge deleted messages */
+  mtx_copy,			/* copy messages to another mailbox */
+  mtx_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM mtxproto = {&mtxdriver};
+
+/* MTX mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *mtx_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+  return mtx_isvalid (name,tmp) ? &mtxdriver : NIL;
+}
+
+
+/* MTX mail test for valid mailbox
+ * Accepts: mailbox name
+ *	    buffer to return file name
+ * Returns: T if valid, NIL otherwise
+ */
+
+int mtx_isvalid (char *name,char *file)
+{
+  int fd;
+  int ret = NIL;
+  char *s,tmp[MAILTMPLEN];
+  struct stat sbuf;
+  struct utimbuf times;
+  errno = EINVAL;		/* assume invalid argument */
+				/* if file, get its status */
+  if ((s = dummy_file (file,name)) && !stat (s,&sbuf) &&
+      ((sbuf.st_mode & S_IFMT) == S_IFREG)) {
+    if (!sbuf.st_size)errno = 0;/* empty file */
+    else if ((fd = open (file,O_BINARY|O_RDONLY,NIL)) >= 0) {
+      memset (tmp,'\0',MAILTMPLEN);
+      if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\015')) &&
+	  (s[1] == '\012')) {	/* valid format? */
+	*s = '\0';		/* tie off header */
+				/* must begin with dd-mmm-yy" */
+	ret = (((tmp[2] == '-' && tmp[6] == '-') ||
+		(tmp[1] == '-' && tmp[5] == '-')) &&
+	       (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL;
+      }
+      else errno = -1;		/* bogus format */
+      close (fd);		/* close the file */
+				/* \Marked status? */
+      if (sbuf.st_ctime > sbuf.st_atime) {
+				/* preserve atime and mtime */
+	times.actime = sbuf.st_atime;
+	times.modtime = sbuf.st_mtime;
+	utime (file,&times);	/* set the times */
+      }
+    }
+  }
+				/* in case INBOX but not mtx format */
+  else if ((errno == ENOENT) && !compare_cstring (name,"INBOX")) errno = -1;
+  return ret;			/* return what we should */
+}
+
+
+/* MTX manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *mtx_parameters (long function,void *value)
+{
+  return NIL;
+}
+
+/* MTX mail scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* MTX mail list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mtx_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_list (NIL,ref,pat);
+}
+
+
+/* MTX mail list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_lsub (NIL,ref,pat);
+}
+
+/* MTX mail create mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long mtx_create (MAILSTREAM *stream,char *mailbox)
+{
+  char *s,mbx[MAILTMPLEN];
+  if (s = dummy_file (mbx,mailbox)) return dummy_create (stream,s);
+  sprintf (mbx,"Can't create %.80s: invalid name",mailbox);
+  mm_log (mbx,ERROR);
+  return NIL;
+}
+
+
+/* MTX mail delete mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long mtx_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return mtx_rename (stream,mailbox,NIL);
+}
+
+/* MTX mail rename mailbox
+ * Accepts: MAIL stream
+ *	    old mailbox name
+ *	    new mailbox name (or NIL for delete)
+ * Returns: T on success, NIL on failure
+ */
+
+long mtx_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  long ret = LONGT;
+  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  int fd,ld;
+  struct stat sbuf;
+  if (!dummy_file (file,old) ||
+      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
+		   ((s = strrchr (tmp,'\\')) && !s[1])))) {
+    sprintf (tmp,newname ?
+	     "Can't rename mailbox %.80s to %.80s: invalid name" :
+	     "Can't delete mailbox %.80s: invalid name",
+	     old,newname);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+  if ((fd = open (file,O_BINARY|O_RDWR,NIL)) < 0) {
+    sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* get exclusive parse/append permission */
+  if ((ld = lockname (lock,file,LOCK_EX)) < 0) {
+    mm_log ("Unable to lock rename mailbox",ERROR);
+    return NIL;
+  }
+				/* lock out other users */
+  if (flock (fd,LOCK_EX|LOCK_NB)) {
+    close (fd);			/* couldn't lock, give up on it then */
+    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
+    mm_log (tmp,ERROR);
+    unlockfd (ld,lock);		/* release exclusive parse/append permission */
+    return NIL;
+  }
+
+  if (newname) {		/* want rename? */
+				/* found superior to destination name? */
+    if ((s = strrchr (tmp,'\\')) && (s != tmp) &&
+	((tmp[1] != ':') || (s != tmp + 2))) {
+      c = s[1];			/* remember character after delimiter */
+      *s = s[1] = '\0';		/* tie off name at delimiter */
+				/* name doesn't exist, create it */
+      if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) {
+	*s = '\\';		/* restore delimiter */
+	if (!dummy_create (stream,tmp)) ret = NIL;
+      }
+      else *s = '\\';		/* restore delimiter */
+      s[1] = c;			/* restore character after delimiter */
+    }
+    flock (fd,LOCK_UN);		/* release lock on the file */
+    close (fd);			/* pacify NTFS */
+				/* rename the file */
+    if (ret && rename (file,tmp)) {
+      sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
+	       strerror (errno));
+      mm_log (tmp,ERROR);
+      ret = NIL;		/* set failure */
+    }
+  }
+  else {
+    flock (fd,LOCK_UN);		/* release lock on the file */
+    close (fd);			/* pacify NTFS */
+    if (unlink (file)) {
+      sprintf (tmp,"Can't delete mailbox %.80s: %.80s",old,strerror (errno));
+      mm_log (tmp,ERROR);
+      ret = NIL;		/* set failure */
+    }
+  }
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+  return ret;			/* return success */
+}
+
+/* MTX mail open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *mtx_open (MAILSTREAM *stream)
+{
+  int fd,ld;
+  char tmp[MAILTMPLEN];
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return &mtxproto;
+  if (stream->local) fatal ("mtx recycle stream");
+				/* canonicalize the mailbox name */
+  if (!dummy_file (tmp,stream->mailbox)) {
+    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
+    mm_log (tmp,ERROR);
+  }
+  if (stream->rdonly ||
+      (fd = open (tmp,O_BINARY|O_RDWR,NIL)) < 0) {
+    if ((fd = open (tmp,O_BINARY|O_RDONLY,NIL)) < 0) {
+      sprintf (tmp,"Can't open mailbox: %.80s",strerror (errno));
+      mm_log (tmp,ERROR);
+      return NIL;
+    }
+    else if (!stream->rdonly) {	/* got it, but readonly */
+      mm_log ("Can't get write access to mailbox, access is readonly",WARN);
+      stream->rdonly = T;
+    }
+  }
+  stream->local = fs_get (sizeof (MTXLOCAL));
+  LOCAL->fd = fd;		/* bind the file */
+  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
+  LOCAL->buflen = CHUNKSIZE - 1;
+				/* note if an INBOX or not */
+  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
+  fs_give ((void **) &stream->mailbox);
+  stream->mailbox = cpystr (tmp);
+				/* get shared parse permission */
+  if ((ld = lockname (tmp,stream->mailbox,LOCK_SH)) < 0) {
+    mm_log ("Unable to lock open mailbox",ERROR);
+    return NIL;
+  }
+  flock (LOCAL->fd,LOCK_SH);	/* lock the file */
+  unlockfd (ld,tmp);		/* release shared parse permission */
+  LOCAL->filesize = 0;		/* initialize parsed file size */
+  LOCAL->filetime = 0;		/* time not set up yet */
+  LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
+  stream->sequence++;		/* bump sequence number */
+  stream->uid_validity = (unsigned long) time (0);
+				/* parse mailbox */
+  stream->nmsgs = stream->recent = 0;
+  if (mtx_ping (stream) && !stream->nmsgs)
+    mm_log ("Mailbox is empty",(long) NIL);
+  if (!LOCAL) return NIL;	/* failure if stream died */
+  stream->perm_seen = stream->perm_deleted =
+    stream->perm_flagged = stream->perm_answered = stream->perm_draft =
+      stream->rdonly ? NIL : T;
+  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
+  return stream;		/* return stream to caller */
+}
+
+/* MTX mail close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void mtx_close (MAILSTREAM *stream,long options)
+{
+  if (stream && LOCAL) {	/* only if a file is open */
+    int silent = stream->silent;
+    stream->silent = T;		/* note this stream is dying */
+    if (options & CL_EXPUNGE) mtx_expunge (stream,NIL,NIL);
+    stream->silent = silent;	/* restore previous status */
+    flock (LOCAL->fd,LOCK_UN);	/* unlock local file */
+    close (LOCAL->fd);		/* close the local file */
+				/* free local text buffer */
+    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+
+/* MTX mail fetch flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ * Sniffs at file to see if some other process changed the flags
+ */
+
+void mtx_flags (MAILSTREAM *stream,char *sequence,long flags)
+{
+  unsigned long i;
+  if (mtx_ping (stream) && 	/* ping mailbox, get new status for messages */
+      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
+       mail_sequence (stream,sequence)))
+    for (i = 1; i <= stream->nmsgs; i++) 
+      if (mail_elt (stream,i)->sequence) mtx_elt (stream,i);
+}
+
+/* MTX mail fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+char *mtx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
+		  long flags)
+{
+  *length = 0;			/* default to empty */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+				/* get to header position */
+  lseek (LOCAL->fd,mtx_hdrpos (stream,msgno,length),L_SET);
+				/* is buffer big enough? */
+  if (*length > LOCAL->buflen) {
+    fs_give ((void **) &LOCAL->buf);
+    LOCAL->buf = (char *) fs_get ((LOCAL->buflen = *length) + 1);
+  }
+  LOCAL->buf[*length] = '\0';	/* tie off string */
+				/* slurp the data */
+  read (LOCAL->fd,LOCAL->buf,*length);
+  return LOCAL->buf;
+}
+
+/* MTX mail fetch message text (body only)
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: T, always
+ */
+
+long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  FDDATA d;
+  unsigned long i,j;
+  MESSAGECACHE *elt;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+  elt = mtx_elt (stream,msgno);	/* get message status */
+				/* if message not seen */
+  if (!(flags & FT_PEEK) && !elt->seen) {
+    elt->seen = T;		/* mark message as seen */
+				/* recalculate status */
+    mtx_update_status (stream,msgno,NIL);
+    mm_flags (stream,msgno);
+  }
+				/* find header position */
+  i = mtx_hdrpos (stream,msgno,&j);
+  d.fd = LOCAL->fd;		/* set up file descriptor */
+  d.pos = i + j;
+  d.chunk = LOCAL->buf;	/* initial buffer chunk */
+  d.chunksize = CHUNKSIZE;
+  INIT (bs,fd_string,&d,elt->rfc822_size - j);
+  return T;			/* success */
+}
+
+/* MTX mail modify flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    flag(s)
+ *	    option flags
+ */
+
+void mtx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
+{
+  struct utimbuf times;
+  struct stat sbuf;
+  if (!stream->rdonly) {	/* make sure the update takes */
+    fsync (LOCAL->fd);
+    fstat (LOCAL->fd,&sbuf);	/* get current write time */
+    times.modtime = LOCAL->filetime = sbuf.st_mtime;
+    times.actime = time (0);	/* make sure read comes after all that */
+    utime (stream->mailbox,&times);
+  }
+}
+
+
+/* MTX mail per-message modify flags
+ * Accepts: MAIL stream
+ *	    message cache element
+ */
+
+void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  struct stat sbuf;
+				/* maybe need to do a checkpoint? */
+  if (LOCAL->filetime && !LOCAL->shouldcheck) {
+    fstat (LOCAL->fd,&sbuf);	/* get current write time */
+    if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
+    LOCAL->filetime = 0;	/* don't do this test for any other messages */
+  }
+				/* recalculate status */
+  mtx_update_status (stream,elt->msgno,NIL);
+}
+
+/* MTX mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream still alive, NIL if not
+ */
+
+long mtx_ping (MAILSTREAM *stream)
+{
+  unsigned long i = 1;
+  long r = T;
+  int ld;
+  char lock[MAILTMPLEN];
+  struct stat sbuf;
+  if (stream && LOCAL) {	/* only if stream already open */
+    fstat (LOCAL->fd,&sbuf);	/* get current file poop */
+    if (LOCAL->filetime && !(LOCAL->mustcheck || LOCAL->shouldcheck) &&
+	(LOCAL->filetime < sbuf.st_mtime)) LOCAL->shouldcheck = T;
+				/* check for changed message status */
+    if (LOCAL->mustcheck || LOCAL->shouldcheck) {
+      LOCAL->filetime = sbuf.st_mtime;
+      if (LOCAL->shouldcheck)	/* babble when we do this unilaterally */
+	mm_notify (stream,"[CHECK] Checking for flag updates",NIL);
+      while (i <= stream->nmsgs) mtx_elt (stream,i++);
+      LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
+    }
+				/* get shared parse/append permission */
+    if ((sbuf.st_size != LOCAL->filesize) &&
+	((ld = lockname (lock,stream->mailbox,LOCK_SH)) >= 0)) {
+				/* parse resulting mailbox */
+      r = (mtx_parse (stream)) ? T : NIL;
+      unlockfd (ld,lock);	/* release shared parse/append permission */
+    }
+  }
+  return r;			/* return result of the parse */
+}
+
+
+/* MTX mail check mailbox (reparses status too)
+ * Accepts: MAIL stream
+ */
+
+void mtx_check (MAILSTREAM *stream)
+{
+				/* mark that a check is desired */
+  if (LOCAL) LOCAL->mustcheck = T;
+  if (mtx_ping (stream)) mm_log ("Check completed",(long) NIL);
+}
+
+/* MTX mail expunge mailbox
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long mtx_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  long ret;
+  struct utimbuf times;
+  struct stat sbuf;
+  off_t pos = 0;
+  int ld;
+  unsigned long i = 1;
+  unsigned long j,k,m,recent;
+  unsigned long n = 0;
+  unsigned long delta = 0;
+  char lock[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  if (!(ret = (sequence ? ((options & EX_UID) ?
+			   mail_uid_sequence (stream,sequence) :
+			   mail_sequence (stream,sequence)) : LONGT) &&
+	mtx_ping (stream)));	/* parse sequence if given, ping stream */
+  else if (stream->rdonly) mm_log ("Expunge ignored on readonly mailbox",WARN);
+  else {
+    if (LOCAL->filetime && !LOCAL->shouldcheck) {
+      fstat (LOCAL->fd,&sbuf);	/* get current write time */
+      if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
+    }
+				/* get exclusive parse/append permission */
+    if ((ld = lockname (lock,stream->mailbox,LOCK_EX)) < 0)
+      mm_log ("Unable to lock expunge mailbox",ERROR);
+				/* make sure see any newly-arrived messages */
+    else if (!mtx_parse (stream));
+				/* get exclusive access */
+    else if (flock (LOCAL->fd,LOCK_EX|LOCK_NB)) {
+      flock (LOCAL->fd,LOCK_SH);/* recover previous lock */
+      mm_log ("Can't expunge because mailbox is in use by another process",
+	      ERROR);
+      unlockfd (ld,lock);	/* release exclusive parse/append permission */
+    }
+
+    else {
+      mm_critical (stream);	/* go critical */
+      recent = stream->recent;	/* get recent now that pinged and locked */
+				/* for each message */
+      while (i <= stream->nmsgs) {
+				/* get cache element */
+	elt = mtx_elt (stream,i);
+				/* number of bytes to smash or preserve */
+	k = elt->private.special.text.size + elt->rfc822_size;
+				/* if need to expunge this message */
+	if (elt->deleted && (sequence ? elt->sequence : T)) {
+				/* if recent, note one less recent message */
+	  if (elt->recent) --recent;
+	  delta += k;		/* number of bytes to delete */
+				/* notify upper levels */
+	  mail_expunged (stream,i);
+	  n++;			/* count up one more expunged message */
+	}
+	else if (i++ && delta) {/* preserved message */
+				/* first byte to preserve */
+	  j = elt->private.special.offset;
+	  do {			/* read from source position */
+	    m = min (k,LOCAL->buflen);
+	    lseek (LOCAL->fd,j,L_SET);
+	    read (LOCAL->fd,LOCAL->buf,m);
+	    pos = j - delta;	/* write to destination position */
+	    while (T) {
+	      lseek (LOCAL->fd,pos,L_SET);
+	      if (write (LOCAL->fd,LOCAL->buf,m) > 0) break;
+	      mm_notify (stream,strerror (errno),WARN);
+	      mm_diskerror (stream,errno,T);
+	    }
+	    pos += m;		/* new position */
+	    j += m;		/* next chunk, perhaps */
+	  } while (k -= m);	/* until done */
+				/* note the new address of this text */
+	  elt->private.special.offset -= delta;
+	}
+				/* preserved but no deleted messages */
+	else pos = elt->private.special.offset + k;
+      }
+      if (n) {			/* truncate file after last message */
+	if (pos != (LOCAL->filesize -= delta)) {
+	  sprintf (LOCAL->buf,
+		   "Calculated size mismatch %lu != %lu, delta = %lu",
+		   (unsigned long) pos,(unsigned long) LOCAL->filesize,delta);
+	  mm_log (LOCAL->buf,WARN);
+	  LOCAL->filesize = pos;/* fix it then */
+	}
+	ftruncate (LOCAL->fd,LOCAL->filesize);
+	sprintf (LOCAL->buf,"Expunged %lu messages",n);
+				/* output the news */
+	mm_log (LOCAL->buf,(long) NIL);
+      }
+      else mm_log ("No messages deleted, so no update needed",(long) NIL);
+      fsync (LOCAL->fd);	/* force disk update */
+      fstat (LOCAL->fd,&sbuf);	/* get new write time */
+      times.modtime = LOCAL->filetime = sbuf.st_mtime;
+      times.actime = time (0);	/* reset atime to now */
+      utime (stream->mailbox,&times);
+      mm_nocritical (stream);	/* release critical */
+				/* notify upper level of new mailbox size */
+      mail_exists (stream,stream->nmsgs);
+      mail_recent (stream,recent);
+      flock (LOCAL->fd,LOCK_SH);/* allow sharers again */
+      unlockfd (ld,lock);	/* release exclusive parse/append permission */
+    }
+  }
+  return ret;
+}
+
+/* MTX mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if success, NIL if failed
+ */
+
+long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  struct stat sbuf;
+  struct utimbuf times;
+  MESSAGECACHE *elt;
+  unsigned long i,j,k;
+  long ret = LONGT;
+  int fd,ld;
+  char file[MAILTMPLEN],lock[MAILTMPLEN];
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+				/* make sure valid mailbox */
+  if (!mtx_isvalid (mailbox,file)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
+    return NIL;
+  case 0:			/* merely empty file? */
+    break;
+  case EACCES:			/* file protected */
+    sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
+    MM_LOG (LOCAL->buf,ERROR);
+    return NIL;
+  case EINVAL:
+    if (pc) return (*pc) (stream,sequence,mailbox,options);
+    sprintf (LOCAL->buf,"Invalid MTX-format mailbox name: %.80s",mailbox);
+    mm_log (LOCAL->buf,ERROR);
+    return NIL;
+  default:
+    if (pc) return (*pc) (stream,sequence,mailbox,options);
+    sprintf (LOCAL->buf,"Not a MTX-format mailbox: %.80s",mailbox);
+    mm_log (LOCAL->buf,ERROR);
+    return NIL;
+  }
+  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+	mail_sequence (stream,sequence))) return NIL;
+				/* got file? */
+  if ((fd = open (file,O_BINARY|O_RDWR|O_CREAT,S_IREAD|S_IWRITE)) < 0) {
+    sprintf (LOCAL->buf,"Unable to open copy mailbox: %.80s",strerror (errno));
+    mm_log (LOCAL->buf,ERROR);
+    return NIL;
+  }
+  mm_critical (stream);		/* go critical */
+				/* get exclusive parse/append permission */
+  if (flock (fd,LOCK_SH) || ((ld = lockname (lock,file,LOCK_EX)) < 0)) {
+    mm_log ("Unable to lock copy mailbox",ERROR);
+    mm_nocritical (stream);
+    return NIL;
+  }
+  fstat (fd,&sbuf);		/* get current file size */
+  lseek (fd,sbuf.st_size,L_SET);/* move to end of file */
+
+				/* for each requested message */
+  for (i = 1; ret && (i <= stream->nmsgs); i++) 
+    if ((elt = mail_elt (stream,i))->sequence) {
+      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
+				/* number of bytes to copy */
+      k = elt->private.special.text.size + elt->rfc822_size;
+      do {			/* read from source position */
+	j = min (k,LOCAL->buflen);
+	read (LOCAL->fd,LOCAL->buf,j);
+	if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
+      } while (ret && (k -= j));/* until done */
+    }
+				/* make sure all the updates take */
+  if (!(ret && (ret = !fsync (fd)))) {
+    sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno));
+    mm_log (LOCAL->buf,ERROR);
+    ftruncate (fd,sbuf.st_size);
+  }
+				/* set atime to now-1 if successful copy */
+  if (ret) times.actime = time (0) - 1;
+				/* else preserved \Marked status */
+  else times.actime = (sbuf.st_ctime > sbuf.st_atime) ?
+	 sbuf.st_atime : time (0);
+  times.modtime = sbuf.st_mtime;/* preserve mtime */
+  utime (file,&times);		/* set the times */
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+  close (fd);			/* close the file */
+  mm_nocritical (stream);	/* release critical */
+				/* delete all requested messages */
+  if (ret && (options & CP_MOVE)) {
+    for (i = 1; i <= stream->nmsgs; i++)
+      if ((elt = mtx_elt (stream,i))->sequence) {
+	elt->deleted = T;	/* mark message deleted */
+				/* recalculate status */
+	mtx_update_status (stream,i,NIL);
+      }
+    if (!stream->rdonly) {	/* make sure the update takes */
+      fsync (LOCAL->fd);
+      fstat (LOCAL->fd,&sbuf);	/* get current write time */
+      times.modtime = LOCAL->filetime = sbuf.st_mtime;
+      times.actime = time (0);	/* make sure atime remains greater */
+      utime (stream->mailbox,&times);
+    }
+  }
+  if (ret && mail_parameters (NIL,GET_COPYUID,NIL))
+    mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN);
+  return ret;
+}
+
+/* MTX mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct stat sbuf;
+  int fd,ld,c;
+  char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  struct utimbuf times;
+  FILE *df;
+  MESSAGECACHE elt;
+  long f;
+  unsigned long i,uf;
+  STRING *message;
+  long ret = LONGT;
+				/* default stream to prototype */
+  if (!stream) stream = &mtxproto;
+				/* make sure valid mailbox */
+  if (!mtx_isvalid (mailbox,file)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    if (!compare_cstring (mailbox,"INBOX")) mtx_create (NIL,"INBOX");
+    else {
+      mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+      return NIL;
+    }
+				/* falls through */
+  case 0:			/* merely empty file? */
+    break;
+  case EACCES:			/* file protected */
+    sprintf (tmp,"Can't access destination: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  case EINVAL:
+    sprintf (tmp,"Invalid MTX-format mailbox name: %.80s",mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;
+  default:
+    sprintf (tmp,"Not a MTX-format mailbox: %.80s",mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* get first message */
+  if (!(*af) (stream,data,&flags,&date,&message)) return NIL;
+
+				/* open destination mailbox */
+  if (((fd = open (file,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IREAD|S_IWRITE))
+       < 0) || !(df = fdopen (fd,"ab"))) {
+    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* get parse/append permission */
+  if (flock (fd,LOCK_SH) || ((ld = lockname (lock,file,LOCK_EX)) < 0)) {
+    mm_log ("Unable to lock append mailbox",ERROR);
+    close (fd);
+    return NIL;
+  }
+  mm_critical (stream);		/* go critical */
+  fstat (fd,&sbuf);		/* get current file size */
+  errno = 0;
+  do {				/* parse flags */
+    if (!SIZE (message)) {	/* guard against zero-length */
+      mm_log ("Append of zero-length message",ERROR);
+      ret = NIL;
+      break;
+    }
+    f = mail_parse_flags (stream,flags,&i);
+				/* reverse bits (dontcha wish we had CIRC?) */
+    for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i)));
+    if (date) {			/* parse date if given */
+      if (!mail_parse_date (&elt,date)) {
+	sprintf (tmp,"Bad date in append: %.80s",date);
+	mm_log (tmp,ERROR);
+	ret = NIL;		/* mark failure */
+	break;
+      }
+      mail_date (tmp,&elt);	/* write preseved date */
+    }
+    else internal_date (tmp);	/* get current date in IMAP format */
+				/* write header */
+    if (fprintf (df,"%s,%lu;%010lo%02lo\015\012",tmp,i = SIZE (message),uf,
+		 (unsigned long) f) < 0) ret = NIL;
+    else {			/* write message */
+      if (i) do c = 0xff & SNX (message);
+      while ((putc (c,df) != EOF) && --i);
+				/* get next message */
+      if (i || !(*af) (stream,data,&flags,&date,&message)) ret = NIL;
+    }
+  } while (ret && message);
+				/* if error... */
+  if (!ret || (fflush (df) == EOF)) {
+    ftruncate (fd,sbuf.st_size);/* revert file */
+    close (fd);			/* make sure fclose() doesn't corrupt us */
+    if (errno) {
+      sprintf (tmp,"Message append failed: %s",strerror (errno));
+      mm_log (tmp,ERROR);
+    }
+    ret = NIL;
+  }
+  if (ret) times.actime = time (0) - 1;
+				/* else preserved \Marked status */
+  else times.actime = (sbuf.st_ctime > sbuf.st_atime) ?
+	 sbuf.st_atime : time (0);
+  times.modtime = sbuf.st_mtime;/* preserve mtime */
+  utime (file,&times);		/* set the times */
+  fclose (df);			/* close the file */
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+  mm_nocritical (stream);	/* release critical */
+  if (ret && mail_parameters (NIL,GET_APPENDUID,NIL))
+    mm_log ("Can not return meaningful APPENDUID with this mailbox format",
+	    WARN);
+  return ret;
+}
+
+/* Internal routines */
+
+
+/* MTX mail parse mailbox
+ * Accepts: MAIL stream
+ * Returns: T if parse OK
+ *	    NIL if failure, stream aborted
+ */
+
+long mtx_parse (MAILSTREAM *stream)
+{
+  struct stat sbuf;
+  MESSAGECACHE *elt = NIL;
+  unsigned char c,*s,*t,*x;
+  char tmp[MAILTMPLEN];
+  unsigned long i,j;
+  long curpos = LOCAL->filesize;
+  long nmsgs = stream->nmsgs;
+  long recent = stream->recent;
+  short added = NIL;
+  short silent = stream->silent;
+  fstat (LOCAL->fd,&sbuf);	/* get status */
+  if (sbuf.st_size < curpos) {	/* sanity check */
+    sprintf (tmp,"Mailbox shrank from %ld to %ld!",curpos,sbuf.st_size);
+    mm_log (tmp,ERROR);
+    mtx_close (stream,NIL);
+    return NIL;
+  }
+  stream->silent = T;		/* don't pass up mm_exists() events yet */
+  while (sbuf.st_size - curpos){/* while there is stuff to parse */
+				/* get to that position in the file */
+    lseek (LOCAL->fd,curpos,L_SET);
+    if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) {
+      sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s",
+	       (unsigned long) curpos,(unsigned long) sbuf.st_size,
+	       i ? strerror (errno) : "no data read");
+      mm_log (tmp,ERROR);
+      mtx_close (stream,NIL);
+      return NIL;
+    }
+    LOCAL->buf[i] = '\0';	/* tie off buffer just in case */
+    if (!((s = strchr (LOCAL->buf,'\015')) && (s[1] == '\012'))) {
+      sprintf (tmp,"Unable to find CRLF at %lu in %lu bytes, text: %s",
+	       (unsigned long) curpos,i,(char *) LOCAL->buf);
+      mm_log (tmp,ERROR);
+      mtx_close (stream,NIL);
+      return NIL;
+    }
+    *s = '\0';			/* tie off header line */
+    i = (s + 2) - LOCAL->buf;	/* note start of text offset */
+    if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) {
+      sprintf (tmp,"Unable to parse internal header at %lu: %s",
+	       (unsigned long) curpos,(char *) LOCAL->buf);
+      mm_log (tmp,ERROR);
+      mtx_close (stream,NIL);
+      return NIL;
+    }
+    *s++ = '\0'; *t++ = '\0';	/* tie off fields */
+
+    added = T;			/* note that a new message was added */
+				/* swell the cache */
+    mail_exists (stream,++nmsgs);
+				/* instantiate an elt for this message */
+    (elt = mail_elt (stream,nmsgs))->valid = T;
+    elt->private.uid = ++stream->uid_last;
+				/* note file offset of header */
+    elt->private.special.offset = curpos;
+				/* in case error */
+    elt->private.special.text.size = 0;
+				/* header size not known yet */
+    elt->private.msg.header.text.size = 0;
+    x = s;			/* parse the header components */
+    if (mail_parse_date (elt,LOCAL->buf) &&
+	(elt->rfc822_size = strtoul (s,(char **) &s,10)) && (!(s && *s)) &&
+	isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) &&
+	isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) &&
+	isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) &&
+	isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12])
+      elt->private.special.text.size = i;
+    else {			/* oops */
+      sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s",
+	       curpos,(char *) LOCAL->buf,(char *) x,(char *) t);
+      mm_log (tmp,ERROR);
+      mtx_close (stream,NIL);
+      return NIL;
+    }
+				/* make sure didn't run off end of file */
+    if ((curpos += (elt->rfc822_size + i)) > sbuf.st_size) {
+      sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
+	       elt->private.special.offset,(unsigned long) curpos,
+	       (unsigned long) sbuf.st_size);
+      mm_log (tmp,ERROR);
+      mtx_close (stream,NIL);
+      return NIL;
+    }
+    c = t[10];			/* remember first system flags byte */
+    t[10] = '\0';		/* tie off flags */
+    j = strtoul (t,NIL,8);	/* get user flags value */
+    t[10] = c;			/* restore first system flags byte */
+				/* set up all valid user flags (reversed!) */
+    while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
+		  stream->user_flags[i]) elt->user_flags |= 1 << i;
+				/* calculate system flags */
+    if ((j = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T;
+    if (j & fDELETED) elt->deleted = T;
+    if (j & fFLAGGED) elt->flagged = T;
+    if (j & fANSWERED) elt->answered = T;
+    if (j & fDRAFT) elt->draft = T;
+    if (!(j & fOLD)) {		/* newly arrived message? */
+      elt->recent = T;
+      recent++;			/* count up a new recent message */
+				/* mark it as old */
+      mtx_update_status (stream,nmsgs,NIL);
+    }
+  }
+  fsync (LOCAL->fd);		/* make sure all the fOLD flags take */
+				/* update parsed file size and time */
+  LOCAL->filesize = sbuf.st_size;
+  fstat (LOCAL->fd,&sbuf);	/* get status again to ensure time is right */
+  LOCAL->filetime = sbuf.st_mtime;
+  if (added && !stream->rdonly){/* make sure atime updated */
+    struct utimbuf times;
+    times.actime = time (0);
+    times.modtime = LOCAL->filetime;
+    utime (stream->mailbox,&times);
+  }
+  stream->silent = silent;	/* can pass up events now */
+  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
+  mail_recent (stream,recent);	/* and of change in recent messages */
+  return LONGT;			/* return the winnage */
+}
+
+/* MTX get cache element with status updating from file
+ * Accepts: MAIL stream
+ *	    message number
+ * Returns: cache element
+ */
+
+MESSAGECACHE *mtx_elt (MAILSTREAM *stream,unsigned long msgno)
+{
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  struct {			/* old flags */
+    unsigned int seen : 1;
+    unsigned int deleted : 1;
+    unsigned int flagged : 1;
+    unsigned int answered : 1;
+    unsigned int draft : 1;
+    unsigned long user_flags;
+  } old;
+  old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged;
+  old.answered = elt->answered; old.draft = elt->draft;
+  old.user_flags = elt->user_flags;
+  mtx_read_flags (stream,elt);
+  if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
+      (old.flagged != elt->flagged) || (old.answered != elt->answered) ||
+      (old.draft != elt->draft) || (old.user_flags != elt->user_flags))
+    mm_flags (stream,msgno);	/* let top level know */
+  return elt;
+}
+
+/* MTX read flags from file
+ * Accepts: MAIL stream
+ * Returns: cache element
+ */
+
+void mtx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  unsigned long i,j;
+				/* noop if readonly and have valid flags */
+  if (stream->rdonly && elt->valid) return;
+				/* set the seek pointer */
+  lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	 elt->private.special.text.size - 14,L_SET);
+				/* read the new flags */
+  if (read (LOCAL->fd,LOCAL->buf,12) < 0) {
+    sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno));
+    fatal (LOCAL->buf);
+  }
+				/* calculate system flags */
+  i = (((LOCAL->buf[10]-'0') * 8) + LOCAL->buf[11]-'0');
+  elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL;
+  elt->flagged = i & fFLAGGED ? T : NIL;
+  elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL;
+  LOCAL->buf[10] = '\0';	/* tie off flags */
+  j = strtoul(LOCAL->buf,NIL,8);/* get user flags value */
+				/* set up all valid user flags (reversed!) */
+  while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
+		stream->user_flags[i]) elt->user_flags |= 1 << i;
+  elt->valid = T;		/* have valid flags now */
+}
+
+/* MTX update status string
+ * Accepts: MAIL stream
+ *	    message number
+ *	    flag saying whether or not to sync
+ */
+
+void mtx_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag)
+{
+  struct utimbuf times;
+  struct stat sbuf;
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  unsigned long j,k = 0;
+				/* readonly */
+  if (stream->rdonly || !elt->valid) mtx_read_flags (stream,elt);
+  else {			/* readwrite */
+    j = elt->user_flags;	/* get user flags */
+				/* reverse bits (dontcha wish we had CIRC?) */
+    while (j) k |= 1 << (29 - find_rightmost_bit (&j));
+				/* print new flag string */
+    sprintf (LOCAL->buf,"%010lo%02o",k,(unsigned)
+	     (fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
+	      (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
+	      (fDRAFT * elt->draft)));
+    while (T) {			/* get to that place in the file */
+      lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	     elt->private.special.text.size - 14,L_SET);
+				/* write new flags */
+      if (write (LOCAL->fd,LOCAL->buf,12) > 0) break;
+      mm_notify (stream,strerror (errno),WARN);
+      mm_diskerror (stream,errno,T);
+    }
+    if (syncflag) {		/* sync if requested */
+      fsync (LOCAL->fd);
+      fstat (LOCAL->fd,&sbuf);	/* get new write time */
+      times.modtime = LOCAL->filetime = sbuf.st_mtime;
+      times.actime = time (0);	/* make sure read is later */
+      utime (stream->mailbox,&times);
+    }
+  }
+}
+
+/* MTX locate header for a message
+ * Accepts: MAIL stream
+ *	    message number
+ *	    pointer to returned header size
+ * Returns: position of header in file
+ */
+
+unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			  unsigned long *size)
+{
+  unsigned long siz;
+  long i = 0;
+  int q = 0;
+  char *s,tmp[MAILTMPLEN];
+  MESSAGECACHE *elt = mtx_elt (stream,msgno);
+  unsigned long ret = elt->private.special.offset +
+    elt->private.special.text.size;
+				/* is header size known? */
+  if (!(*size = elt->private.msg.header.text.size)) {
+    lseek (LOCAL->fd,ret,L_SET);/* get to header position */
+				/* search message for CRLF CRLF */
+    for (siz = 1,s = tmp; siz <= elt->rfc822_size; siz++) {
+				/* read another buffer as necessary */
+      if ((--i <= 0) &&		/* buffer empty? */
+	  (read (LOCAL->fd,s = tmp,
+		 i = min (elt->rfc822_size - siz,(long) MAILTMPLEN)) < 0))
+	return ret;		/* I/O error? */
+      switch (q) {		/* sniff at buffer */
+      case 0:			/* first character */
+	q = (*s++ == '\015') ? 1 : 0;
+	break;
+      case 1:			/* second character */
+	q = (*s++ == '\012') ? 2 : 0;
+	break;
+      case 2:			/* third character */
+	q = (*s++ == '\015') ? 3 : 0;
+	break;
+      case 3:			/* fourth character */
+	if (*s++ == '\012') {	/* have the sequence? */
+				/* yes, note for later */
+	  elt->private.msg.header.text.size = *size = siz;
+	  return ret;
+	}
+	q = 0;			/* lost... */
+	break;
+      }
+    }
+				/* header consumes entire message */
+    elt->private.msg.header.text.size = *size = elt->rfc822_size;
+  }
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/nl_nt.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,61 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Windows/TOPS-20 newline routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Copy string with CRLF newlines
+ * Accepts: destination string
+ *	    pointer to size of destination string buffer
+ *	    source string
+ *	    length of source string
+ * Returns: length of copied string
+ */
+
+unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl,
+			  unsigned char *src,unsigned long srcl)
+{
+				/* flush destination buffer if too small */
+  if (*dst && (srcl > *dstl)) fs_give ((void **) dst);
+  if (!*dst) {			/* make a new buffer if needed */
+    *dst = (char *) fs_get ((size_t) (*dstl = srcl) + 1);
+    if (dstl) *dstl = srcl;	/* return new buffer length to main program */
+  }
+				/* copy strings */
+  if (srcl) memcpy (*dst,src,(size_t) srcl);
+  *(*dst + srcl) = '\0';	/* tie off destination */
+  return srcl;			/* return length */
+}
+
+
+/* Length of string after strcrlfcpy applied
+ * Accepts: source string
+ * Returns: length of string
+ */
+
+unsigned long strcrlflen (STRING *s)
+{
+  return SIZE (s);		/* no-brainer on DOS! */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/os_nt.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,48 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- NT version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 April 1989
+ * Last Edited:	30 August 2006
+ */
+
+#include "tcp_nt.h"		/* must be before osdep includes tcp.h */
+#undef	ERROR			/* quell conflicting def warning */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <time.h>
+#include <errno.h>
+#include <sys\timeb.h>
+#include <fcntl.h>
+#include <sys\stat.h>
+#include "misc.h"
+#include "mailfile.h"
+
+#include "fs_nt.c"
+#include "ftl_nt.c"
+#include "nl_nt.c"
+#include "yunchan.c"
+#include "tcp_nt.c"		/* must be before env_nt.c */
+#include "env_nt.c"
+#include "ssl_nt.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/os_nt.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,60 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- NT version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	27 April 2007
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys\types.h>
+#include <time.h>
+#include <io.h>
+#include <conio.h>
+#include <process.h>
+#undef ERROR			/* quell conflicting defintion warning */
+#include <windows.h>
+#include <lm.h>
+#undef ERROR
+#define ERROR (long) 2		/* must match mail.h */
+
+#if _MSC_VER >= 1400
+#define strtok_r strtok_s	/* for some reason they called it this */
+#else
+/* strtok() is actually MT-safe in MSVC.  Why is it that Microsoft can do
+ * their CRT right, but GNU, Sun, etc. can't?
+ */
+#define strtok_r(a,b,c) strtok(*(c) = a,b)
+#endif
+
+#include "env_nt.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+#include "yunchan.h"
+
+#undef noErr
+#undef MAC
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/os_ntk.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,51 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- NT version + Kerberos
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 April 1989
+ * Last Edited:	30 August 2006
+ */
+
+#include "tcp_nt.h"		/* must be before osdep includes tcp.h */
+#undef	ERROR			/* quell conflicting def warning */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <time.h>
+#include <errno.h>
+#include <sys\timeb.h>
+#include <fcntl.h>
+#include <sys\stat.h>
+#include "misc.h"
+#include "mailfile.h"
+
+#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
+
+#include "fs_nt.c"
+#include "ftl_nt.c"
+#include "nl_nt.c"
+#include "yunchan.c"
+#include "kerb_mit.c"
+#include "tcp_nt.c"		/* must be before env_nt.c */
+#include "env_nt.c"
+#include "ssl_nt.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/os_old.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,48 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- NT version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 April 1989
+ * Last Edited:	21 December 2007
+ */
+
+#include "tcp_nt.h"		/* must be before osdep includes tcp.h */
+#undef	ERROR			/* quell conflicting def warning */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <time.h>
+#include <errno.h>
+#include <sys\timeb.h>
+#include <fcntl.h>
+#include <sys\stat.h>
+#include "misc.h"
+#include "mailfile.h"
+
+#include "fs_nt.c"
+#include "ftl_nt.c"
+#include "nl_nt.c"
+#include "yunchan.c"
+#include "tcp_nt.c"		/* must be before env_nt.c */
+#include "env_nt.c"
+#include "ssl_old.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/os_w2k.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,49 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Windows 2000 version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 April 1989
+ * Last Edited:	30 August 2006
+ */
+
+#include "tcp_nt.h"		/* must be before osdep includes tcp.h */
+#undef	ERROR			/* quell conflicting def warning */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <time.h>
+#include <errno.h>
+#include <sys\timeb.h>
+#include <fcntl.h>
+#include <sys\stat.h>
+#include "misc.h"
+#include "mailfile.h"
+
+#include "fs_nt.c"
+#include "ftl_nt.c"
+#include "nl_nt.c"
+#include "yunchan.c"
+#include "kerb_w2k.c"
+#include "tcp_nt.c"		/* must be before env_nt.c */
+#include "env_nt.c"
+#include "ssl_w2k.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/pmatch.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,89 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	IMAP Wildcard Matching Routines (case-independent)
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	15 June 2000
+ * Last Edited:	30 August 2006
+ */
+
+/* Wildcard pattern match
+ * Accepts: base string
+ *	    pattern string
+ *	    delimiter character
+ * Returns: T if pattern matches base, else NIL
+ */
+
+long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim)
+{
+  switch (*pat) {
+  case '%':			/* non-recursive */
+				/* % at end, OK if no inferiors */
+    if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T;
+                                /* scan remainder of string until delimiter */
+    do if (pmatch_full (s,pat+1,delim)) return T;
+    while ((*s != delim) && *s++);
+    break;
+  case '*':			/* match 0 or more characters */
+    if (!pat[1]) return T;	/* * at end, unconditional match */
+				/* scan remainder of string */
+    do if (pmatch_full (s,pat+1,delim)) return T;
+    while (*s++);
+    break;
+  case '\0':			/* end of pattern */
+    return *s ? NIL : T;	/* success if also end of base */
+  default:			/* match this character */
+    return compare_uchar (*pat,*s) ? NIL : pmatch_full (s+1,pat+1,delim);
+  }
+  return NIL;
+}
+
+/* Directory pattern match
+ * Accepts: base string
+ *	    pattern string
+ *	    delimiter character
+ * Returns: T if base is a matching directory of pattern, else NIL
+ */
+
+long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim)
+{
+  switch (*pat) {
+  case '%':			/* non-recursive */
+    if (!*s) return T;		/* end of base means have a subset match */
+    if (!*++pat) return NIL;	/* % at end, no inferiors permitted */
+				/* scan remainder of string until delimiter */
+    do if (dmatch (s,pat,delim)) return T;
+    while ((*s != delim) && *s++);
+    if (*s && !s[1]) return T;	/* ends with delimiter, must be subset */
+    return dmatch (s,pat,delim);/* do new scan */
+  case '*':			/* match 0 or more characters */
+    return T;			/* unconditional match */
+  case '\0':			/* end of pattern */
+    break;
+  default:			/* match this character */
+    if (*s) return compare_uchar (*pat,*s) ? NIL : dmatch (s+1,pat+1,delim);
+				/* end of base, return if at delimiter */
+    else if (*pat == delim) return T;
+    break;
+  }
+  return NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/pseudo.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,36 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Pseudo Header Strings
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	26 September 1996
+ * Last Edited:	30 August 2006
+ */
+
+/* Local sites may wish to alter this text */
+
+char *pseudo_from = "MAILER-DAEMON";
+char *pseudo_name = "Mail System Internal Data";
+char *pseudo_subject = "DON'T DELETE THIS MESSAGE -- FOLDER INTERNAL DATA";
+char *pseudo_msg =
+  "This text is part of the internal format of your mail folder, and is not\na real message.  It is created automatically by the mail system software.\nIf deleted, important folder data will be lost, and it will be re-created\nwith the data reset to initial values."
+  ;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/pseudo.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,30 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Pseudo Header Strings
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	26 September 1996
+ * Last Edited:	30 August 2006
+ */
+
+
+extern char *pseudo_from,*pseudo_name,*pseudo_subject,*pseudo_msg;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/setproto.bat	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,29 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM     http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM 
+REM ========================================================================
+
+REM Program:	Set default prototype for DOS/NT
+REM
+REM Author:	Mark Crispin
+REM		Networks and Distributed Computing
+REM		Computing & Communications
+REM		University of Washington
+REM		Administration Building, AG-44
+REM		Seattle, WA  98195
+REM		Internet: MRC@CAC.Washington.EDU
+REM
+REM Date:	 9 October 1995
+REM Last Edited: 30 August 2006
+
+REM Set the default drivers
+ECHO #define CREATEPROTO %1proto >> LINKAGE.H
+ECHO #define APPENDPROTO %2proto >> LINKAGE.H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/ssl_none.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,141 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Dummy (no SSL) authentication/encryption module
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	7 February 2001
+ * Last Edited:	30 August 2006
+ */
+
+/* Init server for SSL
+ * Accepts: server name
+ */
+
+void ssl_server_init (char *server)
+{
+  syslog (LOG_ERR,"This server does not support SSL");
+  exit (1);			/* punt this program too */
+}
+
+
+/* Start TLS
+ * Accepts: /etc/services service name
+ * Returns: cpystr'd error string if TLS failed, else NIL for success
+ */
+
+char *ssl_start_tls (char *server)
+{
+  return cpystr ("This server does not support TLS");
+}
+
+/* Get character
+ * Returns: character or EOF
+ */
+
+int PBIN (void)
+{
+  return getchar ();
+}
+
+
+/* Get string
+ * Accepts: destination string pointer
+ *	    number of bytes available
+ * Returns: destination string pointer or NIL if EOF
+ */
+
+char *PSIN (char *s,int n)
+{
+  return fgets (s,n,stdin);
+}
+
+
+/* Get record
+ * Accepts: destination string pointer
+ *	    number of bytes to read
+ * Returns: T if success, NIL otherwise
+ */
+
+long PSINR (char *s,unsigned long n)
+{
+  unsigned long i;
+  while (n && ((i = fread (s,1,n,stdin)) || (errno == EINTR))) s += i,n -= i;
+  return n ? NIL : LONGT;
+}
+
+
+/* Wait for input
+ * Accepts: timeout in seconds
+ * Returns: T if have input on stdin, else NIL
+ */
+
+long INWAIT (long seconds)
+{
+  return server_input_wait (seconds);
+}
+
+/* Put character
+ * Accepts: character
+ * Returns: character written or EOF
+ */
+
+int PBOUT (int c)
+{
+  return putchar (c);
+}
+
+
+/* Put string
+ * Accepts: source string pointer
+ * Returns: 0 or EOF if error
+ */
+
+int PSOUT (char *s)
+{
+  return fputs (s,stdout);
+}
+
+
+/* Put record
+ * Accepts: source sized text
+ * Returns: 0 or EOF if error
+ */
+
+int PSOUTR (SIZEDTEXT *s)
+{
+  unsigned char *t;
+  unsigned long i,j;
+  for (t = s->data,i = s->size;
+       (i && ((j = fwrite (t,1,i,stdout)) || (errno == EINTR)));
+       t += j,i -= j);
+  return i ? EOF : NIL;
+}
+
+
+/* Flush output
+ * Returns: 0 or EOF if error
+ */
+
+int PFLUSH (void)
+{
+  return fflush (stdout);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/ssl_nt.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,721 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	SSL authentication/encryption module for Windows 9x and NT
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	22 September 1998
+ * Last Edited:	13 January 2008
+ */
+
+#define SECURITY_WIN32
+#include <sspi.h>
+#include <schannel.h>
+
+
+#define SSLBUFLEN 8192
+
+
+/* SSL I/O stream */
+
+typedef struct ssl_stream {
+  TCPSTREAM *tcpstream;		/* TCP stream */
+  CredHandle cred;		/* SSL credentials */
+  CtxtHandle context;		/* SSL context */
+				/* stream encryption sizes */
+  SecPkgContext_StreamSizes sizes;
+  size_t bufsize;
+  int ictr;			/* input counter */
+  char *iptr;			/* input pointer */
+  int iextractr;		/* extra input counter */
+  char *iextraptr;		/* extra input pointer */
+  char *ibuf;			/* input buffer */
+  char *obuf;			/* output buffer */
+} SSLSTREAM;
+
+#include "sslio.h"
+
+
+/* Function prototypes */
+
+static SSLSTREAM *ssl_start(TCPSTREAM *tstream,char *host,unsigned long flags);
+static char *ssl_analyze_status (SECURITY_STATUS err,char *buf);
+static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size,
+			       long *contd);
+static long ssl_abort (SSLSTREAM *stream);
+
+/* Secure Sockets Layer network driver dispatch */
+
+static struct ssl_driver ssldriver = {
+  ssl_open,			/* open connection */
+  ssl_aopen,			/* open preauthenticated connection */
+  ssl_getline,			/* get a line */
+  ssl_getbuffer,		/* get a buffer */
+  ssl_soutr,			/* output pushed data */
+  ssl_sout,			/* output string */
+  ssl_close,			/* close connection */
+  ssl_host,			/* return host name */
+  ssl_remotehost,		/* return remote host name */
+  ssl_port,			/* return port number */
+  ssl_localhost			/* return local host name */
+};
+
+				/* security function table */
+static SecurityFunctionTable *sft = NIL;
+static unsigned long ssltsz = 0;/* SSL maximum token length */
+
+
+/* Define crypt32.dll stuff here in case a pre-IE5 Win9x system */
+
+typedef DWORD (CALLBACK *CNTS) (DWORD,PCERT_NAME_BLOB,DWORD,LPSTR,DWORD);
+typedef BOOL (CALLBACK *CGCC) (HCERTCHAINENGINE,PCCERT_CONTEXT,LPFILETIME,
+			       HCERTSTORE,PCERT_CHAIN_PARA,DWORD,LPVOID,
+			       PCCERT_CHAIN_CONTEXT *);
+typedef BOOL (CALLBACK *CVCCP) (LPCSTR,PCCERT_CHAIN_CONTEXT,
+				PCERT_CHAIN_POLICY_PARA,
+				PCERT_CHAIN_POLICY_STATUS);
+typedef VOID (CALLBACK *CFCC) (PCCERT_CHAIN_CONTEXT);
+typedef BOOL (CALLBACK *CFCCX) (PCCERT_CONTEXT);
+
+static CNTS certNameToStr = NIL;
+static CGCC certGetCertificateChain = NIL;
+static CVCCP certVerifyCertificateChainPolicy = NIL;
+static CFCC certFreeCertificateChain = NIL;
+static CFCCX certFreeCertificateContext = NIL;
+
+/* One-time SSL initialization */
+
+static int sslonceonly = 0;
+
+void ssl_onceonlyinit (void)
+{
+  if (!sslonceonly++) {		/* only need to call it once */
+    HINSTANCE lib;
+    FARPROC pi;
+    ULONG np;
+    SecPkgInfo *pp;
+    int i;
+				/* get security library */
+    if (((lib = LoadLibrary ("schannel.dll")) ||
+	 (lib = LoadLibrary ("security.dll"))) &&
+	(pi = GetProcAddress (lib,SECURITY_ENTRYPOINT)) &&
+	(sft = (SecurityFunctionTable *) pi ()) &&
+	!(sft->EnumerateSecurityPackages (&np,&pp))) {
+				/* look for an SSL package */
+      for (i = 0; (i < (int) np); i++) if (!strcmp (pp[i].Name,UNISP_NAME)) {
+				/* note maximum token size and name */
+	ssltsz = pp[i].cbMaxToken;
+				/* apply runtime linkage */
+	mail_parameters (NIL,SET_SSLDRIVER,(void *) &ssldriver);
+	mail_parameters (NIL,SET_SSLSTART,(void *) ssl_start);
+	if ((lib = LoadLibrary ("crypt32.dll")) &&
+	    (certGetCertificateChain = (CGCC)
+	     GetProcAddress (lib,"CertGetCertificateChain")) &&
+	    (certVerifyCertificateChainPolicy = (CVCCP)
+	     GetProcAddress (lib,"CertVerifyCertificateChainPolicy")) &&
+	    (certFreeCertificateChain = (CFCC)
+	     GetProcAddress (lib,"CertFreeCertificateChain")) &&
+	    (certFreeCertificateContext = (CFCCX)
+	     GetProcAddress (lib,"CertFreeCertificateContext")))
+	  certNameToStr = (CNTS) GetProcAddress (lib,"CertNameToStrA");
+	return;			/* all done */
+      }
+    }
+  }
+}
+
+/* SSL open
+ * Accepts: host name
+ *	    contact service name
+ *	    contact port number
+ * Returns: SSL stream if success else NIL
+ */
+
+SSLSTREAM *ssl_open (char *host,char *service,unsigned long port)
+{
+  TCPSTREAM *stream = tcp_open (host,service,port);
+  return stream ? ssl_start (stream,host,port) : NIL;
+}
+
+  
+/* SSL authenticated open
+ * Accepts: host name
+ *	    service name
+ *	    returned user name buffer
+ * Returns: SSL stream if success else NIL
+ */
+
+SSLSTREAM *ssl_aopen (NETMBX *mb,char *service,char *usrbuf)
+{
+  return NIL;			/* don't use this mechanism with SSL */
+}
+
+/* Start SSL/TLS negotiations
+ * Accepts: open TCP stream of session
+ *	    user's host name
+ *	    flags
+ * Returns: SSL stream if success else NIL
+ */
+
+static SSLSTREAM *ssl_start (TCPSTREAM *tstream,char *host,unsigned long flags)
+{
+  SECURITY_STATUS e;
+  ULONG a;
+  TimeStamp t;
+  SecBuffer ibuf[2],obuf[1];
+  SecBufferDesc ibufs,obufs;
+  SCHANNEL_CRED tlscred;
+  CERT_CONTEXT *cert = NIL;
+  CERT_CHAIN_PARA chparam;
+  CERT_CHAIN_CONTEXT *chain;
+  SSL_EXTRA_CERT_CHAIN_POLICY_PARA policy;
+  CERT_CHAIN_POLICY_PARA polparam;
+  CERT_CHAIN_POLICY_STATUS status;
+  char tmp[MAILTMPLEN],certname[256];
+  char *reason = NIL;
+  ULONG req = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT |
+    ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY |
+      ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM | ISC_REQ_EXTENDED_ERROR |
+	ISC_REQ_MANUAL_CRED_VALIDATION;
+  LPSTR usage[] = {
+    szOID_PKIX_KP_SERVER_AUTH,
+    szOID_SERVER_GATED_CRYPTO,
+    szOID_SGC_NETSCAPE
+  };
+  PWSTR whost = NIL;
+  char *buf = (char *) fs_get (ssltsz);
+  unsigned long size = 0;
+  sslcertificatequery_t scq =
+    (sslcertificatequery_t) mail_parameters (NIL,GET_SSLCERTIFICATEQUERY,NIL);
+  sslfailure_t sf = (sslfailure_t) mail_parameters (NIL,GET_SSLFAILURE,NIL);
+  SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
+					    sizeof (SSLSTREAM));
+  stream->tcpstream = tstream;	/* bind TCP stream */
+				/* initialize TLS credential */
+  memset (&tlscred,0,sizeof (SCHANNEL_CRED));
+  tlscred.dwVersion = SCHANNEL_CRED_VERSION;
+  tlscred.grbitEnabledProtocols = SP_PROT_TLS1;
+
+				/* acquire credentials */
+  if (sft->AcquireCredentialsHandle
+      (NIL,UNISP_NAME,SECPKG_CRED_OUTBOUND,NIL,(flags & NET_TLSCLIENT) ?
+       &tlscred : NIL,NIL,NIL,&stream->cred,&t)
+      != SEC_E_OK) reason = "Acquire credentials handle failed";
+  else while (!reason) {	/* negotiate security context */
+				/* initialize buffers */
+    ibuf[0].cbBuffer = size; ibuf[0].pvBuffer = buf;
+    ibuf[1].cbBuffer = 0; ibuf[1].pvBuffer = NIL;
+    obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NIL;
+    ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN;
+    ibuf[1].BufferType = SECBUFFER_EMPTY;
+				/* initialize buffer descriptors */
+    ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION;
+    ibufs.cBuffers = 2; obufs.cBuffers = 1;
+    ibufs.pBuffers = ibuf; obufs.pBuffers = obuf;
+				/* negotiate security */
+    e = sft->InitializeSecurityContext
+      (&stream->cred,size ? &stream->context : NIL,host,req,0,
+       SECURITY_NETWORK_DREP,size? &ibufs:NIL,0,&stream->context,&obufs,&a,&t);
+				/* have an output buffer we need to send? */
+    if (obuf[0].pvBuffer && obuf[0].cbBuffer) {
+      if (!tcp_sout (stream->tcpstream,obuf[0].pvBuffer,obuf[0].cbBuffer))
+	reason = "Unexpected TCP output disconnect";
+				/* free the buffer */
+      sft->FreeContextBuffer (obuf[0].pvBuffer);
+    }
+    if (!reason) switch (e) {	/* negotiation state */
+    case SEC_I_INCOMPLETE_CREDENTIALS:
+      break;			/* server wants client auth */
+    case SEC_I_CONTINUE_NEEDED:
+      if (size) {		/* continue, read any data? */
+				/* yes, anything regurgiated back to us? */
+	if (ibuf[1].BufferType == SECBUFFER_EXTRA) {
+				/* yes, set this as the new data */
+	  memmove (buf,buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer);
+	  size = ibuf[1].cbBuffer;
+	  break;
+	}
+	size = 0;		/* otherwise, read more stuff from server */
+      }
+    case SEC_E_INCOMPLETE_MESSAGE:
+				/* need to read more data from server */
+      if (!tcp_getdata (stream->tcpstream))
+	reason = "Unexpected TCP input disconnect";
+      else {
+	memcpy (buf+size,stream->tcpstream->iptr,stream->tcpstream->ictr);
+	size += stream->tcpstream->ictr;
+				/* empty it from TCP's buffers */
+	stream->tcpstream->iptr += stream->tcpstream->ictr;
+	stream->tcpstream->ictr = 0;
+      }
+      break;
+
+    case SEC_E_OK:		/* success, any data to be regurgitated? */
+      if (ibuf[1].BufferType == SECBUFFER_EXTRA) {
+				/* yes, set this as the new data */
+	memmove (stream->tcpstream->iptr = stream->tcpstream->ibuf,
+		 buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer);
+	stream->tcpstream->ictr = ibuf[1].cbBuffer;
+      }
+      if (certNameToStr && !(flags & NET_NOVALIDATECERT)) {
+				/* need validation, make wchar of host */
+	if (!((size = MultiByteToWideChar (CP_ACP,0,host,-1,NIL,0)) &&
+	      (whost = (PWSTR) fs_get (size*sizeof (WCHAR))) &&
+	      MultiByteToWideChar (CP_ACP,0,host,-1,whost,size)))
+	  fatal ("Can't make wchar of host name!");
+				/* get certificate */
+	if ((sft->QueryContextAttributes
+	     (&stream->context,SECPKG_ATTR_REMOTE_CERT_CONTEXT,&cert) !=
+	     SEC_E_OK) || !cert) {
+	  reason = "*Unable to get certificate";
+	  strcpy (certname,"<no certificate>");
+	}
+	else {			/* get certificate subject name */
+	  (*certNameToStr) (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+			    &cert->pCertInfo->Subject,CERT_X500_NAME_STR,
+			    certname,255);
+				/* build certificate chain */
+	  memset (&chparam,0,sizeof (chparam));
+	  chparam.cbSize = sizeof (chparam);
+	  chparam.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
+	  chparam.RequestedUsage.Usage.rgpszUsageIdentifier = usage;
+	  chparam.RequestedUsage.Usage.cUsageIdentifier =
+	    sizeof (usage) / sizeof (LPSTR);
+	  if (!(*certGetCertificateChain)
+	      (NIL,cert,NIL,cert->hCertStore,&chparam,NIL,NIL,&chain))
+	    reason = ssl_analyze_status (GetLastError (),tmp);
+	  else {		/* validate certificate chain */
+	    memset (&policy,0,sizeof (SSL_EXTRA_CERT_CHAIN_POLICY_PARA));
+	    policy.cbStruct = sizeof (SSL_EXTRA_CERT_CHAIN_POLICY_PARA);
+	    policy.dwAuthType = AUTHTYPE_SERVER;
+	    policy.fdwChecks = NIL;
+	    policy.pwszServerName = whost;
+	    memset (&polparam,0,sizeof (polparam));
+	    polparam.cbSize = sizeof (polparam);
+	    polparam.pvExtraPolicyPara = &policy;
+	    memset (&status,0,sizeof (status));
+	    status.cbSize = sizeof (status);
+	    if (!(*certVerifyCertificateChainPolicy)
+		(CERT_CHAIN_POLICY_SSL,chain,&polparam,&status))
+	      reason = ssl_analyze_status (GetLastError (),tmp);
+	    else if (status.dwError)
+	      reason = ssl_analyze_status (status.dwError,tmp);
+	    (*certFreeCertificateChain) (chain);
+	  }
+	  (*certFreeCertificateContext) (cert);
+	}
+	if (whost) fs_give ((void **) &whost);
+
+	if (reason) {		/* got an error? */
+				/* application callback */
+	  if (scq) reason = (*scq) ((*reason == '*') ? reason + 1 : reason,
+				    host,certname) ? NIL : "";
+	  else if (*certname) {	/* error message to return via mm_log() */
+	    sprintf (buf,"*%.128s: %.255s",
+		     (*reason == '*') ? reason + 1 : reason,certname);
+	    reason = buf;
+	  }
+	}
+      }
+      if (reason ||
+	  (reason = ssl_analyze_status
+	   (sft->QueryContextAttributes
+	    (&stream->context,SECPKG_ATTR_STREAM_SIZES,&stream->sizes),buf)))
+	break;			/* error in certificate or getting sizes */
+      fs_give ((void **) &buf);	/* flush temporary buffer */
+				/* make maximum-sized buffers */
+      stream->bufsize = stream->sizes.cbHeader +
+	stream->sizes.cbMaximumMessage + stream->sizes.cbTrailer;
+      if (stream->sizes.cbMaximumMessage < SSLBUFLEN)
+	fatal ("cbMaximumMessage is less than SSLBUFLEN!");
+      else if (stream->sizes.cbMaximumMessage < 16384) {
+	sprintf (tmp,"WINDOWS BUG: cbMaximumMessage = %ld, should be 16384",
+		 (long) stream->sizes.cbMaximumMessage);
+	mm_log (tmp,NIL);
+      }
+      stream->ibuf = (char *) fs_get (stream->bufsize);
+      stream->obuf = (char *) fs_get (stream->bufsize);
+      return stream;
+    default:
+      reason = ssl_analyze_status (e,buf);
+    }
+  }
+  ssl_close (stream);		/* failed to do SSL */
+  stream = NIL;			/* no stream returned */
+  switch (*reason) {		/* analyze reason */
+  case '*':			/* certificate failure */
+    ++reason;			/* skip over certificate failure indication */
+				/* pass to error callback */
+    if (sf) (*sf) (host,reason,flags);
+    else {			/* no error callback, build error message */
+      sprintf (tmp,"Certificate failure for %.80s: %.512s",host,reason);
+      mm_log (tmp,ERROR);
+    }
+  case '\0':			/* user answered no to certificate callback */
+    if (flags & NET_TRYSSL)	/* return dummy stream to stop tryssl */
+      stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
+				     sizeof (SSLSTREAM));
+    break;
+  default:			/* non-certificate failure */
+    if (flags & NET_TRYSSL);	/* no error output if tryssl */
+				/* pass to error callback */
+    else if (sf) (*sf) (host,reason,flags);
+    else {			/* no error callback, build error message */
+      sprintf (tmp,"TLS/SSL failure for %.80s: %.512s",host,reason);
+      mm_log (tmp,ERROR);
+    }
+    break;
+  }
+  fs_give ((void **) &buf);	/* flush temporary buffer */
+  return stream;
+}
+
+/* Generate error text from SSL error code
+ * Accepts: SSL status
+ *	    scratch buffer
+ * Returns: text if error status, else NIL
+ */
+
+static char *ssl_analyze_status (SECURITY_STATUS err,char *buf)
+{
+  switch (err) {
+  case SEC_E_OK:		/* no error */
+  case SEC_I_CONTINUE_NEEDED:
+  case SEC_I_INCOMPLETE_CREDENTIALS:
+  case SEC_E_INCOMPLETE_MESSAGE:
+    return NIL;
+  case SEC_E_NO_AUTHENTICATING_AUTHORITY:
+    mm_log ("unexpected SEC_E_NO_AUTHENTICATING_AUTHORITY",NIL);
+    return "*No authority could be contacted for authentication";
+  case SEC_E_WRONG_PRINCIPAL:
+    mm_log ("unexpected SEC_E_WRONG_PRINCIPAL",NIL);
+  case CERT_E_CN_NO_MATCH:
+    return "*Server name does not match certificate";
+  case SEC_E_UNTRUSTED_ROOT:
+    mm_log ("unexpected SEC_E_UNTRUSTED_ROOT",NIL);
+  case CERT_E_UNTRUSTEDROOT:
+    return "*Self-signed certificate or untrusted authority";
+  case SEC_E_CERT_EXPIRED:
+    mm_log ("unexpected SEC_E_CERT_EXPIRED",NIL);
+  case CERT_E_EXPIRED:
+    return "*Certificate has expired";
+  case CERT_E_REVOKED:
+    return "*Certificate revoked";
+  case SEC_E_INVALID_TOKEN:
+    return "Invalid token, probably not an SSL server";
+  case SEC_E_UNSUPPORTED_FUNCTION:
+    return "SSL not supported on this machine - upgrade your system software";
+  }
+  sprintf (buf,"Unexpected SSPI or certificate error %lx - report this",err);
+  return buf;
+}
+
+/* SSL receive line
+ * Accepts: SSL stream
+ * Returns: text line string or NIL if failure
+ */
+
+char *ssl_getline (SSLSTREAM *stream)
+{
+  unsigned long n,contd;
+  char *ret = ssl_getline_work (stream,&n,&contd);
+  if (ret && contd) {		/* got a line needing continuation? */
+    STRINGLIST *stl = mail_newstringlist ();
+    STRINGLIST *stc = stl;
+    do {			/* collect additional lines */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+      stc = stc->next = mail_newstringlist ();
+      ret = ssl_getline_work (stream,&n,&contd);
+    } while (ret && contd);
+    if (ret) {			/* stash final part of line on list */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+				/* determine how large a buffer we need */
+      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
+      ret = fs_get (n + 1);	/* copy parts into buffer */
+      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
+	memcpy (ret + n,stc->text.data,stc->text.size);
+      ret[n] = '\0';
+    }
+    mail_free_stringlist (&stl);/* either way, done with list */
+  }
+  return ret;
+}
+
+/* SSL receive line or partial line
+ * Accepts: SSL stream
+ *	    pointer to return size
+ *	    pointer to return continuation flag
+ * Returns: text line string, size and continuation flag, or NIL if failure
+ */
+
+static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size,
+			       long *contd)
+{
+  unsigned long n;
+  char *s,*ret,c,d;
+  *contd = NIL;			/* assume no continuation */
+				/* make sure have data */
+  if (!ssl_getdata (stream)) return NIL;
+  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
+    d = *stream->iptr++;	/* slurp another character */
+    if ((c == '\015') && (d == '\012')) {
+      ret = (char *) fs_get (n--);
+      memcpy (ret,s,*size = n);	/* copy into a free storage string */
+      ret[n] = '\0';		/* tie off string with null */
+      return ret;
+    }
+  }
+				/* copy partial string from buffer */
+  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
+				/* get more data from the net */
+  if (!ssl_getdata (stream)) fs_give ((void **) &ret);
+				/* special case of newline broken by buffer */
+  else if ((c == '\015') && (*stream->iptr == '\012')) {
+    stream->iptr++;		/* eat the line feed */
+    stream->ictr--;
+    ret[*size = --n] = '\0';	/* tie off string with null */
+  }
+  else *contd = LONGT;		/* continuation needed */
+  return ret;
+}
+
+/* SSL receive buffer
+ * Accepts: SSL stream
+ *	    size in bytes
+ *	    buffer to read into
+ * Returns: T if success, NIL otherwise
+ */
+
+long ssl_getbuffer (SSLSTREAM *stream,unsigned long size,char *buffer)
+{
+  unsigned long n;
+  while (size > 0) {		/* until request satisfied */
+    if (!ssl_getdata (stream)) return NIL;
+    n = min (size,stream->ictr);/* number of bytes to transfer */
+				/* do the copy */
+    memcpy (buffer,stream->iptr,n);
+    buffer += n;		/* update pointer */
+    stream->iptr += n;
+    size -= n;			/* update # of bytes to do */
+    stream->ictr -= n;
+  }
+  buffer[0] = '\0';		/* tie off string */
+  return T;
+}
+
+/* SSL receive data
+ * Accepts: TCP/IP stream
+ * Returns: T if success, NIL otherwise
+ */
+
+long ssl_getdata (SSLSTREAM *stream)
+{
+  while (stream->ictr < 1) {	/* decrypted buffer empty? */
+    SECURITY_STATUS status;
+    SecBuffer buf[4];
+    SecBufferDesc msg;
+    size_t i;
+    size_t n = 0;		/* initially no bytes to decrypt */
+    do {			/* yes, make sure have data from TCP */
+      if (stream->iextractr) {	/* have previous unread data? */
+	memcpy (stream->ibuf + n,stream->iextraptr,stream->iextractr);
+	n += stream->iextractr;	/* update number of bytes read */
+	stream->iextractr = 0;	/* no more extra data */
+      }
+      else {			/* read from TCP */
+	if (!tcp_getdata (stream->tcpstream)) return ssl_abort (stream);
+				/* maximum amount of data to copy */
+	if (!(i = min (stream->bufsize - n,stream->tcpstream->ictr)))
+	  fatal ("incomplete SecBuffer exceeds maximum buffer size");
+				/* do the copy */
+	memcpy (stream->ibuf + n,stream->tcpstream->iptr,i);
+	stream->tcpstream->iptr += i;
+	stream->tcpstream->ictr -= i;
+	n += i;			/* update number of bytes to decrypt */
+      }
+      buf[0].cbBuffer = n;	/* first SecBuffer gets data */
+      buf[0].pvBuffer = stream->ibuf;
+      buf[0].BufferType = SECBUFFER_DATA;
+				/* subsequent ones are for spares */
+      buf[1].BufferType = buf[2].BufferType = buf[3].BufferType =
+	SECBUFFER_EMPTY;
+      msg.ulVersion = SECBUFFER_VERSION;
+      msg.cBuffers = 4;		/* number of SecBuffers */
+      msg.pBuffers = buf;	/* first SecBuffer */
+
+    } while ((status = ((DECRYPT_MESSAGE_FN) sft->Reserved4)
+	      (&stream->context,&msg,0,NIL)) == SEC_E_INCOMPLETE_MESSAGE);
+    switch (status) {
+    case SEC_E_OK:		/* won */
+    case SEC_I_RENEGOTIATE:	/* won but lost it after this buffer */
+				/* hunt for a buffer */
+      for (i = 0; (i < 4) && (buf[i].BufferType != SECBUFFER_DATA) ; i++);
+      if (i < 4) {		/* found a buffer? */
+				/* yes, set up pointer and counter */
+	stream->iptr = buf[i].pvBuffer;
+	stream->ictr = buf[i].cbBuffer;
+				/* any unprocessed data? */
+	while (++i < 4) if (buf[i].BufferType == SECBUFFER_EXTRA) {
+				/* yes, note for next time around */
+	  stream->iextraptr = buf[i].pvBuffer;
+	  stream->iextractr = buf[i].cbBuffer;
+	}
+      }
+      break;
+    default:			/* anything else means we've lost */
+      return ssl_abort (stream);
+    }
+  }
+  return LONGT;
+}
+
+/* SSL send string as record
+ * Accepts: SSL stream
+ *	    string pointer
+ * Returns: T if success else NIL
+ */
+
+long ssl_soutr (SSLSTREAM *stream,char *string)
+{
+  return ssl_sout (stream,string,(unsigned long) strlen (string));
+}
+
+
+/* SSL send string
+ * Accepts: SSL stream
+ *	    string pointer
+ *	    byte count
+ * Returns: T if success else NIL
+ */
+
+long ssl_sout (SSLSTREAM *stream,char *string,unsigned long size)
+{
+  SecBuffer buf[4];
+  SecBufferDesc msg;
+  char *s;
+  size_t n;
+  if (!stream->tcpstream) return NIL;
+				/* until request satisfied */
+  for (s = stream->ibuf,n = 0; size;) {
+				/* header */
+    buf[0].BufferType = SECBUFFER_STREAM_HEADER;
+    memset (buf[0].pvBuffer = stream->obuf,0,
+	    buf[0].cbBuffer = stream->sizes.cbHeader);
+				/* message (up to maximum size) */
+    buf[1].BufferType = SECBUFFER_DATA;
+    memcpy (buf[1].pvBuffer = stream->obuf + stream->sizes.cbHeader,string,
+	    buf[1].cbBuffer = min (size,SSLBUFLEN));
+				/* trailer */
+    buf[2].BufferType = SECBUFFER_STREAM_TRAILER;
+    memset (buf[2].pvBuffer = ((char *) buf[1].pvBuffer) + buf[1].cbBuffer,0,
+	    buf[2].cbBuffer = stream->sizes.cbTrailer);
+				/* spare */
+    buf[3].BufferType = SECBUFFER_EMPTY;
+    msg.ulVersion = SECBUFFER_VERSION;
+    msg.cBuffers = 4;		/* number of SecBuffers */
+    msg.pBuffers = buf;		/* first SecBuffer */
+    string += buf[1].cbBuffer;
+    size -= buf[1].cbBuffer;	/* this many bytes processed */
+				/* encrypt and send message */
+    if ((((ENCRYPT_MESSAGE_FN) sft->Reserved3)
+	 (&stream->context,0,&msg,NIL) != SEC_E_OK) ||
+	!tcp_sout (stream->tcpstream,stream->obuf,
+		   buf[0].cbBuffer + buf[1].cbBuffer + buf[2].cbBuffer))
+      return ssl_abort (stream);/* encryption or sending failed */
+  }
+  return LONGT;
+}
+
+/* SSL close
+ * Accepts: SSL stream
+ */
+
+void ssl_close (SSLSTREAM *stream)
+{
+  ssl_abort (stream);		/* nuke the stream */
+  fs_give ((void **) &stream);	/* flush the stream */
+}
+
+
+/* SSL abort stream
+ * Accepts: SSL stream
+ * Returns: NIL always
+ */
+
+static long ssl_abort (SSLSTREAM *stream)
+{
+  if (stream->tcpstream) {	/* close TCP stream */
+    sft->DeleteSecurityContext (&stream->context);
+    sft->FreeCredentialHandle (&stream->cred);
+    tcp_close (stream->tcpstream);
+    stream->tcpstream = NIL;
+  }
+  if (stream->ibuf) fs_give ((void **) &stream->ibuf);
+  if (stream->obuf) fs_give ((void **) &stream->obuf);
+  return NIL;
+}
+
+/* SSL get host name
+ * Accepts: SSL stream
+ * Returns: host name for this stream
+ */
+
+char *ssl_host (SSLSTREAM *stream)
+{
+  return tcp_host (stream->tcpstream);
+}
+
+
+/* SSL get remote host name
+ * Accepts: SSL stream
+ * Returns: host name for this stream
+ */
+
+char *ssl_remotehost (SSLSTREAM *stream)
+{
+  return tcp_remotehost (stream->tcpstream);
+}
+
+
+/* SSL return port for this stream
+ * Accepts: SSL stream
+ * Returns: port number for this stream
+ */
+
+unsigned long ssl_port (SSLSTREAM *stream)
+{
+  return tcp_port (stream->tcpstream);
+}
+
+
+/* SSL get local host name
+ * Accepts: SSL stream
+ * Returns: local host name
+ */
+
+char *ssl_localhost (SSLSTREAM *stream)
+{
+  return tcp_localhost (stream->tcpstream);
+}
+
+#include "ssl_none.c"		/* currently no server support */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/ssl_old.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,625 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	SSL authentication/encryption module for Windows 9x and NT
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	22 September 1998
+ * Last Edited:	13 January 2008
+ */
+
+#define SECURITY_WIN32
+#include <sspi.h>
+#if(_WIN32_WINNT < 0x0400)
+typedef unsigned int ALG_ID;
+#else
+#include <wincrypt.h>
+ALGIDDEF
+#endif
+#include <schnlsp.h>
+#include <issperr.h>
+
+				/* in case a binary runs on Windows 2000 */
+#ifndef ISC_REQ_MANUAL_CRED_VALIDATION
+#define ISC_REQ_MANUAL_CRED_VALIDATION 0x00080000
+#endif
+#ifndef SEC_E_UNTRUSTED_ROOT
+#define SEC_E_UNTRUSTED_ROOT ((HRESULT) 0x80090325L)
+#endif
+#ifndef SEC_E_CERT_EXPIRED
+#define SEC_E_CERT_EXPIRED ((HRESULT) 0x80090328L)
+#endif
+
+
+#define SSLBUFLEN 8192
+
+
+/* SSL I/O stream */
+
+typedef struct ssl_stream {
+  TCPSTREAM *tcpstream;		/* TCP stream */
+  CredHandle cred;		/* SSL credentials */
+  CtxtHandle context;		/* SSL context */
+				/* stream encryption sizes */
+  SecPkgContext_StreamSizes sizes;
+  size_t bufsize;
+  int ictr;			/* input counter */
+  char *iptr;			/* input pointer */
+  int iextractr;		/* extra input counter */
+  char *iextraptr;		/* extra input pointer */
+  char *ibuf;			/* input buffer */
+  char *obuf;			/* output buffer */
+} SSLSTREAM;
+
+#include "sslio.h"
+
+
+/* Function prototypes */
+
+static SSLSTREAM *ssl_start(TCPSTREAM *tstream,char *host,unsigned long flags);
+static char *ssl_analyze_status (SECURITY_STATUS err,char *buf);
+static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size,
+			       long *contd);
+static long ssl_abort (SSLSTREAM *stream);
+
+/* Secure Sockets Layer network driver dispatch */
+
+static struct ssl_driver ssldriver = {
+  ssl_open,			/* open connection */
+  ssl_aopen,			/* open preauthenticated connection */
+  ssl_getline,			/* get a line */
+  ssl_getbuffer,		/* get a buffer */
+  ssl_soutr,			/* output pushed data */
+  ssl_sout,			/* output string */
+  ssl_close,			/* close connection */
+  ssl_host,			/* return host name */
+  ssl_remotehost,		/* return remote host name */
+  ssl_port,			/* return port number */
+  ssl_localhost			/* return local host name */
+};
+
+				/* security function table */
+static SecurityFunctionTable *sft = NIL;
+static unsigned long ssltsz = 0;/* SSL maximum token length */
+
+/* One-time SSL initialization */
+
+static int sslonceonly = 0;
+
+void ssl_onceonlyinit (void)
+{
+  if (!sslonceonly++) {		/* only need to call it once */
+    HINSTANCE lib;
+    FARPROC pi;
+    ULONG np;
+    SecPkgInfo *pp;
+    int i;
+				/* get security library */
+    if (((lib = LoadLibrary ("schannel.dll")) ||
+	 (lib = LoadLibrary ("security.dll"))) &&
+	(pi = GetProcAddress (lib,SECURITY_ENTRYPOINT)) &&
+	(sft = (SecurityFunctionTable *) pi ()) &&
+	!(sft->EnumerateSecurityPackages (&np,&pp))) {
+				/* look for an SSL package */
+      for (i = 0; (i < (int) np); i++) if (!strcmp (pp[i].Name,UNISP_NAME)) {
+				/* note maximum token size and name */
+	ssltsz = pp[i].cbMaxToken;
+				/* apply runtime linkage */
+	mail_parameters (NIL,SET_SSLDRIVER,(void *) &ssldriver);
+	mail_parameters (NIL,SET_SSLSTART,(void *) ssl_start);
+	return;			/* all done */
+      }
+    }
+  }
+}
+
+/* SSL open
+ * Accepts: host name
+ *	    contact service name
+ *	    contact port number
+ * Returns: SSL stream if success else NIL
+ */
+
+SSLSTREAM *ssl_open (char *host,char *service,unsigned long port)
+{
+  TCPSTREAM *stream = tcp_open (host,service,port);
+  return stream ? ssl_start (stream,host,port) : NIL;
+}
+
+  
+/* SSL authenticated open
+ * Accepts: host name
+ *	    service name
+ *	    returned user name buffer
+ * Returns: SSL stream if success else NIL
+ */
+
+SSLSTREAM *ssl_aopen (NETMBX *mb,char *service,char *usrbuf)
+{
+  return NIL;			/* don't use this mechanism with SSL */
+}
+
+/* Start SSL/TLS negotiations
+ * Accepts: open TCP stream of session
+ *	    user's host name
+ *	    flags
+ * Returns: SSL stream if success else NIL
+ */
+
+static SSLSTREAM *ssl_start (TCPSTREAM *tstream,char *host,unsigned long flags)
+{
+  SECURITY_STATUS e;
+  ULONG a;
+  TimeStamp t;
+  SecBuffer ibuf[2],obuf[1];
+  SecBufferDesc ibufs,obufs;
+  char tmp[MAILTMPLEN];
+  char *reason = NIL;
+  ULONG req = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT |
+    ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY |
+      ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM | ISC_REQ_EXTENDED_ERROR +
+	((flags & NET_NOVALIDATECERT) ? ISC_REQ_MANUAL_CRED_VALIDATION :
+	 ISC_REQ_MUTUAL_AUTH);
+  SCHANNEL_CRED tlscred;
+  char *buf = (char *) fs_get (ssltsz);
+  unsigned long size = 0;
+  sslfailure_t sf = (sslfailure_t) mail_parameters (NIL,GET_SSLFAILURE,NIL);
+  SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
+					    sizeof (SSLSTREAM));
+  stream->tcpstream = tstream;	/* bind TCP stream */
+				/* initialize TLS credential */
+  memset (&tlscred,0,sizeof (SCHANNEL_CRED));
+  tlscred.dwVersion = SCHANNEL_CRED_VERSION;
+  tlscred.grbitEnabledProtocols = SP_PROT_TLS1;
+
+				/* acquire credentials */
+  if (sft->AcquireCredentialsHandle
+      (NIL,UNISP_NAME,SECPKG_CRED_OUTBOUND,NIL,(flags & NET_TLSCLIENT) ?
+       &tlscred : NIL,NIL,NIL,&stream->cred,&t)
+      != SEC_E_OK) reason = "Acquire credentials handle failed";
+  else while (!reason) {	/* negotiate security context */
+				/* initialize buffers */
+    ibuf[0].cbBuffer = size; ibuf[0].pvBuffer = buf;
+    ibuf[1].cbBuffer = 0; ibuf[1].pvBuffer = NIL;
+    obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NIL;
+    ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN;
+    ibuf[1].BufferType = SECBUFFER_EMPTY;
+				/* initialize buffer descriptors */
+    ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION;
+    ibufs.cBuffers = 2; obufs.cBuffers = 1;
+    ibufs.pBuffers = ibuf; obufs.pBuffers = obuf;
+				/* negotiate security */
+    e = sft->InitializeSecurityContext
+      (&stream->cred,size ? &stream->context : NIL,host,req,0,
+       SECURITY_NETWORK_DREP,size? &ibufs:NIL,0,&stream->context,&obufs,&a,&t);
+				/* have an output buffer we need to send? */
+    if (obuf[0].pvBuffer && obuf[0].cbBuffer) {
+      if (!tcp_sout (stream->tcpstream,obuf[0].pvBuffer,obuf[0].cbBuffer))
+	reason = "Unexpected TCP output disconnect";
+				/* free the buffer */
+      sft->FreeContextBuffer (obuf[0].pvBuffer);
+    }
+    if (!reason) switch (e) {	/* negotiation state */
+    case SEC_I_INCOMPLETE_CREDENTIALS:
+      break;			/* server wants client auth */
+    case SEC_I_CONTINUE_NEEDED:
+      if (size) {		/* continue, read any data? */
+				/* yes, anything regurgiated back to us? */
+	if (ibuf[1].BufferType == SECBUFFER_EXTRA) {
+				/* yes, set this as the new data */
+	  memmove (buf,buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer);
+	  size = ibuf[1].cbBuffer;
+	  break;
+	}
+	size = 0;		/* otherwise, read more stuff from server */
+      }
+    case SEC_E_INCOMPLETE_MESSAGE:
+				/* need to read more data from server */
+      if (!tcp_getdata (stream->tcpstream))
+	reason = "Unexpected TCP input disconnect";
+      else {
+	memcpy (buf+size,stream->tcpstream->iptr,stream->tcpstream->ictr);
+	size += stream->tcpstream->ictr;
+				/* empty it from TCP's buffers */
+	stream->tcpstream->iptr += stream->tcpstream->ictr;
+	stream->tcpstream->ictr = 0;
+      }
+      break;
+
+    case SEC_E_OK:		/* success, any data to be regurgitated? */
+      if (ibuf[1].BufferType == SECBUFFER_EXTRA) {
+				/* yes, set this as the new data */
+	memmove (stream->tcpstream->iptr = stream->tcpstream->ibuf,
+		 buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer);
+	stream->tcpstream->ictr = ibuf[1].cbBuffer;
+      }
+      if (reason = ssl_analyze_status
+	  (sft->QueryContextAttributes
+	   (&stream->context,SECPKG_ATTR_STREAM_SIZES,&stream->sizes),buf))
+	break;			/* error getting sizes */
+      fs_give ((void **) &buf);	/* flush temporary buffer */
+				/* make maximum-sized buffers */
+      stream->bufsize = stream->sizes.cbHeader +
+	stream->sizes.cbMaximumMessage + stream->sizes.cbTrailer;
+      if (stream->sizes.cbMaximumMessage < SSLBUFLEN)
+	fatal ("cbMaximumMessage is less than SSLBUFLEN!");
+      else if (stream->sizes.cbMaximumMessage < 16384) {
+	sprintf (tmp,"WINDOWS BUG: cbMaximumMessage = %ld, should be 16384",
+		 (long) stream->sizes.cbMaximumMessage);
+	mm_log (tmp,NIL);
+      }
+      stream->ibuf = (char *) fs_get (stream->bufsize);
+      stream->obuf = (char *) fs_get (stream->bufsize);
+      return stream;
+    default:
+      reason = ssl_analyze_status (e,buf);
+    }
+  }
+  ssl_close (stream);		/* failed to do SSL */
+  stream = NIL;			/* no stream returned */
+  fs_give ((void **) &buf);	/* flush temporary buffer */
+  switch (*reason) {		/* analyze reason */
+  case '*':			/* certificate failure */
+    ++reason;			/* skip over certificate failure indication */
+				/* pass to error callback */
+    if (sf) (*sf) (host,reason,flags);
+    else {			/* no error callback, build error message */
+      sprintf (tmp,"Certificate failure for %.80s: %.512s",host,reason);
+      mm_log (tmp,ERROR);
+    }
+  case '\0':			/* user answered no to certificate callback */
+    if (flags & NET_TRYSSL)	/* return dummy stream to stop tryssl */
+      stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
+				     sizeof (SSLSTREAM));
+    break;
+  default:			/* non-certificate failure */
+    if (flags & NET_TRYSSL);	/* no error output if tryssl */
+				/* pass to error callback */
+    else if (sf) (*sf) (host,reason,flags);
+    else {			/* no error callback, build error message */
+      sprintf (tmp,"TLS/SSL failure for %.80s: %.512s",host,reason);
+      mm_log (tmp,ERROR);
+    }
+    break;
+  }
+  return stream;
+}
+
+/* Generate error text from SSL error code
+ * Accepts: SSL status
+ *	    scratch buffer
+ * Returns: text if error status, else NIL
+ */
+
+static char *ssl_analyze_status (SECURITY_STATUS err,char *buf)
+{
+  switch (err) {
+  case SEC_E_OK:		/* no error */
+  case SEC_I_CONTINUE_NEEDED:
+  case SEC_I_INCOMPLETE_CREDENTIALS:
+  case SEC_E_INCOMPLETE_MESSAGE:
+    return NIL;
+  case SEC_E_NO_AUTHENTICATING_AUTHORITY:
+    return "*No authority could be contacted for authentication";
+  case SEC_E_WRONG_PRINCIPAL:
+    return "*Server name does not match certificate";
+  case SEC_E_UNTRUSTED_ROOT:
+    return "*Self-signed certificate or untrusted authority";
+  case SEC_E_CERT_EXPIRED:
+    return "*Certificate has expired";
+  case SEC_E_INVALID_TOKEN:
+    return "Invalid token, probably not an SSL server";
+  case SEC_E_UNSUPPORTED_FUNCTION:
+    return "SSL not supported on this machine - upgrade your system software";
+  }
+  sprintf (buf,"Unexpected SChannel error %lx - report this",err);
+  return buf;
+}
+
+/* SSL receive line
+ * Accepts: SSL stream
+ * Returns: text line string or NIL if failure
+ */
+
+char *ssl_getline (SSLSTREAM *stream)
+{
+  unsigned long n,contd;
+  char *ret = ssl_getline_work (stream,&n,&contd);
+  if (ret && contd) {		/* got a line needing continuation? */
+    STRINGLIST *stl = mail_newstringlist ();
+    STRINGLIST *stc = stl;
+    do {			/* collect additional lines */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+      stc = stc->next = mail_newstringlist ();
+      ret = ssl_getline_work (stream,&n,&contd);
+    } while (ret && contd);
+    if (ret) {			/* stash final part of line on list */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+				/* determine how large a buffer we need */
+      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
+      ret = fs_get (n + 1);	/* copy parts into buffer */
+      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
+	memcpy (ret + n,stc->text.data,stc->text.size);
+      ret[n] = '\0';
+    }
+    mail_free_stringlist (&stl);/* either way, done with list */
+  }
+  return ret;
+}
+
+/* SSL receive line or partial line
+ * Accepts: SSL stream
+ *	    pointer to return size
+ *	    pointer to return continuation flag
+ * Returns: text line string, size and continuation flag, or NIL if failure
+ */
+
+static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size,
+			       long *contd)
+{
+  unsigned long n;
+  char *s,*ret,c,d;
+  *contd = NIL;			/* assume no continuation */
+				/* make sure have data */
+  if (!ssl_getdata (stream)) return NIL;
+  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
+    d = *stream->iptr++;	/* slurp another character */
+    if ((c == '\015') && (d == '\012')) {
+      ret = (char *) fs_get (n--);
+      memcpy (ret,s,*size = n);	/* copy into a free storage string */
+      ret[n] = '\0';		/* tie off string with null */
+      return ret;
+    }
+  }
+				/* copy partial string from buffer */
+  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
+				/* get more data from the net */
+  if (!ssl_getdata (stream)) fs_give ((void **) &ret);
+				/* special case of newline broken by buffer */
+  else if ((c == '\015') && (*stream->iptr == '\012')) {
+    stream->iptr++;		/* eat the line feed */
+    stream->ictr--;
+    ret[*size = --n] = '\0';	/* tie off string with null */
+  }
+  else *contd = LONGT;		/* continuation needed */
+  return ret;
+}
+
+/* SSL receive buffer
+ * Accepts: SSL stream
+ *	    size in bytes
+ *	    buffer to read into
+ * Returns: T if success, NIL otherwise
+ */
+
+long ssl_getbuffer (SSLSTREAM *stream,unsigned long size,char *buffer)
+{
+  unsigned long n;
+  while (size > 0) {		/* until request satisfied */
+    if (!ssl_getdata (stream)) return NIL;
+    n = min (size,stream->ictr);/* number of bytes to transfer */
+				/* do the copy */
+    memcpy (buffer,stream->iptr,n);
+    buffer += n;		/* update pointer */
+    stream->iptr += n;
+    size -= n;			/* update # of bytes to do */
+    stream->ictr -= n;
+  }
+  buffer[0] = '\0';		/* tie off string */
+  return T;
+}
+
+/* SSL receive data
+ * Accepts: TCP/IP stream
+ * Returns: T if success, NIL otherwise
+ */
+
+long ssl_getdata (SSLSTREAM *stream)
+{
+  while (stream->ictr < 1) {	/* decrypted buffer empty? */
+    SECURITY_STATUS status;
+    SecBuffer buf[4];
+    SecBufferDesc msg;
+    size_t i;
+    size_t n = 0;		/* initially no bytes to decrypt */
+    do {			/* yes, make sure have data from TCP */
+      if (stream->iextractr) {	/* have previous unread data? */
+	memcpy (stream->ibuf + n,stream->iextraptr,stream->iextractr);
+	n += stream->iextractr;	/* update number of bytes read */
+	stream->iextractr = 0;	/* no more extra data */
+      }
+      else {			/* read from TCP */
+	if (!tcp_getdata (stream->tcpstream)) return ssl_abort (stream);
+				/* maximum amount of data to copy */
+	if (!(i = min (stream->bufsize - n,stream->tcpstream->ictr)))
+	  fatal ("incomplete SecBuffer exceeds maximum buffer size");
+				/* do the copy */
+	memcpy (stream->ibuf + n,stream->tcpstream->iptr,i);
+	stream->tcpstream->iptr += i;
+	stream->tcpstream->ictr -= i;
+	n += i;			/* update number of bytes to decrypt */
+      }
+      buf[0].cbBuffer = n;	/* first SecBuffer gets data */
+      buf[0].pvBuffer = stream->ibuf;
+      buf[0].BufferType = SECBUFFER_DATA;
+				/* subsequent ones are for spares */
+      buf[1].BufferType = buf[2].BufferType = buf[3].BufferType =
+	SECBUFFER_EMPTY;
+      msg.ulVersion = SECBUFFER_VERSION;
+      msg.cBuffers = 4;		/* number of SecBuffers */
+      msg.pBuffers = buf;	/* first SecBuffer */
+
+    } while ((status = ((DECRYPT_MESSAGE_FN) sft->Reserved4)
+	      (&stream->context,&msg,0,NIL)) == SEC_E_INCOMPLETE_MESSAGE);
+    switch (status) {
+    case SEC_E_OK:		/* won */
+    case SEC_I_RENEGOTIATE:	/* won but lost it after this buffer */
+				/* hunt for a buffer */
+      for (i = 0; (i < 4) && (buf[i].BufferType != SECBUFFER_DATA) ; i++);
+      if (i < 4) {		/* found a buffer? */
+				/* yes, set up pointer and counter */
+	stream->iptr = buf[i].pvBuffer;
+	stream->ictr = buf[i].cbBuffer;
+				/* any unprocessed data? */
+	while (++i < 4) if (buf[i].BufferType == SECBUFFER_EXTRA) {
+				/* yes, note for next time around */
+	  stream->iextraptr = buf[i].pvBuffer;
+	  stream->iextractr = buf[i].cbBuffer;
+	}
+      }
+      break;
+    default:			/* anything else means we've lost */
+      return ssl_abort (stream);
+    }
+  }
+  return LONGT;
+}
+
+/* SSL send string as record
+ * Accepts: SSL stream
+ *	    string pointer
+ * Returns: T if success else NIL
+ */
+
+long ssl_soutr (SSLSTREAM *stream,char *string)
+{
+  return ssl_sout (stream,string,(unsigned long) strlen (string));
+}
+
+
+/* SSL send string
+ * Accepts: SSL stream
+ *	    string pointer
+ *	    byte count
+ * Returns: T if success else NIL
+ */
+
+long ssl_sout (SSLSTREAM *stream,char *string,unsigned long size)
+{
+  SecBuffer buf[4];
+  SecBufferDesc msg;
+  char *s = stream->ibuf;
+  size_t n = 0;
+  while (size) {		/* until satisfied request */
+				/* header */
+    buf[0].BufferType = SECBUFFER_STREAM_HEADER;
+    memset (buf[0].pvBuffer = stream->obuf,0,
+	    buf[0].cbBuffer = stream->sizes.cbHeader);
+				/* message (up to maximum size) */
+    buf[1].BufferType = SECBUFFER_DATA;
+    memcpy (buf[1].pvBuffer = stream->obuf + stream->sizes.cbHeader,string,
+	    buf[1].cbBuffer = min (size,SSLBUFLEN));
+				/* trailer */
+    buf[2].BufferType = SECBUFFER_STREAM_TRAILER;
+    memset (buf[2].pvBuffer = ((char *) buf[1].pvBuffer) + buf[1].cbBuffer,0,
+	    buf[2].cbBuffer = stream->sizes.cbTrailer);
+				/* spare */
+    buf[3].BufferType = SECBUFFER_EMPTY;
+    msg.ulVersion = SECBUFFER_VERSION;
+    msg.cBuffers = 4;		/* number of SecBuffers */
+    msg.pBuffers = buf;		/* first SecBuffer */
+    string += buf[1].cbBuffer;
+    size -= buf[1].cbBuffer;	/* this many bytes processed */
+				/* encrypt and send message */
+    if ((((ENCRYPT_MESSAGE_FN) sft->Reserved3)
+	 (&stream->context,0,&msg,NIL) != SEC_E_OK) ||
+	!tcp_sout (stream->tcpstream,stream->obuf,
+		   buf[0].cbBuffer + buf[1].cbBuffer + buf[2].cbBuffer))
+      return ssl_abort (stream);/* encryption or sending failed */
+  }
+  return LONGT;
+}
+
+/* SSL close
+ * Accepts: SSL stream
+ */
+
+void ssl_close (SSLSTREAM *stream)
+{
+  ssl_abort (stream);		/* nuke the stream */
+  fs_give ((void **) &stream);	/* flush the stream */
+}
+
+
+/* SSL abort stream
+ * Accepts: SSL stream
+ * Returns: NIL always
+ */
+
+static long ssl_abort (SSLSTREAM *stream)
+{
+  if (stream->tcpstream) {	/* close TCP stream */
+    sft->DeleteSecurityContext (&stream->context);
+    sft->FreeCredentialHandle (&stream->cred);
+    tcp_close (stream->tcpstream);
+    stream->tcpstream = NIL;
+  }
+  if (stream->ibuf) fs_give ((void **) &stream->ibuf);
+  if (stream->obuf) fs_give ((void **) &stream->obuf);
+  return NIL;
+}
+
+/* SSL get host name
+ * Accepts: SSL stream
+ * Returns: host name for this stream
+ */
+
+char *ssl_host (SSLSTREAM *stream)
+{
+  return tcp_host (stream->tcpstream);
+}
+
+
+/* SSL get remote host name
+ * Accepts: SSL stream
+ * Returns: host name for this stream
+ */
+
+char *ssl_remotehost (SSLSTREAM *stream)
+{
+  return tcp_remotehost (stream->tcpstream);
+}
+
+
+/* SSL return port for this stream
+ * Accepts: SSL stream
+ * Returns: port number for this stream
+ */
+
+unsigned long ssl_port (SSLSTREAM *stream)
+{
+  return tcp_port (stream->tcpstream);
+}
+
+
+/* SSL get local host name
+ * Accepts: SSL stream
+ * Returns: local host name
+ */
+
+char *ssl_localhost (SSLSTREAM *stream)
+{
+  return tcp_localhost (stream->tcpstream);
+}
+
+#include "ssl_none.c"		/* currently no server support */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/ssl_w2k.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,683 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	SSL authentication/encryption module for Windows 2000
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	22 September 1998
+ * Last Edited:	13 January 2008
+ */
+
+#define SECURITY_WIN32
+#include <sspi.h>
+#include <schannel.h>
+
+
+#define SSLBUFLEN 8192
+
+
+/* SSL I/O stream */
+
+typedef struct ssl_stream {
+  TCPSTREAM *tcpstream;		/* TCP stream */
+  CredHandle cred;		/* SSL credentials */
+  CtxtHandle context;		/* SSL context */
+				/* stream encryption sizes */
+  SecPkgContext_StreamSizes sizes;
+  size_t bufsize;
+  int ictr;			/* input counter */
+  char *iptr;			/* input pointer */
+  int iextractr;		/* extra input counter */
+  char *iextraptr;		/* extra input pointer */
+  char *ibuf;			/* input buffer */
+  char *obuf;			/* output buffer */
+} SSLSTREAM;
+
+#include "sslio.h"
+
+
+/* Function prototypes */
+
+static SSLSTREAM *ssl_start(TCPSTREAM *tstream,char *host,unsigned long flags);
+static char *ssl_analyze_status (SECURITY_STATUS err,char *buf);
+static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size,
+			       long *contd);
+static long ssl_abort (SSLSTREAM *stream);
+
+/* Secure Sockets Layer network driver dispatch */
+
+static struct ssl_driver ssldriver = {
+  ssl_open,			/* open connection */
+  ssl_aopen,			/* open preauthenticated connection */
+  ssl_getline,			/* get a line */
+  ssl_getbuffer,		/* get a buffer */
+  ssl_soutr,			/* output pushed data */
+  ssl_sout,			/* output string */
+  ssl_close,			/* close connection */
+  ssl_host,			/* return host name */
+  ssl_remotehost,		/* return remote host name */
+  ssl_port,			/* return port number */
+  ssl_localhost			/* return local host name */
+};
+
+static unsigned long ssltsz = 0;/* SSL maximum token length */
+
+/* One-time SSL initialization */
+
+static int sslonceonly = 0;
+
+void ssl_onceonlyinit (void)
+{
+  if (!sslonceonly++) {		/* only need to call it once */
+    ULONG np;
+    SecPkgInfo *pp;
+    int i;
+				/* get security library */
+    if (!EnumerateSecurityPackages (&np,&pp)) {
+				/* look for an SSL package */
+      for (i = 0; (i < (int) np); i++) if (!strcmp (pp[i].Name,UNISP_NAME)) {
+				/* note maximum token size and name */
+	ssltsz = pp[i].cbMaxToken;
+				/* apply runtime linkage */
+	mail_parameters (NIL,SET_SSLDRIVER,(void *) &ssldriver);
+	mail_parameters (NIL,SET_SSLSTART,(void *) ssl_start);
+	return;			/* all done */
+      }
+    }
+  }
+}
+
+/* SSL open
+ * Accepts: host name
+ *	    contact service name
+ *	    contact port number
+ * Returns: SSL stream if success else NIL
+ */
+
+SSLSTREAM *ssl_open (char *host,char *service,unsigned long port)
+{
+  TCPSTREAM *stream = tcp_open (host,service,port);
+  return stream ? ssl_start (stream,host,port) : NIL;
+}
+
+  
+/* SSL authenticated open
+ * Accepts: host name
+ *	    service name
+ *	    returned user name buffer
+ * Returns: SSL stream if success else NIL
+ */
+
+SSLSTREAM *ssl_aopen (NETMBX *mb,char *service,char *usrbuf)
+{
+  return NIL;			/* don't use this mechanism with SSL */
+}
+
+/* Start SSL/TLS negotiations
+ * Accepts: open TCP stream of session
+ *	    user's host name
+ *	    flags
+ * Returns: SSL stream if success else NIL
+ */
+
+static SSLSTREAM *ssl_start (TCPSTREAM *tstream,char *host,unsigned long flags)
+{
+  SECURITY_STATUS e;
+  ULONG a;
+  TimeStamp t;
+  SecBuffer ibuf[2],obuf[1];
+  SecBufferDesc ibufs,obufs;
+  SCHANNEL_CRED tlscred;
+  CERT_CONTEXT *cert = NIL;
+  CERT_CHAIN_PARA chparam;
+  CERT_CHAIN_CONTEXT *chain;
+  SSL_EXTRA_CERT_CHAIN_POLICY_PARA policy;
+  CERT_CHAIN_POLICY_PARA polparam;
+  CERT_CHAIN_POLICY_STATUS status;
+  char tmp[MAILTMPLEN],certname[256];
+  char *reason = NIL;
+  ULONG req = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT |
+    ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY |
+      ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM | ISC_REQ_EXTENDED_ERROR |
+	ISC_REQ_MANUAL_CRED_VALIDATION;
+  LPSTR usage[] = {
+    szOID_PKIX_KP_SERVER_AUTH,
+    szOID_SERVER_GATED_CRYPTO,
+    szOID_SGC_NETSCAPE
+  };
+  PWSTR whost = NIL;
+  char *buf = (char *) fs_get (ssltsz);
+  unsigned long size = 0;
+  sslcertificatequery_t scq =
+    (sslcertificatequery_t) mail_parameters (NIL,GET_SSLCERTIFICATEQUERY,NIL);
+  sslfailure_t sf = (sslfailure_t) mail_parameters (NIL,GET_SSLFAILURE,NIL);
+  SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
+					    sizeof (SSLSTREAM));
+  stream->tcpstream = tstream;	/* bind TCP stream */
+				/* initialize TLS credential */
+  memset (&tlscred,0,sizeof (SCHANNEL_CRED));
+  tlscred.dwVersion = SCHANNEL_CRED_VERSION;
+  tlscred.grbitEnabledProtocols = SP_PROT_TLS1;
+
+				/* acquire credentials */
+  if (AcquireCredentialsHandle
+      (NIL,UNISP_NAME,SECPKG_CRED_OUTBOUND,NIL,(flags & NET_TLSCLIENT) ?
+       &tlscred : NIL,NIL,NIL,&stream->cred,&t)
+      != SEC_E_OK) reason = "Acquire credentials handle failed";
+  else while (!reason) {	/* negotiate security context */
+				/* initialize buffers */
+    ibuf[0].cbBuffer = size; ibuf[0].pvBuffer = buf;
+    ibuf[1].cbBuffer = 0; ibuf[1].pvBuffer = NIL;
+    obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NIL;
+    ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN;
+    ibuf[1].BufferType = SECBUFFER_EMPTY;
+				/* initialize buffer descriptors */
+    ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION;
+    ibufs.cBuffers = 2; obufs.cBuffers = 1;
+    ibufs.pBuffers = ibuf; obufs.pBuffers = obuf;
+				/* negotiate security */
+    e = InitializeSecurityContext
+      (&stream->cred,size ? &stream->context : NIL,host,req,0,
+       SECURITY_NETWORK_DREP,size? &ibufs:NIL,0,&stream->context,&obufs,&a,&t);
+				/* have an output buffer we need to send? */
+    if (obuf[0].pvBuffer && obuf[0].cbBuffer) {
+      if (!tcp_sout (stream->tcpstream,obuf[0].pvBuffer,obuf[0].cbBuffer))
+	reason = "Unexpected TCP output disconnect";
+				/* free the buffer */
+      FreeContextBuffer (obuf[0].pvBuffer);
+    }
+    if (!reason) switch (e) {	/* negotiation state */
+    case SEC_I_INCOMPLETE_CREDENTIALS:
+      break;			/* server wants client auth */
+    case SEC_I_CONTINUE_NEEDED:
+      if (size) {		/* continue, read any data? */
+				/* yes, anything regurgiated back to us? */
+	if (ibuf[1].BufferType == SECBUFFER_EXTRA) {
+				/* yes, set this as the new data */
+	  memmove (buf,buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer);
+	  size = ibuf[1].cbBuffer;
+	  break;
+	}
+	size = 0;		/* otherwise, read more stuff from server */
+      }
+    case SEC_E_INCOMPLETE_MESSAGE:
+				/* need to read more data from server */
+      if (!tcp_getdata (stream->tcpstream))
+	reason = "Unexpected TCP input disconnect";
+      else {
+	memcpy (buf+size,stream->tcpstream->iptr,stream->tcpstream->ictr);
+	size += stream->tcpstream->ictr;
+				/* empty it from TCP's buffers */
+	stream->tcpstream->iptr += stream->tcpstream->ictr;
+	stream->tcpstream->ictr = 0;
+      }
+      break;
+
+    case SEC_E_OK:		/* success, any data to be regurgitated? */
+      if (ibuf[1].BufferType == SECBUFFER_EXTRA) {
+				/* yes, set this as the new data */
+	memmove (stream->tcpstream->iptr = stream->tcpstream->ibuf,
+		 buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer);
+	stream->tcpstream->ictr = ibuf[1].cbBuffer;
+      }
+      if (!(flags & NET_NOVALIDATECERT)) {
+				/* need validation, make wchar of host */
+	if (!((size = MultiByteToWideChar (CP_ACP,0,host,-1,NIL,0)) &&
+	      (whost = (PWSTR) fs_get (size*sizeof (WCHAR))) &&
+	      MultiByteToWideChar (CP_ACP,0,host,-1,whost,size)))
+	  fatal ("Can't make wchar of host name!");
+				/* get certificate */
+	if ((QueryContextAttributes
+	     (&stream->context,SECPKG_ATTR_REMOTE_CERT_CONTEXT,&cert) !=
+	     SEC_E_OK) || !cert) {
+	  reason = "*Unable to get certificate";
+	  strcpy (certname,"<no certificate>");
+	}
+	else {			/* get certificate subject name */
+	  CertNameToStr (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+			 &cert->pCertInfo->Subject,CERT_X500_NAME_STR,
+			 certname,255);
+				/* build certificate chain */
+	  memset (&chparam,0,sizeof (chparam));
+	  chparam.cbSize = sizeof (chparam);
+	  chparam.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
+	  chparam.RequestedUsage.Usage.rgpszUsageIdentifier = usage;
+	  chparam.RequestedUsage.Usage.cUsageIdentifier =
+	    sizeof (usage) / sizeof (LPSTR);
+	  if (!CertGetCertificateChain
+	      (NIL,cert,NIL,cert->hCertStore,&chparam,NIL,NIL,&chain))
+	    reason = ssl_analyze_status (GetLastError (),tmp);
+	  else {		/* validate certificate chain */
+	    memset (&policy,0,sizeof (SSL_EXTRA_CERT_CHAIN_POLICY_PARA));
+	    policy.cbStruct = sizeof (SSL_EXTRA_CERT_CHAIN_POLICY_PARA);
+	    policy.dwAuthType = AUTHTYPE_SERVER;
+	    policy.fdwChecks = NIL;
+	    policy.pwszServerName = whost;
+	    memset (&polparam,0,sizeof (polparam));
+	    polparam.cbSize = sizeof (polparam);
+	    polparam.pvExtraPolicyPara = &policy;
+	    memset (&status,0,sizeof (status));
+	    status.cbSize = sizeof (status);
+	    if (!CertVerifyCertificateChainPolicy
+		(CERT_CHAIN_POLICY_SSL,chain,&polparam,&status))
+	      reason = ssl_analyze_status (GetLastError (),tmp);
+	    else if (status.dwError)
+	      reason = ssl_analyze_status (status.dwError,tmp);
+	    CertFreeCertificateChain (chain);
+	  }
+	  CertFreeCertificateContext (cert);
+	}
+	if (whost) fs_give ((void **) &whost);
+
+	if (reason) {		/* got an error? */
+				/* application callback */
+	  if (scq) reason = (*scq) ((*reason == '*') ? reason + 1 : reason,
+				    host,certname) ? NIL : "";
+	  else if (*certname) {	/* error message to return via mm_log() */
+	    sprintf (buf,"*%.128s: %.255s",
+		     (*reason == '*') ? reason + 1 : reason,certname);
+	    reason = buf;
+	  }
+	}
+      }
+      if (reason ||
+	  (reason = ssl_analyze_status
+	   (QueryContextAttributes
+	    (&stream->context,SECPKG_ATTR_STREAM_SIZES,&stream->sizes),buf)))
+	break;			/* error in certificate or getting sizes */
+      fs_give ((void **) &buf);	/* flush temporary buffer */
+				/* make maximum-sized buffers */
+      stream->bufsize = stream->sizes.cbHeader +
+	stream->sizes.cbMaximumMessage + stream->sizes.cbTrailer;
+      if (stream->sizes.cbMaximumMessage < SSLBUFLEN)
+	fatal ("cbMaximumMessage is less than SSLBUFLEN!");
+      else if (stream->sizes.cbMaximumMessage < 16384) {
+	sprintf (tmp,"WINDOWS BUG: cbMaximumMessage = %ld, should be 16384",
+		 (long) stream->sizes.cbMaximumMessage);
+	mm_log (tmp,NIL);
+      }
+      stream->ibuf = (char *) fs_get (stream->bufsize);
+      stream->obuf = (char *) fs_get (stream->bufsize);
+      return stream;
+    default:
+      reason = ssl_analyze_status (e,buf);
+    }
+  }
+  ssl_close (stream);		/* failed to do SSL */
+  stream = NIL;			/* no stream returned */
+  switch (*reason) {		/* analyze reason */
+  case '*':			/* certificate failure */
+    ++reason;			/* skip over certificate failure indication */
+				/* pass to error callback */
+    if (sf) (*sf) (host,reason,flags);
+    else {			/* no error callback, build error message */
+      sprintf (tmp,"Certificate failure for %.80s: %.512s",host,reason);
+      mm_log (tmp,ERROR);
+    }
+  case '\0':			/* user answered no to certificate callback */
+    if (flags & NET_TRYSSL)	/* return dummy stream to stop tryssl */
+      stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
+				     sizeof (SSLSTREAM));
+    break;
+  default:			/* non-certificate failure */
+    if (flags & NET_TRYSSL);	/* no error output if tryssl */
+				/* pass to error callback */
+    else if (sf) (*sf) (host,reason,flags);
+    else {			/* no error callback, build error message */
+      sprintf (tmp,"TLS/SSL failure for %.80s: %.512s",host,reason);
+      mm_log (tmp,ERROR);
+    }
+    break;
+  }
+  fs_give ((void **) &buf);	/* flush temporary buffer */
+  return stream;
+}
+
+/* Generate error text from SSL error code
+ * Accepts: SSL status
+ *	    scratch buffer
+ * Returns: text if error status, else NIL
+ */
+
+static char *ssl_analyze_status (SECURITY_STATUS err,char *buf)
+{
+  switch (err) {
+  case SEC_E_OK:		/* no error */
+  case SEC_I_CONTINUE_NEEDED:
+  case SEC_I_INCOMPLETE_CREDENTIALS:
+  case SEC_E_INCOMPLETE_MESSAGE:
+    return NIL;
+  case SEC_E_NO_AUTHENTICATING_AUTHORITY:
+    mm_log ("unexpected SEC_E_NO_AUTHENTICATING_AUTHORITY",NIL);
+    return "*No authority could be contacted for authentication";
+  case SEC_E_WRONG_PRINCIPAL:
+    mm_log ("unexpected SEC_E_WRONG_PRINCIPAL",NIL);
+  case CERT_E_CN_NO_MATCH:
+    return "*Server name does not match certificate";
+  case SEC_E_UNTRUSTED_ROOT:
+    mm_log ("unexpected SEC_E_UNTRUSTED_ROOT",NIL);
+  case CERT_E_UNTRUSTEDROOT:
+    return "*Self-signed certificate or untrusted authority";
+  case SEC_E_CERT_EXPIRED:
+    mm_log ("unexpected SEC_E_CERT_EXPIRED",NIL);
+  case CERT_E_EXPIRED:
+    return "*Certificate has expired";
+  case CERT_E_REVOKED:
+    return "*Certificate revoked";
+  case SEC_E_INVALID_TOKEN:
+    return "Invalid token, probably not an SSL server";
+  case SEC_E_UNSUPPORTED_FUNCTION:
+    return "SSL not supported on this machine - upgrade your system software";
+  }
+  sprintf (buf,"Unexpected SSPI or certificate error %lx - report this",err);
+  return buf;
+}
+
+/* SSL receive line
+ * Accepts: SSL stream
+ * Returns: text line string or NIL if failure
+ */
+
+char *ssl_getline (SSLSTREAM *stream)
+{
+  unsigned long n,contd;
+  char *ret = ssl_getline_work (stream,&n,&contd);
+  if (ret && contd) {		/* got a line needing continuation? */
+    STRINGLIST *stl = mail_newstringlist ();
+    STRINGLIST *stc = stl;
+    do {			/* collect additional lines */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+      stc = stc->next = mail_newstringlist ();
+      ret = ssl_getline_work (stream,&n,&contd);
+    } while (ret && contd);
+    if (ret) {			/* stash final part of line on list */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+				/* determine how large a buffer we need */
+      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
+      ret = fs_get (n + 1);	/* copy parts into buffer */
+      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
+	memcpy (ret + n,stc->text.data,stc->text.size);
+      ret[n] = '\0';
+    }
+    mail_free_stringlist (&stl);/* either way, done with list */
+  }
+  return ret;
+}
+
+/* SSL receive line or partial line
+ * Accepts: SSL stream
+ *	    pointer to return size
+ *	    pointer to return continuation flag
+ * Returns: text line string, size and continuation flag, or NIL if failure
+ */
+
+static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size,
+			       long *contd)
+{
+  unsigned long n;
+  char *s,*ret,c,d;
+  *contd = NIL;			/* assume no continuation */
+				/* make sure have data */
+  if (!ssl_getdata (stream)) return NIL;
+  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
+    d = *stream->iptr++;	/* slurp another character */
+    if ((c == '\015') && (d == '\012')) {
+      ret = (char *) fs_get (n--);
+      memcpy (ret,s,*size = n);	/* copy into a free storage string */
+      ret[n] = '\0';		/* tie off string with null */
+      return ret;
+    }
+  }
+				/* copy partial string from buffer */
+  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
+				/* get more data from the net */
+  if (!ssl_getdata (stream)) fs_give ((void **) &ret);
+				/* special case of newline broken by buffer */
+  else if ((c == '\015') && (*stream->iptr == '\012')) {
+    stream->iptr++;		/* eat the line feed */
+    stream->ictr--;
+    ret[*size = --n] = '\0';	/* tie off string with null */
+  }
+  else *contd = LONGT;		/* continuation needed */
+  return ret;
+}
+
+/* SSL receive buffer
+ * Accepts: SSL stream
+ *	    size in bytes
+ *	    buffer to read into
+ * Returns: T if success, NIL otherwise
+ */
+
+long ssl_getbuffer (SSLSTREAM *stream,unsigned long size,char *buffer)
+{
+  unsigned long n;
+  while (size > 0) {		/* until request satisfied */
+    if (!ssl_getdata (stream)) return NIL;
+    n = min (size,stream->ictr);/* number of bytes to transfer */
+				/* do the copy */
+    memcpy (buffer,stream->iptr,n);
+    buffer += n;		/* update pointer */
+    stream->iptr += n;
+    size -= n;			/* update # of bytes to do */
+    stream->ictr -= n;
+  }
+  buffer[0] = '\0';		/* tie off string */
+  return T;
+}
+
+/* SSL receive data
+ * Accepts: TCP/IP stream
+ * Returns: T if success, NIL otherwise
+ */
+
+long ssl_getdata (SSLSTREAM *stream)
+{
+  while (stream->ictr < 1) {	/* decrypted buffer empty? */
+    SECURITY_STATUS status;
+    SecBuffer buf[4];
+    SecBufferDesc msg;
+    size_t i;
+    size_t n = 0;		/* initially no bytes to decrypt */
+    do {			/* yes, make sure have data from TCP */
+      if (stream->iextractr) {	/* have previous unread data? */
+	memcpy (stream->ibuf + n,stream->iextraptr,stream->iextractr);
+	n += stream->iextractr;	/* update number of bytes read */
+	stream->iextractr = 0;	/* no more extra data */
+      }
+      else {			/* read from TCP */
+	if (!tcp_getdata (stream->tcpstream)) return ssl_abort (stream);
+				/* maximum amount of data to copy */
+	if (!(i = min (stream->bufsize - n,stream->tcpstream->ictr)))
+	  fatal ("incomplete SecBuffer exceeds maximum buffer size");
+				/* do the copy */
+	memcpy (stream->ibuf + n,stream->tcpstream->iptr,i);
+	stream->tcpstream->iptr += i;
+	stream->tcpstream->ictr -= i;
+	n += i;			/* update number of bytes to decrypt */
+      }
+      buf[0].cbBuffer = n;	/* first SecBuffer gets data */
+      buf[0].pvBuffer = stream->ibuf;
+      buf[0].BufferType = SECBUFFER_DATA;
+				/* subsequent ones are for spares */
+      buf[1].BufferType = buf[2].BufferType = buf[3].BufferType =
+	SECBUFFER_EMPTY;
+      msg.ulVersion = SECBUFFER_VERSION;
+      msg.cBuffers = 4;		/* number of SecBuffers */
+      msg.pBuffers = buf;	/* first SecBuffer */
+    } while ((status = DecryptMessage
+	      (&stream->context,&msg,0,NIL)) == SEC_E_INCOMPLETE_MESSAGE);
+    switch (status) {
+    case SEC_E_OK:		/* won */
+    case SEC_I_RENEGOTIATE:	/* won but lost it after this buffer */
+				/* hunt for a buffer */
+      for (i = 0; (i < 4) && (buf[i].BufferType != SECBUFFER_DATA) ; i++);
+      if (i < 4) {		/* found a buffer? */
+				/* yes, set up pointer and counter */
+	stream->iptr = buf[i].pvBuffer;
+	stream->ictr = buf[i].cbBuffer;
+				/* any unprocessed data? */
+	while (++i < 4) if (buf[i].BufferType == SECBUFFER_EXTRA) {
+				/* yes, note for next time around */
+	  stream->iextraptr = buf[i].pvBuffer;
+	  stream->iextractr = buf[i].cbBuffer;
+	}
+      }
+      break;
+    default:			/* anything else means we've lost */
+      return ssl_abort (stream);
+    }
+  }
+  return LONGT;
+}
+
+/* SSL send string as record
+ * Accepts: SSL stream
+ *	    string pointer
+ * Returns: T if success else NIL
+ */
+
+long ssl_soutr (SSLSTREAM *stream,char *string)
+{
+  return ssl_sout (stream,string,(unsigned long) strlen (string));
+}
+
+
+/* SSL send string
+ * Accepts: SSL stream
+ *	    string pointer
+ *	    byte count
+ * Returns: T if success else NIL
+ */
+
+long ssl_sout (SSLSTREAM *stream,char *string,unsigned long size)
+{
+  SecBuffer buf[4];
+  SecBufferDesc msg;
+  char *s;
+  size_t n;
+  if (!stream->tcpstream) return NIL;
+				/* until request satisfied */
+  for (s = stream->ibuf,n = 0; size;) {
+				/* header */
+    buf[0].BufferType = SECBUFFER_STREAM_HEADER;
+    memset (buf[0].pvBuffer = stream->obuf,0,
+	    buf[0].cbBuffer = stream->sizes.cbHeader);
+				/* message (up to maximum size) */
+    buf[1].BufferType = SECBUFFER_DATA;
+    memcpy (buf[1].pvBuffer = stream->obuf + stream->sizes.cbHeader,string,
+	    buf[1].cbBuffer = min (size,SSLBUFLEN));
+				/* trailer */
+    buf[2].BufferType = SECBUFFER_STREAM_TRAILER;
+    memset (buf[2].pvBuffer = ((char *) buf[1].pvBuffer) + buf[1].cbBuffer,0,
+	    buf[2].cbBuffer = stream->sizes.cbTrailer);
+				/* spare */
+    buf[3].BufferType = SECBUFFER_EMPTY;
+    msg.ulVersion = SECBUFFER_VERSION;
+    msg.cBuffers = 4;		/* number of SecBuffers */
+    msg.pBuffers = buf;		/* first SecBuffer */
+    string += buf[1].cbBuffer;
+    size -= buf[1].cbBuffer;	/* this many bytes processed */
+				/* encrypt and send message */
+    if ((EncryptMessage
+	 (&stream->context,0,&msg,NIL) != SEC_E_OK) ||
+	!tcp_sout (stream->tcpstream,stream->obuf,
+		   buf[0].cbBuffer + buf[1].cbBuffer + buf[2].cbBuffer))
+      return ssl_abort (stream);/* encryption or sending failed */
+  }
+  return LONGT;
+}
+
+/* SSL close
+ * Accepts: SSL stream
+ */
+
+void ssl_close (SSLSTREAM *stream)
+{
+  ssl_abort (stream);		/* nuke the stream */
+  fs_give ((void **) &stream);	/* flush the stream */
+}
+
+
+/* SSL abort stream
+ * Accepts: SSL stream
+ * Returns: NIL always
+ */
+
+static long ssl_abort (SSLSTREAM *stream)
+{
+  if (stream->tcpstream) {	/* close TCP stream */
+    DeleteSecurityContext (&stream->context);
+    FreeCredentialHandle (&stream->cred);
+    tcp_close (stream->tcpstream);
+    stream->tcpstream = NIL;
+  }
+  if (stream->ibuf) fs_give ((void **) &stream->ibuf);
+  if (stream->obuf) fs_give ((void **) &stream->obuf);
+  return NIL;
+}
+
+/* SSL get host name
+ * Accepts: SSL stream
+ * Returns: host name for this stream
+ */
+
+char *ssl_host (SSLSTREAM *stream)
+{
+  return tcp_host (stream->tcpstream);
+}
+
+
+/* SSL get remote host name
+ * Accepts: SSL stream
+ * Returns: host name for this stream
+ */
+
+char *ssl_remotehost (SSLSTREAM *stream)
+{
+  return tcp_remotehost (stream->tcpstream);
+}
+
+
+/* SSL return port for this stream
+ * Accepts: SSL stream
+ * Returns: port number for this stream
+ */
+
+unsigned long ssl_port (SSLSTREAM *stream)
+{
+  return tcp_port (stream->tcpstream);
+}
+
+
+/* SSL get local host name
+ * Accepts: SSL stream
+ * Returns: local host name
+ */
+
+char *ssl_localhost (SSLSTREAM *stream)
+{
+  return tcp_localhost (stream->tcpstream);
+}
+
+#include "ssl_none.c"		/* currently no server support */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/tcp_nt.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,912 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Winsock TCP/IP routines
+ *
+ * Author:	Mark Crispin from Mike Seibel's Winsock code
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 April 1989
+ * Last Edited: 13 January 2007
+ */
+
+#include "ip_nt.c"
+
+
+#define TCPMAXSEND 32768
+
+/* Private functions */
+
+int tcp_socket_open (int family,void *adr,size_t adrlen,unsigned short port,
+		     char *tmp,char *hst);
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+			       long *contd);
+long tcp_abort (TCPSTREAM *stream);
+long tcp_close_socket (SOCKET *sock);
+char *tcp_name (struct sockaddr *sadr,long flag);
+char *tcp_name_valid (char *s);
+
+
+/* Private data */
+
+int wsa_initted = 0;		/* init ? */
+static int wsa_sock_open = 0;	/* keep track of open sockets */
+static tcptimeout_t tmoh = NIL;	/* TCP timeout handler routine */
+static long ttmo_open = 0;	/* TCP timeouts, in seconds */
+static long ttmo_read = 0;
+static long ttmo_write = 0;
+static long allowreversedns = T;/* allow reverse DNS lookup */
+static long tcpdebug = NIL;	/* extra TCP debugging telemetry */
+static char *myClientAddr = NIL;/* client host address */
+static char *myClientHost = NIL;/* client host name */
+static long myClientPort = -1;	/* client port */
+static char *myServerAddr = NIL;/* server host address */
+static char *myServerHost = NIL;/* server host name */
+static long myServerPort = -1;	/* server port */
+
+extern long maxposint;		/* get this from write.c */
+
+/* TCP/IP manipulate parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *tcp_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case SET_TIMEOUT:
+    tmoh = (tcptimeout_t) value;
+  case GET_TIMEOUT:
+    ret = (void *) tmoh;
+    break;
+  case SET_OPENTIMEOUT:
+    ttmo_open = (long) value ? (long) value : (long) WSA_INFINITE;
+  case GET_OPENTIMEOUT:
+    ret = (void *) ttmo_open;
+    break;
+  case SET_READTIMEOUT:
+    ttmo_read = (long) value;
+  case GET_READTIMEOUT:
+    ret = (void *) ttmo_read;
+    break;
+  case SET_WRITETIMEOUT:
+    ttmo_write = (long) value;
+  case GET_WRITETIMEOUT:
+    ret = (void *) ttmo_write;
+    break;
+  case SET_ALLOWREVERSEDNS:
+    allowreversedns = (long) value;
+  case GET_ALLOWREVERSEDNS:
+    ret = (void *) allowreversedns;
+    break;
+  case SET_TCPDEBUG:
+    tcpdebug = (long) value;
+  case GET_TCPDEBUG:
+    ret = (void *) tcpdebug;
+    break;
+  }
+  return ret;
+}
+
+/* TCP/IP open
+ * Accepts: host name
+ *	    contact service name
+ *	    contact port number and optional silent flag
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
+{
+  TCPSTREAM *stream = NIL;
+  int i,family;
+  SOCKET sock = INVALID_SOCKET;
+  int silent = (port & NET_SILENT) ? T : NIL;
+  char *s,*hostname,tmp[MAILTMPLEN];
+  void *adr,*next;
+  size_t adrlen;
+  struct servent *sv = NIL;
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  if (!wsa_initted++) {		/* init Windows Sockets */
+    WSADATA wsock;
+    if (i = (int) WSAStartup (WINSOCK_VERSION,&wsock)) {
+      wsa_initted = 0;		/* in case we try again */
+      sprintf (tmp,"Unable to start Windows Sockets (%d)",i);
+      mm_log (tmp,ERROR);
+      return NIL;
+    }
+  }
+  port &= 0xffff;		/* erase flags */
+				/* lookup service */
+  if (service && (sv = getservbyname (service,"tcp")))
+    port = ntohs (sv->s_port);
+  /* The domain literal form is used (rather than simply the dotted decimal
+     as with other Windows programs) because it has to be a valid "host name"
+     in mailsystem terminology. */
+				/* look like domain literal? */
+  if (host[0] == '[' && host[(strlen (host))-1] == ']') {
+    strcpy (tmp,host+1);	/* yes, copy number part */
+    tmp[strlen (tmp)-1] = '\0';
+    if (adr = ip_stringtoaddr (tmp,&adrlen,&family)) {
+      (*bn) (BLOCK_TCPOPEN,NIL);
+      sock = tcp_socket_open (family,adr,adrlen,(unsigned short) port,tmp,
+			      hostname = host);
+      (*bn) (BLOCK_NONE,NIL);
+      fs_give ((void **) &adr);
+    }
+    else sprintf (tmp,"Bad format domain-literal: %.80s",host);
+  }
+
+  else {			/* lookup host name */
+    if (tcpdebug) {
+      sprintf (tmp,"DNS resolution %.80s",host);
+      mm_log (tmp,TCPDEBUG);
+    }
+    (*bn) (BLOCK_DNSLOOKUP,NIL);/* look up name */
+    if (!(s = ip_nametoaddr (host,&adrlen,&family,&hostname,&next)))
+      sprintf (tmp,"Host not found (#%d): %s",WSAGetLastError (),host);
+    (*bn) (BLOCK_NONE,NIL);
+    if (s) {			/* DNS resolution won? */
+      if (tcpdebug) mm_log ("DNS resolution done",TCPDEBUG);
+      wsa_sock_open++;		/* prevent tcp_close_socket() from freeing in
+				   loop */
+      do {
+	(*bn) (BLOCK_TCPOPEN,NIL);
+	if (((sock = tcp_socket_open (family,s,adrlen,(unsigned short) port,
+				      tmp,hostname)) == INVALID_SOCKET) &&
+	    (s = ip_nametoaddr (NIL,&adrlen,&family,&hostname,&next)) &&
+	    !silent) mm_log (tmp,WARN);
+	(*bn) (BLOCK_NONE,NIL);
+      } while ((sock == INVALID_SOCKET) && s);
+      wsa_sock_open--;		/* undo protection */
+    }
+  }
+  if (sock == INVALID_SOCKET) {	/* do possible cleanup action */
+    if (!silent) mm_log (tmp,ERROR);
+    tcp_close_socket (&sock);	
+  }
+  else {			/* got a socket, create TCP/IP stream */
+    stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0,
+				   sizeof (TCPSTREAM));
+    stream->port = port;	/* port number */
+				/* init socket */
+    stream->tcpsi = stream->tcpso = sock;
+    stream->ictr = 0;		/* init input counter */
+				/* copy official host name */
+    stream->host = cpystr (hostname);
+    if (tcpdebug) mm_log ("Stream open and ready for read",TCPDEBUG);
+  }
+  return stream;		/* return success */
+}
+
+/* Open a TCP socket
+ * Accepts: protocol family
+ *	    address to connect to
+ *	    address length
+ *	    port
+ *	    scratch buffer
+ *	    host name
+ * Returns: socket if success, else SOCKET_ERROR with error string in scratch
+ */
+
+int tcp_socket_open (int family,void *adr,size_t adrlen,unsigned short port,
+		     char *tmp,char *hst)
+{
+  int sock,err;
+  char *s,errmsg[100];
+  size_t len;
+  DWORD eo;
+  WSAEVENT event;
+  WSANETWORKEVENTS events;
+  unsigned long cmd = 0;
+  struct protoent *pt = getprotobyname ("tcp");
+  struct sockaddr *sadr = ip_sockaddr (family,adr,adrlen,port,&len);
+  sprintf (tmp,"Trying IP address [%s]",ip_sockaddrtostring (sadr));
+  mm_log (tmp,NIL);
+				/* get a TCP stream */
+  if ((sock = socket (sadr->sa_family,SOCK_STREAM,pt ? pt->p_proto : 0)) ==
+      INVALID_SOCKET)
+    sprintf (tmp,"Unable to create TCP socket (%d)",WSAGetLastError ());
+  else {
+    /* On Windows, FD_SETSIZE is the number of descriptors which can be
+     * held in an fd_set, as opposed to the maximum descriptor value on UNIX.
+     * Similarly, an fd_set in Windows is a vector of descriptor values, as
+     * opposed to a bitmask of set fds on UNIX.  Thus, an fd_set can hold up
+     * to FD_SETSIZE values which can be larger than FD_SETSIZE, and the test
+     * that is used on UNIX is unnecessary here.
+     */
+    wsa_sock_open++;		/* count this socket as open */
+				/* set socket nonblocking */
+    if (ttmo_open) WSAEventSelect (sock,event = WSACreateEvent (),FD_CONNECT);
+    else event = 0;		/* no event */
+				/* open connection */
+    err = (connect (sock,sadr,len) == SOCKET_ERROR) ? WSAGetLastError () : NIL;
+				/* if timer in effect, wait for event */
+    if (event) while (err == WSAEWOULDBLOCK)
+      switch (eo = WSAWaitForMultipleEvents (1,&event,T,ttmo_open*1000,NIL)) {
+      case WSA_WAIT_EVENT_0:	/* got an event? */
+	err = (WSAEnumNetworkEvents (sock,event,&events) == SOCKET_ERROR) ?
+	  WSAGetLastError () : events.iErrorCode[FD_CONNECT_BIT];
+	break;
+      case WSA_WAIT_IO_COMPLETION:
+	break;			/* fAlertable is NIL so shouldn't happen */
+      default:			/* all other conditions */
+	err = eo;		/* error from WSAWaitForMultipleEvents() */
+	break;
+      }
+
+    switch (err) {		/* analyze result from connect and wait */
+    case 0:			/* got a connection */
+      s = NIL;
+      if (event) {		/* unset blocking mode */
+	WSAEventSelect (sock,event,NIL);
+	if (ioctlsocket (sock,FIONBIO,&cmd) == SOCKET_ERROR)
+	  sprintf (s = errmsg,"Can't set blocking mode (%d)",
+		   WSAGetLastError ());
+      }
+      break;
+    case WSAECONNREFUSED:
+      s = "Refused";
+      break;
+    case WSAENOBUFS:
+      s = "Insufficient system resources";
+      break;
+    case WSA_WAIT_TIMEOUT: case WSAETIMEDOUT:
+      s = "Timed out";
+      break;
+    case WSAEHOSTUNREACH:
+      s = "Host unreachable";
+      break;
+    default:			/* horrible error 69 */
+      sprintf (s = errmsg,"Unknown error (%d)",err);
+      break;
+    }
+				/* flush event */
+    if (event) WSACloseEvent (event);
+    if (s) {			/* got an error? */
+      sprintf (tmp,"Can't connect to %.80s,%ld: %.80s",hst,port,s);
+      tcp_close_socket (&sock);	/* flush socket */
+      sock = INVALID_SOCKET;
+    }
+  }
+  fs_give ((void **) &sadr);	/* and socket address */
+  return sock;			/* return the socket */
+}
+  
+/* TCP/IP authenticated open
+ * Accepts: NETMBX specifier
+ *	    service name
+ *	    returned user name buffer
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
+{
+  return NIL;			/* always NIL on Windows */
+}
+
+/* TCP receive line
+ * Accepts: TCP stream
+ * Returns: text line string or NIL if failure
+ */
+
+char *tcp_getline (TCPSTREAM *stream)
+{
+  unsigned long n,contd;
+  char *ret = tcp_getline_work (stream,&n,&contd);
+  if (ret && contd) {		/* got a line needing continuation? */
+    STRINGLIST *stl = mail_newstringlist ();
+    STRINGLIST *stc = stl;
+    do {			/* collect additional lines */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+      stc = stc->next = mail_newstringlist ();
+      ret = tcp_getline_work (stream,&n,&contd);
+    } while (ret && contd);
+    if (ret) {			/* stash final part of line on list */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+				/* determine how large a buffer we need */
+      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
+      ret = fs_get (n + 1);	/* copy parts into buffer */
+      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
+	memcpy (ret + n,stc->text.data,stc->text.size);
+      ret[n] = '\0';
+    }
+    mail_free_stringlist (&stl);/* either way, done with list */
+  }
+  return ret;
+}
+
+/* TCP receive line or partial line
+ * Accepts: TCP stream
+ *	    pointer to return size
+ *	    pointer to return continuation flag
+ * Returns: text line string, size and continuation flag, or NIL if failure
+ */
+
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+			       long *contd)
+{
+  unsigned long n;
+  char *s,*ret,c,d;
+  *contd = NIL;			/* assume no continuation */
+				/* make sure have data */
+  if (!tcp_getdata (stream)) return NIL;
+  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
+    d = *stream->iptr++;	/* slurp another character */
+    if ((c == '\015') && (d == '\012')) {
+      ret = (char *) fs_get (n--);
+      memcpy (ret,s,*size = n);	/* copy into a free storage string */
+      ret[n] = '\0';		/* tie off string with null */
+      return ret;
+    }
+  }
+				/* copy partial string from buffer */
+  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
+				/* get more data from the net */
+  if (!tcp_getdata (stream)) fs_give ((void **) &ret);
+				/* special case of newline broken by buffer */
+  else if ((c == '\015') && (*stream->iptr == '\012')) {
+    stream->iptr++;		/* eat the line feed */
+    stream->ictr--;
+    ret[*size = --n] = '\0';	/* tie off string with null */
+  }
+  else *contd = LONGT;		/* continuation needed */
+  return ret;
+}
+
+/* TCP/IP receive buffer
+ * Accepts: TCP/IP stream
+ *	    size in bytes
+ *	    buffer to read into
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *s)
+{
+  unsigned long n;
+				/* make sure socket still alive */
+  if (stream->tcpsi == INVALID_SOCKET) return NIL;
+				/* can transfer bytes from buffer? */
+  if (n = min (size,stream->ictr)) {
+    memcpy (s,stream->iptr,n);	/* yes, slurp as much as we can from it */
+    s += n;			/* update pointer */
+    stream->iptr +=n;
+    size -= n;			/* update # of bytes to do */
+    stream->ictr -=n;
+  }
+  if (size) {
+    int i;
+    fd_set fds,efds;
+    struct timeval tmo;
+    time_t t = time (0);
+    blocknotify_t bn=(blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+    (*bn) (BLOCK_TCPREAD,NIL);
+    while (size > 0) {		/* until request satisfied */
+      if (tcpdebug) mm_log ("Reading TCP buffer",TCPDEBUG);
+				/* simple case if not a socket */
+      if (stream->tcpsi != stream->tcpso)
+	while (((i = read (stream->tcpsi,s,(int) min (maxposint,size))) < 0) &&
+	       (errno == EINTR));
+      else {			/* socket case */
+	time_t tl = time (0);
+	time_t now = tl;
+	time_t ti = ttmo_read ? now + ttmo_read : 0;
+	tmo.tv_usec = 0;
+	FD_ZERO (&fds);		/* initialize selection vector */
+	FD_ZERO (&efds);	/* handle errors too */
+				/* set bit in selection vectors */
+	FD_SET (stream->tcpsi,&fds);
+	FD_SET (stream->tcpsi,&efds);
+	errno = NIL;		/* initially no error */
+	do {			/* block under timeout */
+	  tmo.tv_sec = (long) (ti ? ti - now : 0);
+	  i = select (stream->tcpsi+1,&fds,NIL,&efds,ti ? &tmo : NIL);
+	  now = time (0);	/* fake timeout if interrupt & time expired */
+	  if ((i < 0) && ((errno = WSAGetLastError ()) == WSAEINTR) && ti &&
+	      (ti <= now)) i = 0;
+	} while ((i < 0) && (errno == WSAEINTR));
+				/* success from select, read what we can */
+	if (i > 0) while (((i = recv (stream->tcpsi,s,
+				      (int) min (maxposint,size),0)) ==
+			   SOCKET_ERROR) &&
+			  ((errno = WSAGetLastError ()) == WSAEINTR));
+	else if (!i) {		/* timeout, ignore if told to resume */
+	  if (tmoh && (*tmoh) ((long) (now - t),(long) (now - tl))) continue;
+				/* otherwise punt */
+	  if (tcpdebug) mm_log ("TCP buffer read timeout",TCPDEBUG);
+	  return tcp_abort (stream);
+	}
+      }
+      if (i <= 0) {		/* error seen? */
+	if (tcpdebug) {
+	  char tmp[MAILTMPLEN];
+	  if (i) sprintf (s = tmp,"TCP buffer read I/O error %d",errno);
+	  else s = "TCP buffer read end of file";
+	  mm_log (s,TCPDEBUG);
+	}
+	return tcp_abort (stream);
+      }
+      s += i;			/* point at new place to write */
+      size -= i;		/* reduce byte count */
+      if (tcpdebug) mm_log ("Successfully read TCP buffer",TCPDEBUG);
+    }
+    (*bn) (BLOCK_NONE,NIL);
+  }
+  *s = '\0';			/* tie off string */
+  return LONGT;
+}
+
+/* TCP/IP receive data
+ * Accepts: TCP/IP stream
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getdata (TCPSTREAM *stream)
+{
+  int i;
+  fd_set fds,efds;
+  struct timeval tmo;
+  time_t t = time (0);
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  if (stream->tcpsi == INVALID_SOCKET) return NIL;
+  (*bn) (BLOCK_TCPREAD,NIL);
+  while (stream->ictr < 1) {	/* if nothing in the buffer */
+    if (tcpdebug) mm_log ("Reading TCP data",TCPDEBUG);
+				/* simple case if not a socket */
+    if (stream->tcpsi != stream->tcpso)
+      while (((i = read (stream->tcpsi,stream->ibuf,BUFLEN)) < 0) &&
+	     (errno == EINTR));
+    else {
+      time_t tl = time (0);
+      time_t now = tl;
+      time_t ti = ttmo_read ? now + ttmo_read : 0;
+      tmo.tv_usec = 0;
+      FD_ZERO (&fds);		/* initialize selection vector */
+      FD_ZERO (&efds);		/* handle errors too */
+				/* set bit in selection vectors */
+      FD_SET (stream->tcpsi,&fds);
+      FD_SET (stream->tcpsi,&efds);
+      errno = NIL;		/* initially no error */
+      do {			/* block under timeout */
+	tmo.tv_sec = (long) (ti ? ti - now : 0);
+	i = select (stream->tcpsi+1,&fds,NIL,&efds,ti ? &tmo : NIL);
+	now = time (0);		/* fake timeout if interrupt & time expired */
+	if ((i < 0) && ((errno = WSAGetLastError ()) == WSAEINTR) && ti &&
+	    (ti <= now)) i = 0;
+      } while ((i < 0) && (errno == WSAEINTR));
+				/* success from select, read what we can */
+      if (i > 0) while (((i = recv (stream->tcpsi,stream->ibuf,BUFLEN,0)) ==
+			 SOCKET_ERROR) &&
+			((errno = WSAGetLastError ()) == WSAEINTR));
+      else if (!i) {		/* timeout, ignore if told to resume */
+	if (tmoh && (*tmoh) ((long) (now - t),(long) (now - tl))) continue;
+				/* otherwise punt */
+	if (tcpdebug) mm_log ("TCP data read timeout",TCPDEBUG);
+	return tcp_abort (stream);
+      }
+    }
+    if (i <= 0) {		/* error seen? */
+      if (tcpdebug) {
+	char *s,tmp[MAILTMPLEN];
+	if (i) sprintf (s = tmp,"TCP data read I/O error %d",errno);
+	else s = "TCP data read end of file";
+	mm_log (tmp,TCPDEBUG);
+      }
+      return tcp_abort (stream);
+    }
+    stream->iptr = stream->ibuf;/* point at TCP buffer */
+    stream->ictr = i;		/* set new byte count */
+    if (tcpdebug) mm_log ("Successfully read TCP data",TCPDEBUG);
+  }
+  (*bn) (BLOCK_NONE,NIL);
+  return T;
+}
+
+/* TCP/IP send string as record
+ * Accepts: TCP/IP stream
+ *	    string pointer
+ * Returns: T if success else NIL
+ */
+
+long tcp_soutr (TCPSTREAM *stream,char *string)
+{
+  return tcp_sout (stream,string,(unsigned long) strlen (string));
+}
+
+
+/* TCP/IP send string
+ * Accepts: TCP/IP stream
+ *	    string pointer
+ *	    byte count
+ * Returns: T if success else NIL
+ */
+
+long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
+{
+  int i;
+  struct timeval tmo;
+  fd_set fds,efds;
+  time_t t = time (0);
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  tmo.tv_sec = ttmo_write;
+  tmo.tv_usec = 0;
+  FD_ZERO (&fds);		/* initialize selection vector */
+  if (stream->tcpso == INVALID_SOCKET) return NIL;
+  (*bn) (BLOCK_TCPWRITE,NIL);
+  while (size > 0) {		/* until request satisfied */
+    if (tcpdebug) mm_log ("Writing to TCP",TCPDEBUG);
+				/* simple case if not a socket */
+    if (stream->tcpsi != stream->tcpso)
+      while (((i = write (stream->tcpso,string,min (size,TCPMAXSEND))) < 0) &&
+	     (errno == EINTR));
+    else {
+      time_t tl = time (0);	/* start of request */
+      time_t now = tl;
+      time_t ti = ttmo_write ? now + ttmo_write : 0;
+      tmo.tv_usec = 0;
+      FD_ZERO (&fds);		/* initialize selection vector */
+      FD_ZERO (&efds);		/* handle errors too */
+				/* set bit in selection vectors */
+      FD_SET (stream->tcpso,&fds);
+      FD_SET(stream->tcpso,&efds);
+      errno = NIL;		/* block and write */
+      do {			/* block under timeout */
+	tmo.tv_sec = (long) (ti ? ti - now : 0);
+	i = select (stream->tcpso+1,NIL,&fds,&efds,ti ? &tmo : NIL);
+	now = time (0);		/* fake timeout if interrupt & time expired */
+	if ((i < 0) && ((errno = WSAGetLastError ()) == WSAEINTR) && ti &&
+	    (ti <= now)) i = 0;
+      } while ((i < 0) && (errno == WSAEINTR));
+				/* OK to send data? */
+      if (i > 0) while (((i = send (stream->tcpso,string,
+				    (int) min (size,TCPMAXSEND),0)) ==
+			 SOCKET_ERROR) &&
+			((errno = WSAGetLastError ()) == WSAEINTR));
+      else if (!i) {		/* timeout, ignore if told to resume */
+	if (tmoh && (*tmoh) ((long) (now - t),(long) (now - tl))) continue;
+				/* otherwise punt */
+	if (tcpdebug) mm_log ("TCP write timeout",TCPDEBUG);
+	return tcp_abort (stream);
+      }
+    }
+    if (i <= 0) {		/* error seen? */
+      if (tcpdebug) {
+	char tmp[MAILTMPLEN];
+	sprintf (tmp,"TCP write I/O error %d",errno);
+	mm_log (tmp,TCPDEBUG);
+      }
+      return tcp_abort (stream);
+    }
+    string += i;		/* how much we sent */
+    size -= i;			/* count this size */
+    if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG);
+  }
+  (*bn) (BLOCK_NONE,NIL);
+  return T;			/* all done */
+}
+
+/* TCP/IP close
+ * Accepts: TCP/IP stream
+ */
+
+void tcp_close (TCPSTREAM *stream)
+{
+  tcp_abort (stream);		/* nuke the sockets */
+				/* flush host names */
+  if (stream->host) fs_give ((void **) &stream->host);
+  if (stream->remotehost) fs_give ((void **) &stream->remotehost);
+  if (stream->localhost) fs_give ((void **) &stream->localhost);
+  fs_give ((void **) &stream);	/* flush the stream */
+}
+
+
+/* TCP/IP abort sockets
+ * Accepts: TCP/IP stream
+ * Returns: NIL, always
+ */
+
+long tcp_abort (TCPSTREAM *stream)
+{
+  if (stream->tcpsi != stream->tcpso) tcp_close_socket (&stream->tcpso);
+  else stream->tcpso = INVALID_SOCKET;
+  return tcp_close_socket (&stream->tcpsi);
+}
+
+
+/* TCP/IP abort stream
+ * Accepts: WinSock socket
+ * Returns: NIL, always
+ */
+
+long tcp_close_socket (SOCKET *sock)
+{
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+				/* something to close? */
+  if (sock && (*sock != INVALID_SOCKET)) {
+    (*bn) (BLOCK_TCPCLOSE,NIL);
+    closesocket (*sock);	/* WinSock socket close */
+    *sock = INVALID_SOCKET;
+    (*bn) (BLOCK_NONE,NIL);
+    wsa_sock_open--;		/* drop this socket */
+  }
+				/* no more open streams? */
+  if (wsa_initted && !wsa_sock_open) {
+    mm_log ("Winsock cleanup",NIL);
+    wsa_initted = 0;		/* no more sockets, so... */
+    WSACleanup ();		/* free up resources until needed */
+  }
+  return NIL;
+}
+
+/* TCP/IP get host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_host (TCPSTREAM *stream)
+{
+  return stream->host;		/* use tcp_remotehost() if want guarantees */
+}
+
+
+/* TCP/IP get remote host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_remotehost (TCPSTREAM *stream)
+{
+  if (!stream->remotehost) {
+    size_t sadrlen;
+    struct sockaddr *sadr = ip_newsockaddr (&sadrlen);
+    stream->remotehost =	/* get socket's peer name */
+      ((getpeername (stream->tcpsi,sadr,&sadrlen) == SOCKET_ERROR) ||
+       (sadrlen <= 0)) ? cpystr (stream->host) : tcp_name (sadr,NIL);
+    fs_give ((void **) &sadr);
+  }
+  return stream->remotehost;
+}
+
+
+/* TCP/IP return port for this stream
+ * Accepts: TCP/IP stream
+ * Returns: port number for this stream
+ */
+
+unsigned long tcp_port (TCPSTREAM *stream)
+{
+  return stream->port;		/* return port number */
+}
+
+
+/* TCP/IP get local host name
+ * Accepts: TCP/IP stream
+ * Returns: local host name
+ */
+
+char *tcp_localhost (TCPSTREAM *stream)
+{
+  if (!stream->localhost) {
+    size_t sadrlen;
+    struct sockaddr *sadr = ip_newsockaddr (&sadrlen);
+    stream->localhost =		/* get socket's name */
+      ((stream->port & 0xffff000) ||
+       ((getsockname (stream->tcpsi,sadr,&sadrlen) == SOCKET_ERROR) ||
+	(sadrlen <= 0))) ? cpystr (mylocalhost ()) : tcp_name (sadr,NIL);
+    fs_give ((void **) &sadr);
+  }
+  return stream->localhost;	/* return local host name */
+}
+
+/* TCP/IP get client host address (server calls only)
+ * Returns: client host address
+ */
+
+char *tcp_clientaddr ()
+{
+  if (!myClientAddr) {
+    size_t sadrlen;
+    struct sockaddr *sadr = ip_newsockaddr (&sadrlen);
+    if ((getpeername (0,sadr,(void *) &sadrlen) == SOCKET_ERROR) ||
+	(sadrlen <= 0)) myClientAddr = cpystr ("UNKNOWN");
+    else {			/* get stdin's peer name */
+      myClientAddr = cpystr (ip_sockaddrtostring (sadr));
+      if (myClientPort < 0) myClientPort = ip_sockaddrtoport (sadr);
+    }
+    fs_give ((void **) &sadr);
+  }
+  return myClientAddr;
+}
+
+
+/* TCP/IP get client host name (server calls only)
+ * Returns: client host name
+ */
+
+char *tcp_clienthost ()
+{
+  if (!myClientHost) {
+    size_t sadrlen;
+    struct sockaddr *sadr = ip_newsockaddr (&sadrlen);
+    if ((getpeername (0,sadr,(void *) &sadrlen) == SOCKET_ERROR) ||
+	(sadrlen <= 0)) myClientHost = cpystr ("UNKNOWN");
+    else {			/* get stdin's peer name */
+      myClientHost = tcp_name (sadr,T);
+      if (!myClientAddr) myClientAddr = cpystr (ip_sockaddrtostring (sadr));
+      if (myClientPort < 0) myClientPort = ip_sockaddrtoport (sadr);
+    }
+    fs_give ((void **) &sadr);
+  }
+  return myClientHost;
+}
+
+
+/* TCP/IP get client port number (server calls only)
+ * Returns: client port number
+ */
+
+long tcp_clientport ()
+{
+  if (!myClientHost && !myClientAddr) tcp_clientaddr ();
+  return myClientPort;
+}
+
+/* TCP/IP get server host address (server calls only)
+ * Returns: server host address
+ */
+
+char *tcp_serveraddr ()
+{
+  if (!myServerAddr) {
+    size_t sadrlen;
+    struct sockaddr *sadr = ip_newsockaddr (&sadrlen);
+    if (!wsa_initted++) {	/* init Windows Sockets */
+      WSADATA wsock;
+      if (WSAStartup (WINSOCK_VERSION,&wsock)) {
+	wsa_initted = 0;
+	return "random-pc";	/* try again later? */
+      }
+    }
+    if ((getsockname (0,sadr,(void *) &sadrlen) == SOCKET_ERROR) ||
+	(sadrlen <= 0)) myServerAddr = cpystr ("UNKNOWN");
+    else {			/* get stdin's name */
+      myServerAddr = cpystr (ip_sockaddrtostring (sadr));
+      if (myServerPort < 0) myServerPort = ip_sockaddrtoport (sadr);
+    }
+    fs_give ((void **) &sadr);
+  }
+  return myServerAddr;
+}
+
+
+/* TCP/IP get server host name (server calls only)
+ * Returns: server host name
+ */
+
+char *tcp_serverhost ()
+{
+  if (!myServerHost) {		/* once-only */
+    size_t sadrlen;
+    struct sockaddr *sadr = ip_newsockaddr (&sadrlen);
+    if (!wsa_initted++) {	/* init Windows Sockets */
+      WSADATA wsock;
+      if (WSAStartup (WINSOCK_VERSION,&wsock)) {
+	wsa_initted = 0;
+	return "random-pc";	/* try again later? */
+      }
+    }
+				/* get stdin's name */
+    if ((getsockname (0,sadr,(void *) &sadrlen) == SOCKET_ERROR) ||
+	(sadrlen <= 0)) myServerHost = cpystr (mylocalhost ());
+    else {			/* get stdin's name */
+      myServerHost = tcp_name (sadr,NIL);
+      if (!myServerAddr) myServerAddr = cpystr (ip_sockaddrtostring (sadr));
+      if (myServerPort < 0) myServerPort = ip_sockaddrtoport (sadr);
+    }
+    fs_give ((void **) &sadr);
+  }
+  return myServerHost;
+}
+
+
+/* TCP/IP get server port number (server calls only)
+ * Returns: server port number
+ */
+
+long tcp_serverport ()
+{
+  if (!myServerHost && !myServerAddr) tcp_serveraddr ();
+  return myServerPort;
+}
+
+/* TCP/IP return canonical form of host name
+ * Accepts: host name
+ * Returns: canonical form of host name
+ */
+
+char *tcp_canonical (char *name)
+{
+  char *ret,host[MAILTMPLEN];
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+				/* look like domain literal? */
+  if (name[0] == '[' && name[strlen (name) - 1] == ']') return name;
+  (*bn) (BLOCK_DNSLOOKUP,NIL);
+  if (tcpdebug) {
+    sprintf (host,"DNS canonicalization %.80s",name);
+    mm_log (host,TCPDEBUG);
+  }
+				/* get canonical name */
+  if (!ip_nametoaddr (name,NIL,NIL,&ret,NIL)) ret = name;
+  (*bn) (BLOCK_NONE,NIL);	/* alarms OK now */
+  if (tcpdebug) mm_log ("DNS canonicalization done",TCPDEBUG);
+  return ret;
+}
+
+
+/* TCP/IP return name from socket
+ * Accepts: socket
+ *	    verbose flag
+ * Returns: cpystr name
+ */
+
+char *tcp_name (struct sockaddr *sadr,long flag)
+{
+  char *ret,*t,adr[MAILTMPLEN],tmp[MAILTMPLEN];
+  sprintf (ret = adr,"[%.80s]",ip_sockaddrtostring (sadr));
+  if (allowreversedns) {
+    blocknotify_t bn = (blocknotify_t)mail_parameters(NIL,GET_BLOCKNOTIFY,NIL);
+    if (tcpdebug) {
+      sprintf (tmp,"Reverse DNS resolution %s",adr);
+      mm_log (tmp,TCPDEBUG);
+    }
+    (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */
+				/* translate address to name */
+    if (t = tcp_name_valid (ip_sockaddrtoname (sadr))) {
+				/* produce verbose form if needed */
+      if (flag)	sprintf (ret = tmp,"%s %s",t,adr);
+      else ret = t;
+    }
+    (*bn) (BLOCK_NONE,NIL);	/* alarms OK now */
+    if (tcpdebug) mm_log ("Reverse DNS resolution done",TCPDEBUG);
+  }
+  return cpystr (ret);
+}
+
+/* Validate name
+ * Accepts: domain name
+ * Returns: T if valid, NIL otherwise
+ */
+
+char *tcp_name_valid (char *s)
+{
+  int c;
+  char *ret,*tail;
+				/* must be non-empty and not too long */
+  if ((ret = (s && *s) ? s : NIL) && (tail = ret + NETMAXHOST)) {
+				/* must be alnum, dot, or hyphen */
+    while ((c = *s++) && (s <= tail) &&
+	   (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) ||
+	    ((c >= '0') && (c <= '9')) || (c == '-') || (c == '.')));
+    if (c) ret = NIL;
+  }
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/tcp_nt.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,51 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Winsock TCP/IP routines
+ *
+ * Author:	Mark Crispin
+ *	        Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 April 1989
+ * Last Edited:	30 August 2006
+ */
+
+/* TCP input buffer -- must be large enough to prevent overflow */
+
+#define BUFLEN 16384		/* 32768 causes stdin read() to barf */
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#undef ERROR			/* quell conflicting definition diagnostic */
+
+
+/* TCP I/O stream (must be before osdep.h is included) */
+
+#define TCPSTREAM struct tcp_stream
+TCPSTREAM {
+  char *host;			/* host name */
+  char *remotehost;		/* remote host name */
+  unsigned long port;		/* port number */
+  char *localhost;		/* local host name */
+  SOCKET tcpsi;			/* tcp socket */
+  SOCKET tcpso;			/* tcp socket */
+  long ictr;			/* input counter */
+  char *iptr;			/* input pointer */
+  char ibuf[BUFLEN];		/* input buffer */
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/tenexnt.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1310 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Tenex mail routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	22 May 1990
+ * Last Edited:	18 June 2007
+ */
+
+
+/*				FILE TIME SEMANTICS
+ *
+ * The atime is the last read time of the file.
+ * The mtime is the last flags update time of the file.
+ * The ctime is the last write time of the file.
+ *
+ *				TEXT SIZE SEMANTICS
+ *
+ * Most of the text sizes are in internal (LF-only) form, except for the
+ * msg.text size.  Beware.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "mail.h"
+#include "osdep.h"
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/utime.h>
+#include "misc.h"
+#include "dummy.h"
+
+/* TENEX I/O stream local data */
+	
+typedef struct tenex_local {
+  unsigned int shouldcheck: 1;	/* if ping should do a check instead */
+  unsigned int mustcheck: 1;	/* if ping must do a check instead */
+  int fd;			/* file descriptor for I/O */
+  off_t filesize;		/* file size parsed */
+  time_t filetime;		/* last file time */
+  time_t lastsnarf;		/* local snarf time */
+  unsigned char *buf;		/* temporary buffer */
+  unsigned long buflen;		/* current size of temporary buffer */
+  unsigned long uid;		/* current text uid */
+  SIZEDTEXT text;		/* current text */
+} TENEXLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((TENEXLOCAL *) stream->local)
+
+
+/* Function prototypes */
+
+DRIVER *tenex_valid (char *name);
+int tenex_isvalid (char *name,char *file);
+void *tenex_parameters (long function,void *value);
+void tenex_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void tenex_list (MAILSTREAM *stream,char *ref,char *pat);
+void tenex_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long tenex_create (MAILSTREAM *stream,char *mailbox);
+long tenex_delete (MAILSTREAM *stream,char *mailbox);
+long tenex_rename (MAILSTREAM *stream,char *old,char *newname);
+long tenex_status (MAILSTREAM *stream,char *mbx,long flags);
+MAILSTREAM *tenex_open (MAILSTREAM *stream);
+void tenex_close (MAILSTREAM *stream,long options);
+void tenex_fast (MAILSTREAM *stream,char *sequence,long flags);
+void tenex_flags (MAILSTREAM *stream,char *sequence,long flags);
+char *tenex_header (MAILSTREAM *stream,unsigned long msgno,
+		    unsigned long *length,long flags);
+long tenex_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+void tenex_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
+void tenex_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
+long tenex_ping (MAILSTREAM *stream);
+void tenex_check (MAILSTREAM *stream);
+void tenex_snarf (MAILSTREAM *stream);
+long tenex_expunge (MAILSTREAM *stream,char *sequence,long options);
+long tenex_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long tenex_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+unsigned long tenex_size (MAILSTREAM *stream,unsigned long m);
+long tenex_parse (MAILSTREAM *stream);
+MESSAGECACHE *tenex_elt (MAILSTREAM *stream,unsigned long msgno);
+void tenex_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt);
+void tenex_update_status (MAILSTREAM *stream,unsigned long msgno,
+			  long syncflag);
+unsigned long tenex_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			    unsigned long *size);
+
+
+/* Tenex mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER tenexdriver = {
+  "tenex",			/* driver name */
+  DR_LOCAL|DR_MAIL,		/* driver flags */
+  (DRIVER *) NIL,		/* next driver */
+  tenex_valid,			/* mailbox is valid for us */
+  tenex_parameters,		/* manipulate parameters */
+  tenex_scan,			/* scan mailboxes */
+  tenex_list,			/* list mailboxes */
+  tenex_lsub,			/* list subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  tenex_create,			/* create mailbox */
+  tenex_delete,			/* delete mailbox */
+  tenex_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  tenex_open,			/* open mailbox */
+  tenex_close,			/* close mailbox */
+  tenex_flags,			/* fetch message "fast" attributes */
+  tenex_flags,			/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  tenex_header,			/* fetch message header */
+  tenex_text,			/* fetch message body */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  tenex_flag,			/* modify flags */
+  tenex_flagmsg,		/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  tenex_ping,			/* ping mailbox to see if still alive */
+  tenex_check,			/* check for new messages */
+  tenex_expunge,		/* expunge deleted messages */
+  tenex_copy,			/* copy messages to another mailbox */
+  tenex_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM tenexproto = {&tenexdriver};
+
+/* Tenex mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *tenex_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+  return tenex_isvalid (name,tmp) ? &tenexdriver : NIL;
+}
+
+
+/* Tenex mail test for valid mailbox
+ * Accepts: mailbox name
+ *	    buffer to return file name
+ * Returns: T if valid, NIL otherwise
+ */
+
+int tenex_isvalid (char *name,char *file)
+{
+  int fd;
+  int ret = NIL;
+  char *s,tmp[MAILTMPLEN];
+  struct stat sbuf;
+  struct utimbuf times;
+  errno = EINVAL;		/* assume invalid argument */
+				/* if file, get its status */
+  if ((s = dummy_file (file,name)) && !stat (s,&sbuf) &&
+      ((sbuf.st_mode & S_IFMT) == S_IFREG)) {
+    if (!sbuf.st_size)errno = 0;/* empty file */
+    else if ((fd = open (file,O_BINARY|O_RDONLY,NIL)) >= 0) {
+      memset (tmp,'\0',MAILTMPLEN);
+      if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\012')) &&
+	  (s[-1] != '\015')) {	/* valid format? */
+	*s = '\0';		/* tie off header */
+				/* must begin with dd-mmm-yy" */
+	ret = (((tmp[2] == '-' && tmp[6] == '-') ||
+		(tmp[1] == '-' && tmp[5] == '-')) &&
+	       (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL;
+      }
+      else errno = -1;		/* bogus format */
+      close (fd);		/* close the file */
+				/* \Marked status? */
+      if (sbuf.st_ctime > sbuf.st_atime) {
+				/* preserve atime and mtime */
+	times.actime = sbuf.st_atime;
+	times.modtime = sbuf.st_mtime;
+	utime (file,&times);	/* set the times */
+      }
+    }
+  }
+				/* in case INBOX but not tenex format */
+  else if ((errno == ENOENT) && !compare_cstring (name,"INBOX")) errno = -1;
+  return ret;			/* return what we should */
+}
+
+
+/* Tenex manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *tenex_parameters (long function,void *value)
+{
+  return NIL;
+}
+
+/* Tenex mail scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void tenex_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* Tenex mail list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void tenex_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_list (NIL,ref,pat);
+}
+
+
+/* Tenex mail list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void tenex_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_lsub (NIL,ref,pat);
+}
+
+/* Tenex mail create mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long tenex_create (MAILSTREAM *stream,char *mailbox)
+{
+  char *s,mbx[MAILTMPLEN];
+  if (s = dummy_file (mbx,mailbox)) return dummy_create (stream,s);
+  sprintf (mbx,"Can't create %.80s: invalid name",mailbox);
+  mm_log (mbx,ERROR);
+  return NIL;
+}
+
+
+/* Tenex mail delete mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long tenex_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return tenex_rename (stream,mailbox,NIL);
+}
+
+/* Tenex mail rename mailbox
+ * Accepts: MAIL stream
+ *	    old mailbox name
+ *	    new mailbox name (or NIL for delete)
+ * Returns: T on success, NIL on failure
+ */
+
+long tenex_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  long ret = LONGT;
+  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  int fd,ld;
+  struct stat sbuf;
+  if (!dummy_file (file,old) ||
+      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
+		   ((s = strrchr (tmp,'\\')) && !s[1])))) {
+    sprintf (tmp,newname ?
+	     "Can't rename mailbox %.80s to %.80s: invalid name" :
+	     "Can't delete mailbox %.80s: invalid name",
+	     old,newname);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+  else if ((fd = open (file,O_BINARY|O_RDWR,NIL)) < 0) {
+    sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* get exclusive parse/append permission */
+  if ((ld = lockname (lock,file,LOCK_EX)) < 0) {
+    mm_log ("Unable to lock rename mailbox",ERROR);
+    return NIL;
+  }
+				/* lock out other users */
+  if (flock (fd,LOCK_EX|LOCK_NB)) {
+    close (fd);			/* couldn't lock, give up on it then */
+    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
+    mm_log (tmp,ERROR);
+    unlockfd (ld,lock);		/* release exclusive parse/append permission */
+    return NIL;
+  }
+
+  if (newname) {		/* want rename? */
+				/* found superior to destination name? */
+    if ((s = strrchr (tmp,'\\')) && (s != tmp) &&
+	((tmp[1] != ':') || (s != tmp + 2))) {
+      c = s[1];			/* remember character after delimiter */
+      *s = s[1] = '\0';		/* tie off name at delimiter */
+				/* name doesn't exist, create it */
+      if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) {
+	*s = '\\';		/* restore delimiter */
+	if (!dummy_create (stream,tmp)) ret = NIL;
+      }
+      else *s = '\\';		/* restore delimiter */
+      s[1] = c;			/* restore character after delimiter */
+    }
+    flock (fd,LOCK_UN);		/* release lock on the file */
+    close (fd);			/* pacify NTFS */
+				/* rename the file */
+    if (ret && rename (file,tmp)) {
+      sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
+	       strerror (errno));
+      mm_log (tmp,ERROR);
+      ret = NIL;		/* set failure */
+    }
+  }
+  else {
+    flock (fd,LOCK_UN);		/* release lock on the file */
+    close (fd);			/* pacify NTFS */
+    if (unlink (file)) {
+      sprintf (tmp,"Can't delete mailbox %.80s: %.80s",old,strerror (errno));
+      mm_log (tmp,ERROR);
+      ret = NIL;		/* set failure */
+    }
+  }
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+  return ret;			/* return success */
+}
+
+/* Tenex mail open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *tenex_open (MAILSTREAM *stream)
+{
+  int fd,ld;
+  char tmp[MAILTMPLEN];
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return &tenexproto;
+  if (stream->local) fatal ("tenex recycle stream");
+				/* canonicalize the mailbox name */
+  if (!dummy_file (tmp,stream->mailbox)) {
+    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
+    mm_log (tmp,ERROR);
+  }
+  if (stream->rdonly ||
+      (fd = open (tmp,O_BINARY|O_RDWR,NIL)) < 0) {
+    if ((fd = open (tmp,O_BINARY|O_RDONLY,NIL)) < 0) {
+      sprintf (tmp,"Can't open mailbox: %.80s",strerror (errno));
+      mm_log (tmp,ERROR);
+      return NIL;
+    }
+    else if (!stream->rdonly) {	/* got it, but readonly */
+      mm_log ("Can't get write access to mailbox, access is readonly",WARN);
+      stream->rdonly = T;
+    }
+  }
+  stream->local = fs_get (sizeof (TENEXLOCAL));
+  LOCAL->fd = fd;		/* bind the file */
+  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
+  LOCAL->buflen = CHUNKSIZE - 1;
+  LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE);
+  LOCAL->text.size = CHUNKSIZE - 1;
+				/* note if an INBOX or not */
+  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
+  fs_give ((void **) &stream->mailbox);
+  stream->mailbox = cpystr (tmp);
+				/* get shared parse permission */
+  if ((ld = lockname (tmp,stream->mailbox,LOCK_SH)) < 0) {
+    mm_log ("Unable to lock open mailbox",ERROR);
+    return NIL;
+  }
+  flock (LOCAL->fd,LOCK_SH);	/* lock the file */
+  unlockfd (ld,tmp);		/* release shared parse permission */
+  LOCAL->filesize = 0;		/* initialize parsed file size */
+  LOCAL->filetime = 0;		/* time not set up yet */
+  LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
+  stream->sequence++;		/* bump sequence number */
+  stream->uid_validity = (unsigned long) time (0);
+				/* parse mailbox */
+  stream->nmsgs = stream->recent = 0;
+  if (tenex_ping (stream) && !stream->nmsgs)
+    mm_log ("Mailbox is empty",(long) NIL);
+  if (!LOCAL) return NIL;	/* failure if stream died */
+  stream->perm_seen = stream->perm_deleted =
+    stream->perm_flagged = stream->perm_answered = stream->perm_draft =
+      stream->rdonly ? NIL : T;
+  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
+  return stream;		/* return stream to caller */
+}
+
+/* Tenex mail close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void tenex_close (MAILSTREAM *stream,long options)
+{
+  if (stream && LOCAL) {	/* only if a file is open */
+    int silent = stream->silent;
+    stream->silent = T;		/* note this stream is dying */
+    if (options & CL_EXPUNGE) tenex_expunge (stream,NIL,NIL);
+    stream->silent = silent;	/* restore previous status */
+    flock (LOCAL->fd,LOCK_UN);	/* unlock local file */
+    close (LOCAL->fd);		/* close the local file */
+				/* free local text buffer */
+    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+    if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+/* Tenex mail fetch flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ * Sniffs at file to get flags
+ */
+
+void tenex_flags (MAILSTREAM *stream,char *sequence,long flags)
+{
+  STRING bs;
+  MESSAGECACHE *elt;
+  unsigned long i;
+  if (stream && LOCAL &&
+      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
+       mail_sequence (stream,sequence)))
+    for (i = 1; i <= stream->nmsgs; i++)
+      if ((elt = mail_elt (stream,i))->sequence) {
+	if (!elt->rfc822_size) { /* have header size yet? */
+	  lseek (LOCAL->fd,elt->private.special.offset +
+		 elt->private.special.text.size,L_SET);
+				/* resize bigbuf if necessary */
+	  if (LOCAL->buflen < elt->private.msg.full.text.size) {
+	    fs_give ((void **) &LOCAL->buf);
+	    LOCAL->buflen = elt->private.msg.full.text.size;
+	    LOCAL->buf = (char *) fs_get (LOCAL->buflen + 1);
+	  }
+				/* tie off string */
+	  LOCAL->buf[elt->private.msg.full.text.size] = '\0';
+				/* read in the message */
+	  read (LOCAL->fd,LOCAL->buf,elt->private.msg.full.text.size);
+	  INIT (&bs,mail_string,(void *) LOCAL->buf,
+		elt->private.msg.full.text.size);
+				/* calculate its CRLF size */
+	  elt->rfc822_size = unix_crlflen (&bs);
+	}
+	tenex_elt (stream,i);	/* get current flags from file */
+      }
+}
+
+/* TENEX mail fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+char *tenex_header (MAILSTREAM *stream,unsigned long msgno,
+		    unsigned long *length,long flags)
+{
+  char *s;
+  unsigned long i;
+  *length = 0;			/* default to empty */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+				/* get to header position */
+  lseek (LOCAL->fd,tenex_hdrpos (stream,msgno,&i),L_SET);
+  if (flags & FT_INTERNAL) {
+    if (i > LOCAL->buflen) {	/* resize if not enough space */
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get (LOCAL->buflen = i + 1);
+    }
+				/* slurp the data */
+    read (LOCAL->fd,LOCAL->buf,*length = i);
+  }
+  else {
+    s = (char *) fs_get (i + 1);/* get readin buffer */
+    s[i] = '\0';		/* tie off string */
+    read (LOCAL->fd,s,i);	/* slurp the data */
+				/* make CRLF copy of string */
+    *length = unix_crlfcpy (&LOCAL->buf,&LOCAL->buflen,s,i);
+    fs_give ((void **) &s);	/* free readin buffer */
+  }
+  return LOCAL->buf;
+}
+
+/* TENEX mail fetch message text (body only)
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned stringstruct
+ *	    option flags
+ * Returns: T, always
+ */
+
+long tenex_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  char *s;
+  unsigned long i,j;
+  MESSAGECACHE *elt;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+				/* get message status */
+  elt = tenex_elt (stream,msgno);
+				/* if message not seen */
+  if (!(flags & FT_PEEK) && !elt->seen) {
+    elt->seen = T;		/* mark message as seen */
+				/* recalculate status */
+    tenex_update_status (stream,msgno,T);
+    mm_flags (stream,msgno);
+  }
+  if (flags & FT_INTERNAL) {	/* if internal representation wanted */
+				/* find header position */
+    i = tenex_hdrpos (stream,msgno,&j);
+    if (i > LOCAL->buflen) {	/* resize if not enough space */
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get (LOCAL->buflen = i + 1);
+    }
+				/* go to text position */
+    lseek (LOCAL->fd,i + j,L_SET);
+				/* slurp the data */
+    if (read (LOCAL->fd,LOCAL->buf,i) != (long) i) return NIL;
+				/* set up stringstruct for internal */
+    INIT (bs,mail_string,LOCAL->buf,i);
+  }
+  else {			/* normal form, previous text cached? */
+    if (elt->private.uid == LOCAL->uid)
+      i = elt->private.msg.text.text.size;
+    else {			/* not cached, cache it now */
+      LOCAL->uid = elt->private.uid;
+				/* find header position */
+      i = tenex_hdrpos (stream,msgno,&j);
+				/* go to text position */
+      lseek (LOCAL->fd,i + j,L_SET);
+      s = (char *) fs_get ((i = tenex_size (stream,msgno) - j) + 1);
+      s[i] = '\0';		/* tie off string */
+      read (LOCAL->fd,s,i);	/* slurp the data */
+				/* make CRLF copy of string */
+      i = elt->private.msg.text.text.size =
+	strcrlfcpy (&LOCAL->text.data,&LOCAL->text.size,s,i);
+      fs_give ((void **) &s);	/* free readin buffer */
+    }
+				/* set up stringstruct */
+    INIT (bs,mail_string,LOCAL->text.data,i);
+  }
+  return T;			/* success */
+}
+
+/* Tenex mail modify flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    flag(s)
+ *	    option flags
+ */
+
+void tenex_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
+{
+  struct utimbuf times;
+  struct stat sbuf;
+  if (!stream->rdonly) {	/* make sure the update takes */
+    fsync (LOCAL->fd);
+    fstat (LOCAL->fd,&sbuf);	/* get current write time */
+    times.modtime = LOCAL->filetime = sbuf.st_mtime;
+    times.actime = time (0);	/* make sure read comes after all that */
+    utime (stream->mailbox,&times);
+  }
+}
+
+
+/* Tenex mail per-message modify flags
+ * Accepts: MAIL stream
+ *	    message cache element
+ */
+
+void tenex_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  struct stat sbuf;
+				/* maybe need to do a checkpoint? */
+  if (LOCAL->filetime && !LOCAL->shouldcheck) {
+    fstat (LOCAL->fd,&sbuf);	/* get current write time */
+    if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
+    LOCAL->filetime = 0;	/* don't do this test for any other messages */
+  }
+				/* recalculate status */
+  tenex_update_status (stream,elt->msgno,NIL);
+}
+
+/* Tenex mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream still alive, NIL if not
+ */
+
+long tenex_ping (MAILSTREAM *stream)
+{
+  unsigned long i = 1;
+  long r = T;
+  int ld;
+  char lock[MAILTMPLEN];
+  struct stat sbuf;
+  if (stream && LOCAL) {	/* only if stream already open */
+    fstat (LOCAL->fd,&sbuf);	/* get current file poop */
+    if (LOCAL->filetime && !(LOCAL->mustcheck || LOCAL->shouldcheck) &&
+	(LOCAL->filetime < sbuf.st_mtime)) LOCAL->shouldcheck = T;
+				/* check for changed message status */
+    if (LOCAL->mustcheck || LOCAL->shouldcheck) {
+      LOCAL->filetime = sbuf.st_mtime;
+      if (LOCAL->shouldcheck)	/* babble when we do this unilaterally */
+	mm_notify (stream,"[CHECK] Checking for flag updates",NIL);
+      while (i <= stream->nmsgs) tenex_elt (stream,i++);
+      LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
+    }
+				/* get shared parse/append permission */
+    if ((sbuf.st_size != LOCAL->filesize) &&
+	((ld = lockname (lock,stream->mailbox,LOCK_SH)) >= 0)) {
+				/* parse resulting mailbox */
+      r = (tenex_parse (stream)) ? T : NIL;
+      unlockfd (ld,lock);	/* release shared parse/append permission */
+    }
+  }
+  return r;			/* return result of the parse */
+}
+
+
+/* Tenex mail check mailbox (reparses status too)
+ * Accepts: MAIL stream
+ */
+
+void tenex_check (MAILSTREAM *stream)
+{
+				/* mark that a check is desired */
+  if (LOCAL) LOCAL->mustcheck = T;
+  if (tenex_ping (stream)) mm_log ("Check completed",(long) NIL);
+}
+
+/* Tenex mail expunge mailbox
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long tenex_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  long ret;
+  struct utimbuf times;
+  struct stat sbuf;
+  off_t pos = 0;
+  int ld;
+  unsigned long i = 1;
+  unsigned long j,k,m,recent;
+  unsigned long n = 0;
+  unsigned long delta = 0;
+  char lock[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  if (!(ret = (sequence ? ((options & EX_UID) ?
+			   mail_uid_sequence (stream,sequence) :
+			   mail_sequence (stream,sequence)) : LONGT) &&
+	tenex_ping (stream)));	/* parse sequence if given, ping stream */
+  else if (stream->rdonly) mm_log ("Expunge ignored on readonly mailbox",WARN);
+  else {
+    if (LOCAL->filetime && !LOCAL->shouldcheck) {
+      fstat (LOCAL->fd,&sbuf);	/* get current write time */
+      if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
+    }
+				/* get exclusive access */
+    if ((ld = lockname (lock,stream->mailbox,LOCK_EX)) < 0)
+      mm_log ("Unable to lock expunge mailbox",ERROR);
+				/* make sure see any newly-arrived messages */
+    else if (!tenex_parse (stream));
+				/* get exclusive access */
+    else if (flock (LOCAL->fd,LOCK_EX|LOCK_NB)) {
+      flock (LOCAL->fd,LOCK_SH);/* recover previous lock */
+      mm_log ("Can't expunge because mailbox is in use by another process",
+	      ERROR);
+      unlockfd (ld,lock);	/* release exclusive parse/append permission */
+    }
+
+    else {
+      mm_critical (stream);	/* go critical */
+      recent = stream->recent;	/* get recent now that pinged and locked */
+				/* for each message */
+      while (i <= stream->nmsgs) {
+				/* get cache element */
+	elt = tenex_elt (stream,i);
+				/* number of bytes to smash or preserve */
+	k = elt->private.special.text.size + tenex_size (stream,i);
+				/* if need to expunge this message */
+	if (elt->deleted && (sequence ? elt->sequence : T)) {
+				/* if recent, note one less recent message */
+	  if (elt->recent) --recent;
+	  delta += k;		/* number of bytes to delete */
+				/* notify upper levels */
+	  mail_expunged (stream,i);
+	  n++;			/* count up one more expunged message */
+	}
+	else if (i++ && delta) {/* preserved message */
+				/* first byte to preserve */
+	  j = elt->private.special.offset;
+	  do {			/* read from source position */
+	    m = min (k,LOCAL->buflen);
+	    lseek (LOCAL->fd,j,L_SET);
+	    read (LOCAL->fd,LOCAL->buf,m);
+	    pos = j - delta;	/* write to destination position */
+	    while (T) {
+	      lseek (LOCAL->fd,pos,L_SET);
+	      if (write (LOCAL->fd,LOCAL->buf,m) > 0) break;
+	      mm_notify (stream,strerror (errno),WARN);
+	      mm_diskerror (stream,errno,T);
+	    }
+	    pos += m;		/* new position */
+	    j += m;		/* next chunk, perhaps */
+	  } while (k -= m);	/* until done */
+				/* note the new address of this text */
+	  elt->private.special.offset -= delta;
+	}
+				/* preserved but no deleted messages */
+	else pos = elt->private.special.offset + k;
+      }
+
+      if (n) {			/* truncate file after last message */
+	if (pos != (LOCAL->filesize -= delta)) {
+	  sprintf (LOCAL->buf,
+		   "Calculated size mismatch %lu != %lu, delta = %lu",
+		   (unsigned long) pos,(unsigned long) LOCAL->filesize,delta);
+	  mm_log (LOCAL->buf,WARN);
+	  LOCAL->filesize = pos;/* fix it then */
+	}
+	ftruncate (LOCAL->fd,LOCAL->filesize);
+	sprintf (LOCAL->buf,"Expunged %lu messages",n);
+				/* output the news */
+	mm_log (LOCAL->buf,(long) NIL);
+      }
+      else mm_log ("No messages deleted, so no update needed",(long) NIL);
+      fsync (LOCAL->fd);	/* force disk update */
+      fstat (LOCAL->fd,&sbuf);	/* get new write time */
+      times.modtime = LOCAL->filetime = sbuf.st_mtime;
+      times.actime = time (0);	/* reset atime to now */
+      utime (stream->mailbox,&times);
+      mm_nocritical (stream);	/* release critical */
+				/* notify upper level of new mailbox size */
+      mail_exists (stream,stream->nmsgs);
+      mail_recent (stream,recent);
+      flock (LOCAL->fd,LOCK_SH);/* allow sharers again */
+      unlockfd (ld,lock);	/* release exclusive parse/append permission */
+    }
+  }
+  return ret;
+}
+
+/* Tenex mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if success, NIL if failed
+ */
+
+long tenex_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  struct stat sbuf;
+  struct utimbuf times;
+  MESSAGECACHE *elt;
+  unsigned long i,j,k;
+  long ret = LONGT;
+  int fd,ld;
+  char file[MAILTMPLEN],lock[MAILTMPLEN];
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+				/* make sure valid mailbox */
+  if (!tenex_isvalid (mailbox,file)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
+    return NIL;
+  case 0:			/* merely empty file? */
+    break;
+  case EACCES:			/* file protected */
+    sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
+    MM_LOG (LOCAL->buf,ERROR);
+    return NIL;
+  case EINVAL:
+    if (pc) return (*pc) (stream,sequence,mailbox,options);
+    sprintf (LOCAL->buf,"Invalid Tenex-format mailbox name: %.80s",mailbox);
+    mm_log (LOCAL->buf,ERROR);
+    return NIL;
+  default:
+    if (pc) return (*pc) (stream,sequence,mailbox,options);
+    sprintf (LOCAL->buf,"Not a Tenex-format mailbox: %.80s",mailbox);
+    mm_log (LOCAL->buf,ERROR);
+    return NIL;
+  }
+  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+	mail_sequence (stream,sequence))) return NIL;
+				/* got file? */  
+  if ((fd = open (file,O_BINARY|O_RDWR|O_CREAT,S_IREAD|S_IWRITE)) < 0) {
+    sprintf (LOCAL->buf,"Unable to open copy mailbox: %.80s",strerror (errno));
+    mm_log (LOCAL->buf,ERROR);
+    return NIL;
+  }
+  mm_critical (stream);		/* go critical */
+				/* get exclusive parse/append permission */
+  if (flock (fd,LOCK_SH) || ((ld = lockname (lock,file,LOCK_EX)) < 0)) {
+    mm_log ("Unable to lock copy mailbox",ERROR);
+    mm_nocritical (stream);
+    return NIL;
+  }
+  fstat (fd,&sbuf);		/* get current file size */
+  lseek (fd,sbuf.st_size,L_SET);/* move to end of file */
+
+				/* for each requested message */
+  for (i = 1; ret && (i <= stream->nmsgs); i++) 
+    if ((elt = mail_elt (stream,i))->sequence) {
+      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
+				/* number of bytes to copy */
+      k = elt->private.special.text.size + tenex_size (stream,i);
+      do {			/* read from source position */
+	j = min (k,LOCAL->buflen);
+	read (LOCAL->fd,LOCAL->buf,j);
+	if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
+      } while (ret && (k -= j));/* until done */
+    }
+				/* delete all requested messages */
+  if (ret && (options & CP_MOVE)) {
+    sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno));
+    mm_log (LOCAL->buf,ERROR);
+    ftruncate (fd,sbuf.st_size);
+  }
+				/* set atime to now-1 if successful copy */
+  if (ret) times.actime = time (0) - 1;
+				/* else preserved \Marked status */
+  else times.actime = (sbuf.st_ctime > sbuf.st_atime) ?
+	 sbuf.st_atime : time (0);
+  times.modtime = sbuf.st_mtime;/* preserve mtime */
+  utime (file,&times);		/* set the times */
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+  close (fd);			/* close the file */
+  mm_nocritical (stream);	/* release critical */
+				/* delete all requested messages */
+  if (ret && (options & CP_MOVE)) {
+    for (i = 1; i <= stream->nmsgs; i++)
+      if ((elt = tenex_elt (stream,i))->sequence) {
+	elt->deleted = T;	/* mark message deleted */
+				/* recalculate status */
+	tenex_update_status (stream,i,NIL);
+      }
+    if (!stream->rdonly) {	/* make sure the update takes */
+      fsync (LOCAL->fd);
+      fstat (LOCAL->fd,&sbuf);	/* get current write time */
+      times.modtime = LOCAL->filetime = sbuf.st_mtime;
+      times.actime = time (0);	/* make sure atime remains greater */
+      utime (stream->mailbox,&times);
+    }
+  }
+  if (ret && mail_parameters (NIL,GET_COPYUID,NIL))
+    mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN);
+  return ret;
+}
+
+/* Tenex mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long tenex_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct stat sbuf;
+  int fd,ld,c;
+  char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  struct utimbuf times;
+  FILE *df;
+  MESSAGECACHE elt;
+  long f;
+  unsigned long i,j,uf,size;
+  STRING *message;
+  long ret = LONGT;
+				/* default stream to prototype */
+  if (!stream) stream = &tenexproto;
+				/* make sure valid mailbox */
+  if (!tenex_isvalid (mailbox,file)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    if (!compare_cstring (mailbox,"INBOX")) tenex_create (NIL,"INBOX");
+    else {
+      mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+      return NIL;
+    }
+				/* falls through */
+  case 0:			/* merely empty file? */
+    break;
+  case EACCES:			/* file protected */
+    sprintf (tmp,"Can't access destination: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  case EINVAL:
+    sprintf (tmp,"Invalid TENEX-format mailbox name: %.80s",mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;
+  default:
+    sprintf (tmp,"Not a TENEX-format mailbox: %.80s",mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* get first message */
+  if (!(*af) (stream,data,&flags,&date,&message)) return NIL;
+
+				/* open destination mailbox */
+  if (((fd = open (file,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IREAD|S_IWRITE))
+       < 0) || !(df = fdopen (fd,"ab"))) {
+    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* get parse/append permission */
+  if (flock (fd,LOCK_SH) || ((ld = lockname (lock,file,LOCK_EX)) < 0)) {
+    mm_log ("Unable to lock append mailbox",ERROR);
+    close (fd);
+    return NIL;
+  }
+  mm_critical (stream);		/* go critical */
+  fstat (fd,&sbuf);		/* get current file size */
+  errno = 0;
+  do {				/* parse flags */
+    if (!SIZE (message)) {	/* guard against zero-length */
+      mm_log ("Append of zero-length message",ERROR);
+      ret = NIL;
+      break;
+    }
+    f = mail_parse_flags (stream,flags,&i);
+				/* reverse bits (dontcha wish we had CIRC?) */
+    for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i)));
+    if (date) {			/* parse date if given */
+      if (!mail_parse_date (&elt,date)) {
+	sprintf (tmp,"Bad date in append: %.80s",date);
+	mm_log (tmp,ERROR);
+	ret = NIL;		/* mark failure */
+	break;
+      }
+      mail_date (tmp,&elt);	/* write preseved date */
+    }
+    else internal_date (tmp);	/* get current date in IMAP format */
+    i = GETPOS (message);	/* remember current position */
+    for (j = SIZE (message), size = 0; j; --j)
+      if (SNX (message) != '\015') ++size;
+    SETPOS (message,i);		/* restore position */
+				/* write header */
+    if (fprintf (df,"%s,%lu;%010lo%02lo\n",tmp,size,uf,(unsigned long) f) < 0)
+      ret = NIL;
+    else {			/* write message */
+      while (size) if ((c = 0xff & SNX (message)) != '\015') {
+	if (putc (c,df) != EOF) --size;
+	else break;
+      }
+				/* get next message */
+      if (size || !(*af) (stream,data,&flags,&date,&message)) ret = NIL;
+    }
+  } while (ret && message);
+				/* if error... */
+  if (!ret || (fflush (df) == EOF)) {
+    ftruncate (fd,sbuf.st_size);/* revert file */
+    close (fd);			/* make sure fclose() doesn't corrupt us */
+    if (errno) {
+      sprintf (tmp,"Message append failed: %s",strerror (errno));
+      mm_log (tmp,ERROR);
+    }
+    ret = NIL;
+  }
+  if (ret) times.actime = time (0) - 1;
+				/* else preserved \Marked status */
+  else times.actime = (sbuf.st_ctime > sbuf.st_atime) ?
+	 sbuf.st_atime : time (0);
+  times.modtime = sbuf.st_mtime;/* preserve mtime */
+  utime (file,&times);		/* set the times */
+  fclose (df);			/* close the file */
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+  mm_nocritical (stream);	/* release critical */
+  if (ret && mail_parameters (NIL,GET_APPENDUID,NIL))
+    mm_log ("Can not return meaningful APPENDUID with this mailbox format",
+	    WARN);
+  return ret;
+}
+
+/* Internal routines */
+
+
+/* Tenex mail return internal message size in bytes
+ * Accepts: MAIL stream
+ *	    message #
+ * Returns: internal size of message
+ */
+
+unsigned long tenex_size (MAILSTREAM *stream,unsigned long m)
+{
+  MESSAGECACHE *elt = mail_elt (stream,m);
+  return ((m < stream->nmsgs) ? mail_elt (stream,m+1)->private.special.offset :
+	  LOCAL->filesize) -
+	    (elt->private.special.offset + elt->private.special.text.size);
+}
+
+/* Tenex mail parse mailbox
+ * Accepts: MAIL stream
+ * Returns: T if parse OK
+ *	    NIL if failure, stream aborted
+ */
+
+long tenex_parse (MAILSTREAM *stream)
+{
+  struct stat sbuf;
+  MESSAGECACHE *elt = NIL;
+  unsigned char c,*s,*t,*x;
+  char tmp[MAILTMPLEN];
+  unsigned long i,j;
+  long curpos = LOCAL->filesize;
+  long nmsgs = stream->nmsgs;
+  long recent = stream->recent;
+  short added = NIL;
+  short silent = stream->silent;
+  fstat (LOCAL->fd,&sbuf);	/* get status */
+  if (sbuf.st_size < curpos) {	/* sanity check */
+    sprintf (tmp,"Mailbox shrank from %ld to %ld!",curpos,sbuf.st_size);
+    mm_log (tmp,ERROR);
+    tenex_close (stream,NIL);
+    return NIL;
+  }
+  stream->silent = T;		/* don't pass up mm_exists() events yet */
+  while (sbuf.st_size - curpos){/* while there is stuff to parse */
+				/* get to that position in the file */
+    lseek (LOCAL->fd,curpos,L_SET);
+    if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) {
+      sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s",
+	       (unsigned long) curpos,(unsigned long) sbuf.st_size,
+	       i ? strerror (errno) : "no data read");
+      mm_log (tmp,ERROR);
+      tenex_close (stream,NIL);
+      return NIL;
+    }
+    LOCAL->buf[i] = '\0';	/* tie off buffer just in case */
+    if (!(s = strchr (LOCAL->buf,'\012'))) {
+      sprintf (tmp,"Unable to find newline at %lu in %lu bytes, text: %s",
+	       (unsigned long) curpos,i,(char *) LOCAL->buf);
+      mm_log (tmp,ERROR);
+      tenex_close (stream,NIL);
+      return NIL;
+    }
+    *s = '\0';			/* tie off header line */
+    i = (s + 1) - LOCAL->buf;	/* note start of text offset */
+    if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) {
+      sprintf (tmp,"Unable to parse internal header at %lu: %s",
+	       (unsigned long) curpos,(char *) LOCAL->buf);
+      mm_log (tmp,ERROR);
+      tenex_close (stream,NIL);
+      return NIL;
+    }
+    *s++ = '\0'; *t++ = '\0';	/* tie off fields */
+
+    added = T;			/* note that a new message was added */
+				/* swell the cache */
+    mail_exists (stream,++nmsgs);
+				/* instantiate an elt for this message */
+    (elt = mail_elt (stream,nmsgs))->valid = T;
+    elt->private.uid = ++stream->uid_last;
+				/* note file offset of header */
+    elt->private.special.offset = curpos;
+				/* in case error */
+    elt->private.special.text.size = 0;
+				/* header size not known yet */
+    elt->private.msg.header.text.size = 0;
+    x = s;			/* parse the header components */
+    if (mail_parse_date (elt,LOCAL->buf) &&
+	(elt->private.msg.full.text.size = strtoul (s,(char **) &s,10)) &&
+	(!(s && *s)) && isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) &&
+	isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) &&
+	isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) &&
+	isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12])
+      elt->private.special.text.size = i;
+    else {			/* oops */
+      sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s",
+	       curpos,(char *) LOCAL->buf,(char *) x,(char *) t);
+      mm_log (tmp,ERROR);
+      tenex_close (stream,NIL);
+      return NIL;
+    }
+				/* make sure didn't run off end of file */
+    if ((curpos += (elt->private.msg.full.text.size + i)) > sbuf.st_size) {
+      sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
+	       elt->private.special.offset,(unsigned long) curpos,
+	       (unsigned long) sbuf.st_size);
+      mm_log (tmp,ERROR);
+      tenex_close (stream,NIL);
+      return NIL;
+    }
+    c = t[10];			/* remember first system flags byte */
+    t[10] = '\0';		/* tie off flags */
+    j = strtoul (t,NIL,8);	/* get user flags value */
+    t[10] = c;			/* restore first system flags byte */
+				/* set up all valid user flags (reversed!) */
+    while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
+		  stream->user_flags[i]) elt->user_flags |= 1 << i;
+				/* calculate system flags */
+    if ((j = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T;
+    if (j & fDELETED) elt->deleted = T;
+    if (j & fFLAGGED) elt->flagged = T;
+    if (j & fANSWERED) elt->answered = T;
+    if (j & fDRAFT) elt->draft = T;
+    if (!(j & fOLD)) {		/* newly arrived message? */
+      elt->recent = T;
+      recent++;			/* count up a new recent message */
+				/* mark it as old */
+      tenex_update_status (stream,nmsgs,NIL);
+    }
+  }
+  fsync (LOCAL->fd);		/* make sure all the fOLD flags take */
+				/* update parsed file size and time */
+  LOCAL->filesize = sbuf.st_size;
+  fstat (LOCAL->fd,&sbuf);	/* get status again to ensure time is right */
+  LOCAL->filetime = sbuf.st_mtime;
+  if (added && !stream->rdonly){/* make sure atime updated */
+    struct utimbuf times;
+    times.actime = time (0);
+    times.modtime = LOCAL->filetime;
+    utime (stream->mailbox,&times);
+  }
+  stream->silent = silent;	/* can pass up events now */
+  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
+  mail_recent (stream,recent);	/* and of change in recent messages */
+  return LONGT;			/* return the winnage */
+}
+
+/* Tenex get cache element with status updating from file
+ * Accepts: MAIL stream
+ *	    message number
+ * Returns: cache element
+ */
+
+MESSAGECACHE *tenex_elt (MAILSTREAM *stream,unsigned long msgno)
+{
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  struct {			/* old flags */
+    unsigned int seen : 1;
+    unsigned int deleted : 1;
+    unsigned int flagged : 1;
+    unsigned int answered : 1;
+    unsigned int draft : 1;
+    unsigned long user_flags;
+  } old;
+  old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged;
+  old.answered = elt->answered; old.draft = elt->draft;
+  old.user_flags = elt->user_flags;
+  tenex_read_flags (stream,elt);
+  if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
+      (old.flagged != elt->flagged) || (old.answered != elt->answered) ||
+      (old.draft != elt->draft) || (old.user_flags != elt->user_flags))
+    mm_flags (stream,msgno);	/* let top level know */
+  return elt;
+}
+
+
+/* Tenex read flags from file
+ * Accepts: MAIL stream
+ * Returns: cache element
+ */
+
+void tenex_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  unsigned long i,j;
+				/* noop if readonly and have valid flags */
+  if (stream->rdonly && elt->valid) return;
+				/* set the seek pointer */
+  lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	 elt->private.special.text.size - 13,L_SET);
+				/* read the new flags */
+  if (read (LOCAL->fd,LOCAL->buf,12) < 0) {
+    sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno));
+    fatal (LOCAL->buf);
+  }
+				/* calculate system flags */
+  i = (((LOCAL->buf[10]-'0') * 8) + LOCAL->buf[11]-'0');
+  elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL;
+  elt->flagged = i & fFLAGGED ? T : NIL;
+  elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL;
+  LOCAL->buf[10] = '\0';	/* tie off flags */
+  j = strtoul(LOCAL->buf,NIL,8);/* get user flags value */
+				/* set up all valid user flags (reversed!) */
+  while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
+		stream->user_flags[i]) elt->user_flags |= 1 << i;
+  elt->valid = T;		/* have valid flags now */
+}
+
+/* Tenex update status string
+ * Accepts: MAIL stream
+ *	    message number
+ *	    flag saying whether or not to sync
+ */
+
+void tenex_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag)
+{
+  struct utimbuf times;
+  struct stat sbuf;
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  unsigned long j,k = 0;
+				/* readonly */
+  if (stream->rdonly || !elt->valid) tenex_read_flags (stream,elt);
+  else {			/* readwrite */
+    j = elt->user_flags;	/* get user flags */
+				/* reverse bits (dontcha wish we had CIRC?) */
+    while (j) k |= 1 << (29 - find_rightmost_bit (&j));
+				/* print new flag string */
+    sprintf (LOCAL->buf,"%010lo%02o",k,(unsigned)
+	     (fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
+	      (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
+	      (fDRAFT * elt->draft)));
+    while (T) {			/* get to that place in the file */
+      lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	     elt->private.special.text.size - 13,L_SET);
+				/* write new flags */
+      if (write (LOCAL->fd,LOCAL->buf,12) > 0) break;
+      mm_notify (stream,strerror (errno),WARN);
+      mm_diskerror (stream,errno,T);
+    }
+    if (syncflag) {		/* sync if requested */
+      fsync (LOCAL->fd);
+      fstat (LOCAL->fd,&sbuf);	/* get new write time */
+      times.modtime = LOCAL->filetime = sbuf.st_mtime;
+      times.actime = time (0);	/* make sure read is later */
+      utime (stream->mailbox,&times);
+    }
+  }
+}
+
+/* Tenex locate header for a message
+ * Accepts: MAIL stream
+ *	    message number
+ *	    pointer to returned header size
+ * Returns: position of header in file
+ */
+
+unsigned long tenex_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			    unsigned long *size)
+{
+  unsigned long siz;
+  long i = 0;
+  char c = '\0';
+  char *s = NIL;
+  MESSAGECACHE *elt = tenex_elt (stream,msgno);
+  unsigned long ret = elt->private.special.offset +
+    elt->private.special.text.size;
+  unsigned long msiz = tenex_size (stream,msgno);
+				/* is header size known? */
+  if (!(*size = elt->private.msg.header.text.size)) {
+    lseek (LOCAL->fd,ret,L_SET);/* get to header position */
+				/* search message for LF LF */
+    for (siz = 0; siz < msiz; siz++) {
+      if (--i <= 0)		/* read another buffer as necessary */
+	read (LOCAL->fd,s = LOCAL->buf,i = min (msiz-siz,(long) MAILTMPLEN));
+				/* two newline sequence? */
+      if ((c == '\012') && (*s == '\012')) {
+				/* yes, note for later */
+	elt->private.msg.header.text.size = (*size = siz + 1);
+	return ret;		/* return to caller */
+      }
+      else c = *s++;		/* next character */
+    }
+				/* header consumes entire message */
+    elt->private.msg.header.text.size = *size = msiz;
+  }
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/unixnt.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,2297 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX mail routines
+ *
+ * Author:	Mark Crispin
+ *		UW Technology
+ *		University of Washington
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	20 December 1989
+ * Last Edited:	27 March 2008
+ */
+
+
+/*				DEDICATION
+ *
+ *  This file is dedicated to my dog, Unix, also known as Yun-chan and
+ * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast.  Unix
+ * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after
+ * a two-month bout with cirrhosis of the liver.
+ *
+ *  He was a dear friend, and I miss him terribly.
+ *
+ *  Lift a leg, Yunie.  Luv ya forever!!!!
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "mail.h"
+#include "osdep.h"
+#include <time.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/utime.h>
+#include "unixnt.h"
+#include "pseudo.h"
+#include "fdstring.h"
+#include "misc.h"
+#include "dummy.h"
+
+/* UNIX I/O stream local data */
+
+typedef struct unix_local {
+  unsigned int dirty : 1;	/* disk copy needs updating */
+  unsigned int ddirty : 1;	/* double-dirty, ping becomes checkpoint */
+  unsigned int pseudo : 1;	/* uses a pseudo message */
+  unsigned int appending : 1;	/* don't mark new messages as old */
+  int fd;			/* mailbox file descriptor */
+  int ld;			/* lock file descriptor */
+  char *lname;			/* lock file name */
+  off_t filesize;		/* file size parsed */
+  time_t filetime;		/* last file time */
+  unsigned char *buf;		/* temporary buffer */
+  unsigned long buflen;		/* current size of temporary buffer */
+  unsigned long uid;		/* current text uid */
+  SIZEDTEXT text;		/* current text */
+  unsigned long textlen;	/* current text length */
+  char *line;			/* returned line */
+  char *linebuf;		/* line readin buffer */
+  unsigned long linebuflen;	/* current line readin buffer length */
+} UNIXLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((UNIXLOCAL *) stream->local)
+
+
+/* UNIX protected file structure */
+
+typedef struct unix_file {
+  MAILSTREAM *stream;		/* current stream */
+  off_t curpos;			/* current file position */
+  off_t protect;		/* protected position */
+  off_t filepos;		/* current last written file position */
+  char *buf;			/* overflow buffer */
+  size_t buflen;		/* current overflow buffer length */
+  char *bufpos;			/* current buffer position */
+} UNIXFILE;
+
+/* Function prototypes */
+
+DRIVER *unix_valid (char *name);
+void *unix_parameters (long function,void *value);
+void unix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void unix_list (MAILSTREAM *stream,char *ref,char *pat);
+void unix_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long unix_create (MAILSTREAM *stream,char *mailbox);
+long unix_delete (MAILSTREAM *stream,char *mailbox);
+long unix_rename (MAILSTREAM *stream,char *old,char *newname);
+MAILSTREAM *unix_open (MAILSTREAM *stream);
+void unix_close (MAILSTREAM *stream,long options);
+char *unix_header (MAILSTREAM *stream,unsigned long msgno,
+		   unsigned long *length,long flags);
+long unix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+char *unix_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
+		      unsigned long *length,long flags);
+void unix_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
+long unix_ping (MAILSTREAM *stream);
+void unix_check (MAILSTREAM *stream);
+long unix_expunge (MAILSTREAM *stream,char *sequence,long options);
+long unix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long unix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+int unix_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
+		     STRING *msg);
+int unix_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set);
+
+void unix_abort (MAILSTREAM *stream);
+char *unix_file (char *dst,char *name);
+int unix_lock (char *file,int flags,int mode,char *lock,int op);
+void unix_unlock (int fd,MAILSTREAM *stream,char *lock);
+int unix_parse (MAILSTREAM *stream,char *lock,int op);
+char *unix_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size);
+unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr);
+unsigned long unix_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt,
+			    unsigned long uid,long flag);
+long unix_rewrite (MAILSTREAM *stream,unsigned long *nexp,char *lock,
+		   long flags);
+long unix_extend (MAILSTREAM *stream,unsigned long size);
+void unix_write (UNIXFILE *f,char *s,unsigned long i);
+void unix_phys_write (UNIXFILE *f,char *buf,size_t size);
+
+/* UNIX mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER unixdriver = {
+  "unix",			/* driver name */
+				/* driver flags */
+  DR_LOCAL|DR_MAIL|DR_NONEWMAILRONLY|DR_XPOINT,
+  (DRIVER *) NIL,		/* next driver */
+  unix_valid,			/* mailbox is valid for us */
+  unix_parameters,		/* manipulate parameters */
+  unix_scan,			/* scan mailboxes */
+  unix_list,			/* list mailboxes */
+  unix_lsub,			/* list subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  unix_create,			/* create mailbox */
+  unix_delete,			/* delete mailbox */
+  unix_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  unix_open,			/* open mailbox */
+  unix_close,			/* close mailbox */
+  NIL,				/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  unix_header,			/* fetch message header */
+  unix_text,			/* fetch message text */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  NIL,				/* modify flags */
+  unix_flagmsg,			/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  unix_ping,			/* ping mailbox to see if still alive */
+  unix_check,			/* check for new messages */
+  unix_expunge,			/* expunge deleted messages */
+  unix_copy,			/* copy messages to another mailbox */
+  unix_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM unixproto = {&unixdriver};
+
+				/* driver parameters */
+static long unix_fromwidget = T;
+
+/* UNIX mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *unix_valid (char *name)
+{
+  int fd;
+  DRIVER *ret = NIL;
+  int c,r;
+  char tmp[MAILTMPLEN],file[MAILTMPLEN],*s,*t;
+  struct stat sbuf;
+  struct utimbuf times;
+  errno = EINVAL;		/* assume invalid argument */
+				/* must be non-empty file */
+  if ((t = dummy_file (file,name)) && !stat (t,&sbuf) &&
+      ((sbuf.st_mode & S_IFMT) == S_IFREG)) {
+    if (!sbuf.st_size)errno = 0;/* empty file */
+    else if ((fd = open (file,O_BINARY|O_RDONLY,NIL)) >= 0) {
+      memset (tmp,'\0',MAILTMPLEN);
+      if (read (fd,tmp,MAILTMPLEN-1) <= 0) errno = -1;
+      else {			/* ignore leading whitespace */
+	for (s = tmp,c = '\n';
+	     (*s == '\r') || (*s == '\n') || (*s == ' ') || (*s == '\t');
+	     c = *s++);
+	if (c == '\n') {	/* at start of a line? */
+	  VALID (s,t,r,c);	/* yes, validate format */
+	  if (r) ret = &unixdriver;
+	  else errno = -1;	/* invalid format */
+	}
+      }
+      close (fd);		/* close the file */
+				/* \Marked status? */
+      if ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) {
+				/* yes, preserve atime and mtime */
+	times.actime = sbuf.st_atime;
+	times.modtime = sbuf.st_mtime;
+	utime (file,&times);	/* set the times */
+      }
+    }
+  }
+  return ret;			/* return what we should */
+}
+/* UNIX manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *unix_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case SET_FROMWIDGET:
+    unix_fromwidget = (long) value;
+  case GET_FROMWIDGET:
+    ret = (void *) unix_fromwidget;
+    break;
+  }
+  return ret;
+}
+
+/* UNIX mail scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void unix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* UNIX mail list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void unix_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_list (NIL,ref,pat);
+}
+
+
+/* UNIX mail list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void unix_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_lsub (NIL,ref,pat);
+}
+
+/* UNIX mail create mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long unix_create (MAILSTREAM *stream,char *mailbox)
+{
+  char *s,mbx[MAILTMPLEN],tmp[MAILTMPLEN];
+  long ret = NIL;
+  int fd;
+  time_t ti = time (0);
+  if (!(s = dummy_file (mbx,mailbox))) {
+    sprintf (tmp,"Can't create %.80s: invalid name",mailbox);
+    mm_log (tmp,ERROR);
+  }
+				/* create underlying file */
+  else if (dummy_create_path (stream,s,NIL)) {
+    if ((s = strrchr (s,'\\')) && !s[1]) ret = T;
+    if ((fd = open (mbx,O_WRONLY|O_BINARY,NIL)) < 0) {
+      sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno));
+      mm_log (tmp,ERROR);
+      unlink (mbx);		/* delete the file */
+    }
+    else {			/* initialize header */
+      memset (tmp,'\0',MAILTMPLEN);
+      sprintf (tmp,"From %s %s",pseudo_from,ctime (&ti));
+      if (s = strpbrk (tmp,"\r\n")) *s = '\0';
+      strcat (tmp,"\r\nDate: ");
+      rfc822_fixed_date (s = tmp + strlen (tmp));
+      sprintf (s += strlen (s),	/* write the pseudo-header */
+	       "\r\nFrom: %s <%s@%s>\r\nSubject: %s\r\nX-IMAP: %010lu 0000000000\r\nStatus: RO\r\n\r\n%s\r\n\r\n",
+	       pseudo_name,pseudo_from,mylocalhost (),pseudo_subject,
+	       (unsigned long) ti,pseudo_msg);
+      if (write (fd,tmp,strlen (tmp)) > 0) {
+	close (fd);		/* close file */
+	ret = T;
+      }
+      else {
+	sprintf (tmp,"Can't initialize mailbox node %.80s: %s",mbx,
+		 strerror (errno));
+	mm_log (tmp,ERROR);
+	close (fd);		/* close file before unlinking */
+	unlink (mbx);		/* delete the file */
+      }
+    }
+  }
+  return ret;
+}
+
+/* UNIX mail delete mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long unix_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return unix_rename (stream,mailbox,NIL);
+}
+
+
+/* UNIX mail rename mailbox
+ * Accepts: MAIL stream
+ *	    old mailbox name
+ *	    new mailbox name (or NIL for delete)
+ * Returns: T on success, NIL on failure
+ */
+
+long unix_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  long ret = NIL;
+  char c,*s = NIL;
+  char tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN],lockx[MAILTMPLEN];
+  int fd,ld;
+  struct stat sbuf;
+  mm_critical (stream);		/* get the c-client lock */
+  if (!dummy_file (file,old) ||
+      (newname && (!(s = dummy_file (tmp,newname)) ||
+		   ((s = strrchr (s,'\\')) && !s[1]))))
+    sprintf (tmp,newname ?
+	     "Can't rename mailbox %.80s to %.80s: invalid name" :
+	     "Can't delete mailbox %.80s: invalid name",
+	     old,newname);
+  else if ((ld = lockname (lock,file,NIL)) < 0)
+    sprintf (tmp,"Can't get lock for mailbox %.80s",old);
+
+  else {			/* lock out other c-clients */
+    if (flock (ld,LOCK_EX|LOCK_NB)) {
+      close (ld);		/* couldn't lock, give up on it then */
+      sprintf (tmp,"Mailbox %.80s is in use by another process",old);
+    }
+				/* lock out non c-client applications */
+    else if ((fd = unix_lock (file,O_BINARY|O_RDWR,S_IREAD|S_IWRITE,lockx,
+			      LOCK_EX)) < 0)
+      sprintf (tmp,"Can't lock mailbox %.80s: %s",old,strerror (errno));
+    else {
+      unix_unlock(fd,NIL,lockx);/* pacify evil NTFS */
+      if (newname) {		/* want rename? */
+				/* found superior to destination name? */
+	if ((s = strrchr (tmp,'\\')) && (s != tmp) &&
+	    ((tmp[1] != ':') || (s != tmp + 2))) {
+	  c = s[1];		/* remember character after delimiter */
+	  *s = s[1] = '\0';	/* tie off name at delimiter */
+				/* name doesn't exist, create it */
+	  if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) {
+	    *s = '\\';		/* restore delimiter */
+	    if (!dummy_create (stream,newname)) {
+	      flock (ld,LOCK_UN);
+	      close (ld);	/* close c-client lock */
+	      unlink (lock);	/* and delete it */
+	      mm_nocritical (stream);
+	      return NIL;	/* couldn't create superior */
+	    }
+	  }
+	  else *s = '\\';	/* restore delimiter */
+	  s[1] = c;		/* restore character after delimiter */
+	}
+	if (rename (file,tmp))
+	  sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
+		   strerror (errno));
+	else ret = T;		/* set success */
+      }
+      else if (unlink (file))	/* want delete */
+	sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
+      else ret = T;		/* set success */
+      flock (ld,LOCK_UN);	/* release c-client lock */
+      close (ld);		/* close c-client lock */
+      unlink (lock);		/* and delete it */
+    }
+  }
+  mm_nocritical (stream);	/* no longer critical */
+  if (!ret) mm_log (tmp,ERROR);	/* log error */
+  return ret;			/* return success or failure */
+}
+
+/* UNIX mail open
+ * Accepts: Stream to open
+ * Returns: Stream on success, NIL on failure
+ */
+
+MAILSTREAM *unix_open (MAILSTREAM *stream)
+{
+  int fd;
+  char tmp[MAILTMPLEN];
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return &unixproto;
+  if (stream->local) fatal ("unix recycle stream");
+  stream->local = memset (fs_get (sizeof (UNIXLOCAL)),0,sizeof (UNIXLOCAL));
+				/* note if an INBOX or not */
+  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
+				/* canonicalize the stream mailbox name */
+  if (!dummy_file (tmp,stream->mailbox)) {
+    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* flush old name */
+  fs_give ((void **) &stream->mailbox);
+				/* save canonical name */
+  stream->mailbox = cpystr (tmp);
+  LOCAL->fd = LOCAL->ld = -1;	/* no file or state locking yet */
+  LOCAL->buf = (char *) fs_get ((LOCAL->buflen = CHUNKSIZE) + 1);
+  LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE);
+  LOCAL->text.size = CHUNKSIZE - 1;
+  LOCAL->linebuf = (char *) fs_get (CHUNKSIZE);
+  LOCAL->linebuflen = CHUNKSIZE - 1;
+  stream->sequence++;		/* bump sequence number */
+  if (!stream->rdonly) {	/* make lock for read/write access */
+    if ((fd = lockname (tmp,stream->mailbox,NIL)) < 0)
+      mm_log ("Can't open mailbox lock, access is readonly",WARN);
+				/* can get the lock? */
+    else if (flock (fd,LOCK_EX|LOCK_NB)) {
+      if (!stream->silent)
+	mm_log ("Mailbox is open by another process, access is readonly",WARN);
+      close (fd);
+    }
+    else {			/* got the lock, nobody else can alter state */
+      LOCAL->ld = fd;		/* note lock's fd and name */
+      LOCAL->lname = cpystr (tmp);
+    }
+  }
+
+				/* parse mailbox */
+  stream->nmsgs = stream->recent = 0;
+				/* will we be able to get write access? */
+  if ((LOCAL->ld >= 0) && access (stream->mailbox,02) && (errno == EACCES)) {
+    mm_log ("Can't get write access to mailbox, access is readonly",WARN);
+    flock (LOCAL->ld,LOCK_UN);	/* release the lock */
+    close (LOCAL->ld);		/* close the lock file */
+    LOCAL->ld = -1;		/* no more lock fd */
+    unlink (LOCAL->lname);	/* delete it */
+  }
+				/* reset UID validity */
+  stream->uid_validity = stream->uid_last = 0;
+  if (stream->silent && !stream->rdonly && (LOCAL->ld < 0))
+    unix_abort (stream);	/* abort if can't get RW silent stream */
+				/* parse mailbox */
+  else if (unix_parse (stream,tmp,LOCK_SH)) {
+    unix_unlock (LOCAL->fd,stream,tmp);
+    mail_unlock (stream);
+    mm_nocritical (stream);	/* done with critical */
+  }
+  if (!LOCAL) return NIL;	/* failure if stream died */
+				/* make sure upper level knows readonly */
+  stream->rdonly = (LOCAL->ld < 0);
+				/* notify about empty mailbox */
+  if (!(stream->nmsgs || stream->silent)) mm_log ("Mailbox is empty",NIL);
+  if (!stream->rdonly) {	/* flags stick if readwrite */
+    stream->perm_seen = stream->perm_deleted =
+      stream->perm_flagged = stream->perm_answered = stream->perm_draft = T;
+				/* have permanent keywords */
+    stream->perm_user_flags = 0xffffffff;
+				/* and maybe can create them too */
+    stream->kwd_create = stream->user_flags[NUSERFLAGS-1] ? NIL : T;
+  }
+  return stream;		/* return stream alive to caller */
+}
+
+
+/* UNIX mail close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void unix_close (MAILSTREAM *stream,long options)
+{
+  int silent = stream->silent;
+  stream->silent = T;		/* go silent */
+				/* expunge if requested */
+  if (options & CL_EXPUNGE) unix_expunge (stream,NIL,NIL);
+				/* else dump final checkpoint */
+  else if (LOCAL->dirty) unix_check (stream);
+  stream->silent = silent;	/* restore old silence state */
+  unix_abort (stream);		/* now punt the file and local data */
+}
+
+/* UNIX mail fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+				/* lines to filter from header */
+static STRINGLIST *unix_hlines = NIL;
+
+char *unix_header (MAILSTREAM *stream,unsigned long msgno,
+		   unsigned long *length,long flags)
+{
+  MESSAGECACHE *elt;
+  unsigned char *s;
+  *length = 0;			/* default to empty */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+  elt = mail_elt (stream,msgno);/* get cache */
+  if (!unix_hlines) {		/* once only code */
+    STRINGLIST *lines = unix_hlines = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "Status"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-Status"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-Keywords"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-UID"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-IMAP"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-IMAPbase"));
+  }
+				/* go to header position */
+  lseek (LOCAL->fd,elt->private.special.offset +
+	 elt->private.msg.header.offset,L_SET);
+
+  if (flags & FT_INTERNAL) {	/* initial data OK? */
+    if (elt->private.msg.header.text.size > LOCAL->buflen) {
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
+				     elt->private.msg.header.text.size) + 1);
+    }
+				/* read message */
+    read (LOCAL->fd,LOCAL->buf,elt->private.msg.header.text.size);
+				/* got text, tie off string */
+    LOCAL->buf[*length = elt->private.msg.header.text.size] = '\0';
+  }
+  else {			/* need to make a CRLF version */
+    read (LOCAL->fd,s = (char *) fs_get (elt->private.msg.header.text.size+1),
+	  elt->private.msg.header.text.size);
+				/* tie off string, and convert to CRLF */
+    s[elt->private.msg.header.text.size] = '\0';
+    *length = unix_crlfcpy (&LOCAL->buf,&LOCAL->buflen,s,
+			    elt->private.msg.header.text.size);
+    fs_give ((void **) &s);	/* free readin buffer */
+  }
+  *length = mail_filter (LOCAL->buf,*length,unix_hlines,FT_NOT);
+  return LOCAL->buf;		/* return processed copy */
+}
+
+/* UNIX mail fetch message text
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned stringstruct
+ *	    option flags
+ * Returns: T on success, NIL if failure
+ */
+
+long unix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  char *s;
+  unsigned long i;
+  MESSAGECACHE *elt;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+  elt = mail_elt (stream,msgno);/* get cache element */
+				/* if message not seen */
+  if (!(flags & FT_PEEK) && !elt->seen) {
+				/* mark message seen and dirty */
+    elt->seen = elt->private.dirty = LOCAL->dirty = T;
+    mm_flags (stream,msgno);
+  }
+  s = unix_text_work (stream,elt,&i,flags);
+  INIT (bs,mail_string,s,i);	/* set up stringstruct */
+  return T;			/* success */
+}
+
+/* UNIX mail fetch message text worker routine
+ * Accepts: MAIL stream
+ *	    message cache element
+ *	    pointer to returned header text length
+ *	    option flags
+ */
+
+char *unix_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
+		      unsigned long *length,long flags)
+{
+  FDDATA d;
+  STRING bs;
+  unsigned char c,*s,tmp[CHUNKSIZE];
+				/* go to text position */
+  lseek (LOCAL->fd,elt->private.special.offset +
+	 elt->private.msg.text.offset,L_SET);
+  if (flags & FT_INTERNAL) {	/* initial data OK? */
+    if (elt->private.msg.text.text.size > LOCAL->buflen) {
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
+				     elt->private.msg.text.text.size) + 1);
+    }
+				/* read message */
+    read (LOCAL->fd,LOCAL->buf,elt->private.msg.text.text.size);
+				/* got text, tie off string */
+    LOCAL->buf[*length = elt->private.msg.text.text.size] = '\0';
+    return LOCAL->buf;
+  }
+				/* have it cached already? */
+  if (elt->private.uid != LOCAL->uid) {
+				/* not cached, cache it now */
+    LOCAL->uid = elt->private.uid;
+				/* is buffer big enough? */
+    if (elt->rfc822_size > LOCAL->text.size) {
+      /* excessively conservative, but the right thing is too hard to do */
+      fs_give ((void **) &LOCAL->text.data);
+      LOCAL->text.data = (unsigned char *)
+	fs_get ((LOCAL->text.size = elt->rfc822_size) + 1);
+    }
+    d.fd = LOCAL->fd;		/* yes, set up file descriptor */
+    d.pos = elt->private.special.offset + elt->private.msg.text.offset;
+    d.chunk = tmp;		/* initial buffer chunk */
+    d.chunksize = CHUNKSIZE;	/* file chunk size */
+    INIT (&bs,fd_string,&d,elt->private.msg.text.text.size);
+    for (s = (char *) LOCAL->text.data; SIZE (&bs);) switch (c = SNX (&bs)) {
+    case '\r':			/* carriage return seen */
+      *s++ = c;			/* copy it and any succeeding LF */
+      if (SIZE (&bs) && (CHR (&bs) == '\n')) *s++ = SNX (&bs);
+      break;
+    case '\n':
+      *s++ = '\r';		/* insert a CR */
+    default:
+      *s++ = c;			/* copy characters */
+    }
+    *s = '\0';			/* tie off buffer */
+				/* calculate length of cached data */
+    LOCAL->textlen = s - LOCAL->text.data;
+  }
+  *length = LOCAL->textlen;	/* return from cache */
+  return (char *) LOCAL->text.data;
+}
+
+/* UNIX per-message modify flag
+ * Accepts: MAIL stream
+ *	    message cache element
+ */
+
+void unix_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+				/* only after finishing */
+  if (elt->valid) elt->private.dirty = LOCAL->dirty = T;
+}
+
+
+/* UNIX mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ */
+
+long unix_ping (MAILSTREAM *stream)
+{
+  char lock[MAILTMPLEN];
+  struct stat sbuf;
+				/* big no-op if not readwrite */
+  if (LOCAL && (LOCAL->ld >= 0) && !stream->lock) {
+    if (stream->rdonly) {	/* does he want to give up readwrite? */
+				/* checkpoint if we changed something */
+      if (LOCAL->dirty) unix_check (stream);
+      flock (LOCAL->ld,LOCK_UN);/* release readwrite lock */
+      close (LOCAL->ld);	/* close the readwrite lock file */
+      LOCAL->ld = -1;		/* no more readwrite lock fd */
+      unlink (LOCAL->lname);	/* delete the readwrite lock file */
+    }
+    else {			/* get current mailbox size */
+      if (LOCAL->fd >= 0) fstat (LOCAL->fd,&sbuf);
+      else if (stat (stream->mailbox,&sbuf)) {
+	sprintf (LOCAL->buf,"Mailbox stat failed, aborted: %s",
+		 strerror (errno));
+	MM_LOG (LOCAL->buf,ERROR);
+	unix_abort (stream);
+	return NIL;
+      }
+				/* parse if mailbox changed */
+      if ((LOCAL->ddirty || (sbuf.st_size != LOCAL->filesize)) &&
+	  unix_parse (stream,lock,LOCK_EX)) {
+				/* force checkpoint if double-dirty */
+	if (LOCAL->ddirty) unix_rewrite (stream,NIL,lock,NIL);
+				/* unlock mailbox */
+	else unix_unlock (LOCAL->fd,stream,lock);
+	mail_unlock (stream);	/* and stream */
+	mm_nocritical (stream);	/* done with critical */
+      }
+    }
+  }
+  return LOCAL ? LONGT : NIL;	/* return if still alive */
+}
+
+/* UNIX mail check mailbox
+ * Accepts: MAIL stream
+ */
+
+void unix_check (MAILSTREAM *stream)
+{
+  char lock[MAILTMPLEN];
+				/* parse and lock mailbox */
+  if (LOCAL && (LOCAL->ld >= 0) && !stream->lock &&
+      unix_parse (stream,lock,LOCK_EX)) {
+				/* any unsaved changes? */
+    if (LOCAL->dirty && unix_rewrite (stream,NIL,lock,NIL)) {
+      if (!stream->silent) mm_log ("Checkpoint completed",NIL);
+    }
+				/* no checkpoint needed, just unlock */
+    else unix_unlock (LOCAL->fd,stream,lock);
+    mail_unlock (stream);	/* unlock the stream */
+    mm_nocritical (stream);	/* done with critical */
+  }
+}
+
+
+/* UNIX mail expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long unix_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  long ret;
+  unsigned long i;
+  char lock[MAILTMPLEN];
+  char *msg = NIL;
+				/* parse and lock mailbox */
+  if (ret = (sequence ? ((options & EX_UID) ?
+			 mail_uid_sequence (stream,sequence) :
+			 mail_sequence (stream,sequence)) : LONGT) &&
+      LOCAL && (LOCAL->ld >= 0) && !stream->lock &&
+      unix_parse (stream,lock,LOCK_EX)) {
+				/* check expunged messages if not dirty */
+    for (i = 1; !LOCAL->dirty && (i <= stream->nmsgs); i++) {
+      MESSAGECACHE *elt = mail_elt (stream,i);
+      if (mail_elt (stream,i)->deleted) LOCAL->dirty = T;
+    }
+    if (!LOCAL->dirty) {	/* not dirty and no expunged messages */
+      unix_unlock (LOCAL->fd,stream,lock);
+      msg = "No messages deleted, so no update needed";
+    }
+    else if (unix_rewrite (stream,&i,lock,sequence ? LONGT : NIL)) {
+      if (i) sprintf (msg = LOCAL->buf,"Expunged %lu messages",i);
+      else msg = "Mailbox checkpointed, but no messages expunged";
+    }
+				/* rewrite failed */
+    else unix_unlock (LOCAL->fd,stream,lock);
+    mail_unlock (stream);	/* unlock the stream */
+    mm_nocritical (stream);	/* done with critical */
+    if (msg && !stream->silent) mm_log (msg,NIL);
+  }
+  else if (!stream->silent) mm_log("Expunge ignored on readonly mailbox",WARN);
+  return ret;
+}
+
+/* UNIX mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if copy successful, else NIL
+ */
+
+long unix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  struct stat sbuf;
+  int fd;
+  char *s,file[MAILTMPLEN],lock[MAILTMPLEN];
+  struct utimbuf times;
+  unsigned long i,j;
+  MESSAGECACHE *elt;
+  long ret = T;
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+  copyuid_t cu = (copyuid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ?
+			      NIL : mail_parameters (NIL,GET_COPYUID,NIL));
+  SEARCHSET *source = cu ? mail_newsearchset () : NIL;
+  SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
+  MAILSTREAM *tstream = NIL;
+  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+	mail_sequence (stream,sequence))) return NIL;
+				/* make sure destination is valid */
+  if (!(unix_valid (mailbox) || !errno))
+    switch (errno) {
+    case ENOENT:			/* no such file? */
+      if (compare_cstring (mailbox,"INBOX")) {
+	mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
+	return NIL;
+      }
+      if (pc) return (*pc) (stream,sequence,mailbox,options);
+      unix_create (NIL,"INBOX");/* create empty INBOX */
+    case EACCES:		/* file protected */
+      sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
+      MM_LOG (LOCAL->buf,ERROR);
+      return NIL;
+    case EINVAL:
+      if (pc) return (*pc) (stream,sequence,mailbox,options);
+      sprintf (LOCAL->buf,"Invalid UNIX-format mailbox name: %.80s",mailbox);
+      mm_log (LOCAL->buf,ERROR);
+      return NIL;
+    default:
+      if (pc) return (*pc) (stream,sequence,mailbox,options);
+      sprintf (LOCAL->buf,"Not a UNIX-format mailbox: %.80s",mailbox);
+      mm_log (LOCAL->buf,ERROR);
+      return NIL;
+    }
+
+				/* try to open rewrite for UIDPLUS */
+  if ((tstream = mail_open_work (&unixdriver,NIL,mailbox,
+				 OP_SILENT|OP_NOKOD)) && tstream->rdonly)
+    tstream = mail_close (tstream);
+  if (cu && !tstream) {		/* wanted a COPYUID? */
+    sprintf (LOCAL->buf,"Unable to write-open mailbox for COPYUID: %.80s",
+	     mailbox);
+    MM_LOG (LOCAL->buf,WARN);
+    cu = NIL;			/* don't try to do COPYUID */
+  }
+  LOCAL->buf[0] = '\0';
+  mm_critical (stream);		/* go critical */
+  if ((fd = unix_lock (dummy_file (file,mailbox),
+		       O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IREAD|S_IWRITE,
+		       lock,LOCK_EX)) < 0) {
+    mm_nocritical (stream);	/* done with critical */
+    sprintf (LOCAL->buf,"Can't open destination mailbox: %s",strerror (errno));
+    mm_log (LOCAL->buf,ERROR);	/* log the error */
+    return NIL;			/* failed */
+  }
+  fstat (fd,&sbuf);		/* get current file size */
+				/* write all requested messages to mailbox */
+  for (i = 1; ret && (i <= stream->nmsgs); i++)
+    if ((elt = mail_elt (stream,i))->sequence) {
+      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
+      read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size);
+      if (LOCAL->buf[(j = elt->private.special.text.size) - 2] != '\r') {
+	LOCAL->buf[j - 1] = '\r';
+	LOCAL->buf[j++] = '\n';
+      }
+      if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
+      else {			/* internal header succeeded */
+	s = unix_header (stream,i,&j,NIL);
+				/* header size, sans trailing newline */
+	if (j && (s[j - 4] == '\r')) j -= 2;
+	if (write (fd,s,j) < 0) ret = NIL;
+	else {			/* message header succeeded */
+	  j = tstream ?		/* write UIDPLUS data if have readwrite */
+	    unix_xstatus (stream,LOCAL->buf,elt,++(tstream->uid_last),LONGT) :
+	    unix_xstatus (stream,LOCAL->buf,elt,NIL,NIL);
+	  if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
+	  else {		/* message status succeeded */
+	    s = unix_text_work (stream,elt,&j,NIL);
+	    if ((write (fd,s,j) < 0) || (write (fd,"\r\n",2) < 0))
+	      ret = NIL;
+	    else if (cu) {	/* need to pass back new UID? */
+	      mail_append_set (source,mail_uid (stream,i));
+	      mail_append_set (dest,tstream->uid_last);
+	    }
+	  }
+	}
+      }
+    }
+
+  if (!ret || fsync (fd)) {	/* force out the update */
+    sprintf (LOCAL->buf,"Message copy failed: %s",strerror (errno));
+    ftruncate (fd,sbuf.st_size);
+    ret = NIL;
+  }
+				/* force UIDVALIDITY assignment now */
+  if (tstream && !tstream->uid_validity)
+    tstream->uid_validity = (unsigned long) time (0);
+				/* return sets if doing COPYUID */
+  if (cu && ret) (*cu) (stream,mailbox,tstream->uid_validity,source,dest);
+  else {			/* flush any sets we may have built */
+    mail_free_searchset (&source);
+    mail_free_searchset (&dest);
+  }
+  times.modtime = time (0);	/* set mtime to now */
+				/* set atime to now-1 if successful copy */
+  if (ret) times.actime = times.modtime - 1;
+		
+  else times.actime =		/* else preserve \Marked status */
+	 ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ?
+	 sbuf.st_atime : times.modtime;
+  utime (file,&times);		/* set the times */
+  unix_unlock (fd,NIL,lock);	/* unlock and close mailbox */
+  if (tstream) {		/* update last UID if we can */
+    UNIXLOCAL * local = (UNIXLOCAL *) tstream->local;
+    local->dirty = T;		/* do a rewrite */
+    local->appending = T;	/* but not at the cost of marking as old */
+    tstream = mail_close (tstream);
+  }
+				/* log the error */
+  if (!ret) mm_log (LOCAL->buf,ERROR);
+				/* delete if requested message */
+  else if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++)
+    if ((elt = mail_elt (stream,i))->sequence)
+      elt->deleted = elt->private.dirty = LOCAL->dirty = T;
+  mm_nocritical (stream);	/* release critical */
+  return ret;
+}
+
+/* UNIX mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+#define BUFLEN 8*MAILTMPLEN
+
+long unix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct stat sbuf;
+  int fd;
+  unsigned long i;
+  char *flags,*date,buf[BUFLEN],tmp[MAILTMPLEN],file[MAILTMPLEN],
+    lock[MAILTMPLEN];
+  struct utimbuf times;
+  FILE *sf,*df;
+  MESSAGECACHE elt;
+  STRING *message;
+  unsigned long uidlocation = 0;
+  appenduid_t au = (appenduid_t)
+    (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL :
+     mail_parameters (NIL,GET_APPENDUID,NIL));
+  SEARCHSET *dst = au ? mail_newsearchset () : NIL;
+  long ret = LONGT;
+  MAILSTREAM *tstream = NIL;
+  if (!stream) {		/* stream specified? */
+    stream = &unixproto;	/* no, default stream to prototype */
+    for (i = 0; i < NUSERFLAGS && stream->user_flags[i]; ++i)
+      fs_give ((void **) &stream->user_flags[i]);
+  }
+  if (!unix_valid (mailbox)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    if (!compare_cstring (mailbox,"INBOX")) {
+      mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+      return NIL;
+    }
+    unix_create (NIL,"INBOX");	/* create empty INBOX */
+  case 0:			/* merely empty file? */
+    tstream = stream;
+    break;
+  case EACCES:			/* file protected */
+    sprintf (tmp,"Can't access destination: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  case EINVAL:
+    sprintf (tmp,"Invalid UNIX-format mailbox name: %.80s",mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;
+  default:
+    sprintf (tmp,"Not a UNIX-format mailbox: %.80s",mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* get sniffing stream for keywords */
+  else if (!(tstream = mail_open (NIL,mailbox,
+				  OP_READONLY|OP_SILENT|OP_NOKOD|OP_SNIFF))) {
+    sprintf (tmp,"Unable to examine mailbox for APPEND: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+
+				/* get first message */
+  if (!(*af) (tstream,data,&flags,&date,&message)) return NIL;
+  if (!(sf = tmpfile ())) {	/* must have scratch file */
+    sprintf (tmp,".%lx.%lx",(unsigned long) time (0),(unsigned long)getpid ());
+    if (!stat (tmp,&sbuf) || !(sf = fopen (tmp,"wb+"))) {
+      sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno));
+      mm_log (tmp,ERROR);
+      return NIL;
+    }
+    unlink (tmp);
+  }
+  do {				/* parse date */
+    if (!date) rfc822_date (date = tmp);
+    if (!mail_parse_date (&elt,date)) {
+      sprintf (tmp,"Bad date in append: %.80s",date);
+      mm_log (tmp,ERROR);
+    }
+    else {			/* user wants to suppress time zones? */
+      if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) {
+	time_t when = mail_longdate (&elt);
+	date = ctime (&when);	/* use traditional date */
+      }
+				/* use POSIX-style date */
+      else date = mail_cdate (tmp,&elt);
+      if (!SIZE (message)) mm_log ("Append of zero-length message",ERROR);
+      else if (!unix_collect_msg (tstream,sf,flags,date,message)) {
+	sprintf (tmp,"Error writing scratch file: %.80s",strerror (errno));
+	mm_log (tmp,ERROR);
+      }
+				/* get next message */
+      else if ((*af) (tstream,data,&flags,&date,&message)) continue;
+    }
+    fclose (sf);		/* punt scratch file */
+    return NIL;			/* give up */
+  } while (message);		/* until no more messages */
+  if (fflush (sf)) {
+    sprintf (tmp,"Error finishing scratch file: %.80s",strerror (errno));
+    mm_log (tmp,ERROR);
+    fclose (sf);		/* punt scratch file */
+    return NIL;			/* give up */
+  }
+  i = ftell (sf);		/* size of scratch file */
+
+				/* close sniffing stream */
+  if (tstream != stream) tstream = mail_close (tstream);
+  mm_critical (stream);		/* go critical */
+				/* try to open readwrite for UIDPLUS */
+  if ((tstream = mail_open_work (&unixdriver,NIL,mailbox,
+				 OP_SILENT|OP_NOKOD)) && tstream->rdonly)
+    tstream = mail_close (tstream);
+  if (au && !tstream) {		/* wanted an APPENDUID? */
+    sprintf (tmp,"Unable to re-open mailbox for APPENDUID: %.80s",mailbox);
+    MM_LOG (tmp,WARN);
+    au = NIL;
+  }
+  if (((fd = unix_lock (dummy_file (file,mailbox),
+			O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IREAD|S_IWRITE,
+			lock,LOCK_EX)) < 0) || !(df = fdopen (fd,"ab"))) {
+    mm_nocritical (stream);	/* done with critical */
+    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+  fstat (fd,&sbuf);		/* get current file size */
+  rewind (sf);
+  times.modtime = time (0);	/* set mtime to now */
+				/* write all messages */
+  if (!unix_append_msgs (tstream,sf,df,au ? dst : NIL) ||
+      (fflush (df) == EOF) || fsync (fd)) {
+    sprintf (buf,"Message append failed: %s",strerror (errno));
+    mm_log (buf,ERROR);
+    ftruncate (fd,sbuf.st_size);/* revert file */
+    times.actime =		/* preserve \Marked status */
+      ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ?
+      sbuf.st_atime : times.modtime;
+    ret = NIL;			/* return error */
+  }
+				/* set atime to now-1 if successful copy */
+  else times.actime = times.modtime - 1;
+  utime (file,&times);		/* set the times */
+  fclose (sf);			/* done with scratch file */
+				/* force UIDVALIDITY assignment now */
+  if (tstream && !tstream->uid_validity)
+    tstream->uid_validity = (unsigned long) time (0);
+				/* return sets if doing APPENDUID */
+  if (au && ret) (*au) (mailbox,tstream->uid_validity,dst);
+  else mail_free_searchset (&dst);
+  flock (fd,LOCK_UN);		/* unlock mailbox (can't use unix_unlock() */
+  if (lock && *lock) unlink (lock);
+  fclose (df);			/* close mailbox */
+  if (tstream) {		/* update last UID if we can */
+    UNIXLOCAL * local = (UNIXLOCAL *) tstream->local;
+    local->dirty = T;		/* do a rewrite */
+    local->appending = T;	/* but not at the cost of marking as old */
+    tstream = mail_close (tstream);
+  }
+  mm_nocritical (stream);	/* release critical */
+  return ret;
+}
+
+/* Collect and write single message to append scratch file
+ * Accepts: MAIL stream
+ *	    scratch file
+ *	    flags
+ *	    date
+ *	    message stringstruct
+ * Returns: NIL if write error, else T
+ */
+
+int unix_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
+		     STRING *msg)
+{
+  unsigned char *s,*t;
+  unsigned long uf;
+  long f = mail_parse_flags (stream,flags,&uf);
+				/* write metadata */
+  if (fprintf (sf,"%ld %lu ",f,SIZE (msg) + 2) < 0) return NIL;
+  for (s = date; *s; *s++) switch (*s) {
+  default:
+    if (putc (*s,sf) == EOF) return NIL;
+  case '\r': case '\n':
+    break;
+  }
+  if (fputs ("\r\n",sf) == EOF) return NIL;
+  while (uf)			/* write user flags */    
+    if ((s = stream->user_flags[find_rightmost_bit (&uf)]) &&
+	(fprintf (sf," %s",s) < 0)) return NIL;
+  if (fputs ("\r\n",sf) == EOF) return NIL;
+  while (SIZE (msg)) {		/* copy text to scratch file */
+    for (s = (unsigned char *) msg->curpos, t = s + msg->cursize; s < t; ++s)
+      if (!*s) *s = 0x80;	/* disallow NUL */
+				/* write buffered text */
+    if (fwrite (msg->curpos,1,msg->cursize,sf) == msg->cursize)
+      SETPOS (msg,GETPOS (msg) + msg->cursize);
+    else return NIL;		/* failed */
+  }
+				/* write trailing CRLF and return */
+  return (fputs ("\r\n",sf) == EOF) ? NIL : T;
+}
+
+/* Append messages from scratch file to mailbox
+ * Accepts: MAIL stream
+ *	    source file
+ *	    destination file
+ *	    uidset to update if non-NIL
+ * Returns: T if success, NIL if failure
+ */
+
+int unix_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set)
+{
+  int ti,zn,c;
+  long f;
+  unsigned long i,j;
+  char *x,tmp[MAILTMPLEN];
+  int hdrp = T;
+				/* get message metadata line */
+  while (fgets (tmp,MAILTMPLEN,sf)) {
+    if (!(isdigit (tmp[0]) && strchr (tmp,'\n'))) return NIL;
+    f = strtol (tmp,&x,10);	/* get flags */
+    if (!((*x++ == ' ') && isdigit (*x))) return NIL;
+    i = strtoul (x,&x,10);	/* get message size */
+    if ((*x++ != ' ') ||	/* build initial header */
+	(fprintf (df,"From %s@%s %sStatus: ",myusername(),mylocalhost(),x)<0)||
+	(f&fSEEN && (putc ('R',df) == EOF)) ||
+	(fputs ("\r\nX-Status: ",df) == EOF) ||
+	(f&fDELETED && (putc ('D',df) == EOF)) ||
+	(f&fFLAGGED && (putc ('F',df) == EOF)) ||
+	(f&fANSWERED && (putc ('A',df) == EOF)) ||
+	(f&fDRAFT && (putc ('T',df) == EOF)) ||
+	(fputs ("\r\nX-Keywords:",df) == EOF)) return NIL;
+				/* copy keywords */
+    while ((c = getc (sf)) != '\n') switch (c) {
+    case EOF:
+      return NIL;
+    default:
+      if (putc (c,df) == EOF) return NIL;
+    }
+    if ((putc ('\n',df) == EOF) ||
+	(set && (fprintf (df,"X-UID: %lu\r\n",++(stream->uid_last)) < 0)))
+      return NIL;
+
+    for (c = '\n'; i && fgets (tmp,MAILTMPLEN,sf); c = tmp[j-1]) {
+				/* get read line length */
+      if (i < (j = strlen (tmp))) fatal ("unix_append_msgs overrun");
+      i -= j;			/* number of bytes left */
+      if (!j) continue;		/* do nothing if line emptied */
+				/* complete line? */
+      if ((c == '\n')) switch (tmp[0]) {
+      case 'F':			/* possible "From " (case counts here) */
+	if ((j > 4) && (tmp[0] == 'F') && (tmp[1] == 'r') && (tmp[2] == 'o') &&
+	    (tmp[3] == 'm') && (tmp[4] == ' ')) {
+	  if (!unix_fromwidget) {
+	    VALID (tmp,x,ti,zn);/* conditional, only write widget if */
+	    if (!ti) break;	/*  it looks like a valid header */
+	  }			/* write the widget */
+	  if (putc ('>',df) == EOF) return NIL;
+	}
+	break;
+      case 'S': case 's':	/* possible "Status:" */
+	if (hdrp && (j > 6) && ((tmp[1] == 't') || (tmp[1] == 'T')) &&
+	    ((tmp[2] == 'a') || (tmp[2] == 'A')) &&
+	    ((tmp[3] == 't') || (tmp[3] == 'T')) &&
+	    ((tmp[4] == 'u') || (tmp[4] == 'U')) &&
+	    ((tmp[5] == 's') || (tmp[5] == 'S')) && (tmp[6] == ':') &&
+	    (fputs ("X-Original-",df) == EOF)) return NIL;
+	break;
+      case 'X': case 'x':	/* possible X-??? header */
+	if (hdrp && (tmp[1] == '-') &&
+				/* possible X-UID: */
+	    (((j > 5) && ((tmp[2] == 'U') || (tmp[2] == 'u')) &&
+	      ((tmp[3] == 'I') || (tmp[3] == 'i')) &&
+	      ((tmp[4] == 'D') || (tmp[4] == 'd')) && (tmp[5] == ':')) ||
+				/* possible X-IMAP: */
+	     ((j > 6) && ((tmp[2] == 'I') || (tmp[2] == 'i')) &&
+	      ((tmp[3] == 'M') || (tmp[3] == 'm')) &&
+	      ((tmp[4] == 'A') || (tmp[4] == 'a')) &&
+	      ((tmp[5] == 'P') || (tmp[5] == 'p')) &&
+	      ((tmp[6] == ':') ||
+				/* or X-IMAPbase: */
+	       ((j > 10) && ((tmp[6] == 'b') || (tmp[6] == 'B')) &&
+		((tmp[7] == 'a') || (tmp[7] == 'A')) &&
+		((tmp[8] == 's') || (tmp[8] == 'S')) &&
+		((tmp[9] == 'e') || (tmp[9] == 'E')) && (tmp[10] == ':')))) ||
+				/* possible X-Status: */
+	     ((j > 8) && ((tmp[2] == 'S') || (tmp[2] == 's')) &&
+	      ((tmp[3] == 't') || (tmp[3] == 'T')) &&
+	      ((tmp[4] == 'a') || (tmp[4] == 'A')) &&
+	      ((tmp[5] == 't') || (tmp[5] == 'T')) &&
+	      ((tmp[6] == 'u') || (tmp[6] == 'U')) &&
+	      ((tmp[7] == 's') || (tmp[7] == 'S')) && (tmp[8] == ':')) ||
+				/* possible X-Keywords: */
+	     ((j > 10) && ((tmp[2] == 'K') || (tmp[2] == 'k')) &&
+	      ((tmp[3] == 'e') || (tmp[3] == 'E')) &&
+	      ((tmp[4] == 'y') || (tmp[4] == 'Y')) &&
+	      ((tmp[5] == 'w') || (tmp[5] == 'W')) &&
+	      ((tmp[6] == 'o') || (tmp[6] == 'O')) &&
+	      ((tmp[7] == 'r') || (tmp[7] == 'R')) &&
+	      ((tmp[8] == 'd') || (tmp[8] == 'D')) &&
+	      ((tmp[9] == 's') || (tmp[9] == 'S')) && (tmp[10] == ':'))) &&
+	    (fputs ("X-Original-",df) == EOF)) return NIL;
+	break;
+      case '\n':		/* blank line */
+	hdrp = NIL;
+	break;
+      default:			/* nothing to do */
+	break;
+      }
+				/* just write the line */
+      if (fwrite (tmp,1,j,df) != j) return NIL;
+    }
+    if (i) return NIL;		/* didn't read entire message */
+				/* update set */
+    if (stream) mail_append_set (set,stream->uid_last);
+  }
+  return T;
+}
+
+/* Internal routines */
+
+
+/* UNIX mail abort stream
+ * Accepts: MAIL stream
+ */
+
+void unix_abort (MAILSTREAM *stream)
+{
+  if (LOCAL) {			/* only if a file is open */
+    if (LOCAL->fd >= 0) close (LOCAL->fd);
+    if (LOCAL->ld >= 0) {	/* have a mailbox lock? */
+      flock (LOCAL->ld,LOCK_UN);/* yes, release the lock */
+      close (LOCAL->ld);	/* close the lock file */
+      unlink (LOCAL->lname);	/* and delete it */
+    }
+    if (LOCAL->lname) fs_give ((void **) &LOCAL->lname);
+				/* free local text buffers */
+    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+    if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data);
+    if (LOCAL->linebuf) fs_give ((void **) &LOCAL->linebuf);
+    if (LOCAL->line) fs_give ((void **) &LOCAL->line);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+/* UNIX open and lock mailbox
+ * Accepts: file name to open/lock
+ *	    file open mode
+ *	    destination buffer for lock file name
+ *	    type of locking operation (LOCK_SH or LOCK_EX)
+ */
+
+int unix_lock (char *file,int flags,int mode,char *lock,int op)
+{
+  int fd,ld,j;
+  int i = LOCKTIMEOUT * 60 - 1;
+  char tmp[MAILTMPLEN];
+  time_t t;
+  struct stat sb;
+  sprintf (lock,"%s.lock",file);/* build lock filename */
+  do {				/* until OK or out of tries */
+    t = time (0);		/* get the time now */
+				/* try to get the lock */
+    if ((ld = open(lock,O_BINARY|O_WRONLY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE))>=0)
+      close (ld);		/* got it, close the lock file! */
+    else if (errno != EEXIST) {	/* miscellaneous error */
+      sprintf (tmp,"Error creating %.80s: %s",lock,strerror (errno));
+      if (!(i%15)) mm_log (tmp,WARN);
+    }
+				/* lock exists, still active? */
+    else if (!stat (lock,&sb) && (t > sb.st_ctime + LOCKTIMEOUT * 60) &&
+	     ((ld = open(lock,O_BINARY|O_WRONLY|O_CREAT,S_IREAD|S_IWRITE))>=0))
+      close (ld);		/* got timed-out lock file */
+    else {			/* active lock, try again */
+      if (!(i%15)) {
+	sprintf (tmp,"Mailbox %.80s is locked, will override in %d seconds...",
+		 file,i);
+	mm_log (tmp,WARN);
+      }
+      sleep (1);		/* wait a second before next retry */
+    }
+  } while (*lock && ld < 0 && i--);
+				/* open file */
+  if ((fd = open (file,flags,mode)) >= 0) flock (fd,op);
+  else {			/* open failed */
+    j = errno;			/* preserve error code */
+    if (*lock) unlink (lock);	/* flush the lock file if any */
+    errno = j;			/* restore error code */
+  }
+  return fd;
+}
+
+/* UNIX unlock and close mailbox
+ * Accepts: file descriptor
+ *	    (optional) mailbox stream to check atime/mtime
+ *	    (optional) lock file name
+ */
+
+void unix_unlock (int fd,MAILSTREAM *stream,char *lock)
+{
+  if (stream) {			/* need to muck with times? */
+    struct stat sbuf;
+    struct utimbuf times;
+    time_t now = time (0);
+    fstat (fd,&sbuf);		/* get file times */
+    if (LOCAL->ld >= 0) {	/* yes, readwrite session? */
+      times.actime = now;	/* set atime to now */
+				/* set mtime to (now - 1) if necessary */
+      times.modtime = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1;
+    }
+    else if (stream->recent) {	/* readonly with recent messages */
+      if ((sbuf.st_atime >= sbuf.st_mtime) ||
+	  (sbuf.st_atime >= sbuf.st_ctime))
+				/* keep past mtime, whack back atime */
+	times.actime = (times.modtime = (sbuf.st_mtime < now) ?
+			sbuf.st_mtime : now) - 1;
+      else now = 0;		/* no time change needed */
+    }
+				/* readonly with no recent messages */
+    else if ((sbuf.st_atime < sbuf.st_mtime) ||
+	     (sbuf.st_atime < sbuf.st_ctime)) {
+      times.actime = now;	/* set atime to now */
+				/* set mtime to (now - 1) if necessary */
+      times.modtime = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1;
+    }
+    else now = 0;		/* no time change needed */
+				/* set the times, note change */
+    if (now && !utime (stream->mailbox,&times))
+      LOCAL->filetime = times.modtime;
+  }
+  flock (fd,LOCK_UN);		/* release flock'ers */
+  if (!stream) close (fd);	/* close the file if no stream */
+				/* flush the lock file if any */
+  if (lock && *lock) unlink (lock);
+}
+
+/* UNIX mail parse and lock mailbox
+ * Accepts: MAIL stream
+ *	    space to write lock file name
+ *	    type of locking operation
+ * Returns: T if parse OK, critical & mailbox is locked shared; NIL if failure
+ */
+
+int unix_parse (MAILSTREAM *stream,char *lock,int op)
+{
+  int zn;
+  unsigned long i,j,k,m;
+  unsigned char c,*s,*t,*u,tmp[MAILTMPLEN],date[30];
+  int ti = 0,retain = T;
+  unsigned long nmsgs = stream->nmsgs;
+  unsigned long prevuid = nmsgs ? mail_elt (stream,nmsgs)->private.uid : 0;
+  unsigned long recent = stream->recent;
+  unsigned long oldnmsgs = stream->nmsgs;
+  short silent = stream->silent;
+  short pseudoseen = NIL;
+  struct stat sbuf;
+  STRING bs;
+  FDDATA d;
+  MESSAGECACHE *elt;
+  mail_lock (stream);		/* guard against recursion or pingers */
+				/* toss out previous descriptor */
+  if (LOCAL->fd >= 0) close (LOCAL->fd);
+  mm_critical (stream);		/* open and lock mailbox (shared OK) */
+  if ((LOCAL->fd = unix_lock (stream->mailbox,
+			      O_BINARY + ((LOCAL->ld >= 0) ? O_RDWR:O_RDONLY),
+			      NIL,lock,op)) < 0) {
+    sprintf (tmp,"Mailbox open failed, aborted: %s",strerror (errno));
+    mm_log (tmp,ERROR);
+    unix_abort (stream);
+    mail_unlock (stream);
+    mm_nocritical (stream);	/* done with critical */
+    return NIL;
+  }
+  fstat (LOCAL->fd,&sbuf);	/* get status */
+				/* validate change in size */
+  if (sbuf.st_size < LOCAL->filesize) {
+    sprintf (tmp,"Mailbox shrank from %lu to %lu bytes, aborted",
+	     (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
+    mm_log (tmp,ERROR);		/* this is pretty bad */
+    unix_unlock (LOCAL->fd,stream,lock);
+    unix_abort (stream);
+    mail_unlock (stream);
+    mm_nocritical (stream);	/* done with critical */
+    return NIL;
+  }
+
+				/* new data? */
+  else if (i = sbuf.st_size - LOCAL->filesize) {
+    d.fd = LOCAL->fd;		/* yes, set up file descriptor */
+    d.pos = LOCAL->filesize;	/* get to that position in the file */
+    d.chunk = LOCAL->buf;	/* initial buffer chunk */
+    d.chunksize = CHUNKSIZE;	/* file chunk size */
+    INIT (&bs,fd_string,&d,i);	/* initialize stringstruct */
+				/* skip leading whitespace for broken MTAs */
+    while (((c = CHR (&bs)) == '\n') || (c == '\r') ||
+	   (c == ' ') || (c == '\t')) SNX (&bs);
+    if (SIZE (&bs)) {		/* read new data */
+				/* remember internal header position */
+      j = LOCAL->filesize + GETPOS (&bs);
+      s = unix_mbxline (stream,&bs,&i);
+      t = NIL,zn = 0;
+      if (i) VALID (s,t,ti,zn);	/* see if valid From line */
+      if (!ti) {		/* someone pulled the rug from under us */
+	sprintf (tmp,"Unexpected changes to mailbox (try restarting): %.20s",
+		 (char *) s);
+	mm_log (tmp,ERROR);
+	unix_unlock (LOCAL->fd,stream,lock);
+	unix_abort (stream);
+	mail_unlock (stream);
+	mm_nocritical (stream);	/* done with critical */
+	return NIL;
+      }
+      stream->silent = T;	/* quell main program new message events */
+      do {			/* found a message */
+				/* instantiate first new message */
+	mail_exists (stream,++nmsgs);
+	(elt = mail_elt (stream,nmsgs))->valid = T;
+	recent++;		/* assume recent by default */
+	elt->recent = T;
+				/* note position/size of internal header */
+	elt->private.special.offset = j;
+	elt->private.msg.header.offset = elt->private.special.text.size = i;
+
+				/* generate plausible IMAPish date string */
+	date[2] = date[6] = date[20] = '-'; date[11] = ' ';
+	date[14] = date[17] = ':';
+				/* dd */
+	date[0] = t[ti - 2]; date[1] = t[ti - 1];
+				/* mmm */
+	date[3] = t[ti - 6]; date[4] = t[ti - 5]; date[5] = t[ti - 4];
+				/* hh */
+	date[12] = t[ti + 1]; date[13] = t[ti + 2];
+				/* mm */
+	date[15] = t[ti + 4]; date[16] = t[ti + 5];
+	if (t[ti += 6] == ':') {/* ss */
+	  date[18] = t[++ti]; date[19] = t[++ti];
+	  ti++;			/* move to space */
+	}
+	else date[18] = date[19] = '0';
+				/* yy -- advance over timezone if necessary */
+	if (zn == ti) ti += (((t[zn+1] == '+') || (t[zn+1] == '-')) ? 6 : 4);
+	date[7] = t[ti + 1]; date[8] = t[ti + 2];
+	date[9] = t[ti + 3]; date[10] = t[ti + 4];
+				/* zzz */
+	t = zn ? (t + zn + 1) : (unsigned char *) "LCL";
+	date[21] = *t++; date[22] = *t++; date[23] = *t++;
+	if ((date[21] != '+') && (date[21] != '-')) date[24] = '\0';
+	else {			/* numeric time zone */
+	  date[24] = *t++; date[25] = *t++;
+	  date[26] = '\0'; date[20] = ' ';
+	}
+				/* set internal date */
+	if (!mail_parse_date (elt,date)) {
+	  sprintf (tmp,"Unable to parse internal date: %s",(char *) date);
+	  mm_log (tmp,WARN);
+	}
+
+	do {			/* look for message body */
+	  s = t = unix_mbxline (stream,&bs,&i);
+	  if (i) switch (*s) {	/* check header lines */
+	  case 'X':		/* possible X-???: line */
+	    if (s[1] == '-') {	/* must be immediately followed by hyphen */
+				/* X-Status: becomes Status: in S case */
+	      if (s[2] == 'S' && s[3] == 't' && s[4] == 'a' && s[5] == 't' &&
+		  s[6] == 'u' && s[7] == 's' && s[8] == ':') s += 2;
+				/* possible X-Keywords */
+	      else if (s[2] == 'K' && s[3] == 'e' && s[4] == 'y' &&
+		       s[5] == 'w' && s[6] == 'o' && s[7] == 'r' &&
+		       s[8] == 'd' && s[9] == 's' && s[10] == ':') {
+		SIZEDTEXT uf;
+		retain = NIL;	/* don't retain continuation */
+		s += 11;	/* flush leading whitespace */
+		while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n'))){
+		  while (*s == ' ') s++;
+				/* find end of keyword */
+		  if (!(u = strpbrk (s," \n\r"))) u = s + strlen (s);
+				/* got a keyword? */
+		  if ((k = (u - s)) && (k <= MAXUSERFLAG)) {
+		    uf.data = (unsigned char *) s;
+		    uf.size = k;
+		    for (j = 0; (j < NUSERFLAGS) && stream->user_flags[j]; ++j)
+		      if (!compare_csizedtext (stream->user_flags[j],&uf)) {
+			elt->user_flags |= ((long) 1) << j;
+			break;
+		      }
+		  }
+		  s = u;	/* advance to next keyword */
+		}
+		break;
+	      }
+
+				/* possible X-IMAP */
+	      else if ((s[2] == 'I') && (s[3] == 'M') && (s[4] == 'A') &&
+		       (s[5] == 'P') && ((m = (s[6] == ':')) ||
+					 ((s[6] == 'b') && (s[7] == 'a') &&
+					  (s[8] == 's') && (s[9] == 'e') &&
+					  (s[10] == ':')))) {
+		retain = NIL;	/* don't retain continuation */
+		if ((nmsgs == 1) && !stream->uid_validity) {
+				/* advance to data */
+		  s += m ? 7 : 11;
+				/* flush whitespace */
+		  while (*s == ' ') s++;
+		  j = 0;	/* slurp UID validity */
+				/* found a digit? */
+		  while (isdigit (*s)) {
+		    j *= 10;	/* yes, add it in */
+		    j += *s++ - '0';
+		  }
+				/* flush whitespace */
+		  while (*s == ' ') s++;
+				/* must have valid UID validity and UID last */
+		  if (j && isdigit (*s)) {
+				/* pseudo-header seen if X-IMAP */
+		    if (m) pseudoseen = LOCAL->pseudo = T;
+				/* save UID validity */
+		    stream->uid_validity = j;
+		    j = 0;	/* slurp UID last */
+		    while (isdigit (*s)) {
+		      j *= 10;	/* yes, add it in */
+		      j += *s++ - '0';
+		    }
+				/* save UID last */
+		    stream->uid_last = j;
+				/* process keywords */
+		    for (j = 0; (*s != '\n') && ((*s != '\r')||(s[1] != '\n'));
+			 s = u,j++) {
+				/* flush leading whitespace */
+		      while (*s == ' ') s++;
+		      u = strpbrk (s," \n\r");
+				/* got a keyword? */
+		      if ((j < NUSERFLAGS) && (k = (u - s)) &&
+			  (k <= MAXUSERFLAG)) {
+			if (stream->user_flags[j])
+			  fs_give ((void **) &stream->user_flags[j]);
+			stream->user_flags[j] = (char *) fs_get (k + 1);
+			strncpy (stream->user_flags[j],s,k);
+			stream->user_flags[j][k] = '\0';
+		      }
+		    }
+		  }
+		}
+		break;
+	      }
+
+				/* possible X-UID */
+	      else if (s[2] == 'U' && s[3] == 'I' && s[4] == 'D' &&
+		       s[5] == ':') {
+		retain = NIL;	/* don't retain continuation */
+				/* only believe if have a UID validity */
+		if (stream->uid_validity && ((nmsgs > 1) || !pseudoseen)) {
+		  s += 6;	/* advance to UID value */
+				/* flush whitespace */
+		  while (*s == ' ') s++;
+		  j = 0;
+				/* found a digit? */
+		  while (isdigit (*s)) {
+		    j *= 10;	/* yes, add it in */
+		    j += *s++ - '0';
+		  }
+				/* flush remainder of line */
+		  while (*s != '\n') s++;
+				/* make sure not duplicated */
+		  if (elt->private.uid)
+		    sprintf (tmp,"Message %lu UID %lu already has UID %lu",
+			     pseudoseen ? elt->msgno - 1 : elt->msgno,
+			     j,elt->private.uid);
+				/* make sure UID doesn't go backwards */
+		  else if (j <= prevuid)
+		    sprintf (tmp,"Message %lu UID %lu less than %lu",
+			     pseudoseen ? elt->msgno - 1 : elt->msgno,
+			     j,prevuid + 1);
+#if 0	/* this is currently broken by UIDPLUS */
+				/* or skip by mailbox's recorded last */
+		  else if (j > stream->uid_last)
+		    sprintf (tmp,"Message %lu UID %lu greater than last %lu",
+			     pseudoseen ? elt->msgno - 1 : elt->msgno,
+			     j,stream->uid_last);
+#endif
+		  else {	/* normal UID case */
+		    prevuid = elt->private.uid = j;
+#if 1	/* temporary kludge for UIDPLUS */
+		    if (prevuid > stream->uid_last) {
+		      stream->uid_last = prevuid;
+		      LOCAL->ddirty = LOCAL->dirty = T;
+		    }		    
+#endif
+		    break;	/* exit this cruft */
+		  }
+		  mm_log (tmp,WARN);
+				/* invalidate UID validity */
+		  stream->uid_validity = 0;
+		  elt->private.uid = 0;
+		}
+		break;
+	      }
+	    }
+				/* otherwise fall into S case */
+
+	  case 'S':		/* possible Status: line */
+	    if (s[0] == 'S' && s[1] == 't' && s[2] == 'a' && s[3] == 't' &&
+		s[4] == 'u' && s[5] == 's' && s[6] == ':') {
+	      retain = NIL;	/* don't retain continuation */
+	      s += 6;		/* advance to status flags */
+	      do switch (*s++) {/* parse flags */
+	      case 'R':		/* message read */
+		elt->seen = T;
+		break;
+	      case 'O':		/* message old */
+		if (elt->recent) {
+		  elt->recent = NIL;
+		  recent--;	/* it really wasn't recent */
+		}
+		break;
+	      case 'D':		/* message deleted */
+		elt->deleted = T;
+		break;
+	      case 'F':		/* message flagged */
+		elt->flagged = T;
+		break;
+	      case 'A':		/* message answered */
+		elt->answered = T;
+		break;
+	      case 'T':		/* message is a draft */
+		elt->draft = T;
+		break;
+	      default:		/* some other crap */
+		break;
+	      } while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n')));
+	      break;		/* all done */
+	    }
+				/* otherwise fall into default case */
+
+	  default:		/* ordinary header line */
+	    if ((*s == 'S') || (*s == 's') ||
+		(((*s == 'X') || (*s == 'x')) && (s[1] == '-'))) {
+	      unsigned char *e,*v;
+				/* must match what mail_filter() does */
+	      for (u = s,v = tmp,e = u + min (i,MAILTMPLEN - 1);
+		   (u < e) && ((c = (*u ? *u : (*u = ' '))) != ':') &&
+		   ((c > ' ') || ((c != ' ') && (c != '\t') &&
+				  (c != '\r') && (c != '\n')));
+		   *v++ = *u++);
+	      *v = '\0';	/* tie off */
+				/* matches internal header? */
+	      if (!compare_cstring (tmp,"STATUS") ||
+		  !compare_cstring (tmp,"X-STATUS") ||
+		  !compare_cstring (tmp,"X-KEYWORDS") ||
+		  !compare_cstring (tmp,"X-UID") ||
+		  !compare_cstring (tmp,"X-IMAP") ||
+		  !compare_cstring (tmp,"X-IMAPBASE")) {
+		char err[MAILTMPLEN];
+		sprintf (err,"Discarding bogus %s header in message %lu",
+			 (char *) tmp,elt->msgno);
+		mm_log (err,WARN);
+		retain = NIL;	/* don't retain continuation */
+		break;		/* different case or something */
+	      }
+	    }
+				/* retain or non-continuation? */
+	    if (retain || ((*s != ' ') && (*s != '\t'))) {
+	      retain = T;	/* retaining continuation now */
+				/* line length in CRLF format newline */
+	      k = i + (((i < 2) || (s[i - 2] != '\r')) ? 1 : 0);
+				/* header size */
+	      elt->rfc822_size = elt->private.spare.data += k;
+	    }
+	    else {
+	      char err[MAILTMPLEN];
+	      sprintf (err,"Discarding bogus continuation in msg %lu: %.80s",
+		      elt->msgno,(char *) s);
+	      if (u = strpbrk (err,"\r\n")) *u = '\0';
+	      mm_log (err,WARN);
+	      break;		/* different case or something */
+	    }
+	    break;
+	  }
+	} while (i && (*t != '\n') && ((*t != '\r') || (t[1] != '\n')));
+				/* "internal" header sans trailing newline */
+	if (i) elt->private.spare.data -= 2;
+				/* assign a UID if none found */
+	if (((nmsgs > 1) || !pseudoseen) && !elt->private.uid) {
+	  prevuid = elt->private.uid = ++stream->uid_last;
+	  elt->private.dirty = T;
+	  LOCAL->ddirty = T;	/* force update */
+	}
+	else elt->private.dirty = elt->recent;
+
+				/* note size of header, location of text */
+	elt->private.msg.header.text.size = 
+	  (elt->private.msg.text.offset =
+	   (LOCAL->filesize + GETPOS (&bs)) - elt->private.special.offset) -
+	     elt->private.special.text.size;
+	k = m = 0;		/* no previous line size yet */
+				/* note current position */
+	j = LOCAL->filesize + GETPOS (&bs);
+	if (i) do {		/* look for next message */
+	  s = unix_mbxline (stream,&bs,&i);
+	  if (i) {		/* got new data? */
+	    VALID (s,t,ti,zn);	/* yes, parse line */
+	    if (!ti) {		/* not a header line, add it to message */
+	      if (s[i - 1] == '\n')
+		elt->rfc822_size += 
+		  k = i + (m = (((i < 2) || s[i - 2] != '\r') ? 1 : 0));
+	      else {		/* file does not end with newline! */
+		elt->rfc822_size += i;
+		k = m = 0;
+	      }
+				/* update current position */
+	      j = LOCAL->filesize + GETPOS (&bs);
+	    }
+	  }
+	} while (i && !ti);	/* until found a header */
+	elt->private.msg.text.text.size = j -
+	  (elt->private.special.offset + elt->private.msg.text.offset);
+	if (k == 2) {		/* last line was blank? */
+	  elt->private.msg.text.text.size -= (m ? 1 : 2);
+	  elt->rfc822_size -= 2;
+	}
+				/* until end of buffer */
+      } while (!stream->sniff && i);
+      if (pseudoseen) {		/* flush pseudo-message if present */
+				/* decrement recent count */
+	if (mail_elt (stream,1)->recent) recent--;
+				/* and the exists count */
+	mail_exists (stream,nmsgs--);
+	mail_expunged(stream,1);/* fake an expunge of that message */
+      }
+				/* need to start a new UID validity? */
+      if (!stream->uid_validity) {
+	stream->uid_validity = (unsigned long) time (0);
+	if (nmsgs) {		/* don't bother if empty file */
+				/* make dirty to restart UID epoch */
+	  LOCAL->ddirty = LOCAL->dirty = T;
+				/* need to rewrite msg 1 if not pseudo */
+	  if (!LOCAL->pseudo) mail_elt (stream,1)->private.dirty = T;
+	  mm_log ("Assigning new unique identifiers to all messages",NIL);
+	}
+      }
+      stream->nmsgs = oldnmsgs;	/* whack it back down */
+      stream->silent = silent;	/* restore old silent setting */
+				/* notify upper level of new mailbox sizes */
+      mail_exists (stream,nmsgs);
+      mail_recent (stream,recent);
+				/* mark dirty so O flags are set */
+      if (recent) LOCAL->dirty = T;
+    }
+  }
+				/* no change, don't babble if never got time */
+  else if (LOCAL->filetime && LOCAL->filetime != sbuf.st_mtime)
+    mm_log ("New mailbox modification time but apparently no changes",WARN);
+				/* update parsed file size and time */
+  LOCAL->filesize = sbuf.st_size;
+  LOCAL->filetime = sbuf.st_mtime;
+  return T;			/* return the winnage */
+}
+
+/* UNIX read line from mailbox
+ * Accepts: mail stream
+ *	    stringstruct
+ *	    pointer to line size
+ * Returns: pointer to input line
+ */
+
+char *unix_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size)
+{
+  unsigned long i,j,k,m;
+  char *s,*t,*te;
+  char *ret = "";
+				/* flush old buffer */
+  if (LOCAL->line) fs_give ((void **) &LOCAL->line);
+				/* if buffer needs refreshing */
+  if (!bs->cursize) SETPOS (bs,GETPOS (bs));
+  if (SIZE (bs)) {		/* find newline */
+				/* end of fast scan */
+    te = (t = (s = bs->curpos) + bs->cursize) - 12;
+    while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) {
+      --s;			/* back up */
+      break;			/* exit loop */
+    }
+				/* final character-at-a-time scan */
+    while ((s < t) && (*s != '\n')) ++s;
+				/* difficult case if line spans buffer */
+    if ((i = s - bs->curpos) == bs->cursize) {
+				/* have space in line buffer? */
+      if (i > LOCAL->linebuflen) {
+	fs_give ((void **) &LOCAL->linebuf);
+	LOCAL->linebuf = (char *) fs_get (LOCAL->linebuflen = i);
+      }
+				/* remember what we have so far */
+      memcpy (LOCAL->linebuf,bs->curpos,i);
+				/* load next buffer */
+      SETPOS (bs,k = GETPOS (bs) + i);
+				/* end of fast scan */
+      te = (t = (s = bs->curpos) + bs->cursize) - 12;
+				/* fast scan in overlap buffer */
+      while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) {
+	--s;			/* back up */
+	break;			/* exit loop */
+      }
+
+				/* final character-at-a-time scan */
+      while ((s < t) && (*s != '\n')) ++s;
+				/* huge line? */
+      if ((j = s - bs->curpos) == bs->cursize) {
+	SETPOS (bs,GETPOS (bs) + j);
+				/* look for end of line (s-l-o-w!!) */
+	for (m = SIZE (bs); m && (SNX (bs) != '\n'); --m,++j);
+	SETPOS (bs,k);		/* go back to where it started */
+      }
+				/* got size of data, make buffer for return */
+      ret = LOCAL->line = (char *) fs_get (i + j + 2);
+				/* copy first chunk */
+      memcpy (ret,LOCAL->linebuf,i);
+      while (j) {		/* copy remainder */
+	if (!bs->cursize) SETPOS (bs,GETPOS (bs));
+	memcpy (ret + i,bs->curpos,k = min (j,bs->cursize));
+	i += k;			/* account for this much read in */
+	j -= k;
+	bs->curpos += k;	/* increment new position */
+	bs->cursize -= k;	/* eat that many bytes */
+      }
+      if (!bs->cursize) SETPOS (bs,GETPOS (bs));
+				/* read newline at end */
+      if (SIZE (bs)) ret[i++] = SNX (bs);
+      ret[i] = '\0';		/* makes debugging easier */
+    }
+    else {			/* this is easy */
+      ret = bs->curpos;		/* string it at this position */
+      bs->curpos += ++i;	/* increment new position */
+      bs->cursize -= i;		/* eat that many bytes */
+    }
+    *size = i;			/* return that to user */
+  }
+  else *size = 0;		/* end of data, return empty */
+  return ret;
+}
+
+/* UNIX make pseudo-header
+ * Accepts: MAIL stream
+ *	    buffer to write pseudo-header
+ * Returns: length of pseudo-header
+ */
+
+unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr)
+{
+  int i;
+  char *s,*t,tmp[MAILTMPLEN];
+  time_t now = time(0);
+  rfc822_fixed_date (tmp);
+  sprintf (hdr,"From %s %.24s\r\nDate: %s\r\nFrom: %s <%s@%.80s>\r\nSubject: %s\r\nMessage-ID: <%lu@%.80s>\r\nX-IMAP: %010ld %010ld",
+	   pseudo_from,ctime (&now),
+	   tmp,pseudo_name,pseudo_from,mylocalhost (),pseudo_subject,
+	   (unsigned long) now,mylocalhost (),stream->uid_validity,
+	   stream->uid_last);
+  for (t = hdr + strlen (hdr),i = 0; i < NUSERFLAGS; ++i)
+    if (stream->user_flags[i])
+      sprintf (t += strlen (t)," %s",stream->user_flags[i]);
+  strcpy (t += strlen (t),"\r\nStatus: RO\r\n\r\n");
+  for (s = pseudo_msg,t += strlen (t); *s; *t++ = *s++)
+    if (*s == '\n') *t++ = '\r';
+  *t++ = '\r'; *t++ = '\n'; *t++ = '\r'; *t++ = '\n';
+  *t = '\0';			/* tie off pseudo header */
+  return t - hdr;		/* return length of pseudo header */
+}
+
+/* UNIX make status string
+ * Accepts: MAIL stream
+ *	    destination string to write
+ *	    message cache entry
+ *	    UID to write if non-zero (else use elt->private.uid)
+ *	    non-zero flag to write UID (.LT. 0 to write UID base info too)
+ * Returns: length of string
+ */
+
+unsigned long unix_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt,
+			    unsigned long uid,long flag)
+{
+  char *t,stack[64];
+  char *s = status;
+  unsigned long n;
+  unsigned long pad = 50;
+  /* This used to use sprintf(), but thanks to certain cretinous C libraries
+     with horribly slow implementations of sprintf() I had to change it to this
+     mess.  At least it should be fast. */
+  *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't'; *s++ = 'u'; *s++ = 's';
+  *s++ = ':'; *s++ = ' ';
+  if (elt->seen) *s++ = 'R';
+				/* only write O if have a UID */
+  if (flag && (!elt->recent || LOCAL->appending)) *s++ = 'O';
+  *s++ = '\r'; *s++ = '\n';
+  *s++ = 'X'; *s++ = '-'; *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't';
+  *s++ = 'u'; *s++ = 's'; *s++ = ':'; *s++ = ' ';
+  if (elt->deleted) *s++ = 'D';
+  if (elt->flagged) *s++ = 'F';
+  if (elt->answered) *s++ = 'A';
+  if (elt->draft) *s++ = 'T';
+  *s++ = '\r'; *s++ = '\n';
+
+  *s++ = 'X'; *s++ = '-'; *s++ = 'K'; *s++ = 'e'; *s++ = 'y'; *s++ = 'w';
+  *s++ = 'o'; *s++ = 'r'; *s++ = 'd'; *s++ = 's'; *s++ = ':';
+  if (n = elt->user_flags) do {
+    *s++ = ' ';
+    for (t = stream->user_flags[find_rightmost_bit (&n)]; *t; *s++ = *t++);
+  } while (n);
+  n = s - status;		/* get size of stuff so far */
+				/* pad X-Keywords to make size constant */
+  if (n < pad) for (n = pad - n; n > 0; --n) *s++ = ' ';
+  *s++ = '\r'; *s++ = '\n';
+  if (flag) {			/* want to include UID? */
+    t = stack;
+				/* push UID digits on the stack */
+    n = uid ? uid : elt->private.uid;
+    do *t++ = (char) (n % 10) + '0';
+    while (n /= 10);
+    *s++ = 'X'; *s++ = '-'; *s++ = 'U'; *s++ = 'I'; *s++ = 'D'; *s++ = ':';
+    *s++ = ' ';
+				/* pop UID from stack */
+    while (t > stack) *s++ = *--t;
+    *s++ = '\r'; *s++ = '\n';
+  }
+				/* end of extended message status */
+  *s++ = '\r'; *s++ = '\n'; *s = '\0';
+  return s - status;		/* return size of resulting string */
+}
+
+/* Rewrite mailbox file
+ * Accepts: MAIL stream, must be critical and locked
+ *	    return pointer to number of expunged messages if want expunge
+ *	    lock file name
+ *	    expunge sequence, not deleted flag
+ * Returns: T if success and mailbox unlocked, NIL if failure
+ */
+
+#define OVERFLOWBUFLEN 8192	/* initial overflow buffer length */
+
+long unix_rewrite (MAILSTREAM *stream,unsigned long *nexp,char *lock,
+		   long flags)
+{
+  MESSAGECACHE *elt;
+  UNIXFILE f;
+  char *s;
+  struct utimbuf times;
+  long ret,flag;
+  unsigned long i,j;
+  unsigned long recent = stream->recent;
+  unsigned long size = LOCAL->pseudo ? unix_pseudo (stream,LOCAL->buf) : 0;
+  if (nexp) *nexp = 0;		/* initially nothing expunged */
+				/* calculate size of mailbox after rewrite */
+  for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs; i++) {
+    elt = mail_elt (stream,i);	/* get cache */
+    if (!(nexp && elt->deleted && (flags ? elt->sequence : T))) {
+				/* add RFC822 size of this message */
+      size += elt->private.special.text.size + elt->private.spare.data +
+	unix_xstatus (stream,LOCAL->buf,elt,NIL,flag) +
+	  elt->private.msg.text.text.size + 2;
+      flag = 1;			/* only count X-IMAPbase once */
+    }
+  }
+  if (!size) {			/* no messages and no pseudo, make one now */
+    size = unix_pseudo (stream,LOCAL->buf);
+    LOCAL->pseudo = T;
+  }
+				/* extend the file as necessary */
+  if (ret = unix_extend (stream,size)) {
+    /* Set up buffered I/O file structure
+     * curpos	current position being written through buffering
+     * filepos	current position being written physically to the disk
+     * bufpos	current position being written in the buffer
+     * protect	current maximum position that can be written to the disk
+     *		before buffering is forced
+     * The code tries to buffer so that that disk is written in multiples of
+     * OVERBLOWBUFLEN bytes.
+     */
+    f.stream = stream;		/* note mail stream */
+    f.curpos = f.filepos = 0;	/* start of file */
+    f.protect = stream->nmsgs ?	/* initial protection pointer */
+    mail_elt (stream,1)->private.special.offset : 8192;
+    f.bufpos = f.buf = (char *) fs_get (f.buflen = OVERFLOWBUFLEN);
+
+    if (LOCAL->pseudo)		/* update pseudo-header */
+      unix_write (&f,LOCAL->buf,unix_pseudo (stream,LOCAL->buf));
+				/* loop through all messages */
+    for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs;) {
+      elt = mail_elt (stream,i);/* get cache */
+				/* expunge this message? */
+      if (nexp && elt->deleted && (flags ? elt->sequence : T)) {
+				/* one less recent message */
+	if (elt->recent) --recent;
+	mail_expunged(stream,i);/* notify upper levels */
+	++*nexp;		/* count up one more expunged message */
+      }
+      else {			/* preserve this message */
+	i++;			/* advance to next message */
+	if ((flag < 0) ||	/* need to rewrite message? */
+	    elt->private.dirty ||
+	    (((unsigned long) f.curpos) != elt->private.special.offset) ||
+	    (elt->private.msg.header.text.size !=
+	     (elt->private.spare.data +
+	      unix_xstatus (stream,LOCAL->buf,elt,NIL,flag)))) {
+	  unsigned long newoffset = f.curpos;
+				/* yes, seek to internal header */
+	  lseek (LOCAL->fd,elt->private.special.offset,L_SET);
+	  read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size);
+				/* protection pointer moves to RFC822 header */
+	  f.protect = elt->private.special.offset +
+	    elt->private.msg.header.offset;
+				/* write internal header */
+	  unix_write (&f,LOCAL->buf,elt->private.special.text.size);
+				/* get RFC822 header */
+	  s = unix_header (stream,elt->msgno,&j,NIL);
+				/* in case this got decremented */
+	  elt->private.msg.header.offset = elt->private.special.text.size;
+				/* header size, sans trailing newline */
+	  if ((j < 4) || (s[j - 4] == '\r')) j -= 2;
+	  if (j != elt->private.spare.data) fatal ("header size inconsistent");
+				/* protection pointer moves to RFC822 text */
+	  f.protect = elt->private.special.offset +
+	    elt->private.msg.text.offset;
+	  unix_write (&f,s,j);	/* write RFC822 header */
+				/* write status and UID */
+	  unix_write (&f,LOCAL->buf,
+		      j = unix_xstatus (stream,LOCAL->buf,elt,NIL,flag));
+	  flag = 1;		/* only write X-IMAPbase once */
+				/* new file header size */
+	  elt->private.msg.header.text.size = elt->private.spare.data + j;
+
+				/* did text move? */
+	  if (f.curpos != f.protect) {
+				/* get message text */
+	    s = unix_text_work (stream,elt,&j,FT_INTERNAL);
+				/* can't happen it says here */
+	    if (j > elt->private.msg.text.text.size)
+	      fatal ("text size inconsistent");
+				/* new text offset, status/UID may change it */
+	    elt->private.msg.text.offset = f.curpos - newoffset;
+				/* protection pointer moves to next message */
+	    f.protect = (i <= stream->nmsgs) ?
+	      mail_elt (stream,i)->private.special.offset : (f.curpos + j + 2);
+	    unix_write (&f,s,j);/* write text */
+				/* write trailing newline */
+	    unix_write (&f,"\r\n",2);
+	  }
+	  else {		/* tie off header and status */
+	    unix_write (&f,NIL,NIL);
+				/* protection pointer moves to next message */
+	    f.protect = (i <= stream->nmsgs) ?
+	      mail_elt (stream,i)->private.special.offset : size;
+				/* locate end of message text */
+	    j = f.filepos + elt->private.msg.text.text.size;
+				/* trailing newline already there? */
+	    if (f.protect == (off_t) (j + 2)) f.curpos = f.filepos = f.protect;
+	    else {		/* trailing newline missing, write it */
+	      f.curpos = f.filepos = j;
+	      unix_write (&f,"\r\n",2);
+	    }
+	  }
+				/* new internal header offset */
+	  elt->private.special.offset = newoffset;
+	  elt->private.dirty =NIL;/* message is now clean */
+	}
+	else {			/* no need to rewrite this message */
+				/* tie off previous message if needed */
+	  unix_write (&f,NIL,NIL);
+				/* protection pointer moves to next message */
+	  f.protect = (i <= stream->nmsgs) ?
+	    mail_elt (stream,i)->private.special.offset : size;
+				/* locate end of message text */
+	  j = f.filepos + elt->private.special.text.size +
+	    elt->private.msg.header.text.size +
+	      elt->private.msg.text.text.size;
+				/* trailing newline already there? */
+	  if (f.protect == (off_t) (j + 2)) f.curpos = f.filepos = f.protect;
+	  else {		/* trailing newline missing, write it */
+	    f.curpos = f.filepos = j;
+	    unix_write (&f,"\r\n",2);
+	  }
+	}
+      }
+    }
+
+    unix_write (&f,NIL,NIL);	/* tie off final message */
+    if (size != ((unsigned long) f.filepos)) fatal ("file size inconsistent");
+    fs_give ((void **) &f.buf);	/* free buffer */
+				/* make sure tied off */
+    ftruncate (LOCAL->fd,LOCAL->filesize = size);
+    fsync (LOCAL->fd);		/* make sure the updates take */
+    if (size && (flag < 0)) fatal ("lost UID base information");
+				/* no longer dirty */
+    LOCAL->ddirty = LOCAL->dirty = NIL;
+  				/* notify upper level of new mailbox sizes */
+    mail_exists (stream,stream->nmsgs);
+    mail_recent (stream,recent);
+				/* set atime to now, mtime a second earlier */
+    times.modtime = (times.actime = time (0)) -1;
+				/* set the times, note change */
+    if (!utime (stream->mailbox,&times)) LOCAL->filetime = times.modtime;
+				/* flush the lock file */
+    unix_unlock (LOCAL->fd,stream,lock);
+  }
+  return ret;			/* return state from algorithm */
+}
+
+/* Extend UNIX mailbox file
+ * Accepts: MAIL stream
+ *	    new desired size
+ * Return: T if success, else NIL
+ */
+
+long unix_extend (MAILSTREAM *stream,unsigned long size)
+{
+  unsigned long i = (size > ((unsigned long) LOCAL->filesize)) ?
+    size - ((unsigned long) LOCAL->filesize) : 0;
+  if (i) {			/* does the mailbox need to grow? */
+    if (i > LOCAL->buflen) {	/* make sure have enough space */
+				/* this user won the lottery all right */
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get ((LOCAL->buflen = i) + 1);
+    }
+    memset (LOCAL->buf,'\0',i);	/* get a block of nulls */
+    while (T) {			/* until write successful or punt */
+      lseek (LOCAL->fd,LOCAL->filesize,L_SET);
+      if ((write (LOCAL->fd,LOCAL->buf,i) >= 0) && !fsync (LOCAL->fd)) break;
+      else {
+	long e = errno;		/* note error before doing ftruncate */
+	ftruncate (LOCAL->fd,LOCAL->filesize);
+	if (mm_diskerror (stream,e,NIL)) {
+	  fsync (LOCAL->fd);	/* user chose to punt */
+	  sprintf (LOCAL->buf,"Unable to extend mailbox: %s",strerror (e));
+	  if (!stream->silent) mm_log (LOCAL->buf,ERROR);
+	  return NIL;
+	}
+      }
+    }
+  }
+  return LONGT;
+}
+
+/* Write data to buffered file
+ * Accepts: buffered file pointer
+ *	    file data or NIL to indicate "flush buffer"
+ *	    date size (ignored for "flush buffer")
+ * Does not return until success
+ */
+
+void unix_write (UNIXFILE *f,char *buf,unsigned long size)
+{
+  unsigned long i,j,k;
+  if (buf) {			/* doing buffered write? */
+    i = f->bufpos - f->buf;	/* yes, get size of current buffer data */
+				/* yes, have space in current buffer chunk? */
+    if (j = i ? ((f->buflen - i) % OVERFLOWBUFLEN) : f->buflen) {
+				/* yes, fill up buffer as much as we can */
+      memcpy (f->bufpos,buf,k = min (j,size));
+      f->bufpos += k;		/* new buffer position */
+      f->curpos += k;		/* new current position */
+      if (j -= k) return;	/* all done if still have buffer free space */
+      buf += k;			/* full, get new unwritten data pointer */
+      size -= k;		/* new data size */
+      i += k;			/* new buffer data size */
+    }
+    /* This chunk of the buffer is full.  See if can make some space by
+     * writing to the disk, if there's enough unprotected space to do so.
+     * Try to fill out any unaligned chunk, along with any subsequent full
+     * chunks that will fit in unprotected space.
+     */
+				/* any unprotected space we can write to? */
+    if (j = min (i,f->protect - f->filepos)) {
+				/* yes, filepos not at chunk boundary? */
+      if ((k = f->filepos % OVERFLOWBUFLEN) && ((k = OVERFLOWBUFLEN - k) < j))
+	j -= k;			/* yes, and can write out partial chunk */
+      else k = 0;		/* no partial chunk to write */
+				/* if at least a chunk free, write that too */
+      if (j > OVERFLOWBUFLEN) k += j - (j % OVERFLOWBUFLEN);
+      if (k) {			/* write data if there is anything we can */
+	unix_phys_write (f,f->buf,k);
+				/* slide buffer */
+	if (i -= k) memmove (f->buf,f->buf + k,i);
+	f->bufpos = f->buf + i;	/* new end of buffer */
+      }
+    }
+
+    /* Have flushed the buffer as best as possible.  All done if no more
+     * data to write.  Otherwise, if the buffer is empty AND if the unwritten
+     * data is larger than a chunk AND the unprotected space is also larger
+     * than a chunk, then write as many chunks as we can directly from the
+     * data.  Buffer the rest, expanding the buffer as needed.
+     */
+    if (size) {			/* have more data that we need to buffer? */
+				/* can write any of it to disk instead? */
+      if ((f->bufpos == f->buf) && 
+	  ((j = min (f->protect - f->filepos,size)) > OVERFLOWBUFLEN)) {
+				/* write as much as we can right now */
+	unix_phys_write (f,buf,j -= (j % OVERFLOWBUFLEN));
+	buf += j;		/* new data pointer */
+	size -= j;		/* new data size */
+	f->curpos += j;		/* advance current pointer */
+      }
+      if (size) {		/* still have data that we need to buffer? */
+				/* yes, need to expand the buffer? */
+	if ((i = ((f->bufpos + size) - f->buf)) > f->buflen) {
+				/* note current position in buffer */
+	  j = f->bufpos - f->buf;
+	  i += OVERFLOWBUFLEN;	/* yes, grow another chunk */
+	  fs_resize ((void **) &f->buf,f->buflen = i - (i % OVERFLOWBUFLEN));
+				/* in case buffer relocated */
+	  f->bufpos = f->buf + j;
+	}
+				/* buffer remaining data */
+	memcpy (f->bufpos,buf,size);
+	f->bufpos += size;	/* new end of buffer */
+	f->curpos += size;	/* advance current pointer */
+      }
+    }
+  }
+  else {			/* flush buffer to disk */
+    unix_phys_write (f,f->buf,i = f->bufpos - f->buf);
+    f->bufpos = f->buf;		/* reset buffer */
+				/* update positions */
+    f->curpos = f->protect = f->filepos;
+  }
+}
+
+/* Physical disk write
+ * Accepts: buffered file pointer
+ *	    buffer address
+ *	    buffer size
+ * Does not return until success
+ */
+
+void unix_phys_write (UNIXFILE *f,char *buf,size_t size)
+{
+  MAILSTREAM *stream = f->stream;
+				/* write data at desired position */
+  while (size && ((lseek (LOCAL->fd,f->filepos,L_SET) < 0) ||
+		  (write (LOCAL->fd,buf,size) < 0))) {
+    int e;
+    char tmp[MAILTMPLEN];
+    sprintf (tmp,"Unable to write to mailbox: %s",strerror (e = errno));
+    mm_log (tmp,ERROR);
+    mm_diskerror (NIL,e,T);	/* serious problem, must retry */
+  }
+  f->filepos += size;		/* update file position */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/unixnt.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,161 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX mail routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	20 December 1989
+ * Last Edited:	30 August 2006
+ */
+
+
+/*				DEDICATION
+ *
+ *  This file is dedicated to my dog, Unix, also known as Yun-chan and
+ * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast.  Unix
+ * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after
+ * a two-month bout with cirrhosis of the liver.
+ *
+ *  He was a dear friend, and I miss him terribly.
+ *
+ *  Lift a leg, Yunie.  Luv ya forever!!!!
+ */
+
+/* Validate line
+ * Accepts: pointer to candidate string to validate as a From header
+ *	    return pointer to end of date/time field
+ *	    return pointer to offset from t of time (hours of ``mmm dd hh:mm'')
+ *	    return pointer to offset from t of time zone (if non-zero)
+ * Returns: t,ti,zn set if valid From string, else ti is NIL
+ */
+
+#define VALID(s,x,ti,zn) {						\
+  ti = 0;								\
+  if ((*s == 'F') && (s[1] == 'r') && (s[2] == 'o') && (s[3] == 'm') &&	\
+      (s[4] == ' ')) {							\
+    for (x = s + 5; *x && *x != '\012'; x++);				\
+    if (*x) {								\
+      if (x[-1] == '\015') --x;						\
+      if (x - s >= 41) {						\
+	for (zn = -1; x[zn] != ' '; zn--);				\
+	if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') &&	\
+	    (x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') &&	\
+	    (x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') &&	\
+	    (x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))\
+	  x += zn - 12;							\
+      }									\
+      if (x - s >= 27) {						\
+	if (x[-5] == ' ') {						\
+	  if (x[-8] == ':') zn = 0,ti = -5;				\
+	  else if (x[-9] == ' ') ti = zn = -9;				\
+	  else if ((x[-11] == ' ') && ((x[-10]=='+') || (x[-10]=='-')))	\
+	    ti = zn = -11;						\
+	}								\
+	else if (x[-4] == ' ') {					\
+	  if (x[-9] == ' ') zn = -4,ti = -9;				\
+	}								\
+	else if (x[-6] == ' ') {					\
+	  if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-')))	\
+	    zn = -6,ti = -11;						\
+	}								\
+	if (ti && !((x[ti - 3] == ':') &&				\
+		    (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') &&	\
+		    (x[ti - 3] == ' ') && (x[ti - 7] == ' ') &&		\
+		    (x[ti - 11] == ' '))) ti = 0;			\
+      }									\
+    }									\
+  }									\
+}
+
+/* You are not expected to understand this macro, but read the next page if
+ * you are not faint of heart.
+ *
+ * Known formats to the VALID macro are:
+ *		From user Wed Dec  2 05:53 1992
+ * BSD		From user Wed Dec  2 05:53:22 1992
+ * SysV		From user Wed Dec  2 05:53 PST 1992
+ * rn		From user Wed Dec  2 05:53:22 PST 1992
+ *		From user Wed Dec  2 05:53 -0700 1992
+ * emacs	From user Wed Dec  2 05:53:22 -0700 1992
+ *		From user Wed Dec  2 05:53 1992 PST
+ *		From user Wed Dec  2 05:53:22 1992 PST
+ *		From user Wed Dec  2 05:53 1992 -0700
+ * Solaris	From user Wed Dec  2 05:53:22 1992 -0700
+ *
+ * Plus all of the above with `` remote from xxx'' after it. Thank you very
+ * much, smail and Solaris, for making my life considerably more complicated.
+ */
+
+/*
+ * What?  You want to understand the VALID macro anyway?  Alright, since you
+ * insist.  Actually, it isn't really all that difficult, provided that you
+ * take it step by step.
+ *
+ * Line 1	Initializes the return ti value to failure (0);
+ * Lines 2-3	Validates that the 1st-5th characters are ``From ''.
+ * Lines 4-6	Validates that there is an end of line and points x at it.
+ * Lines 7-14	First checks to see if the line is at least 41 characters long.
+ *		If so, it scans backwards to find the rightmost space.  From
+ *		that point, it scans backwards to see if the string matches
+ *		`` remote from''.  If so, it sets x to point to the space at
+ *		the start of the string.
+ * Line 15	Makes sure that there are at least 27 characters in the line.
+ * Lines 16-21	Checks if the date/time ends with the year (there is a space
+ *		five characters back).  If there is a colon three characters
+ *		further back, there is no timezone field, so zn is set to 0
+ *		and ti is set in front of the year.  Otherwise, there must
+ *		either to be a space four characters back for a three-letter
+ *		timezone, or a space six characters back followed by a + or -
+ *		for a numeric timezone; in either case, zn and ti become the
+ *		offset of the space immediately before it.
+ * Lines 22-24	Are the failure case for line 14.  If there is a space four
+ *		characters back, it is a three-letter timezone; there must be a
+ *		space for the year nine characters back.  zn is the zone
+ *		offset; ti is the offset of the space.
+ * Lines 25-28	Are the failure case for line 20.  If there is a space six
+ *		characters back, it is a numeric timezone; there must be a
+ *		space eleven characters back and a + or - five characters back.
+ *		zn is the zone offset; ti is the offset of the space.
+ * Line 29-32	If ti is valid, make sure that the string before ti is of the
+ *		form www mmm dd hh:mm or www mmm dd hh:mm:ss, otherwise
+ *		invalidate ti.  There must be a colon three characters back
+ *		and a space six or nine	characters back (depending upon
+ *		whether or not the character six characters back is a colon).
+ *		There must be a space three characters further back (in front
+ *		of the day), one seven characters back (in front of the month),
+ *		and one eleven characters back (in front of the day of week).
+ *		ti is set to be the offset of the space before the time.
+ *
+ * Why a macro?  It gets invoked a *lot* in a tight loop.  On some of the
+ * newer pipelined machines it is faster being open-coded than it would be if
+ * subroutines are called.
+ *
+ * Why does it scan backwards from the end of the line, instead of doing the
+ * much easier forward scan?  There is no deterministic way to parse the
+ * ``user'' field, because it may contain unquoted spaces!  Yes, I tested it to
+ * see if unquoted spaces were possible.  They are, and I've encountered enough
+ * evil mail to be totally unwilling to trust that ``it will never happen''.
+ */
+
+/* Build parameters */
+
+#define KODRETRY 15		/* kiss-of-death retry in seconds */
+#define LOCKTIMEOUT 5		/* lock timeout in minutes */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/write.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,59 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Write data, treating partial writes as an error
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	26 May 1995
+ * Last Edited:	30 August 2006
+ */
+
+/*  The whole purpose of this unfortunate routine is to deal with DOS and
+ * certain cretinous versions of UNIX which decided that the "bytes actually
+ * written" return value from write() gave them license to use that for things
+ * that are really errors, such as disk quota exceeded, maximum file size
+ * exceeded, disk full, etc.
+ * 
+ *  BSD won't screw us this way on the local filesystem, but who knows what
+ * some NFS-mounted filesystem will do.
+ */
+
+#undef write
+
+/* Write data to file
+ * Accepts: file descriptor
+ *	    I/O vector structure
+ *	    number of vectors in structure
+ * Returns: number of bytes written if successful, -1 if failure
+ */
+
+long maxposint = (long)((((unsigned long) 1) << ((sizeof(int) * 8) - 1)) - 1);
+
+long safe_write (int fd,char *buf,long nbytes)
+{
+  long i,j;
+  if (nbytes > 0) for (i = nbytes; i; i -= j,buf += j) {
+    while (((j = write (fd,buf,(int) min (maxposint,i))) < 0) &&
+	   (errno == EINTR));
+    if (j < 0) return j;
+  }
+  return nbytes;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/yunchan.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,286 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Unix compatibility routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	14 September 1996
+ * Last Edited:	30 August 2006
+ */
+
+
+/*				DEDICATION
+ *
+ *  This file is dedicated to my dog, Unix, also known as Yun-chan and
+ * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast.  Unix
+ * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after
+ * a two-month bout with cirrhosis of the liver.
+ *
+ *  He was a dear friend, and I miss him terribly.
+ *
+ *  Lift a leg, Yunie.  Luv ya forever!!!!
+ */
+ 
+/* Emulator for BSD flock() call
+ * Accepts: file descriptor
+ *	    operation bitmask
+ * Returns: 0 if successful, -1 if failure
+ */
+
+/*  Our friends in Redmond have decided that you can not write to any segment
+ * which has a shared lock.  This screws up the shared-write mailbox drivers
+ * (mbx, mtx, and tenex).  As a workaround, we'll only lock the first byte of
+ * the file, meaning that you can't write that byte shared.
+ *  This behavior seems to be new as of NT 4.0.
+ */
+
+int flock (int fd,int op)
+{
+  HANDLE hdl = (HANDLE) _get_osfhandle (fd);
+  DWORD flags = (op & LOCK_NB) ? LOCKFILE_FAIL_IMMEDIATELY : 0;
+  OVERLAPPED offset = {NIL,NIL,0,0,NIL};
+  int ret = -1;
+  blocknotify_t bn = (blocknotify_t) 
+    ((op & LOCK_NB) ? NIL : mail_parameters (NIL,GET_BLOCKNOTIFY,NIL));
+  if (hdl < 0) errno = EBADF;	/* error in file descriptor */
+  else switch (op & ~LOCK_NB) {	/* translate to LockFileEx() op */
+  case LOCK_EX:			/* exclusive */
+    flags |= LOCKFILE_EXCLUSIVE_LOCK;
+  case LOCK_SH:			/* shared */
+    if (!check_nt ()) return 0;	/* always succeeds if not NT */
+    if (bn) (*bn) (BLOCK_FILELOCK,NIL);
+				/* bug for bug compatible with Unix */
+    UnlockFileEx (hdl,NIL,1,0,&offset);
+				/* lock the file as requested */
+    if (LockFileEx (hdl,flags,NIL,1,0,&offset)) ret = 0;
+    if (bn) (*bn) (BLOCK_NONE,NIL);
+				/* if failed */
+    if (ret) errno = (op & LOCK_NB) ? EAGAIN : EBADF;
+    break;
+  case LOCK_UN:			/* unlock */
+    if (check_nt ()) UnlockFileEx (hdl,NIL,1,0,&offset);
+    ret = 0;			/* always succeeds */
+  default:			/* default */
+    errno = EINVAL;		/* bad call */
+    break;
+  }
+  return ret;
+}
+
+/* Local storage */
+
+static char *loghdr;		/* log file header string */
+static HANDLE loghdl = NIL;	/* handle of event source */
+
+/* Emulator for BSD syslog() routine
+ * Accepts: priority
+ *	    message
+ *	    parameters
+ */
+
+void syslog (int priority,const char *message,...)
+{
+  va_list args;
+  LPTSTR strs[2];
+  char tmp[MAILTMPLEN];		/* callers must be careful not to pop this */
+  unsigned short etype;
+  if (!check_nt ()) return;	/* no-op on non-NT system */
+				/* default event source */
+  if (!loghdl) openlog ("c-client",LOG_PID,LOG_MAIL);
+  switch (priority) {		/* translate UNIX type into NT type */
+  case LOG_ALERT:
+    etype = EVENTLOG_ERROR_TYPE;
+    break;
+  case LOG_INFO:
+    etype = EVENTLOG_INFORMATION_TYPE;
+    break;
+  default:
+    etype = EVENTLOG_WARNING_TYPE;
+  }
+  va_start (args,message);	/* initialize vararg mechanism */
+  vsprintf (tmp,message,args);	/* build message */
+  strs[0] = loghdr;		/* write header */
+  strs[1] = tmp;		/* then the message */
+				/* report the event */
+  ReportEvent (loghdl,etype,(unsigned short) priority,2000,NIL,2,0,strs,NIL);
+  va_end (args);
+}
+
+
+/* Emulator for BSD openlog() routine
+ * Accepts: identity
+ *	    options
+ *	    facility
+ */
+
+void openlog (const char *ident,int logopt,int facility)
+{
+  char tmp[MAILTMPLEN];
+  if (!check_nt ()) return;	/* no-op on non-NT system */
+  if (loghdl) fatal ("Duplicate openlog()!");
+  loghdl = RegisterEventSource (NIL,ident);
+  sprintf (tmp,(logopt & LOG_PID) ? "%s[%d]" : "%s",ident,getpid ());
+  loghdr = cpystr (tmp);	/* save header for later */
+}
+
+/* Copy Unix string with CRLF newlines
+ * Accepts: destination string
+ *	    pointer to size of destination string buffer
+ *	    source string
+ *	    length of source string
+ * Returns: length of copied string
+ */
+
+unsigned long unix_crlfcpy (char **dst,unsigned long *dstl,char *src,
+			    unsigned long srcl)
+{
+  unsigned long i,j;
+  char *d = src;
+				/* count number of LF's in source string(s) */
+  for (i = srcl,j = 0; j < srcl; j++) if (*d++ == '\012') i++;
+				/* flush destination buffer if too small */
+  if (*dst && (i > *dstl)) fs_give ((void **) dst);
+  if (!*dst) {			/* make a new buffer if needed */
+    *dst = (char *) fs_get ((*dstl = i) + 1);
+    if (dstl) *dstl = i;	/* return new buffer length to main program */
+  }
+  d = *dst;			/* destination string */
+				/* copy strings, inserting CR's before LF's */
+  while (srcl--) switch (*src) {
+  case '\015':			/* unlikely carriage return */
+    *d++ = *src++;		/* copy it and any succeeding linefeed */
+    if (srcl && *src == '\012') {
+      *d++ = *src++;
+      srcl--;
+    }
+    break;
+  case '\012':			/* line feed? */
+    *d++ ='\015';		/* yes, prepend a CR, drop into default case */
+  default:			/* ordinary chararacter */
+    *d++ = *src++;		/* just copy character */
+    break;
+  }
+  *d = '\0';			/* tie off destination */
+  return d - *dst;		/* return length */
+}
+
+/* Length of Unix string after unix_crlfcpy applied
+ * Accepts: source string
+ * Returns: length of string
+ */
+
+unsigned long unix_crlflen (STRING *s)
+{
+  unsigned long pos = GETPOS (s);
+  unsigned long i = SIZE (s);
+  unsigned long j = i;
+  while (j--) switch (SNX (s)) {/* search for newlines */
+  case '\015':			/* unlikely carriage return */
+    if (j && (CHR (s) == '\012')) {
+      SNX (s);			/* eat the line feed */
+      j--;
+    }
+    break;
+  case '\012':			/* line feed? */
+    i++;
+  default:			/* ordinary chararacter */
+    break;
+  }
+  SETPOS (s,pos);		/* restore old position */
+  return i;
+}
+
+/* Undoubtably, I'm going to regret these two routines in the future.  I
+ * regret them now.  Their purpose is to work around two problems in the
+ * VC++ 6.0 C library:
+ *  (1) tmpfile() creates the file in the current directory instead of a
+ *	temporary directory
+ *  (2) tmpfile() and fclose() think that on NT systems, it works to unlink
+ *	the file while it's still open, so there's no need for the _tmpfname
+ *	hook at fclose().  Unfortunately, that doesn't work in Win2K.
+ * I would be delighted to have a better alternative.
+ */
+
+#undef fclose			/* use the real fclose() in close_file() */
+
+/* Substitute for Microsoft's tmpfile() that uses the real temporary directory
+ * Returns: FILE structure if success, NIL if failure
+ */
+
+FILE *create_tempfile (void)
+{
+  FILE *ret = NIL;
+  char *s = _tempnam (getenv ("TEMP"),"msg");
+  if (s) {			/* if got temporary name... */
+				/* open file, and stash name on _tmpfname */
+    if (ret = fopen (s,"w+b")) ret->_tmpfname = s;
+    else fs_give ((void **) &s);/* flush temporary string */
+  }
+  return ret;
+}
+
+
+/* Substitute for Microsoft's fclose() that always flushes _tmpfname
+ * Returns: FILE structure if success, NIL if failure
+ */
+
+int close_file (FILE *stream)
+{
+  int ret;
+  char *s = stream->_tmpfname;
+  stream->_tmpfname = NIL;	/* just in case fclose() tries to delete it */
+  ret = fclose (stream);	/* close the file */
+  if (s) {			/* was there a _tmpfname? */
+    unlink (s);			/* yup, delete it */
+    fs_give ((void **) &s);	/* and flush the name */
+  }
+  return ret;
+}
+
+/* Get password from console
+ * Accepts: prompt
+ * Returns: password
+ */
+
+#define PWDLEN 128		/* used by Linux */
+
+char *getpass (const char *prompt)
+{
+  static char pwd[PWDLEN];
+  int ch,i,done;
+  fputs (prompt,stderr);	/* output prompt */
+  for (i = done = 0; !done; ) switch (ch = _getch()) {
+  case 0x03:			/* CTRL/C stops program */
+    _exit (1);
+  case '\b':			/* BACKSPACE erase previous character */
+    if (i) pwd[--i] = '\0';
+    break;
+  case '\n': case '\r':		/* CR or LF terminates string */
+    done = 1;
+    break;
+  default:			/* any other character is a pwd char */
+    if (i < (PWDLEN - 1)) pwd[i++] = ch;
+    break;
+  }
+  pwd[i] = '\0';		/* tie off string with null */
+  putchar ('\n');		/* echo newline */
+  return pwd;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/nt/yunchan.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,86 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Unix compatibility routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	14 September 1996
+ * Last Edited:	30 August 2006
+ */
+
+
+/*				DEDICATION
+ *
+ *  This file is dedicated to my dog, Unix, also known as Yun-chan and
+ * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast.  Unix
+ * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after
+ * a two-month bout with cirrhosis of the liver.
+ *
+ *  He was a dear friend, and I miss him terribly.
+ *
+ *  Lift a leg, Yunie.  Luv ya forever!!!!
+ */
+
+/* For flock() emulation */
+
+#define LOCK_SH 1
+#define LOCK_EX 2
+#define LOCK_NB 4
+#define LOCK_UN 8
+
+
+/* syslog() emulation */
+
+#define LOG_MAIL	(2<<3)	/* mail system */
+#define LOG_DAEMON	(3<<3)	/* system daemons */
+#define LOG_AUTH	(4<<3)	/* security/authorization messages */
+#define LOG_EMERG	0	/* system is unusable */
+#define LOG_ALERT	1	/* action must be taken immediately */
+#define LOG_CRIT	2	/* critical conditions */
+#define LOG_ERR		3	/* error conditions */
+#define LOG_WARNING	4	/* warning conditions */
+#define LOG_NOTICE	5	/* normal but signification condition */
+#define LOG_INFO	6	/* informational */
+#define LOG_DEBUG	7	/* debug-level messages */
+#define LOG_PID		0x01	/* log the pid with each message */
+#define LOG_CONS	0x02	/* log on the console if errors in sending */
+#define LOG_ODELAY	0x04	/* delay open until syslog() is called */
+#define LOG_NDELAY	0x08	/* don't delay open */
+#define LOG_NOWAIT	0x10	/* if forking to log on console, don't wait() */
+
+#define tmpfile create_tempfile
+#define fclose close_file
+#define fsync _commit
+#define ftruncate chsize
+#define gethostid clock
+#define sleep(x) Sleep (1000 * x)
+
+
+long alarm (long seconds);
+int flock (int fd,int op);
+void openlog (const char *ident,int logopt,int facility);
+void syslog (int priority,const char *message,...);
+unsigned long unix_crlfcpy (char **dst,unsigned long *dstl,char *src,
+			    unsigned long srcl);
+unsigned long unix_crlflen (STRING *s);
+FILE *create_tempfile (void);
+int close_file (FILE *stream);
+char *getpass (const char *prompt);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/os2/auths.cmd	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,48 @@
+/* rexx */
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+/*
+ * Program:	Authenticator Linkage Generator for OS/2
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 June 1999
+ * Last Edited:	30 August 2006
+ */
+'@echo off'
+/* Erase old authenticators list */
+'if exist auths.c del auths.c'
+parse arg args
+n=words(args)
+a_file='auths.c'
+c_file='linkage.c'
+h_file='linkage.h'
+call stream a_file, 'C', 'open write'
+call stream c_file, 'C', 'open write'
+call stream h_file, 'C', 'open write'
+do i=1 to n
+  arg=word(args,i)
+  call lineout a_file, '#include "auth_'arg'.c"'
+  call lineout h_file, 'extern AUTHENTICATOR auth_'arg';'
+  call lineout c_file, '  auth_link (&auth_'arg');	/* link in the 'arg' authenticator */'
+  end
+call stream h_file, 'C', 'close'
+call stream c_file, 'C', 'close'
+call stream a_file, 'C', 'close'
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/os2/drivers.cmd	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,45 @@
+/* rexx */
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+/*
+ * Program:	Authenticator Linkage Generator for OS/2
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 June 1999
+ * Last Edited:	30 August 2006
+ */
+'@echo off'
+/* Erase old authenticators list */
+'if exist linkage.h del linkage.h'
+'if exist linkage.c del linkage.c'
+parse arg args
+n=words(args)
+c_file='linkage.c'
+h_file='linkage.h'
+call stream c_file, 'C', 'open write'
+call stream h_file, 'C', 'open write'
+do i=1 to n
+  arg=word(args,i)
+  call lineout h_file, 'extern DRIVER 'arg'driver;'
+  call lineout c_file, '  mail_link (&'arg'driver);	/* link in the 'arg' driver */'
+  end
+call stream h_file, 'C', 'close'
+call stream c_file, 'C', 'close'
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/os2/dummy.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,43 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Dummy routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	9 May 1991
+ * Last Edited:	30 August 2006
+ */
+
+/* Exported function prototypes */
+
+void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void dummy_list (MAILSTREAM *stream,char *ref,char *pat);
+void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long scan_contents (DRIVER *dtb,char *name,char *contents,
+		    unsigned long csiz,unsigned long fsiz);
+long dummy_scan_contents (char *name,char *contents,unsigned long csiz,
+			  unsigned long fsiz);
+long dummy_create (MAILSTREAM *stream,char *mailbox);
+long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode);
+long dummy_delete (MAILSTREAM *stream,char *mailbox);
+long dummy_rename (MAILSTREAM *stream,char *old,char *newname);
+char *dummy_file (char *dst,char *name);
+long dummy_canonicalize (char *tmp,char *ref,char *pat);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/os2/dummyos2.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,714 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Dummy routines for OS2
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	24 May 1993
+ * Last Edited:	30 August 2006
+ */
+
+/* Thanks to Nicholas Sheppard for the original version */
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <sys/stat.h>
+#include <io.h>
+#include <fcntl.h>
+#include <os2.h>
+#undef ADDRESS
+#include "mail.h"
+#include "osdep.h"
+#include "misc.h"
+#include "dummy.h"
+
+/* Function prototypes */
+
+DRIVER *dummy_valid (char *name);
+void *dummy_parameters (long function,void *value);
+void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents,
+		      long level);
+long dummy_listed (MAILSTREAM *stream,char delimiter,char *name,
+		   long attributes,char *contents);
+long dummy_subscribe (MAILSTREAM *stream,char *mailbox);
+MAILSTREAM *dummy_open (MAILSTREAM *stream);
+void dummy_close (MAILSTREAM *stream,long options);
+long dummy_ping (MAILSTREAM *stream);
+void dummy_check (MAILSTREAM *stream);
+long dummy_expunge (MAILSTREAM *stream,char *sequence,long options);
+long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+/* Dummy routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER dummydriver = {
+  "dummy",			/* driver name */
+  DR_LOCAL|DR_MAIL,		/* driver flags */
+  (DRIVER *) NIL,		/* next driver */
+  dummy_valid,			/* mailbox is valid for us */
+  dummy_parameters,		/* manipulate parameters */
+  dummy_scan,			/* scan mailboxes */
+  dummy_list,			/* list mailboxes */
+  dummy_lsub,			/* list subscribed mailboxes */
+  dummy_subscribe,		/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  dummy_create,			/* create mailbox */
+  dummy_delete,			/* delete mailbox */
+  dummy_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  dummy_open,			/* open mailbox */
+  dummy_close,			/* close mailbox */
+  NIL,				/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message structure */
+  NIL,				/* fetch header */
+  NIL,				/* fetch text */
+  NIL,				/* fetch message data */
+  NIL,				/* unique identifier */
+  NIL,				/* message number from UID */
+  NIL,				/* modify flags */
+  NIL,				/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  dummy_ping,			/* ping mailbox to see if still alive */
+  dummy_check,			/* check for new messages */
+  dummy_expunge,		/* expunge deleted messages */
+  dummy_copy,			/* copy messages to another mailbox */
+  dummy_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+
+				/* prototype stream */
+MAILSTREAM dummyproto = {&dummydriver};
+
+/* Dummy validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *dummy_valid (char *name)
+{
+  char *s,*t,tmp[MAILTMPLEN];
+  struct stat sbuf;
+				/* must be valid local mailbox */
+  if (name && *name && (*name != '{') && (s = mailboxfile (tmp,name))) {
+				/* indeterminate INBOX */
+    if (!*s) return &dummydriver;
+				/* remove trailing \ */
+    if ((t = strrchr (s,'\\')) && !t[1]) *t = '\0';
+    if (!stat (s,&sbuf)) switch (sbuf.st_mode & S_IFMT) {
+    case S_IFREG:		/* file */
+    case S_IFDIR:		/* future use */
+      return &dummydriver;
+    }
+  }
+  return NIL;
+}
+
+
+/* Dummy manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *dummy_parameters (long function,void *value)
+{
+  return NIL;
+}
+
+/* Dummy scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  char *s,test[MAILTMPLEN],file[MAILTMPLEN];
+  long i = 0;
+  if (!pat || !*pat) {		/* empty pattern? */
+    if (dummy_canonicalize (test,ref,"*")) {
+				/* tie off name at root */
+      if (s = strchr (test,'\\')) *++s = '\0';
+      else test[0] = '\0';
+      dummy_listed (stream,'\\',test,LATT_NOSELECT,NIL);
+    }
+  }
+				/* get canonical form of name */
+  else if (dummy_canonicalize (test,ref,pat)) {
+				/* found any wildcards? */
+    if (s = strpbrk (test,"%*")) {
+				/* yes, copy name up to that point */
+      strncpy (file,test,(size_t) (i = s - test));
+      file[i] = '\0';		/* tie off */
+    }
+    else strcpy (file,test);	/* use just that name then */
+				/* find directory name */
+    if (s = strrchr (file,'\\')) {
+      *++s = '\0';		/* found, tie off at that point */
+      s = file;
+    }
+				/* silly case */
+    else if (file[0] == '#') s = file;
+				/* do the work */
+    dummy_list_work (stream,s,test,contents,0);
+    if (pmatch ("INBOX",test))	/* always an INBOX */
+      dummy_listed (stream,NIL,"INBOX",LATT_NOINFERIORS,contents);
+  }
+}
+
+/* Dummy list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void dummy_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  dummy_scan (stream,ref,pat,NIL);
+}
+
+
+/* Dummy list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  void *sdb = NIL;
+  char *s,*t,test[MAILTMPLEN];
+  int showuppers = pat[strlen (pat) - 1] == '%';
+				/* get canonical form of name */
+  if (dummy_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) do
+    if (*s != '{') {
+      if (pmatch_full (s,test,'\\')) {
+	if (pmatch (s,"INBOX")) mm_lsub (stream,NIL,s,LATT_NOINFERIORS);
+	else mm_lsub (stream,'\\',s,NIL);
+      }
+      else while (showuppers && (t = strrchr (s,'\\'))) {
+	*t = '\0';		/* tie off the name */
+	if (pmatch_full (s,test,'\\')) mm_lsub (stream,'\\',s,LATT_NOSELECT);
+      }
+    }
+  while (s = sm_read (&sdb));	/* until no more subscriptions */
+}
+
+
+/* Dummy subscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to add to subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_subscribe (MAILSTREAM *stream,char *mailbox)
+{
+  char *s,tmp[MAILTMPLEN];
+  struct stat sbuf;
+				/* must be valid local mailbox */
+  if ((s = mailboxfile (tmp,mailbox)) && *s && !stat (s,&sbuf) &&
+      ((sbuf.st_mode & S_IFMT) == S_IFREG)) return sm_subscribe (mailbox);
+  sprintf (tmp,"Can't subscribe %.80s: not a mailbox",mailbox);
+  mm_log (tmp,ERROR);
+  return NIL;
+}
+
+/* Dummy list mailboxes worker routine
+ * Accepts: mail stream
+ *	    directory name to search
+ *	    search pattern
+ *	    string to scan
+ *	    search level
+ */
+
+void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents,
+		      long level)
+{
+  unsigned long i = 1;
+  FILEFINDBUF3 f;
+  HDIR hd = HDIR_CREATE;
+  struct stat sbuf;
+  char tmp[MAILTMPLEN];
+				/* punt if bogus name */
+  if (!mailboxdir (tmp,dir,NIL)) return;
+				/* make directory wildcard */
+  strcat (tmp,(tmp[strlen (tmp) -1] == '\\') ? "*.*" : "\\*.*");
+				/* do nothing if can't open directory */
+  if (!DosFindFirst (tmp,&hd,FILE_NORMAL,&f,sizeof (f),&i,FIL_STANDARD)) {
+				/* list it if not at top-level */
+    if (!level && dir && pmatch_full (dir,pat,'\\'))
+      dummy_listed (stream,'\\',dir,LATT_NOSELECT,contents);
+				/* scan directory */
+    if (!dir || dir[strlen (dir) -1] == '\\') do {
+      if (((f.name[0] != '.') ||
+	   (f.name[1] && ((f.name[1] != '.') || f.name[2]))) &&
+	  (strlen (f.name) <= NETMAXMBX)) {
+				/* see if name is useful */
+	if (dir) sprintf (tmp,"%s%s",dir,f.name);
+	else strcpy (tmp,f.name);
+				/* make sure useful and can get info */
+	if ((pmatch_full (tmp,pat,'\\') ||
+	     pmatch_full (strcat (tmp,"\\"),pat,'\\') ||
+	     dmatch (tmp,pat,'\\')) &&
+	    mailboxdir (tmp,dir,f.name) && tmp[0] && !stat (tmp,&sbuf)) {
+				/* now make name we'd return */
+	  if (dir) sprintf (tmp,"%s%s",dir,f.name);
+	  else strcpy (tmp,f.name);
+				/* only interested in file type */
+	  switch (sbuf.st_mode & S_IFMT) {
+	  case S_IFDIR:		/* directory? */
+	    if (pmatch_full (tmp,pat,'\\')) {
+	      if (!dummy_listed (stream,'\\',tmp,LATT_NOSELECT,contents))break;
+	      strcat (tmp,"\\");/* set up for dmatch call */
+	    }
+				/* try again with trailing \ */
+	    else if (pmatch_full (strcat (tmp,"\\"),pat,'\\') &&
+		     !dummy_listed (stream,'\\',tmp,LATT_NOSELECT,contents))
+	      break;
+	    if (dmatch (tmp,pat,'\\') &&
+		(level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL)))
+	      dummy_list_work (stream,tmp,pat,contents,level+1);
+	    break;
+	  case S_IFREG:		/* ordinary name */
+	    if (pmatch_full (tmp,pat,'\\') && !pmatch ("INBOX",tmp))
+	      dummy_listed (stream,'\\',tmp,LATT_NOINFERIORS,contents);
+	    break;
+	  }
+	}
+      }
+      i = 1;
+    } while (!DosFindNext (h,&f,sizeof (f),&i));
+  }
+}
+
+/* Mailbox found
+ * Accepts: hierarchy delimiter
+ *	    mailbox name
+ *	    attributes
+ *	    contents to search before calling mm_list()
+ * Returns: T, always
+ */
+
+#define BUFSIZE 4*MAILTMPLEN
+
+long dummy_listed (MAILSTREAM *stream,char delimiter,char *name,
+		   long attributes,char *contents)
+{
+  struct stat sbuf;
+  int fd;
+  long csiz,ssiz,bsiz;
+  char *s,*buf,tmp[MAILTMPLEN];
+  if (contents) {		/* want to search contents? */
+				/* forget it if can't select or open */
+    if ((attributes & LATT_NOSELECT) || !(csiz = strlen (contents)) ||
+	!(s = dummy_file (tmp,name)) || stat (s,&sbuf) ||
+	(csiz > sbuf.st_size) || ((fd = open (tmp,O_RDONLY,NIL)) < 0))
+      return T;
+				/* get buffer including slop */    
+    buf = (char *) fs_get (BUFSIZE + (ssiz = 4 * ((csiz / 4) + 1)) + 1);
+    memset (buf,'\0',ssiz);	/* no slop area the first time */
+    while (sbuf.st_size) {	/* until end of file */
+      read (fd,buf+ssiz,bsiz = min (sbuf.st_size,BUFSIZE));
+      if (search ((unsigned char *) buf,bsiz+ssiz,
+		  (unsigned char *) contents,csiz)) break;
+      memcpy (buf,buf+BUFSIZE,ssiz);
+      sbuf.st_size -= bsiz;	/* note that we read that much */
+    }
+    fs_give ((void **) &buf);	/* flush buffer */
+    close (fd);			/* finished with file */
+    if (!sbuf.st_size) return T;/* not found */
+  }
+				/* notify main program */
+  mm_list (stream,delimiter,name,attributes);
+  return T;
+}
+
+/* Dummy create mailbox
+ * Accepts: mail stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_create (MAILSTREAM *stream,char *mailbox)
+{
+  char tmp[MAILTMPLEN];
+  if (compare_cstring (mailbox,"INBOX") && dummy_file (tmp,mailbox))
+    return dummy_create_path (stream,tmp,NIL);
+  sprintf (tmp,"Can't create %.80s: invalid name",mailbox);
+  mm_log (tmp,ERROR);
+  return NIL;
+}
+
+
+/* Dummy create path
+ * Accepts: mail stream
+ *	    path name to create
+ *	    directory mode
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode)
+{
+  struct stat sbuf;
+  char c,*s,tmp[MAILTMPLEN];
+  int fd;
+  long ret = NIL;
+  char *t = strrchr (path,'\\');
+  char *pt = (path[1] == ':') ? path + 2 : path;
+  int wantdir = t && !t[1];
+  if (wantdir) *t = '\0';	/* flush trailing delimiter for directory */
+				/* found superior to this name? */
+  if ((s = strrchr (pt,'\\')) && (s != pt)) {
+    strncpy (tmp,path,(size_t) (s - path));
+    tmp[s - path] = '\0';	/* make directory name for stat */
+    c = *++s;			/* tie off in case need to recurse */
+    *s = '\0';
+				/* name doesn't exist, create it */
+    if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+	!dummy_create_path (stream,path,dirmode)) return NIL;
+    *s = c;			/* restore full name */
+  }
+  if (wantdir) {		/* want to create directory? */
+    ret = !mkdir (path);
+    *t = '\\';			/* restore directory delimiter */
+  }
+				/* create file */
+  else if ((fd = open (path,O_WRONLY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE)) >= 0)
+    ret = !close (fd);		/* close file */
+  if (!ret) {			/* error? */
+    sprintf (tmp,"Can't create mailbox node %.80s: %.80s",path,
+	     strerror (errno));
+    mm_log (tmp,ERROR);
+  }
+  return ret;			/* return status */
+}
+
+/* Dummy delete mailbox
+ * Accepts: mail stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_delete (MAILSTREAM *stream,char *mailbox)
+{
+  struct stat sbuf;
+  char *s,tmp[MAILTMPLEN];
+  if (!(s = dummy_file (tmp,mailbox))) {
+    sprintf (tmp,"Can't delete - invalid name: %.80s",s);
+    mm_log (tmp,ERROR);
+  }
+				/* no trailing \ */
+  if ((s = strrchr (tmp,'\\')) && !s[1]) *s = '\0';
+  if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) == S_IFDIR) ?
+      rmdir (tmp) : unlink (tmp)) {
+    sprintf (tmp,"Can't delete mailbox %.80s: %.80s",mailbox,strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+  return T;			/* return success */
+}
+
+
+/* Mail rename mailbox
+ * Accepts: mail stream
+ *	    old mailbox name
+ *	    new mailbox name
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  struct stat sbuf;
+  char c,*s,tmp[MAILTMPLEN],mbx[MAILTMPLEN],oldname[MAILTMPLEN];
+  long ret = NIL;
+				/* no trailing \ allowed */
+  if (!dummy_file (oldname,old) || !(s = dummy_file (mbx,newname)) ||
+      ((s = strrchr (s,'\\')) && !s[1])) {
+    sprintf (mbx,"Can't rename %.80s to %.80s: invalid name",old,newname);
+    mm_log (mbx,ERROR);
+    return NIL;
+  }
+				/* found superior to destination name? */
+  if (s && (s != mbx) && ((mbx[1] != ':') || (s != mbx + 2))) {
+    c = s[1];			/* remember character after delimiter */
+    *s = s[1] = '\0';		/* tie off name at delimiter */
+				/* name doesn't exist, create it */
+    if (stat (mbx,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) {
+      *s = '\\';		/* restore delimiter */
+      if (!dummy_create (stream,mbx)) return NIL;
+    }
+    else *s = '\\';		/* restore delimiter */
+    s[1] = c;			/* restore character after delimiter */
+  }
+				/* rename of non-ex INBOX creates dest */
+  if (!compare_cstring (old,"INBOX") && stat (oldname,&sbuf))
+    return dummy_create (NIL,mbx);
+  if (rename (oldname,mbx)) {
+    sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %.80s",old,newname,
+	     strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+  return LONGT;			/* return success */
+}
+
+/* Dummy open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *dummy_open (MAILSTREAM *stream)
+{
+  int fd;
+  char err[MAILTMPLEN],tmp[MAILTMPLEN];
+  struct stat sbuf;
+				/* OP_PROTOTYPE call */
+  if (!stream) return &dummyproto;
+  err[0] = '\0';		/* no error message yet */
+				/* can we open the file? */
+  if (!dummy_file (tmp,stream->mailbox))
+    sprintf (err,"Can't open this name: %.80s",stream->mailbox);
+  else if ((fd = open (tmp,O_RDONLY,NIL)) < 0) {
+				/* no, error unless INBOX */
+    if (compare_cstring (stream->mailbox,"INBOX"))
+      sprintf (err,"%.80s: %.80s",strerror (errno),stream->mailbox);
+  }
+  else {			/* file had better be empty then */
+    fstat (fd,&sbuf);		/* sniff at its size */
+    close (fd);
+    if (sbuf.st_size)		/* bogus format if non-empty */
+      sprintf (err,"%.80s (file %.80s) is not in valid mailbox format",
+	       stream->mailbox,tmp);
+  }
+  if (err[0]) {			/* if an error happened */
+    mm_log (err,stream->silent ? WARN : ERROR);
+    return NIL;
+  }
+  else if (!stream->silent) {	/* only if silence not requested */
+    mail_exists (stream,0);	/* say there are 0 messages */
+    mail_recent (stream,0);	/* and certainly no recent ones! */
+    stream->uid_validity = time (0);
+  }
+  stream->inbox = T;		/* note that it's an INBOX */
+  return stream;		/* return success */
+}
+
+
+/* Dummy close
+ * Accepts: MAIL stream
+ *	    options
+ */
+
+void dummy_close (MAILSTREAM *stream,long options)
+{
+				/* return silently */
+}
+
+/* Dummy ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ */
+
+long dummy_ping (MAILSTREAM *stream)
+{
+  MAILSTREAM *test;
+				/* time to do another test? */
+  if (time (0) >= ((time_t) (stream->gensym + 30))) {
+				/* has mailbox format changed? */
+    if ((test = mail_open (NIL,stream->mailbox,OP_PROTOTYPE)) &&
+	(test->dtb != stream->dtb) &&
+	(test = mail_open (NIL,stream->mailbox,NIL))) {
+				/* preserve some resources */
+      test->original_mailbox = stream->original_mailbox;
+      stream->original_mailbox = NIL;
+      test->sparep = stream->sparep;
+      stream->sparep = NIL;
+      test->sequence = stream->sequence;
+      mail_close ((MAILSTREAM *) /* flush resources used by dummy stream */
+		  memcpy (fs_get (sizeof (MAILSTREAM)),stream,
+			  sizeof (MAILSTREAM)));
+				/* swap the streams */
+      memcpy (stream,test,sizeof (MAILSTREAM));
+      fs_give ((void **) &test);/* flush test now that copied */
+				/* make sure application knows */
+      mail_exists (stream,stream->recent = stream->nmsgs);
+    }
+				/* still hasn't changed */
+    else stream->gensym = time (0);
+  }
+  return T;
+}
+
+
+/* Dummy check mailbox
+ * Accepts: MAIL stream
+ * No-op for readonly files, since read/writer can expunge it from under us!
+ */
+
+void dummy_check (MAILSTREAM *stream)
+{
+  dummy_ping (stream);		/* invoke ping */
+}
+
+
+/* Dummy expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long dummy_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  return LONGT;
+}
+
+/* Dummy copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    options
+ * Returns: T if copy successful, else NIL
+ */
+
+long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+      mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy");
+  return NIL;
+}
+
+
+/* Dummy append message string
+ * Accepts: mail stream
+ *	    destination mailbox
+ *	    append callback function
+ *	    data for callback
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct stat sbuf;
+  int fd = -1;
+  int e;
+  char tmp[MAILTMPLEN];
+  MAILSTREAM *ts = default_proto (T);
+  if (compare_cstring (mailbox,"INBOX") && dummy_file (tmp,mailbox) &&
+      ((fd = open (tmp,O_RDONLY,NIL)) < 0)) {
+    if ((e = errno) == ENOENT)	/* failed, was it no such file? */
+      mm_notify (stream,"[TRYCREATE] Must create mailbox before append",
+		 (long) NIL);
+    sprintf (tmp,"%.80s: %.80s",strerror (e),mailbox);
+    mm_log (tmp,ERROR);		/* pass up error */
+    return NIL;			/* always fails */
+  }
+  if (fd >= 0) {		/* found file? */
+    fstat (fd,&sbuf);		/* get its size */
+    close (fd);			/* toss out the fd */
+    if (sbuf.st_size) ts = NIL;	/* non-empty file? */
+  }
+  if (ts) return (*ts->dtb->append) (stream,mailbox,af,data);
+  sprintf (tmp,"Indeterminate mailbox format: %.80s",mailbox);
+  mm_log (tmp,ERROR);
+  return NIL;
+}
+
+/* Dummy mail generate file string
+ * Accepts: temporary buffer to write into
+ *	    mailbox name string
+ * Returns: local file string or NIL if failure
+ */
+
+char *dummy_file (char *dst,char *name)
+{
+  char *s = mailboxfile (dst,name);
+				/* return our standard inbox */
+  return (s && !*s) ? strcpy (dst,sysinbox ()) : s;
+}
+
+
+/* Dummy canonicalize name
+ * Accepts: buffer to write name
+ *	    reference
+ *	    pattern
+ * Returns: T if success, NIL if failure
+ */
+
+long dummy_canonicalize (char *tmp,char *ref,char *pat)
+{
+  unsigned long i;
+  char *s,dev[4];
+				/* initially no device */
+  dev[0] = dev[1] = dev[2] = dev[3] = '\0';
+  if (ref) switch (*ref) {	/* preliminary reference check */
+  case '{':			/* remote names not allowed */
+    return NIL;			/* disallowed */
+  case '\0':			/* empty reference string */
+    break;
+  default:			/* all other names */
+    if (ref[1] == ':') {	/* start with device name? */
+      dev[0] = *ref++; dev[1] = *ref++;
+    }
+    break;
+  }
+  if (pat[1] == ':') {		/* device name in pattern? */
+    dev[0] = *pat++; dev[1] = *pat++;
+    ref = NIL;			/* ignore reference */
+  }
+  switch (*pat) {
+  case '#':			/* namespace names */
+    if (mailboxfile (tmp,pat)) strcpy (tmp,pat);
+    else return NIL;		/* unknown namespace */
+    break;
+  case '{':			/* remote names not allowed */
+    return NIL;
+  case '\\':			/* rooted name */
+    ref = NIL;			/* ignore reference */
+    break;
+  }
+				/* make sure device names are rooted */
+  if (dev[0] && (*(ref ? ref : pat) != '\\')) dev[2] = '\\';
+				/* build name */
+  sprintf (tmp,"%s%s%s",dev,ref ? ref : "",pat);
+  ucase (tmp);			/* force upper case */
+				/* count wildcards */
+  for (i = 0, s = tmp; *s; *s++) if ((*s == '*') || (*s == '%')) ++i;
+  if (i > MAXWILDCARDS) {	/* ridiculous wildcarding? */
+    MM_LOG ("Excessive wildcards in LIST/LSUB",ERROR);
+    return NIL;
+  }
+  return T;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/os2/env_os2.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,318 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	OS/2 environment routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+static char *myLocalHost = NIL;	/* local host name */
+static char *myHomeDir = NIL;	/* home directory name */
+static char *myNewsrc = NIL;	/* newsrc file name */
+static short no822tztext = NIL;	/* disable RFC [2]822 timezone text */
+
+#include "write.c"		/* include safe writing routines */
+#include "pmatch.c"		/* include wildcard pattern matcher */
+
+
+/* Get all authenticators */
+
+#include "auths.c"
+
+/* Environment manipulate parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *env_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case SET_HOMEDIR:
+    myHomeDir = cpystr ((char *) value);
+  case GET_HOMEDIR:
+    ret = (void *) myHomeDir;
+    break;
+  case SET_LOCALHOST:
+    myLocalHost = cpystr ((char *) value);
+  case GET_LOCALHOST:
+    ret = (void *) myLocalHost;
+    break;
+  case SET_NEWSRC:
+    if (myNewsrc) fs_give ((void **) &myNewsrc);
+    myNewsrc = cpystr ((char *) value);
+  case GET_NEWSRC:
+    if (!myNewsrc) {		/* set news file name if not defined */
+      char tmp[MAILTMPLEN];
+      sprintf (tmp,"%s\\newsrc",myhomedir ());
+      myNewsrc = cpystr (tmp);
+    }
+    ret = (void *) myNewsrc;
+    break;
+  case SET_DISABLE822TZTEXT:
+    no822tztext = value ? T : NIL;
+  case GET_DISABLE822TZTEXT:
+    ret = (void *) (no822tztext ? VOIDT : NIL);
+    break;
+  }
+  return ret;
+}
+
+/* Write current time
+ * Accepts: destination string
+ *	    optional format of day-of-week prefix
+ *	    format of date and time
+ *	    flag whether to append symbolic timezone
+ */
+
+static void do_date (char *date,char *prefix,char *fmt,int suffix)
+{
+  time_t tn = time (0);
+  struct tm *t = gmtime (&tn);
+  int zone = t->tm_hour * 60 + t->tm_min;
+  int julian = t->tm_yday;
+  t = localtime (&tn);		/* get local time now */
+				/* minus UTC minutes since midnight */
+  zone = t->tm_hour * 60 + t->tm_min - zone;
+  /* julian can be one of:
+   *  36x  local time is December 31, UTC is January 1, offset -24 hours
+   *    1  local time is 1 day ahead of UTC, offset +24 hours
+   *    0  local time is same day as UTC, no offset
+   *   -1  local time is 1 day behind UTC, offset -24 hours
+   * -36x  local time is January 1, UTC is December 31, offset +24 hours
+   */
+  if (julian = t->tm_yday -julian)
+    zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
+  if (prefix) {			/* want day of week? */
+    sprintf (date,prefix,days[t->tm_wday]);
+    date += strlen (date);	/* make next sprintf append */
+  }
+				/* output the date */
+  sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
+	   t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
+  if (suffix) {			/* append timezone suffix if desired */
+    char *tz;
+    tzset ();			/* get timezone from TZ environment stuff */
+    tz = tzname[daylight ? (((struct tm *) t)->tm_isdst > 0) : 0];
+    if (tz && tz[0]) {
+      char *s;
+      for (s = tz; *s; s++) if (*s & 0x80) return;
+      sprintf (date + strlen (date)," (%.50s)",tz);
+    }
+  }
+}
+
+
+/* Write current time in RFC 822 format
+ * Accepts: destination string
+ */
+
+void rfc822_date (char *date)
+{
+  do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d",
+	   no822tztext ? NIL : T);
+}
+
+
+/* Write current time in fixed-width RFC 822 format
+ * Accepts: destination string
+ */
+
+void rfc822_fixed_date (char *date)
+{
+  do_date (date,NIL,"%02d %s %4d %02d:%02d:%02d %+03d%02d",NIL);
+}
+
+
+/* Write current time in internal format
+ * Accepts: destination string
+ */
+
+void internal_date (char *date)
+{
+  do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL);
+}
+
+/* Return my home directory name
+ * Returns: my home directory name
+ */
+
+char *myhomedir ()
+{
+  if (!myHomeDir) {		/* get home directory name if not yet known */
+    char *s;
+    if ((s = getenv ("PINEHOME")) || (s = getenv ("HOME")) ||
+	(s = getenv ("ETC"))) {
+      myHomeDir = cpystr (s);
+      while (s = strchr (myHomeDir,'/')) *s = '\\';
+      if ((s = strrchr (myHomeDir,'\\')) && !s[1]) *s = '\0';
+    }
+    else myHomeDir = cpystr ("");
+  }
+  return myHomeDir;
+}
+
+
+/* Return mailbox file name
+ * Accepts: destination buffer
+ *	    mailbox name
+ * Returns: file name
+ */
+
+char *mailboxfile (char *dst,char *name)
+{
+  char *s;
+  char *ext = (char *) mail_parameters (NIL,GET_EXTENSION,NIL);
+				/* forbid extraneous extensions */
+  if ((s = strchr ((s = strrchr (name,'\\')) ? s : name,'.')) &&
+      ((ext = (char *) mail_parameters (NIL,GET_EXTENSION,NIL)) ||
+       strchr (s+1,'.'))) return NIL;
+				/* absolute path name? */
+  if ((*name == '\\') || (name[1] == ':')) strcpy (dst,name);
+  else sprintf (dst,"%s\\%s",myhomedir (),name);
+  if (ext) sprintf (dst + strlen (dst),".%s",ext);
+  return dst;
+}
+
+/* Lock file name
+ * Accepts: return buffer for file name
+ *	    file name
+ *	    locking to be placed on file if non-NIL
+ * Returns: file descriptor of lock or -1 if error
+ */
+
+int lockname (char *lock,char *fname,int op)
+{
+  int ld;
+  char c,*s;
+  if (!((s = lockdir (lock,getenv ("TEMP"),NIL)) ||
+	(s = lockdir (lock,getenv ("TMP"),NIL)) ||
+	(s = lockdir (lock,getenv ("TMPDIR"),NIL)) ||
+				/* C:\TEMP is last resort */
+	(s = lockdir (lock,defaultDrive (),"TEMP")))) {
+    mm_log ("Unable to find temporary directory",ERROR);
+    return -1;
+  }
+				/* generate file name */
+  while (c = *fname++) switch (c) {
+  case '/': case '\\': case ':':
+    *s++ = '!';			/* convert bad chars to ! */
+    break;
+  default:
+    *s++ = c;
+    break;
+  }
+  *s++ = c;			/* tie off name */
+				/* get the lock */
+  if (((ld = open (lock,O_BINARY|O_RDWR|O_CREAT,S_IREAD|S_IWRITE)) >= 0) && op)
+    flock (ld,op);		/* apply locking function */
+  return ld;			/* return locking file descriptor */
+}
+
+/* Build lock directory, check to see if it exists
+ * Accepts: return buffer for lock directory
+ *	    first part of possible name
+ *	    optional second part
+ * Returns: pointer to end of buffer if buffer has a good name, else NIL
+ */
+
+char *lockdir (char *lock,char *first,char *last)
+{
+  struct stat sbuf;
+  char c,*s;
+  if (first && *first) {	/* first part must be non-NIL */
+				/* copy first part */
+    for (s = lock; *first; c = *s++ = *first++);
+    if (last && *last) {	/* copy last part if specified */
+				/* write trailing \ in case not in first */
+      if (c != '\\') *s++ = '\\';
+      while (*last) c = *s++ = *last++;
+    }
+    if (c == '\\') --s;		/* delete trailing \ if any */
+    *s = '\0';			/* tie off name at this point */
+    return stat (lock,&sbuf) ? NIL : s;
+  }
+  return NIL;			/* failed */
+}
+
+
+/* Unlock file descriptor
+ * Accepts: file descriptor
+ *	    lock file name from lockfd()
+ */
+
+void unlockfd (int fd,char *lock)
+{
+  flock (fd,LOCK_UN);		/* unlock it */
+  close (fd);			/* close it */
+}
+
+
+/* Determine default prototype stream to user
+ * Accepts: type (NIL for create, T for append)
+ * Returns: default prototype stream
+ */
+
+MAILSTREAM *default_proto (long type)
+{
+  extern MAILSTREAM DEFAULTPROTO;
+  return &DEFAULTPROTO;		/* return default driver's prototype */
+}
+
+/* Global data */
+
+static unsigned rndm = 0;	/* initial `random' number */
+
+
+/* Return random number
+ */
+
+long random ()
+{
+  if (!rndm) srand (rndm = (unsigned) time (0L));
+  return (long) rand ();
+}
+
+
+/* Emulator for BSD syslog() routine
+ * Accepts: priority
+ *	    message
+ *	    parameters
+ */
+
+void syslog (int priority,const char *message,...)
+{
+}
+
+
+/* Emulator for BSD openlog() routine
+ * Accepts: identity
+ *	    options
+ *	    facility
+ */
+
+void openlog (const char *ident,int logopt,int facility)
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/os2/env_os2.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,62 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	OS/2 environment routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	14 March 1996
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Function prototypes */
+
+#include "env.h"
+
+long random (void);
+
+
+/* syslog() emulation */
+
+#define LOG_MAIL	(2<<3)	/* mail system */
+#define LOG_DAEMON	(3<<3)	/* system daemons */
+#define LOG_AUTH	(4<<3)	/* security/authorization messages */
+#define LOG_EMERG	0	/* system is unusable */
+#define LOG_ALERT	1	/* action must be taken immediately */
+#define LOG_CRIT	2	/* critical conditions */
+#define LOG_ERR		3	/* error conditions */
+#define LOG_WARNING	4	/* warning conditions */
+#define LOG_NOTICE	5	/* normal but signification condition */
+#define LOG_INFO	6	/* informational */
+#define LOG_DEBUG	7	/* debug-level messages */
+#define LOG_PID		0x01	/* log the pid with each message */
+#define LOG_CONS	0x02	/* log on the console if errors in sending */
+#define LOG_ODELAY	0x04	/* delay open until syslog() is called */
+#define LOG_NDELAY	0x08	/* don't delay open */
+#define LOG_NOWAIT	0x10	/* if forking to log on console, don't wait() */
+
+void openlog (const char *ident,int logopt,int facility);
+void syslog (int priority,const char *message,...);
+
+void rfc822_fixed_date (char *date);
+int lockname (char *lock,char *fname,int op);
+char *lockdir (char *lock,char *first,char *last);
+void unlockfd (int fd,char *lock);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/os2/fs_os2.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,62 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Free storage management routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Get a block of free storage
+ * Accepts: size of desired block
+ * Returns: free storage block
+ */
+
+void *fs_get (size_t size)
+{
+  void *block = malloc (size ? size : (size_t) 1);
+  if (!block) fatal ("Out of memory");
+  return (block);
+}
+
+
+/* Resize a block of free storage
+ * Accepts: ** pointer to current block
+ *	    new size
+ */
+
+void fs_resize (void **block,size_t size)
+{
+  if (!(*block = realloc (*block,size ? size : (size_t) 1)))
+    fatal ("Can't resize memory");
+}
+
+
+/* Return a block of free storage
+ * Accepts: ** pointer to free storage block
+ */
+
+void fs_give (void **block)
+{
+  free (*block);
+  *block = NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/os2/ftl_os2.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,38 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	DOS/VMS/TOPS-20 crash management routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Report a fatal error
+ * Accepts: string to output
+ */
+
+void fatal (char *string)
+{
+  mm_fatal (string);		/* pass up the string */
+  abort ();			/* die horribly */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/os2/makefile.os2	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,109 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+# Program:	Portable C client makefile -- OS/2 version
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		11 May 1989
+# Last Edited:	30 August 2006
+
+
+EXTRAAUTHENTICATORS =
+EXTRADRIVERS =
+EXTRACFLAGS =
+DEFAULTAUTHENTICATORS = ext md5 pla log
+DRIVERS = imap nntp pop3 mbx mtx tenex unix
+DEFAULTDRIVER =	mbx
+CFLAGS = -DOMF -DCHUNKSIZE=65536 -O2 -Zomf $(EXTRACFLAGS)
+CC = gcc
+CCLIENTLIB = cclient.lib
+
+all:	$(CCLIENTLIB)
+
+.c.obj:
+	$(CC) $(CFLAGS) -o $@ -c $*.c
+
+osdep.h: os_os2.h
+	copy os_os2.h osdep.h
+	drivers.cmd $(EXTRADRIVERS) $(DRIVERS) dummy
+	auths.cmd $(EXTRAAUTHENTICATORS) $(DEFAULTAUTHENTICATORS)
+	setproto.cmd $(DEFAULTDRIVER)
+
+mail.obj: mail.h misc.h osdep.h mail.c
+
+misc.obj: mail.h misc.h misc.c
+
+fdstring.obj: mail.h misc.h osdep.h fdstring.h fdstring.c
+
+flstring.obj: mail.h misc.h osdep.h flstring.h flstring.c
+
+netmsg.obj: mail.h misc.h netmsg.h osdep.h netmsg.c
+
+newsrc.obj: mail.h misc.h newsrc.h osdep.h newsrc.c
+
+rfc822.obj: mail.h rfc822.h misc.h rfc822.c
+
+smanager.obj: mail.h misc.h smanager.c
+
+utf8.obj: mail.h misc.h osdep.h utf8.h
+
+utf8aux.obj: mail.h misc.h osdep.h utf8.h
+
+imap4r1.obj: mail.h imap4r1.h misc.h osdep.h imap4r1.c
+
+nntp.obj: mail.h nntp.h smtp.h rfc822.h misc.h osdep.h nntp.c
+
+pop3.obj: mail.h rfc822.h misc.h osdep.h pop3.c
+
+smtp.obj: mail.h smtp.h rfc822.h misc.h osdep.h smtp.c
+
+os_os2.obj: mail.h osdep.h env_os2.h fs.h ftl.h nl.h tcp.h tcp_os2.h \
+	os_os2.c fs_os2.c ftl_os2.c nl_os2.c env_os2.c tcp_os2.c \
+	mailfile.h auth_md5.c auth_log.c pmatch.c write.c
+
+mbxnt.obj: mail.h misc.h osdep.h mbxnt.c
+
+mtxnt.obj: mail.h misc.h osdep.h mtxnt.c
+
+tenexnt.obj: mail.h misc.h osdep.h tenexnt.c
+
+unixnt.obj: mail.h unixnt.h pseudo.h misc.h osdep.h unixnt.c
+
+dummyos2.obj: mail.h dummy.h misc.h osdep.h dummyos2.c
+
+pseudo.obj: pseudo.h
+
+$(CCLIENTLIB): mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \
+	newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
+	imap4r1.obj nntp.obj pop3.obj smtp.obj os_os2.obj \
+	mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj
+	del $(CCLIENTLIB)
+	LIB /NOLOGO /OUT:$(CCLIENTLIB) \
+	mail.obj misc.obj fdstring.obj flstring.obj netmsg.obj \
+	newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
+	imap4r1.obj nntp.obj pop3.obj smtp.obj os_os2.obj \
+	mbxnt.obj mtxnt.obj tenexnt.obj unixnt.obj dummynt.obj pseudo.obj
+
+clean:
+	del *.lib *.obj linkage.* osdep.* auths.c *.exe *.exp
+
+# A monument to a hack of long ago and far away...
+
+love:
+	@echo not war?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/os2/mbxnt.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1694 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	MBX mail routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	3 October 1995
+ * Last Edited:	28 September 2007
+ */
+
+
+/*				FILE TIME SEMANTICS
+ *
+ * The atime is the last read time of the file.
+ * The mtime is the last flags update time of the file.
+ * The ctime is the last write time of the file.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "mail.h"
+#include "osdep.h"
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/utime.h>
+#include "misc.h"
+#include "dummy.h"
+#include "fdstring.h"
+
+
+/* Build parameters */
+
+#define HDRSIZE 2048
+
+/* MBX I/O stream local data */
+	
+typedef struct mbx_local {
+  unsigned int flagcheck: 1;	/* if ping should sweep for flags */
+  unsigned int expok: 1;	/* if expunging OK in ping */
+  unsigned int expunged : 1;	/* if one or more expunged messages */
+  int fd;			/* file descriptor for I/O */
+  int ld;			/* lock file descriptor */
+  int ffuserflag;		/* first free user flag */
+  off_t filesize;		/* file size parsed */
+  time_t filetime;		/* last file time */
+  time_t lastsnarf;		/* last snarf time */
+  unsigned char *buf;		/* temporary buffer */
+  unsigned long buflen;		/* current size of temporary buffer */
+  char lock[MAILTMPLEN];	/* buffer to write lock name */
+} MBXLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((MBXLOCAL *) stream->local)
+
+/* Function prototypes */
+
+DRIVER *mbx_valid (char *name);
+int mbx_isvalid (MAILSTREAM **stream,char *name,char *file,int *ld,char *lock,
+		 long flags);
+void *mbx_parameters (long function,void *value);
+void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void mbx_list (MAILSTREAM *stream,char *ref,char *pat);
+void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long mbx_create (MAILSTREAM *stream,char *mailbox);
+long mbx_delete (MAILSTREAM *stream,char *mailbox);
+long mbx_rename (MAILSTREAM *stream,char *old,char *newname);
+long mbx_status (MAILSTREAM *stream,char *mbx,long flags);
+MAILSTREAM *mbx_open (MAILSTREAM *stream);
+void mbx_close (MAILSTREAM *stream,long options);
+void mbx_abort (MAILSTREAM *stream);
+void mbx_flags (MAILSTREAM *stream,char *sequence,long flags);
+char *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
+		  long flags);
+long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
+void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
+long mbx_ping (MAILSTREAM *stream);
+void mbx_check (MAILSTREAM *stream);
+long mbx_expunge (MAILSTREAM *stream,char *sequence,long options);
+void mbx_snarf (MAILSTREAM *stream);
+long mbx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long mbx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+long mbx_parse (MAILSTREAM *stream);
+MESSAGECACHE *mbx_elt (MAILSTREAM *stream,unsigned long msgno,long expok);
+unsigned long mbx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt);
+void mbx_update_header (MAILSTREAM *stream);
+void mbx_update_status (MAILSTREAM *stream,unsigned long msgno,long flags);
+unsigned long mbx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			  unsigned long *size,char **hdr);
+unsigned long mbx_rewrite (MAILSTREAM *stream,unsigned long *reclaimed,
+			   long flags);
+long mbx_flaglock (MAILSTREAM *stream);
+
+/* MBX mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER mbxdriver = {
+  "mbx",			/* driver name */
+  DR_LOCAL|DR_MAIL|DR_CRLF|DR_LOCKING,
+				/* driver flags */
+  (DRIVER *) NIL,		/* next driver */
+  mbx_valid,			/* mailbox is valid for us */
+  mbx_parameters,		/* manipulate parameters */
+  mbx_scan,			/* scan mailboxes */
+  mbx_list,			/* list mailboxes */
+  mbx_lsub,			/* list subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  mbx_create,			/* create mailbox */
+  mbx_delete,			/* delete mailbox */
+  mbx_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  mbx_open,			/* open mailbox */
+  mbx_close,			/* close mailbox */
+  mbx_flags,			/* fetch message "fast" attributes */
+  mbx_flags,			/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  mbx_header,			/* fetch message header */
+  mbx_text,			/* fetch message body */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  mbx_flag,			/* modify flags */
+  mbx_flagmsg,			/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  mbx_ping,			/* ping mailbox to see if still alive */
+  mbx_check,			/* check for new messages */
+  mbx_expunge,			/* expunge deleted messages */
+  mbx_copy,			/* copy messages to another mailbox */
+  mbx_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM mbxproto = {&mbxdriver};
+
+/* MBX mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *mbx_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+  int fd = mbx_isvalid (NIL,name,tmp,NIL,NIL,NIL);
+  if (fd < 0) return NIL;
+  close (fd);			/* don't need the fd now */
+  return &mbxdriver;
+}
+
+
+/* MBX mail test for valid mailbox
+ * Accepts: returned stream with valid mailbox keywords
+ *	    mailbox name
+ *	    buffer to write file name
+ *	    returned lock fd
+ *	    returned lock name
+ *	    RW flags or NIL for readonly
+ * Returns: file descriptor if valid, NIL otherwise
+ */
+
+#define MBXISVALIDNOUID 0x1	/* RW, don't do UID action */
+#define MBXISVALIDUID 0x2	/* RW, do UID action */
+
+int mbx_isvalid (MAILSTREAM **stream,char *name,char *file,int *ld,char *lock,
+		 long flags)
+{
+  int fd,upd;
+  int ret = -1;
+  unsigned long i;
+  long j,k;
+  off_t pos;
+  char c,*s,*t,hdr[HDRSIZE];
+  struct stat sbuf;
+  struct utimbuf times;
+  int error = EINVAL;		/* assume invalid argument */
+  if (ld) *ld = -1;		/* initially no lock */
+				/* if file, get its status */
+  if ((s = dummy_file (file,name)) && !stat (s,&sbuf) &&
+      ((sbuf.st_mode & S_IFMT) == S_IFREG) &&
+      ((fd = open (file,(flags ? O_RDWR : O_RDONLY)|O_BINARY,NIL)) >= 0)) {
+    error = -1;			/* assume bogus format */
+    if (((((j = read (fd,hdr,HDRSIZE)) == HDRSIZE) && (hdr[0] == '*')) ||
+				/* locked, set byte 0 to "*", read rest */
+	 ((j < 0) && (lseek (fd,1,L_SET) == 1) &&
+	  (read (fd,hdr+1,HDRSIZE-1) == (HDRSIZE-1)) && (hdr[0] = '*'))) &&
+	(hdr[1] == 'm') && (hdr[2] == 'b') && (hdr[3] == 'x') &&
+	(hdr[4] == '*') && (hdr[5] == '\015') && (hdr[6] == '\012') &&
+	isxdigit (hdr[7]) && isxdigit (hdr[8]) && isxdigit (hdr[9]) &&
+	isxdigit (hdr[10]) && isxdigit (hdr[11]) && isxdigit (hdr[12]) &&
+	isxdigit (hdr[13]) && isxdigit (hdr[14]) && isxdigit (c = hdr[15]) &&
+	isxdigit (hdr[16]) && isxdigit (hdr[17]) && isxdigit (hdr[18]) &&
+	isxdigit (hdr[19]) && isxdigit (hdr[20]) && isxdigit (hdr[21]) &&
+	isxdigit (hdr[22]) && (hdr[23] == '\015') && (hdr[24] == '\012')) {
+      ret = fd;			/* mbx format */
+
+      if (stream) {		/* lock if making a mini-stream */
+	if (flock (fd,LOCK_SH) ||
+	    (flags && ((*ld = lockname (lock,file,LOCK_EX)) < 0))) ret = -1;
+				/* reread data now that locked */
+	else if (lseek (fd,0,L_SET) ||
+		 (read (fd,hdr+1,HDRSIZE-1) != (HDRSIZE-1))) ret = -1;
+	else {
+	  *stream = (MAILSTREAM *) memset (fs_get (sizeof (MAILSTREAM)),0,
+					   sizeof (MAILSTREAM));
+	  hdr[15] = '\0';	/* tie off UIDVALIDITY */
+	  (*stream)->uid_validity = strtoul (hdr+7,NIL,16);
+	  hdr[15] = c;		/* now get UIDLAST */
+	  (*stream)->uid_last = strtoul (hdr+15,NIL,16);
+				/* parse user flags */
+	  for (i = 0, s = hdr + 25;
+	       (i < NUSERFLAGS) && (t = strchr (s,'\015')) && (t - s);
+	       i++, s = t + 2) {
+	    *t = '\0';		/* tie off flag */
+	    if (strlen (s) <= MAXUSERFLAG)
+	      (*stream)->user_flags[i] = cpystr (s);
+	  }
+				/* make sure have true UIDLAST */
+	  if (flags & MBXISVALIDUID) {
+	    for (upd = NIL,pos = 2048, k = 0; pos < sbuf.st_size;
+		 pos += (j + k)) {
+				/* read header for this message */
+	      lseek (fd,pos,L_SET);
+	      if ((j = read (fd,hdr,64)) >= 0) {
+		hdr[j] = '\0';
+		if ((s = strchr (hdr,'\015')) && (s[1] == '\012')) {
+		  *s = '\0';
+		  k = s + 2 - hdr;
+		  if ((s = strchr (hdr,',')) && (j = strtol (s+1,&s,10)) &&
+		      (*s == ';') && (s = strchr (s+1,'-'))) {
+				/* get UID if there is any */
+		    i = strtoul (++s,&t,16);
+		    if (!*t && (t == (s + 8)) && (i <= (*stream)->uid_last)) {
+		      if (!i) {
+			lseek (fd,pos + s - hdr,L_SET);
+			sprintf (hdr,"%08lx",++(*stream)->uid_last);
+			write (fd,hdr,8);
+			upd = T;
+		      }
+		      continue;
+		    }
+		  }
+		}
+		ret = -1;	/* error, give up */
+		*stream = mail_close (*stream);
+		pos = sbuf.st_size + 1;
+		j = k = 0;
+	      }
+	    }
+
+	    if (upd) {	    /* need to update hdr with new UIDLAST? */
+	      lseek (fd,15,L_SET);
+	      sprintf (hdr,"%08lx",(*stream)->uid_last);
+	      write (fd,hdr,8);
+	    }
+	  }
+	}
+      }
+    }
+    if (ret != fd) close (fd);	/* close the file */
+    else lseek (fd,0,L_SET);	/* else rewind to start */
+				/* \Marked status? */
+    if (sbuf.st_ctime > sbuf.st_atime) {
+				/* preserve atime and mtime */
+      times.actime = sbuf.st_atime;
+      times.modtime = sbuf.st_mtime;
+      utime (file,&times);	/* set the times */
+    }
+  }
+				/* in case INBOX but not mbx format */
+  else if (((error = errno) == ENOENT) && !compare_cstring (name,"INBOX"))
+    error = -1;
+  if ((ret < 0) && ld && (*ld >= 0)) {
+    unlockfd (*ld,lock);
+    *ld = -1;
+  }
+  errno = error;		/* return as last error */
+  return ret;			/* return what we should */
+}
+
+/* MBX manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *mbx_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case SET_ONETIMEEXPUNGEATPING:
+    if (value) ((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expok = T;
+  case GET_ONETIMEEXPUNGEATPING:
+    if (value) ret = (void *)
+      (((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expok ? VOIDT : NIL);
+    break;
+  }
+  return ret;
+}
+
+
+/* MBX mail scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* MBX mail list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mbx_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_list (NIL,ref,pat);
+}
+
+
+/* MBX mail list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_lsub (NIL,ref,pat);
+}
+
+/* MBX mail create mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long mbx_create (MAILSTREAM *stream,char *mailbox)
+{
+  char *s,mbx[MAILTMPLEN],tmp[HDRSIZE];
+  long ret = NIL;
+  int i,fd;
+  if (!(s = dummy_file (mbx,mailbox))) {
+    sprintf (mbx,"Can't create %.80s: invalid name",mailbox);
+    mm_log (mbx,ERROR);
+  }
+				/* create underlying file */
+  else if (dummy_create (stream,s)) {
+				/* done if made directory */
+    if ((s = strrchr (s,'\\')) && !s[1]) return T;
+    if ((fd = open (mbx,O_WRONLY|O_BINARY,NIL)) < 0) {
+      sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno));
+      mm_log (tmp,ERROR);
+      unlink (mbx);		/* delete the file */
+    }
+    else {
+      memset (tmp,'\0',HDRSIZE);/* initialize header */
+      sprintf (s = tmp,"*mbx*\015\012%08lx00000000\015\012",
+	       (unsigned long) time (0));
+      for (i = 0; i < NUSERFLAGS; ++i)
+	sprintf (s += strlen (s),"%s\015\012",
+		 (stream && stream->user_flags[i]) ? stream->user_flags[i] :
+		 "");
+      if (write (fd,tmp,HDRSIZE) != HDRSIZE) {
+	sprintf (tmp,"Can't initialize mailbox node %.80s: %s",
+		 mbx,strerror (errno));
+	mm_log (tmp,ERROR);
+	unlink (mbx);		/* delete the file */
+      }
+      else ret = T;		/* success */
+      close (fd);		/* close file */
+    }
+  }
+  return ret;
+}
+
+
+/* MBX mail delete mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long mbx_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return mbx_rename (stream,mailbox,NIL);
+}
+
+/* MBX mail rename mailbox
+ * Accepts: MAIL stream
+ *	    old mailbox name
+ *	    new mailbox name (or NIL for delete)
+ * Returns: T on success, NIL on failure
+ */
+
+long mbx_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  long ret = LONGT;
+  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  int fd,ld;
+  struct stat sbuf;
+  if (!dummy_file (file,old) ||
+      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
+		   ((s = strrchr (tmp,'\\')) && !s[1])))) {
+    sprintf (tmp,newname ?
+	     "Can't rename mailbox %.80s to %.80s: invalid name" :
+	     "Can't delete mailbox %.80s: invalid name",
+	     old,newname);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+  else if ((fd = open (file,O_RDWR|O_BINARY,NIL)) < 0) {
+    sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* get parse/append permission */
+  if ((ld = lockname (lock,file,LOCK_EX)) < 0) {
+    mm_log ("Unable to lock rename mailbox",ERROR);
+    return NIL;
+  }
+				/* lock out other users */
+  if (flock (fd,LOCK_EX|LOCK_NB)) {
+    close (fd);			/* couldn't lock, give up on it then */
+    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
+    mm_log (tmp,ERROR);
+    unlockfd (ld,lock);		/* release exclusive parse/append permission */
+    return NIL;
+  }
+
+  if (newname) {		/* want rename? */
+				/* found superior to destination name? */
+    if ((s = strrchr (tmp,'\\')) && (s != tmp) &&
+	((tmp[1] != ':') || (s != tmp + 2))) {
+      c = s[1];			/* remember character after delimiter */
+      *s = s[1] = '\0';		/* tie off name at delimiter */
+				/* name doesn't exist, create it */
+      if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) {
+	*s = '\\';		/* restore delimiter */
+	if (!dummy_create (stream,tmp)) ret = NIL;
+      }
+      else *s = '\\';		/* restore delimiter */
+      s[1] = c;			/* restore character after delimiter */
+    }
+    flock (fd,LOCK_UN);		/* release lock on the file */
+    close (fd);			/* pacify NTFS */
+				/* rename the file */
+    if (ret && rename (file,tmp)) {
+      sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
+	       strerror (errno));
+      mm_log (tmp,ERROR);
+      ret = NIL;		/* set failure */
+    }
+  }
+  else {
+    flock (fd,LOCK_UN);		/* release lock on the file */
+    close (fd);			/* pacify NTFS */
+    if (unlink (file)) {
+      sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
+      mm_log (tmp,ERROR);
+      ret = NIL;		/* set failure */
+    }
+  }
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+				/* recreate file if renamed INBOX */
+  if (ret && !compare_cstring (old,"INBOX")) mbx_create (NIL,"INBOX");
+  return ret;			/* return success */
+}
+
+/* MBX mail open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *mbx_open (MAILSTREAM *stream)
+{
+  int fd,ld;
+  short silent;
+  char tmp[MAILTMPLEN];
+  if (!stream) return &mbxproto;/* return prototype for OP_PROTOTYPE call */
+  if (stream->local) fatal ("mbx recycle stream");
+				/* canonicalize the mailbox name */
+  if (!dummy_file (tmp,stream->mailbox)) {
+    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
+    mm_log (tmp,ERROR);
+  }
+  if (stream->rdonly ||
+      (fd = open (tmp,O_RDWR|O_BINARY,NIL)) < 0) {
+    if ((fd = open (tmp,O_RDONLY|O_BINARY,NIL)) < 0) {
+      sprintf (tmp,"Can't open mailbox: %s",strerror (errno));
+      mm_log (tmp,ERROR);
+      return NIL;
+    }
+    else if (!stream->rdonly) {	/* got it, but readonly */
+      mm_log ("Can't get write access to mailbox, access is readonly",WARN);
+      stream->rdonly = T;
+    }
+  }
+
+  stream->local = memset (fs_get (sizeof (MBXLOCAL)),NIL,sizeof (MBXLOCAL));
+  LOCAL->fd = fd;		/* bind the file */
+  LOCAL->ld = -1;		/* no flaglock */
+  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
+  LOCAL->buflen = CHUNKSIZE - 1;
+				/* note if an INBOX or not */
+  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
+  fs_give ((void **) &stream->mailbox);
+  stream->mailbox = cpystr (tmp);
+				/* get parse/append permission */
+  if ((ld = lockname (tmp,stream->mailbox,LOCK_EX)) < 0) {
+    mm_log ("Unable to lock open mailbox",ERROR);
+    return NIL;
+  }
+  flock (LOCAL->fd,LOCK_SH);	/* lock the file */
+  unlockfd (ld,tmp);		/* release shared parse permission */
+  LOCAL->filesize = HDRSIZE;	/* initialize parsed file size */
+  LOCAL->filetime = 0;		/* time not set up yet */
+  LOCAL->expok = LOCAL->flagcheck = NIL;
+  stream->sequence++;		/* bump sequence number */
+				/* parse mailbox */
+  stream->nmsgs = stream->recent = 0;
+  silent = stream->silent;	/* defer events */
+  stream->silent = T;
+  if (mbx_ping (stream) && !stream->nmsgs)
+    mm_log ("Mailbox is empty",(long) NIL);
+  stream->silent = silent;	/* now notify upper level */
+  mail_exists (stream,stream->nmsgs);
+  mail_recent (stream,stream->recent);
+  if (!LOCAL) return NIL;	/* failure if stream died */
+  stream->perm_seen = stream->perm_deleted = stream->perm_flagged =
+    stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T;
+  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
+  stream->kwd_create = (stream->user_flags[NUSERFLAGS-1] || stream->rdonly) ?
+    NIL : T;			/* can we create new user flags? */
+  return stream;		/* return stream to caller */
+}
+
+/* MBX mail close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void mbx_close (MAILSTREAM *stream,long options)
+{
+  if (stream && LOCAL) {	/* only if a file is open */
+    int silent = stream->silent;
+    stream->silent = T;		/* note this stream is dying */
+				/* do an expunge if requested */
+    if (options & CL_EXPUNGE) mbx_expunge (stream,NIL,NIL);
+    else {			/* otherwise do a checkpoint to purge */
+      LOCAL->expok = T;		/*  possible expunged messages */
+      mbx_ping (stream);
+    }
+    stream->silent = silent;	/* restore previous status */
+    mbx_abort (stream);
+  }
+}
+
+
+/* MBX mail abort stream
+ * Accepts: MAIL stream
+ */
+
+void mbx_abort (MAILSTREAM *stream)
+{
+  if (stream && LOCAL) {	/* only if a file is open */
+    flock (LOCAL->fd,LOCK_UN);	/* unlock local file */
+    close (LOCAL->fd);		/* close the local file */
+				/* free local text buffer */
+    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+
+/* MBX mail fetch flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ * Sniffs at file to see if some other process changed the flags
+ */
+
+void mbx_flags (MAILSTREAM *stream,char *sequence,long flags)
+{
+  MESSAGECACHE *elt;
+  unsigned long i;
+  if (mbx_ping (stream) &&	/* ping mailbox, get new status for messages */
+      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
+       mail_sequence (stream,sequence)))
+    for (i = 1; i <= stream->nmsgs; i++) 
+      if ((elt = mail_elt (stream,i))->sequence && !elt->valid)
+	mbx_elt (stream,i,NIL);
+}
+
+/* MBX mail fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+char *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
+		  long flags)
+{
+  unsigned long i;
+  char *s;
+  *length = 0;			/* default to empty */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+				/* get header position, possibly header */
+  i = mbx_hdrpos (stream,msgno,length,&s);
+  if (!s) {			/* mbx_hdrpos() returned header? */
+    lseek (LOCAL->fd,i,L_SET);	/* no, get to header position */
+				/* is buffer big enough? */
+    if (*length > LOCAL->buflen) {
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get ((LOCAL->buflen = *length) + 1);
+    }
+				/* slurp the data */
+    read (LOCAL->fd,s = LOCAL->buf,*length);
+  }
+  s[*length] = '\0';		/* tie off string */
+  return s;
+}
+
+/* MBX mail fetch message text (body only)
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: T on success, NIL on failure
+ */
+
+long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  FDDATA d;
+  unsigned long i,j;
+  MESSAGECACHE *elt;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+				/* get message status */
+  elt = mbx_elt (stream,msgno,NIL);
+				/* if message not seen */
+  if (!(flags & FT_PEEK) && !elt->seen && mbx_flaglock (stream)) {
+    elt->seen = T;		/* mark message as seen */
+				/* recalculate status */
+    mbx_update_status (stream,msgno,NIL);
+    mm_flags (stream,msgno);
+				/* update flags */
+    mbx_flag (stream,NIL,NIL,NIL);
+  }
+  if (!LOCAL) return NIL;	/* mbx_flaglock() could have aborted */
+				/* find header position */
+  i = mbx_hdrpos (stream,msgno,&j,NIL);
+  d.fd = LOCAL->fd;		/* set up file descriptor */
+  d.pos = i + j;
+  d.chunk = LOCAL->buf;	/* initial buffer chunk */
+  d.chunksize = CHUNKSIZE;
+  INIT (bs,fd_string,&d,elt->rfc822_size - j);
+  return LONGT;			/* success */
+}
+
+/* MBX mail modify flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    flag(s)
+ *	    option flags
+ * Unlocks flag lock
+ */
+
+void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
+{
+  struct utimbuf times;
+  struct stat sbuf;
+				/* make sure the update takes */
+  if (!stream->rdonly && LOCAL && (LOCAL->fd >= 0) && (LOCAL->ld >= 0)) {
+    fsync (LOCAL->fd);
+    fstat (LOCAL->fd,&sbuf);	/* get current write time */
+    times.modtime = LOCAL->filetime = sbuf.st_mtime;
+				/* update header */
+    if ((LOCAL->ffuserflag < NUSERFLAGS) &&
+	stream->user_flags[LOCAL->ffuserflag]) mbx_update_header (stream);
+    times.actime = time (0);	/* make sure read comes after all that */
+    utime (stream->mailbox,&times);
+  }
+  if (LOCAL->ld >= 0) {		/* unlock now */
+    unlockfd (LOCAL->ld,LOCAL->lock);
+    LOCAL->ld = -1;
+  }
+}
+
+
+/* MBX mail per-message modify flags
+ * Accepts: MAIL stream
+ *	    message cache element
+ */
+
+void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  if (mbx_flaglock (stream)) mbx_update_status (stream,elt->msgno,NIL);
+}
+
+/* MBX mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream still alive, NIL if not
+ */
+
+long mbx_ping (MAILSTREAM *stream)
+{
+  unsigned long i,pos;
+  long ret = NIL;
+  int ld;
+  char lock[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  struct stat sbuf;
+  if (stream && LOCAL) {	/* only if stream already open */
+    ret = LONGT;		/* assume OK */
+    fstat (LOCAL->fd,&sbuf);	/* get current file poop */
+				/* allow expunge if permitted at ping */
+    if (mail_parameters (NIL,GET_EXPUNGEATPING,NIL)) LOCAL->expok = T;
+				/* if external modification */
+    if (LOCAL->filetime && (LOCAL->filetime < sbuf.st_mtime))
+      LOCAL->flagcheck = T;	/* upgrade to flag checking */
+				/* new mail or flagcheck handling needed? */
+    if (((sbuf.st_size - LOCAL->filesize) || LOCAL->flagcheck ||
+	 !stream->nmsgs) &&
+	((ld = lockname (lock,stream->mailbox,LOCK_EX)) >= 0)) {
+      if (!LOCAL->flagcheck) ret = mbx_parse (stream);
+				/* sweep mailbox for changed message status */
+      else if (ret = mbx_parse (stream)) {
+	unsigned long recent = 0;
+	LOCAL->filetime = sbuf.st_mtime;
+	for (i = 1; i <= stream->nmsgs; )
+	  if (elt = mbx_elt (stream,i,LOCAL->expok)) {
+	    if (elt->recent) ++recent;
+	    ++i;
+	  }
+	mail_recent (stream,recent);
+	LOCAL->flagcheck = NIL;	/* got all the updates */
+      }
+      unlockfd (ld,lock);	/* release shared parse/append permission */
+    }
+    if (ret) {			/* must still be alive */
+      if (!LOCAL->expunged)	/* look for holes if none known yet */
+	for (i = 1, pos = HDRSIZE;
+	     !LOCAL->expunged && (i <= stream->nmsgs);
+	     i++, pos += elt->private.special.text.size + elt->rfc822_size)
+	  if ((elt = mail_elt (stream,i))->private.special.offset != pos)
+	    LOCAL->expunged = T;/* found a hole */
+				/* burp any holes */
+      if (LOCAL->expunged && !stream->rdonly) {
+	if (mbx_rewrite (stream,&i,NIL)) fatal ("expunge on check");
+	if (i) {		/* any space reclaimed? */
+	  LOCAL->expunged = NIL;/* no more pending expunge */
+	  sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",i);
+	  mm_log (LOCAL->buf,(long) NIL);
+	}
+      }
+      LOCAL->expok = NIL;	/* no more expok */
+    }
+  }
+  return ret;			/* return result of the parse */
+}
+
+/* MBX mail check mailbox (reparses status too)
+ * Accepts: MAIL stream
+ */
+
+void mbx_check (MAILSTREAM *stream)
+{
+  if (LOCAL) LOCAL->expok = T;	/* mark that a check is desired */
+  if (mbx_ping (stream)) mm_log ("Check completed",(long) NIL);
+}
+
+
+/* MBX mail expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T if success, NIL if failure
+ */
+
+long mbx_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  long ret;
+  unsigned long nexp,reclaimed;
+  if (ret = sequence ? ((options & EX_UID) ?
+			mail_uid_sequence (stream,sequence) :
+			mail_sequence (stream,sequence)) : LONGT) {
+    if (!mbx_ping (stream));	/* do nothing if stream dead */
+    else if (stream->rdonly)	/* won't do on readonly files! */
+      mm_log ("Expunge ignored on readonly mailbox",WARN);
+				/* if expunged any messages */
+    else if (nexp = mbx_rewrite (stream,&reclaimed,sequence ? -1 : 1)) {
+      sprintf (LOCAL->buf,"Expunged %lu messages",nexp);
+      mm_log (LOCAL->buf,(long) NIL);
+    }
+    else if (reclaimed) {	 /* or if any prior expunged space reclaimed */
+      sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",reclaimed);
+      mm_log (LOCAL->buf,(long) NIL);
+    }
+    else mm_log ("No messages deleted, so no update needed",(long) NIL);
+  }
+  return ret;
+}
+
+/* MBX mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if success, NIL if failed
+ */
+
+long mbx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  struct stat sbuf;
+  struct utimbuf times;
+  MESSAGECACHE *elt;
+  unsigned long i,j,k,m;
+  long ret = LONGT;
+  int fd,ld;
+  char *s,*t,file[MAILTMPLEN],lock[MAILTMPLEN];
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+  copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL);
+  SEARCHSET *source = cu ? mail_newsearchset () : NIL;
+  SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
+  MAILSTREAM *dstream = NIL;
+  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+	mail_sequence (stream,sequence))) return NIL;
+				/* make sure valid mailbox */
+  if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock,
+			 cu ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0)
+    switch (errno) {
+    case ENOENT:		/* no such file? */
+      mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
+      return NIL;
+    case EACCES:		/* file protected */
+      sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
+      MM_LOG (LOCAL->buf,ERROR);
+      return NIL;
+    case EINVAL:
+      if (pc) return (*pc) (stream,sequence,mailbox,options);
+      sprintf (LOCAL->buf,"Invalid MBX-format mailbox name: %.80s",mailbox);
+      mm_log (LOCAL->buf,ERROR);
+      return NIL;
+    default:
+      if (pc) return (*pc) (stream,sequence,mailbox,options);
+      sprintf (LOCAL->buf,"Not a MBX-format mailbox: %.80s",mailbox);
+      mm_log (LOCAL->buf,ERROR);
+      return NIL;
+    }
+				/* got file? */  
+  if ((fd = open (dummy_file (file,mailbox),O_RDWR|O_CREAT|O_BINARY,
+		  S_IREAD|S_IWRITE)) < 0) {
+    sprintf (LOCAL->buf,"Unable to open copy mailbox: %s",strerror (errno));
+    mm_log (LOCAL->buf,ERROR);
+    return NIL;
+  }
+  mm_critical (stream);		/* go critical */
+  fstat (fd,&sbuf);		/* get current file size */
+  lseek (fd,sbuf.st_size,L_SET);/* move to end of file */
+
+				/* for each requested message */
+  for (i = 1; ret && (i <= stream->nmsgs); i++) 
+    if ((elt = mail_elt (stream,i))->sequence) {
+      lseek (LOCAL->fd,elt->private.special.offset +
+	     elt->private.special.text.size,L_SET);
+      mail_date(LOCAL->buf,elt);/* build target header */
+				/* get target keyword mask */
+      for (j = elt->user_flags, k = 0; j; )
+	if (s = stream->user_flags[find_rightmost_bit (&j)])
+	  for (m = 0; (m < NUSERFLAGS) && (t = dstream->user_flags[m]); m++)
+	    if (!compare_cstring (s,t) && (k |= 1 << m)) break;
+      sprintf (LOCAL->buf+strlen(LOCAL->buf),",%lu;%08lx%04x-%08lx\015\012",
+	       elt->rfc822_size,k,(unsigned)
+	       ((fSEEN * elt->seen) + (fDELETED * elt->deleted) +
+		(fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
+		(fDRAFT * elt->draft)),cu ? ++dstream->uid_last : 0);
+				/* write target header */
+      if (ret = (write (fd,LOCAL->buf,strlen (LOCAL->buf)) > 0)) {
+	for (k = elt->rfc822_size; ret && (j = min (k,LOCAL->buflen)); k -= j){
+	  read (LOCAL->fd,LOCAL->buf,j);
+	  ret = write (fd,LOCAL->buf,j) >= 0;
+	}
+	if (cu) {		/* need to pass back new UID? */
+	  mail_append_set (source,mail_uid (stream,i));
+	  mail_append_set (dest,dstream->uid_last);
+	}
+      }
+    }
+
+				/* make sure all the updates take */
+  if (!(ret && (ret = !fsync (fd)))) {
+    sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno));
+    mm_log (LOCAL->buf,ERROR);
+    ftruncate (fd,sbuf.st_size);
+  }
+  if (cu && ret) {		/* return sets if doing COPYUID */
+    (*cu) (stream,mailbox,dstream->uid_validity,source,dest);
+    lseek (fd,15,L_SET);	/* update UIDLAST */
+    sprintf (LOCAL->buf,"%08lx",dstream->uid_last);
+    write (fd,LOCAL->buf,8);
+  }
+  else {			/* flush any sets we may have built */
+    mail_free_searchset (&source);
+    mail_free_searchset (&dest);
+  }
+				/* set atime to now-1 if successful copy */
+  if (ret) times.actime = time (0) - 1;
+				/* else preserved \Marked status */
+  else times.actime = (sbuf.st_ctime > sbuf.st_atime) ?
+	 sbuf.st_atime : time (0);
+  times.modtime = sbuf.st_mtime;/* preserve mtime */
+  utime (file,&times);		/* set the times */
+  close (fd);			/* close the file */
+  mm_nocritical (stream);	/* release critical */
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+				/* delete all requested messages */
+  if (ret && (options & CP_MOVE) && mbx_flaglock (stream)) {
+    for (i = 1; i <= stream->nmsgs; i++) if (mail_elt (stream,i)->sequence) {
+				/* mark message deleted */
+      mbx_elt (stream,i,NIL)->deleted = T;
+				/* recalculate status */
+      mbx_update_status (stream,i,NIL);
+    }
+				/* update flags */
+    mbx_flag (stream,NIL,NIL,NIL);
+  }
+  if (dstream != stream) mail_close (dstream);
+  return ret;
+}
+
+/* MBX mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long mbx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct stat sbuf;
+  int fd,ld;
+  char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  struct utimbuf times;
+  FILE *df;
+  MESSAGECACHE elt;
+  long f;
+  unsigned long i,uf;
+  STRING *message;
+  long ret = NIL;
+  MAILSTREAM *dstream = NIL;
+  appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL);
+  SEARCHSET *dst = au ? mail_newsearchset () : NIL;
+				/* make sure valid mailbox */
+				/* make sure valid mailbox */
+  if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock,
+			 au ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0)
+    switch (errno) {
+    case ENOENT:		/* no such file? */
+      if (compare_cstring (mailbox,"INBOX")) {
+	mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+	return NIL;
+      }
+				/* can create INBOX here */
+      mbx_create (dstream = stream ? stream : &mbxproto,"INBOX");
+      if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock,
+			     au ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0)
+	break;
+    case EACCES:		/* file protected */
+      sprintf (tmp,"Can't access destination: %.80s",mailbox);
+      MM_LOG (tmp,ERROR);
+      return NIL;
+    case EINVAL:
+      sprintf (tmp,"Invalid MBX-format mailbox name: %.80s",mailbox);
+      mm_log (tmp,ERROR);
+      return NIL;
+    default:
+      sprintf (tmp,"Not a MBX-format mailbox: %.80s",mailbox);
+      mm_log (tmp,ERROR);
+      return NIL;
+    }
+
+				/* get first message */
+  if (!(*af) (dstream,data,&flags,&date,&message)) close (fd);
+  else if (!(df = fdopen (fd,"r+b"))) {
+    MM_LOG ("Unable to reopen append mailbox",ERROR);
+    close (fd);
+  }
+  else {
+    mm_critical (dstream);	/* go critical */
+    fstat (fd,&sbuf);		/* get current file size */
+    fseek (df,sbuf.st_size,SEEK_SET);
+    errno = 0;
+    for (ret = LONGT; ret && message; ) {
+      if (!SIZE (message)) {	/* guard against zero-length */
+	mm_log ("Append of zero-length message",ERROR);
+	ret = NIL;
+	break;
+      }
+      f = mail_parse_flags (dstream,flags,&uf);
+      if (date) {		/* parse date if given */
+	if (!mail_parse_date (&elt,date)) {
+	  sprintf (tmp,"Bad date in append: %.80s",date);
+	  mm_log (tmp,ERROR);
+	  ret = NIL;		/* mark failure */
+	  break;
+	}
+	mail_date (tmp,&elt);	/* write preseved date */
+      }
+      else internal_date (tmp);	/* get current date in IMAP format */
+				/* write header */
+      if (fprintf (df,"%s,%lu;%08lx%04lx-%08lx\015\012",tmp,i = SIZE (message),
+		   uf,(unsigned long) f,au ? ++dstream->uid_last : 0) < 0)
+	ret = NIL;
+      else {			/* write message */
+	size_t j;
+	if (!message->cursize) SETPOS (message,GETPOS (message));
+	while (i && (j = fwrite (message->curpos,1,message->cursize,df))) {
+	  i -= j;
+	  SETPOS (message,GETPOS (message) + j);
+	}
+				/* get next message */
+	if (i || !(*af) (dstream,data,&flags,&date,&message)) ret = NIL;
+	else if (au) mail_append_set (dst,dstream->uid_last);
+      }
+    }
+
+				/* if error... */
+    if (!ret || (fflush (df) == EOF)) {
+				/* revert file */
+      ftruncate (fd,sbuf.st_size);
+      close (fd);		/* make sure fclose() doesn't corrupt us */
+      if (errno) {
+	sprintf (tmp,"Message append failed: %s",strerror (errno));
+	mm_log (tmp,ERROR);
+      }
+      ret = NIL;
+    }
+    if (au && ret) {		/* return sets if doing APPENDUID */
+      (*au) (mailbox,dstream->uid_validity,dst);
+      fseek (df,15,SEEK_SET);	/* update UIDLAST */
+      fprintf (df,"%08lx",dstream->uid_last);
+    }
+    else mail_free_searchset (&dst);
+    if (ret) times.actime = time (0) - 1;
+				/* else preserve \Marked status */
+    else times.actime = (sbuf.st_ctime > sbuf.st_atime) ?
+	   sbuf.st_atime : time (0);
+				/* preserve mtime */
+    times.modtime = sbuf.st_mtime;
+    utime (file,&times);	/* set the times */
+    fclose (df);		/* close the file */
+    mm_nocritical (dstream);	/* release critical */
+  }
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+  if (dstream != stream) mail_close (dstream);
+  return ret;
+}
+
+/* Internal routines */
+
+
+/* MBX mail parse mailbox
+ * Accepts: MAIL stream
+ * Returns: T if parse OK
+ *	    NIL if failure, stream aborted
+ */
+
+long mbx_parse (MAILSTREAM *stream)
+{
+  struct stat sbuf;
+  MESSAGECACHE *elt = NIL;
+  unsigned char c,*s,*t,*x;
+  char tmp[MAILTMPLEN];
+  unsigned long i,j,k,m;
+  off_t curpos = LOCAL->filesize;
+  unsigned long nmsgs = stream->nmsgs;
+  unsigned long recent = stream->recent;
+  unsigned long lastuid = 0;
+  short dirty = NIL;
+  short added = NIL;
+  short silent = stream->silent;
+  short uidwarn = T;
+  fstat (LOCAL->fd,&sbuf);	/* get status */
+  if (sbuf.st_size < curpos) {	/* sanity check */
+    sprintf (tmp,"Mailbox shrank from %lu to %lu!",
+	     (unsigned long) curpos,(unsigned long) sbuf.st_size);
+    mm_log (tmp,ERROR);
+    mbx_abort (stream);
+    return NIL;
+  }
+  lseek (LOCAL->fd,0,L_SET);	/* rewind file */
+				/* read internal header */
+  read (LOCAL->fd,LOCAL->buf,HDRSIZE);
+  LOCAL->buf[HDRSIZE] = '\0';	/* tie off header */
+  c = LOCAL->buf[15];		/* save first character of last UID */
+  LOCAL->buf[15] = '\0';
+				/* parse UID validity */
+  stream->uid_validity = strtoul (LOCAL->buf + 7,NIL,16);
+  LOCAL->buf[15] = c;		/* restore first character of last UID */
+				/* parse last UID */
+  i = strtoul (LOCAL->buf + 15,NIL,16);
+  stream->uid_last = stream->rdonly ? max (i,stream->uid_last) : i;
+				/* parse user flags */
+  for (i = 0, s = LOCAL->buf + 25;
+       (i < NUSERFLAGS) && (t = strchr (s,'\015')) && (t - s);
+       i++, s = t + 2) {
+    *t = '\0';			/* tie off flag */
+    if (!stream->user_flags[i] && (strlen (s) <= MAXUSERFLAG))
+      stream->user_flags[i] = cpystr (s);
+  }
+  LOCAL->ffuserflag = (int) i;	/* first free user flag */
+
+  stream->silent = T;		/* don't pass up mm_exists() events yet */
+  while (sbuf.st_size - curpos){/* while there is stuff to parse */
+				/* get to that position in the file */
+    lseek (LOCAL->fd,curpos,L_SET);
+    if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) {
+      sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s",
+	       (unsigned long) curpos,(unsigned long) sbuf.st_size,
+	       i ? strerror (errno) : "no data read");
+      mm_log (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+    LOCAL->buf[i] = '\0';	/* tie off buffer just in case */
+    if (!((s = strchr (LOCAL->buf,'\015')) && (s[1] == '\012'))) {
+      sprintf (tmp,"Unable to find CRLF at %lu in %lu bytes, text: %.80s",
+	       (unsigned long) curpos,i,(char *) LOCAL->buf);
+      mm_log (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+    *s = '\0';			/* tie off header line */
+    i = (s + 2) - LOCAL->buf;	/* note start of text offset */
+    if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) {
+      sprintf (tmp,"Unable to parse internal header at %lu: %.80s",
+	       (unsigned long) curpos,(char *) LOCAL->buf);
+      mm_log (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+    if (!(isxdigit (t[1]) && isxdigit (t[2]) && isxdigit (t[3]) &&
+	  isxdigit (t[4]) && isxdigit (t[5]) && isxdigit (t[6]) &&
+	  isxdigit (t[7]) && isxdigit (t[8]) && isxdigit (t[9]) &&
+	  isxdigit (t[10]) && isxdigit (t[11]) && isxdigit (t[12]))) {
+      sprintf (tmp,"Unable to parse message flags at %lu: %.80s",
+	       (unsigned long) curpos,(char *) LOCAL->buf);
+      mm_log (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+    if ((t[13] != '-') || t[22] ||
+	!(isxdigit (t[14]) && isxdigit (t[15]) && isxdigit (t[16]) &&
+	  isxdigit (t[17]) && isxdigit (t[18]) && isxdigit (t[19]) &&
+	  isxdigit (t[20]) && isxdigit (t[21]))) {
+      sprintf (tmp,"Unable to parse message UID at %lu: %.80s",
+	       (unsigned long) curpos,(char *) LOCAL->buf);
+      mm_log (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+
+    *s++ = '\0'; *t++ = '\0';	/* break up fields */
+				/* get message size */
+    if (!(j = strtoul (s,(char **) &x,10)) && (!(x && *x))) {
+      sprintf (tmp,"Unable to parse message size at %lu: %.80s,%.80s;%.80s",
+	       (unsigned long) curpos,(char *) LOCAL->buf,(char *) s,
+	       (char *) t);
+      mm_log (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+				/* make sure didn't run off end of file */
+    if (((off_t) (curpos + i + j)) > sbuf.st_size) {
+      sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
+	       (unsigned long) curpos,(unsigned long) (curpos + i + j),
+	       (unsigned long) sbuf.st_size);
+      mm_log (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+				/* parse UID */
+    if ((m = strtoul (t+13,NIL,16)) &&
+	((m <= lastuid) || (m > stream->uid_last))) {
+      if (uidwarn) {
+	sprintf (tmp,"Invalid UID %08lx in message %lu, rebuilding UIDs",
+		 m,nmsgs+1);
+	mm_log (tmp,WARN);
+	uidwarn = NIL;
+				/* restart UID validity */
+	stream->uid_validity = (unsigned long) time (0);
+      }
+      m = 0;			/* lose this UID */
+      dirty = T;		/* mark dirty, set new lastuid */
+      stream->uid_last = lastuid;
+    }
+
+    t[12] = '\0';		/* parse system flags */
+    if ((k = strtoul (t+8,NIL,16)) & fEXPUNGED) {
+      if (m) lastuid = m;	/* expunge message, update last UID seen */
+      else {			/* no UID assigned? */
+	lastuid = ++stream->uid_last;
+	dirty = T;
+      }
+    }
+    else {			/* not expunged, swell the cache */
+      added = T;		/* note that a new message was added */
+      mail_exists (stream,++nmsgs);
+				/* instantiate an elt for this message */
+      (elt = mail_elt (stream,nmsgs))->valid = T;
+				/* parse the date */
+      if (!mail_parse_date (elt,LOCAL->buf)) {
+	sprintf (tmp,"Unable to parse message date at %lu: %.80s",
+		 (unsigned long) curpos,(char *) LOCAL->buf);
+	mm_log (tmp,ERROR);
+	mbx_abort (stream);
+	return NIL;
+      }
+				/* note file offset of header */
+      elt->private.special.offset = curpos;
+				/* and internal header size */
+      elt->private.special.text.size = i;
+				/* header size not known yet */
+      elt->private.msg.header.text.size = 0;
+      elt->rfc822_size = j;	/* note message size */
+				/* calculate system flags */
+      if (k & fSEEN) elt->seen = T;
+      if (k & fDELETED) elt->deleted = T;
+      if (k & fFLAGGED) elt->flagged = T;
+      if (k & fANSWERED) elt->answered = T;
+      if (k & fDRAFT) elt->draft = T;
+      t[8] = '\0';		/* get user flags value */
+      elt->user_flags = strtoul (t,NIL,16);
+				/* UID already assigned? */
+      if (!(elt->private.uid = m) || !(k & fOLD)) {
+	elt->recent = T;	/* no, mark as recent */
+	++recent;		/* count up a new recent message */
+	dirty = T;		/* and must rewrite header */
+				/* assign new UID */
+	if (!elt->private.uid) elt->private.uid = ++stream->uid_last;
+	mbx_update_status (stream,elt->msgno,NIL);
+      }
+				/* update last parsed UID */
+      lastuid = elt->private.uid;
+    }
+    curpos += i + j;		/* update position */
+  }
+
+  if (dirty && !stream->rdonly){/* update header */
+    mbx_update_header (stream);
+    fsync (LOCAL->fd);		/* make sure all the UID updates take */
+  }
+				/* update parsed file size and time */
+  LOCAL->filesize = sbuf.st_size;
+  fstat (LOCAL->fd,&sbuf);	/* get status again to ensure time is right */
+  LOCAL->filetime = sbuf.st_mtime;
+  if (added && !stream->rdonly){/* make sure atime updated */
+    struct utimbuf times;
+    times.actime = time (0);
+    times.modtime = LOCAL->filetime;
+    utime (stream->mailbox,&times);
+  }
+  stream->silent = silent;	/* can pass up events now */
+  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
+  mail_recent (stream,recent);	/* and of change in recent messages */
+  return LONGT;			/* return the winnage */
+}
+
+/* MBX get cache element with status updating from file
+ * Accepts: MAIL stream
+ *	    message number
+ *	    expunge OK flag
+ * Returns: cache element
+ */
+
+MESSAGECACHE *mbx_elt (MAILSTREAM *stream,unsigned long msgno,long expok)
+{
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  struct {			/* old flags */
+    unsigned int seen : 1;
+    unsigned int deleted : 1;
+    unsigned int flagged : 1;
+    unsigned int answered : 1;
+    unsigned int draft : 1;
+    unsigned long user_flags;
+  } old;
+  old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged;
+  old.answered = elt->answered; old.draft = elt->draft;
+  old.user_flags = elt->user_flags;
+				/* get new flags */
+  if (mbx_read_flags (stream,elt) && expok) {
+    mail_expunged (stream,elt->msgno);
+    return NIL;			/* return this message was expunged */
+  }
+  if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
+      (old.flagged != elt->flagged) || (old.answered != elt->answered) ||
+      (old.draft != elt->draft) || (old.user_flags != elt->user_flags))
+    mm_flags (stream,msgno);	/* let top level know */
+  return elt;
+}
+
+/* MBX read flags from file
+ * Accepts: MAIL stream
+ *	    cache element
+ * Returns: non-NIL if message expunged
+ */
+
+unsigned long mbx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  unsigned long i;
+  struct stat sbuf;
+  fstat (LOCAL->fd,&sbuf);	/* get status */
+				/* make sure file size is good */
+  if (sbuf.st_size < LOCAL->filesize) {
+    sprintf (LOCAL->buf,"Mailbox shrank from %lu to %lu in flag read!",
+	     (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
+    fatal (LOCAL->buf);
+  }
+				/* set the seek pointer */
+  lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	 elt->private.special.text.size - 24,L_SET);
+				/* read the new flags */
+  if (read (LOCAL->fd,LOCAL->buf,14) < 0) {
+    sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno));
+    fatal (LOCAL->buf);
+  }
+  if ((LOCAL->buf[0] != ';') || (LOCAL->buf[13] != '-')) {
+    LOCAL->buf[14] = '\0';	/* tie off buffer for error message */
+    sprintf (LOCAL->buf+50,"Invalid flags for message %lu (%lu %lu): %s",
+	     elt->msgno,elt->private.special.offset,
+	     elt->private.special.text.size,(char *) LOCAL->buf);
+    fatal (LOCAL->buf+50);
+  }
+  LOCAL->buf[13] = '\0';	/* tie off buffer */
+				/* calculate system flags */
+  i = strtoul (LOCAL->buf+9,NIL,16);
+  elt->seen = i & fSEEN ? T : NIL;
+  elt->deleted = i & fDELETED ? T : NIL;
+  elt->flagged = i & fFLAGGED ? T : NIL;
+  elt->answered = i & fANSWERED ? T : NIL;
+  elt->draft = i & fDRAFT ? T : NIL;
+  LOCAL->expunged |= i & fEXPUNGED ? T : NIL;
+  LOCAL->buf[9] = '\0';		/* tie off flags */
+				/* get user flags value */
+  elt->user_flags = strtoul (LOCAL->buf+1,NIL,16);
+  elt->valid = T;		/* have valid flags now */
+  return i & fEXPUNGED;
+}
+
+/* MBX update header
+ * Accepts: MAIL stream
+ */
+
+#define NTKLUDGEOFFSET 7
+
+void mbx_update_header (MAILSTREAM *stream)
+{
+  int i;
+  char *s = LOCAL->buf;
+  memset (s,'\0',HDRSIZE);	/* initialize header */
+  sprintf (s,"*mbx*\015\012%08lx%08lx\015\012",
+	   stream->uid_validity,stream->uid_last);
+  for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i]; ++i)
+    sprintf (s += strlen (s),"%s\015\012",stream->user_flags[i]);
+  LOCAL->ffuserflag = i;	/* first free user flag */
+				/* can we create more user flags? */
+  stream->kwd_create = (i < NUSERFLAGS) ? T : NIL;
+				/* write reserved lines */
+  while (i++ < NUSERFLAGS) strcat (s,"\015\012");
+  while (T) {			/* rewind file */
+    lseek (LOCAL->fd,NTKLUDGEOFFSET,L_SET);
+				/* write new header */
+    if (write (LOCAL->fd,LOCAL->buf + NTKLUDGEOFFSET,
+	       HDRSIZE - NTKLUDGEOFFSET) > 0) break;
+    mm_notify (stream,strerror (errno),WARN);
+    mm_diskerror (stream,errno,T);
+  }
+}
+
+/* MBX update status string
+ * Accepts: MAIL stream
+ *	    message number
+ *	    flags
+ */
+
+void mbx_update_status (MAILSTREAM *stream,unsigned long msgno,long flags)
+{
+  struct stat sbuf;
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+				/* readonly */
+  if (stream->rdonly || !elt->valid) mbx_read_flags (stream,elt);
+  else {			/* readwrite */
+    fstat (LOCAL->fd,&sbuf);	/* get status */
+				/* make sure file size is good */
+    if (sbuf.st_size < LOCAL->filesize) {
+      sprintf (LOCAL->buf,"Mailbox shrank from %lu to %lu in flag update!",
+	       (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
+      fatal (LOCAL->buf);
+    }
+				/* set the seek pointer */
+    lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	   elt->private.special.text.size - 24,L_SET);
+				/* read the new flags */
+    if (read (LOCAL->fd,LOCAL->buf,14) < 0) {
+      sprintf (LOCAL->buf,"Unable to read old status: %s",strerror (errno));
+      fatal (LOCAL->buf);
+    }
+    if ((LOCAL->buf[0] != ';') || (LOCAL->buf[13] != '-')) {
+      LOCAL->buf[14] = '\0';	/* tie off buffer for error message */
+      sprintf (LOCAL->buf+50,"Invalid flags for message %lu (%lu %lu): %s",
+	       elt->msgno,elt->private.special.offset,
+	       elt->private.special.text.size,(char *) LOCAL->buf);
+      fatal (LOCAL->buf+50);
+    }
+				/* print new flag string */
+    sprintf (LOCAL->buf,"%08lx%04x-%08lx",elt->user_flags,(unsigned)
+	     (((elt->deleted && flags) ?
+	       fEXPUNGED : (strtoul (LOCAL->buf+9,NIL,16)) & fEXPUNGED) +
+	      (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
+	      (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
+	      (fDRAFT * elt->draft) + fOLD),elt->private.uid);
+    while (T) {			/* get to that place in the file */
+      lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	     elt->private.special.text.size - 23,L_SET);
+				/* write new flags and UID */
+      if (write (LOCAL->fd,LOCAL->buf,21) > 0) break;
+      mm_notify (stream,strerror (errno),WARN);
+      mm_diskerror (stream,errno,T);
+    }
+  }
+}
+
+/* MBX locate header for a message
+ * Accepts: MAIL stream
+ *	    message number
+ *	    pointer to returned header size
+ *	    pointer to possible returned header
+ * Returns: position of header in file
+ */
+
+#define HDRBUFLEN 16384		/* good enough for most headers */
+#define SLOP 4			/* CR LF CR LF */
+
+unsigned long mbx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			  unsigned long *size,char **hdr)
+{
+  unsigned long siz,done;
+  long i;
+  unsigned char *s,*t,*te;
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  unsigned long ret = elt->private.special.offset +
+    elt->private.special.text.size;
+  if (hdr) *hdr = NIL;		/* assume no header returned */
+				/* is header size known? */ 
+  if (*size = elt->private.msg.header.text.size) return ret;
+				/* paranoia check */
+  if (LOCAL->buflen < (HDRBUFLEN + SLOP))
+    fatal ("LOCAL->buf smaller than HDRBUFLEN");
+  lseek (LOCAL->fd,ret,L_SET);	/* get to header position */
+				/* read HDRBUFLEN chunks with 4 byte slop */
+  for (done = siz = 0, s = LOCAL->buf;
+       (i = min ((long) (elt->rfc822_size - done),(long) HDRBUFLEN)) &&
+       (read (LOCAL->fd,s,i) == i);
+       done += i, siz += (t - LOCAL->buf) - SLOP, s = LOCAL->buf + SLOP) {
+    te = (t = s + i) - 12;	/* calculate end of fast scan */
+				/* fast scan for CR */
+    for (s = LOCAL->buf; s < te;)
+      if (((*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') ||
+	   (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') ||
+	   (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') ||
+	   (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015')) &&
+	  (*s == '\012') && (*++s == '\015') && (*++s == '\012')) {
+	*size = elt->private.msg.header.text.size = siz + (++s - LOCAL->buf);
+	if (hdr) *hdr = LOCAL->buf;
+	return ret;
+      }
+    for (te = t - 3; (s < te);)	/* final character-at-a-time scan */
+      if ((*s++ == '\015') && (*s == '\012') && (*++s == '\015') &&
+	  (*++s == '\012')) {
+	*size = elt->private.msg.header.text.size = siz + (++s - LOCAL->buf);
+	if (hdr) *hdr = LOCAL->buf;
+	return ret;
+      }
+    if (i <= SLOP) break;	/* end of data */
+				/* slide over last 4 bytes */
+    memmove (LOCAL->buf,t - SLOP,SLOP);
+    hdr = NIL;			/* can't return header this way */
+  }
+				/* not found: header consumes entire message */
+  elt->private.msg.header.text.size = *size = elt->rfc822_size;
+  if (hdr) *hdr = LOCAL->buf;	/* possibly return header too */
+  return ret;
+}
+
+/* MBX mail rewrite mailbox
+ * Accepts: MAIL stream
+ *	    pointer to return reclaimed size
+ *	    flags (0 = no expunge, 1 = expunge deleted, -1 = expunge sequence)
+ * Returns: number of expunged messages
+ */
+
+unsigned long mbx_rewrite (MAILSTREAM *stream,unsigned long *reclaimed,
+			   long flags)
+{
+  struct utimbuf times;
+  struct stat sbuf;
+  off_t pos,ppos;
+  int ld;
+  unsigned long i,j,k,m,delta;
+  unsigned long n = *reclaimed = 0;
+  unsigned long recent = 0;
+  char lock[MAILTMPLEN];
+  MESSAGECACHE *elt;
+				/* get parse/append permission */
+  if ((ld = lockname (lock,stream->mailbox,LOCK_EX)) < 0) {
+    mm_log ("Unable to lock expunge mailbox",ERROR);
+    return 0;
+  }
+  fstat (LOCAL->fd,&sbuf);	/* get current write time */
+  if (LOCAL->filetime && !LOCAL->flagcheck &&
+      (LOCAL->filetime < sbuf.st_mtime)) LOCAL->flagcheck = T;
+  if (!mbx_parse (stream)) {	/* make sure see any newly-arrived messages */
+    unlockfd (ld,lock);		/* failed?? */
+    return 0;
+  }
+  if (LOCAL->flagcheck) {	/* sweep flags if need flagcheck */
+    LOCAL->filetime = sbuf.st_mtime;
+    for (i = 1; i <= stream->nmsgs; ++i) mbx_elt (stream,i,NIL);
+    LOCAL->flagcheck = NIL;
+  }
+
+				/* get exclusive access */
+  if (!flock (LOCAL->fd,LOCK_EX|LOCK_NB)) {
+    mm_critical (stream);	/* go critical */
+    for (i = 1,delta = 0,pos = ppos = HDRSIZE; i <= stream->nmsgs; ) {
+				/* note if message not at predicted location */
+      if (m = (elt = mbx_elt (stream,i,NIL))->private.special.offset - ppos) {
+	ppos = elt->private.special.offset;
+	*reclaimed += m;	/* note reclaimed message space */
+	delta += m;		/* and as expunge delta  */
+      }
+				/* number of bytes to smash or preserve */
+      ppos += (k = elt->private.special.text.size + elt->rfc822_size);
+				/* if need to expunge this message*/
+      if (flags && elt->deleted && ((flags > 0) || elt->sequence)) {
+	delta += k;		/* number of bytes to delete */
+	mail_expunged(stream,i);/* notify upper levels */
+	n++;			/* count up one more expunged message */
+      }
+      else {			/* preserved message */
+	i++;			/* count this message */
+	if (elt->recent) ++recent;
+	if (delta) {		/* moved, note first byte to preserve */
+	  j = elt->private.special.offset;
+	  do {			/* read from source position */
+	    m = min (k,LOCAL->buflen);
+	    lseek (LOCAL->fd,j,L_SET);
+	    read (LOCAL->fd,LOCAL->buf,m);
+	    pos = j - delta;	/* write to destination position */
+	    while (T) {
+	      lseek (LOCAL->fd,pos,L_SET);
+	      if (write (LOCAL->fd,LOCAL->buf,m) > 0) break;
+	      mm_notify (stream,strerror (errno),WARN);
+	      mm_diskerror (stream,errno,T);
+	    }
+	    pos += m;		/* new position */
+	    j += m;		/* next chunk, perhaps */
+	  } while (k -= m);	/* until done */
+				/* note the new address of this text */
+	  elt->private.special.offset -= delta;
+	}
+				/* preserved but no deleted messages yet */
+	else pos = elt->private.special.offset + k;
+      }
+    }
+				/* deltaed file size match position? */
+    if (m = (LOCAL->filesize -= delta) - pos) {
+      *reclaimed += m;		/* probably an fEXPUNGED msg */
+      LOCAL->filesize = pos;	/* set correct size */
+    }
+				/* truncate file after last message */
+    ftruncate (LOCAL->fd,LOCAL->filesize);
+    fsync (LOCAL->fd);		/* force disk update */
+    mm_nocritical (stream);	/* release critical */
+    flock (LOCAL->fd,LOCK_SH);	/* allow sharers again */
+  }
+
+  else {			/* can't get exclusive */
+    flock (LOCAL->fd,LOCK_SH);	/* recover previous shared mailbox lock */
+				/* do hide-expunge when shared */
+    if (flags) for (i = 1; i <= stream->nmsgs; ) {
+      if (elt = mbx_elt (stream,i,T)) {
+				/* make the message invisible */
+	if (elt->deleted && ((flags > 0) || elt->sequence)) {
+	  mbx_update_status (stream,elt->msgno,LONGT);
+				/* notify upper levels */
+	  mail_expunged (stream,i);
+	  n++;			/* count up one more expunged message */
+	}
+	else {
+	  i++;			/* preserved message */
+	  if (elt->recent) ++recent;
+	}
+      }
+      else n++;			/* count up one more expunged message */
+    }
+    fsync (LOCAL->fd);		/* force disk update */
+  }
+  fstat (LOCAL->fd,&sbuf);	/* get new write time */
+  times.modtime = LOCAL->filetime = sbuf.st_mtime;
+  times.actime = time (0);	/* reset atime to now */
+  utime (stream->mailbox,&times);
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+				/* notify upper level of new mailbox size */
+  mail_exists (stream,stream->nmsgs);
+  mail_recent (stream,recent);
+  return n;			/* return number of expunged messages */
+}
+
+/* MBX mail lock for flag updating
+ * Accepts: stream
+ * Returns: T if successful, NIL if failure
+ */
+
+long mbx_flaglock (MAILSTREAM *stream)
+{
+  struct stat sbuf;
+  unsigned long i;
+  int ld;
+  char lock[MAILTMPLEN];
+				/* no-op if readonly or already locked */
+  if (!stream->rdonly && LOCAL && (LOCAL->fd >= 0) && (LOCAL->ld < 0)) {
+				/* lock now */
+    if ((ld = lockname (lock,stream->mailbox,LOCK_EX)) < 0) return NIL;
+    if (!LOCAL->flagcheck) {	/* don't do this if flagcheck already needed */
+      if (LOCAL->filetime) {	/* know previous time? */
+	fstat (LOCAL->fd,&sbuf);/* get current write time */
+	if (LOCAL->filetime < sbuf.st_mtime) LOCAL->flagcheck = T;
+	LOCAL->filetime = 0;	/* don't do this test for any other messages */
+      }
+      if (!mbx_parse (stream)) {/* parse mailbox */
+	unlockfd (ld,lock);	/* shouldn't happen */
+	return NIL;
+      }
+      if (LOCAL->flagcheck)	/* invalidate cache if flagcheck */
+	for (i = 1; i <= stream->nmsgs; ++i) mail_elt (stream,i)->valid = NIL;
+    }
+    LOCAL->ld = ld;		/* copy to stream for subsequent calls */
+    memcpy (LOCAL->lock,lock,MAILTMPLEN);
+  }
+  return LONGT;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/os2/mtxnt.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1232 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	MTX mail routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	22 May 1990
+ * Last Edited:	15 June 2007
+ */
+
+
+/*				FILE TIME SEMANTICS
+ *
+ * The atime is the last read time of the file.
+ * The mtime is the last flags update time of the file.
+ * The ctime is the last write time of the file.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "mail.h"
+#include "osdep.h"
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/utime.h>
+#include "misc.h"
+#include "dummy.h"
+#include "fdstring.h"
+
+/* MTX I/O stream local data */
+	
+typedef struct mtx_local {
+  unsigned int shouldcheck: 1;	/* if ping should do a check instead */
+  unsigned int mustcheck: 1;	/* if ping must do a check instead */
+  int fd;			/* file descriptor for I/O */
+  off_t filesize;		/* file size parsed */
+  time_t filetime;		/* last file time */
+  time_t lastsnarf;		/* last snarf time */
+  unsigned char *buf;		/* temporary buffer */
+  unsigned long buflen;		/* current size of temporary buffer */
+} MTXLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((MTXLOCAL *) stream->local)
+
+
+/* Function prototypes */
+
+DRIVER *mtx_valid (char *name);
+int mtx_isvalid (char *name,char *file);
+void *mtx_parameters (long function,void *value);
+void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void mtx_list (MAILSTREAM *stream,char *ref,char *pat);
+void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long mtx_create (MAILSTREAM *stream,char *mailbox);
+long mtx_delete (MAILSTREAM *stream,char *mailbox);
+long mtx_rename (MAILSTREAM *stream,char *old,char *newname);
+long mtx_status (MAILSTREAM *stream,char *mbx,long flags);
+MAILSTREAM *mtx_open (MAILSTREAM *stream);
+void mtx_close (MAILSTREAM *stream,long options);
+void mtx_flags (MAILSTREAM *stream,char *sequence,long flags);
+char *mtx_header (MAILSTREAM *stream,unsigned long msgno,
+		  unsigned long *length,long flags);
+long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+void mtx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
+void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
+long mtx_ping (MAILSTREAM *stream);
+void mtx_check (MAILSTREAM *stream);
+void mtx_snarf (MAILSTREAM *stream);
+long mtx_expunge (MAILSTREAM *stream,char *sequence,long options);
+long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+long mtx_parse (MAILSTREAM *stream);
+MESSAGECACHE *mtx_elt (MAILSTREAM *stream,unsigned long msgno);
+void mtx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt);
+void mtx_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag);
+unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			  unsigned long *size);
+
+
+/* MTX mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER mtxdriver = {
+  "mtx",			/* driver name */
+				/* driver flags */
+  DR_LOCAL|DR_MAIL|DR_CRLF|DR_NOSTICKY,
+  (DRIVER *) NIL,		/* next driver */
+  mtx_valid,			/* mailbox is valid for us */
+  mtx_parameters,		/* manipulate parameters */
+  mtx_scan,			/* scan mailboxes */
+  mtx_list,			/* list mailboxes */
+  mtx_lsub,			/* list subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  mtx_create,			/* create mailbox */
+  mtx_delete,			/* delete mailbox */
+  mtx_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  mtx_open,			/* open mailbox */
+  mtx_close,			/* close mailbox */
+  mtx_flags,			/* fetch message "fast" attributes */
+  mtx_flags,			/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  mtx_header,			/* fetch message header */
+  mtx_text,			/* fetch message body */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  mtx_flag,			/* modify flags */
+  mtx_flagmsg,			/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  mtx_ping,			/* ping mailbox to see if still alive */
+  mtx_check,			/* check for new messages */
+  mtx_expunge,			/* expunge deleted messages */
+  mtx_copy,			/* copy messages to another mailbox */
+  mtx_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM mtxproto = {&mtxdriver};
+
+/* MTX mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *mtx_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+  return mtx_isvalid (name,tmp) ? &mtxdriver : NIL;
+}
+
+
+/* MTX mail test for valid mailbox
+ * Accepts: mailbox name
+ *	    buffer to return file name
+ * Returns: T if valid, NIL otherwise
+ */
+
+int mtx_isvalid (char *name,char *file)
+{
+  int fd;
+  int ret = NIL;
+  char *s,tmp[MAILTMPLEN];
+  struct stat sbuf;
+  struct utimbuf times;
+  errno = EINVAL;		/* assume invalid argument */
+				/* if file, get its status */
+  if ((s = dummy_file (file,name)) && !stat (s,&sbuf) &&
+      ((sbuf.st_mode & S_IFMT) == S_IFREG)) {
+    if (!sbuf.st_size)errno = 0;/* empty file */
+    else if ((fd = open (file,O_BINARY|O_RDONLY,NIL)) >= 0) {
+      memset (tmp,'\0',MAILTMPLEN);
+      if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\015')) &&
+	  (s[1] == '\012')) {	/* valid format? */
+	*s = '\0';		/* tie off header */
+				/* must begin with dd-mmm-yy" */
+	ret = (((tmp[2] == '-' && tmp[6] == '-') ||
+		(tmp[1] == '-' && tmp[5] == '-')) &&
+	       (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL;
+      }
+      else errno = -1;		/* bogus format */
+      close (fd);		/* close the file */
+				/* \Marked status? */
+      if (sbuf.st_ctime > sbuf.st_atime) {
+				/* preserve atime and mtime */
+	times.actime = sbuf.st_atime;
+	times.modtime = sbuf.st_mtime;
+	utime (file,&times);	/* set the times */
+      }
+    }
+  }
+				/* in case INBOX but not mtx format */
+  else if ((errno == ENOENT) && !compare_cstring (name,"INBOX")) errno = -1;
+  return ret;			/* return what we should */
+}
+
+
+/* MTX manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *mtx_parameters (long function,void *value)
+{
+  return NIL;
+}
+
+/* MTX mail scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* MTX mail list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mtx_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_list (NIL,ref,pat);
+}
+
+
+/* MTX mail list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_lsub (NIL,ref,pat);
+}
+
+/* MTX mail create mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long mtx_create (MAILSTREAM *stream,char *mailbox)
+{
+  char *s,mbx[MAILTMPLEN];
+  if (s = dummy_file (mbx,mailbox)) return dummy_create (stream,s);
+  sprintf (mbx,"Can't create %.80s: invalid name",mailbox);
+  mm_log (mbx,ERROR);
+  return NIL;
+}
+
+
+/* MTX mail delete mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long mtx_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return mtx_rename (stream,mailbox,NIL);
+}
+
+/* MTX mail rename mailbox
+ * Accepts: MAIL stream
+ *	    old mailbox name
+ *	    new mailbox name (or NIL for delete)
+ * Returns: T on success, NIL on failure
+ */
+
+long mtx_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  long ret = LONGT;
+  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  int fd,ld;
+  struct stat sbuf;
+  if (!dummy_file (file,old) ||
+      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
+		   ((s = strrchr (tmp,'\\')) && !s[1])))) {
+    sprintf (tmp,newname ?
+	     "Can't rename mailbox %.80s to %.80s: invalid name" :
+	     "Can't delete mailbox %.80s: invalid name",
+	     old,newname);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+  if ((fd = open (file,O_BINARY|O_RDWR,NIL)) < 0) {
+    sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* get exclusive parse/append permission */
+  if ((ld = lockname (lock,file,LOCK_EX)) < 0) {
+    mm_log ("Unable to lock rename mailbox",ERROR);
+    return NIL;
+  }
+				/* lock out other users */
+  if (flock (fd,LOCK_EX|LOCK_NB)) {
+    close (fd);			/* couldn't lock, give up on it then */
+    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
+    mm_log (tmp,ERROR);
+    unlockfd (ld,lock);		/* release exclusive parse/append permission */
+    return NIL;
+  }
+
+  if (newname) {		/* want rename? */
+				/* found superior to destination name? */
+    if ((s = strrchr (tmp,'\\')) && (s != tmp) &&
+	((tmp[1] != ':') || (s != tmp + 2))) {
+      c = s[1];			/* remember character after delimiter */
+      *s = s[1] = '\0';		/* tie off name at delimiter */
+				/* name doesn't exist, create it */
+      if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) {
+	*s = '\\';		/* restore delimiter */
+	if (!dummy_create (stream,tmp)) ret = NIL;
+      }
+      else *s = '\\';		/* restore delimiter */
+      s[1] = c;			/* restore character after delimiter */
+    }
+    flock (fd,LOCK_UN);		/* release lock on the file */
+    close (fd);			/* pacify NTFS */
+				/* rename the file */
+    if (ret && rename (file,tmp)) {
+      sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
+	       strerror (errno));
+      mm_log (tmp,ERROR);
+      ret = NIL;		/* set failure */
+    }
+  }
+  else {
+    flock (fd,LOCK_UN);		/* release lock on the file */
+    close (fd);			/* pacify NTFS */
+    if (unlink (file)) {
+      sprintf (tmp,"Can't delete mailbox %.80s: %.80s",old,strerror (errno));
+      mm_log (tmp,ERROR);
+      ret = NIL;		/* set failure */
+    }
+  }
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+  return ret;			/* return success */
+}
+
+/* MTX mail open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *mtx_open (MAILSTREAM *stream)
+{
+  int fd,ld;
+  char tmp[MAILTMPLEN];
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return &mtxproto;
+  if (stream->local) fatal ("mtx recycle stream");
+				/* canonicalize the mailbox name */
+  if (!dummy_file (tmp,stream->mailbox)) {
+    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
+    mm_log (tmp,ERROR);
+  }
+  if (stream->rdonly ||
+      (fd = open (tmp,O_BINARY|O_RDWR,NIL)) < 0) {
+    if ((fd = open (tmp,O_BINARY|O_RDONLY,NIL)) < 0) {
+      sprintf (tmp,"Can't open mailbox: %.80s",strerror (errno));
+      mm_log (tmp,ERROR);
+      return NIL;
+    }
+    else if (!stream->rdonly) {	/* got it, but readonly */
+      mm_log ("Can't get write access to mailbox, access is readonly",WARN);
+      stream->rdonly = T;
+    }
+  }
+  stream->local = fs_get (sizeof (MTXLOCAL));
+  LOCAL->fd = fd;		/* bind the file */
+  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
+  LOCAL->buflen = CHUNKSIZE - 1;
+				/* note if an INBOX or not */
+  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
+  fs_give ((void **) &stream->mailbox);
+  stream->mailbox = cpystr (tmp);
+				/* get shared parse permission */
+  if ((ld = lockname (tmp,stream->mailbox,LOCK_SH)) < 0) {
+    mm_log ("Unable to lock open mailbox",ERROR);
+    return NIL;
+  }
+  flock (LOCAL->fd,LOCK_SH);	/* lock the file */
+  unlockfd (ld,tmp);		/* release shared parse permission */
+  LOCAL->filesize = 0;		/* initialize parsed file size */
+  LOCAL->filetime = 0;		/* time not set up yet */
+  LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
+  stream->sequence++;		/* bump sequence number */
+  stream->uid_validity = (unsigned long) time (0);
+				/* parse mailbox */
+  stream->nmsgs = stream->recent = 0;
+  if (mtx_ping (stream) && !stream->nmsgs)
+    mm_log ("Mailbox is empty",(long) NIL);
+  if (!LOCAL) return NIL;	/* failure if stream died */
+  stream->perm_seen = stream->perm_deleted =
+    stream->perm_flagged = stream->perm_answered = stream->perm_draft =
+      stream->rdonly ? NIL : T;
+  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
+  return stream;		/* return stream to caller */
+}
+
+/* MTX mail close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void mtx_close (MAILSTREAM *stream,long options)
+{
+  if (stream && LOCAL) {	/* only if a file is open */
+    int silent = stream->silent;
+    stream->silent = T;		/* note this stream is dying */
+    if (options & CL_EXPUNGE) mtx_expunge (stream,NIL,NIL);
+    stream->silent = silent;	/* restore previous status */
+    flock (LOCAL->fd,LOCK_UN);	/* unlock local file */
+    close (LOCAL->fd);		/* close the local file */
+				/* free local text buffer */
+    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+
+/* MTX mail fetch flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ * Sniffs at file to see if some other process changed the flags
+ */
+
+void mtx_flags (MAILSTREAM *stream,char *sequence,long flags)
+{
+  unsigned long i;
+  if (mtx_ping (stream) && 	/* ping mailbox, get new status for messages */
+      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
+       mail_sequence (stream,sequence)))
+    for (i = 1; i <= stream->nmsgs; i++) 
+      if (mail_elt (stream,i)->sequence) mtx_elt (stream,i);
+}
+
+/* MTX mail fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+char *mtx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
+		  long flags)
+{
+  *length = 0;			/* default to empty */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+				/* get to header position */
+  lseek (LOCAL->fd,mtx_hdrpos (stream,msgno,length),L_SET);
+				/* is buffer big enough? */
+  if (*length > LOCAL->buflen) {
+    fs_give ((void **) &LOCAL->buf);
+    LOCAL->buf = (char *) fs_get ((LOCAL->buflen = *length) + 1);
+  }
+  LOCAL->buf[*length] = '\0';	/* tie off string */
+				/* slurp the data */
+  read (LOCAL->fd,LOCAL->buf,*length);
+  return LOCAL->buf;
+}
+
+/* MTX mail fetch message text (body only)
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: T, always
+ */
+
+long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  FDDATA d;
+  unsigned long i,j;
+  MESSAGECACHE *elt;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+  elt = mtx_elt (stream,msgno);	/* get message status */
+				/* if message not seen */
+  if (!(flags & FT_PEEK) && !elt->seen) {
+    elt->seen = T;		/* mark message as seen */
+				/* recalculate status */
+    mtx_update_status (stream,msgno,NIL);
+    mm_flags (stream,msgno);
+  }
+				/* find header position */
+  i = mtx_hdrpos (stream,msgno,&j);
+  d.fd = LOCAL->fd;		/* set up file descriptor */
+  d.pos = i + j;
+  d.chunk = LOCAL->buf;	/* initial buffer chunk */
+  d.chunksize = CHUNKSIZE;
+  INIT (bs,fd_string,&d,elt->rfc822_size - j);
+  return T;			/* success */
+}
+
+/* MTX mail modify flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    flag(s)
+ *	    option flags
+ */
+
+void mtx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
+{
+  struct utimbuf times;
+  struct stat sbuf;
+  if (!stream->rdonly) {	/* make sure the update takes */
+    fsync (LOCAL->fd);
+    fstat (LOCAL->fd,&sbuf);	/* get current write time */
+    times.modtime = LOCAL->filetime = sbuf.st_mtime;
+    times.actime = time (0);	/* make sure read comes after all that */
+    utime (stream->mailbox,&times);
+  }
+}
+
+
+/* MTX mail per-message modify flags
+ * Accepts: MAIL stream
+ *	    message cache element
+ */
+
+void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  struct stat sbuf;
+				/* maybe need to do a checkpoint? */
+  if (LOCAL->filetime && !LOCAL->shouldcheck) {
+    fstat (LOCAL->fd,&sbuf);	/* get current write time */
+    if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
+    LOCAL->filetime = 0;	/* don't do this test for any other messages */
+  }
+				/* recalculate status */
+  mtx_update_status (stream,elt->msgno,NIL);
+}
+
+/* MTX mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream still alive, NIL if not
+ */
+
+long mtx_ping (MAILSTREAM *stream)
+{
+  unsigned long i = 1;
+  long r = T;
+  int ld;
+  char lock[MAILTMPLEN];
+  struct stat sbuf;
+  if (stream && LOCAL) {	/* only if stream already open */
+    fstat (LOCAL->fd,&sbuf);	/* get current file poop */
+    if (LOCAL->filetime && !(LOCAL->mustcheck || LOCAL->shouldcheck) &&
+	(LOCAL->filetime < sbuf.st_mtime)) LOCAL->shouldcheck = T;
+				/* check for changed message status */
+    if (LOCAL->mustcheck || LOCAL->shouldcheck) {
+      LOCAL->filetime = sbuf.st_mtime;
+      if (LOCAL->shouldcheck)	/* babble when we do this unilaterally */
+	mm_notify (stream,"[CHECK] Checking for flag updates",NIL);
+      while (i <= stream->nmsgs) mtx_elt (stream,i++);
+      LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
+    }
+				/* get shared parse/append permission */
+    if ((sbuf.st_size != LOCAL->filesize) &&
+	((ld = lockname (lock,stream->mailbox,LOCK_SH)) >= 0)) {
+				/* parse resulting mailbox */
+      r = (mtx_parse (stream)) ? T : NIL;
+      unlockfd (ld,lock);	/* release shared parse/append permission */
+    }
+  }
+  return r;			/* return result of the parse */
+}
+
+
+/* MTX mail check mailbox (reparses status too)
+ * Accepts: MAIL stream
+ */
+
+void mtx_check (MAILSTREAM *stream)
+{
+				/* mark that a check is desired */
+  if (LOCAL) LOCAL->mustcheck = T;
+  if (mtx_ping (stream)) mm_log ("Check completed",(long) NIL);
+}
+
+/* MTX mail expunge mailbox
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long mtx_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  long ret;
+  struct utimbuf times;
+  struct stat sbuf;
+  off_t pos = 0;
+  int ld;
+  unsigned long i = 1;
+  unsigned long j,k,m,recent;
+  unsigned long n = 0;
+  unsigned long delta = 0;
+  char lock[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  if (!(ret = (sequence ? ((options & EX_UID) ?
+			   mail_uid_sequence (stream,sequence) :
+			   mail_sequence (stream,sequence)) : LONGT) &&
+	mtx_ping (stream)));	/* parse sequence if given, ping stream */
+  else if (stream->rdonly) mm_log ("Expunge ignored on readonly mailbox",WARN);
+  else {
+    if (LOCAL->filetime && !LOCAL->shouldcheck) {
+      fstat (LOCAL->fd,&sbuf);	/* get current write time */
+      if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
+    }
+				/* get exclusive parse/append permission */
+    if ((ld = lockname (lock,stream->mailbox,LOCK_EX)) < 0)
+      mm_log ("Unable to lock expunge mailbox",ERROR);
+				/* make sure see any newly-arrived messages */
+    else if (!mtx_parse (stream));
+				/* get exclusive access */
+    else if (flock (LOCAL->fd,LOCK_EX|LOCK_NB)) {
+      flock (LOCAL->fd,LOCK_SH);/* recover previous lock */
+      mm_log ("Can't expunge because mailbox is in use by another process",
+	      ERROR);
+      unlockfd (ld,lock);	/* release exclusive parse/append permission */
+    }
+
+    else {
+      mm_critical (stream);	/* go critical */
+      recent = stream->recent;	/* get recent now that pinged and locked */
+				/* for each message */
+      while (i <= stream->nmsgs) {
+				/* get cache element */
+	elt = mtx_elt (stream,i);
+				/* number of bytes to smash or preserve */
+	k = elt->private.special.text.size + elt->rfc822_size;
+				/* if need to expunge this message */
+	if (elt->deleted && (sequence ? elt->sequence : T)) {
+				/* if recent, note one less recent message */
+	  if (elt->recent) --recent;
+	  delta += k;		/* number of bytes to delete */
+				/* notify upper levels */
+	  mail_expunged (stream,i);
+	  n++;			/* count up one more expunged message */
+	}
+	else if (i++ && delta) {/* preserved message */
+				/* first byte to preserve */
+	  j = elt->private.special.offset;
+	  do {			/* read from source position */
+	    m = min (k,LOCAL->buflen);
+	    lseek (LOCAL->fd,j,L_SET);
+	    read (LOCAL->fd,LOCAL->buf,m);
+	    pos = j - delta;	/* write to destination position */
+	    while (T) {
+	      lseek (LOCAL->fd,pos,L_SET);
+	      if (write (LOCAL->fd,LOCAL->buf,m) > 0) break;
+	      mm_notify (stream,strerror (errno),WARN);
+	      mm_diskerror (stream,errno,T);
+	    }
+	    pos += m;		/* new position */
+	    j += m;		/* next chunk, perhaps */
+	  } while (k -= m);	/* until done */
+				/* note the new address of this text */
+	  elt->private.special.offset -= delta;
+	}
+				/* preserved but no deleted messages */
+	else pos = elt->private.special.offset + k;
+      }
+      if (n) {			/* truncate file after last message */
+	if (pos != (LOCAL->filesize -= delta)) {
+	  sprintf (LOCAL->buf,
+		   "Calculated size mismatch %lu != %lu, delta = %lu",
+		   (unsigned long) pos,(unsigned long) LOCAL->filesize,delta);
+	  mm_log (LOCAL->buf,WARN);
+	  LOCAL->filesize = pos;/* fix it then */
+	}
+	ftruncate (LOCAL->fd,LOCAL->filesize);
+	sprintf (LOCAL->buf,"Expunged %lu messages",n);
+				/* output the news */
+	mm_log (LOCAL->buf,(long) NIL);
+      }
+      else mm_log ("No messages deleted, so no update needed",(long) NIL);
+      fsync (LOCAL->fd);	/* force disk update */
+      fstat (LOCAL->fd,&sbuf);	/* get new write time */
+      times.modtime = LOCAL->filetime = sbuf.st_mtime;
+      times.actime = time (0);	/* reset atime to now */
+      utime (stream->mailbox,&times);
+      mm_nocritical (stream);	/* release critical */
+				/* notify upper level of new mailbox size */
+      mail_exists (stream,stream->nmsgs);
+      mail_recent (stream,recent);
+      flock (LOCAL->fd,LOCK_SH);/* allow sharers again */
+      unlockfd (ld,lock);	/* release exclusive parse/append permission */
+    }
+  }
+  return ret;
+}
+
+/* MTX mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if success, NIL if failed
+ */
+
+long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  struct stat sbuf;
+  struct utimbuf times;
+  MESSAGECACHE *elt;
+  unsigned long i,j,k;
+  long ret = LONGT;
+  int fd,ld;
+  char file[MAILTMPLEN],lock[MAILTMPLEN];
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+				/* make sure valid mailbox */
+  if (!mtx_isvalid (mailbox,file)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
+    return NIL;
+  case 0:			/* merely empty file? */
+    break;
+  case EACCES:			/* file protected */
+    sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
+    MM_LOG (LOCAL->buf,ERROR);
+    return NIL;
+  case EINVAL:
+    if (pc) return (*pc) (stream,sequence,mailbox,options);
+    sprintf (LOCAL->buf,"Invalid MTX-format mailbox name: %.80s",mailbox);
+    mm_log (LOCAL->buf,ERROR);
+    return NIL;
+  default:
+    if (pc) return (*pc) (stream,sequence,mailbox,options);
+    sprintf (LOCAL->buf,"Not a MTX-format mailbox: %.80s",mailbox);
+    mm_log (LOCAL->buf,ERROR);
+    return NIL;
+  }
+  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+	mail_sequence (stream,sequence))) return NIL;
+				/* got file? */
+  if ((fd = open (file,O_BINARY|O_RDWR|O_CREAT,S_IREAD|S_IWRITE)) < 0) {
+    sprintf (LOCAL->buf,"Unable to open copy mailbox: %.80s",strerror (errno));
+    mm_log (LOCAL->buf,ERROR);
+    return NIL;
+  }
+  mm_critical (stream);		/* go critical */
+				/* get exclusive parse/append permission */
+  if (flock (fd,LOCK_SH) || ((ld = lockname (lock,file,LOCK_EX)) < 0)) {
+    mm_log ("Unable to lock copy mailbox",ERROR);
+    mm_nocritical (stream);
+    return NIL;
+  }
+  fstat (fd,&sbuf);		/* get current file size */
+  lseek (fd,sbuf.st_size,L_SET);/* move to end of file */
+
+				/* for each requested message */
+  for (i = 1; ret && (i <= stream->nmsgs); i++) 
+    if ((elt = mail_elt (stream,i))->sequence) {
+      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
+				/* number of bytes to copy */
+      k = elt->private.special.text.size + elt->rfc822_size;
+      do {			/* read from source position */
+	j = min (k,LOCAL->buflen);
+	read (LOCAL->fd,LOCAL->buf,j);
+	if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
+      } while (ret && (k -= j));/* until done */
+    }
+				/* make sure all the updates take */
+  if (!(ret && (ret = !fsync (fd)))) {
+    sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno));
+    mm_log (LOCAL->buf,ERROR);
+    ftruncate (fd,sbuf.st_size);
+  }
+				/* set atime to now-1 if successful copy */
+  if (ret) times.actime = time (0) - 1;
+				/* else preserved \Marked status */
+  else times.actime = (sbuf.st_ctime > sbuf.st_atime) ?
+	 sbuf.st_atime : time (0);
+  times.modtime = sbuf.st_mtime;/* preserve mtime */
+  utime (file,&times);		/* set the times */
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+  close (fd);			/* close the file */
+  mm_nocritical (stream);	/* release critical */
+				/* delete all requested messages */
+  if (ret && (options & CP_MOVE)) {
+    for (i = 1; i <= stream->nmsgs; i++)
+      if ((elt = mtx_elt (stream,i))->sequence) {
+	elt->deleted = T;	/* mark message deleted */
+				/* recalculate status */
+	mtx_update_status (stream,i,NIL);
+      }
+    if (!stream->rdonly) {	/* make sure the update takes */
+      fsync (LOCAL->fd);
+      fstat (LOCAL->fd,&sbuf);	/* get current write time */
+      times.modtime = LOCAL->filetime = sbuf.st_mtime;
+      times.actime = time (0);	/* make sure atime remains greater */
+      utime (stream->mailbox,&times);
+    }
+  }
+  if (ret && mail_parameters (NIL,GET_COPYUID,NIL))
+    mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN);
+  return ret;
+}
+
+/* MTX mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct stat sbuf;
+  int fd,ld,c;
+  char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  struct utimbuf times;
+  FILE *df;
+  MESSAGECACHE elt;
+  long f;
+  unsigned long i,uf;
+  STRING *message;
+  long ret = LONGT;
+				/* default stream to prototype */
+  if (!stream) stream = &mtxproto;
+				/* make sure valid mailbox */
+  if (!mtx_isvalid (mailbox,file)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    if (!compare_cstring (mailbox,"INBOX")) mtx_create (NIL,"INBOX");
+    else {
+      mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+      return NIL;
+    }
+				/* falls through */
+  case 0:			/* merely empty file? */
+    break;
+  case EACCES:			/* file protected */
+    sprintf (tmp,"Can't access destination: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  case EINVAL:
+    sprintf (tmp,"Invalid MTX-format mailbox name: %.80s",mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;
+  default:
+    sprintf (tmp,"Not a MTX-format mailbox: %.80s",mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* get first message */
+  if (!(*af) (stream,data,&flags,&date,&message)) return NIL;
+
+				/* open destination mailbox */
+  if (((fd = open (file,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IREAD|S_IWRITE))
+       < 0) || !(df = fdopen (fd,"ab"))) {
+    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* get parse/append permission */
+  if (flock (fd,LOCK_SH) || ((ld = lockname (lock,file,LOCK_EX)) < 0)) {
+    mm_log ("Unable to lock append mailbox",ERROR);
+    close (fd);
+    return NIL;
+  }
+  mm_critical (stream);		/* go critical */
+  fstat (fd,&sbuf);		/* get current file size */
+  errno = 0;
+  do {				/* parse flags */
+    if (!SIZE (message)) {	/* guard against zero-length */
+      mm_log ("Append of zero-length message",ERROR);
+      ret = NIL;
+      break;
+    }
+    f = mail_parse_flags (stream,flags,&i);
+				/* reverse bits (dontcha wish we had CIRC?) */
+    for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i)));
+    if (date) {			/* parse date if given */
+      if (!mail_parse_date (&elt,date)) {
+	sprintf (tmp,"Bad date in append: %.80s",date);
+	mm_log (tmp,ERROR);
+	ret = NIL;		/* mark failure */
+	break;
+      }
+      mail_date (tmp,&elt);	/* write preseved date */
+    }
+    else internal_date (tmp);	/* get current date in IMAP format */
+				/* write header */
+    if (fprintf (df,"%s,%lu;%010lo%02lo\015\012",tmp,i = SIZE (message),uf,
+		 (unsigned long) f) < 0) ret = NIL;
+    else {			/* write message */
+      if (i) do c = 0xff & SNX (message);
+      while ((putc (c,df) != EOF) && --i);
+				/* get next message */
+      if (i || !(*af) (stream,data,&flags,&date,&message)) ret = NIL;
+    }
+  } while (ret && message);
+				/* if error... */
+  if (!ret || (fflush (df) == EOF)) {
+    ftruncate (fd,sbuf.st_size);/* revert file */
+    close (fd);			/* make sure fclose() doesn't corrupt us */
+    if (errno) {
+      sprintf (tmp,"Message append failed: %s",strerror (errno));
+      mm_log (tmp,ERROR);
+    }
+    ret = NIL;
+  }
+  if (ret) times.actime = time (0) - 1;
+				/* else preserved \Marked status */
+  else times.actime = (sbuf.st_ctime > sbuf.st_atime) ?
+	 sbuf.st_atime : time (0);
+  times.modtime = sbuf.st_mtime;/* preserve mtime */
+  utime (file,&times);		/* set the times */
+  fclose (df);			/* close the file */
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+  mm_nocritical (stream);	/* release critical */
+  if (ret && mail_parameters (NIL,GET_APPENDUID,NIL))
+    mm_log ("Can not return meaningful APPENDUID with this mailbox format",
+	    WARN);
+  return ret;
+}
+
+/* Internal routines */
+
+
+/* MTX mail parse mailbox
+ * Accepts: MAIL stream
+ * Returns: T if parse OK
+ *	    NIL if failure, stream aborted
+ */
+
+long mtx_parse (MAILSTREAM *stream)
+{
+  struct stat sbuf;
+  MESSAGECACHE *elt = NIL;
+  unsigned char c,*s,*t,*x;
+  char tmp[MAILTMPLEN];
+  unsigned long i,j;
+  long curpos = LOCAL->filesize;
+  long nmsgs = stream->nmsgs;
+  long recent = stream->recent;
+  short added = NIL;
+  short silent = stream->silent;
+  fstat (LOCAL->fd,&sbuf);	/* get status */
+  if (sbuf.st_size < curpos) {	/* sanity check */
+    sprintf (tmp,"Mailbox shrank from %ld to %ld!",curpos,sbuf.st_size);
+    mm_log (tmp,ERROR);
+    mtx_close (stream,NIL);
+    return NIL;
+  }
+  stream->silent = T;		/* don't pass up mm_exists() events yet */
+  while (sbuf.st_size - curpos){/* while there is stuff to parse */
+				/* get to that position in the file */
+    lseek (LOCAL->fd,curpos,L_SET);
+    if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) {
+      sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s",
+	       (unsigned long) curpos,(unsigned long) sbuf.st_size,
+	       i ? strerror (errno) : "no data read");
+      mm_log (tmp,ERROR);
+      mtx_close (stream,NIL);
+      return NIL;
+    }
+    LOCAL->buf[i] = '\0';	/* tie off buffer just in case */
+    if (!((s = strchr (LOCAL->buf,'\015')) && (s[1] == '\012'))) {
+      sprintf (tmp,"Unable to find CRLF at %lu in %lu bytes, text: %s",
+	       (unsigned long) curpos,i,(char *) LOCAL->buf);
+      mm_log (tmp,ERROR);
+      mtx_close (stream,NIL);
+      return NIL;
+    }
+    *s = '\0';			/* tie off header line */
+    i = (s + 2) - LOCAL->buf;	/* note start of text offset */
+    if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) {
+      sprintf (tmp,"Unable to parse internal header at %lu: %s",
+	       (unsigned long) curpos,(char *) LOCAL->buf);
+      mm_log (tmp,ERROR);
+      mtx_close (stream,NIL);
+      return NIL;
+    }
+    *s++ = '\0'; *t++ = '\0';	/* tie off fields */
+
+    added = T;			/* note that a new message was added */
+				/* swell the cache */
+    mail_exists (stream,++nmsgs);
+				/* instantiate an elt for this message */
+    (elt = mail_elt (stream,nmsgs))->valid = T;
+    elt->private.uid = ++stream->uid_last;
+				/* note file offset of header */
+    elt->private.special.offset = curpos;
+				/* in case error */
+    elt->private.special.text.size = 0;
+				/* header size not known yet */
+    elt->private.msg.header.text.size = 0;
+    x = s;			/* parse the header components */
+    if (mail_parse_date (elt,LOCAL->buf) &&
+	(elt->rfc822_size = strtoul (s,(char **) &s,10)) && (!(s && *s)) &&
+	isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) &&
+	isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) &&
+	isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) &&
+	isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12])
+      elt->private.special.text.size = i;
+    else {			/* oops */
+      sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s",
+	       curpos,(char *) LOCAL->buf,(char *) x,(char *) t);
+      mm_log (tmp,ERROR);
+      mtx_close (stream,NIL);
+      return NIL;
+    }
+				/* make sure didn't run off end of file */
+    if ((curpos += (elt->rfc822_size + i)) > sbuf.st_size) {
+      sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
+	       elt->private.special.offset,(unsigned long) curpos,
+	       (unsigned long) sbuf.st_size);
+      mm_log (tmp,ERROR);
+      mtx_close (stream,NIL);
+      return NIL;
+    }
+    c = t[10];			/* remember first system flags byte */
+    t[10] = '\0';		/* tie off flags */
+    j = strtoul (t,NIL,8);	/* get user flags value */
+    t[10] = c;			/* restore first system flags byte */
+				/* set up all valid user flags (reversed!) */
+    while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
+		  stream->user_flags[i]) elt->user_flags |= 1 << i;
+				/* calculate system flags */
+    if ((j = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T;
+    if (j & fDELETED) elt->deleted = T;
+    if (j & fFLAGGED) elt->flagged = T;
+    if (j & fANSWERED) elt->answered = T;
+    if (j & fDRAFT) elt->draft = T;
+    if (!(j & fOLD)) {		/* newly arrived message? */
+      elt->recent = T;
+      recent++;			/* count up a new recent message */
+				/* mark it as old */
+      mtx_update_status (stream,nmsgs,NIL);
+    }
+  }
+  fsync (LOCAL->fd);		/* make sure all the fOLD flags take */
+				/* update parsed file size and time */
+  LOCAL->filesize = sbuf.st_size;
+  fstat (LOCAL->fd,&sbuf);	/* get status again to ensure time is right */
+  LOCAL->filetime = sbuf.st_mtime;
+  if (added && !stream->rdonly){/* make sure atime updated */
+    struct utimbuf times;
+    times.actime = time (0);
+    times.modtime = LOCAL->filetime;
+    utime (stream->mailbox,&times);
+  }
+  stream->silent = silent;	/* can pass up events now */
+  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
+  mail_recent (stream,recent);	/* and of change in recent messages */
+  return LONGT;			/* return the winnage */
+}
+
+/* MTX get cache element with status updating from file
+ * Accepts: MAIL stream
+ *	    message number
+ * Returns: cache element
+ */
+
+MESSAGECACHE *mtx_elt (MAILSTREAM *stream,unsigned long msgno)
+{
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  struct {			/* old flags */
+    unsigned int seen : 1;
+    unsigned int deleted : 1;
+    unsigned int flagged : 1;
+    unsigned int answered : 1;
+    unsigned int draft : 1;
+    unsigned long user_flags;
+  } old;
+  old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged;
+  old.answered = elt->answered; old.draft = elt->draft;
+  old.user_flags = elt->user_flags;
+  mtx_read_flags (stream,elt);
+  if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
+      (old.flagged != elt->flagged) || (old.answered != elt->answered) ||
+      (old.draft != elt->draft) || (old.user_flags != elt->user_flags))
+    mm_flags (stream,msgno);	/* let top level know */
+  return elt;
+}
+
+/* MTX read flags from file
+ * Accepts: MAIL stream
+ * Returns: cache element
+ */
+
+void mtx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  unsigned long i,j;
+				/* noop if readonly and have valid flags */
+  if (stream->rdonly && elt->valid) return;
+				/* set the seek pointer */
+  lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	 elt->private.special.text.size - 14,L_SET);
+				/* read the new flags */
+  if (read (LOCAL->fd,LOCAL->buf,12) < 0) {
+    sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno));
+    fatal (LOCAL->buf);
+  }
+				/* calculate system flags */
+  i = (((LOCAL->buf[10]-'0') * 8) + LOCAL->buf[11]-'0');
+  elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL;
+  elt->flagged = i & fFLAGGED ? T : NIL;
+  elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL;
+  LOCAL->buf[10] = '\0';	/* tie off flags */
+  j = strtoul(LOCAL->buf,NIL,8);/* get user flags value */
+				/* set up all valid user flags (reversed!) */
+  while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
+		stream->user_flags[i]) elt->user_flags |= 1 << i;
+  elt->valid = T;		/* have valid flags now */
+}
+
+/* MTX update status string
+ * Accepts: MAIL stream
+ *	    message number
+ *	    flag saying whether or not to sync
+ */
+
+void mtx_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag)
+{
+  struct utimbuf times;
+  struct stat sbuf;
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  unsigned long j,k = 0;
+				/* readonly */
+  if (stream->rdonly || !elt->valid) mtx_read_flags (stream,elt);
+  else {			/* readwrite */
+    j = elt->user_flags;	/* get user flags */
+				/* reverse bits (dontcha wish we had CIRC?) */
+    while (j) k |= 1 << (29 - find_rightmost_bit (&j));
+				/* print new flag string */
+    sprintf (LOCAL->buf,"%010lo%02o",k,(unsigned)
+	     (fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
+	      (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
+	      (fDRAFT * elt->draft)));
+    while (T) {			/* get to that place in the file */
+      lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	     elt->private.special.text.size - 14,L_SET);
+				/* write new flags */
+      if (write (LOCAL->fd,LOCAL->buf,12) > 0) break;
+      mm_notify (stream,strerror (errno),WARN);
+      mm_diskerror (stream,errno,T);
+    }
+    if (syncflag) {		/* sync if requested */
+      fsync (LOCAL->fd);
+      fstat (LOCAL->fd,&sbuf);	/* get new write time */
+      times.modtime = LOCAL->filetime = sbuf.st_mtime;
+      times.actime = time (0);	/* make sure read is later */
+      utime (stream->mailbox,&times);
+    }
+  }
+}
+
+/* MTX locate header for a message
+ * Accepts: MAIL stream
+ *	    message number
+ *	    pointer to returned header size
+ * Returns: position of header in file
+ */
+
+unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			  unsigned long *size)
+{
+  unsigned long siz;
+  long i = 0;
+  int q = 0;
+  char *s,tmp[MAILTMPLEN];
+  MESSAGECACHE *elt = mtx_elt (stream,msgno);
+  unsigned long ret = elt->private.special.offset +
+    elt->private.special.text.size;
+				/* is header size known? */
+  if (!(*size = elt->private.msg.header.text.size)) {
+    lseek (LOCAL->fd,ret,L_SET);/* get to header position */
+				/* search message for CRLF CRLF */
+    for (siz = 1,s = tmp; siz <= elt->rfc822_size; siz++) {
+				/* read another buffer as necessary */
+      if ((--i <= 0) &&		/* buffer empty? */
+	  (read (LOCAL->fd,s = tmp,
+		 i = min (elt->rfc822_size - siz,(long) MAILTMPLEN)) < 0))
+	return ret;		/* I/O error? */
+      switch (q) {		/* sniff at buffer */
+      case 0:			/* first character */
+	q = (*s++ == '\015') ? 1 : 0;
+	break;
+      case 1:			/* second character */
+	q = (*s++ == '\012') ? 2 : 0;
+	break;
+      case 2:			/* third character */
+	q = (*s++ == '\015') ? 3 : 0;
+	break;
+      case 3:			/* fourth character */
+	if (*s++ == '\012') {	/* have the sequence? */
+				/* yes, note for later */
+	  elt->private.msg.header.text.size = *size = siz;
+	  return ret;
+	}
+	q = 0;			/* lost... */
+	break;
+      }
+    }
+				/* header consumes entire message */
+    elt->private.msg.header.text.size = *size = elt->rfc822_size;
+  }
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/os2/nl_os2.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,61 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Windows/TOPS-20 newline routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Copy string with CRLF newlines
+ * Accepts: destination string
+ *	    pointer to size of destination string buffer
+ *	    source string
+ *	    length of source string
+ * Returns: length of copied string
+ */
+
+unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl,
+			  unsigned char *src,unsigned long srcl)
+{
+				/* flush destination buffer if too small */
+  if (*dst && (srcl > *dstl)) fs_give ((void **) dst);
+  if (!*dst) {			/* make a new buffer if needed */
+    *dst = (char *) fs_get ((size_t) (*dstl = srcl) + 1);
+    if (dstl) *dstl = srcl;	/* return new buffer length to main program */
+  }
+				/* copy strings */
+  if (srcl) memcpy (*dst,src,(size_t) srcl);
+  *(*dst + srcl) = '\0';	/* tie off destination */
+  return srcl;			/* return length */
+}
+
+
+/* Length of string after strcrlfcpy applied
+ * Accepts: source string
+ * Returns: length of string
+ */
+
+unsigned long strcrlflen (STRING *s)
+{
+  return SIZE (s);		/* no-brainer on DOS! */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/os2/os_os2.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,100 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- OS/2 emx version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	14 March 1996
+ * Last Edited:	30 August 2006
+ */
+
+#include <stdio.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "tcp_os2.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include "misc.h"
+#include "fs_os2.c"
+#include "ftl_os2.c"
+#include "nl_os2.c"
+#include "env_os2.c"
+#include "tcp_os2.c"
+
+/* Return my local host name
+ * Returns: my local host name
+ */
+
+char *mylocalhost (void)
+{
+  if (!myLocalHost) {		/* known yet? */
+    char *s,tmp[MAILTMPLEN];
+    struct hostent *he;
+				/* could we get local id? */
+    gethostname (tmp,MAILTMPLEN-1);
+    if (he = gethostbyname (lcase (tmp))) {
+      if (he->h_name) s = he->h_name;
+      else sprintf (s = tmp,"[%i.%i.%i.%i]",he->h_addr[0],he->h_addr[1],
+		    he->h_addr[2],he->h_addr[3]);
+    }
+    else s = "random-pc";
+    myLocalHost = cpystr (s);	/* record for subsequent use */
+  }
+  return myLocalHost;
+}
+
+
+/* Look up host address
+ * Accepts: pointer to pointer to host name
+ *	    socket address block
+ * Returns: non-zero with host address in socket, official host name in host;
+ *	    else NIL
+ */
+
+long lookuphost (char **host,struct sockaddr_in *sin)
+{
+  long ret = -1;
+  char tmp[MAILTMPLEN];
+  struct hostent *hn = gethostbyname (lcase (strcpy (tmp,*host)));
+  if (!hn) return NIL;		/* got a host name? */
+  *host = cpystr (hn->h_name);	/* set official name */
+				/* copy host addresses */
+  memcpy (&sin->sin_addr,hn->h_addr,hn->h_length);
+  return T;
+}
+
+
+/*
+ * Emulator for BSD syslog() routine.
+ */
+
+void syslog (int priority,const char *message,...)
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/os2/os_os2.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,38 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- OS/2 emx version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	14 March 1996
+ * Last Edited:	30 August 2006
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include "env_os2.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/os2/pmatch.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,89 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	IMAP Wildcard Matching Routines (case-independent)
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	15 June 2000
+ * Last Edited:	30 August 2006
+ */
+
+/* Wildcard pattern match
+ * Accepts: base string
+ *	    pattern string
+ *	    delimiter character
+ * Returns: T if pattern matches base, else NIL
+ */
+
+long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim)
+{
+  switch (*pat) {
+  case '%':			/* non-recursive */
+				/* % at end, OK if no inferiors */
+    if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T;
+                                /* scan remainder of string until delimiter */
+    do if (pmatch_full (s,pat+1,delim)) return T;
+    while ((*s != delim) && *s++);
+    break;
+  case '*':			/* match 0 or more characters */
+    if (!pat[1]) return T;	/* * at end, unconditional match */
+				/* scan remainder of string */
+    do if (pmatch_full (s,pat+1,delim)) return T;
+    while (*s++);
+    break;
+  case '\0':			/* end of pattern */
+    return *s ? NIL : T;	/* success if also end of base */
+  default:			/* match this character */
+    return compare_uchar (*pat,*s) ? NIL : pmatch_full (s+1,pat+1,delim);
+  }
+  return NIL;
+}
+
+/* Directory pattern match
+ * Accepts: base string
+ *	    pattern string
+ *	    delimiter character
+ * Returns: T if base is a matching directory of pattern, else NIL
+ */
+
+long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim)
+{
+  switch (*pat) {
+  case '%':			/* non-recursive */
+    if (!*s) return T;		/* end of base means have a subset match */
+    if (!*++pat) return NIL;	/* % at end, no inferiors permitted */
+				/* scan remainder of string until delimiter */
+    do if (dmatch (s,pat,delim)) return T;
+    while ((*s != delim) && *s++);
+    if (*s && !s[1]) return T;	/* ends with delimiter, must be subset */
+    return dmatch (s,pat,delim);/* do new scan */
+  case '*':			/* match 0 or more characters */
+    return T;			/* unconditional match */
+  case '\0':			/* end of pattern */
+    break;
+  default:			/* match this character */
+    if (*s) return compare_uchar (*pat,*s) ? NIL : dmatch (s+1,pat+1,delim);
+				/* end of base, return if at delimiter */
+    else if (*pat == delim) return T;
+    break;
+  }
+  return NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/os2/pseudo.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,36 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Pseudo Header Strings
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	26 September 1996
+ * Last Edited:	30 August 2006
+ */
+
+/* Local sites may wish to alter this text */
+
+char *pseudo_from = "MAILER-DAEMON";
+char *pseudo_name = "Mail System Internal Data";
+char *pseudo_subject = "DON'T DELETE THIS MESSAGE -- FOLDER INTERNAL DATA";
+char *pseudo_msg =
+  "This text is part of the internal format of your mail folder, and is not\na real message.  It is created automatically by the mail system software.\nIf deleted, important folder data will be lost, and it will be re-created\nwith the data reset to initial values."
+  ;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/os2/pseudo.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,30 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Pseudo Header Strings
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	26 September 1996
+ * Last Edited:	30 August 2006
+ */
+
+
+extern char *pseudo_from,*pseudo_name,*pseudo_subject,*pseudo_msg;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/os2/setproto.cmd	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,34 @@
+/* rexx */
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+/*
+ * Program:	Set default prototype for OS/2
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 June 1999
+ * Last Edited:	30 August 2006
+ */
+'@echo off'
+parse arg default args
+h_file='linkage.h'
+call stream h_file, 'C', 'open write'
+call lineout h_file, '#define DEFAULTPROTO' default'proto'
+call stream h_file, 'C', 'close'
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/os2/tcp_os2.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,434 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	MS-DOS TCP/IP routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 April 1989
+ * Last Edited:	13 January 2008
+ */
+
+static tcptimeout_t tmoh = NIL;	/* TCP timeout handler routine */
+static long ttmo_read = 0;	/* TCP timeouts, in seconds */
+static long ttmo_write = 0;
+
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+			       long *contd);
+
+/* TCP/IP manipulate parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *tcp_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case SET_TIMEOUT:
+    tmoh = (tcptimeout_t) value;
+  case GET_TIMEOUT:
+    ret = (void *) tmoh;
+    break;
+  case SET_READTIMEOUT:
+    ttmo_read = (long) value;
+  case GET_READTIMEOUT:
+    ret = (void *) ttmo_read;
+    break;
+  case SET_WRITETIMEOUT:
+    ttmo_write = (long) value;
+  case GET_WRITETIMEOUT:
+    ret = (void *) ttmo_write;
+    break;
+  }
+  return ret;
+}
+
+/* TCP/IP open
+ * Accepts: host name
+ *	    contact service name
+ *	    contact port number
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
+{
+  TCPSTREAM *stream = NIL;
+  struct sockaddr_in sin;
+  int sock;
+  char *s,tmp[MAILTMPLEN];
+  port &= 0xffff;		/* erase flags */
+  /* The domain literal form is used (rather than simply the dotted decimal
+     as with other Unix programs) because it has to be a valid "host name"
+     in mailsystem terminology. */
+  sin.sin_family = AF_INET;	/* family is always Internet */
+				/* look like domain literal? */
+  if (host[0] == '[' && host[(strlen (host))-1] == ']') {
+    strcpy (tmp,host+1);	/* yes, copy number part */
+    tmp[strlen (tmp)-1] = '\0';
+    if ((sin.sin_addr.s_addr = inet_addr (tmp)) == -1) {
+      sprintf (tmp,"Bad format domain-literal: %.80s",host);
+      mm_log (tmp,ERROR);
+      return NIL;
+    }
+  }
+				/* look up host name */
+  else if (!lookuphost (&host,&sin)) {
+    sprintf (tmp,"Host not found: %s",host);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+
+				/* copy port number in network format */
+  if (!(sin.sin_port = htons (port))) fatal ("Bad port argument to tcp_open");
+				/* get a TCP stream */
+  if ((sock = socket (sin.sin_family,SOCK_STREAM,0)) < 0) {
+    sprintf (tmp,"Unable to create TCP socket (%d)",errno);
+    mm_log (tmp,ERROR);
+    fs_give ((void **) &host);
+    return NIL;
+  }
+#if 0
+  /* needed? */
+  else if (sock >= FD_SETSIZE) {/* unselectable sockets are useless */
+    sprintf (tmp,"Unable to create selectable TCP socket (%d >= %d)",
+	     sock,FD_SETSIZE);
+    close (sock);
+    errno = ENOBUFS;		/* just in case */
+    return NIL;
+  }
+#endif
+				/* open connection */
+  if (connect (sock,(struct sockaddr *) &sin,sizeof (sin)) < 0) {
+    switch (errno) {		/* analyze error */
+    case ECONNREFUSED:
+      s = "Refused";
+      break;
+    case ENOBUFS:
+      s = "Insufficient system resources";
+      break;
+    case ETIMEDOUT:
+      s = "Timed out";
+      break;
+    default:
+      s = "Unknown error";
+      break;
+    }
+    sprintf (tmp,"Can't connect to %.80s,%ld: %s (%d)",host,port,s,errno);
+    mm_log (tmp,ERROR);
+    close (sock);
+    fs_give ((void **) &host);
+    return NIL;
+  }
+				/* create TCP/IP stream */
+  stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
+  stream->host = host;		/* official host name */
+  stream->localhost = cpystr (mylocalhost ());
+  stream->port = port;		/* port number */
+  stream->tcps = sock;		/* init socket */
+  stream->ictr = 0;		/* init input counter */
+  return stream;		/* return success */
+}
+  
+/* TCP/IP authenticated open
+ * Accepts: NETMBX specifier
+ *	    service name
+ *	    returned user name buffer
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
+{
+  return NIL;			/* always NIL on DOS */
+}
+
+/* TCP receive line
+ * Accepts: TCP stream
+ * Returns: text line string or NIL if failure
+ */
+
+char *tcp_getline (TCPSTREAM *stream)
+{
+  unsigned long n,contd;
+  char *ret = tcp_getline_work (stream,&n,&contd);
+  if (ret && contd) {		/* got a line needing continuation? */
+    STRINGLIST *stl = mail_newstringlist ();
+    STRINGLIST *stc = stl;
+    do {			/* collect additional lines */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+      stc = stc->next = mail_newstringlist ();
+      ret = tcp_getline_work (stream,&n,&contd);
+    } while (ret && contd);
+    if (ret) {			/* stash final part of line on list */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+				/* determine how large a buffer we need */
+      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
+      ret = fs_get (n + 1);	/* copy parts into buffer */
+      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
+	memcpy (ret + n,stc->text.data,stc->text.size);
+      ret[n] = '\0';
+    }
+    mail_free_stringlist (&stl);/* either way, done with list */
+  }
+  return ret;
+}
+
+/* TCP receive line or partial line
+ * Accepts: TCP stream
+ *	    pointer to return size
+ *	    pointer to return continuation flag
+ * Returns: text line string, size and continuation flag, or NIL if failure
+ */
+
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+			       long *contd)
+{
+  unsigned long n;
+  char *s,*ret,c,d;
+  *contd = NIL;			/* assume no continuation */
+				/* make sure have data */
+  if (!tcp_getdata (stream)) return NIL;
+  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
+    d = *stream->iptr++;	/* slurp another character */
+    if ((c == '\015') && (d == '\012')) {
+      ret = (char *) fs_get (n--);
+      memcpy (ret,s,*size = n);	/* copy into a free storage string */
+      ret[n] = '\0';		/* tie off string with null */
+      return ret;
+    }
+  }
+				/* copy partial string from buffer */
+  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
+				/* get more data from the net */
+  if (!tcp_getdata (stream)) fs_give ((void **) &ret);
+				/* special case of newline broken by buffer */
+  else if ((c == '\015') && (*stream->iptr == '\012')) {
+    stream->iptr++;		/* eat the line feed */
+    stream->ictr--;
+    ret[*size = --n] = '\0';	/* tie off string with null */
+  }
+  else *contd = LONGT;		/* continuation needed */
+  return ret;
+}
+
+/* TCP/IP receive buffer
+ * Accepts: TCP/IP stream
+ *	    size in bytes
+ *	    buffer to read into
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
+{
+  unsigned long n;
+  char *bufptr = buffer;
+  while (size > 0) {		/* until request satisfied */
+    if (!tcp_getdata (stream)) return NIL;
+    n = min (size,stream->ictr);/* number of bytes to transfer */
+				/* do the copy */
+    memcpy (bufptr,stream->iptr,n);
+    bufptr += n;		/* update pointer */
+    stream->iptr +=n;
+    size -= n;			/* update # of bytes to do */
+    stream->ictr -=n;
+  }
+  bufptr[0] = '\0';		/* tie off string */
+  return T;
+}
+
+/* TCP/IP receive data
+ * Accepts: TCP/IP stream
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getdata (TCPSTREAM *stream)
+{
+  int i;
+  fd_set fds,efds;
+  struct timeval tmo;
+  time_t t = time (0);
+  if (stream->tcps < 0) return NIL;
+  while (stream->ictr < 1) {	/* if nothing in the buffer */
+    time_t tl = time (0);	/* start of request */
+    tmo.tv_sec = ttmo_read;	/* read timeout */
+    tmo.tv_usec = 0;
+    FD_ZERO (&fds);		/* initialize selection vector */
+    FD_ZERO (&efds);		/* handle errors too */
+    FD_SET (stream->tcps,&fds);/* set bit in selection vector */
+    FD_SET(stream->tcps,&efds);/* set bit in error selection vector */
+    errno = NIL;		/* block and read */
+    while (((i = select (stream->tcps+1,&fds,0,&efds,ttmo_read ? &tmo : 0))<0)
+	   && (errno == EINTR));
+    if (!i) {			/* timeout? */
+      time_t tc = time (0);
+      if (tmoh && ((*tmoh) (tc - t,tc - tl))) continue;
+      else return tcp_abort (stream);
+    }
+    else if (i < 0) return tcp_abort (stream);
+    while (((i = read (stream->tcps,stream->ibuf,BUFLEN)) < 0) &&
+	   (errno == EINTR));
+    if (i < 1) return tcp_abort (stream);
+    stream->iptr = stream->ibuf;/* point at TCP buffer */
+    stream->ictr = i;		/* set new byte count */
+  }
+  return T;
+}
+
+/* TCP/IP send string as record
+ * Accepts: TCP/IP stream
+ *	    string pointer
+ * Returns: T if success else NIL
+ */
+
+long tcp_soutr (TCPSTREAM *stream,char *string)
+{
+  return tcp_sout (stream,string,(unsigned long) strlen (string));
+}
+
+
+/* TCP/IP send string
+ * Accepts: TCP/IP stream
+ *	    string pointer
+ *	    byte count
+ * Returns: T if success else NIL
+ */
+
+long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
+{
+  int i;
+  fd_set fds;
+  struct timeval tmo;
+  time_t t = time (0);
+  if (stream->tcps < 0) return NIL;
+  while (size > 0) {		/* until request satisfied */
+    time_t tl = time (0);	/* start of request */
+    tmo.tv_sec = ttmo_write;	/* write timeout */
+    tmo.tv_usec = 0;
+    FD_ZERO (&fds);		/* initialize selection vector */
+    FD_SET (stream->tcps,&fds);/* set bit in selection vector */
+    errno = NIL;		/* block and write */
+    while (((i = select (stream->tcps+1,0,&fds,0,ttmo_write ? &tmo : 0)) < 0)
+	   && (errno == EINTR));
+    if (!i) {			/* timeout? */
+      time_t tc = time (0);
+      if (tmoh && ((*tmoh) (tc - t,tc - tl))) continue;
+      else return tcp_abort (stream);
+    }
+    else if (i < 0) return tcp_abort (stream);
+    while (((i = write (stream->tcps,string,size)) < 0) && (errno == EINTR));
+    if (i < 0) return tcp_abort (stream);
+    size -= i;			/* how much we sent */
+    string += i;
+  }
+  return T;			/* all done */
+}
+
+/* TCP/IP close
+ * Accepts: TCP/IP stream
+ */
+
+void tcp_close (TCPSTREAM *stream)
+{
+  tcp_abort (stream);		/* nuke the socket */
+				/* flush host names */
+  fs_give ((void **) &stream->host);
+  fs_give ((void **) &stream->localhost);
+  fs_give ((void **) &stream);	/* flush the stream */
+}
+
+
+/* TCP/IP abort stream
+ * Accepts: TCP/IP stream
+ * Returns: NIL always
+ */
+
+long tcp_abort (TCPSTREAM *stream)
+{
+  if (stream->tcps >= 0) close (stream->tcps);
+  stream->tcps = -1;
+  return NIL;
+}
+
+/* TCP/IP get host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_host (TCPSTREAM *stream)
+{
+  return stream->host;		/* return host name */
+}
+
+
+/* TCP/IP get remote host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_remotehost (TCPSTREAM *stream)
+{
+  return stream->host;		/* all we can do for now */
+}
+
+
+/* TCP/IP return port for this stream
+ * Accepts: TCP/IP stream
+ * Returns: port number for this stream
+ */
+
+unsigned long tcp_port (TCPSTREAM *stream)
+{
+  return stream->port;		/* return port number */
+}
+
+
+/* TCP/IP get local host name
+ * Accepts: TCP/IP stream
+ * Returns: local host name
+ */
+
+char *tcp_localhost (TCPSTREAM *stream)
+{
+  return stream->localhost;	/* return local host name */
+}
+
+
+/* TCP/IP return canonical form of host name
+ * Accepts: host name
+ * Returns: canonical form of host name
+ */
+
+char *tcp_canonical (char *name)
+{
+  return name;
+}
+
+
+/* TCP/IP get client host name (server calls only)
+ * Returns: client host name
+ */
+
+char *tcp_clienthost ()
+{
+  return "UNKNOWN";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/os2/tcp_os2.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,51 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	OS2 routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 April 1989
+ * Last Edited:	30 August 2006
+ */
+
+/* TCP input buffer -- must be large enough to prevent overflow */
+
+#define BUFLEN 8192
+
+
+/* TCP I/O stream (must be before osdep.h is included) */
+
+#define TCPSTREAM struct tcp_stream
+TCPSTREAM {
+  char *host;			/* host name */
+  unsigned long port;		/* port number */
+  char *localhost;		/* local host name */
+  int tcps;			/* tcp socket */
+  long ictr;			/* input counter */
+  char *iptr;			/* input pointer */
+  char ibuf[BUFLEN];		/* input buffer */
+};
+
+
+/* Local function prototypes */
+
+long lookuphost (char **host,struct sockaddr_in *sin);
+long tcp_abort (TCPSTREAM *stream);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/os2/tenexnt.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1310 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Tenex mail routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	22 May 1990
+ * Last Edited:	18 June 2007
+ */
+
+
+/*				FILE TIME SEMANTICS
+ *
+ * The atime is the last read time of the file.
+ * The mtime is the last flags update time of the file.
+ * The ctime is the last write time of the file.
+ *
+ *				TEXT SIZE SEMANTICS
+ *
+ * Most of the text sizes are in internal (LF-only) form, except for the
+ * msg.text size.  Beware.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "mail.h"
+#include "osdep.h"
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/utime.h>
+#include "misc.h"
+#include "dummy.h"
+
+/* TENEX I/O stream local data */
+	
+typedef struct tenex_local {
+  unsigned int shouldcheck: 1;	/* if ping should do a check instead */
+  unsigned int mustcheck: 1;	/* if ping must do a check instead */
+  int fd;			/* file descriptor for I/O */
+  off_t filesize;		/* file size parsed */
+  time_t filetime;		/* last file time */
+  time_t lastsnarf;		/* local snarf time */
+  unsigned char *buf;		/* temporary buffer */
+  unsigned long buflen;		/* current size of temporary buffer */
+  unsigned long uid;		/* current text uid */
+  SIZEDTEXT text;		/* current text */
+} TENEXLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((TENEXLOCAL *) stream->local)
+
+
+/* Function prototypes */
+
+DRIVER *tenex_valid (char *name);
+int tenex_isvalid (char *name,char *file);
+void *tenex_parameters (long function,void *value);
+void tenex_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void tenex_list (MAILSTREAM *stream,char *ref,char *pat);
+void tenex_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long tenex_create (MAILSTREAM *stream,char *mailbox);
+long tenex_delete (MAILSTREAM *stream,char *mailbox);
+long tenex_rename (MAILSTREAM *stream,char *old,char *newname);
+long tenex_status (MAILSTREAM *stream,char *mbx,long flags);
+MAILSTREAM *tenex_open (MAILSTREAM *stream);
+void tenex_close (MAILSTREAM *stream,long options);
+void tenex_fast (MAILSTREAM *stream,char *sequence,long flags);
+void tenex_flags (MAILSTREAM *stream,char *sequence,long flags);
+char *tenex_header (MAILSTREAM *stream,unsigned long msgno,
+		    unsigned long *length,long flags);
+long tenex_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+void tenex_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
+void tenex_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
+long tenex_ping (MAILSTREAM *stream);
+void tenex_check (MAILSTREAM *stream);
+void tenex_snarf (MAILSTREAM *stream);
+long tenex_expunge (MAILSTREAM *stream,char *sequence,long options);
+long tenex_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long tenex_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+unsigned long tenex_size (MAILSTREAM *stream,unsigned long m);
+long tenex_parse (MAILSTREAM *stream);
+MESSAGECACHE *tenex_elt (MAILSTREAM *stream,unsigned long msgno);
+void tenex_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt);
+void tenex_update_status (MAILSTREAM *stream,unsigned long msgno,
+			  long syncflag);
+unsigned long tenex_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			    unsigned long *size);
+
+
+/* Tenex mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER tenexdriver = {
+  "tenex",			/* driver name */
+  DR_LOCAL|DR_MAIL,		/* driver flags */
+  (DRIVER *) NIL,		/* next driver */
+  tenex_valid,			/* mailbox is valid for us */
+  tenex_parameters,		/* manipulate parameters */
+  tenex_scan,			/* scan mailboxes */
+  tenex_list,			/* list mailboxes */
+  tenex_lsub,			/* list subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  tenex_create,			/* create mailbox */
+  tenex_delete,			/* delete mailbox */
+  tenex_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  tenex_open,			/* open mailbox */
+  tenex_close,			/* close mailbox */
+  tenex_flags,			/* fetch message "fast" attributes */
+  tenex_flags,			/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  tenex_header,			/* fetch message header */
+  tenex_text,			/* fetch message body */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  tenex_flag,			/* modify flags */
+  tenex_flagmsg,		/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  tenex_ping,			/* ping mailbox to see if still alive */
+  tenex_check,			/* check for new messages */
+  tenex_expunge,		/* expunge deleted messages */
+  tenex_copy,			/* copy messages to another mailbox */
+  tenex_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM tenexproto = {&tenexdriver};
+
+/* Tenex mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *tenex_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+  return tenex_isvalid (name,tmp) ? &tenexdriver : NIL;
+}
+
+
+/* Tenex mail test for valid mailbox
+ * Accepts: mailbox name
+ *	    buffer to return file name
+ * Returns: T if valid, NIL otherwise
+ */
+
+int tenex_isvalid (char *name,char *file)
+{
+  int fd;
+  int ret = NIL;
+  char *s,tmp[MAILTMPLEN];
+  struct stat sbuf;
+  struct utimbuf times;
+  errno = EINVAL;		/* assume invalid argument */
+				/* if file, get its status */
+  if ((s = dummy_file (file,name)) && !stat (s,&sbuf) &&
+      ((sbuf.st_mode & S_IFMT) == S_IFREG)) {
+    if (!sbuf.st_size)errno = 0;/* empty file */
+    else if ((fd = open (file,O_BINARY|O_RDONLY,NIL)) >= 0) {
+      memset (tmp,'\0',MAILTMPLEN);
+      if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\012')) &&
+	  (s[-1] != '\015')) {	/* valid format? */
+	*s = '\0';		/* tie off header */
+				/* must begin with dd-mmm-yy" */
+	ret = (((tmp[2] == '-' && tmp[6] == '-') ||
+		(tmp[1] == '-' && tmp[5] == '-')) &&
+	       (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL;
+      }
+      else errno = -1;		/* bogus format */
+      close (fd);		/* close the file */
+				/* \Marked status? */
+      if (sbuf.st_ctime > sbuf.st_atime) {
+				/* preserve atime and mtime */
+	times.actime = sbuf.st_atime;
+	times.modtime = sbuf.st_mtime;
+	utime (file,&times);	/* set the times */
+      }
+    }
+  }
+				/* in case INBOX but not tenex format */
+  else if ((errno == ENOENT) && !compare_cstring (name,"INBOX")) errno = -1;
+  return ret;			/* return what we should */
+}
+
+
+/* Tenex manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *tenex_parameters (long function,void *value)
+{
+  return NIL;
+}
+
+/* Tenex mail scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void tenex_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* Tenex mail list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void tenex_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_list (NIL,ref,pat);
+}
+
+
+/* Tenex mail list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void tenex_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_lsub (NIL,ref,pat);
+}
+
+/* Tenex mail create mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long tenex_create (MAILSTREAM *stream,char *mailbox)
+{
+  char *s,mbx[MAILTMPLEN];
+  if (s = dummy_file (mbx,mailbox)) return dummy_create (stream,s);
+  sprintf (mbx,"Can't create %.80s: invalid name",mailbox);
+  mm_log (mbx,ERROR);
+  return NIL;
+}
+
+
+/* Tenex mail delete mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long tenex_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return tenex_rename (stream,mailbox,NIL);
+}
+
+/* Tenex mail rename mailbox
+ * Accepts: MAIL stream
+ *	    old mailbox name
+ *	    new mailbox name (or NIL for delete)
+ * Returns: T on success, NIL on failure
+ */
+
+long tenex_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  long ret = LONGT;
+  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  int fd,ld;
+  struct stat sbuf;
+  if (!dummy_file (file,old) ||
+      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
+		   ((s = strrchr (tmp,'\\')) && !s[1])))) {
+    sprintf (tmp,newname ?
+	     "Can't rename mailbox %.80s to %.80s: invalid name" :
+	     "Can't delete mailbox %.80s: invalid name",
+	     old,newname);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+  else if ((fd = open (file,O_BINARY|O_RDWR,NIL)) < 0) {
+    sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* get exclusive parse/append permission */
+  if ((ld = lockname (lock,file,LOCK_EX)) < 0) {
+    mm_log ("Unable to lock rename mailbox",ERROR);
+    return NIL;
+  }
+				/* lock out other users */
+  if (flock (fd,LOCK_EX|LOCK_NB)) {
+    close (fd);			/* couldn't lock, give up on it then */
+    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
+    mm_log (tmp,ERROR);
+    unlockfd (ld,lock);		/* release exclusive parse/append permission */
+    return NIL;
+  }
+
+  if (newname) {		/* want rename? */
+				/* found superior to destination name? */
+    if ((s = strrchr (tmp,'\\')) && (s != tmp) &&
+	((tmp[1] != ':') || (s != tmp + 2))) {
+      c = s[1];			/* remember character after delimiter */
+      *s = s[1] = '\0';		/* tie off name at delimiter */
+				/* name doesn't exist, create it */
+      if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) {
+	*s = '\\';		/* restore delimiter */
+	if (!dummy_create (stream,tmp)) ret = NIL;
+      }
+      else *s = '\\';		/* restore delimiter */
+      s[1] = c;			/* restore character after delimiter */
+    }
+    flock (fd,LOCK_UN);		/* release lock on the file */
+    close (fd);			/* pacify NTFS */
+				/* rename the file */
+    if (ret && rename (file,tmp)) {
+      sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
+	       strerror (errno));
+      mm_log (tmp,ERROR);
+      ret = NIL;		/* set failure */
+    }
+  }
+  else {
+    flock (fd,LOCK_UN);		/* release lock on the file */
+    close (fd);			/* pacify NTFS */
+    if (unlink (file)) {
+      sprintf (tmp,"Can't delete mailbox %.80s: %.80s",old,strerror (errno));
+      mm_log (tmp,ERROR);
+      ret = NIL;		/* set failure */
+    }
+  }
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+  return ret;			/* return success */
+}
+
+/* Tenex mail open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *tenex_open (MAILSTREAM *stream)
+{
+  int fd,ld;
+  char tmp[MAILTMPLEN];
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return &tenexproto;
+  if (stream->local) fatal ("tenex recycle stream");
+				/* canonicalize the mailbox name */
+  if (!dummy_file (tmp,stream->mailbox)) {
+    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
+    mm_log (tmp,ERROR);
+  }
+  if (stream->rdonly ||
+      (fd = open (tmp,O_BINARY|O_RDWR,NIL)) < 0) {
+    if ((fd = open (tmp,O_BINARY|O_RDONLY,NIL)) < 0) {
+      sprintf (tmp,"Can't open mailbox: %.80s",strerror (errno));
+      mm_log (tmp,ERROR);
+      return NIL;
+    }
+    else if (!stream->rdonly) {	/* got it, but readonly */
+      mm_log ("Can't get write access to mailbox, access is readonly",WARN);
+      stream->rdonly = T;
+    }
+  }
+  stream->local = fs_get (sizeof (TENEXLOCAL));
+  LOCAL->fd = fd;		/* bind the file */
+  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
+  LOCAL->buflen = CHUNKSIZE - 1;
+  LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE);
+  LOCAL->text.size = CHUNKSIZE - 1;
+				/* note if an INBOX or not */
+  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
+  fs_give ((void **) &stream->mailbox);
+  stream->mailbox = cpystr (tmp);
+				/* get shared parse permission */
+  if ((ld = lockname (tmp,stream->mailbox,LOCK_SH)) < 0) {
+    mm_log ("Unable to lock open mailbox",ERROR);
+    return NIL;
+  }
+  flock (LOCAL->fd,LOCK_SH);	/* lock the file */
+  unlockfd (ld,tmp);		/* release shared parse permission */
+  LOCAL->filesize = 0;		/* initialize parsed file size */
+  LOCAL->filetime = 0;		/* time not set up yet */
+  LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
+  stream->sequence++;		/* bump sequence number */
+  stream->uid_validity = (unsigned long) time (0);
+				/* parse mailbox */
+  stream->nmsgs = stream->recent = 0;
+  if (tenex_ping (stream) && !stream->nmsgs)
+    mm_log ("Mailbox is empty",(long) NIL);
+  if (!LOCAL) return NIL;	/* failure if stream died */
+  stream->perm_seen = stream->perm_deleted =
+    stream->perm_flagged = stream->perm_answered = stream->perm_draft =
+      stream->rdonly ? NIL : T;
+  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
+  return stream;		/* return stream to caller */
+}
+
+/* Tenex mail close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void tenex_close (MAILSTREAM *stream,long options)
+{
+  if (stream && LOCAL) {	/* only if a file is open */
+    int silent = stream->silent;
+    stream->silent = T;		/* note this stream is dying */
+    if (options & CL_EXPUNGE) tenex_expunge (stream,NIL,NIL);
+    stream->silent = silent;	/* restore previous status */
+    flock (LOCAL->fd,LOCK_UN);	/* unlock local file */
+    close (LOCAL->fd);		/* close the local file */
+				/* free local text buffer */
+    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+    if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+/* Tenex mail fetch flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ * Sniffs at file to get flags
+ */
+
+void tenex_flags (MAILSTREAM *stream,char *sequence,long flags)
+{
+  STRING bs;
+  MESSAGECACHE *elt;
+  unsigned long i;
+  if (stream && LOCAL &&
+      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
+       mail_sequence (stream,sequence)))
+    for (i = 1; i <= stream->nmsgs; i++)
+      if ((elt = mail_elt (stream,i))->sequence) {
+	if (!elt->rfc822_size) { /* have header size yet? */
+	  lseek (LOCAL->fd,elt->private.special.offset +
+		 elt->private.special.text.size,L_SET);
+				/* resize bigbuf if necessary */
+	  if (LOCAL->buflen < elt->private.msg.full.text.size) {
+	    fs_give ((void **) &LOCAL->buf);
+	    LOCAL->buflen = elt->private.msg.full.text.size;
+	    LOCAL->buf = (char *) fs_get (LOCAL->buflen + 1);
+	  }
+				/* tie off string */
+	  LOCAL->buf[elt->private.msg.full.text.size] = '\0';
+				/* read in the message */
+	  read (LOCAL->fd,LOCAL->buf,elt->private.msg.full.text.size);
+	  INIT (&bs,mail_string,(void *) LOCAL->buf,
+		elt->private.msg.full.text.size);
+				/* calculate its CRLF size */
+	  elt->rfc822_size = unix_crlflen (&bs);
+	}
+	tenex_elt (stream,i);	/* get current flags from file */
+      }
+}
+
+/* TENEX mail fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+char *tenex_header (MAILSTREAM *stream,unsigned long msgno,
+		    unsigned long *length,long flags)
+{
+  char *s;
+  unsigned long i;
+  *length = 0;			/* default to empty */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+				/* get to header position */
+  lseek (LOCAL->fd,tenex_hdrpos (stream,msgno,&i),L_SET);
+  if (flags & FT_INTERNAL) {
+    if (i > LOCAL->buflen) {	/* resize if not enough space */
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get (LOCAL->buflen = i + 1);
+    }
+				/* slurp the data */
+    read (LOCAL->fd,LOCAL->buf,*length = i);
+  }
+  else {
+    s = (char *) fs_get (i + 1);/* get readin buffer */
+    s[i] = '\0';		/* tie off string */
+    read (LOCAL->fd,s,i);	/* slurp the data */
+				/* make CRLF copy of string */
+    *length = unix_crlfcpy (&LOCAL->buf,&LOCAL->buflen,s,i);
+    fs_give ((void **) &s);	/* free readin buffer */
+  }
+  return LOCAL->buf;
+}
+
+/* TENEX mail fetch message text (body only)
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned stringstruct
+ *	    option flags
+ * Returns: T, always
+ */
+
+long tenex_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  char *s;
+  unsigned long i,j;
+  MESSAGECACHE *elt;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+				/* get message status */
+  elt = tenex_elt (stream,msgno);
+				/* if message not seen */
+  if (!(flags & FT_PEEK) && !elt->seen) {
+    elt->seen = T;		/* mark message as seen */
+				/* recalculate status */
+    tenex_update_status (stream,msgno,T);
+    mm_flags (stream,msgno);
+  }
+  if (flags & FT_INTERNAL) {	/* if internal representation wanted */
+				/* find header position */
+    i = tenex_hdrpos (stream,msgno,&j);
+    if (i > LOCAL->buflen) {	/* resize if not enough space */
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get (LOCAL->buflen = i + 1);
+    }
+				/* go to text position */
+    lseek (LOCAL->fd,i + j,L_SET);
+				/* slurp the data */
+    if (read (LOCAL->fd,LOCAL->buf,i) != (long) i) return NIL;
+				/* set up stringstruct for internal */
+    INIT (bs,mail_string,LOCAL->buf,i);
+  }
+  else {			/* normal form, previous text cached? */
+    if (elt->private.uid == LOCAL->uid)
+      i = elt->private.msg.text.text.size;
+    else {			/* not cached, cache it now */
+      LOCAL->uid = elt->private.uid;
+				/* find header position */
+      i = tenex_hdrpos (stream,msgno,&j);
+				/* go to text position */
+      lseek (LOCAL->fd,i + j,L_SET);
+      s = (char *) fs_get ((i = tenex_size (stream,msgno) - j) + 1);
+      s[i] = '\0';		/* tie off string */
+      read (LOCAL->fd,s,i);	/* slurp the data */
+				/* make CRLF copy of string */
+      i = elt->private.msg.text.text.size =
+	strcrlfcpy (&LOCAL->text.data,&LOCAL->text.size,s,i);
+      fs_give ((void **) &s);	/* free readin buffer */
+    }
+				/* set up stringstruct */
+    INIT (bs,mail_string,LOCAL->text.data,i);
+  }
+  return T;			/* success */
+}
+
+/* Tenex mail modify flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    flag(s)
+ *	    option flags
+ */
+
+void tenex_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
+{
+  struct utimbuf times;
+  struct stat sbuf;
+  if (!stream->rdonly) {	/* make sure the update takes */
+    fsync (LOCAL->fd);
+    fstat (LOCAL->fd,&sbuf);	/* get current write time */
+    times.modtime = LOCAL->filetime = sbuf.st_mtime;
+    times.actime = time (0);	/* make sure read comes after all that */
+    utime (stream->mailbox,&times);
+  }
+}
+
+
+/* Tenex mail per-message modify flags
+ * Accepts: MAIL stream
+ *	    message cache element
+ */
+
+void tenex_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  struct stat sbuf;
+				/* maybe need to do a checkpoint? */
+  if (LOCAL->filetime && !LOCAL->shouldcheck) {
+    fstat (LOCAL->fd,&sbuf);	/* get current write time */
+    if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
+    LOCAL->filetime = 0;	/* don't do this test for any other messages */
+  }
+				/* recalculate status */
+  tenex_update_status (stream,elt->msgno,NIL);
+}
+
+/* Tenex mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream still alive, NIL if not
+ */
+
+long tenex_ping (MAILSTREAM *stream)
+{
+  unsigned long i = 1;
+  long r = T;
+  int ld;
+  char lock[MAILTMPLEN];
+  struct stat sbuf;
+  if (stream && LOCAL) {	/* only if stream already open */
+    fstat (LOCAL->fd,&sbuf);	/* get current file poop */
+    if (LOCAL->filetime && !(LOCAL->mustcheck || LOCAL->shouldcheck) &&
+	(LOCAL->filetime < sbuf.st_mtime)) LOCAL->shouldcheck = T;
+				/* check for changed message status */
+    if (LOCAL->mustcheck || LOCAL->shouldcheck) {
+      LOCAL->filetime = sbuf.st_mtime;
+      if (LOCAL->shouldcheck)	/* babble when we do this unilaterally */
+	mm_notify (stream,"[CHECK] Checking for flag updates",NIL);
+      while (i <= stream->nmsgs) tenex_elt (stream,i++);
+      LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
+    }
+				/* get shared parse/append permission */
+    if ((sbuf.st_size != LOCAL->filesize) &&
+	((ld = lockname (lock,stream->mailbox,LOCK_SH)) >= 0)) {
+				/* parse resulting mailbox */
+      r = (tenex_parse (stream)) ? T : NIL;
+      unlockfd (ld,lock);	/* release shared parse/append permission */
+    }
+  }
+  return r;			/* return result of the parse */
+}
+
+
+/* Tenex mail check mailbox (reparses status too)
+ * Accepts: MAIL stream
+ */
+
+void tenex_check (MAILSTREAM *stream)
+{
+				/* mark that a check is desired */
+  if (LOCAL) LOCAL->mustcheck = T;
+  if (tenex_ping (stream)) mm_log ("Check completed",(long) NIL);
+}
+
+/* Tenex mail expunge mailbox
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long tenex_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  long ret;
+  struct utimbuf times;
+  struct stat sbuf;
+  off_t pos = 0;
+  int ld;
+  unsigned long i = 1;
+  unsigned long j,k,m,recent;
+  unsigned long n = 0;
+  unsigned long delta = 0;
+  char lock[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  if (!(ret = (sequence ? ((options & EX_UID) ?
+			   mail_uid_sequence (stream,sequence) :
+			   mail_sequence (stream,sequence)) : LONGT) &&
+	tenex_ping (stream)));	/* parse sequence if given, ping stream */
+  else if (stream->rdonly) mm_log ("Expunge ignored on readonly mailbox",WARN);
+  else {
+    if (LOCAL->filetime && !LOCAL->shouldcheck) {
+      fstat (LOCAL->fd,&sbuf);	/* get current write time */
+      if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
+    }
+				/* get exclusive access */
+    if ((ld = lockname (lock,stream->mailbox,LOCK_EX)) < 0)
+      mm_log ("Unable to lock expunge mailbox",ERROR);
+				/* make sure see any newly-arrived messages */
+    else if (!tenex_parse (stream));
+				/* get exclusive access */
+    else if (flock (LOCAL->fd,LOCK_EX|LOCK_NB)) {
+      flock (LOCAL->fd,LOCK_SH);/* recover previous lock */
+      mm_log ("Can't expunge because mailbox is in use by another process",
+	      ERROR);
+      unlockfd (ld,lock);	/* release exclusive parse/append permission */
+    }
+
+    else {
+      mm_critical (stream);	/* go critical */
+      recent = stream->recent;	/* get recent now that pinged and locked */
+				/* for each message */
+      while (i <= stream->nmsgs) {
+				/* get cache element */
+	elt = tenex_elt (stream,i);
+				/* number of bytes to smash or preserve */
+	k = elt->private.special.text.size + tenex_size (stream,i);
+				/* if need to expunge this message */
+	if (elt->deleted && (sequence ? elt->sequence : T)) {
+				/* if recent, note one less recent message */
+	  if (elt->recent) --recent;
+	  delta += k;		/* number of bytes to delete */
+				/* notify upper levels */
+	  mail_expunged (stream,i);
+	  n++;			/* count up one more expunged message */
+	}
+	else if (i++ && delta) {/* preserved message */
+				/* first byte to preserve */
+	  j = elt->private.special.offset;
+	  do {			/* read from source position */
+	    m = min (k,LOCAL->buflen);
+	    lseek (LOCAL->fd,j,L_SET);
+	    read (LOCAL->fd,LOCAL->buf,m);
+	    pos = j - delta;	/* write to destination position */
+	    while (T) {
+	      lseek (LOCAL->fd,pos,L_SET);
+	      if (write (LOCAL->fd,LOCAL->buf,m) > 0) break;
+	      mm_notify (stream,strerror (errno),WARN);
+	      mm_diskerror (stream,errno,T);
+	    }
+	    pos += m;		/* new position */
+	    j += m;		/* next chunk, perhaps */
+	  } while (k -= m);	/* until done */
+				/* note the new address of this text */
+	  elt->private.special.offset -= delta;
+	}
+				/* preserved but no deleted messages */
+	else pos = elt->private.special.offset + k;
+      }
+
+      if (n) {			/* truncate file after last message */
+	if (pos != (LOCAL->filesize -= delta)) {
+	  sprintf (LOCAL->buf,
+		   "Calculated size mismatch %lu != %lu, delta = %lu",
+		   (unsigned long) pos,(unsigned long) LOCAL->filesize,delta);
+	  mm_log (LOCAL->buf,WARN);
+	  LOCAL->filesize = pos;/* fix it then */
+	}
+	ftruncate (LOCAL->fd,LOCAL->filesize);
+	sprintf (LOCAL->buf,"Expunged %lu messages",n);
+				/* output the news */
+	mm_log (LOCAL->buf,(long) NIL);
+      }
+      else mm_log ("No messages deleted, so no update needed",(long) NIL);
+      fsync (LOCAL->fd);	/* force disk update */
+      fstat (LOCAL->fd,&sbuf);	/* get new write time */
+      times.modtime = LOCAL->filetime = sbuf.st_mtime;
+      times.actime = time (0);	/* reset atime to now */
+      utime (stream->mailbox,&times);
+      mm_nocritical (stream);	/* release critical */
+				/* notify upper level of new mailbox size */
+      mail_exists (stream,stream->nmsgs);
+      mail_recent (stream,recent);
+      flock (LOCAL->fd,LOCK_SH);/* allow sharers again */
+      unlockfd (ld,lock);	/* release exclusive parse/append permission */
+    }
+  }
+  return ret;
+}
+
+/* Tenex mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if success, NIL if failed
+ */
+
+long tenex_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  struct stat sbuf;
+  struct utimbuf times;
+  MESSAGECACHE *elt;
+  unsigned long i,j,k;
+  long ret = LONGT;
+  int fd,ld;
+  char file[MAILTMPLEN],lock[MAILTMPLEN];
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+				/* make sure valid mailbox */
+  if (!tenex_isvalid (mailbox,file)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
+    return NIL;
+  case 0:			/* merely empty file? */
+    break;
+  case EACCES:			/* file protected */
+    sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
+    MM_LOG (LOCAL->buf,ERROR);
+    return NIL;
+  case EINVAL:
+    if (pc) return (*pc) (stream,sequence,mailbox,options);
+    sprintf (LOCAL->buf,"Invalid Tenex-format mailbox name: %.80s",mailbox);
+    mm_log (LOCAL->buf,ERROR);
+    return NIL;
+  default:
+    if (pc) return (*pc) (stream,sequence,mailbox,options);
+    sprintf (LOCAL->buf,"Not a Tenex-format mailbox: %.80s",mailbox);
+    mm_log (LOCAL->buf,ERROR);
+    return NIL;
+  }
+  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+	mail_sequence (stream,sequence))) return NIL;
+				/* got file? */  
+  if ((fd = open (file,O_BINARY|O_RDWR|O_CREAT,S_IREAD|S_IWRITE)) < 0) {
+    sprintf (LOCAL->buf,"Unable to open copy mailbox: %.80s",strerror (errno));
+    mm_log (LOCAL->buf,ERROR);
+    return NIL;
+  }
+  mm_critical (stream);		/* go critical */
+				/* get exclusive parse/append permission */
+  if (flock (fd,LOCK_SH) || ((ld = lockname (lock,file,LOCK_EX)) < 0)) {
+    mm_log ("Unable to lock copy mailbox",ERROR);
+    mm_nocritical (stream);
+    return NIL;
+  }
+  fstat (fd,&sbuf);		/* get current file size */
+  lseek (fd,sbuf.st_size,L_SET);/* move to end of file */
+
+				/* for each requested message */
+  for (i = 1; ret && (i <= stream->nmsgs); i++) 
+    if ((elt = mail_elt (stream,i))->sequence) {
+      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
+				/* number of bytes to copy */
+      k = elt->private.special.text.size + tenex_size (stream,i);
+      do {			/* read from source position */
+	j = min (k,LOCAL->buflen);
+	read (LOCAL->fd,LOCAL->buf,j);
+	if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
+      } while (ret && (k -= j));/* until done */
+    }
+				/* delete all requested messages */
+  if (ret && (options & CP_MOVE)) {
+    sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno));
+    mm_log (LOCAL->buf,ERROR);
+    ftruncate (fd,sbuf.st_size);
+  }
+				/* set atime to now-1 if successful copy */
+  if (ret) times.actime = time (0) - 1;
+				/* else preserved \Marked status */
+  else times.actime = (sbuf.st_ctime > sbuf.st_atime) ?
+	 sbuf.st_atime : time (0);
+  times.modtime = sbuf.st_mtime;/* preserve mtime */
+  utime (file,&times);		/* set the times */
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+  close (fd);			/* close the file */
+  mm_nocritical (stream);	/* release critical */
+				/* delete all requested messages */
+  if (ret && (options & CP_MOVE)) {
+    for (i = 1; i <= stream->nmsgs; i++)
+      if ((elt = tenex_elt (stream,i))->sequence) {
+	elt->deleted = T;	/* mark message deleted */
+				/* recalculate status */
+	tenex_update_status (stream,i,NIL);
+      }
+    if (!stream->rdonly) {	/* make sure the update takes */
+      fsync (LOCAL->fd);
+      fstat (LOCAL->fd,&sbuf);	/* get current write time */
+      times.modtime = LOCAL->filetime = sbuf.st_mtime;
+      times.actime = time (0);	/* make sure atime remains greater */
+      utime (stream->mailbox,&times);
+    }
+  }
+  if (ret && mail_parameters (NIL,GET_COPYUID,NIL))
+    mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN);
+  return ret;
+}
+
+/* Tenex mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long tenex_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct stat sbuf;
+  int fd,ld,c;
+  char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  struct utimbuf times;
+  FILE *df;
+  MESSAGECACHE elt;
+  long f;
+  unsigned long i,j,uf,size;
+  STRING *message;
+  long ret = LONGT;
+				/* default stream to prototype */
+  if (!stream) stream = &tenexproto;
+				/* make sure valid mailbox */
+  if (!tenex_isvalid (mailbox,file)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    if (!compare_cstring (mailbox,"INBOX")) tenex_create (NIL,"INBOX");
+    else {
+      mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+      return NIL;
+    }
+				/* falls through */
+  case 0:			/* merely empty file? */
+    break;
+  case EACCES:			/* file protected */
+    sprintf (tmp,"Can't access destination: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  case EINVAL:
+    sprintf (tmp,"Invalid TENEX-format mailbox name: %.80s",mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;
+  default:
+    sprintf (tmp,"Not a TENEX-format mailbox: %.80s",mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* get first message */
+  if (!(*af) (stream,data,&flags,&date,&message)) return NIL;
+
+				/* open destination mailbox */
+  if (((fd = open (file,O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IREAD|S_IWRITE))
+       < 0) || !(df = fdopen (fd,"ab"))) {
+    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* get parse/append permission */
+  if (flock (fd,LOCK_SH) || ((ld = lockname (lock,file,LOCK_EX)) < 0)) {
+    mm_log ("Unable to lock append mailbox",ERROR);
+    close (fd);
+    return NIL;
+  }
+  mm_critical (stream);		/* go critical */
+  fstat (fd,&sbuf);		/* get current file size */
+  errno = 0;
+  do {				/* parse flags */
+    if (!SIZE (message)) {	/* guard against zero-length */
+      mm_log ("Append of zero-length message",ERROR);
+      ret = NIL;
+      break;
+    }
+    f = mail_parse_flags (stream,flags,&i);
+				/* reverse bits (dontcha wish we had CIRC?) */
+    for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i)));
+    if (date) {			/* parse date if given */
+      if (!mail_parse_date (&elt,date)) {
+	sprintf (tmp,"Bad date in append: %.80s",date);
+	mm_log (tmp,ERROR);
+	ret = NIL;		/* mark failure */
+	break;
+      }
+      mail_date (tmp,&elt);	/* write preseved date */
+    }
+    else internal_date (tmp);	/* get current date in IMAP format */
+    i = GETPOS (message);	/* remember current position */
+    for (j = SIZE (message), size = 0; j; --j)
+      if (SNX (message) != '\015') ++size;
+    SETPOS (message,i);		/* restore position */
+				/* write header */
+    if (fprintf (df,"%s,%lu;%010lo%02lo\n",tmp,size,uf,(unsigned long) f) < 0)
+      ret = NIL;
+    else {			/* write message */
+      while (size) if ((c = 0xff & SNX (message)) != '\015') {
+	if (putc (c,df) != EOF) --size;
+	else break;
+      }
+				/* get next message */
+      if (size || !(*af) (stream,data,&flags,&date,&message)) ret = NIL;
+    }
+  } while (ret && message);
+				/* if error... */
+  if (!ret || (fflush (df) == EOF)) {
+    ftruncate (fd,sbuf.st_size);/* revert file */
+    close (fd);			/* make sure fclose() doesn't corrupt us */
+    if (errno) {
+      sprintf (tmp,"Message append failed: %s",strerror (errno));
+      mm_log (tmp,ERROR);
+    }
+    ret = NIL;
+  }
+  if (ret) times.actime = time (0) - 1;
+				/* else preserved \Marked status */
+  else times.actime = (sbuf.st_ctime > sbuf.st_atime) ?
+	 sbuf.st_atime : time (0);
+  times.modtime = sbuf.st_mtime;/* preserve mtime */
+  utime (file,&times);		/* set the times */
+  fclose (df);			/* close the file */
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+  mm_nocritical (stream);	/* release critical */
+  if (ret && mail_parameters (NIL,GET_APPENDUID,NIL))
+    mm_log ("Can not return meaningful APPENDUID with this mailbox format",
+	    WARN);
+  return ret;
+}
+
+/* Internal routines */
+
+
+/* Tenex mail return internal message size in bytes
+ * Accepts: MAIL stream
+ *	    message #
+ * Returns: internal size of message
+ */
+
+unsigned long tenex_size (MAILSTREAM *stream,unsigned long m)
+{
+  MESSAGECACHE *elt = mail_elt (stream,m);
+  return ((m < stream->nmsgs) ? mail_elt (stream,m+1)->private.special.offset :
+	  LOCAL->filesize) -
+	    (elt->private.special.offset + elt->private.special.text.size);
+}
+
+/* Tenex mail parse mailbox
+ * Accepts: MAIL stream
+ * Returns: T if parse OK
+ *	    NIL if failure, stream aborted
+ */
+
+long tenex_parse (MAILSTREAM *stream)
+{
+  struct stat sbuf;
+  MESSAGECACHE *elt = NIL;
+  unsigned char c,*s,*t,*x;
+  char tmp[MAILTMPLEN];
+  unsigned long i,j;
+  long curpos = LOCAL->filesize;
+  long nmsgs = stream->nmsgs;
+  long recent = stream->recent;
+  short added = NIL;
+  short silent = stream->silent;
+  fstat (LOCAL->fd,&sbuf);	/* get status */
+  if (sbuf.st_size < curpos) {	/* sanity check */
+    sprintf (tmp,"Mailbox shrank from %ld to %ld!",curpos,sbuf.st_size);
+    mm_log (tmp,ERROR);
+    tenex_close (stream,NIL);
+    return NIL;
+  }
+  stream->silent = T;		/* don't pass up mm_exists() events yet */
+  while (sbuf.st_size - curpos){/* while there is stuff to parse */
+				/* get to that position in the file */
+    lseek (LOCAL->fd,curpos,L_SET);
+    if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) {
+      sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s",
+	       (unsigned long) curpos,(unsigned long) sbuf.st_size,
+	       i ? strerror (errno) : "no data read");
+      mm_log (tmp,ERROR);
+      tenex_close (stream,NIL);
+      return NIL;
+    }
+    LOCAL->buf[i] = '\0';	/* tie off buffer just in case */
+    if (!(s = strchr (LOCAL->buf,'\012'))) {
+      sprintf (tmp,"Unable to find newline at %lu in %lu bytes, text: %s",
+	       (unsigned long) curpos,i,(char *) LOCAL->buf);
+      mm_log (tmp,ERROR);
+      tenex_close (stream,NIL);
+      return NIL;
+    }
+    *s = '\0';			/* tie off header line */
+    i = (s + 1) - LOCAL->buf;	/* note start of text offset */
+    if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) {
+      sprintf (tmp,"Unable to parse internal header at %lu: %s",
+	       (unsigned long) curpos,(char *) LOCAL->buf);
+      mm_log (tmp,ERROR);
+      tenex_close (stream,NIL);
+      return NIL;
+    }
+    *s++ = '\0'; *t++ = '\0';	/* tie off fields */
+
+    added = T;			/* note that a new message was added */
+				/* swell the cache */
+    mail_exists (stream,++nmsgs);
+				/* instantiate an elt for this message */
+    (elt = mail_elt (stream,nmsgs))->valid = T;
+    elt->private.uid = ++stream->uid_last;
+				/* note file offset of header */
+    elt->private.special.offset = curpos;
+				/* in case error */
+    elt->private.special.text.size = 0;
+				/* header size not known yet */
+    elt->private.msg.header.text.size = 0;
+    x = s;			/* parse the header components */
+    if (mail_parse_date (elt,LOCAL->buf) &&
+	(elt->private.msg.full.text.size = strtoul (s,(char **) &s,10)) &&
+	(!(s && *s)) && isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) &&
+	isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) &&
+	isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) &&
+	isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12])
+      elt->private.special.text.size = i;
+    else {			/* oops */
+      sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s",
+	       curpos,(char *) LOCAL->buf,(char *) x,(char *) t);
+      mm_log (tmp,ERROR);
+      tenex_close (stream,NIL);
+      return NIL;
+    }
+				/* make sure didn't run off end of file */
+    if ((curpos += (elt->private.msg.full.text.size + i)) > sbuf.st_size) {
+      sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
+	       elt->private.special.offset,(unsigned long) curpos,
+	       (unsigned long) sbuf.st_size);
+      mm_log (tmp,ERROR);
+      tenex_close (stream,NIL);
+      return NIL;
+    }
+    c = t[10];			/* remember first system flags byte */
+    t[10] = '\0';		/* tie off flags */
+    j = strtoul (t,NIL,8);	/* get user flags value */
+    t[10] = c;			/* restore first system flags byte */
+				/* set up all valid user flags (reversed!) */
+    while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
+		  stream->user_flags[i]) elt->user_flags |= 1 << i;
+				/* calculate system flags */
+    if ((j = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T;
+    if (j & fDELETED) elt->deleted = T;
+    if (j & fFLAGGED) elt->flagged = T;
+    if (j & fANSWERED) elt->answered = T;
+    if (j & fDRAFT) elt->draft = T;
+    if (!(j & fOLD)) {		/* newly arrived message? */
+      elt->recent = T;
+      recent++;			/* count up a new recent message */
+				/* mark it as old */
+      tenex_update_status (stream,nmsgs,NIL);
+    }
+  }
+  fsync (LOCAL->fd);		/* make sure all the fOLD flags take */
+				/* update parsed file size and time */
+  LOCAL->filesize = sbuf.st_size;
+  fstat (LOCAL->fd,&sbuf);	/* get status again to ensure time is right */
+  LOCAL->filetime = sbuf.st_mtime;
+  if (added && !stream->rdonly){/* make sure atime updated */
+    struct utimbuf times;
+    times.actime = time (0);
+    times.modtime = LOCAL->filetime;
+    utime (stream->mailbox,&times);
+  }
+  stream->silent = silent;	/* can pass up events now */
+  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
+  mail_recent (stream,recent);	/* and of change in recent messages */
+  return LONGT;			/* return the winnage */
+}
+
+/* Tenex get cache element with status updating from file
+ * Accepts: MAIL stream
+ *	    message number
+ * Returns: cache element
+ */
+
+MESSAGECACHE *tenex_elt (MAILSTREAM *stream,unsigned long msgno)
+{
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  struct {			/* old flags */
+    unsigned int seen : 1;
+    unsigned int deleted : 1;
+    unsigned int flagged : 1;
+    unsigned int answered : 1;
+    unsigned int draft : 1;
+    unsigned long user_flags;
+  } old;
+  old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged;
+  old.answered = elt->answered; old.draft = elt->draft;
+  old.user_flags = elt->user_flags;
+  tenex_read_flags (stream,elt);
+  if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
+      (old.flagged != elt->flagged) || (old.answered != elt->answered) ||
+      (old.draft != elt->draft) || (old.user_flags != elt->user_flags))
+    mm_flags (stream,msgno);	/* let top level know */
+  return elt;
+}
+
+
+/* Tenex read flags from file
+ * Accepts: MAIL stream
+ * Returns: cache element
+ */
+
+void tenex_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  unsigned long i,j;
+				/* noop if readonly and have valid flags */
+  if (stream->rdonly && elt->valid) return;
+				/* set the seek pointer */
+  lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	 elt->private.special.text.size - 13,L_SET);
+				/* read the new flags */
+  if (read (LOCAL->fd,LOCAL->buf,12) < 0) {
+    sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno));
+    fatal (LOCAL->buf);
+  }
+				/* calculate system flags */
+  i = (((LOCAL->buf[10]-'0') * 8) + LOCAL->buf[11]-'0');
+  elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL;
+  elt->flagged = i & fFLAGGED ? T : NIL;
+  elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL;
+  LOCAL->buf[10] = '\0';	/* tie off flags */
+  j = strtoul(LOCAL->buf,NIL,8);/* get user flags value */
+				/* set up all valid user flags (reversed!) */
+  while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
+		stream->user_flags[i]) elt->user_flags |= 1 << i;
+  elt->valid = T;		/* have valid flags now */
+}
+
+/* Tenex update status string
+ * Accepts: MAIL stream
+ *	    message number
+ *	    flag saying whether or not to sync
+ */
+
+void tenex_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag)
+{
+  struct utimbuf times;
+  struct stat sbuf;
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  unsigned long j,k = 0;
+				/* readonly */
+  if (stream->rdonly || !elt->valid) tenex_read_flags (stream,elt);
+  else {			/* readwrite */
+    j = elt->user_flags;	/* get user flags */
+				/* reverse bits (dontcha wish we had CIRC?) */
+    while (j) k |= 1 << (29 - find_rightmost_bit (&j));
+				/* print new flag string */
+    sprintf (LOCAL->buf,"%010lo%02o",k,(unsigned)
+	     (fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
+	      (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
+	      (fDRAFT * elt->draft)));
+    while (T) {			/* get to that place in the file */
+      lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	     elt->private.special.text.size - 13,L_SET);
+				/* write new flags */
+      if (write (LOCAL->fd,LOCAL->buf,12) > 0) break;
+      mm_notify (stream,strerror (errno),WARN);
+      mm_diskerror (stream,errno,T);
+    }
+    if (syncflag) {		/* sync if requested */
+      fsync (LOCAL->fd);
+      fstat (LOCAL->fd,&sbuf);	/* get new write time */
+      times.modtime = LOCAL->filetime = sbuf.st_mtime;
+      times.actime = time (0);	/* make sure read is later */
+      utime (stream->mailbox,&times);
+    }
+  }
+}
+
+/* Tenex locate header for a message
+ * Accepts: MAIL stream
+ *	    message number
+ *	    pointer to returned header size
+ * Returns: position of header in file
+ */
+
+unsigned long tenex_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			    unsigned long *size)
+{
+  unsigned long siz;
+  long i = 0;
+  char c = '\0';
+  char *s = NIL;
+  MESSAGECACHE *elt = tenex_elt (stream,msgno);
+  unsigned long ret = elt->private.special.offset +
+    elt->private.special.text.size;
+  unsigned long msiz = tenex_size (stream,msgno);
+				/* is header size known? */
+  if (!(*size = elt->private.msg.header.text.size)) {
+    lseek (LOCAL->fd,ret,L_SET);/* get to header position */
+				/* search message for LF LF */
+    for (siz = 0; siz < msiz; siz++) {
+      if (--i <= 0)		/* read another buffer as necessary */
+	read (LOCAL->fd,s = LOCAL->buf,i = min (msiz-siz,(long) MAILTMPLEN));
+				/* two newline sequence? */
+      if ((c == '\012') && (*s == '\012')) {
+				/* yes, note for later */
+	elt->private.msg.header.text.size = (*size = siz + 1);
+	return ret;		/* return to caller */
+      }
+      else c = *s++;		/* next character */
+    }
+				/* header consumes entire message */
+    elt->private.msg.header.text.size = *size = msiz;
+  }
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/os2/unixnt.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,2297 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX mail routines
+ *
+ * Author:	Mark Crispin
+ *		UW Technology
+ *		University of Washington
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	20 December 1989
+ * Last Edited:	27 March 2008
+ */
+
+
+/*				DEDICATION
+ *
+ *  This file is dedicated to my dog, Unix, also known as Yun-chan and
+ * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast.  Unix
+ * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after
+ * a two-month bout with cirrhosis of the liver.
+ *
+ *  He was a dear friend, and I miss him terribly.
+ *
+ *  Lift a leg, Yunie.  Luv ya forever!!!!
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "mail.h"
+#include "osdep.h"
+#include <time.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/utime.h>
+#include "unixnt.h"
+#include "pseudo.h"
+#include "fdstring.h"
+#include "misc.h"
+#include "dummy.h"
+
+/* UNIX I/O stream local data */
+
+typedef struct unix_local {
+  unsigned int dirty : 1;	/* disk copy needs updating */
+  unsigned int ddirty : 1;	/* double-dirty, ping becomes checkpoint */
+  unsigned int pseudo : 1;	/* uses a pseudo message */
+  unsigned int appending : 1;	/* don't mark new messages as old */
+  int fd;			/* mailbox file descriptor */
+  int ld;			/* lock file descriptor */
+  char *lname;			/* lock file name */
+  off_t filesize;		/* file size parsed */
+  time_t filetime;		/* last file time */
+  unsigned char *buf;		/* temporary buffer */
+  unsigned long buflen;		/* current size of temporary buffer */
+  unsigned long uid;		/* current text uid */
+  SIZEDTEXT text;		/* current text */
+  unsigned long textlen;	/* current text length */
+  char *line;			/* returned line */
+  char *linebuf;		/* line readin buffer */
+  unsigned long linebuflen;	/* current line readin buffer length */
+} UNIXLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((UNIXLOCAL *) stream->local)
+
+
+/* UNIX protected file structure */
+
+typedef struct unix_file {
+  MAILSTREAM *stream;		/* current stream */
+  off_t curpos;			/* current file position */
+  off_t protect;		/* protected position */
+  off_t filepos;		/* current last written file position */
+  char *buf;			/* overflow buffer */
+  size_t buflen;		/* current overflow buffer length */
+  char *bufpos;			/* current buffer position */
+} UNIXFILE;
+
+/* Function prototypes */
+
+DRIVER *unix_valid (char *name);
+void *unix_parameters (long function,void *value);
+void unix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void unix_list (MAILSTREAM *stream,char *ref,char *pat);
+void unix_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long unix_create (MAILSTREAM *stream,char *mailbox);
+long unix_delete (MAILSTREAM *stream,char *mailbox);
+long unix_rename (MAILSTREAM *stream,char *old,char *newname);
+MAILSTREAM *unix_open (MAILSTREAM *stream);
+void unix_close (MAILSTREAM *stream,long options);
+char *unix_header (MAILSTREAM *stream,unsigned long msgno,
+		   unsigned long *length,long flags);
+long unix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+char *unix_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
+		      unsigned long *length,long flags);
+void unix_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
+long unix_ping (MAILSTREAM *stream);
+void unix_check (MAILSTREAM *stream);
+long unix_expunge (MAILSTREAM *stream,char *sequence,long options);
+long unix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long unix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+int unix_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
+		     STRING *msg);
+int unix_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set);
+
+void unix_abort (MAILSTREAM *stream);
+char *unix_file (char *dst,char *name);
+int unix_lock (char *file,int flags,int mode,char *lock,int op);
+void unix_unlock (int fd,MAILSTREAM *stream,char *lock);
+int unix_parse (MAILSTREAM *stream,char *lock,int op);
+char *unix_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size);
+unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr);
+unsigned long unix_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt,
+			    unsigned long uid,long flag);
+long unix_rewrite (MAILSTREAM *stream,unsigned long *nexp,char *lock,
+		   long flags);
+long unix_extend (MAILSTREAM *stream,unsigned long size);
+void unix_write (UNIXFILE *f,char *s,unsigned long i);
+void unix_phys_write (UNIXFILE *f,char *buf,size_t size);
+
+/* UNIX mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER unixdriver = {
+  "unix",			/* driver name */
+				/* driver flags */
+  DR_LOCAL|DR_MAIL|DR_NONEWMAILRONLY|DR_XPOINT,
+  (DRIVER *) NIL,		/* next driver */
+  unix_valid,			/* mailbox is valid for us */
+  unix_parameters,		/* manipulate parameters */
+  unix_scan,			/* scan mailboxes */
+  unix_list,			/* list mailboxes */
+  unix_lsub,			/* list subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  unix_create,			/* create mailbox */
+  unix_delete,			/* delete mailbox */
+  unix_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  unix_open,			/* open mailbox */
+  unix_close,			/* close mailbox */
+  NIL,				/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  unix_header,			/* fetch message header */
+  unix_text,			/* fetch message text */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  NIL,				/* modify flags */
+  unix_flagmsg,			/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  unix_ping,			/* ping mailbox to see if still alive */
+  unix_check,			/* check for new messages */
+  unix_expunge,			/* expunge deleted messages */
+  unix_copy,			/* copy messages to another mailbox */
+  unix_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM unixproto = {&unixdriver};
+
+				/* driver parameters */
+static long unix_fromwidget = T;
+
+/* UNIX mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *unix_valid (char *name)
+{
+  int fd;
+  DRIVER *ret = NIL;
+  int c,r;
+  char tmp[MAILTMPLEN],file[MAILTMPLEN],*s,*t;
+  struct stat sbuf;
+  struct utimbuf times;
+  errno = EINVAL;		/* assume invalid argument */
+				/* must be non-empty file */
+  if ((t = dummy_file (file,name)) && !stat (t,&sbuf) &&
+      ((sbuf.st_mode & S_IFMT) == S_IFREG)) {
+    if (!sbuf.st_size)errno = 0;/* empty file */
+    else if ((fd = open (file,O_BINARY|O_RDONLY,NIL)) >= 0) {
+      memset (tmp,'\0',MAILTMPLEN);
+      if (read (fd,tmp,MAILTMPLEN-1) <= 0) errno = -1;
+      else {			/* ignore leading whitespace */
+	for (s = tmp,c = '\n';
+	     (*s == '\r') || (*s == '\n') || (*s == ' ') || (*s == '\t');
+	     c = *s++);
+	if (c == '\n') {	/* at start of a line? */
+	  VALID (s,t,r,c);	/* yes, validate format */
+	  if (r) ret = &unixdriver;
+	  else errno = -1;	/* invalid format */
+	}
+      }
+      close (fd);		/* close the file */
+				/* \Marked status? */
+      if ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) {
+				/* yes, preserve atime and mtime */
+	times.actime = sbuf.st_atime;
+	times.modtime = sbuf.st_mtime;
+	utime (file,&times);	/* set the times */
+      }
+    }
+  }
+  return ret;			/* return what we should */
+}
+/* UNIX manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *unix_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case SET_FROMWIDGET:
+    unix_fromwidget = (long) value;
+  case GET_FROMWIDGET:
+    ret = (void *) unix_fromwidget;
+    break;
+  }
+  return ret;
+}
+
+/* UNIX mail scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void unix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* UNIX mail list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void unix_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_list (NIL,ref,pat);
+}
+
+
+/* UNIX mail list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void unix_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_lsub (NIL,ref,pat);
+}
+
+/* UNIX mail create mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long unix_create (MAILSTREAM *stream,char *mailbox)
+{
+  char *s,mbx[MAILTMPLEN],tmp[MAILTMPLEN];
+  long ret = NIL;
+  int fd;
+  time_t ti = time (0);
+  if (!(s = dummy_file (mbx,mailbox))) {
+    sprintf (tmp,"Can't create %.80s: invalid name",mailbox);
+    mm_log (tmp,ERROR);
+  }
+				/* create underlying file */
+  else if (dummy_create_path (stream,s,NIL)) {
+    if ((s = strrchr (s,'\\')) && !s[1]) ret = T;
+    if ((fd = open (mbx,O_WRONLY|O_BINARY,NIL)) < 0) {
+      sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno));
+      mm_log (tmp,ERROR);
+      unlink (mbx);		/* delete the file */
+    }
+    else {			/* initialize header */
+      memset (tmp,'\0',MAILTMPLEN);
+      sprintf (tmp,"From %s %s",pseudo_from,ctime (&ti));
+      if (s = strpbrk (tmp,"\r\n")) *s = '\0';
+      strcat (tmp,"\r\nDate: ");
+      rfc822_fixed_date (s = tmp + strlen (tmp));
+      sprintf (s += strlen (s),	/* write the pseudo-header */
+	       "\r\nFrom: %s <%s@%s>\r\nSubject: %s\r\nX-IMAP: %010lu 0000000000\r\nStatus: RO\r\n\r\n%s\r\n\r\n",
+	       pseudo_name,pseudo_from,mylocalhost (),pseudo_subject,
+	       (unsigned long) ti,pseudo_msg);
+      if (write (fd,tmp,strlen (tmp)) > 0) {
+	close (fd);		/* close file */
+	ret = T;
+      }
+      else {
+	sprintf (tmp,"Can't initialize mailbox node %.80s: %s",mbx,
+		 strerror (errno));
+	mm_log (tmp,ERROR);
+	close (fd);		/* close file before unlinking */
+	unlink (mbx);		/* delete the file */
+      }
+    }
+  }
+  return ret;
+}
+
+/* UNIX mail delete mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long unix_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return unix_rename (stream,mailbox,NIL);
+}
+
+
+/* UNIX mail rename mailbox
+ * Accepts: MAIL stream
+ *	    old mailbox name
+ *	    new mailbox name (or NIL for delete)
+ * Returns: T on success, NIL on failure
+ */
+
+long unix_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  long ret = NIL;
+  char c,*s = NIL;
+  char tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN],lockx[MAILTMPLEN];
+  int fd,ld;
+  struct stat sbuf;
+  mm_critical (stream);		/* get the c-client lock */
+  if (!dummy_file (file,old) ||
+      (newname && (!(s = dummy_file (tmp,newname)) ||
+		   ((s = strrchr (s,'\\')) && !s[1]))))
+    sprintf (tmp,newname ?
+	     "Can't rename mailbox %.80s to %.80s: invalid name" :
+	     "Can't delete mailbox %.80s: invalid name",
+	     old,newname);
+  else if ((ld = lockname (lock,file,NIL)) < 0)
+    sprintf (tmp,"Can't get lock for mailbox %.80s",old);
+
+  else {			/* lock out other c-clients */
+    if (flock (ld,LOCK_EX|LOCK_NB)) {
+      close (ld);		/* couldn't lock, give up on it then */
+      sprintf (tmp,"Mailbox %.80s is in use by another process",old);
+    }
+				/* lock out non c-client applications */
+    else if ((fd = unix_lock (file,O_BINARY|O_RDWR,S_IREAD|S_IWRITE,lockx,
+			      LOCK_EX)) < 0)
+      sprintf (tmp,"Can't lock mailbox %.80s: %s",old,strerror (errno));
+    else {
+      unix_unlock(fd,NIL,lockx);/* pacify evil NTFS */
+      if (newname) {		/* want rename? */
+				/* found superior to destination name? */
+	if ((s = strrchr (tmp,'\\')) && (s != tmp) &&
+	    ((tmp[1] != ':') || (s != tmp + 2))) {
+	  c = s[1];		/* remember character after delimiter */
+	  *s = s[1] = '\0';	/* tie off name at delimiter */
+				/* name doesn't exist, create it */
+	  if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) {
+	    *s = '\\';		/* restore delimiter */
+	    if (!dummy_create (stream,newname)) {
+	      flock (ld,LOCK_UN);
+	      close (ld);	/* close c-client lock */
+	      unlink (lock);	/* and delete it */
+	      mm_nocritical (stream);
+	      return NIL;	/* couldn't create superior */
+	    }
+	  }
+	  else *s = '\\';	/* restore delimiter */
+	  s[1] = c;		/* restore character after delimiter */
+	}
+	if (rename (file,tmp))
+	  sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
+		   strerror (errno));
+	else ret = T;		/* set success */
+      }
+      else if (unlink (file))	/* want delete */
+	sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
+      else ret = T;		/* set success */
+      flock (ld,LOCK_UN);	/* release c-client lock */
+      close (ld);		/* close c-client lock */
+      unlink (lock);		/* and delete it */
+    }
+  }
+  mm_nocritical (stream);	/* no longer critical */
+  if (!ret) mm_log (tmp,ERROR);	/* log error */
+  return ret;			/* return success or failure */
+}
+
+/* UNIX mail open
+ * Accepts: Stream to open
+ * Returns: Stream on success, NIL on failure
+ */
+
+MAILSTREAM *unix_open (MAILSTREAM *stream)
+{
+  int fd;
+  char tmp[MAILTMPLEN];
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return &unixproto;
+  if (stream->local) fatal ("unix recycle stream");
+  stream->local = memset (fs_get (sizeof (UNIXLOCAL)),0,sizeof (UNIXLOCAL));
+				/* note if an INBOX or not */
+  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
+				/* canonicalize the stream mailbox name */
+  if (!dummy_file (tmp,stream->mailbox)) {
+    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* flush old name */
+  fs_give ((void **) &stream->mailbox);
+				/* save canonical name */
+  stream->mailbox = cpystr (tmp);
+  LOCAL->fd = LOCAL->ld = -1;	/* no file or state locking yet */
+  LOCAL->buf = (char *) fs_get ((LOCAL->buflen = CHUNKSIZE) + 1);
+  LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE);
+  LOCAL->text.size = CHUNKSIZE - 1;
+  LOCAL->linebuf = (char *) fs_get (CHUNKSIZE);
+  LOCAL->linebuflen = CHUNKSIZE - 1;
+  stream->sequence++;		/* bump sequence number */
+  if (!stream->rdonly) {	/* make lock for read/write access */
+    if ((fd = lockname (tmp,stream->mailbox,NIL)) < 0)
+      mm_log ("Can't open mailbox lock, access is readonly",WARN);
+				/* can get the lock? */
+    else if (flock (fd,LOCK_EX|LOCK_NB)) {
+      if (!stream->silent)
+	mm_log ("Mailbox is open by another process, access is readonly",WARN);
+      close (fd);
+    }
+    else {			/* got the lock, nobody else can alter state */
+      LOCAL->ld = fd;		/* note lock's fd and name */
+      LOCAL->lname = cpystr (tmp);
+    }
+  }
+
+				/* parse mailbox */
+  stream->nmsgs = stream->recent = 0;
+				/* will we be able to get write access? */
+  if ((LOCAL->ld >= 0) && access (stream->mailbox,02) && (errno == EACCES)) {
+    mm_log ("Can't get write access to mailbox, access is readonly",WARN);
+    flock (LOCAL->ld,LOCK_UN);	/* release the lock */
+    close (LOCAL->ld);		/* close the lock file */
+    LOCAL->ld = -1;		/* no more lock fd */
+    unlink (LOCAL->lname);	/* delete it */
+  }
+				/* reset UID validity */
+  stream->uid_validity = stream->uid_last = 0;
+  if (stream->silent && !stream->rdonly && (LOCAL->ld < 0))
+    unix_abort (stream);	/* abort if can't get RW silent stream */
+				/* parse mailbox */
+  else if (unix_parse (stream,tmp,LOCK_SH)) {
+    unix_unlock (LOCAL->fd,stream,tmp);
+    mail_unlock (stream);
+    mm_nocritical (stream);	/* done with critical */
+  }
+  if (!LOCAL) return NIL;	/* failure if stream died */
+				/* make sure upper level knows readonly */
+  stream->rdonly = (LOCAL->ld < 0);
+				/* notify about empty mailbox */
+  if (!(stream->nmsgs || stream->silent)) mm_log ("Mailbox is empty",NIL);
+  if (!stream->rdonly) {	/* flags stick if readwrite */
+    stream->perm_seen = stream->perm_deleted =
+      stream->perm_flagged = stream->perm_answered = stream->perm_draft = T;
+				/* have permanent keywords */
+    stream->perm_user_flags = 0xffffffff;
+				/* and maybe can create them too */
+    stream->kwd_create = stream->user_flags[NUSERFLAGS-1] ? NIL : T;
+  }
+  return stream;		/* return stream alive to caller */
+}
+
+
+/* UNIX mail close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void unix_close (MAILSTREAM *stream,long options)
+{
+  int silent = stream->silent;
+  stream->silent = T;		/* go silent */
+				/* expunge if requested */
+  if (options & CL_EXPUNGE) unix_expunge (stream,NIL,NIL);
+				/* else dump final checkpoint */
+  else if (LOCAL->dirty) unix_check (stream);
+  stream->silent = silent;	/* restore old silence state */
+  unix_abort (stream);		/* now punt the file and local data */
+}
+
+/* UNIX mail fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+				/* lines to filter from header */
+static STRINGLIST *unix_hlines = NIL;
+
+char *unix_header (MAILSTREAM *stream,unsigned long msgno,
+		   unsigned long *length,long flags)
+{
+  MESSAGECACHE *elt;
+  unsigned char *s;
+  *length = 0;			/* default to empty */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+  elt = mail_elt (stream,msgno);/* get cache */
+  if (!unix_hlines) {		/* once only code */
+    STRINGLIST *lines = unix_hlines = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "Status"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-Status"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-Keywords"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-UID"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-IMAP"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-IMAPbase"));
+  }
+				/* go to header position */
+  lseek (LOCAL->fd,elt->private.special.offset +
+	 elt->private.msg.header.offset,L_SET);
+
+  if (flags & FT_INTERNAL) {	/* initial data OK? */
+    if (elt->private.msg.header.text.size > LOCAL->buflen) {
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
+				     elt->private.msg.header.text.size) + 1);
+    }
+				/* read message */
+    read (LOCAL->fd,LOCAL->buf,elt->private.msg.header.text.size);
+				/* got text, tie off string */
+    LOCAL->buf[*length = elt->private.msg.header.text.size] = '\0';
+  }
+  else {			/* need to make a CRLF version */
+    read (LOCAL->fd,s = (char *) fs_get (elt->private.msg.header.text.size+1),
+	  elt->private.msg.header.text.size);
+				/* tie off string, and convert to CRLF */
+    s[elt->private.msg.header.text.size] = '\0';
+    *length = unix_crlfcpy (&LOCAL->buf,&LOCAL->buflen,s,
+			    elt->private.msg.header.text.size);
+    fs_give ((void **) &s);	/* free readin buffer */
+  }
+  *length = mail_filter (LOCAL->buf,*length,unix_hlines,FT_NOT);
+  return LOCAL->buf;		/* return processed copy */
+}
+
+/* UNIX mail fetch message text
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned stringstruct
+ *	    option flags
+ * Returns: T on success, NIL if failure
+ */
+
+long unix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  char *s;
+  unsigned long i;
+  MESSAGECACHE *elt;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+  elt = mail_elt (stream,msgno);/* get cache element */
+				/* if message not seen */
+  if (!(flags & FT_PEEK) && !elt->seen) {
+				/* mark message seen and dirty */
+    elt->seen = elt->private.dirty = LOCAL->dirty = T;
+    mm_flags (stream,msgno);
+  }
+  s = unix_text_work (stream,elt,&i,flags);
+  INIT (bs,mail_string,s,i);	/* set up stringstruct */
+  return T;			/* success */
+}
+
+/* UNIX mail fetch message text worker routine
+ * Accepts: MAIL stream
+ *	    message cache element
+ *	    pointer to returned header text length
+ *	    option flags
+ */
+
+char *unix_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
+		      unsigned long *length,long flags)
+{
+  FDDATA d;
+  STRING bs;
+  unsigned char c,*s,tmp[CHUNKSIZE];
+				/* go to text position */
+  lseek (LOCAL->fd,elt->private.special.offset +
+	 elt->private.msg.text.offset,L_SET);
+  if (flags & FT_INTERNAL) {	/* initial data OK? */
+    if (elt->private.msg.text.text.size > LOCAL->buflen) {
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
+				     elt->private.msg.text.text.size) + 1);
+    }
+				/* read message */
+    read (LOCAL->fd,LOCAL->buf,elt->private.msg.text.text.size);
+				/* got text, tie off string */
+    LOCAL->buf[*length = elt->private.msg.text.text.size] = '\0';
+    return LOCAL->buf;
+  }
+				/* have it cached already? */
+  if (elt->private.uid != LOCAL->uid) {
+				/* not cached, cache it now */
+    LOCAL->uid = elt->private.uid;
+				/* is buffer big enough? */
+    if (elt->rfc822_size > LOCAL->text.size) {
+      /* excessively conservative, but the right thing is too hard to do */
+      fs_give ((void **) &LOCAL->text.data);
+      LOCAL->text.data = (unsigned char *)
+	fs_get ((LOCAL->text.size = elt->rfc822_size) + 1);
+    }
+    d.fd = LOCAL->fd;		/* yes, set up file descriptor */
+    d.pos = elt->private.special.offset + elt->private.msg.text.offset;
+    d.chunk = tmp;		/* initial buffer chunk */
+    d.chunksize = CHUNKSIZE;	/* file chunk size */
+    INIT (&bs,fd_string,&d,elt->private.msg.text.text.size);
+    for (s = (char *) LOCAL->text.data; SIZE (&bs);) switch (c = SNX (&bs)) {
+    case '\r':			/* carriage return seen */
+      *s++ = c;			/* copy it and any succeeding LF */
+      if (SIZE (&bs) && (CHR (&bs) == '\n')) *s++ = SNX (&bs);
+      break;
+    case '\n':
+      *s++ = '\r';		/* insert a CR */
+    default:
+      *s++ = c;			/* copy characters */
+    }
+    *s = '\0';			/* tie off buffer */
+				/* calculate length of cached data */
+    LOCAL->textlen = s - LOCAL->text.data;
+  }
+  *length = LOCAL->textlen;	/* return from cache */
+  return (char *) LOCAL->text.data;
+}
+
+/* UNIX per-message modify flag
+ * Accepts: MAIL stream
+ *	    message cache element
+ */
+
+void unix_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+				/* only after finishing */
+  if (elt->valid) elt->private.dirty = LOCAL->dirty = T;
+}
+
+
+/* UNIX mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ */
+
+long unix_ping (MAILSTREAM *stream)
+{
+  char lock[MAILTMPLEN];
+  struct stat sbuf;
+				/* big no-op if not readwrite */
+  if (LOCAL && (LOCAL->ld >= 0) && !stream->lock) {
+    if (stream->rdonly) {	/* does he want to give up readwrite? */
+				/* checkpoint if we changed something */
+      if (LOCAL->dirty) unix_check (stream);
+      flock (LOCAL->ld,LOCK_UN);/* release readwrite lock */
+      close (LOCAL->ld);	/* close the readwrite lock file */
+      LOCAL->ld = -1;		/* no more readwrite lock fd */
+      unlink (LOCAL->lname);	/* delete the readwrite lock file */
+    }
+    else {			/* get current mailbox size */
+      if (LOCAL->fd >= 0) fstat (LOCAL->fd,&sbuf);
+      else if (stat (stream->mailbox,&sbuf)) {
+	sprintf (LOCAL->buf,"Mailbox stat failed, aborted: %s",
+		 strerror (errno));
+	MM_LOG (LOCAL->buf,ERROR);
+	unix_abort (stream);
+	return NIL;
+      }
+				/* parse if mailbox changed */
+      if ((LOCAL->ddirty || (sbuf.st_size != LOCAL->filesize)) &&
+	  unix_parse (stream,lock,LOCK_EX)) {
+				/* force checkpoint if double-dirty */
+	if (LOCAL->ddirty) unix_rewrite (stream,NIL,lock,NIL);
+				/* unlock mailbox */
+	else unix_unlock (LOCAL->fd,stream,lock);
+	mail_unlock (stream);	/* and stream */
+	mm_nocritical (stream);	/* done with critical */
+      }
+    }
+  }
+  return LOCAL ? LONGT : NIL;	/* return if still alive */
+}
+
+/* UNIX mail check mailbox
+ * Accepts: MAIL stream
+ */
+
+void unix_check (MAILSTREAM *stream)
+{
+  char lock[MAILTMPLEN];
+				/* parse and lock mailbox */
+  if (LOCAL && (LOCAL->ld >= 0) && !stream->lock &&
+      unix_parse (stream,lock,LOCK_EX)) {
+				/* any unsaved changes? */
+    if (LOCAL->dirty && unix_rewrite (stream,NIL,lock,NIL)) {
+      if (!stream->silent) mm_log ("Checkpoint completed",NIL);
+    }
+				/* no checkpoint needed, just unlock */
+    else unix_unlock (LOCAL->fd,stream,lock);
+    mail_unlock (stream);	/* unlock the stream */
+    mm_nocritical (stream);	/* done with critical */
+  }
+}
+
+
+/* UNIX mail expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long unix_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  long ret;
+  unsigned long i;
+  char lock[MAILTMPLEN];
+  char *msg = NIL;
+				/* parse and lock mailbox */
+  if (ret = (sequence ? ((options & EX_UID) ?
+			 mail_uid_sequence (stream,sequence) :
+			 mail_sequence (stream,sequence)) : LONGT) &&
+      LOCAL && (LOCAL->ld >= 0) && !stream->lock &&
+      unix_parse (stream,lock,LOCK_EX)) {
+				/* check expunged messages if not dirty */
+    for (i = 1; !LOCAL->dirty && (i <= stream->nmsgs); i++) {
+      MESSAGECACHE *elt = mail_elt (stream,i);
+      if (mail_elt (stream,i)->deleted) LOCAL->dirty = T;
+    }
+    if (!LOCAL->dirty) {	/* not dirty and no expunged messages */
+      unix_unlock (LOCAL->fd,stream,lock);
+      msg = "No messages deleted, so no update needed";
+    }
+    else if (unix_rewrite (stream,&i,lock,sequence ? LONGT : NIL)) {
+      if (i) sprintf (msg = LOCAL->buf,"Expunged %lu messages",i);
+      else msg = "Mailbox checkpointed, but no messages expunged";
+    }
+				/* rewrite failed */
+    else unix_unlock (LOCAL->fd,stream,lock);
+    mail_unlock (stream);	/* unlock the stream */
+    mm_nocritical (stream);	/* done with critical */
+    if (msg && !stream->silent) mm_log (msg,NIL);
+  }
+  else if (!stream->silent) mm_log("Expunge ignored on readonly mailbox",WARN);
+  return ret;
+}
+
+/* UNIX mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if copy successful, else NIL
+ */
+
+long unix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  struct stat sbuf;
+  int fd;
+  char *s,file[MAILTMPLEN],lock[MAILTMPLEN];
+  struct utimbuf times;
+  unsigned long i,j;
+  MESSAGECACHE *elt;
+  long ret = T;
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+  copyuid_t cu = (copyuid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ?
+			      NIL : mail_parameters (NIL,GET_COPYUID,NIL));
+  SEARCHSET *source = cu ? mail_newsearchset () : NIL;
+  SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
+  MAILSTREAM *tstream = NIL;
+  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+	mail_sequence (stream,sequence))) return NIL;
+				/* make sure destination is valid */
+  if (!(unix_valid (mailbox) || !errno))
+    switch (errno) {
+    case ENOENT:			/* no such file? */
+      if (compare_cstring (mailbox,"INBOX")) {
+	mm_notify (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
+	return NIL;
+      }
+      if (pc) return (*pc) (stream,sequence,mailbox,options);
+      unix_create (NIL,"INBOX");/* create empty INBOX */
+    case EACCES:		/* file protected */
+      sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
+      MM_LOG (LOCAL->buf,ERROR);
+      return NIL;
+    case EINVAL:
+      if (pc) return (*pc) (stream,sequence,mailbox,options);
+      sprintf (LOCAL->buf,"Invalid UNIX-format mailbox name: %.80s",mailbox);
+      mm_log (LOCAL->buf,ERROR);
+      return NIL;
+    default:
+      if (pc) return (*pc) (stream,sequence,mailbox,options);
+      sprintf (LOCAL->buf,"Not a UNIX-format mailbox: %.80s",mailbox);
+      mm_log (LOCAL->buf,ERROR);
+      return NIL;
+    }
+
+				/* try to open rewrite for UIDPLUS */
+  if ((tstream = mail_open_work (&unixdriver,NIL,mailbox,
+				 OP_SILENT|OP_NOKOD)) && tstream->rdonly)
+    tstream = mail_close (tstream);
+  if (cu && !tstream) {		/* wanted a COPYUID? */
+    sprintf (LOCAL->buf,"Unable to write-open mailbox for COPYUID: %.80s",
+	     mailbox);
+    MM_LOG (LOCAL->buf,WARN);
+    cu = NIL;			/* don't try to do COPYUID */
+  }
+  LOCAL->buf[0] = '\0';
+  mm_critical (stream);		/* go critical */
+  if ((fd = unix_lock (dummy_file (file,mailbox),
+		       O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IREAD|S_IWRITE,
+		       lock,LOCK_EX)) < 0) {
+    mm_nocritical (stream);	/* done with critical */
+    sprintf (LOCAL->buf,"Can't open destination mailbox: %s",strerror (errno));
+    mm_log (LOCAL->buf,ERROR);	/* log the error */
+    return NIL;			/* failed */
+  }
+  fstat (fd,&sbuf);		/* get current file size */
+				/* write all requested messages to mailbox */
+  for (i = 1; ret && (i <= stream->nmsgs); i++)
+    if ((elt = mail_elt (stream,i))->sequence) {
+      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
+      read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size);
+      if (LOCAL->buf[(j = elt->private.special.text.size) - 2] != '\r') {
+	LOCAL->buf[j - 1] = '\r';
+	LOCAL->buf[j++] = '\n';
+      }
+      if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
+      else {			/* internal header succeeded */
+	s = unix_header (stream,i,&j,NIL);
+				/* header size, sans trailing newline */
+	if (j && (s[j - 4] == '\r')) j -= 2;
+	if (write (fd,s,j) < 0) ret = NIL;
+	else {			/* message header succeeded */
+	  j = tstream ?		/* write UIDPLUS data if have readwrite */
+	    unix_xstatus (stream,LOCAL->buf,elt,++(tstream->uid_last),LONGT) :
+	    unix_xstatus (stream,LOCAL->buf,elt,NIL,NIL);
+	  if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
+	  else {		/* message status succeeded */
+	    s = unix_text_work (stream,elt,&j,NIL);
+	    if ((write (fd,s,j) < 0) || (write (fd,"\r\n",2) < 0))
+	      ret = NIL;
+	    else if (cu) {	/* need to pass back new UID? */
+	      mail_append_set (source,mail_uid (stream,i));
+	      mail_append_set (dest,tstream->uid_last);
+	    }
+	  }
+	}
+      }
+    }
+
+  if (!ret || fsync (fd)) {	/* force out the update */
+    sprintf (LOCAL->buf,"Message copy failed: %s",strerror (errno));
+    ftruncate (fd,sbuf.st_size);
+    ret = NIL;
+  }
+				/* force UIDVALIDITY assignment now */
+  if (tstream && !tstream->uid_validity)
+    tstream->uid_validity = (unsigned long) time (0);
+				/* return sets if doing COPYUID */
+  if (cu && ret) (*cu) (stream,mailbox,tstream->uid_validity,source,dest);
+  else {			/* flush any sets we may have built */
+    mail_free_searchset (&source);
+    mail_free_searchset (&dest);
+  }
+  times.modtime = time (0);	/* set mtime to now */
+				/* set atime to now-1 if successful copy */
+  if (ret) times.actime = times.modtime - 1;
+		
+  else times.actime =		/* else preserve \Marked status */
+	 ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ?
+	 sbuf.st_atime : times.modtime;
+  utime (file,&times);		/* set the times */
+  unix_unlock (fd,NIL,lock);	/* unlock and close mailbox */
+  if (tstream) {		/* update last UID if we can */
+    UNIXLOCAL * local = (UNIXLOCAL *) tstream->local;
+    local->dirty = T;		/* do a rewrite */
+    local->appending = T;	/* but not at the cost of marking as old */
+    tstream = mail_close (tstream);
+  }
+				/* log the error */
+  if (!ret) mm_log (LOCAL->buf,ERROR);
+				/* delete if requested message */
+  else if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++)
+    if ((elt = mail_elt (stream,i))->sequence)
+      elt->deleted = elt->private.dirty = LOCAL->dirty = T;
+  mm_nocritical (stream);	/* release critical */
+  return ret;
+}
+
+/* UNIX mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+#define BUFLEN 8*MAILTMPLEN
+
+long unix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct stat sbuf;
+  int fd;
+  unsigned long i;
+  char *flags,*date,buf[BUFLEN],tmp[MAILTMPLEN],file[MAILTMPLEN],
+    lock[MAILTMPLEN];
+  struct utimbuf times;
+  FILE *sf,*df;
+  MESSAGECACHE elt;
+  STRING *message;
+  unsigned long uidlocation = 0;
+  appenduid_t au = (appenduid_t)
+    (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL :
+     mail_parameters (NIL,GET_APPENDUID,NIL));
+  SEARCHSET *dst = au ? mail_newsearchset () : NIL;
+  long ret = LONGT;
+  MAILSTREAM *tstream = NIL;
+  if (!stream) {		/* stream specified? */
+    stream = &unixproto;	/* no, default stream to prototype */
+    for (i = 0; i < NUSERFLAGS && stream->user_flags[i]; ++i)
+      fs_give ((void **) &stream->user_flags[i]);
+  }
+  if (!unix_valid (mailbox)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    if (!compare_cstring (mailbox,"INBOX")) {
+      mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+      return NIL;
+    }
+    unix_create (NIL,"INBOX");	/* create empty INBOX */
+  case 0:			/* merely empty file? */
+    tstream = stream;
+    break;
+  case EACCES:			/* file protected */
+    sprintf (tmp,"Can't access destination: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  case EINVAL:
+    sprintf (tmp,"Invalid UNIX-format mailbox name: %.80s",mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;
+  default:
+    sprintf (tmp,"Not a UNIX-format mailbox: %.80s",mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* get sniffing stream for keywords */
+  else if (!(tstream = mail_open (NIL,mailbox,
+				  OP_READONLY|OP_SILENT|OP_NOKOD|OP_SNIFF))) {
+    sprintf (tmp,"Unable to examine mailbox for APPEND: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+
+				/* get first message */
+  if (!(*af) (tstream,data,&flags,&date,&message)) return NIL;
+  if (!(sf = tmpfile ())) {	/* must have scratch file */
+    sprintf (tmp,".%lx.%lx",(unsigned long) time (0),(unsigned long)getpid ());
+    if (!stat (tmp,&sbuf) || !(sf = fopen (tmp,"wb+"))) {
+      sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno));
+      mm_log (tmp,ERROR);
+      return NIL;
+    }
+    unlink (tmp);
+  }
+  do {				/* parse date */
+    if (!date) rfc822_date (date = tmp);
+    if (!mail_parse_date (&elt,date)) {
+      sprintf (tmp,"Bad date in append: %.80s",date);
+      mm_log (tmp,ERROR);
+    }
+    else {			/* user wants to suppress time zones? */
+      if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) {
+	time_t when = mail_longdate (&elt);
+	date = ctime (&when);	/* use traditional date */
+      }
+				/* use POSIX-style date */
+      else date = mail_cdate (tmp,&elt);
+      if (!SIZE (message)) mm_log ("Append of zero-length message",ERROR);
+      else if (!unix_collect_msg (tstream,sf,flags,date,message)) {
+	sprintf (tmp,"Error writing scratch file: %.80s",strerror (errno));
+	mm_log (tmp,ERROR);
+      }
+				/* get next message */
+      else if ((*af) (tstream,data,&flags,&date,&message)) continue;
+    }
+    fclose (sf);		/* punt scratch file */
+    return NIL;			/* give up */
+  } while (message);		/* until no more messages */
+  if (fflush (sf)) {
+    sprintf (tmp,"Error finishing scratch file: %.80s",strerror (errno));
+    mm_log (tmp,ERROR);
+    fclose (sf);		/* punt scratch file */
+    return NIL;			/* give up */
+  }
+  i = ftell (sf);		/* size of scratch file */
+
+				/* close sniffing stream */
+  if (tstream != stream) tstream = mail_close (tstream);
+  mm_critical (stream);		/* go critical */
+				/* try to open readwrite for UIDPLUS */
+  if ((tstream = mail_open_work (&unixdriver,NIL,mailbox,
+				 OP_SILENT|OP_NOKOD)) && tstream->rdonly)
+    tstream = mail_close (tstream);
+  if (au && !tstream) {		/* wanted an APPENDUID? */
+    sprintf (tmp,"Unable to re-open mailbox for APPENDUID: %.80s",mailbox);
+    MM_LOG (tmp,WARN);
+    au = NIL;
+  }
+  if (((fd = unix_lock (dummy_file (file,mailbox),
+			O_BINARY|O_WRONLY|O_APPEND|O_CREAT,S_IREAD|S_IWRITE,
+			lock,LOCK_EX)) < 0) || !(df = fdopen (fd,"ab"))) {
+    mm_nocritical (stream);	/* done with critical */
+    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+  fstat (fd,&sbuf);		/* get current file size */
+  rewind (sf);
+  times.modtime = time (0);	/* set mtime to now */
+				/* write all messages */
+  if (!unix_append_msgs (tstream,sf,df,au ? dst : NIL) ||
+      (fflush (df) == EOF) || fsync (fd)) {
+    sprintf (buf,"Message append failed: %s",strerror (errno));
+    mm_log (buf,ERROR);
+    ftruncate (fd,sbuf.st_size);/* revert file */
+    times.actime =		/* preserve \Marked status */
+      ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ?
+      sbuf.st_atime : times.modtime;
+    ret = NIL;			/* return error */
+  }
+				/* set atime to now-1 if successful copy */
+  else times.actime = times.modtime - 1;
+  utime (file,&times);		/* set the times */
+  fclose (sf);			/* done with scratch file */
+				/* force UIDVALIDITY assignment now */
+  if (tstream && !tstream->uid_validity)
+    tstream->uid_validity = (unsigned long) time (0);
+				/* return sets if doing APPENDUID */
+  if (au && ret) (*au) (mailbox,tstream->uid_validity,dst);
+  else mail_free_searchset (&dst);
+  flock (fd,LOCK_UN);		/* unlock mailbox (can't use unix_unlock() */
+  if (lock && *lock) unlink (lock);
+  fclose (df);			/* close mailbox */
+  if (tstream) {		/* update last UID if we can */
+    UNIXLOCAL * local = (UNIXLOCAL *) tstream->local;
+    local->dirty = T;		/* do a rewrite */
+    local->appending = T;	/* but not at the cost of marking as old */
+    tstream = mail_close (tstream);
+  }
+  mm_nocritical (stream);	/* release critical */
+  return ret;
+}
+
+/* Collect and write single message to append scratch file
+ * Accepts: MAIL stream
+ *	    scratch file
+ *	    flags
+ *	    date
+ *	    message stringstruct
+ * Returns: NIL if write error, else T
+ */
+
+int unix_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
+		     STRING *msg)
+{
+  unsigned char *s,*t;
+  unsigned long uf;
+  long f = mail_parse_flags (stream,flags,&uf);
+				/* write metadata */
+  if (fprintf (sf,"%ld %lu ",f,SIZE (msg) + 2) < 0) return NIL;
+  for (s = date; *s; *s++) switch (*s) {
+  default:
+    if (putc (*s,sf) == EOF) return NIL;
+  case '\r': case '\n':
+    break;
+  }
+  if (fputs ("\r\n",sf) == EOF) return NIL;
+  while (uf)			/* write user flags */    
+    if ((s = stream->user_flags[find_rightmost_bit (&uf)]) &&
+	(fprintf (sf," %s",s) < 0)) return NIL;
+  if (fputs ("\r\n",sf) == EOF) return NIL;
+  while (SIZE (msg)) {		/* copy text to scratch file */
+    for (s = (unsigned char *) msg->curpos, t = s + msg->cursize; s < t; ++s)
+      if (!*s) *s = 0x80;	/* disallow NUL */
+				/* write buffered text */
+    if (fwrite (msg->curpos,1,msg->cursize,sf) == msg->cursize)
+      SETPOS (msg,GETPOS (msg) + msg->cursize);
+    else return NIL;		/* failed */
+  }
+				/* write trailing CRLF and return */
+  return (fputs ("\r\n",sf) == EOF) ? NIL : T;
+}
+
+/* Append messages from scratch file to mailbox
+ * Accepts: MAIL stream
+ *	    source file
+ *	    destination file
+ *	    uidset to update if non-NIL
+ * Returns: T if success, NIL if failure
+ */
+
+int unix_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set)
+{
+  int ti,zn,c;
+  long f;
+  unsigned long i,j;
+  char *x,tmp[MAILTMPLEN];
+  int hdrp = T;
+				/* get message metadata line */
+  while (fgets (tmp,MAILTMPLEN,sf)) {
+    if (!(isdigit (tmp[0]) && strchr (tmp,'\n'))) return NIL;
+    f = strtol (tmp,&x,10);	/* get flags */
+    if (!((*x++ == ' ') && isdigit (*x))) return NIL;
+    i = strtoul (x,&x,10);	/* get message size */
+    if ((*x++ != ' ') ||	/* build initial header */
+	(fprintf (df,"From %s@%s %sStatus: ",myusername(),mylocalhost(),x)<0)||
+	(f&fSEEN && (putc ('R',df) == EOF)) ||
+	(fputs ("\r\nX-Status: ",df) == EOF) ||
+	(f&fDELETED && (putc ('D',df) == EOF)) ||
+	(f&fFLAGGED && (putc ('F',df) == EOF)) ||
+	(f&fANSWERED && (putc ('A',df) == EOF)) ||
+	(f&fDRAFT && (putc ('T',df) == EOF)) ||
+	(fputs ("\r\nX-Keywords:",df) == EOF)) return NIL;
+				/* copy keywords */
+    while ((c = getc (sf)) != '\n') switch (c) {
+    case EOF:
+      return NIL;
+    default:
+      if (putc (c,df) == EOF) return NIL;
+    }
+    if ((putc ('\n',df) == EOF) ||
+	(set && (fprintf (df,"X-UID: %lu\r\n",++(stream->uid_last)) < 0)))
+      return NIL;
+
+    for (c = '\n'; i && fgets (tmp,MAILTMPLEN,sf); c = tmp[j-1]) {
+				/* get read line length */
+      if (i < (j = strlen (tmp))) fatal ("unix_append_msgs overrun");
+      i -= j;			/* number of bytes left */
+      if (!j) continue;		/* do nothing if line emptied */
+				/* complete line? */
+      if ((c == '\n')) switch (tmp[0]) {
+      case 'F':			/* possible "From " (case counts here) */
+	if ((j > 4) && (tmp[0] == 'F') && (tmp[1] == 'r') && (tmp[2] == 'o') &&
+	    (tmp[3] == 'm') && (tmp[4] == ' ')) {
+	  if (!unix_fromwidget) {
+	    VALID (tmp,x,ti,zn);/* conditional, only write widget if */
+	    if (!ti) break;	/*  it looks like a valid header */
+	  }			/* write the widget */
+	  if (putc ('>',df) == EOF) return NIL;
+	}
+	break;
+      case 'S': case 's':	/* possible "Status:" */
+	if (hdrp && (j > 6) && ((tmp[1] == 't') || (tmp[1] == 'T')) &&
+	    ((tmp[2] == 'a') || (tmp[2] == 'A')) &&
+	    ((tmp[3] == 't') || (tmp[3] == 'T')) &&
+	    ((tmp[4] == 'u') || (tmp[4] == 'U')) &&
+	    ((tmp[5] == 's') || (tmp[5] == 'S')) && (tmp[6] == ':') &&
+	    (fputs ("X-Original-",df) == EOF)) return NIL;
+	break;
+      case 'X': case 'x':	/* possible X-??? header */
+	if (hdrp && (tmp[1] == '-') &&
+				/* possible X-UID: */
+	    (((j > 5) && ((tmp[2] == 'U') || (tmp[2] == 'u')) &&
+	      ((tmp[3] == 'I') || (tmp[3] == 'i')) &&
+	      ((tmp[4] == 'D') || (tmp[4] == 'd')) && (tmp[5] == ':')) ||
+				/* possible X-IMAP: */
+	     ((j > 6) && ((tmp[2] == 'I') || (tmp[2] == 'i')) &&
+	      ((tmp[3] == 'M') || (tmp[3] == 'm')) &&
+	      ((tmp[4] == 'A') || (tmp[4] == 'a')) &&
+	      ((tmp[5] == 'P') || (tmp[5] == 'p')) &&
+	      ((tmp[6] == ':') ||
+				/* or X-IMAPbase: */
+	       ((j > 10) && ((tmp[6] == 'b') || (tmp[6] == 'B')) &&
+		((tmp[7] == 'a') || (tmp[7] == 'A')) &&
+		((tmp[8] == 's') || (tmp[8] == 'S')) &&
+		((tmp[9] == 'e') || (tmp[9] == 'E')) && (tmp[10] == ':')))) ||
+				/* possible X-Status: */
+	     ((j > 8) && ((tmp[2] == 'S') || (tmp[2] == 's')) &&
+	      ((tmp[3] == 't') || (tmp[3] == 'T')) &&
+	      ((tmp[4] == 'a') || (tmp[4] == 'A')) &&
+	      ((tmp[5] == 't') || (tmp[5] == 'T')) &&
+	      ((tmp[6] == 'u') || (tmp[6] == 'U')) &&
+	      ((tmp[7] == 's') || (tmp[7] == 'S')) && (tmp[8] == ':')) ||
+				/* possible X-Keywords: */
+	     ((j > 10) && ((tmp[2] == 'K') || (tmp[2] == 'k')) &&
+	      ((tmp[3] == 'e') || (tmp[3] == 'E')) &&
+	      ((tmp[4] == 'y') || (tmp[4] == 'Y')) &&
+	      ((tmp[5] == 'w') || (tmp[5] == 'W')) &&
+	      ((tmp[6] == 'o') || (tmp[6] == 'O')) &&
+	      ((tmp[7] == 'r') || (tmp[7] == 'R')) &&
+	      ((tmp[8] == 'd') || (tmp[8] == 'D')) &&
+	      ((tmp[9] == 's') || (tmp[9] == 'S')) && (tmp[10] == ':'))) &&
+	    (fputs ("X-Original-",df) == EOF)) return NIL;
+	break;
+      case '\n':		/* blank line */
+	hdrp = NIL;
+	break;
+      default:			/* nothing to do */
+	break;
+      }
+				/* just write the line */
+      if (fwrite (tmp,1,j,df) != j) return NIL;
+    }
+    if (i) return NIL;		/* didn't read entire message */
+				/* update set */
+    if (stream) mail_append_set (set,stream->uid_last);
+  }
+  return T;
+}
+
+/* Internal routines */
+
+
+/* UNIX mail abort stream
+ * Accepts: MAIL stream
+ */
+
+void unix_abort (MAILSTREAM *stream)
+{
+  if (LOCAL) {			/* only if a file is open */
+    if (LOCAL->fd >= 0) close (LOCAL->fd);
+    if (LOCAL->ld >= 0) {	/* have a mailbox lock? */
+      flock (LOCAL->ld,LOCK_UN);/* yes, release the lock */
+      close (LOCAL->ld);	/* close the lock file */
+      unlink (LOCAL->lname);	/* and delete it */
+    }
+    if (LOCAL->lname) fs_give ((void **) &LOCAL->lname);
+				/* free local text buffers */
+    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+    if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data);
+    if (LOCAL->linebuf) fs_give ((void **) &LOCAL->linebuf);
+    if (LOCAL->line) fs_give ((void **) &LOCAL->line);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+/* UNIX open and lock mailbox
+ * Accepts: file name to open/lock
+ *	    file open mode
+ *	    destination buffer for lock file name
+ *	    type of locking operation (LOCK_SH or LOCK_EX)
+ */
+
+int unix_lock (char *file,int flags,int mode,char *lock,int op)
+{
+  int fd,ld,j;
+  int i = LOCKTIMEOUT * 60 - 1;
+  char tmp[MAILTMPLEN];
+  time_t t;
+  struct stat sb;
+  sprintf (lock,"%s.lock",file);/* build lock filename */
+  do {				/* until OK or out of tries */
+    t = time (0);		/* get the time now */
+				/* try to get the lock */
+    if ((ld = open(lock,O_BINARY|O_WRONLY|O_CREAT|O_EXCL,S_IREAD|S_IWRITE))>=0)
+      close (ld);		/* got it, close the lock file! */
+    else if (errno != EEXIST) {	/* miscellaneous error */
+      sprintf (tmp,"Error creating %.80s: %s",lock,strerror (errno));
+      if (!(i%15)) mm_log (tmp,WARN);
+    }
+				/* lock exists, still active? */
+    else if (!stat (lock,&sb) && (t > sb.st_ctime + LOCKTIMEOUT * 60) &&
+	     ((ld = open(lock,O_BINARY|O_WRONLY|O_CREAT,S_IREAD|S_IWRITE))>=0))
+      close (ld);		/* got timed-out lock file */
+    else {			/* active lock, try again */
+      if (!(i%15)) {
+	sprintf (tmp,"Mailbox %.80s is locked, will override in %d seconds...",
+		 file,i);
+	mm_log (tmp,WARN);
+      }
+      sleep (1);		/* wait a second before next retry */
+    }
+  } while (*lock && ld < 0 && i--);
+				/* open file */
+  if ((fd = open (file,flags,mode)) >= 0) flock (fd,op);
+  else {			/* open failed */
+    j = errno;			/* preserve error code */
+    if (*lock) unlink (lock);	/* flush the lock file if any */
+    errno = j;			/* restore error code */
+  }
+  return fd;
+}
+
+/* UNIX unlock and close mailbox
+ * Accepts: file descriptor
+ *	    (optional) mailbox stream to check atime/mtime
+ *	    (optional) lock file name
+ */
+
+void unix_unlock (int fd,MAILSTREAM *stream,char *lock)
+{
+  if (stream) {			/* need to muck with times? */
+    struct stat sbuf;
+    struct utimbuf times;
+    time_t now = time (0);
+    fstat (fd,&sbuf);		/* get file times */
+    if (LOCAL->ld >= 0) {	/* yes, readwrite session? */
+      times.actime = now;	/* set atime to now */
+				/* set mtime to (now - 1) if necessary */
+      times.modtime = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1;
+    }
+    else if (stream->recent) {	/* readonly with recent messages */
+      if ((sbuf.st_atime >= sbuf.st_mtime) ||
+	  (sbuf.st_atime >= sbuf.st_ctime))
+				/* keep past mtime, whack back atime */
+	times.actime = (times.modtime = (sbuf.st_mtime < now) ?
+			sbuf.st_mtime : now) - 1;
+      else now = 0;		/* no time change needed */
+    }
+				/* readonly with no recent messages */
+    else if ((sbuf.st_atime < sbuf.st_mtime) ||
+	     (sbuf.st_atime < sbuf.st_ctime)) {
+      times.actime = now;	/* set atime to now */
+				/* set mtime to (now - 1) if necessary */
+      times.modtime = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1;
+    }
+    else now = 0;		/* no time change needed */
+				/* set the times, note change */
+    if (now && !utime (stream->mailbox,&times))
+      LOCAL->filetime = times.modtime;
+  }
+  flock (fd,LOCK_UN);		/* release flock'ers */
+  if (!stream) close (fd);	/* close the file if no stream */
+				/* flush the lock file if any */
+  if (lock && *lock) unlink (lock);
+}
+
+/* UNIX mail parse and lock mailbox
+ * Accepts: MAIL stream
+ *	    space to write lock file name
+ *	    type of locking operation
+ * Returns: T if parse OK, critical & mailbox is locked shared; NIL if failure
+ */
+
+int unix_parse (MAILSTREAM *stream,char *lock,int op)
+{
+  int zn;
+  unsigned long i,j,k,m;
+  unsigned char c,*s,*t,*u,tmp[MAILTMPLEN],date[30];
+  int ti = 0,retain = T;
+  unsigned long nmsgs = stream->nmsgs;
+  unsigned long prevuid = nmsgs ? mail_elt (stream,nmsgs)->private.uid : 0;
+  unsigned long recent = stream->recent;
+  unsigned long oldnmsgs = stream->nmsgs;
+  short silent = stream->silent;
+  short pseudoseen = NIL;
+  struct stat sbuf;
+  STRING bs;
+  FDDATA d;
+  MESSAGECACHE *elt;
+  mail_lock (stream);		/* guard against recursion or pingers */
+				/* toss out previous descriptor */
+  if (LOCAL->fd >= 0) close (LOCAL->fd);
+  mm_critical (stream);		/* open and lock mailbox (shared OK) */
+  if ((LOCAL->fd = unix_lock (stream->mailbox,
+			      O_BINARY + ((LOCAL->ld >= 0) ? O_RDWR:O_RDONLY),
+			      NIL,lock,op)) < 0) {
+    sprintf (tmp,"Mailbox open failed, aborted: %s",strerror (errno));
+    mm_log (tmp,ERROR);
+    unix_abort (stream);
+    mail_unlock (stream);
+    mm_nocritical (stream);	/* done with critical */
+    return NIL;
+  }
+  fstat (LOCAL->fd,&sbuf);	/* get status */
+				/* validate change in size */
+  if (sbuf.st_size < LOCAL->filesize) {
+    sprintf (tmp,"Mailbox shrank from %lu to %lu bytes, aborted",
+	     (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
+    mm_log (tmp,ERROR);		/* this is pretty bad */
+    unix_unlock (LOCAL->fd,stream,lock);
+    unix_abort (stream);
+    mail_unlock (stream);
+    mm_nocritical (stream);	/* done with critical */
+    return NIL;
+  }
+
+				/* new data? */
+  else if (i = sbuf.st_size - LOCAL->filesize) {
+    d.fd = LOCAL->fd;		/* yes, set up file descriptor */
+    d.pos = LOCAL->filesize;	/* get to that position in the file */
+    d.chunk = LOCAL->buf;	/* initial buffer chunk */
+    d.chunksize = CHUNKSIZE;	/* file chunk size */
+    INIT (&bs,fd_string,&d,i);	/* initialize stringstruct */
+				/* skip leading whitespace for broken MTAs */
+    while (((c = CHR (&bs)) == '\n') || (c == '\r') ||
+	   (c == ' ') || (c == '\t')) SNX (&bs);
+    if (SIZE (&bs)) {		/* read new data */
+				/* remember internal header position */
+      j = LOCAL->filesize + GETPOS (&bs);
+      s = unix_mbxline (stream,&bs,&i);
+      t = NIL,zn = 0;
+      if (i) VALID (s,t,ti,zn);	/* see if valid From line */
+      if (!ti) {		/* someone pulled the rug from under us */
+	sprintf (tmp,"Unexpected changes to mailbox (try restarting): %.20s",
+		 (char *) s);
+	mm_log (tmp,ERROR);
+	unix_unlock (LOCAL->fd,stream,lock);
+	unix_abort (stream);
+	mail_unlock (stream);
+	mm_nocritical (stream);	/* done with critical */
+	return NIL;
+      }
+      stream->silent = T;	/* quell main program new message events */
+      do {			/* found a message */
+				/* instantiate first new message */
+	mail_exists (stream,++nmsgs);
+	(elt = mail_elt (stream,nmsgs))->valid = T;
+	recent++;		/* assume recent by default */
+	elt->recent = T;
+				/* note position/size of internal header */
+	elt->private.special.offset = j;
+	elt->private.msg.header.offset = elt->private.special.text.size = i;
+
+				/* generate plausible IMAPish date string */
+	date[2] = date[6] = date[20] = '-'; date[11] = ' ';
+	date[14] = date[17] = ':';
+				/* dd */
+	date[0] = t[ti - 2]; date[1] = t[ti - 1];
+				/* mmm */
+	date[3] = t[ti - 6]; date[4] = t[ti - 5]; date[5] = t[ti - 4];
+				/* hh */
+	date[12] = t[ti + 1]; date[13] = t[ti + 2];
+				/* mm */
+	date[15] = t[ti + 4]; date[16] = t[ti + 5];
+	if (t[ti += 6] == ':') {/* ss */
+	  date[18] = t[++ti]; date[19] = t[++ti];
+	  ti++;			/* move to space */
+	}
+	else date[18] = date[19] = '0';
+				/* yy -- advance over timezone if necessary */
+	if (zn == ti) ti += (((t[zn+1] == '+') || (t[zn+1] == '-')) ? 6 : 4);
+	date[7] = t[ti + 1]; date[8] = t[ti + 2];
+	date[9] = t[ti + 3]; date[10] = t[ti + 4];
+				/* zzz */
+	t = zn ? (t + zn + 1) : (unsigned char *) "LCL";
+	date[21] = *t++; date[22] = *t++; date[23] = *t++;
+	if ((date[21] != '+') && (date[21] != '-')) date[24] = '\0';
+	else {			/* numeric time zone */
+	  date[24] = *t++; date[25] = *t++;
+	  date[26] = '\0'; date[20] = ' ';
+	}
+				/* set internal date */
+	if (!mail_parse_date (elt,date)) {
+	  sprintf (tmp,"Unable to parse internal date: %s",(char *) date);
+	  mm_log (tmp,WARN);
+	}
+
+	do {			/* look for message body */
+	  s = t = unix_mbxline (stream,&bs,&i);
+	  if (i) switch (*s) {	/* check header lines */
+	  case 'X':		/* possible X-???: line */
+	    if (s[1] == '-') {	/* must be immediately followed by hyphen */
+				/* X-Status: becomes Status: in S case */
+	      if (s[2] == 'S' && s[3] == 't' && s[4] == 'a' && s[5] == 't' &&
+		  s[6] == 'u' && s[7] == 's' && s[8] == ':') s += 2;
+				/* possible X-Keywords */
+	      else if (s[2] == 'K' && s[3] == 'e' && s[4] == 'y' &&
+		       s[5] == 'w' && s[6] == 'o' && s[7] == 'r' &&
+		       s[8] == 'd' && s[9] == 's' && s[10] == ':') {
+		SIZEDTEXT uf;
+		retain = NIL;	/* don't retain continuation */
+		s += 11;	/* flush leading whitespace */
+		while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n'))){
+		  while (*s == ' ') s++;
+				/* find end of keyword */
+		  if (!(u = strpbrk (s," \n\r"))) u = s + strlen (s);
+				/* got a keyword? */
+		  if ((k = (u - s)) && (k <= MAXUSERFLAG)) {
+		    uf.data = (unsigned char *) s;
+		    uf.size = k;
+		    for (j = 0; (j < NUSERFLAGS) && stream->user_flags[j]; ++j)
+		      if (!compare_csizedtext (stream->user_flags[j],&uf)) {
+			elt->user_flags |= ((long) 1) << j;
+			break;
+		      }
+		  }
+		  s = u;	/* advance to next keyword */
+		}
+		break;
+	      }
+
+				/* possible X-IMAP */
+	      else if ((s[2] == 'I') && (s[3] == 'M') && (s[4] == 'A') &&
+		       (s[5] == 'P') && ((m = (s[6] == ':')) ||
+					 ((s[6] == 'b') && (s[7] == 'a') &&
+					  (s[8] == 's') && (s[9] == 'e') &&
+					  (s[10] == ':')))) {
+		retain = NIL;	/* don't retain continuation */
+		if ((nmsgs == 1) && !stream->uid_validity) {
+				/* advance to data */
+		  s += m ? 7 : 11;
+				/* flush whitespace */
+		  while (*s == ' ') s++;
+		  j = 0;	/* slurp UID validity */
+				/* found a digit? */
+		  while (isdigit (*s)) {
+		    j *= 10;	/* yes, add it in */
+		    j += *s++ - '0';
+		  }
+				/* flush whitespace */
+		  while (*s == ' ') s++;
+				/* must have valid UID validity and UID last */
+		  if (j && isdigit (*s)) {
+				/* pseudo-header seen if X-IMAP */
+		    if (m) pseudoseen = LOCAL->pseudo = T;
+				/* save UID validity */
+		    stream->uid_validity = j;
+		    j = 0;	/* slurp UID last */
+		    while (isdigit (*s)) {
+		      j *= 10;	/* yes, add it in */
+		      j += *s++ - '0';
+		    }
+				/* save UID last */
+		    stream->uid_last = j;
+				/* process keywords */
+		    for (j = 0; (*s != '\n') && ((*s != '\r')||(s[1] != '\n'));
+			 s = u,j++) {
+				/* flush leading whitespace */
+		      while (*s == ' ') s++;
+		      u = strpbrk (s," \n\r");
+				/* got a keyword? */
+		      if ((j < NUSERFLAGS) && (k = (u - s)) &&
+			  (k <= MAXUSERFLAG)) {
+			if (stream->user_flags[j])
+			  fs_give ((void **) &stream->user_flags[j]);
+			stream->user_flags[j] = (char *) fs_get (k + 1);
+			strncpy (stream->user_flags[j],s,k);
+			stream->user_flags[j][k] = '\0';
+		      }
+		    }
+		  }
+		}
+		break;
+	      }
+
+				/* possible X-UID */
+	      else if (s[2] == 'U' && s[3] == 'I' && s[4] == 'D' &&
+		       s[5] == ':') {
+		retain = NIL;	/* don't retain continuation */
+				/* only believe if have a UID validity */
+		if (stream->uid_validity && ((nmsgs > 1) || !pseudoseen)) {
+		  s += 6;	/* advance to UID value */
+				/* flush whitespace */
+		  while (*s == ' ') s++;
+		  j = 0;
+				/* found a digit? */
+		  while (isdigit (*s)) {
+		    j *= 10;	/* yes, add it in */
+		    j += *s++ - '0';
+		  }
+				/* flush remainder of line */
+		  while (*s != '\n') s++;
+				/* make sure not duplicated */
+		  if (elt->private.uid)
+		    sprintf (tmp,"Message %lu UID %lu already has UID %lu",
+			     pseudoseen ? elt->msgno - 1 : elt->msgno,
+			     j,elt->private.uid);
+				/* make sure UID doesn't go backwards */
+		  else if (j <= prevuid)
+		    sprintf (tmp,"Message %lu UID %lu less than %lu",
+			     pseudoseen ? elt->msgno - 1 : elt->msgno,
+			     j,prevuid + 1);
+#if 0	/* this is currently broken by UIDPLUS */
+				/* or skip by mailbox's recorded last */
+		  else if (j > stream->uid_last)
+		    sprintf (tmp,"Message %lu UID %lu greater than last %lu",
+			     pseudoseen ? elt->msgno - 1 : elt->msgno,
+			     j,stream->uid_last);
+#endif
+		  else {	/* normal UID case */
+		    prevuid = elt->private.uid = j;
+#if 1	/* temporary kludge for UIDPLUS */
+		    if (prevuid > stream->uid_last) {
+		      stream->uid_last = prevuid;
+		      LOCAL->ddirty = LOCAL->dirty = T;
+		    }		    
+#endif
+		    break;	/* exit this cruft */
+		  }
+		  mm_log (tmp,WARN);
+				/* invalidate UID validity */
+		  stream->uid_validity = 0;
+		  elt->private.uid = 0;
+		}
+		break;
+	      }
+	    }
+				/* otherwise fall into S case */
+
+	  case 'S':		/* possible Status: line */
+	    if (s[0] == 'S' && s[1] == 't' && s[2] == 'a' && s[3] == 't' &&
+		s[4] == 'u' && s[5] == 's' && s[6] == ':') {
+	      retain = NIL;	/* don't retain continuation */
+	      s += 6;		/* advance to status flags */
+	      do switch (*s++) {/* parse flags */
+	      case 'R':		/* message read */
+		elt->seen = T;
+		break;
+	      case 'O':		/* message old */
+		if (elt->recent) {
+		  elt->recent = NIL;
+		  recent--;	/* it really wasn't recent */
+		}
+		break;
+	      case 'D':		/* message deleted */
+		elt->deleted = T;
+		break;
+	      case 'F':		/* message flagged */
+		elt->flagged = T;
+		break;
+	      case 'A':		/* message answered */
+		elt->answered = T;
+		break;
+	      case 'T':		/* message is a draft */
+		elt->draft = T;
+		break;
+	      default:		/* some other crap */
+		break;
+	      } while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n')));
+	      break;		/* all done */
+	    }
+				/* otherwise fall into default case */
+
+	  default:		/* ordinary header line */
+	    if ((*s == 'S') || (*s == 's') ||
+		(((*s == 'X') || (*s == 'x')) && (s[1] == '-'))) {
+	      unsigned char *e,*v;
+				/* must match what mail_filter() does */
+	      for (u = s,v = tmp,e = u + min (i,MAILTMPLEN - 1);
+		   (u < e) && ((c = (*u ? *u : (*u = ' '))) != ':') &&
+		   ((c > ' ') || ((c != ' ') && (c != '\t') &&
+				  (c != '\r') && (c != '\n')));
+		   *v++ = *u++);
+	      *v = '\0';	/* tie off */
+				/* matches internal header? */
+	      if (!compare_cstring (tmp,"STATUS") ||
+		  !compare_cstring (tmp,"X-STATUS") ||
+		  !compare_cstring (tmp,"X-KEYWORDS") ||
+		  !compare_cstring (tmp,"X-UID") ||
+		  !compare_cstring (tmp,"X-IMAP") ||
+		  !compare_cstring (tmp,"X-IMAPBASE")) {
+		char err[MAILTMPLEN];
+		sprintf (err,"Discarding bogus %s header in message %lu",
+			 (char *) tmp,elt->msgno);
+		mm_log (err,WARN);
+		retain = NIL;	/* don't retain continuation */
+		break;		/* different case or something */
+	      }
+	    }
+				/* retain or non-continuation? */
+	    if (retain || ((*s != ' ') && (*s != '\t'))) {
+	      retain = T;	/* retaining continuation now */
+				/* line length in CRLF format newline */
+	      k = i + (((i < 2) || (s[i - 2] != '\r')) ? 1 : 0);
+				/* header size */
+	      elt->rfc822_size = elt->private.spare.data += k;
+	    }
+	    else {
+	      char err[MAILTMPLEN];
+	      sprintf (err,"Discarding bogus continuation in msg %lu: %.80s",
+		      elt->msgno,(char *) s);
+	      if (u = strpbrk (err,"\r\n")) *u = '\0';
+	      mm_log (err,WARN);
+	      break;		/* different case or something */
+	    }
+	    break;
+	  }
+	} while (i && (*t != '\n') && ((*t != '\r') || (t[1] != '\n')));
+				/* "internal" header sans trailing newline */
+	if (i) elt->private.spare.data -= 2;
+				/* assign a UID if none found */
+	if (((nmsgs > 1) || !pseudoseen) && !elt->private.uid) {
+	  prevuid = elt->private.uid = ++stream->uid_last;
+	  elt->private.dirty = T;
+	  LOCAL->ddirty = T;	/* force update */
+	}
+	else elt->private.dirty = elt->recent;
+
+				/* note size of header, location of text */
+	elt->private.msg.header.text.size = 
+	  (elt->private.msg.text.offset =
+	   (LOCAL->filesize + GETPOS (&bs)) - elt->private.special.offset) -
+	     elt->private.special.text.size;
+	k = m = 0;		/* no previous line size yet */
+				/* note current position */
+	j = LOCAL->filesize + GETPOS (&bs);
+	if (i) do {		/* look for next message */
+	  s = unix_mbxline (stream,&bs,&i);
+	  if (i) {		/* got new data? */
+	    VALID (s,t,ti,zn);	/* yes, parse line */
+	    if (!ti) {		/* not a header line, add it to message */
+	      if (s[i - 1] == '\n')
+		elt->rfc822_size += 
+		  k = i + (m = (((i < 2) || s[i - 2] != '\r') ? 1 : 0));
+	      else {		/* file does not end with newline! */
+		elt->rfc822_size += i;
+		k = m = 0;
+	      }
+				/* update current position */
+	      j = LOCAL->filesize + GETPOS (&bs);
+	    }
+	  }
+	} while (i && !ti);	/* until found a header */
+	elt->private.msg.text.text.size = j -
+	  (elt->private.special.offset + elt->private.msg.text.offset);
+	if (k == 2) {		/* last line was blank? */
+	  elt->private.msg.text.text.size -= (m ? 1 : 2);
+	  elt->rfc822_size -= 2;
+	}
+				/* until end of buffer */
+      } while (!stream->sniff && i);
+      if (pseudoseen) {		/* flush pseudo-message if present */
+				/* decrement recent count */
+	if (mail_elt (stream,1)->recent) recent--;
+				/* and the exists count */
+	mail_exists (stream,nmsgs--);
+	mail_expunged(stream,1);/* fake an expunge of that message */
+      }
+				/* need to start a new UID validity? */
+      if (!stream->uid_validity) {
+	stream->uid_validity = (unsigned long) time (0);
+	if (nmsgs) {		/* don't bother if empty file */
+				/* make dirty to restart UID epoch */
+	  LOCAL->ddirty = LOCAL->dirty = T;
+				/* need to rewrite msg 1 if not pseudo */
+	  if (!LOCAL->pseudo) mail_elt (stream,1)->private.dirty = T;
+	  mm_log ("Assigning new unique identifiers to all messages",NIL);
+	}
+      }
+      stream->nmsgs = oldnmsgs;	/* whack it back down */
+      stream->silent = silent;	/* restore old silent setting */
+				/* notify upper level of new mailbox sizes */
+      mail_exists (stream,nmsgs);
+      mail_recent (stream,recent);
+				/* mark dirty so O flags are set */
+      if (recent) LOCAL->dirty = T;
+    }
+  }
+				/* no change, don't babble if never got time */
+  else if (LOCAL->filetime && LOCAL->filetime != sbuf.st_mtime)
+    mm_log ("New mailbox modification time but apparently no changes",WARN);
+				/* update parsed file size and time */
+  LOCAL->filesize = sbuf.st_size;
+  LOCAL->filetime = sbuf.st_mtime;
+  return T;			/* return the winnage */
+}
+
+/* UNIX read line from mailbox
+ * Accepts: mail stream
+ *	    stringstruct
+ *	    pointer to line size
+ * Returns: pointer to input line
+ */
+
+char *unix_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size)
+{
+  unsigned long i,j,k,m;
+  char *s,*t,*te;
+  char *ret = "";
+				/* flush old buffer */
+  if (LOCAL->line) fs_give ((void **) &LOCAL->line);
+				/* if buffer needs refreshing */
+  if (!bs->cursize) SETPOS (bs,GETPOS (bs));
+  if (SIZE (bs)) {		/* find newline */
+				/* end of fast scan */
+    te = (t = (s = bs->curpos) + bs->cursize) - 12;
+    while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) {
+      --s;			/* back up */
+      break;			/* exit loop */
+    }
+				/* final character-at-a-time scan */
+    while ((s < t) && (*s != '\n')) ++s;
+				/* difficult case if line spans buffer */
+    if ((i = s - bs->curpos) == bs->cursize) {
+				/* have space in line buffer? */
+      if (i > LOCAL->linebuflen) {
+	fs_give ((void **) &LOCAL->linebuf);
+	LOCAL->linebuf = (char *) fs_get (LOCAL->linebuflen = i);
+      }
+				/* remember what we have so far */
+      memcpy (LOCAL->linebuf,bs->curpos,i);
+				/* load next buffer */
+      SETPOS (bs,k = GETPOS (bs) + i);
+				/* end of fast scan */
+      te = (t = (s = bs->curpos) + bs->cursize) - 12;
+				/* fast scan in overlap buffer */
+      while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) {
+	--s;			/* back up */
+	break;			/* exit loop */
+      }
+
+				/* final character-at-a-time scan */
+      while ((s < t) && (*s != '\n')) ++s;
+				/* huge line? */
+      if ((j = s - bs->curpos) == bs->cursize) {
+	SETPOS (bs,GETPOS (bs) + j);
+				/* look for end of line (s-l-o-w!!) */
+	for (m = SIZE (bs); m && (SNX (bs) != '\n'); --m,++j);
+	SETPOS (bs,k);		/* go back to where it started */
+      }
+				/* got size of data, make buffer for return */
+      ret = LOCAL->line = (char *) fs_get (i + j + 2);
+				/* copy first chunk */
+      memcpy (ret,LOCAL->linebuf,i);
+      while (j) {		/* copy remainder */
+	if (!bs->cursize) SETPOS (bs,GETPOS (bs));
+	memcpy (ret + i,bs->curpos,k = min (j,bs->cursize));
+	i += k;			/* account for this much read in */
+	j -= k;
+	bs->curpos += k;	/* increment new position */
+	bs->cursize -= k;	/* eat that many bytes */
+      }
+      if (!bs->cursize) SETPOS (bs,GETPOS (bs));
+				/* read newline at end */
+      if (SIZE (bs)) ret[i++] = SNX (bs);
+      ret[i] = '\0';		/* makes debugging easier */
+    }
+    else {			/* this is easy */
+      ret = bs->curpos;		/* string it at this position */
+      bs->curpos += ++i;	/* increment new position */
+      bs->cursize -= i;		/* eat that many bytes */
+    }
+    *size = i;			/* return that to user */
+  }
+  else *size = 0;		/* end of data, return empty */
+  return ret;
+}
+
+/* UNIX make pseudo-header
+ * Accepts: MAIL stream
+ *	    buffer to write pseudo-header
+ * Returns: length of pseudo-header
+ */
+
+unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr)
+{
+  int i;
+  char *s,*t,tmp[MAILTMPLEN];
+  time_t now = time(0);
+  rfc822_fixed_date (tmp);
+  sprintf (hdr,"From %s %.24s\r\nDate: %s\r\nFrom: %s <%s@%.80s>\r\nSubject: %s\r\nMessage-ID: <%lu@%.80s>\r\nX-IMAP: %010ld %010ld",
+	   pseudo_from,ctime (&now),
+	   tmp,pseudo_name,pseudo_from,mylocalhost (),pseudo_subject,
+	   (unsigned long) now,mylocalhost (),stream->uid_validity,
+	   stream->uid_last);
+  for (t = hdr + strlen (hdr),i = 0; i < NUSERFLAGS; ++i)
+    if (stream->user_flags[i])
+      sprintf (t += strlen (t)," %s",stream->user_flags[i]);
+  strcpy (t += strlen (t),"\r\nStatus: RO\r\n\r\n");
+  for (s = pseudo_msg,t += strlen (t); *s; *t++ = *s++)
+    if (*s == '\n') *t++ = '\r';
+  *t++ = '\r'; *t++ = '\n'; *t++ = '\r'; *t++ = '\n';
+  *t = '\0';			/* tie off pseudo header */
+  return t - hdr;		/* return length of pseudo header */
+}
+
+/* UNIX make status string
+ * Accepts: MAIL stream
+ *	    destination string to write
+ *	    message cache entry
+ *	    UID to write if non-zero (else use elt->private.uid)
+ *	    non-zero flag to write UID (.LT. 0 to write UID base info too)
+ * Returns: length of string
+ */
+
+unsigned long unix_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt,
+			    unsigned long uid,long flag)
+{
+  char *t,stack[64];
+  char *s = status;
+  unsigned long n;
+  unsigned long pad = 50;
+  /* This used to use sprintf(), but thanks to certain cretinous C libraries
+     with horribly slow implementations of sprintf() I had to change it to this
+     mess.  At least it should be fast. */
+  *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't'; *s++ = 'u'; *s++ = 's';
+  *s++ = ':'; *s++ = ' ';
+  if (elt->seen) *s++ = 'R';
+				/* only write O if have a UID */
+  if (flag && (!elt->recent || LOCAL->appending)) *s++ = 'O';
+  *s++ = '\r'; *s++ = '\n';
+  *s++ = 'X'; *s++ = '-'; *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't';
+  *s++ = 'u'; *s++ = 's'; *s++ = ':'; *s++ = ' ';
+  if (elt->deleted) *s++ = 'D';
+  if (elt->flagged) *s++ = 'F';
+  if (elt->answered) *s++ = 'A';
+  if (elt->draft) *s++ = 'T';
+  *s++ = '\r'; *s++ = '\n';
+
+  *s++ = 'X'; *s++ = '-'; *s++ = 'K'; *s++ = 'e'; *s++ = 'y'; *s++ = 'w';
+  *s++ = 'o'; *s++ = 'r'; *s++ = 'd'; *s++ = 's'; *s++ = ':';
+  if (n = elt->user_flags) do {
+    *s++ = ' ';
+    for (t = stream->user_flags[find_rightmost_bit (&n)]; *t; *s++ = *t++);
+  } while (n);
+  n = s - status;		/* get size of stuff so far */
+				/* pad X-Keywords to make size constant */
+  if (n < pad) for (n = pad - n; n > 0; --n) *s++ = ' ';
+  *s++ = '\r'; *s++ = '\n';
+  if (flag) {			/* want to include UID? */
+    t = stack;
+				/* push UID digits on the stack */
+    n = uid ? uid : elt->private.uid;
+    do *t++ = (char) (n % 10) + '0';
+    while (n /= 10);
+    *s++ = 'X'; *s++ = '-'; *s++ = 'U'; *s++ = 'I'; *s++ = 'D'; *s++ = ':';
+    *s++ = ' ';
+				/* pop UID from stack */
+    while (t > stack) *s++ = *--t;
+    *s++ = '\r'; *s++ = '\n';
+  }
+				/* end of extended message status */
+  *s++ = '\r'; *s++ = '\n'; *s = '\0';
+  return s - status;		/* return size of resulting string */
+}
+
+/* Rewrite mailbox file
+ * Accepts: MAIL stream, must be critical and locked
+ *	    return pointer to number of expunged messages if want expunge
+ *	    lock file name
+ *	    expunge sequence, not deleted flag
+ * Returns: T if success and mailbox unlocked, NIL if failure
+ */
+
+#define OVERFLOWBUFLEN 8192	/* initial overflow buffer length */
+
+long unix_rewrite (MAILSTREAM *stream,unsigned long *nexp,char *lock,
+		   long flags)
+{
+  MESSAGECACHE *elt;
+  UNIXFILE f;
+  char *s;
+  struct utimbuf times;
+  long ret,flag;
+  unsigned long i,j;
+  unsigned long recent = stream->recent;
+  unsigned long size = LOCAL->pseudo ? unix_pseudo (stream,LOCAL->buf) : 0;
+  if (nexp) *nexp = 0;		/* initially nothing expunged */
+				/* calculate size of mailbox after rewrite */
+  for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs; i++) {
+    elt = mail_elt (stream,i);	/* get cache */
+    if (!(nexp && elt->deleted && (flags ? elt->sequence : T))) {
+				/* add RFC822 size of this message */
+      size += elt->private.special.text.size + elt->private.spare.data +
+	unix_xstatus (stream,LOCAL->buf,elt,NIL,flag) +
+	  elt->private.msg.text.text.size + 2;
+      flag = 1;			/* only count X-IMAPbase once */
+    }
+  }
+  if (!size) {			/* no messages and no pseudo, make one now */
+    size = unix_pseudo (stream,LOCAL->buf);
+    LOCAL->pseudo = T;
+  }
+				/* extend the file as necessary */
+  if (ret = unix_extend (stream,size)) {
+    /* Set up buffered I/O file structure
+     * curpos	current position being written through buffering
+     * filepos	current position being written physically to the disk
+     * bufpos	current position being written in the buffer
+     * protect	current maximum position that can be written to the disk
+     *		before buffering is forced
+     * The code tries to buffer so that that disk is written in multiples of
+     * OVERBLOWBUFLEN bytes.
+     */
+    f.stream = stream;		/* note mail stream */
+    f.curpos = f.filepos = 0;	/* start of file */
+    f.protect = stream->nmsgs ?	/* initial protection pointer */
+    mail_elt (stream,1)->private.special.offset : 8192;
+    f.bufpos = f.buf = (char *) fs_get (f.buflen = OVERFLOWBUFLEN);
+
+    if (LOCAL->pseudo)		/* update pseudo-header */
+      unix_write (&f,LOCAL->buf,unix_pseudo (stream,LOCAL->buf));
+				/* loop through all messages */
+    for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs;) {
+      elt = mail_elt (stream,i);/* get cache */
+				/* expunge this message? */
+      if (nexp && elt->deleted && (flags ? elt->sequence : T)) {
+				/* one less recent message */
+	if (elt->recent) --recent;
+	mail_expunged(stream,i);/* notify upper levels */
+	++*nexp;		/* count up one more expunged message */
+      }
+      else {			/* preserve this message */
+	i++;			/* advance to next message */
+	if ((flag < 0) ||	/* need to rewrite message? */
+	    elt->private.dirty ||
+	    (((unsigned long) f.curpos) != elt->private.special.offset) ||
+	    (elt->private.msg.header.text.size !=
+	     (elt->private.spare.data +
+	      unix_xstatus (stream,LOCAL->buf,elt,NIL,flag)))) {
+	  unsigned long newoffset = f.curpos;
+				/* yes, seek to internal header */
+	  lseek (LOCAL->fd,elt->private.special.offset,L_SET);
+	  read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size);
+				/* protection pointer moves to RFC822 header */
+	  f.protect = elt->private.special.offset +
+	    elt->private.msg.header.offset;
+				/* write internal header */
+	  unix_write (&f,LOCAL->buf,elt->private.special.text.size);
+				/* get RFC822 header */
+	  s = unix_header (stream,elt->msgno,&j,NIL);
+				/* in case this got decremented */
+	  elt->private.msg.header.offset = elt->private.special.text.size;
+				/* header size, sans trailing newline */
+	  if ((j < 4) || (s[j - 4] == '\r')) j -= 2;
+	  if (j != elt->private.spare.data) fatal ("header size inconsistent");
+				/* protection pointer moves to RFC822 text */
+	  f.protect = elt->private.special.offset +
+	    elt->private.msg.text.offset;
+	  unix_write (&f,s,j);	/* write RFC822 header */
+				/* write status and UID */
+	  unix_write (&f,LOCAL->buf,
+		      j = unix_xstatus (stream,LOCAL->buf,elt,NIL,flag));
+	  flag = 1;		/* only write X-IMAPbase once */
+				/* new file header size */
+	  elt->private.msg.header.text.size = elt->private.spare.data + j;
+
+				/* did text move? */
+	  if (f.curpos != f.protect) {
+				/* get message text */
+	    s = unix_text_work (stream,elt,&j,FT_INTERNAL);
+				/* can't happen it says here */
+	    if (j > elt->private.msg.text.text.size)
+	      fatal ("text size inconsistent");
+				/* new text offset, status/UID may change it */
+	    elt->private.msg.text.offset = f.curpos - newoffset;
+				/* protection pointer moves to next message */
+	    f.protect = (i <= stream->nmsgs) ?
+	      mail_elt (stream,i)->private.special.offset : (f.curpos + j + 2);
+	    unix_write (&f,s,j);/* write text */
+				/* write trailing newline */
+	    unix_write (&f,"\r\n",2);
+	  }
+	  else {		/* tie off header and status */
+	    unix_write (&f,NIL,NIL);
+				/* protection pointer moves to next message */
+	    f.protect = (i <= stream->nmsgs) ?
+	      mail_elt (stream,i)->private.special.offset : size;
+				/* locate end of message text */
+	    j = f.filepos + elt->private.msg.text.text.size;
+				/* trailing newline already there? */
+	    if (f.protect == (off_t) (j + 2)) f.curpos = f.filepos = f.protect;
+	    else {		/* trailing newline missing, write it */
+	      f.curpos = f.filepos = j;
+	      unix_write (&f,"\r\n",2);
+	    }
+	  }
+				/* new internal header offset */
+	  elt->private.special.offset = newoffset;
+	  elt->private.dirty =NIL;/* message is now clean */
+	}
+	else {			/* no need to rewrite this message */
+				/* tie off previous message if needed */
+	  unix_write (&f,NIL,NIL);
+				/* protection pointer moves to next message */
+	  f.protect = (i <= stream->nmsgs) ?
+	    mail_elt (stream,i)->private.special.offset : size;
+				/* locate end of message text */
+	  j = f.filepos + elt->private.special.text.size +
+	    elt->private.msg.header.text.size +
+	      elt->private.msg.text.text.size;
+				/* trailing newline already there? */
+	  if (f.protect == (off_t) (j + 2)) f.curpos = f.filepos = f.protect;
+	  else {		/* trailing newline missing, write it */
+	    f.curpos = f.filepos = j;
+	    unix_write (&f,"\r\n",2);
+	  }
+	}
+      }
+    }
+
+    unix_write (&f,NIL,NIL);	/* tie off final message */
+    if (size != ((unsigned long) f.filepos)) fatal ("file size inconsistent");
+    fs_give ((void **) &f.buf);	/* free buffer */
+				/* make sure tied off */
+    ftruncate (LOCAL->fd,LOCAL->filesize = size);
+    fsync (LOCAL->fd);		/* make sure the updates take */
+    if (size && (flag < 0)) fatal ("lost UID base information");
+				/* no longer dirty */
+    LOCAL->ddirty = LOCAL->dirty = NIL;
+  				/* notify upper level of new mailbox sizes */
+    mail_exists (stream,stream->nmsgs);
+    mail_recent (stream,recent);
+				/* set atime to now, mtime a second earlier */
+    times.modtime = (times.actime = time (0)) -1;
+				/* set the times, note change */
+    if (!utime (stream->mailbox,&times)) LOCAL->filetime = times.modtime;
+				/* flush the lock file */
+    unix_unlock (LOCAL->fd,stream,lock);
+  }
+  return ret;			/* return state from algorithm */
+}
+
+/* Extend UNIX mailbox file
+ * Accepts: MAIL stream
+ *	    new desired size
+ * Return: T if success, else NIL
+ */
+
+long unix_extend (MAILSTREAM *stream,unsigned long size)
+{
+  unsigned long i = (size > ((unsigned long) LOCAL->filesize)) ?
+    size - ((unsigned long) LOCAL->filesize) : 0;
+  if (i) {			/* does the mailbox need to grow? */
+    if (i > LOCAL->buflen) {	/* make sure have enough space */
+				/* this user won the lottery all right */
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get ((LOCAL->buflen = i) + 1);
+    }
+    memset (LOCAL->buf,'\0',i);	/* get a block of nulls */
+    while (T) {			/* until write successful or punt */
+      lseek (LOCAL->fd,LOCAL->filesize,L_SET);
+      if ((write (LOCAL->fd,LOCAL->buf,i) >= 0) && !fsync (LOCAL->fd)) break;
+      else {
+	long e = errno;		/* note error before doing ftruncate */
+	ftruncate (LOCAL->fd,LOCAL->filesize);
+	if (mm_diskerror (stream,e,NIL)) {
+	  fsync (LOCAL->fd);	/* user chose to punt */
+	  sprintf (LOCAL->buf,"Unable to extend mailbox: %s",strerror (e));
+	  if (!stream->silent) mm_log (LOCAL->buf,ERROR);
+	  return NIL;
+	}
+      }
+    }
+  }
+  return LONGT;
+}
+
+/* Write data to buffered file
+ * Accepts: buffered file pointer
+ *	    file data or NIL to indicate "flush buffer"
+ *	    date size (ignored for "flush buffer")
+ * Does not return until success
+ */
+
+void unix_write (UNIXFILE *f,char *buf,unsigned long size)
+{
+  unsigned long i,j,k;
+  if (buf) {			/* doing buffered write? */
+    i = f->bufpos - f->buf;	/* yes, get size of current buffer data */
+				/* yes, have space in current buffer chunk? */
+    if (j = i ? ((f->buflen - i) % OVERFLOWBUFLEN) : f->buflen) {
+				/* yes, fill up buffer as much as we can */
+      memcpy (f->bufpos,buf,k = min (j,size));
+      f->bufpos += k;		/* new buffer position */
+      f->curpos += k;		/* new current position */
+      if (j -= k) return;	/* all done if still have buffer free space */
+      buf += k;			/* full, get new unwritten data pointer */
+      size -= k;		/* new data size */
+      i += k;			/* new buffer data size */
+    }
+    /* This chunk of the buffer is full.  See if can make some space by
+     * writing to the disk, if there's enough unprotected space to do so.
+     * Try to fill out any unaligned chunk, along with any subsequent full
+     * chunks that will fit in unprotected space.
+     */
+				/* any unprotected space we can write to? */
+    if (j = min (i,f->protect - f->filepos)) {
+				/* yes, filepos not at chunk boundary? */
+      if ((k = f->filepos % OVERFLOWBUFLEN) && ((k = OVERFLOWBUFLEN - k) < j))
+	j -= k;			/* yes, and can write out partial chunk */
+      else k = 0;		/* no partial chunk to write */
+				/* if at least a chunk free, write that too */
+      if (j > OVERFLOWBUFLEN) k += j - (j % OVERFLOWBUFLEN);
+      if (k) {			/* write data if there is anything we can */
+	unix_phys_write (f,f->buf,k);
+				/* slide buffer */
+	if (i -= k) memmove (f->buf,f->buf + k,i);
+	f->bufpos = f->buf + i;	/* new end of buffer */
+      }
+    }
+
+    /* Have flushed the buffer as best as possible.  All done if no more
+     * data to write.  Otherwise, if the buffer is empty AND if the unwritten
+     * data is larger than a chunk AND the unprotected space is also larger
+     * than a chunk, then write as many chunks as we can directly from the
+     * data.  Buffer the rest, expanding the buffer as needed.
+     */
+    if (size) {			/* have more data that we need to buffer? */
+				/* can write any of it to disk instead? */
+      if ((f->bufpos == f->buf) && 
+	  ((j = min (f->protect - f->filepos,size)) > OVERFLOWBUFLEN)) {
+				/* write as much as we can right now */
+	unix_phys_write (f,buf,j -= (j % OVERFLOWBUFLEN));
+	buf += j;		/* new data pointer */
+	size -= j;		/* new data size */
+	f->curpos += j;		/* advance current pointer */
+      }
+      if (size) {		/* still have data that we need to buffer? */
+				/* yes, need to expand the buffer? */
+	if ((i = ((f->bufpos + size) - f->buf)) > f->buflen) {
+				/* note current position in buffer */
+	  j = f->bufpos - f->buf;
+	  i += OVERFLOWBUFLEN;	/* yes, grow another chunk */
+	  fs_resize ((void **) &f->buf,f->buflen = i - (i % OVERFLOWBUFLEN));
+				/* in case buffer relocated */
+	  f->bufpos = f->buf + j;
+	}
+				/* buffer remaining data */
+	memcpy (f->bufpos,buf,size);
+	f->bufpos += size;	/* new end of buffer */
+	f->curpos += size;	/* advance current pointer */
+      }
+    }
+  }
+  else {			/* flush buffer to disk */
+    unix_phys_write (f,f->buf,i = f->bufpos - f->buf);
+    f->bufpos = f->buf;		/* reset buffer */
+				/* update positions */
+    f->curpos = f->protect = f->filepos;
+  }
+}
+
+/* Physical disk write
+ * Accepts: buffered file pointer
+ *	    buffer address
+ *	    buffer size
+ * Does not return until success
+ */
+
+void unix_phys_write (UNIXFILE *f,char *buf,size_t size)
+{
+  MAILSTREAM *stream = f->stream;
+				/* write data at desired position */
+  while (size && ((lseek (LOCAL->fd,f->filepos,L_SET) < 0) ||
+		  (write (LOCAL->fd,buf,size) < 0))) {
+    int e;
+    char tmp[MAILTMPLEN];
+    sprintf (tmp,"Unable to write to mailbox: %s",strerror (e = errno));
+    mm_log (tmp,ERROR);
+    mm_diskerror (NIL,e,T);	/* serious problem, must retry */
+  }
+  f->filepos += size;		/* update file position */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/os2/unixnt.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,161 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX mail routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	20 December 1989
+ * Last Edited:	30 August 2006
+ */
+
+
+/*				DEDICATION
+ *
+ *  This file is dedicated to my dog, Unix, also known as Yun-chan and
+ * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast.  Unix
+ * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after
+ * a two-month bout with cirrhosis of the liver.
+ *
+ *  He was a dear friend, and I miss him terribly.
+ *
+ *  Lift a leg, Yunie.  Luv ya forever!!!!
+ */
+
+/* Validate line
+ * Accepts: pointer to candidate string to validate as a From header
+ *	    return pointer to end of date/time field
+ *	    return pointer to offset from t of time (hours of ``mmm dd hh:mm'')
+ *	    return pointer to offset from t of time zone (if non-zero)
+ * Returns: t,ti,zn set if valid From string, else ti is NIL
+ */
+
+#define VALID(s,x,ti,zn) {						\
+  ti = 0;								\
+  if ((*s == 'F') && (s[1] == 'r') && (s[2] == 'o') && (s[3] == 'm') &&	\
+      (s[4] == ' ')) {							\
+    for (x = s + 5; *x && *x != '\012'; x++);				\
+    if (*x) {								\
+      if (x[-1] == '\015') --x;						\
+      if (x - s >= 41) {						\
+	for (zn = -1; x[zn] != ' '; zn--);				\
+	if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') &&	\
+	    (x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') &&	\
+	    (x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') &&	\
+	    (x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))\
+	  x += zn - 12;							\
+      }									\
+      if (x - s >= 27) {						\
+	if (x[-5] == ' ') {						\
+	  if (x[-8] == ':') zn = 0,ti = -5;				\
+	  else if (x[-9] == ' ') ti = zn = -9;				\
+	  else if ((x[-11] == ' ') && ((x[-10]=='+') || (x[-10]=='-')))	\
+	    ti = zn = -11;						\
+	}								\
+	else if (x[-4] == ' ') {					\
+	  if (x[-9] == ' ') zn = -4,ti = -9;				\
+	}								\
+	else if (x[-6] == ' ') {					\
+	  if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-')))	\
+	    zn = -6,ti = -11;						\
+	}								\
+	if (ti && !((x[ti - 3] == ':') &&				\
+		    (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') &&	\
+		    (x[ti - 3] == ' ') && (x[ti - 7] == ' ') &&		\
+		    (x[ti - 11] == ' '))) ti = 0;			\
+      }									\
+    }									\
+  }									\
+}
+
+/* You are not expected to understand this macro, but read the next page if
+ * you are not faint of heart.
+ *
+ * Known formats to the VALID macro are:
+ *		From user Wed Dec  2 05:53 1992
+ * BSD		From user Wed Dec  2 05:53:22 1992
+ * SysV		From user Wed Dec  2 05:53 PST 1992
+ * rn		From user Wed Dec  2 05:53:22 PST 1992
+ *		From user Wed Dec  2 05:53 -0700 1992
+ * emacs	From user Wed Dec  2 05:53:22 -0700 1992
+ *		From user Wed Dec  2 05:53 1992 PST
+ *		From user Wed Dec  2 05:53:22 1992 PST
+ *		From user Wed Dec  2 05:53 1992 -0700
+ * Solaris	From user Wed Dec  2 05:53:22 1992 -0700
+ *
+ * Plus all of the above with `` remote from xxx'' after it. Thank you very
+ * much, smail and Solaris, for making my life considerably more complicated.
+ */
+
+/*
+ * What?  You want to understand the VALID macro anyway?  Alright, since you
+ * insist.  Actually, it isn't really all that difficult, provided that you
+ * take it step by step.
+ *
+ * Line 1	Initializes the return ti value to failure (0);
+ * Lines 2-3	Validates that the 1st-5th characters are ``From ''.
+ * Lines 4-6	Validates that there is an end of line and points x at it.
+ * Lines 7-14	First checks to see if the line is at least 41 characters long.
+ *		If so, it scans backwards to find the rightmost space.  From
+ *		that point, it scans backwards to see if the string matches
+ *		`` remote from''.  If so, it sets x to point to the space at
+ *		the start of the string.
+ * Line 15	Makes sure that there are at least 27 characters in the line.
+ * Lines 16-21	Checks if the date/time ends with the year (there is a space
+ *		five characters back).  If there is a colon three characters
+ *		further back, there is no timezone field, so zn is set to 0
+ *		and ti is set in front of the year.  Otherwise, there must
+ *		either to be a space four characters back for a three-letter
+ *		timezone, or a space six characters back followed by a + or -
+ *		for a numeric timezone; in either case, zn and ti become the
+ *		offset of the space immediately before it.
+ * Lines 22-24	Are the failure case for line 14.  If there is a space four
+ *		characters back, it is a three-letter timezone; there must be a
+ *		space for the year nine characters back.  zn is the zone
+ *		offset; ti is the offset of the space.
+ * Lines 25-28	Are the failure case for line 20.  If there is a space six
+ *		characters back, it is a numeric timezone; there must be a
+ *		space eleven characters back and a + or - five characters back.
+ *		zn is the zone offset; ti is the offset of the space.
+ * Line 29-32	If ti is valid, make sure that the string before ti is of the
+ *		form www mmm dd hh:mm or www mmm dd hh:mm:ss, otherwise
+ *		invalidate ti.  There must be a colon three characters back
+ *		and a space six or nine	characters back (depending upon
+ *		whether or not the character six characters back is a colon).
+ *		There must be a space three characters further back (in front
+ *		of the day), one seven characters back (in front of the month),
+ *		and one eleven characters back (in front of the day of week).
+ *		ti is set to be the offset of the space before the time.
+ *
+ * Why a macro?  It gets invoked a *lot* in a tight loop.  On some of the
+ * newer pipelined machines it is faster being open-coded than it would be if
+ * subroutines are called.
+ *
+ * Why does it scan backwards from the end of the line, instead of doing the
+ * much easier forward scan?  There is no deterministic way to parse the
+ * ``user'' field, because it may contain unquoted spaces!  Yes, I tested it to
+ * see if unquoted spaces were possible.  They are, and I've encountered enough
+ * evil mail to be totally unwilling to trust that ``it will never happen''.
+ */
+
+/* Build parameters */
+
+#define KODRETRY 15		/* kiss-of-death retry in seconds */
+#define LOCKTIMEOUT 5		/* lock timeout in minutes */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/os2/write.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,59 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Write data, treating partial writes as an error
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	26 May 1995
+ * Last Edited:	30 August 2006
+ */
+
+/*  The whole purpose of this unfortunate routine is to deal with DOS and
+ * certain cretinous versions of UNIX which decided that the "bytes actually
+ * written" return value from write() gave them license to use that for things
+ * that are really errors, such as disk quota exceeded, maximum file size
+ * exceeded, disk full, etc.
+ * 
+ *  BSD won't screw us this way on the local filesystem, but who knows what
+ * some NFS-mounted filesystem will do.
+ */
+
+#undef write
+
+/* Write data to file
+ * Accepts: file descriptor
+ *	    I/O vector structure
+ *	    number of vectors in structure
+ * Returns: number of bytes written if successful, -1 if failure
+ */
+
+long maxposint = (long)((((unsigned long) 1) << ((sizeof(int) * 8) - 1)) - 1);
+
+long safe_write (int fd,char *buf,long nbytes)
+{
+  long i,j;
+  if (nbytes > 0) for (i = nbytes; i; i -= j,buf += j) {
+    while (((j = write (fd,buf,(int) min (maxposint,i))) < 0) &&
+	   (errno == EINTR));
+    if (j < 0) return j;
+  }
+  return nbytes;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/tops-20/build.ctl	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,63 @@
+! ========================================================================
+! Copyright 1988-2006 University of Washington
+!
+! Licensed under the Apache License, Version 2.0 (the "License");
+! you may not use this file except in compliance with the License.
+! You may obtain a copy of the License at
+!
+!     http://www.apache.org/licenses/LICENSE-2.0
+!
+! 
+! ========================================================================
+
+! Program:	Portable C client build for TOPS-20
+!
+! Author:	Mark Crispin
+!		Networks and Distributed Computing
+!		Computing & Communications
+!		University of Washington
+!		Administration Building, AG-44
+!		Seattle, WA  98195
+!		Internet: MRC@CAC.Washington.EDU
+!
+! Date:		11 May 1989
+! Last Edited:	30 August 2006
+
+!
+! Set environment
+@DEFINE SYS: PS:<KCC-6>,SYS:
+!
+! Build c-client library
+!
+@COPY OS_T20.* OSDEP.*
+@CCX -c -m -w=note MAIL.C DUMMYT20.C IMAP4R1.C SMTP.C NNTP.C POP3.C RFC822.C MISC.C OSDEP.C FLSTRING.C SMANAGER.C NEWSRC.C NETMSG.C UTF8.C UTF8AUX.C
+!
+! Build c-client library file.  Should use MAKLIB, but MAKLIB barfs on MAIL.REL
+!
+@DELETE CCLINT.REL
+@APPEND MAIL.REL,DUMMYT20.REL,IMAP4R1.REL,SMTP.REL,NNTP.REL,POP3.REL,RFC822.REL,MISC.REL,OSDEP.REL,FLSTRING.REL,SMANAGER.REL,NEWSRC.REL,NETMSG.REL,UTF8.REL,UTF8AUX.REL CCLINT.REL
+!
+! Build MTEST library test program
+!
+@CCX -c -m -w=note MTEST.C
+@LINK
+*/SET:.HIGH.:200000
+*C:LIBCKX.REL
+*MTEST.REL
+*CCLINT.REL
+*MTEST/SAVE
+*/GO
+!
+! Build MAILUTIL
+!
+@CCX -c -m -w=note MAILUTIL.C
+@RENAME MAILUTIL.REL MUTIL.REL
+@LINK
+*/SET:.HIGH.:200000
+*C:LIBCKX.REL
+*MUTIL.REL
+*CCLINT.REL
+*MUTIL/SAVE
+*/GO
+@RESET
+@RENAME MUTIL.EXE MAILUTIL.EXE
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/tops-20/dummy.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,43 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Dummy routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	9 May 1991
+ * Last Edited:	30 August 2006
+ */
+
+/* Exported function prototypes */
+
+void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void dummy_list (MAILSTREAM *stream,char *ref,char *pat);
+void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long scan_contents (DRIVER *dtb,char *name,char *contents,
+		    unsigned long csiz,unsigned long fsiz);
+long dummy_scan_contents (char *name,char *contents,unsigned long csiz,
+			  unsigned long fsiz);
+long dummy_create (MAILSTREAM *stream,char *mailbox);
+long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode);
+long dummy_delete (MAILSTREAM *stream,char *mailbox);
+long dummy_rename (MAILSTREAM *stream,char *old,char *newname);
+char *dummy_file (char *dst,char *name);
+long dummy_canonicalize (char *tmp,char *ref,char *pat);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/tops-20/dummyt20.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,294 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Dummy routines for TOPS-20
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	13 June 1995
+ * Last Edited:	30 August 2006
+ */
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include "mail.h"
+#include "osdep.h"
+#include "dummy.h"
+#include "misc.h"
+
+/* Function prototypes */
+
+DRIVER *dummy_valid (char *name);
+void *dummy_parameters (long function,void *value);
+MAILSTREAM *dummy_open (MAILSTREAM *stream);
+void dummy_close (MAILSTREAM *stream,long options);
+long dummy_ping (MAILSTREAM *stream);
+void dummy_check (MAILSTREAM *stream);
+long dummy_expunge (MAILSTREAM *stream,char *sequence,long options);
+long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+/* Dummy routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER dummydriver = {
+  "dummy",			/* driver name */
+  DR_LOCAL|DR_MAIL,		/* driver flags */
+  (DRIVER *) NIL,		/* next driver */
+  dummy_valid,			/* mailbox is valid for us */
+  dummy_parameters,		/* manipulate parameters */
+  dummy_scan,			/* scan mailboxes */
+  dummy_list,			/* list mailboxes */
+  dummy_lsub,			/* list subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  dummy_create,			/* create mailbox */
+  dummy_delete,			/* delete mailbox */
+  dummy_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  dummy_open,			/* open mailbox */
+  dummy_close,			/* close mailbox */
+  NIL,				/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message structure */
+  NIL,				/* fetch header */
+  NIL,				/* fetch text */
+  NIL,				/* fetch message data */
+  NIL,				/* unique identifier */
+  NIL,				/* message number from UID */
+  NIL,				/* modify flags */
+  NIL,				/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  dummy_ping,			/* ping mailbox to see if still alive */
+  dummy_check,			/* check for new messages */
+  dummy_expunge,		/* expunge deleted messages */
+  dummy_copy,			/* copy messages to another mailbox */
+  dummy_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+
+				/* prototype stream */
+MAILSTREAM dummyproto = {&dummydriver};
+
+/* Dummy validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *dummy_valid (char *name)
+{
+				/* must be valid local mailbox */
+  return (name && *name && (*name != '{') && !compare_cstring (name,"INBOX")) ?
+    &dummydriver : NIL;
+}
+
+
+/* Dummy manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *dummy_parameters (long function,void *value)
+{
+  return NIL;
+}
+
+/* Dummy scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+				/* return silently */
+}
+
+
+/* Dummy list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void dummy_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+				/* return silently */
+}
+
+
+/* Dummy list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+				/* return silently */
+}
+
+/* Dummy create mailbox
+ * Accepts: mail stream
+ *	    mailbox name to create
+ *	    driver type to use
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_create (MAILSTREAM *stream,char *mailbox)
+{
+  return NIL;			/* always fails */
+}
+
+
+/* Dummy delete mailbox
+ * Accepts: mail stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return NIL;			/* always fails */
+}
+
+
+/* Mail rename mailbox
+ * Accepts: mail stream
+ *	    old mailbox name
+ *	    new mailbox name
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  return NIL;			/* always fails */
+}
+
+/* Dummy open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *dummy_open (MAILSTREAM *stream)
+{
+  char tmp[MAILTMPLEN];
+				/* OP_PROTOTYPE call or silence */
+  if (!stream || stream->silent) return NIL;
+  if (compare_cstring (stream->mailbox,"INBOX")) {
+    sprintf (tmp,"Not a mailbox: %s",stream->mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;			/* always fails */
+  }
+  if (!stream->silent) {	/* only if silence not requested */
+    mail_exists (stream,0);	/* say there are 0 messages */
+    mail_recent (stream,0);
+    stream->uid_validity = time (0);
+  }
+  stream->inbox = T;		/* note that it's an INBOX */
+  return stream;		/* return success */
+}
+
+
+/* Dummy close
+ * Accepts: MAIL stream
+ *	    options
+ */
+
+void dummy_close (MAILSTREAM *stream,long options)
+{
+				/* return silently */
+}
+
+/* Dummy ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ * No-op for readonly files, since read/writer can expunge it from under us!
+ */
+
+long dummy_ping (MAILSTREAM *stream)
+{
+  return T;
+}
+
+
+/* Dummy check mailbox
+ * Accepts: MAIL stream
+ * No-op for readonly files, since read/writer can expunge it from under us!
+ */
+
+void dummy_check (MAILSTREAM *stream)
+{
+  dummy_ping (stream);		/* invoke ping */
+}
+
+
+/* Dummy expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long dummy_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  return LONGT;
+}
+
+/* Dummy copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    options
+ * Returns: T if copy successful, else NIL
+ */
+
+long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+      mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy");
+  return NIL;
+}
+
+
+/* Dummy append message string
+ * Accepts: mail stream
+ *	    destination mailbox
+ *	    append callback function
+ *	    data for callback
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  char tmp[MAILTMPLEN];
+  sprintf (tmp,"Can't append to %s",mailbox);
+  mm_log (tmp,ERROR);		/* pass up error */
+  return NIL;			/* always fails */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/tops-20/env_t20.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,226 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Environment routines -- TOPS-20 version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Dedication:
+ * This file is dedicated with affection to the TOPS-20 operating system, which
+ * set standards for user and programmer friendliness that have still not been
+ * equaled by more `modern' operating systems.
+ * Wasureru mon ka!!!!
+ */
+
+/* c-client environment parameters */
+
+static char *myUserName = NIL;	/* user name */
+static char *myHomeDir = NIL;	/* home directory name */
+static char *myLocalHost = NIL;	/* local host name */
+static char *myNewsrc = NIL;	/* newsrc file name */
+static short no822tztext = NIL;	/* disable RFC [2]822 timezone text */
+
+
+#include "pmatch.c"		/* include wildcard pattern matcher */
+
+/* Environment manipulate parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *env_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case SET_USERNAME:
+    if (myUserName) fs_give ((void **) &myUserName);
+    myUserName = cpystr ((char *) value);
+  case GET_USERNAME:
+    ret = (void *) myUserName;
+    break;
+  case SET_HOMEDIR:
+    if (myHomeDir) fs_give ((void **) &myHomeDir);
+    myHomeDir = cpystr ((char *) value);
+  case GET_HOMEDIR:
+    ret = (void *) myHomeDir;
+    break;
+  case SET_LOCALHOST:
+    if (myLocalHost) fs_give ((void **) &myLocalHost);
+    myLocalHost = cpystr ((char *) value);
+  case GET_LOCALHOST:
+    ret = (void *) myLocalHost;
+    break;
+  case SET_NEWSRC:
+    if (myNewsrc) fs_give ((void **) &myNewsrc);
+    myNewsrc = cpystr ((char *) value);
+  case GET_NEWSRC:
+    ret = (void *) myNewsrc;
+    break;
+  case SET_DISABLE822TZTEXT:
+    no822tztext = value ? T : NIL;
+  case GET_DISABLE822TZTEXT:
+    ret = (void *) (no822tztext ? VOIDT : NIL);
+    break;
+  }
+  return ret;
+}
+
+/* Write current time in RFC 822 format
+ * Accepts: destination string
+ */
+
+void rfc822_date (char *date)
+{
+  char *s;
+  int argblk[4];
+  argblk[1] = (int) (date-1);
+  argblk[2] = -1;		/* time now */
+  argblk[3] = OT_822;		/* want RFC [2]822 format */
+  jsys (ODTIM,argblk);
+				/* suppress time zone text if desired */
+  if (no822tztext && (s = strstr (date," ("))) *s = NIL;
+}
+
+
+/* Write current time in internal format
+ * Accepts: destination string
+ */
+
+void internal_date (char *date)
+{
+  int argblk[5];
+  argblk[1] = (int) (date-1);
+  argblk[2] = -1;		/* time now */
+  argblk[3] = OT_4YR;		/* output in 4-digit year format */
+  jsys (ODTIM,argblk);
+  argblk[2] = ' ';		/* delimit with space */
+  jsys (BOUT,argblk);
+  argblk[2] = -1;		/* time now */
+  argblk[4] = 0;		/* no flags */
+  jsys (ODCNV,argblk);		/* get time zone */
+  argblk[2] = ((argblk[4] & 077000000) >> 18) * -100;
+				/* add an hour if summer time */
+  if (argblk[4] & IC_ADS) argblk[2] += 100;
+  argblk[3] = 0340005000012;
+  jsys (NOUT,argblk);
+}
+
+/* Return my user name
+ * Accepts: pointer to optional flags
+ * Returns: my user name
+ */
+
+char *myusername_full (unsigned long *flags)
+{
+  if (!myUserName) {		/* get user name if don't have it yet */
+    char tmp[MAILTMPLEN];
+    int argblk[5],i;
+    jsys (GJINF,argblk);	/* get job poop */
+    if (!(i = argblk[1])) {	/* remember user number */
+      if (flags) *flags = MU_NOTLOGGEDIN;
+      return "SYSTEM";		/* not logged in */
+    }
+    argblk[1] = (int) (tmp-1);	/* destination */
+    argblk[2] = i;		/* user number */
+    jsys (DIRST,argblk);	/* get user name string */
+    myUserName = cpystr (tmp);	/* copy user name */
+    argblk[1] = 0;		/* no flags */
+    argblk[2] = i;		/* user number */
+    argblk[3] = 0;		/* no stepping */
+    jsys (RCDIR,argblk);	/* get home directory */
+    argblk[1] = (int) (tmp-1);	/* destination */
+    argblk[2] = argblk[3];	/* home directory number */
+    jsys (DIRST,argblk);	/* get home directory string */
+    myHomeDir = cpystr (tmp);	/* copy home directory */
+    if (!myNewsrc) {		/* set news file name if not defined */
+      sprintf (tmp,"%sNEWSRC",myhomedir ());
+      myNewsrc = cpystr (tmp);
+    }
+    if (flags) *flags = MU_LOGGEDIN;
+  }
+  return myUserName;
+}
+
+/* Return my local host name
+ * Returns: my local host name
+ */
+
+char *mylocalhost ()
+{
+  if (!myLocalHost) {		/* initialize if first time */
+    char tmp[MAILTMPLEN];
+    int argblk[5];
+    argblk[1] = _GTHNS;		/* convert number to string */
+    argblk[2] = (int) (tmp-1);
+    argblk[3] = -1;		/* want local host */
+    if (!jsys (GTHST,argblk)) strcpy (tmp,"LOCAL");
+    myLocalHost = cpystr (tmp);
+  }
+  return myLocalHost;
+}
+
+
+/* Return my home directory name
+ * Returns: my home directory name
+ */
+
+char *myhomedir ()
+{
+  if (!myHomeDir) myusername ();/* initialize if first time */
+  return myHomeDir ? myHomeDir : "";
+}
+
+
+/* Determine default prototype stream to user
+ * Accepts: type (NIL for create, T for append)
+ * Returns: default prototype stream
+ */
+
+MAILSTREAM *default_proto (long type)
+{
+  return NIL;			/* no default prototype */
+}
+
+/* Emulator for BSD syslog() routine
+ * Accepts: priority
+ *	    message
+ *	    parameters
+ */
+
+void syslog (int priority,const char *message,...)
+{
+}
+
+
+/* Emulator for BSD openlog() routine
+ * Accepts: identity
+ *	    options
+ *	    facility
+ */
+
+void openlog (const char *ident,int logopt,int facility)
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/tops-20/env_t20.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,73 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	TOPS-20 environment routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	25 May 1995
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Dedication:
+ * This file is dedicated with affection to the TOPS-20 operating system, which
+ * set standards for user and programmer friendliness that have still not been
+ * equaled by more `modern' operating systems.
+ * Wasureru mon ka!!!!
+ */
+
+
+#define SUBSCRIPTIONFILE(t) sprintf (t,"%s\\SUBSCRIPTIONS.TXT",myhomedir ())
+#define SUBSCRIPTIONTEMP(t) sprintf (t,"%s\\SUBSCRIPTIONS.TMP",myhomedir ())
+
+/* Function prototypes */
+
+#include "env.h"
+
+char *myusername_full (unsigned long *flags);
+#define MU_LOGGEDIN 0
+#define MU_NOTLOGGEDIN 1
+#define MU_ANONYMOUS 2
+#define myusername() \
+  myusername_full (NIL)
+
+
+/* syslog() emulation */
+
+#define LOG_MAIL	(2<<3)	/* mail system */
+#define LOG_DAEMON	(3<<3)	/* system daemons */
+#define LOG_AUTH	(4<<3)	/* security/authorization messages */
+#define LOG_EMERG	0	/* system is unusable */
+#define LOG_ALERT	1	/* action must be taken immediately */
+#define LOG_CRIT	2	/* critical conditions */
+#define LOG_ERR		3	/* error conditions */
+#define LOG_WARNING	4	/* warning conditions */
+#define LOG_NOTICE	5	/* normal but signification condition */
+#define LOG_INFO	6	/* informational */
+#define LOG_DEBUG	7	/* debug-level messages */
+#define LOG_PID		0x01	/* log the pid with each message */
+#define LOG_CONS	0x02	/* log on the console if errors in sending */
+#define LOG_ODELAY	0x04	/* delay open until syslog() is called */
+#define LOG_NDELAY	0x08	/* don't delay open */
+#define LOG_NOWAIT	0x10	/* if forking to log on console, don't wait() */
+
+void openlog (const char *ident,int logopt,int facility);
+void syslog (int priority,const char *message,...);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/tops-20/fs_t20.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,62 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Free storage management routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Get a block of free storage
+ * Accepts: size of desired block
+ * Returns: free storage block
+ */
+
+void *fs_get (size_t size)
+{
+  void *block = malloc (size ? size : (size_t) 1);
+  if (!block) fatal ("Out of memory");
+  return (block);
+}
+
+
+/* Resize a block of free storage
+ * Accepts: ** pointer to current block
+ *	    new size
+ */
+
+void fs_resize (void **block,size_t size)
+{
+  if (!(*block = realloc (*block,size ? size : (size_t) 1)))
+    fatal ("Can't resize memory");
+}
+
+
+/* Return a block of free storage
+ * Accepts: ** pointer to free storage block
+ */
+
+void fs_give (void **block)
+{
+  free (*block);
+  *block = NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/tops-20/ftl_t20.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,38 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	DOS/VMS/TOPS-20 crash management routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Report a fatal error
+ * Accepts: string to output
+ */
+
+void fatal (char *string)
+{
+  mm_fatal (string);		/* pass up the string */
+  abort ();			/* die horribly */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/tops-20/linkage.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,37 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Default driver linkage
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	13 June 1995
+ * Last Edited:	23 May 2007
+ */
+
+  mail_link (&imapdriver);		/* link in the imap driver */
+  mail_link (&nntpdriver);		/* link in the nntp driver */
+  mail_link (&pop3driver);		/* link in the pop3 driver */
+  mail_link (&dummydriver);		/* link in the dummy driver */
+  auth_link (&auth_ext);		/* link in the ext authenticator */
+  auth_link (&auth_md5);		/* link in the md5 authenticator */
+  auth_link (&auth_pla);		/* link in the plain authenticator */
+  auth_link (&auth_log);		/* link in the log authenticator */
+  mail_versioncheck (CCLIENTVERSION);	/* validate version */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/tops-20/linkage.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,36 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Default driver linkage
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	13 June 1995
+ * Last Edited:	30 August 2006
+ */
+
+extern DRIVER imapdriver;
+extern DRIVER nntpdriver;
+extern DRIVER pop3driver;
+extern DRIVER dummydriver;
+extern AUTHENTICATOR auth_ext;
+extern AUTHENTICATOR auth_log;
+extern AUTHENTICATOR auth_md5;
+extern AUTHENTICATOR auth_pla;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/tops-20/log_t20.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,80 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	TOPS-20 server login
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Dedication:
+ * This file is dedicated with affection to the TOPS-20 operating system, which
+ * set standards for user and programmer friendliness that have still not been
+ * equaled by more `modern' operating systems.
+ * Wasureru mon ka!!!!
+ */
+
+/* Server log in
+ * Accepts: user name string
+ *	    password string
+ *	    authenticating user name string
+ *	    argument count
+ *	    argument vector
+ * Returns: T if password validated, NIL otherwise
+ */
+
+long server_login (char *user,char *pass,char *authuser,int argc,char *argv[])
+{
+  int uid;
+  int argblk[5];
+  if (authuser && *authuser) {	/* not available */
+    syslog (LOG_NOTICE|LOG_AUTH,
+	    "Login %s failed: invalid authentication ID %s host=%.80s",
+	    user,authuser,tcp_clienthost ());
+    sleep (3);
+    return NIL;
+  }
+  argblk[1] = RC_EMO;		/* require exact match */
+  argblk[2] = (int) (user-1);	/* user name */
+  argblk[3] = 0;		/* no stepping */
+  if (!jsys (RCUSR,argblk)) return NIL;
+  uid = argblk[1] = argblk[3];	/* user number */
+  argblk[2] = (int) (pass-1);	/* password */
+  argblk[3] = 0;		/* no special account */
+  if (!jsys (LOGIN,argblk)) return NIL;
+  return T;
+}
+
+
+/* Authenticated server log in
+ * Accepts: user name string
+ *	    authenticating user name string
+ *	    argument count
+ *	    argument vector
+ * Returns: T if password validated, NIL otherwise
+ */
+
+long authserver_login (char *user,char *authuser,int argc,char *argv[])
+{
+  return NIL;			/* how to implement this on TOPS-20??? */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/tops-20/nl_t20.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,61 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Windows/TOPS-20 newline routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Copy string with CRLF newlines
+ * Accepts: destination string
+ *	    pointer to size of destination string buffer
+ *	    source string
+ *	    length of source string
+ * Returns: length of copied string
+ */
+
+unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl,
+			  unsigned char *src,unsigned long srcl)
+{
+				/* flush destination buffer if too small */
+  if (*dst && (srcl > *dstl)) fs_give ((void **) dst);
+  if (!*dst) {			/* make a new buffer if needed */
+    *dst = (char *) fs_get ((size_t) (*dstl = srcl) + 1);
+    if (dstl) *dstl = srcl;	/* return new buffer length to main program */
+  }
+				/* copy strings */
+  if (srcl) memcpy (*dst,src,(size_t) srcl);
+  *(*dst + srcl) = '\0';	/* tie off destination */
+  return srcl;			/* return length */
+}
+
+
+/* Length of string after strcrlfcpy applied
+ * Accepts: source string
+ * Returns: length of string
+ */
+
+unsigned long strcrlflen (STRING *s)
+{
+  return SIZE (s);		/* no-brainer on DOS! */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/tops-20/os_t20.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,106 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- TOPS-20 version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Dedication:
+ * This file is dedicated with affection to the TOPS-20 operating system, which
+ * set standards for user and programmer friendliness that have still not been
+ * equaled by more `modern' operating systems.
+ * Wasureru mon ka!!!!
+ */
+
+#include "mail.h"
+#include <jsys.h>		/* must be before tcp_t20.h */
+#include "tcp_t20.h"		/* must be before osdep include tcp.h */
+#include <time.h>
+#include "osdep.h"
+#include <sys/time.h>
+#include "misc.h"
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <ctype.h>
+
+#include "fs_t20.c"
+#include "ftl_t20.c"
+#include "nl_t20.c"
+#include "env_t20.c"
+#include "tcp_t20.c"
+#include "log_t20.c"
+
+#define MD5ENABLE "PS:<SYSTEM>CRAM-MD5.PWD"
+#include "auth_md5.c"
+#include "auth_ext.c"
+#include "auth_pla.c"
+#include "auth_log.c"
+
+/* Emulator for UNIX gethostid() call
+ * Returns: host id
+ */
+
+long gethostid ()
+{
+  int argblk[5];
+#ifndef _APRID
+#define _APRID 28
+#endif
+  argblk[1] = _APRID;
+  jsys (GETAB,argblk);
+  return (long) argblk[1];
+}
+
+
+/* Emulator for UNIX getpass() call
+ * Accepts: prompt
+ * Returns: password
+ */
+
+#define PWDLEN 128		/* used by Linux */
+
+char *getpass (const char *prompt)
+{
+  char *s;
+  static char pwd[PWDLEN];
+  int argblk[5],mode;
+  argblk[1] = (int) (prompt-1);	/* prompt user */
+  jsys (PSOUT,argblk);
+  argblk[1] = _PRIIN;		/* get current TTY mode */
+  jsys (RFMOD,argblk);
+  mode = argblk[2];		/* save for later */
+  argblk[2] &= ~06000;
+  jsys (SFMOD,argblk);
+  jsys (STPAR,argblk);
+  fgets (pwd,PWDLEN-1,stdin);
+  pwd[PWDLEN-1] = '\0';
+  if (s = strchr (pwd,'\n')) *s = '\0';
+  putchar ('\n');
+  argblk[2] = mode;
+  jsys (SFMOD,argblk);
+  jsys (STPAR,argblk);
+  return pwd;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/tops-20/os_t20.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,52 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- TOPS-20 version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 January 2007
+ */
+
+
+/* Dedication:
+ * This file is dedicated with affection to the TOPS-20 operating system, which
+ * set standards for user and programmer friendliness that have still not been
+ * equaled by more `modern' operating systems.
+ * Wasureru mon ka!!!!
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <unistd.h>
+
+#include "env_t20.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+
+long gethostid (void);
+char *getpass (const char *prompt);
+
+#define strtok_r(a,b,c) strtok(a,b)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/tops-20/pmatch.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,89 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	IMAP Wildcard Matching Routines (case-independent)
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	15 June 2000
+ * Last Edited:	30 August 2006
+ */
+
+/* Wildcard pattern match
+ * Accepts: base string
+ *	    pattern string
+ *	    delimiter character
+ * Returns: T if pattern matches base, else NIL
+ */
+
+long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim)
+{
+  switch (*pat) {
+  case '%':			/* non-recursive */
+				/* % at end, OK if no inferiors */
+    if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T;
+                                /* scan remainder of string until delimiter */
+    do if (pmatch_full (s,pat+1,delim)) return T;
+    while ((*s != delim) && *s++);
+    break;
+  case '*':			/* match 0 or more characters */
+    if (!pat[1]) return T;	/* * at end, unconditional match */
+				/* scan remainder of string */
+    do if (pmatch_full (s,pat+1,delim)) return T;
+    while (*s++);
+    break;
+  case '\0':			/* end of pattern */
+    return *s ? NIL : T;	/* success if also end of base */
+  default:			/* match this character */
+    return compare_uchar (*pat,*s) ? NIL : pmatch_full (s+1,pat+1,delim);
+  }
+  return NIL;
+}
+
+/* Directory pattern match
+ * Accepts: base string
+ *	    pattern string
+ *	    delimiter character
+ * Returns: T if base is a matching directory of pattern, else NIL
+ */
+
+long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim)
+{
+  switch (*pat) {
+  case '%':			/* non-recursive */
+    if (!*s) return T;		/* end of base means have a subset match */
+    if (!*++pat) return NIL;	/* % at end, no inferiors permitted */
+				/* scan remainder of string until delimiter */
+    do if (dmatch (s,pat,delim)) return T;
+    while ((*s != delim) && *s++);
+    if (*s && !s[1]) return T;	/* ends with delimiter, must be subset */
+    return dmatch (s,pat,delim);/* do new scan */
+  case '*':			/* match 0 or more characters */
+    return T;			/* unconditional match */
+  case '\0':			/* end of pattern */
+    break;
+  default:			/* match this character */
+    if (*s) return compare_uchar (*pat,*s) ? NIL : dmatch (s+1,pat+1,delim);
+				/* end of base, return if at delimiter */
+    else if (*pat == delim) return T;
+    break;
+  }
+  return NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/tops-20/shortsym.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,608 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Definitions for compilers with 6-letter symbol limits
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	24 May 1995
+ * Last Edited:	1 January 2008
+ */
+
+#define auth_link a_link
+#define auth_log a_log
+#define auth_login_client al_cli
+#define auth_login_server al_ser
+#define auth_ext a_ext
+#define auth_external_client ae_cli
+#define auth_external_server ae_ser
+#define auth_md5 a_md5
+#define auth_md5_valid a5_val
+#define auth_md5_client a5_cli
+#define auth_md5_server a5_ser
+#define auth_pla a_pla
+#define auth_plain_client ap_cli
+#define auth_plain_server ap_ser
+#define authenticate a_auth
+#define authserver_login a_serv
+#define body_encodings bencds
+#define body_types btypes
+#define compare_csizedtext cm_szt
+#define compare_cstring cm_str
+#define compare_uchar cm_uch
+#define compare_ulong cm_uln
+#define default_proto d_prot
+#define dummy_append d_appn
+#define dummy_canonicalize d_cano
+#define dummy_check d_chck
+#define dummy_close d_clos
+#define dummy_copy d_copy
+#define dummy_create d_crea
+#define dummy_create_path d_crep
+#define dummy_delete d_del
+#define dummy_expunge d_exp
+#define dummy_file d_fil
+#define dummy_list d_list
+#define dummy_list_work d_lstw
+#define dummy_listed d_lstd
+#define dummy_lsub d_lsub
+#define dummy_open d_open
+#define dummy_parameters d_parm
+#define dummy_ping d_ping
+#define dummy_rename d_ren
+#define dummy_scan d_scan
+#define dummy_search d_srch
+#define dummy_subscribe d_subs
+#define dummy_valid d_val
+#define env_parameters e_parm
+#define fatal fatal
+#define file_string fl_str
+#define file_string_init fl_ini
+#define file_string_next fl_nxt
+#define file_string_setpos fl_sps
+#define fs_get f_get
+#define fs_give f_give
+#define fs_resize f_rsiz
+#define hash_create h_crea
+#define hash_destory h_dest
+#define hash_index h_indx
+#define hash_lookup h_lkup
+#define hash_add h_add
+#define hash_lookup_and_add h_lad
+#define imap_OK i_OK
+#define imap_acl_work i_aclw
+#define imap_append i_appn
+#define imap_append_single i_apps
+#define imap_anon i_anon
+#define imap_auth i_auth
+#define imap_cache i_cach
+#define imap_cap i_cap
+#define imap_capability i_capa
+#define imap_challenge i_chln
+#define imap_check i_chck
+#define imap_close i_clos
+#define imap_copy i_copy
+#define imap_create i_crea
+#define imap_delete i_del
+#define imap_deleteacl i_dacl
+#define imap_expunge i_expn
+#define imap_fake i_fake
+#define imap_fast i_fast
+#define imap_fetch i_fetc
+#define imap_flag i_flag
+#define imap_flags i_flgs
+#define imap_gc i_gc
+#define imap_gc_body ig_bdy
+#define imap_getacl i_gacl
+#define imap_getquota i_gqot
+#define imap_getquotaroot i_gqtr
+#define imap_host i_host
+#define imap_list i_list
+#define imap_listrights i_lrgh
+#define imap_list_work il_wrk
+#define imap_login i_logn
+#define imap_lsub i_lsub
+#define imap_manage i_man
+#define imap_msgdata i_msgd
+#define imap_msgno i_msgn
+#define imap_myrights i_mrgh
+#define imap_open i_open
+#define imap_parameters i_parm
+#define imap_parse_address ip_adr
+#define imap_parse_adrlist ip_adl
+#define imap_parse_astring ip_ast
+#define imap_parse_body ip_bdy
+#define imap_parse_body_parameter ipb_pa
+#define imap_parse_body_structure ipb_st
+#define imap_parse_capabilities ip_cap
+#define imap_parse_disposition ip_dsp
+#define imap_parse_envelope ip_env
+#define imap_parse_extension ip_ext
+#define imap_parse_flags ip_flg
+#define imap_parse_header ip_hdr
+#define imap_parse_language ip_lng
+#define imap_parse_namespace ip_nam
+#define imap_parse_reply ip_rep
+#define imap_parse_response ip_rsp
+#define imap_parse_string ip_str
+#define imap_parse_stringlist ip_stl
+#define imap_parse_thread ip_thr
+#define imap_parse_unsolicited ip_uns
+#define imap_parse_user_flag ipu_fl
+#define imap_ping i_ping
+#define imap_reform_sequence i_rfrs
+#define imap_rename i_ren
+#define imap_reply i_rep
+#define imap_response i_rspn
+#define imap_scan i_scan
+#define imap_search i_srch
+#define imap_send i_send
+#define imap_send_astring is_ast
+#define imap_send_literal is_lit
+#define imap_send_sdate iss_da
+#define imap_send_slist iss_sl
+#define imap_send_spgm iss_pg
+#define imap_send_spgm_trim iss_pt
+#define imap_send_sset iss_st
+#define imap_send_sset_work iss_sw
+#define imap_setacl i_sacl
+#define imap_setquota i_sqot
+#define imap_sort i_sort
+#define imap_sout i_sout
+#define imap_soutr i_sotr
+#define imap_status i_stat
+#define imap_structure i_stru
+#define imap_subscribe i_sub
+#define imap_thread i_thrd
+#define imap_thread_work i_thrw
+#define imap_uid i_uid
+#define imap_unsubscribe i_uns
+#define imap_valid i_val
+#define internal_date in_dat
+#define mail_append_full m_appn
+#define mail_append_multiple m_appm
+#define mail_append_set m_apps
+#define mail_auth m_auth
+#define mail_body m_body
+#define mail_cdate m_cdat
+#define mail_check m_chck
+#define mail_close_full m_clos
+#define mail_copy_full m_copy
+#define mail_create m_crea
+#define mail_criteria m_crit
+#define mail_criteria_date mc_dat
+#define mail_criteria_string mc_str
+#define mail_date m_date
+#define mail_debug m_dbug
+#define mail_delete m_del
+#define mail_dlog m_dlog
+#define mail_elt m_elt
+#define mail_exists m_exst
+#define mail_expunge_full m_expn
+#define mail_expunged m_expd
+#define mail_fetch_body fs_bdy
+#define mail_fetch_fast mf_fst
+#define mail_fetch_flags mf_flg
+#define mail_fetch_header mf_hdr
+#define mail_fetch_message mf_msg
+#define mail_fetch_mime mf_mim
+#define mail_fetch_overview mf_ovr
+#define mail_fetch_overview_sequence mf_ovs
+#define mail_fetch_overview_default mf_ovd
+#define mail_fetch_structure mf_str
+#define mail_fetch_text mf_txt
+#define mail_fetch_text_return mf_txr
+#define mail_fetch_string_return mf_tsr
+#define mail_fetchfrom mf_frm
+#define mail_fetchsubject mf_sub
+#define mail_filter m_filt
+#define mail_flag m_flag
+#define mail_free_acl mr_acl
+#define mail_free_address mr_add
+#define mail_free_body mr_bdy
+#define mail_free_body_data mrb_da
+#define mail_free_body_parameter mrb_pr
+#define mail_free_body_part mrb_pt
+#define mail_free_cache mr_cac
+#define mail_free_elt mr_elt
+#define mail_free_envelope mr_env
+#define mail_free_handle mr_han
+#define mail_free_namespace mr_nsp
+#define mail_free_quotalist mr_qtl
+#define mail_free_searchheader mrs_hd
+#define mail_free_searchor mrs_or
+#define mail_free_searchpgm mrs_pg
+#define mail_free_searchpgmlist mrs_pl
+#define mail_free_searchset mrs_st
+#define mail_free_sortpgm mr_spg
+#define mail_free_stringlist mr_sls
+#define mail_free_threadnode mr_thn
+#define mail_gc m_gc
+#define mail_gc_msg m_gcm
+#define mail_gc_body m_gcb
+#define mail_initbody m_ibdy
+#define mail_link m_link
+#define mail_list m_list
+#define mail_lock m_lock
+#define mail_longdate ml_lda
+#define mail_lookup_auth m_laut
+#define mail_lookup_auth_name m_latn
+#define mail_lsub m_lsub
+#define mail_makehandle m_mhdl
+#define mail_match_lines m_mlns
+#define mail_msgno m_msgn
+#define mail_newacl mn_acl
+#define mail_newaddr mn_add
+#define mail_newbody mn_bdy
+#define mail_newbody_parameter mnb_pr
+#define mail_newbody_part mnb_pt
+#define mail_newbody_message_part mnb_mp
+#define mail_new_cache_elt mn_elt
+#define mail_newenvelope mn_env
+#define mail_newmsg mn_msg
+#define mail_newquotalist mn_qtl
+#define mail_newsearchheader mns_hd
+#define mail_newsearchor mns_or
+#define mail_newsearchpgm mns_pg
+#define mail_newsearchpgmlist mns_pl
+#define mail_newsearchset mns_st
+#define mail_newsortpgm mn_spg
+#define mail_newstringlist mn_sls
+#define mail_newthreadnode mn_thr
+#define mail_nodebug m_ndbg
+#define mail_open m_open
+#define mail_parameters m_parm
+#define mail_parse_date mp_dat
+#define mail_parse_flags mp_flg
+#define mail_parse_set mp_set
+#define mail_partial_body mpt_bd
+#define mail_partial_text mpt_tx
+#define mail_ping m_ping
+#define mail_read m_read
+#define mail_recent m_rcent
+#define mail_rename m_ren
+#define mail_scan m_scan
+#define mail_search_addr ms_adr
+#define mail_search_body ms_bdy
+#define mail_search_default ms_def
+#define mail_search_full m_srch
+#define mail_search_gets ms_gts
+#define mail_search_header ms_hdr
+#define mail_search_header_text ms_hdt
+#define mail_search_keyword ms_key
+#define mail_search_msg ms_msg
+#define mail_search_string ms_str
+#define mail_search_string_work ms_stw
+#define mail_search_text ms_txt
+#define mail_sequence m_seq
+#define mail_shortdate m_shtd
+#define mail_skip_fwd msk_fw
+#define mail_skip_re msk_re
+#define mail_sort ml_srt
+#define mail_sort_cache ms_csh
+#define mail_sort_compare ms_cmp
+#define mail_sort_loadcache ms_lcs
+#define mail_sort_msgs ms_mgs
+#define mail_status m_stat
+#define mail_status_default m_stad
+#define mail_stream m_strm
+#define mail_string m_strg
+#define mail_string_init mt_ini
+#define mail_string_next mt_nxt
+#define mail_string_setpos mt_sps
+#define mail_strip_subject mst_sb
+#define mail_strip_subject_wsp mst_ws
+#define mail_strip_subject_blob mst_bl
+#define mail_subscribe m_sub
+#define mail_thread m_thr
+#define mail_threadlist mt_lst
+#define mail_thread_c2node mt_c2n
+#define mail_thread_check_child mt_ckc
+#define mail_thread_compare_date mtc_da
+#define mail_thread_loadcache mt_ldc
+#define mail_thread_msgs mt_mgs
+#define mail_thread_orderedsubject mt_osb
+#define mail_thread_parse_msgid mtp_mi
+#define mail_thread_parse_references mtp_rf
+#define mail_thread_prune_dummy mt_prd
+#define mail_thread_references mt_ref
+#define mail_thread_sort mt_srt
+#define mail_uid m_uid
+#define mail_uid_sequence mu_seq
+#define mail_unlock m_unl
+#define mail_unsubscribe m_uns
+#define mail_usable_network_stream m_usns
+#define mail_utf7_valid m_ut7v
+#define mail_valid m_val
+#define mail_valid_net mv_net
+#define mail_valid_net_parse mvn_pr
+#define mail_valid_net_parse_work mvn_pw
+#define mail_versioncheck m_vers
+#define mailboxfile mbxfil
+#define md5_init m5_ini
+#define md5_update m5_upd
+#define md5_final m5_fin
+#define mime2_decode m2_dec
+#define mime2_text m2_txt
+#define mime2_token m2_tok
+#define mm_cache mm_cac
+#define mm_critical mm_crt
+#define mm_diskerror mm_dse
+#define mm_dlog mm_dlg
+#define mm_exists mm_exs
+#define mm_expunged mm_exp
+#define mm_fatal mm_ftl
+#define mm_flags mm_flg
+#define mm_list mm_lst
+#define mm_log mm_log
+#define mm_login mm_lgi
+#define mm_lsub mm_lsb
+#define mm_mailbox mm_mbx
+#define mm_nocritical mm_ncr
+#define mm_notify mm_not
+#define mm_searched mm_src
+#define myhomedir myhome
+#define mylocalhost myhost
+#define myusername_full myuser
+#define net_aopen nt_aop
+#define net_close nt_cls
+#define net_getbuffer nt_gtb
+#define net_getdata nt_gtd
+#define net_getline nt_gtl
+#define net_host nt_hst
+#define net_localhost nt_lhs
+#define net_open nt_opn
+#define net_port nt_prt
+#define net_sout nt_sot
+#define net_soutr nt_str
+#define netmsg_read nm_rea
+#define netmsg_slurp nm_slr
+#define netmsg_slurp_text nm_slt
+#define newsrc_check_uid nsc_ui
+#define newsrc_create ns_crea
+#define newsrc_error ns_err
+#define newsrc_lsub ns_lsub
+#define newsrc_newmessages ns_nms
+#define newsrc_newstate ns_nst
+#define newsrc_read ns_rea
+#define newsrc_status ns_sta
+#define newsrc_update ns_upd
+#define newsrc_write ns_wri
+#define newsrc_write_error ns_wer
+#define nntp_append n_appn
+#define nntp_canonicalize n_cano
+#define nntp_check n_chck
+#define nntp_close n_clos
+#define nntp_copy n_copy
+#define nntp_create n_crea
+#define nntp_delete n_del
+#define nntp_expunge n_expn
+#define nntp_fake n_fake
+#define nntp_fetchfast nf_fst
+#define nntp_fetchflags nf_flg
+#define nntp_fetchmessage nf_msg
+#define nntp_flagmsg n_fmsg
+#define nntp_gc n_gc
+#define nntp_getmap n_gmap
+#define nntp_header n_head
+#define nntp_isvalid n_isvl
+#define nntp_list n_list
+#define nntp_lsub n_lsub
+#define nntp_mail n_mail
+#define nntp_mclose n_mcls
+#define nntp_mopen n_mopn
+#define nntp_open_full n_open
+#define nntp_over n_ovr
+#define nntp_overview n_over
+#define nntp_parameters n_parm
+#define nntp_parsestructure n_pars
+#define nntp_parse_overview n_povr
+#define nntp_ping n_ping
+#define nntp_rename n_ren
+#define nntp_reply n_repl
+#define nntp_scan n_scan
+#define nntp_search n_srch
+#define nntp_search_msg ns_msg
+#define nntp_send n_send
+#define nntp_send_auth ns_aut
+#define nntp_send_auth_work ns_atw
+#define nntp_send_work n_sndw
+#define nntp_sort n_sort
+#define nntp_sort_loadcache ns_lcs
+#define nntp_soutr n_sout
+#define nntp_status n_stat
+#define nntp_subscribe n_sub
+#define nntp_text n_text
+#define nntp_text_slurp nt_slp
+#define nntp_thread n_thrd
+#define nntp_unsubscribe n_uns
+#define nntp_valid n_val
+#define pop3_append p_appn
+#define pop3_auth p_auth
+#define pop3_cache p_cach
+#define pop3_challenge p_chal
+#define pop3_check p_chck
+#define pop3_close p_clos
+#define pop3_copy p_copy
+#define pop3_create p_crea
+#define pop3_delete p_del
+#define pop3_expunge p_exp
+#define pop3_fake p_fake
+#define pop3_fetchfast pf_fst
+#define pop3_fetchflags pf_flg
+#define pop3_fetchmessage pf_msg
+#define pop3_gc p_gc
+#define pop3_list p_list
+#define pop3_lsub p_lsub
+#define pop3_open p_open
+#define pop3_parameters p_parm
+#define pop3_parsestructure p_pars
+#define pop3_ping p_ping
+#define pop3_rename p_ren
+#define pop3_reply p_rep
+#define pop3_response p_resp
+#define pop3_scan p_scan
+#define pop3_send p_send
+#define pop3_send_num ps_num
+#define pop3_status p_stat
+#define pop3_subscribe p_sub
+#define pop3_unsubscribe p_uns
+#define pop3_valid p_val
+#define rfc822_8bit r
+#define rfc822_address r_addr
+#define rfc822_address_line ra_lin
+#define rfc822_base64 r_b64
+#define rfc822_binary r_bin
+#define rfc822_cat r_cat
+#define rfc822_contents r_cont
+#define rfc822_cpy r_cpy
+#define rfc822_cpy_adr rc_adr
+#define rfc822_date r_date
+#define rfc822_default_subtype rd_sub
+#define rfc822_encode_body_7bit reb_7b
+#define rfc822_encode_body_8bit reb_8b
+#define rfc822_header r_head
+#define rfc822_header_line rh_lin
+#define rfc822_output r_out
+#define rfc822_output_address ro_adr
+#define rfc822_output_address_line roa_ln
+#define rfc822_output_address_list roa_li
+#define rfc822_output_body ro_bdy
+#define rfc822_output_body_header rob_hd
+#define rfc822_output_full ro_ful
+#define rfc822_output_flush ro_flu
+#define rfc822_output_header ro_hdr
+#define rfc822_output_header_line roh_ln
+#define rfc822_output_cat ro_cat
+#define rfc822_output_parameter ro_par
+#define rfc822_output_stringlist ro_stl
+#define rfc822_output_text ro_txt
+#define rfc822_parse_address rp_adr
+#define rfc822_parse_addrspec rp_ads
+#define rfc822_parse_adrlist rp_adl
+#define rfc822_parse_content rp_cnt
+#define rfc822_parse_content_header rpc_hd
+#define rfc822_parse_group rp_grp
+#define rfc822_parse_mailbox rp_mbx
+#define rfc822_parse_msg_full rp_msg
+#define rfc822_parse_parameter rp_par
+#define rfc822_parse_phrase rp_phr
+#define rfc822_parse_routeaddr rp_rte
+#define rfc822_parse_word rp_wrd
+#define rfc822_phraseonly r_poly
+#define rfc822_qprint r_qpnt
+#define rfc822_quote r_quot
+#define rfc822_skip_comment rs_cmt
+#define rfc822_skipws rs_ws
+#define rfc822_timezone r_tz
+#define rfc822_write_address_full rw_adr
+#define rfc822_write_body_header rwbh_8
+#define server_input_wait s_iwat
+#define server_login s_log
+#define server_init s_init
+#define sm_read sm_rd
+#define sm_subscribe sm_sub
+#define sm_unsubscribe sm_uns
+#define smtp_auth s_auth
+#define smtp_challenge s_chal
+#define smtp_close s_clos
+#define smtp_ehlo s_ehlo
+#define smtp_fake s_fake
+#define smtp_mail s_mail
+#define smtp_open_full s_open
+#define smtp_rcpt s_rcpt
+#define smtp_reply s_repl
+#define smtp_response s_resp
+#define smtp_send s_send
+#define smtp_send_auth ss_aut
+#define smtp_send_auth_work ss_atw
+#define smtp_send_work ss_wrk
+#define smtp_soutr s_str
+#define strcrlfcpy sc_cpy
+#define strcrlflen sc_len
+#define tcp_aopen t_aopn
+#define tcp_canonical t_cnon
+#define tcp_clientaddr t_cadr
+#define tcp_clienthost t_chst
+#define tcp_clientport t_cprt
+#define tcp_close t_clos
+#define tcp_getbuffer tg_buf
+#define tcp_getdata tg_dat
+#define tcp_getline tg_lin
+#define tcp_host t_host
+#define tcp_localhost t_lhst
+#define tcp_open t_open
+#define tcp_parameters t_parameters
+#define tcp_port t_port
+#define tcp_remotehost t_rhst
+#define tcp_serveraddr t_sadr
+#define tcp_serverhost t_shst
+#define tcp_serverport t_sprt
+#define tcp_sout t_sout
+#define tcp_soutr t_str
+#define textcpy txcopy
+#define textcpystring txcpst
+#define textcpyoffstring txcpos
+#define ucs4_cs_get u4_csg
+#define ucs4_decompose u4_dcm
+#define ucs4_decompose_recursive u4_dcr
+#define ucs4_rmapbuf u4r_bf
+#define ucs4_rmaplen u4r_ln
+#define ucs4_rmaptext u4r_tx
+#define ucs4_titlecase u4_tcs
+#define ucs4_width u4_wid
+#define utf8_badcharset u8_bcs
+#define utf8_charset u8_chs
+#define utf8_cstext u8_cst
+#define utf8_cstocstext u8_cct
+#define utf8_from_mutf7 u8fmu7
+#define utf8_get u8_get
+#define utf8_get_raw u8_gtr
+#define utf8_iso2022text u8_i22
+#define utf8_mime2text u8_mi2
+#define utf8_put u8_put
+#define utf8_rmap u8_rmp
+#define utf8_rmap_cs u8r_cs
+#define utf8_rmap_gen u8r_gn
+#define utf8_rmapsize u8r_sz
+#define utf8_rmaptext u8r_tx
+#define utf8_script u8_scr
+#define utf8_searchpgm u8_spg
+#define utf8_size u8_siz
+#define utf8_stringlist u8_lst
+#define utf8_text u8_txt
+#define utf8_text_2022 u8t_22
+#define utf8_text_8859_1 u8t_we
+#define utf8_text_1byte0 u8t_10
+#define utf8_text_1byte u8t_1b
+#define utf8_text_1byte8 u8t_18
+#define utf8_text_cs ut8_cs
+#define utf8_text_euc u8t_eu
+#define utf8_text_dbyte u8t_db
+#define utf8_text_dbyte2 u8t_d2
+#define utf8_text_sjis u8t_sj
+#define utf8_text_ucs2 u8t_u2
+#define utf8_text_ucs4 ut8_u4
+#define utf8_text_utf7 ut8_u7
+#define utf8_text_utf8 ut8_u8
+#define utf8_text_utf16 ut8_16
+#define utf8_to_mutf7 u8tmu7
+#define utf8_validate u8_val
+#define utf8_textwidth u8_twd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/tops-20/tcp_t20.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,365 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	TOPS-20 TCP/IP routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	13 January 2008
+ */
+
+
+/* Dedication:
+ * This file is dedicated with affection to the TOPS-20 operating system, which
+ * set standards for user and programmer friendliness that have still not been
+ * equaled by more `modern' operating systems.
+ * Wasureru mon ka!!!!
+ */
+
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+			       long *contd);
+
+/* TCP/IP manipulate parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *tcp_parameters (long function,void *value)
+{
+  return NIL;
+}
+
+/* TCP/IP open
+ * Accepts: host name
+ *	    contact service name
+ *	    contact port number
+ * Returns: TCP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
+{
+  char *s,tmp[MAILTMPLEN];
+  TCPSTREAM *stream = NIL;
+  int argblk[5],jfn;
+  unsigned long i,j,k,l;
+  char file[MAILTMPLEN];
+  port &= 0xffff;		/* erase flags */
+				/* domain literal? */
+  if (host[0] == '[' && host[strlen (host)-1] == ']') {
+    if (((i = strtoul (s = host+1,&s,10)) <= 255) && *s++ == '.' &&
+	((j = strtoul (s,&s,10)) <= 255) && *s++ == '.' &&
+	((k = strtoul (s,&s,10)) <= 255) && *s++ == '.' &&
+	((l = strtoul (s,&s,10)) <= 255) && *s++ == ']' && !*s) {
+      argblk[3] = (i << 24) + (j << 16) + (k << 8) + l;
+      sprintf (tmp,"[%lu.%lu.%lu.%lu]",i,j,k,l);
+    }
+    else {
+      sprintf (tmp,"Bad format domain-literal: %.80s",host);
+      mm_log (tmp,ERROR);
+      return NIL;
+    }
+  }
+  else {			/* host name */
+    argblk[1] = _GTHPN;		/* get IP address and primary name */
+    argblk[2] = (int) (host-1);	/* pointer to host */
+    argblk[4] = (int) (tmp-1);
+    if (!jsys (GTHST,argblk)) {	/* first try DEC's domain way */
+      argblk[1] = _GTHPN;	/* get IP address and primary name */
+      argblk[2] = (int) (host-1);
+      argblk[4] = (int) (tmp-1);
+      if (!jsys (GTDOM,argblk)){/* try the CHIVES domain way */
+	argblk[1] = _GTHSN;	/* failed, do the host table then */
+	if (!jsys (GTHST,argblk)) {
+	  sprintf (tmp,"No such host as %s",host);
+	  mm_log (tmp,ERROR);
+	  return NIL;
+	}
+	argblk[1] = _GTHNS;	/* convert number to string */
+	argblk[2] = (int) (tmp-1);
+				/* get the official name */
+	if (!jsys (GTHST,argblk)) strcpy (tmp,host);
+      }
+    }
+  }
+
+  sprintf (file,"TCP:.%o-%d;PERSIST:30;CONNECTION:ACTIVE",argblk[3],port);
+  argblk[1] = GJ_SHT;		/* short form GTJFN% */
+  argblk[2] = (int) (file-1);	/* pointer to file name */
+				/* get JFN for TCP: file */
+  if (!jsys (GTJFN,argblk)) fatal ("Unable to create TCP JFN");
+  jfn = argblk[1];		/* note JFN for later */
+				/* want 8-bit bidirectional I/O */
+  argblk[2] = OF_RD|OF_WR|(FLD (8,monsym("OF%BSZ")));
+  if (!jsys (OPENF,argblk)) {
+    sprintf (file,"Can't connect to %s,%d server",tmp,port);
+    mm_log (file,ERROR);
+    return NIL;
+  }
+				/* create TCP/IP stream */
+  stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
+  stream->host = cpystr (tmp);	/* copy official host name */
+  argblk[1] = _GTHNS;		/* convert number to string */
+  argblk[2] = (int) (tmp-1);
+  argblk[3] = -1;		/* want local host */
+  if (!jsys (GTHST,argblk)) strcpy (tmp,"LOCAL");
+  stream->localhost = cpystr (tmp);
+  stream->port = port;		/* save port number */
+  stream->jfn = jfn;		/* init JFN */
+  return stream;
+}
+
+/* TCP/IP authenticated open
+ * Accepts: NETMBX specifier
+ *	    service name
+ *	    returned user name buffer
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
+{
+  return NIL;
+}
+
+/* TCP receive line
+ * Accepts: TCP stream
+ * Returns: text line string or NIL if failure
+ */
+
+char *tcp_getline (TCPSTREAM *stream)
+{
+  unsigned long n,contd;
+  char *ret = tcp_getline_work (stream,&n,&contd);
+  if (ret && contd) {		/* got a line needing continuation? */
+    STRINGLIST *stl = mail_newstringlist ();
+    STRINGLIST *stc = stl;
+    do {			/* collect additional lines */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+      stc = stc->next = mail_newstringlist ();
+      ret = tcp_getline_work (stream,&n,&contd);
+    } while (ret && contd);
+    if (ret) {			/* stash final part of line on list */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+				/* determine how large a buffer we need */
+      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
+      ret = fs_get (n + 1);	/* copy parts into buffer */
+      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
+	memcpy (ret + n,stc->text.data,stc->text.size);
+      ret[n] = '\0';
+    }
+    mail_free_stringlist (&stl);/* either way, done with list */
+  }
+  return ret;
+}
+
+/* TCP receive line or partial line
+ * Accepts: TCP stream
+ *	    pointer to return size
+ *	    pointer to return continuation flag
+ * Returns: text line string, size and continuation flag, or NIL if failure
+ */
+
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+			       long *contd)
+{
+  int argblk[5];
+  unsigned long n,m;
+  char *ret,*stp,*st;
+  *contd = NIL;			/* assume no continuation */
+  argblk[1] = stream->jfn;	/* read from TCP */
+				/* pointer to buffer */
+  argblk[2] = (int) (stream->ibuf - 1);
+  argblk[3] = BUFLEN;		/* max number of bytes to read */
+  argblk[4] = '\012';		/* terminate on LF */
+  if (!jsys (SIN,argblk)) return NIL;
+  n = BUFLEN - argblk[3];	/* number of bytes read */
+				/* got a complete line? */
+  if ((stream->ibuf[n - 2] == '\015') && (stream->ibuf[n - 1] == '\012')) {
+    memcpy ((ret = (char *) fs_get (n)),stream->ibuf,*size = n - 2);
+    ret[n - 2] = '\0';		/* tie off string with null */
+    return ret;
+  }
+				/* copy partial string */
+  memcpy ((ret = (char *) fs_get (n)),stream->ibuf,*size = n);
+				/* special case of newline broken by buffer */
+  if ((stream->ibuf[n - 1] == '\015') && jsys (BIN,argblk) &&
+      (argblk[2] == '\012')) {	/* was it? */
+    ret[n - 1] = '\0';		/* tie off string with null */
+  }
+				/* otherwise back up */
+  else if (!jsys (BKJFN,argblk)) fs_give ((void **) &ret);
+  else *contd = LONGT;		/* continuation needed */
+  return ret;
+}
+
+/* TCP/IP receive buffer
+ * Accepts: TCP/IP stream
+ *	    size in bytes
+ *	    buffer to read into
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
+{
+  int argblk[5];
+  argblk[1] = stream->jfn;	/* read from TCP */
+  argblk[2] = (int) (buffer-1);	/* pointer to buffer */
+  argblk[3] = -size;		/* number of bytes to read */
+  if (!jsys (SIN,argblk)) return NIL;
+  buffer[size] = '\0';		/* tie off text */
+  return T;
+}
+
+
+/* TCP/IP send string as record
+ * Accepts: TCP/IP stream
+ *	    string pointer
+ * Returns: T if success else NIL
+ */
+
+long tcp_soutr (TCPSTREAM *stream,char *string)
+{
+  int argblk[5];
+  argblk[1] = stream->jfn;	/* write to TCP */
+  argblk[2] = (int) (string-1);	/* pointer to buffer */
+  argblk[3] = 0;		/* write until NUL */
+  if (!jsys (SOUTR,argblk)) return NIL;
+  return T;
+}
+
+
+/* TCP/IP send string
+ * Accepts: TCP/IP stream
+ *	    string pointer
+ *	    byte count
+ * Returns: T if success else NIL
+ */
+
+long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
+{
+  int argblk[5];
+  argblk[1] = stream->jfn;	/* write to TCP */
+  argblk[2] = (int) (string-1);	/* pointer to buffer */
+  argblk[3] = -size;		/* write this many bytes */
+  if (!jsys (SOUTR,argblk)) return NIL;
+  return T;
+}
+
+/* TCP/IP close
+ * Accepts: TCP/IP stream
+ */
+
+void tcp_close (TCPSTREAM *stream)
+{
+  int argblk[5];
+  argblk[1] = stream->jfn;	/* close TCP */
+  jsys (CLOSF,argblk);
+				/* flush host names */
+  fs_give ((void **) &stream->host);
+  fs_give ((void **) &stream->localhost);
+  fs_give ((void **) &stream);	/* flush the stream */
+}
+
+
+/* TCP/IP return host for this stream
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_host (TCPSTREAM *stream)
+{
+  return stream->host;		/* return host name */
+}
+
+
+/* TCP/IP return remote host for this stream
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_remotehost (TCPSTREAM *stream)
+{
+  return stream->host;		/* return host name */
+}
+
+
+/* TCP/IP return port for this stream
+ * Accepts: TCP/IP stream
+ * Returns: port number for this stream
+ */
+
+unsigned long tcp_port (TCPSTREAM *stream)
+{
+  return stream->port;		/* return port number */
+}
+
+
+/* TCP/IP return local host for this stream
+ * Accepts: TCP/IP stream
+ * Returns: local host name for this stream
+ */
+
+char *tcp_localhost (TCPSTREAM *stream)
+{
+  return stream->localhost;	/* return local host name */
+}
+
+/* TCP/IP return canonical form of host name
+ * Accepts: host name
+ * Returns: canonical form of host name
+ */
+
+char *tcp_canonical (char *name)
+{
+  int argblk[5];
+  static char tmp[MAILTMPLEN];
+				/* look like domain literal? */
+  if (name[0] == '[' && name[strlen (name) - 1] == ']') return name;
+  argblk[1] = _GTHPN;		/* get IP address and primary name */
+  argblk[2] = (int) (name-1);	/* pointer to host */
+  argblk[4] = (int) (tmp-1);	/* pointer to return destination */
+  if (!jsys (GTHST,argblk)) {	/* first try DEC's domain way */
+    argblk[1] = _GTHPN;		/* get IP address and primary name */
+    argblk[2] = (int) (name-1);
+    argblk[4] = (int) (tmp-1);
+    if (!jsys (GTDOM,argblk)) {	/* try the CHIVES domain way */
+      argblk[1] = _GTHSN;	/* failed, do the host table then */
+      if (!jsys (GTHST,argblk)) return name;
+      argblk[1] = _GTHNS;	/* convert number to string */
+      argblk[2] = (int) (tmp-1);
+				/* get the official name */
+      if (!jsys (GTHST,argblk)) return name;
+    }
+  }
+  return tmp;
+}
+
+
+/* TCP/IP get client host name (server calls only)
+ * Returns: client host name
+ */
+
+char *tcp_clienthost ()
+{
+  return "UNKNOWN";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/tops-20/tcp_t20.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,65 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	TOPS-20 TCP/IP routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Dedication:
+ * This file is dedicated with affection to the TOPS-20 operating system, which
+ * set standards for user and programmer friendliness that have still not been
+ * equaled by more `modern' operating systems.
+ * Wasureru mon ka!!!!
+ */
+
+/* TCP input buffer */
+
+#define BUFLEN 8192
+
+/* TCP I/O stream (must be before osdep.h is included) */
+
+#define TCPSTREAM struct tcp_stream
+TCPSTREAM {
+  char *host;			/* host name */
+  unsigned long port;		/* port number */
+  char *localhost;		/* local host name */
+  int jfn;			/* jfn for connection */
+  char ibuf[BUFLEN];		/* input buffer */
+};
+
+
+/* All of these should be in JSYS.H, but just in case... */
+
+#ifndef _GTHPN
+#define _GTHPN 12
+#endif
+
+#ifndef _GTDPN
+#define _GTDPN 12
+#endif
+
+#ifndef GTDOM
+#define GTDOM (FLD (1,JSYS_CLASS) | 501
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/Makefile	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1070 @@
+# ========================================================================
+# Copyright 1988-2007 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+# Program:	C client makefile
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		11 May 1989
+# Last Edited:	17 December 2007
+
+
+# Command line build parameters
+
+EXTRAAUTHENTICATORS=
+EXTRADRIVERS=mbox
+PASSWDTYPE=std
+SSLTYPE=nopwd
+IP=4
+
+
+# The optimization level here for GCC ports is set here for a reason.  It's
+# to get you to read this text.
+# The general concensus seems to be that -O2 is the one to use.
+# Over the years, I've been told to use many different settings, including -O6.
+# In recent versions of GCC [as of 2/2005], -O6 generates bad code that, among
+# other ill effects, causes infinite loops.
+# -O3 seems to be safe, but empirical observation from our local expert
+# indicates that in some (many?) cases -O3 code runs slower than -O2.
+
+GCCOPTLEVEL= -O2
+
+
+# Try to have some consistency in GCC builds.  We want optimization, but we
+# also want to be able to debug.
+
+GCCCFLAGS= -g $(GCCOPTLEVEL) -pipe -fno-omit-frame-pointer
+GCC4CFLAGS= $(GCCCFLAGS) -Wno-pointer-sign
+
+
+# Extended flags needed for SSL.  You may need to modify.
+
+SSLDIR=/usr/local/ssl
+SSLCERTS=$(SSLDIR)/certs
+SSLKEYS=$(SSLCERTS)
+SSLINCLUDE=$(SSLDIR)/include
+SSLLIB=$(SSLDIR)/lib
+
+SSLCRYPTO=-lcrypto
+
+# Older versions of MIT Kerberos also have a libcrypto.  If so, you may need
+# to use this instead
+#SSLCRYPTO=$(SSLLIB)/libcrypto.a
+
+# RSA Security Inc. released the RSA public key encryption algorithm into
+# the public domain on September 6, 2000.  There is no longer any need to
+# use RSAREF.
+SSLRSA= # -lRSAglue -lrsaref
+
+SSLCFLAGS= -I$(SSLINCLUDE) -I$(SSLINCLUDE)/openssl\
+ -DSSL_CERT_DIRECTORY=\"$(SSLCERTS)\" -DSSL_KEY_DIRECTORY=\"$(SSLKEYS)\"
+SSLLDFLAGS= -L$(SSLLIB) -lssl $(SSLCRYPTO) $(SSLRSA)
+
+
+# Extended flags needed for non-standard passwd types.  You may need to modify.
+
+AFSDIR=/usr/afsws
+AFSCFLAGS=-I$(AFSDIR)/include
+AFSLIB=$(AFSDIR)/lib
+AFSLDFLAGS=-L$(AFSLIB)/afs -L$(AFSLIB) -L$(AFSDIR)/domestic/lib\
+ -lkauth -lprot -lubik -lauth -lrxkad -lrx -llwp -ldes -lcom_err\
+ $(AFSLIB)/afs/util.a -laudit -lsys
+# AFSLDFLAGS may also need -L/usr/ucblib -lucb
+DCECFLAGS= -DDCE_MINIMAL -DPASSWD_OVERRIDE=\"/opt/pop3/passwd/passwd\"
+DCELDFLAGS= -ldce
+PAMLDFLAGS= -lpam -ldl
+
+
+# Build parameters normally set by the individual port
+
+CHECKPW=std
+LOGINPW=std
+SIGTYPE=bsd
+CRXTYPE=std
+ACTIVEFILE=/usr/lib/news/active
+SPOOLDIR=/usr/spool
+MAILSPOOL=$(SPOOLDIR)/mail
+NEWSSPOOL=$(SPOOLDIR)/news
+RSHPATH=/usr/ucb/rsh
+MD5PWD=/etc/cram-md5.pwd
+# Tries one of the test alternatives below if not specified.
+LOCKPGM=
+# Test alternatives if LOCKPGM not specified
+LOCKPGM1=/usr/libexec/mlock
+LOCKPGM2=/usr/sbin/mlock
+LOCKPGM3=/etc/mlock
+
+
+# Default formats for creating new mailboxes and for empty mailboxes in the
+# default namespace; must be set to the associated driver's prototype.
+#
+# The CREATEPROTO is the default format for new mailbox creation.
+# The EMPTYPROTO is the default format for handling zero-byte files.
+#
+# Normally, this is set by the individual port.
+#
+# NOTE: namespace formats (e.g. mh and news) can not be set as a default format
+# since they do not exist in the default namespace.  Also, it is meaningless to
+# set certain other formats (e.g. mbx, mx, and mix) as the EMPTYPROTO since
+# these formats can never be empty files.
+
+CREATEPROTO=unixproto
+EMPTYPROTO=unixproto
+
+
+# Commands possibly overriden by the individual port
+
+ARRC=ar rc
+CC=cc
+LN=ln -s
+RANLIB=ranlib
+
+
+# Standard distribution build parameters
+
+DEFAULTAUTHENTICATORS=ext md5 pla log
+#
+# mh needs to be after any other directory format drivers (such as mx or mix)
+# since otherwise mh will seize any directory that is under the mh path.
+# However, mh needs to be before any sysinbox formats (such as mmdf or unix)
+# since otherwise INBOX won't work correctly when mh_allow_inbox is set.
+#
+DEFAULTDRIVERS=imap nntp pop3 mix mx mbx tenex mtx mh mmdf unix news phile
+CHUNKSIZE=65536
+
+# Normally no need to change any of these
+
+ARCHIVE=c-client.a
+BINARIES=osdep.o mail.o misc.o newsrc.o smanager.o utf8.o utf8aux.o siglocal.o \
+ dummy.o pseudo.o netmsg.o flstring.o fdstring.o \
+ rfc822.o nntp.o smtp.o imap4r1.o pop3.o \
+ unix.o mbx.o mmdf.o tenex.o mtx.o news.o phile.o mh.o mx.o mix.o
+CFLAGS=-g
+
+CAT=cat
+MAKE=make
+MV=mv
+RM=rm -rf
+SH=sh
+
+
+# Primary build command
+
+BUILD=$(MAKE) build EXTRACFLAGS='$(EXTRACFLAGS)'\
+ EXTRALDFLAGS='$(EXTRALDFLAGS)'\
+ EXTRADRIVERS='$(EXTRADRIVERS)' EXTRAAUTHENTICATORS='$(EXTRAAUTHENTICATORS)'\
+ PASSWDTYPE=$(PASSWDTYPE) SSLTYPE=$(SSLTYPE) IP=$(IP)
+
+
+# Here if no make argument established
+
+missing: osdep.h
+	$(MAKE) all `$(CAT) SPECIALS`
+
+osdep.h:
+	@echo You must specify what type of system
+	@false
+
+
+# Current ports
+
+a32:	# AIX 3.2 for RS/6000
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 SIGTYPE=psx CRXTYPE=nfs \
+	 SPOOLDIR=/var/spool \
+	 RSHPATH=/usr/bin/rsh \
+	 BASECFLAGS="-g -Dunix=1 -D_BSD" \
+	 BASELDFLAGS="-lbsd"
+
+a41:	# AIX 4.1 for RS/6000
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 SIGTYPE=psx CHECKPW=a41 CRXTYPE=nfs \
+	 SPOOLDIR=/var/spool \
+	 RSHPATH=/usr/bin/rsh \
+	 BASECFLAGS="-g -Dunix=1 -D_BSD -qro -qroconst" \
+	 BASELDFLAGS="-ls"
+
+aix:	# AIX/370
+	@echo You are building for AIX on an S/370 class machine
+	@echo If you want AIX on an RS/6000 you need to use a32 or a41 instead!
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 CRXTYPE=nfs \
+	 BASECFLAGS="-g" \
+	 BASELDFLAGS="-lbsd"
+
+aos:	# AOS for RT
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 CRXTYPE=nfs \
+	 BASECFLAGS="-g -Dconst="
+
+art:	# AIX 2.2.1 for RT
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 SIGTYPE=sv4 \
+	 SPOOLDIR=/var \
+	 ACTIVEFILE=/usr/local/news/control/active \
+	 RSHPATH=/bin/rsh \
+	 BASECFLAGS="-g -Dconst= -Dvoid=char" \
+	 RANLIB=true 
+
+asv:	# Altos SVR4
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 SIGTYPE=sv4 LOGINPW=old \
+	 ACTIVEFILE=/usr/spool/news/active \
+	 RSHPATH=/usr/bin/rcmd \
+	 BASECFLAGS="-Dconst= -DSIGSTOP=SIGKILL" \
+	 BASELDFLAGS="-lsocket -lrpc -lgen -lcrypt -lxenix" \
+	 RANLIB=true
+
+aux:	# A/UX
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 CRXTYPE=nfs \
+	 MAILSPOOL=/usr/mail \
+	 BASECFLAGS="-g -B/usr/lib/big/ -Dvoid=char -Dconst=" \
+	 RANLIB=true ARRC="ar -rc"
+
+bs3:	# BSD/i386 3.0 or higher
+	$(BUILD) `$(CAT) SPECIALS` OS=bsi \
+	 CHECKPW=bsi LOGINPW=bsi CRXTYPE=nfs \
+	 SPOOLDIR=/var NEWSSPOOL=/var/news/spool \
+	 ACTIVEFILE=/var/news/etc/active \
+	 RSHPATH=/usr/bin/rsh \
+	 BASECFLAGS="$(GCCCFLAGS)" CC=shlicc
+
+bsd:	# BSD UNIX
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 CRXTYPE=nfs \
+	 BASECFLAGS="-g -Dconst="
+
+bsf:	# FreeBSD
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 SIGTYPE=psx CRXTYPE=nfs \
+	 SPOOLDIR=/var \
+	 ACTIVEFILE=/usr/local/news/lib/active \
+	 RSHPATH=/usr/bin/rsh \
+	 BASECFLAGS="$(GCCCFLAGS)" \
+	 BASELDFLAGS="-lcrypt"
+
+bsi:	# BSD/i386
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 CRXTYPE=nfs \
+	 SPOOLDIR=/var NEWSSPOOL=/var/news/spool \
+	 ACTIVEFILE=/var/news/etc/active \
+	 RSHPATH=/usr/bin/rsh \
+	 BASECFLAGS="$(GCCCFLAGS)"
+
+bso:	# OpenBSD
+	$(BUILD) `$(CAT) SPECIALS` OS=bsi \
+	 SIGTYPE=psx CRXTYPE=nfs \
+	 SPOOLDIR=/var \
+	 ACTIVEFILE=/usr/local/news/lib/active \
+	 RSHPATH=/usr/bin/rsh \
+	 BASECFLAGS="$(GCCCFLAGS)"
+
+cvx:	# Convex
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 CRXTYPE=nfs \
+	 BASECFLAGS="-O -ext -Dconst="
+
+cyg:	# Cygwin - note that most local file drivers don't work!!
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	DEFAULTDRIVERS="imap nntp pop3 mbx unix phile" \
+	SIGTYPE=psx CHECKPW=cyg LOGINPW=cyg CRXTYPE=std \
+	SPOOLDIR=/var \
+	ACTIVEFILE=/usr/local/news/lib/active \
+	RSHPATH=/usr/bin/rsh \
+	BASECFLAGS="$(GCCCFLAGS)" \
+	BASELDFLAGS="-lcrypt" \
+	CC=gcc
+
+d-g:	# Data General DG/UX
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 SIGTYPE=sv4 CRXTYPE=nfs \
+	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
+	 ACTIVEFILE=/local/news/active \
+	 RSHPATH=/usr/bin/remsh \
+	 BASECFLAGS="-g -Dconst=" \
+	 BASELDFLAGS="-lnsl -lsocket" \
+	 RANLIB=true
+
+d54:	# Data General DG/UX 5.4
+	$(BUILD) `$(CAT) SPECIALS` OS=d-g \
+	 SIGTYPE=sv4 CRXTYPE=nfs \
+	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
+	 ACTIVEFILE=/local/news/active \
+	 RSHPATH=/usr/bin/remsh \
+	 BASECFLAGS="-g -Dconst=" \
+	 BASELDFLAGS="-lnsl -lsocket" \
+	 RANLIB=true
+
+dpx:	# Bull DPX/2
+	$(BUILD) `$(CAT) SPECIALS` OS=sv4 \
+	 SIGTYPE=sv4 CHECKPW=sv4 LOGINPW=sv4 \
+	 RSHPATH=/usr/bin/remsh \
+	 BASECFLAGS="-Dconst= -DSYSTEM5 -DSHORT_IDENT" \
+	 BASELDFLAGS="-linet" \
+	 RANLIB=true LN=ln
+
+drs:	# ICL DRS/NX
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 SIGTYPE=sv4 CHECKPW=sv4 LOGINPW=sv4 CRXTYPE=nfs \
+	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
+	 ACTIVEFILE=/var/lib/news/active \
+	 RSHPATH=/usr/bin/rsh \
+	 BASECFLAGS="-O" \
+	 BASELDFLAGS="-lsocket -lgen" \
+	 RANLIB=true
+
+do4:	# Apollo Domain/OS sr10.4
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 CRXTYPE=nfs \
+	 BASECFLAGS="-A systype,bsd4.3 -D_APOLLO_SOURCE" \
+	 RANLIB=true
+
+dyn:	# Dynix
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 CRXTYPE=nfs \
+	 BASECFLAGS="-g -Dconst="
+
+epx:	# EP/IX
+	$(BUILD) `$(CAT) SPECIALS` OS=sv4 \
+	 SIGTYPE=sv4 CHECKPW=sv4 LOGINPW=sv4 \
+	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
+	 ACTIVEFILE=/usr/share/news/active \
+	 RSHPATH=/usr/net/rsh \
+	 BASECFLAGS="-g -systype svr4" \
+	 BASELDFLAGS="-lsocket -lnsl -lgen" \
+	 RANLIB=true
+
+ga4:	# GCC AIX 4.1 for RS/6000
+	$(BUILD) `$(CAT) SPECIALS` OS=a41 \
+	 SIGTYPE=psx CHECKPW=a41 CRXTYPE=nfs \
+	 SPOOLDIR=/var/spool \
+	 RSHPATH=/usr/bin/rsh \
+	 BASECFLAGS="-g -Dunix=1 -D_BSD" \
+	 BASELDFLAGS="-ls"
+
+gas:	# GCC Altos SVR4
+	$(BUILD) `$(CAT) SPECIALS` OS=asv \
+	 SIGTYPE=sv4 LOGINPW=old \
+	 ACTIVEFILE=/usr/spool/news/active \
+	 RSHPATH=/usr/bin/rcmd \
+	 BASECFLAGS="-g -O -DALTOS_SYSTEM_V -DSIGSTOP=SIGKILL" \
+	 BASELDFLAGS="-lsocket -lrpc -lgen -lcrypt -lxenix" \
+	 RANLIB=true CC=gcc
+
+gh9:	# GCC HP-UX 9.x
+	$(BUILD) `$(CAT) SPECIALS` OS=hpp \
+	 SIGTYPE=psx CRXTYPE=nfs \
+	 MAILSPOOL=/usr/mail \
+	 RSHPATH=/usr/bin/remsh \
+	 BASECFLAGS="$(GCCCFLAGS)" \
+	 RANLIB=true CC=gcc
+
+ghp:	# GCC HP-UX 10.x
+	$(BUILD) `$(CAT) SPECIALS` OS=hpp \
+	 SIGTYPE=psx CRXTYPE=nfs \
+	 SPOOLDIR=/var \
+	 ACTIVEFILE=/var/news/active \
+	 RSHPATH=/usr/bin/remsh \
+	 BASECFLAGS="$(GCCCFLAGS)" \
+	 RANLIB=true CC=gcc
+
+ghs:	# GCC HP-UX with Trusted Computer Base
+	$(BUILD) `$(CAT) SPECIALS` OS=shp \
+	 SIGTYPE=psx CHECKPW=sec CRXTYPE=nfs \
+	 SPOOLDIR=/var \
+	 ACTIVEFILE=/var/news/active \
+	 RSHPATH=/usr/bin/remsh \
+	 BASECFLAGS="$(GCCCFLAGS)" \
+	 BASELDFLAGS="-lnet -lV3 -lsec" \
+	 RANLIB=true CC=gcc
+
+go5:	# GCC 2.7.1 (95q4) SCO Open Server 5.0.x
+	$(BUILD) `$(CAT) SPECIALS` OS=sc5 \
+	 SIGTYPE=psx CHECKPW=sec LOGINPW=sec \
+	 CREATEPROTO=mmdfproto EMPTYPROTO=mmdfproto \
+	 SPOOLDIR=/var/spool \
+	 ACTIVEFILE=/var/lib/news/active \
+	 RSHPATH=/usr/bin/rcmd \
+	 BASECFLAGS="$(GCCCFLAGS) -I/usr/include -L/lib" \
+	 BASELDFLAGS="-lsocket -lprot -lx -ltinfo -lm" \
+	 RANLIB=true CC=gcc
+
+gsc:	# Santa Cruz Operation
+	$(BUILD) `$(CAT) SPECIALS` OS=sco \
+	 SIGTYPE=sv4 CHECKPW=sec LOGINPW=sec \
+	 CREATEPROTO=mmdfproto EMPTYPROTO=mmdfproto \
+	 RSHPATH=/usr/bin/rcmd \
+	 BASECFLAGS="$(GCCCFLAGS)" \
+	 BASELDFLAGS="-lsocket -lprot -lcrypt_i -lx -los" \
+	 RANLIB=true LN=ln CC=gcc
+
+gsg:	# GCC Silicon Graphics
+	$(BUILD) `$(CAT) SPECIALS` OS=sgi \
+	 SIGTYPE=sv4 CRXTYPE=nfs \
+	 MAILSPOOL=/usr/mail \
+	 RSHPATH=/usr/bsd/rsh \
+	 BASECFLAGS="$(GCCCFLAGS)" \
+	 RANLIB=true CC=gcc
+
+gso:	os_sol.h	# GCC Solaris
+	$(BUILD) `$(CAT) SPECIALS` OS=sol \
+	 SIGTYPE=psx CHECKPW=psx CRXTYPE=nfs \
+	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
+	 ACTIVEFILE=/usr/share/news/active \
+	 RSHPATH=/usr/bin/rsh \
+	 BASECFLAGS="$(GCCCFLAGS)" \
+	 BASELDFLAGS="-lsocket -lnsl -lgen" \
+	 RANLIB=true CC=gcc
+
+gsu:	# GCC SUN-OS
+	$(BUILD) `$(CAT) SPECIALS` OS=sun \
+	 CRXTYPE=nfs \
+	 BASECFLAGS="$(GCCCFLAGS)" \
+	 BASELDFLAGS="-ldl" \
+	 CC=gcc
+
+gul:	# GCC Ultrix
+	$(BUILD) `$(CAT) SPECIALS` OS=ult \
+	 SIGTYPE=psx CHECKPW=ult CRXTYPE=nfs \
+	 BASECFLAGS="$(GCCCFLAGS)" \
+	 BASELDFLAGS="-lauth -lc" \
+	 CC=gcc
+
+h11:	# HP-UX 11i
+	$(BUILD) `$(CAT) SPECIALS` OS=hpp \
+	 SIGTYPE=psx CRXTYPE=nfs \
+	 SPOOLDIR=/var \
+	 ACTIVEFILE=/var/news/active \
+	 RSHPATH=/usr/bin/remsh \
+	 BASECFLAGS="-g -Ae" \
+	 RANLIB=true
+
+hpp:	# HP-UX 9.x
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 SIGTYPE=psx CRXTYPE=nfs \
+	 MAILSPOOL=/usr/mail \
+	 RSHPATH=/usr/bin/remsh \
+	 BASECFLAGS="-g -Aa -D_HPUX_SOURCE" \
+	 BASELDFLAGS="-lnet -lV3" \
+	 RANLIB=true
+
+hpx:	# HP-UX 10.x
+	$(BUILD) `$(CAT) SPECIALS` OS=hpp \
+	 SIGTYPE=psx CRXTYPE=nfs \
+	 SPOOLDIR=/var \
+	 ACTIVEFILE=/var/news/active \
+	 RSHPATH=/usr/bin/remsh \
+	 BASECFLAGS="-g -Ae" \
+	 BASELDFLAGS="-lnet -lV3" \
+	 RANLIB=true
+
+isc:	# Interactive
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 SIGTYPE=sv4 CHECKPW=sv4 LOGINPW=sv4 \
+	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
+	 ACTIVEFILE=/var/spool/news/active \
+	 BASECFLAGS="-Xp -D_SYSV3" \
+	 BASELDFLAGS="-linet -lnsl_s -lgen -lx -lsec -liberty" \
+	 RANLIB=true
+
+lnp:	# Linux Pluggable Authentication modules
+	$(BUILD) `$(CAT) SPECIALS` OS=slx \
+	 SIGTYPE=psx CHECKPW=pam CRXTYPE=nfs \
+	 SPOOLDIR=/var/spool \
+	 ACTIVEFILE=/var/lib/news/active \
+	 RSHPATH=/usr/bin/rsh \
+	 BASECFLAGS="$(GCCCFLAGS)" \
+	 BASELDFLAGS="$(PAMLDFLAGS)"
+
+lnx:	# Linux non-shadow passwords
+	@echo You are building for traditional Linux *without* shadow
+	@echo passwords and with the crypt function in the C library.
+	@echo If your system has shadow passwords, or if crypt is not
+	@echo in the C library, you must use slx, sl4, or sl5 instead!
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 SIGTYPE=psx CRXTYPE=nfs \
+	 SPOOLDIR=/var/spool \
+	 ACTIVEFILE=/var/lib/news/active \
+	 RSHPATH=/usr/bin/rsh \
+	 BASECFLAGS="$(GCCCFLAGS)"
+
+lyn:	# LynxOS
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 CRXTYPE=nfs \
+	 RSHPATH=/bin/rsh \
+	 BASECFLAGS="$(GCCCFLAGS)" \
+	 BASELDFLAGS=-lbsd \
+	 CC=gcc
+
+mct:	# MachTen - CRXTYPE=nfs doesn't work (at least not on 2.2)
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 SPOOLDIR=/var/spool \
+	 BASECFLAGS="$(GCCCFLAGS)"
+
+mnt:	# Mint
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 SIGTYPE=psx CRXTYPE=nfs \
+	 SPOOLDIR=/var/spool \
+	 ACTIVEFILE=/var/lib/news/active \
+	 RSHPATH=/usr/bin/rsh \
+	 BASECFLAGS="$(GCCCFLAGS)"
+
+neb:	# NetBSD
+	$(BUILD) `$(CAT) SPECIALS` OS=bsi \
+	 CRXTYPE=nfs \
+	 SPOOLDIR=/var \
+	 ACTIVEFILE=/var/db/news/active \
+	 RSHPATH=/usr/bin/rsh \
+	 BASECFLAGS="$(GCCCFLAGS)" \
+	 BASELDFLAGS="-lcrypt"
+
+nec:	# NEC UX
+	$(BUILD) `$(CAT) SPECIALS` OS=sv4 \
+	 SIGTYPE=sv4 CHECKPW=sv4 \
+	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
+	 ACTIVEFILE=/var/news/lib/active \
+	 RSHPATH=/usr/bin/rsh \
+	 BASECFLAGS="-g -Kopt=2 -KOlimit=2000" \
+	 BASELDFLAGS="-lsocket -lnsl -lgen" \
+	 RANLIB=true CC=/usr/abiccs/bin/cc
+
+nto:	# QNX Neutrino RTP
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 CRXTYPE=nfs \
+	 SPOOLDIR=/var/spool \
+	 ACTIVEFILE=/var/lib/news/active \
+	 RSHPATH=/usr/bin/rsh \
+	 BASECFLAGS="-g -O"
+
+nxt:	# NEXTSTEP
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 CRXTYPE=nfs \
+	 BASECFLAGS="$(GCCCFLAGS)"
+
+nx3:	# NEXTSTEP 3.0 single threaded
+	$(BUILD) `$(CAT) SPECIALS` OS=nxt \
+	 CRXTYPE=nfs \
+	 BASECFLAGS="$(GCCCFLAGS)"
+	echo "void malloc_singlethreaded (void);" >> linkage.h
+	echo "  malloc_singlethreaded ();" >> linkage.c
+
+osf:	# OSF/1
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 SIGTYPE=psx CRXTYPE=nfs \
+	 SPOOLDIR=/var/spool \
+	 BASECFLAGS="-g3 -w -O2 -Olimit 1500"
+
+# Note: sia_become_user() used by LOGINPW=os4 doesn't seem to work right.  The
+# user doesn't get proper file access, and the process can't be killed.
+
+os4:	# OSF/1 (Digital UNIX) 4
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 SIGTYPE=psx CHECKPW=os4 LOGINPW=os4 CRXTYPE=nfs \
+	 SPOOLDIR=/var/spool \
+	 BASECFLAGS="-g3 -w -std0 -O2"
+
+osx:	# Mac OS X
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 CRXTYPE=nfs \
+	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
+	 RSHPATH=/usr/bin/rsh \
+	 BASECFLAGS="$(GCC4CFLAGS)"
+
+ptx:	# PTX
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 SIGTYPE=psx CHECKPW=svo LOGINPW=sv4 CRXTYPE=nfs \
+	 MAILSPOOL=/usr/mail \
+	 RSHPATH=/usr/bin/resh \
+	 BASECFLAGS="-Wc,-O3 -Wc,-seq -Dprivate=PRIVATE" \
+	 BASELDFLAGS="-lseq -lsec -lsocket -linet -lnsl -lgen" \
+	 RANLIB=true
+
+pyr:	# Pyramid
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 CRXTYPE=nfs \
+	 BASECFLAGS="-g -Dconst="
+
+qnx:	# QNX
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 CHECKPW=psx LOGINPW=old \
+	 RSHPATH=/usr/ucb/rsh \
+	 BASECFLAGS="-Otax -g -Dunix=1 -D_POSIX_SOURCE" \
+	 BASELDFLAGS="-g -N128k -llogin -lsocket -lunix"
+
+s40:	# SUN-OS 4.0
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 CRXTYPE=nfs \
+	 BASECFLAGS="-g -Dconst="
+
+sc5:	# SCO Open Server 5.0
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 SIGTYPE=psx CHECKPW=sec LOGINPW=sec \
+	 CREATEPROTO=mmdfproto EMPTYPROTO=mmdfproto \
+	 SPOOLDIR=/var/spool \
+	 ACTIVEFILE=/var/lib/news/active \
+	 RSHPATH=/usr/bin/rcmd \
+	 BASECFLAGS="-O3 -s -belf" \
+	 BASELDFLAGS="-lsocket -lprot -lx -ltinfo -lm" \
+	 RANLIB=true
+
+sco:	# Santa Cruz Operation
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 SIGTYPE=sv4 CHECKPW=sec LOGINPW=sec \
+	 CREATEPROTO=mmdfproto EMPTYPROTO=mmdfproto \
+	 RSHPATH=/usr/bin/rcmd \
+	 BASECFLAGS="-O3" \
+	 BASELDFLAGS="-lsocket -lprot -lcrypt_i -lx -los" \
+	 RANLIB=true LN=ln
+
+# Note: setting _POSIX_SOURCE doesn't seem to build it as of SGI IRIX 5.3
+
+sgi:	# Silicon Graphics
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 SIGTYPE=sv4 CRXTYPE=nfs \
+	 MAILSPOOL=/usr/mail \
+	 RSHPATH=/usr/bsd/rsh \
+	 BASECFLAGS="-g3 -O2 -Olimit 8192" \
+	 RANLIB=true
+
+sg6:	# Silicon Graphics, IRIX 6.5
+	MAKEFLAGS= $(BUILD) `$(CAT) SPECIALS` OS=sgi \
+	 SIGTYPE=sv4 CRXTYPE=nfs \
+	 MAILSPOOL=/usr/mail \
+	 RSHPATH=/usr/bsd/rsh \
+	 BASECFLAGS="-g3 -O2 -OPT:Olimit=0 -woff 1110,1116" \
+	 RANLIB=true
+
+# Note: Mark Kaesling says that setluid() isn't in HP-UX with SecureWare.
+
+shp:	# HP-UX with Trusted Computer Base
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 SIGTYPE=psx CHECKPW=sec CRXTYPE=nfs \
+	 SPOOLDIR=/var \
+	 ACTIVEFILE=/var/news/active \
+	 RSHPATH=/usr/bin/remsh \
+	 BASECFLAGS="-g -Ae" \
+	 BASELDFLAGS="-lnet -lV3 -lsec" \
+	 RANLIB=true
+
+slx:	# Secure Linux
+	@echo You are building for libc6/glibc versions of Secure Linux
+	@echo If you want libc5 versions you must use sl5 instead!
+	@echo If you want libc4 versions you must use sl4 instead!
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 SIGTYPE=psx CHECKPW=psx CRXTYPE=nfs \
+	 SPOOLDIR=/var/spool \
+	 ACTIVEFILE=/var/lib/news/active \
+	 RSHPATH=/usr/bin/rsh \
+	 BASECFLAGS="$(GCCCFLAGS)" \
+	 BASELDFLAGS="-lcrypt"
+
+sl4:	# Secure Linux using libc4
+	@echo You are building for libc4 versions of Secure Linux
+	@echo If you want libc6/glibc versions you must use slx instead!
+	@echo If you want libc5 versions you must use sl5 instead!
+	$(BUILD) `$(CAT) SPECIALS` OS=slx \
+	 SIGTYPE=psx CHECKPW=psx CRXTYPE=nfs \
+	 SPOOLDIR=/var/spool \
+	 ACTIVEFILE=/var/lib/news/active \
+	 RSHPATH=/usr/bin/rsh \
+	 BASECFLAGS="$(GCCCFLAGS)" \
+	 BASELDFLAGS="-lshadow"
+
+sl5:	# Secure Linux using libc5
+	@echo You are building for libc5 versions of Secure Linux
+	@echo If you want libc6/glibc versions you must use slx instead!
+	@echo If you want libc4 versions you must use sl4 instead!
+	$(BUILD) `$(CAT) SPECIALS` OS=slx \
+	 SIGTYPE=psx CHECKPW=psx CRXTYPE=nfs \
+	 SPOOLDIR=/var/spool \
+	 ACTIVEFILE=/var/lib/news/active \
+	 RSHPATH=/usr/bin/rsh \
+	 BASECFLAGS="$(GCCCFLAGS)"
+
+snx:	# Siemens Nixdorf SINIX and Reliant UNIX
+	$(BUILD) `$(CAT) SPECIALS` OS=sv4 \
+	 SIGTYPE=psx CHECKPW=sv4 \
+	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
+	 ACTIVEFILE=/usr/share/news/active \
+	 RSHPATH=/usr/bin/rsh \
+	 BASECFLAGS="-g -D_SYS_CLOCK_H -Dconst=" \
+	 BASELDFLAGS="-lsocket -lnsl -lgen" \
+	 RANLIB=true
+
+# Sorry about the -w, but the cretinous SUN Workshop Pro C compiler barfs on
+# implicit casts between char and unsigned char.
+
+soc:	os_sol.h	# Solaris with cc
+	$(BUILD) `$(CAT) SPECIALS` OS=sol \
+	 SIGTYPE=psx CHECKPW=psx CRXTYPE=nfs \
+	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
+	 ACTIVEFILE=/usr/share/news/active \
+	 RSHPATH=/usr/bin/rsh \
+	 BASECFLAGS="-g -O -w" \
+	 BASELDFLAGS="-lsocket -lnsl -lgen" \
+	 RANLIB=true CC=/opt/SUNWspro/bin/cc
+
+
+# Note: It is a long and disgusting story about why cc is set to ucbcc.  You
+# need to invoke the C compiler so that it links with the SVR4 libraries and
+# not the BSD libraries, otherwise readdir() will return the wrong information.
+# Of all the names in the most common path, ucbcc is the only name to be found
+# (on /usr/ccs/bin) that points to a suitable compiler.  cc is likely to be
+# /usr/ucb/cc which is absolutely not the compiler that you want.  The real
+# SVR4 cc is probably something like /opt/SUNWspro/bin/cc which is rarely in
+# anyone's path.
+#
+# ucbcc is probably a link to acc, e.g. /opt/SUNWspro/SC4.0/bin/acc, and is
+# the UCB C compiler using the SVR4 libraries.
+#
+# If ucbcc isn't on your system, then punt on the SUN C compiler and use gcc
+# instead (the gso port instead of the sol port).
+# 
+# If, in spite of all the above warnings, you choose to use the "soc" port
+# instead of the "sol" port, be sure to check the behavior of the LIST command
+# in imapd.  Also, note that the "soc" port uses -O.  If you want to use the
+# real SVR4 compiler, you must use -O.  If it works to compile with -O2, then
+# cc is probably using the UCB compiler with BSD libraries, and will not build
+# a good binary
+#
+# To recap:
+# 1) The sol port is designed to be built using the UCB compiler using the
+#    SVR4 libraries.  This compiler is "ucbcc", which is lunk to acc.  You
+#    use -O2 as one of the CFLAGS.
+# 2) If you build the sol port with the UCB compiler using the BSD libraries,
+#    you will get no error messages but you will get bad binaries (the most
+#    obvious symptom is dropping the first two characters return filenames
+#    from the imapd LIST command.  This compiler also uses -O2, and is very
+#    often what the user gets from "cc".  BEWARE!!!
+# 3) If you build the sol port with the real SVR4 compiler, which is often
+#    hidden away or unavailable on many systems, then you will get errors
+#    from -O2 and you need to change that to -O.  But you will get a good
+#    binary.  However, you should try it with -O2 first, to make sure that
+#    you got this compiler and not the UCB compiler using BSD libraries.
+
+sol:	os_sol.h	# Solaris
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 SIGTYPE=psx CHECKPW=psx CRXTYPE=nfs \
+	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
+	 ACTIVEFILE=/usr/share/news/active \
+	 RSHPATH=/usr/bin/rsh \
+	 BASECFLAGS="-g -O2" \
+	 BASELDFLAGS="-lsocket -lnsl -lgen" \
+	 RANLIB=true CC=ucbcc
+
+sos:	# Secure OSF/1
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 SIGTYPE=psx CHECKPW=sce LOGINPW=sec CRXTYPE=nfs \
+	 BASECFLAGS="-g3 -w -O2 -Olimit 1500" \
+	 BASELDFLAGS="-lsecurity -laud"
+
+ssn:	# Secure SUN-OS
+	$(BUILD) `$(CAT) SPECIALS` OS=sun \
+	 CHECKPW=ssn CRXTYPE=nfs \
+	 BASECFLAGS="-g -Dconst=" \
+	 BASELDFLAGS="-ldl"
+
+sua:	# Windows Vista Subsystem for UNIX Applications
+	$(BUILD) `$(CAT) SPECIALS` OS=sua \
+	 SIGTYPE=psx CRXTYPE=nfs LOGINPW=old \
+	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
+	 ACTIVEFILE=/var/lib/news/active \
+	 RSHPATH=/usr/bin/rsh \
+	 BASECFLAGS="-g -O2" \
+	 BASELDFLAGS="-lcrypt"
+
+sun:	# SUN-OS
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 CRXTYPE=nfs \
+	 BASECFLAGS="-g -Dconst=" \
+	 BASELDFLAGS="-ldl"
+
+sv2:	# SVR2
+	@echo You are being *very* optimistic!
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 SIGTYPE=sv4 LOGINPW=old \
+	 MAILSPOOL=/usr/mail \
+	 RSHPATH=/usr/bin/remsh \
+	 BASECFLAGS="-Dconst= -DSYSTEM5 -DSHORT_IDENT -I/usr/ethernet/include" \
+	 BASELDFLAGS="-lnet" \
+	 RANLIB=true LN=ln
+
+sv4:	# SVR4
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 SIGTYPE=sv4 CHECKPW=sv4 LOGINPW=sv4 \
+	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
+	 ACTIVEFILE=/usr/share/news/active \
+	 RSHPATH=/usr/bin/resh \
+	 BASECFLAGS="-g -Dconst=" \
+	 BASELDFLAGS="-lsocket -lnsl -lgen" \
+	 RANLIB=true
+
+ult:	# Ultrix
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 SIGTYPE=psx CHECKPW=ult CRXTYPE=nfs \
+	 BASECFLAGS="-g3 -O2 -Olimit 1500 -Dconst=" \
+	 BASELDFLAGS="-lauth -lc"
+
+uw2:	# UnixWare SVR4.2
+	$(BUILD) `$(CAT) SPECIALS` OS=sv4 \
+	 SIGTYPE=sv4 CHECKPW=sv4 \
+	 SPOOLDIR=/var/spool MAILSPOOL=/var/mail \
+	 ACTIVEFILE=/var/news/lib/active \
+	 RSHPATH=/usr/bin/rsh \
+	 BASECFLAGS="-g" \
+	 BASELDFLAGS="-lsocket -lnsl -lgen" \
+	 RANLIB=true
+
+vul:	# VAX Ultrix
+	$(BUILD) `$(CAT) SPECIALS` OS=ult \
+	 SIGTYPE=psx CHECKPW=ult CRXTYPE=nfs \
+	 BASECFLAGS="-O2 -Dconst=" \
+	 BASELDFLAGS="-lauth -lc"
+
+vu2:	# VAX Ultrix 2.3, etc.
+	$(BUILD) `$(CAT) SPECIALS` OS=$@ \
+	 CRXTYPE=nfs \
+	 BASECFLAGS="-O2 -Dconst= -Dvoid=char"
+
+
+# Build it!
+
+build:	clean once $(ARCHIVE)
+
+all:	$(ARCHIVE)
+
+$(ARCHIVE): $(BINARIES)
+	sh -c '$(RM) $(ARCHIVE) || true'
+	@$(CAT) ARCHIVE
+	@$(SH) ARCHIVE
+
+.c.o:
+	`$(CAT) CCTYPE` -c `$(CAT) CFLAGS` $*.c
+
+
+# Cleanup
+
+clean:
+	sh -c '$(RM) auths.c crexcl.c ip_unix.c linkage.[ch] siglocal.c osdep*.[ch] *.o ARCHIVE *FLAGS *TYPE $(ARCHIVE) || true'
+
+
+# Dependencies
+
+dummy.o: mail.h misc.h osdep.h dummy.h
+fdstring.o: mail.h misc.h osdep.h fdstring.h
+flstring.o: mail.h misc.h osdep.h flstring.h
+imap4r1.o: mail.h misc.h osdep.h imap4r1.h rfc822.h
+mail.o: mail.h misc.h osdep.h rfc822.h linkage.h
+mbx.o: mail.h misc.h osdep.h dummy.h
+mh.o: mail.h misc.h osdep.h dummy.h
+mix.o: mail.h misc.h osdep.h dummy.h
+mx.o: mail.h misc.h osdep.h dummy.h
+misc.o: mail.h misc.h osdep.h
+mmdf.o: mail.h misc.h osdep.h pseudo.h dummy.h
+mtx.o: mail.h misc.h osdep.h dummy.h
+netmsg.o: mail.h misc.h osdep.h netmsg.h
+news.o: mail.h misc.h osdep.h
+newsrc.o: mail.h misc.h osdep.h newsrc.h
+nntp.o: mail.h misc.h osdep.h netmsg.h smtp.h nntp.h rfc822.h
+phile.o: mail.h misc.h osdep.h rfc822.h dummy.h
+pseudo.o: pseudo.h
+pop3.o: mail.h misc.h osdep.h rfc822.h
+smanager.o: mail.h misc.h osdep.h
+smtp.o: mail.h misc.h osdep.h smtp.h rfc822.h
+rfc822.o: mail.h misc.h osdep.h rfc822.h
+tenex.o: mail.h misc.h osdep.h dummy.h
+unix.o: mail.h misc.h osdep.h unix.h pseudo.h dummy.h
+utf8.o: mail.h misc.h osdep.h utf8.h tmap.c widths.c
+utf8aux.o: mail.h misc.h osdep.h utf8.h
+
+
+# OS-dependent
+
+osdep.o:mail.h misc.h env.h fs.h ftl.h nl.h tcp.h \
+	osdep.h env_unix.h tcp_unix.h \
+	osdep.c env_unix.c fs_unix.c ftl_unix.c nl_unix.c tcp_unix.c ip_unix.c\
+	auths.c crexcl.c flockcyg.c flocklnx.c flocksim.c fsync.c \
+	gethstid.c getspnam.c \
+	gr_wait.c gr_wait4.c gr_waitp.c \
+	kerb_mit.c \
+	auth_ext.c auth_gss.c auth_log.c auth_md5.c auth_pla.c \
+	pmatch.c scandir.c setpgrp.c strerror.c truncate.c write.c \
+	memmove.c memmove2.c memset.c \
+	tz_bsd.c tz_nul.c tz_sv4.c \
+	write.c sslstdio.c \
+	strerror.c strpbrk.c strstr.c strtok.c strtoul.c \
+	OSCFLAGS
+	@echo Building OS-dependent module
+	@echo If you get No such file error messages for files x509.h, ssl.h,
+	@echo pem.h, buffer.h, bio.h, and crypto.h, that means that OpenSSL
+	@echo is not installed on your system.  Either install OpenSSL first
+	@echo or build with command: make `$(CAT) OSTYPE` SSLTYPE=none
+	`$(CAT) CCTYPE` -c `$(CAT) CFLAGS` `$(CAT) OSCFLAGS` -c osdep.c
+
+osdep.c: osdepbas.c osdepckp.c osdeplog.c osdepssl.c
+	$(CAT) osdepbas.c osdepckp.c osdeplog.c osdepssl.c > osdep.c
+
+osdepbas.c:
+	@echo osdepbas.c not found...try make clean and new make
+	@false
+
+osdepckp.c:
+	@echo osdepckp.c not found...try make clean and new make
+	@false
+
+osdeplog.c:
+	@echo osdeplog.c not found...try make clean and new make
+	@false
+
+osdepssl.c:
+	@echo osdepssl.c not found...try make clean and new make
+	@false
+
+siglocal.c:
+	@echo siglocal.c not found...try make clean and new make
+	@false
+
+crexcl.c:
+	@echo crexcl.c not found...do make clean and new make
+	@false
+
+ip_unix.c:
+	@echo ip_unix.c not found...do make clean and new make
+	@false
+
+os_sol.h:
+	sh -c 'if [ -f /lib/libc.a ]; then (strings /lib/libc.a | grep getpassphrase > /dev/null) && $(LN) os_soln.h os_sol.h || $(LN) os_solo.h os_sol.h ; else $(LN) os_soln.h os_sol.h ; fi'
+
+
+# Once-only environment setup
+
+once:	onceenv ckp$(PASSWDTYPE) ssl$(SSLTYPE) osdep.c
+
+onceenv:
+	@echo Once-only environment setup...
+	echo $(CC) > CCTYPE
+	echo $(BASECFLAGS) '$(EXTRACFLAGS)' -DCHUNKSIZE=$(CHUNKSIZE) > CFLAGS
+	echo -DCREATEPROTO=$(CREATEPROTO) -DEMPTYPROTO=$(EMPTYPROTO) \
+	 -DMD5ENABLE=\"$(MD5PWD)\" -DMAILSPOOL=\"$(MAILSPOOL)\" \
+	 -DANONYMOUSHOME=\"$(MAILSPOOL)/anonymous\" \
+	 -DACTIVEFILE=\"$(ACTIVEFILE)\" -DNEWSSPOOL=\"$(NEWSSPOOL)\" \
+	 -DRSHPATH=\"$(RSHPATH)\" -DLOCKPGM=\"$(LOCKPGM)\" \
+	 -DLOCKPGM1=\"$(LOCKPGM1)\" -DLOCKPGM2=\"$(LOCKPGM2)\" \
+	 -DLOCKPGM3=\"$(LOCKPGM3)\" > OSCFLAGS
+	echo $(BASELDFLAGS) $(EXTRALDFLAGS) > LDFLAGS
+	echo "$(ARRC) $(ARCHIVE) $(BINARIES);$(RANLIB) $(ARCHIVE)" > ARCHIVE
+	echo $(OS) > OSTYPE
+	./drivers $(EXTRADRIVERS) $(DEFAULTDRIVERS) dummy
+	./mkauths $(EXTRAAUTHENTICATORS) $(DEFAULTAUTHENTICATORS)
+	echo "  mail_versioncheck (CCLIENTVERSION);" >> linkage.c
+	$(LN) os_$(OS).h osdep.h
+	$(LN) os_$(OS).c osdepbas.c
+	$(LN) log_$(LOGINPW).c osdeplog.c
+	$(LN) sig_$(SIGTYPE).c siglocal.c
+	$(LN) crx_$(CRXTYPE).c crexcl.c
+	$(LN) ip$(IP)_unix.c ip_unix.c
+	sh -c '(test $(OS) = sc5 -o $(OS) = sco -o ! -f /usr/include/sys/statvfs.h) && echo -DNOFSTATVFS >> OSCFLAGS || fgrep statvfs64 /usr/include/sys/statvfs.h > /dev/null || echo -DNOFSTATVFS64 >> OSCFLAGS'
+
+
+# Password checkers
+
+ckpafs:	# AFS
+	@echo AFS password authentication
+	echo $(AFSCFLAGS) >> OSCFLAGS
+#	echo $(AFSLDFLAGS) >> LDFLAGS
+# Note: Steve Roseman says that AFS libraries have to be lunk before SSL
+	echo $(AFSLDFLAGS) `$(CAT) LDFLAGS` > LDFLAGS.tmp
+	mv LDFLAGS.tmp LDFLAGS
+	$(LN) ckp_afs.c osdepckp.c
+
+ckpdce:	# DCE
+	@echo DCE password authentication
+	echo $(DCECFLAGS) >> OSCFLAGS
+	echo $(DCELDFLAGS) >> LDFLAGS
+	$(LN) ckp_dce.c osdepckp.c
+
+ckpgss:	# Kerberos V (must have gss EXTRAAUTHENTICATOR as well)
+	@echo Kerberos V password authentication
+	$(LN) ckp_gss.c osdepckp.c
+
+ckpnul:	# NUL authenticator (disables all plaintext authentication)
+	@echo Plaintext authentication prohibited
+	echo "  mail_parameters (NIL,SET_DISABLEPLAINTEXT,(void *) 1);" >> linkage.c
+	$(LN) ckp_nul.c osdepckp.c
+
+ckppam:	# Pluggable Authentication Modules authenticator
+	@echo PAM password authentication
+	echo $(PAMLDFLAGS) >> LDFLAGS
+	$(LN) ckp_pam.c osdepckp.c
+
+ckppmb:	# Broken (e.g. SUN) Pluggable Authentication Modules authenticator
+	@echo Broken PAM password authentication
+	echo $(PAMLDFLAGS) >> LDFLAGS
+	$(LN) ckp_pmb.c osdepckp.c
+
+ckpstd:	# Port standard
+	@echo Standard password authentication
+	$(LN) ckp_$(CHECKPW).c osdepckp.c
+
+ckptwo:	# Something plus standard
+	@echo $(CHECKPWALT) password authentication first, then standard
+	$(CAT) ckp_1st.c ckp_$(CHECKPWALT).c ckp_2nd.c ckp_$(CHECKPW).c \
+	 ckp_3rd.c > osdepckp.c
+
+
+# SSL support
+
+sslnone:# No SSL
+	@echo Building without SSL support
+	$(LN) ssl_none.c osdepssl.c
+
+sslnopwd: sslunix snopwd
+
+sslunix.nopwd: sslnopwd
+
+sslsco.nopwd: sslsco snopwd
+
+sslunix: sbasic sldunix
+
+sslsco:	sbasic sldsco
+
+sbasic:	# UNIX OpenSSL
+	@echo Building with SSL
+	$(LN) ssl_unix.c osdepssl.c
+	echo $(SSLCFLAGS) >> OSCFLAGS
+	echo "  ssl_onceonlyinit ();" >> linkage.c
+
+snopwd:	# Plaintext disable
+	@echo Building with SSL and plaintext passwords disabled unless SSL/TLS
+	echo "  mail_parameters (NIL,SET_DISABLEPLAINTEXT,(void *) 2);" >> linkage.c
+
+sldunix:# Normal UNIX SSL load flags
+	echo $(SSLLDFLAGS) >> LDFLAGS
+
+
+sldsco:	# SCO SSL load flags
+# Note: Tim Rice says that SSL has to be lunk before other libraries on SCO.
+	echo $(SSLLDFLAGS) `cat LDFLAGS` > LDFLAGS.tmp
+	mv LDFLAGS.tmp LDFLAGS
+
+
+# A monument to a hack of long ago and far away...
+
+love:
+	@echo not war?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/Makefile.gss	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,39 @@
+# ========================================================================
+# Copyright 1988-2007 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+# Program:	GSSAPI makefile
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		11 May 1989
+# Last Edited:	4 April 2007
+
+
+# Extended flags needed for additional authenticators.  You may need to modify.
+
+GSSDIR=/usr/local
+GSSINCLUDE=$(GSSDIR)/include
+GSSLIB=$(GSSDIR)/lib
+GSSCFLAGS= -I$(GSSINCLUDE) -DGSS_C_NT_HOSTBASED_SERVICE=gss_nt_service_name -DKRB5_DEPRECATED=1
+GSSOLDLDFLAGS= -L$(GSSLIB) -lgssapi_krb5 -lkrb5 -lcrypto -lcom_err
+GSSNEWLDFLAGS= -L$(GSSLIB) -lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err
+
+gss:	# GSSAPI Kerberos V flags
+	echo $(GSSCFLAGS) >> OSCFLAGS
+	sh -c '(test -f $(GSSLIB)/libk5crypto.a) && echo $(GSSNEWLDFLAGS) || echo $(GSSOLDLDFLAGS)' >> LDFLAGS
+	echo "#include \"kerb_mit.c\"" >> auths.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ckp_1st.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,53 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Dual check password part 1
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+struct passwd *checkpw_alt(struct passwd *pw,char *pass,int argc,char *argv[]);
+struct passwd *checkpw_std(struct passwd *pw,char *pass,int argc,char *argv[]);
+
+/* Check password
+ * Accepts: login passwd struct
+ *	    password string
+ *	    argument count
+ *	    argument vector
+ * Returns: passwd struct if password validated, NIL otherwise
+ */
+
+struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
+{
+  struct passwd *ret;
+				/* in case first checker smashes it */
+  char *user = cpystr (pw->pw_name);
+  if (!(ret = checkpw_alt (pw,pass,argc,argv)))
+    ret = checkpw_std (getpwnam (user),pass,argc,argv);
+  fs_give ((void **) &user);
+  return ret;
+}
+
+/* Redefine alt checker's routine name */
+
+#define checkpw checkpw_alt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ckp_2nd.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,36 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Dual check password part 2
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Undefine routine name */
+
+#undef checkpw
+
+/* Redefine std checker's routine name */
+
+#define checkpw checkpw_std
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ckp_3rd.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,32 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Dual check password part 3
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Undefine routine name */
+
+#undef checkpw
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ckp_a41.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,52 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	AIX 4.1 check password
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988	
+ * Last Edited:	30 August 2006
+ */
+ 
+#include <login.h>
+
+/* Check password
+ * Accepts: login passwd struct
+ *	    password string
+ *	    argument count
+ *	    argument vector
+ * Returns: passwd struct if password validated, NIL otherwise
+ */
+
+struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
+{
+  int reenter = 0;
+  char *msg = NIL;
+  char *user = cpystr (pw->pw_name);
+				/* validate password */
+  struct passwd *ret = (pw && !loginrestrictions (user,S_RLOGIN,NIL,&msg) &&
+			!authenticate (user,pass,&reenter,&msg)) ?
+			  getpwnam (user) : NIL;
+				/* clean up any message returned */
+  if (msg) fs_give ((void **) &msg);
+  if (user) fs_give ((void **) &user);
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ckp_afs.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,71 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	AFS check password
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* AFS cleanup
+ * Accepts: data
+ */
+
+void checkpw_cleanup (void *data)
+{
+  ktc_ForgetAllTokens ();
+}
+
+
+/* Check password
+ * Accepts: login passwd struct
+ *	    password string
+ *	    argument count
+ *	    argument vector
+ * Returns: passwd struct if password validated, NIL otherwise
+ */
+
+#undef INIT
+#define min AFS_MIN
+#define max AFS_MAX
+#include <afs/param.h>
+#include <afs/kautils.h>
+
+struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
+{
+  char *reason;
+				/* faster validation for POP servers */
+  if (!strcmp ((char *) mail_parameters (NIL,GET_SERVICENAME,NIL),"pop")) {
+    struct ktc_encryptionKey key;
+    struct ktc_token token;
+				/* just check the password */
+    ka_StringToKey (pass,NIL,&key);
+    if (ka_GetAdminToken (pw->pw_name,"","",&key,600,&token,1)) return NIL;
+  }
+				/* check password and get AFS token */
+  else if (ka_UserAuthenticateGeneral
+	   (KA_USERAUTH_VERSION + KA_USERAUTH_DOSETPAG,pw->pw_name,NIL,NIL,
+	    pass,0,0,0,&reason)) return NIL;
+				/* arm hook to delete credentials */
+  mail_parameters (NIL,SET_LOGOUTHOOK,(void *) checkpw_cleanup);
+  return pw;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ckp_bsi.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,50 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	BSI check password
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Check password
+ * Accepts: login passwd struct
+ *	    password string
+ *	    argument count
+ *	    argument vector
+ * Returns: passwd struct if password validated, NIL otherwise
+ */
+
+#include <login_cap.h>
+
+struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
+{
+  char *s,tmp[MAILTMPLEN];
+  login_cap_t *lc;
+				/* make service name */
+  sprintf (tmp,"auth-%s",(char *) mail_parameters (NIL,GET_SERVICENAME,NIL));
+				/* validate password */
+  return ((lc = login_getclass (pw->pw_class)) &&
+	  (s = login_getstyle (lc,NIL,tmp)) &&
+	  (auth_response (pw->pw_name,lc->lc_class,s,"response",NIL,"",pass)
+	   > 0)) ? pw : NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ckp_cyg.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,63 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Cygwin check password
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* This module is against my better judgement.  If you want to run an imapd
+ * or ipop[23]d you should use the native NT or W2K ports intead of this
+ * Cygwin port.  There is no surety that this module works right or will work
+ * right in the future.
+ */
+
+#undef ERROR
+#include <windows.h>
+#include <sys/cygwin.h>
+
+
+/* Check password
+ * Accepts: login passwd struct
+ *	    password string
+ *	    argument count
+ *	    argument vector
+ * Returns: passwd struct if password validated, NIL otherwise
+ */
+
+static char *cyg_user = NIL;
+static HANDLE cyg_hdl = NIL;
+
+struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
+{
+				/* flush last pw-checked user */
+  if (cyg_user) fs_give ((void **) &cyg_user);
+				/* forbid if UID 0 or SYSTEM uid */
+  if (!pw->pw_uid || (pw->pw_uid == SYSTEMUID) ||
+      ((cyg_hdl = cygwin_logon_user (pw,pass)) == INVALID_HANDLE_VALUE))
+    return NIL;			/* bad UID or password */
+				/* remember user for this handle */
+  cyg_user = cpystr (pw->pw_name);
+  return pw;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ckp_dce.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,83 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	DCE check password
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Check password
+ * Accepts: login passwd struct
+ *	    password string
+ *	    argument count
+ *	    argument vector
+ * Returns: passwd struct if password validated, NIL otherwise
+ */
+
+#include <dce/rpc.h>
+#include <dce/sec_login.h>
+
+struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
+{
+  sec_passwd_rec_t pwr;
+  sec_login_handle_t lhdl;
+  boolean32 rstpwd;
+  sec_login_auth_src_t asrc;
+  error_status_t status;
+  FILE *fd;
+				/* easy case */
+  if (pw->pw_passwd && pw->pw_passwd[0] && pw->pw_passwd[1] &&
+      !strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) return pw;
+				/* try DCE password cache file */
+  if (fd = fopen (PASSWD_OVERRIDE,"r")) {
+    char *usr = cpystr (pw->pw_name);
+    while ((pw = fgetpwent (fd)) && strcmp (usr,pw->pw_name));
+    fclose (fd);		/* finished with cache file */
+				/* validate cached password */
+    if (pw && pw->pw_passwd && pw->pw_passwd[0] && pw->pw_passwd[1] &&
+	!strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) {
+      fs_give ((void **) &usr);
+      return pw;
+    }
+    if (!pw) pw = getpwnam (usr);
+    fs_give ((void **) &usr);
+  }
+  if (pw) {			/* try S-L-O-W DCE... */
+    sec_login_setup_identity ((unsigned_char_p_t) pw->pw_name,
+			      sec_login_no_flags,&lhdl,&status);
+    if (status == error_status_ok) {
+      pwr.key.tagged_union.plain = (idl_char *) pass;
+      pwr.key.key_type = sec_passwd_plain;
+      pwr.pepper = NIL;
+      pwr.version_number = sec_passwd_c_version_none;
+				/* validate password with login context */
+      sec_login_validate_identity (lhdl,&pwr,&rstpwd,&asrc,&status);
+      if (!rstpwd && (asrc == sec_login_auth_src_network) &&
+	  (status == error_status_ok)) {
+	sec_login_purge_context (&lhdl,&status);
+	if (status == error_status_ok) return pw;
+      }
+    }
+  }
+  return NIL;			/* password validation failed */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ckp_gss.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,90 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Kerberos 5 check password
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	11 October 2007
+ */
+
+/* Check password
+ * Accepts: login passwd struct
+ *	    password string
+ *	    argument count
+ *	    argument vector
+ * Returns: passwd struct if password validated, NIL otherwise
+ */
+
+struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
+{
+  char svrnam[MAILTMPLEN],cltnam[MAILTMPLEN];
+  krb5_context ctx;
+  krb5_timestamp now;
+  krb5_principal service;
+  krb5_ccache ccache;
+  krb5_error_code code;
+  krb5_creds *crd = (krb5_creds *) memset (fs_get (sizeof (krb5_creds)),0,
+						   sizeof (krb5_creds));
+  struct passwd *ret = NIL;
+  if (*pass) {			/* only if password non-empty */
+				/* make service name */
+    sprintf (svrnam,"%.80s@%.512s",
+	     (char *) mail_parameters (NIL,GET_SERVICENAME,NIL),
+	     tcp_serverhost ());
+				/* make client name with principal */
+    sprintf (cltnam,"%.80s/%.80s",pw->pw_name,
+	     (char *) mail_parameters (NIL,GET_SERVICENAME,NIL));
+				/* get a context */
+    if (!krb5_init_context (&ctx)) {
+				/* get time, client and server principals */
+      if (!krb5_timeofday (ctx,&now) &&
+	/* Normally, kerb_cp_svr_name (defined/set in env_unix.c) is NIL, so
+	 * only the user name is used as a client principal.  A few sites want
+	 * to have separate client principals for different services, but many
+	 * other sites vehemently object...
+	 */
+	  !krb5_parse_name (ctx,kerb_cp_svr_name ? cltnam : pw->pw_name,
+			    &crd->client) &&
+	  !krb5_parse_name (ctx,svrnam,&service) &&
+	  !krb5_build_principal_ext(ctx,&crd->server,
+				    krb5_princ_realm (ctx,crd->client)->length,
+				    krb5_princ_realm (ctx,crd->client)->data,
+				    KRB5_TGS_NAME_SIZE,KRB5_TGS_NAME,
+				    krb5_princ_realm (ctx,crd->client)->length,
+				    krb5_princ_realm (ctx,crd->client)->data,
+				    0)) {
+				/* expire in 3 minutes */
+	crd->times.endtime = now + (3 * 60);
+	if (krb5_cc_resolve (ctx,"MEMORY:pwk",&ccache) ||
+	    krb5_cc_initialize (ctx,ccache,crd->client)) ccache = 0;
+	if (!krb5_get_in_tkt_with_password (ctx,NIL,NIL,NIL,NIL,pass,ccache,
+					    crd,0) &&
+	    !krb5_verify_init_creds (ctx,crd,service,0,ccache ? &ccache : 0,0))
+	  ret = pw;
+	krb5_free_creds (ctx,crd);/* flush creds and service principal */
+	krb5_free_principal (ctx,service);
+      }
+      krb5_free_context (ctx);	/* don't need context any more */
+    }
+  }
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ckp_nul.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,40 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Null check password
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	23 July 1998
+ * Last Edited:	30 August 2006
+ */
+
+/* Check password
+ * Accepts: login passwd struct
+ *	    password string
+ *	    argument count
+ *	    argument vector
+ * Returns: passwd struct if password validated, NIL otherwise
+ */
+
+struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
+{
+  return NIL;			/* always fails */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ckp_os4.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,78 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	OSF/1 (Digital UNIX) 4 check password
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Dummy collection routine
+ * Accepts: how long to wait for user
+ *	    how to run parameter collection
+ *	    title
+ *	    number of prompts
+ *	    prompts
+ * Returns: collection status
+ *
+ * Because Spider Boardman, who wrote SIA, says that it's needed for buggy SIA
+ * mechanisms, that's why.
+ */
+
+static int checkpw_collect (int timeout,int rendition,uchar_t *title,
+			    int nprompts,prompt_t *prompts)
+{
+  switch (rendition) {
+  case SIAONELINER: case SIAINFO: case SIAWARNING: return SIACOLSUCCESS;
+  }
+  return SIACOLABORT;		/* another else is bogus */
+}
+
+
+/* Check password
+ * Accepts: login passwd struct
+ *	    password string
+ *	    argument count
+ *	    argument vector
+ * Returns: passwd struct if password validated, NIL otherwise
+ */
+
+struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
+{
+  int i;
+  char *s;
+  char *name = cpystr (pw->pw_name);
+  char *host = cpystr (tcp_clienthost ());
+  struct passwd *ret = NIL;
+				/* tie off address */
+  if (s = strchr (host,' ')) *s = '\0';
+  if (*host == '[') {		/* convert [a.b.c.d] to a.b.c.d */
+    memmove (host,host+1,i = strlen (host + 2));
+    host[i] = '\0';
+  }
+				/* validate password */
+  if (sia_validate_user (checkpw_collect,argc,argv,host,name,NIL,NIL,NIL,pass)
+      == SIASUCCESS) ret = getpwnam (name);
+  fs_give ((void **) &name);
+  fs_give ((void **) &host);
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ckp_pam.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,136 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Pluggable Authentication Modules login services
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	31 August 2006
+ */
+
+
+#ifdef MAC_OSX_KLUDGE		/* why can't Apple be compatible? */
+#include <pam/pam_appl.h>
+#else
+#include <security/pam_appl.h>
+#endif
+
+struct checkpw_cred {
+  char *uname;			/* user name */
+  char *pass;			/* password */
+};
+
+/* PAM conversation function
+ * Accepts: number of messages
+ *	    vector of messages
+ *	    pointer to response return
+ *	    application data
+ * Returns: PAM_SUCCESS if OK, response vector filled in, else PAM_CONV_ERR
+ */
+
+static int checkpw_conv (int num_msg,const struct pam_message **msg,
+			 struct pam_response **resp,void *appdata_ptr)
+{
+  int i;
+  struct checkpw_cred *cred = (struct checkpw_cred *) appdata_ptr;
+  struct pam_response *reply = fs_get (sizeof (struct pam_response) * num_msg);
+  for (i = 0; i < num_msg; i++) switch (msg[i]->msg_style) {
+  case PAM_PROMPT_ECHO_ON:	/* assume want user name */
+    reply[i].resp_retcode = PAM_SUCCESS;
+    reply[i].resp = cpystr (cred->uname);
+    break;
+  case PAM_PROMPT_ECHO_OFF:	/* assume want password */
+    reply[i].resp_retcode = PAM_SUCCESS;
+    reply[i].resp = cpystr (cred->pass);
+    break;
+  case PAM_TEXT_INFO:
+  case PAM_ERROR_MSG:
+    reply[i].resp_retcode = PAM_SUCCESS;
+    reply[i].resp = NULL;
+    break;
+  default:			/* unknown message style */
+    fs_give ((void **) &reply);
+    return PAM_CONV_ERR;
+  }
+  *resp = reply;
+  return PAM_SUCCESS;
+}
+
+
+/* PAM cleanup
+ * Accepts: handle
+ */
+
+static void checkpw_cleanup (pam_handle_t *hdl)
+{
+#if 0	/* see checkpw() for why this is #if 0 */
+  pam_close_session (hdl,NIL);	/* close session [uw]tmp */
+#endif
+  pam_setcred (hdl,PAM_DELETE_CRED);
+  pam_end (hdl,PAM_SUCCESS);
+}
+
+/* Server log in
+ * Accepts: user name string
+ *	    password string
+ * Returns: T if password validated, NIL otherwise
+ */
+
+struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
+{
+  pam_handle_t *hdl;
+  struct pam_conv conv;
+  struct checkpw_cred cred;
+  char *name = cpystr (pw->pw_name);
+  conv.conv = &checkpw_conv;
+  conv.appdata_ptr = &cred;
+  cred.uname = name;
+  cred.pass = pass;
+  if (pw = ((pam_start ((char *) mail_parameters (NIL,GET_SERVICENAME,NIL),
+			pw->pw_name,&conv,&hdl) == PAM_SUCCESS) &&
+	    (pam_set_item (hdl,PAM_RHOST,tcp_clientaddr ()) == PAM_SUCCESS) &&
+	    (pam_authenticate (hdl,NIL) == PAM_SUCCESS) &&
+	    (pam_acct_mgmt (hdl,NIL) == PAM_SUCCESS) &&
+	    (pam_setcred (hdl,PAM_ESTABLISH_CRED) == PAM_SUCCESS)) ?
+      getpwnam (name) : NIL) {
+#if 0
+    /*
+     * Some people have reported that this causes a SEGV in strncpy() from
+     * pam_unix.so.1
+     */
+    /*
+     * This pam_open_session() call is inconsistant with how we handle other
+     * platforms, where we don't write [uw]tmp records.  However, unlike our
+     * code on other platforms, pam_acct_mgmt() will check those records for
+     * inactivity and deny the authentication.
+     */
+    pam_open_session (hdl,NIL);	/* make sure account doesn't go inactive */
+#endif
+				/* arm hook to delete credentials */
+    mail_parameters (NIL,SET_LOGOUTHOOK,(void *) checkpw_cleanup);
+    mail_parameters (NIL,SET_LOGOUTDATA,(void *) hdl);
+  }
+  else checkpw_cleanup (hdl);	/* clean up */
+  fs_give ((void **) &name);
+				/* reset log facility in case PAM broke it */
+  if (myServerName) openlog (myServerName,LOG_PID,syslog_facility);
+  return pw;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ckp_pmb.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,128 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Pluggable Authentication Modules login services, buggy systems
+ *		(use this instead of ckp_pam.c on Solaris)
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	31 August 2006
+ */
+
+
+#include <security/pam_appl.h>
+
+static char *pam_uname;		/* user name */
+static char *pam_pass;		/* password */
+
+/* PAM conversation function
+ * Accepts: number of messages
+ *	    vector of messages
+ *	    pointer to response return
+ *	    application data
+ * Returns: PAM_SUCCESS if OK, response vector filled in, else PAM_CONV_ERR
+ */
+
+static int checkpw_conv (int num_msg,const struct pam_message **msg,
+			 struct pam_response **resp,void *appdata_ptr)
+{
+  int i;
+  struct pam_response *reply = fs_get (sizeof (struct pam_response) * num_msg);
+  for (i = 0; i < num_msg; i++) switch (msg[i]->msg_style) {
+  case PAM_PROMPT_ECHO_ON:	/* assume want user name */
+    reply[i].resp_retcode = PAM_SUCCESS;
+    reply[i].resp = cpystr (pam_uname);
+    break;
+  case PAM_PROMPT_ECHO_OFF:	/* assume want password */
+    reply[i].resp_retcode = PAM_SUCCESS;
+    reply[i].resp = cpystr (pam_pass);
+    break;
+  case PAM_TEXT_INFO:
+  case PAM_ERROR_MSG:
+    reply[i].resp_retcode = PAM_SUCCESS;
+    reply[i].resp = NULL;
+    break;
+  default:			/* unknown message style */
+    fs_give ((void **) &reply);
+    return PAM_CONV_ERR;
+  }
+  *resp = reply;
+  return PAM_SUCCESS;
+}
+
+
+/* PAM cleanup
+ * Accepts: handle
+ */
+
+static void checkpw_cleanup (pam_handle_t *hdl)
+{
+#if 0	/* see checkpw() for why this is #if 0 */
+  pam_close_session (hdl,NIL);	/* close session [uw]tmp */
+#endif
+  pam_setcred (hdl,PAM_DELETE_CRED);
+  pam_end (hdl,PAM_SUCCESS);
+}
+
+/* Server log in
+ * Accepts: user name string
+ *	    password string
+ * Returns: T if password validated, NIL otherwise
+ */
+
+struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
+{
+  pam_handle_t *hdl;
+  struct pam_conv conv;
+  char *name = cpystr (pw->pw_name);
+  conv.conv = &checkpw_conv;
+  pam_uname = pw->pw_name;
+  pam_pass = pass;
+  if (pw = ((pam_start ((char *) mail_parameters (NIL,GET_SERVICENAME,NIL),
+			pw->pw_name,&conv,&hdl) == PAM_SUCCESS) &&
+	    (pam_set_item (hdl,PAM_RHOST,tcp_clientaddr ()) == PAM_SUCCESS) &&
+	    (pam_authenticate (hdl,NIL) == PAM_SUCCESS) &&
+	    (pam_acct_mgmt (hdl,NIL) == PAM_SUCCESS) &&
+	    (pam_setcred (hdl,PAM_ESTABLISH_CRED) == PAM_SUCCESS)) ?
+      getpwnam (name) : NIL) {
+#if 0
+    /*
+     * Some people have reported that this causes a SEGV in strncpy() from
+     * pam_unix.so.1
+     */
+    /*
+     * This pam_open_session() call is inconsistant with how we handle other
+     * platforms, where we don't write [uw]tmp records.  However, unlike our
+     * code on other platforms, pam_acct_mgmt() will check those records for
+     * inactivity and deny the authentication.
+     */
+    pam_open_session (hdl,NIL);	/* make sure account doesn't go inactive */
+#endif
+				/* arm hook to delete credentials */
+    mail_parameters (NIL,SET_LOGOUTHOOK,(void *) checkpw_cleanup);
+    mail_parameters (NIL,SET_LOGOUTDATA,(void *) hdl);
+  }
+  else checkpw_cleanup (hdl);	/* clean up */
+  fs_give ((void **) &name);
+				/* reset log facility in case PAM broke it */
+  if (myServerName) openlog (myServerName,LOG_PID,syslog_facility);
+  return pw;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ckp_psx.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,101 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	POSIX check password
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Check password
+ * Accepts: login passwd struct
+ *	    password string
+ *	    argument count
+ *	    argument vector
+ * Returns: passwd struct if password validated, NIL otherwise
+ */
+
+struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
+{
+  char tmp[MAILTMPLEN];
+  struct spwd *sp = NIL;
+  time_t left;
+  time_t now = time (0);
+  struct tm *t = gmtime (&now);
+  int zone = t->tm_hour * 60 + t->tm_min;
+  int julian = t->tm_yday;
+  t = localtime (&now);		/* get local time now */
+				/* minus UTC minutes since midnight */
+  zone = t->tm_hour * 60 + t->tm_min - zone;
+  /* julian can be one of:
+   *  36x  local time is December 31, UTC is January 1, offset -24 hours
+   *    1  local time is 1 day ahead of UTC, offset +24 hours
+   *    0  local time is same day as UTC, no offset
+   *   -1  local time is 1 day behind UTC, offset -24 hours
+   * -36x  local time is January 1, UTC is December 31, offset +24 hours
+   */
+  if (julian = t->tm_yday -julian)
+    zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
+				/* days since 1/1/1970 local time */
+  now = ((now /60) + zone) / (60*24);
+				/* non-shadow authentication */
+  if (!pw->pw_passwd || !pw->pw_passwd[0] || !pw->pw_passwd[1] ||
+      strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) {
+    /* As far as I've been able to determine, here is how the expiration
+     * fields in the shadow authentication data work:
+     *  lstchg	last password change date if non-negative.  If zero, the
+     *		user can not log in without changing password.
+     *  max	number of days a password is valid if positive
+     *  warn	number of days of password expiration warning
+     *  expire	date account expires if positive
+     *  inact	number of days an accout can be inactive (not checked!)
+     * The expiration day is the *last* day that the password or account
+     * is valid.
+     */
+				/* shadow authentication */
+    if ((sp = getspnam (pw->pw_name)) && sp->sp_lstchg &&
+	((sp->sp_lstchg < 0) || (sp->sp_max <= 0) ||
+	 ((sp->sp_lstchg + sp->sp_max) >= now)) &&
+	((sp->sp_expire <= 0) || (sp->sp_expire >= now)) &&
+	sp->sp_pwdp && sp->sp_pwdp[0] && sp->sp_pwdp[1] &&
+	!strcmp (sp->sp_pwdp,(char *) crypt (pass,sp->sp_pwdp))) {
+      if ((sp->sp_lstchg > 0) && (sp->sp_max > 0) &&
+	  ((left = (sp->sp_lstchg + sp->sp_max) - now) <= sp->sp_warn)) {
+	if (left) {
+	  sprintf (tmp,"[ALERT] Password expires in %ld day(s)",(long) left);
+	  mm_notify (NIL,tmp,NIL);
+	}
+	else mm_notify (NIL,"[ALERT] Password expires today!",WARN);
+      }
+      if ((sp->sp_expire > 0) && ((left = sp->sp_expire - now) < 28)) {
+	if (left) {
+	  sprintf (tmp,"[ALERT] Account expires in %ld day(s)",(long) left);
+	  mm_notify (NIL,tmp,NIL);
+	}
+	else mm_notify (NIL,"[ALERT] Account expires today!",WARN);
+      }
+      endspent ();		/* don't need shadow password data any more */
+    }
+    else pw = NIL;		/* password failed */
+  }
+  return pw;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ckp_sce.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,51 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	SecureWare check password
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Check password
+ * Accepts: login passwd struct
+ *	    password string
+ *	    argument count
+ *	    argument vector
+ * Returns: passwd struct if password validated, NIL otherwise
+ */
+
+struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
+{
+  struct es_passwd *pp;
+  set_auth_parameters (argc,argv);
+  if ((pw->pw_passwd && pw->pw_passwd[0] && pw->pw_passwd[1] &&
+       !strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) ||
+      ((pp = getespwnam (pw->pw_name)) && !pp->ufld->fd_lock &&
+       !pp->ufld->fd_psw_chg_reqd &&
+       pp->ufld->fd_encrypt && pp->ufld->fd_encrypt[0] &&
+       pp->ufld->fd_encrypt[1] &&
+       !strcmp (pp->ufld->fd_encrypt,bigcrypt (pass,pp->ufld->fd_encrypt))))
+    endprpwent ();		/* don't need shadow password data any more */
+  else pw = NIL;		/* password failed */
+  return pw;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ckp_sec.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,50 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	SecureWare check password
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Check password
+ * Accepts: login passwd struct
+ *	    password string
+ *	    argument count
+ *	    argument vector
+ * Returns: passwd struct if password validated, NIL otherwise
+ */
+
+struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
+{
+  struct pr_passwd *pp;
+  set_auth_parameters (argc,argv);
+  if ((pw->pw_passwd && pw->pw_passwd[0] && pw->pw_passwd[1] &&
+       !strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) ||
+      ((pp = getprpwnam (pw->pw_name)) && !pp->ufld.fd_lock &&
+       pp->ufld.fd_encrypt && pp->ufld.fd_encrypt[0] &&
+       pp->ufld.fd_encrypt[1] &&
+       !strcmp (pp->ufld.fd_encrypt,bigcrypt (pass,pp->ufld.fd_encrypt))))
+    endprpwent ();		/* don't need shadow password data any more */
+  else pw = NIL;		/* password failed */
+  return pw;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ckp_ssn.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,56 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Secure SUN-OS check password
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+#include <sys/label.h>
+#include <sys/audit.h>
+#include <pwdadj.h>
+
+
+/* Check password
+ * Accepts: login passwd struct
+ *	    password string
+ *	    argument count
+ *	    argument vector
+ * Returns: passwd struct if password validated, NIL otherwise
+ */
+
+struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
+{
+  struct passwd_adjunct *pa;
+  char *user = cpystr (pw->pw_name);
+				/* validate user and password */
+  struct passwd *ret =
+    ((pw->pw_passwd && pw->pw_passwd[0] && pw->pw_passwd[1] &&
+      !strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) ||
+     ((pa = getpwanam (pw->pw_name)) &&
+      pa->pwa_passwd && pa->pwa_passwd[0] && pa->pwa_passwd[1] &&
+      !strcmp (pa->pwa_passwd,(char *) crypt (pass,pa->pwa_passwd)))) ?
+	getpwnam (user) : NIL;
+  if (user) fs_give ((void **) &user);
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ckp_std.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,42 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Standard check password
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Check password
+ * Accepts: login passwd struct
+ *	    password string
+ *	    argument count
+ *	    argument vector
+ * Returns: passwd struct if password validated, NIL otherwise
+ */
+
+struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
+{
+  return (pw->pw_passwd && pw->pw_passwd[0] && pw->pw_passwd[1] &&
+	  !strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) ?
+	    pw : NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ckp_sv4.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,90 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	SVR4 check password
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Check password
+ * Accepts: login passwd struct
+ *	    password string
+ *	    argument count
+ *	    argument vector
+ * Returns: passwd struct if password validated, NIL otherwise
+ */
+
+struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
+{
+  char tmp[MAILTMPLEN];
+  struct spwd *sp = NIL;
+  time_t left;
+  time_t now = time (0);
+  struct tm *t = gmtime (&now);
+  int zone = t->tm_hour * 60 + t->tm_min;
+  int julian = t->tm_yday;
+  t = localtime (&now);		/* get local time now */
+				/* minus UTC minutes since midnight */
+  zone = t->tm_hour * 60 + t->tm_min - zone;
+  /* julian can be one of:
+   *  36x  local time is December 31, UTC is January 1, offset -24 hours
+   *    1  local time is 1 day ahead of UTC, offset +24 hours
+   *    0  local time is same day as UTC, no offset
+   *   -1  local time is 1 day behind UTC, offset -24 hours
+   * -36x  local time is January 1, UTC is December 31, offset +24 hours
+   */
+  if (julian = t->tm_yday -julian)
+    zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
+				/* days since 1/1/1970 local time */
+  now = ((now /60) + zone) / (60*24);
+				/* non-shadow authentication */
+  if (!pw->pw_passwd || !pw->pw_passwd[0] || !pw->pw_passwd[1] ||
+      strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) {
+    /* As far as I've been able to determine, here is how the expiration
+     * fields in the shadow authentication data work:
+     *  lstchg	last password change date if non-negative.  If zero, the
+     *		user can not log in without changing password.
+     *  max	number of days a password is valid if positive
+     *  warn	number of days of password expiration warning
+     * The expiration day is the *last* day that the password is valid.
+     */
+				/* shadow authentication */
+    if ((sp = getspnam (pw->pw_name)) && sp->sp_lstchg &&
+	((sp->sp_lstchg < 0) || (sp->sp_max <= 0) ||
+	 ((sp->sp_lstchg + sp->sp_max) >= now)) &&
+	sp->sp_pwdp && sp->sp_pwdp[0] && sp->sp_pwdp[1] &&
+	!strcmp (sp->sp_pwdp,(char *) crypt (pass,sp->sp_pwdp))) {
+      if ((sp->sp_lstchg > 0) && (sp->sp_max > 0) &&
+	  ((left = (sp->sp_lstchg + sp->sp_max) - now) <= sp->sp_warn)) {
+	if (left) {
+	  sprintf (tmp,"[ALERT] Password expires in %ld day(s)",(long) left);
+	  mm_notify (NIL,tmp,NIL);
+	}
+	else mm_notify (NIL,"[ALERT] Password expires today!",WARN);
+      }
+      endspent ();		/* don't need shadow password data any more */
+    }
+    else pw = NIL;		/* password failed */
+  }
+  return pw;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ckp_svo.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,89 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Old SVR4 check password
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Check password
+ * Accepts: login passwd struct
+ *	    password string
+ *	    argument count
+ *	    argument vector
+ * Returns: passwd struct if password validated, NIL otherwise
+ */
+
+struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
+{
+  char tmp[MAILTMPLEN];
+  struct spwd *sp = NIL;
+  time_t left;
+  time_t now = time (0);
+  struct tm *t = gmtime (&now);
+  int zone = t->tm_hour * 60 + t->tm_min;
+  int julian = t->tm_yday;
+  t = localtime (&now);		/* get local time now */
+				/* minus UTC minutes since midnight */
+  zone = t->tm_hour * 60 + t->tm_min - zone;
+  /* julian can be one of:
+   *  36x  local time is December 31, UTC is January 1, offset -24 hours
+   *    1  local time is 1 day ahead of UTC, offset +24 hours
+   *    0  local time is same day as UTC, no offset
+   *   -1  local time is 1 day behind UTC, offset -24 hours
+   * -36x  local time is January 1, UTC is December 31, offset +24 hours
+   */
+  if (julian = t->tm_yday -julian)
+    zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
+				/* days since 1/1/1970 local time */
+  now = ((now /60) + zone) / (60*24);
+				/* non-shadow authentication */
+  if (!pw->pw_passwd || !pw->pw_passwd[0] || !pw->pw_passwd[1] ||
+      strcmp (pw->pw_passwd,(char *) crypt (pass,pw->pw_passwd))) {
+    /* As far as I've been able to determine, here is how the expiration
+     * fields in the shadow authentication data work:
+     *  lstchg	last password change date if non-negative.  If zero, the
+     *		user can not log in without changing password.
+     *  max	number of days a password is valid if positive
+     * The expiration day is the *last* day that the password is valid.
+     */
+				/* shadow authentication */
+    if ((sp = getspnam (pw->pw_name)) && sp->sp_lstchg &&
+	((sp->sp_lstchg < 0) || (sp->sp_max <= 0) ||
+	 ((sp->sp_lstchg + sp->sp_max) >= now)) &&
+	sp->sp_pwdp && sp->sp_pwdp[0] && sp->sp_pwdp[1] &&
+	!strcmp (sp->sp_pwdp,(char *) crypt (pass,sp->sp_pwdp))) {
+      if ((sp->sp_lstchg > 0) && (sp->sp_max > 0) &&
+	  ((left = (sp->sp_lstchg + sp->sp_max) - now) <= 28)) {
+	if (left) {
+	  sprintf (tmp,"[ALERT] Password expires in %ld day(s)",(long) left);
+	  mm_notify (NIL,tmp,NIL);
+	}
+	else mm_notify (NIL,"[ALERT] Password expires today!",WARN);
+      }
+      endspent ();		/* don't need shadow password data any more */
+    }
+    else pw = NIL;		/* password failed */
+  }
+  return pw;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ckp_ult.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,40 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	ULTRIX check password
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Check password
+ * Accepts: login passwd struct
+ *	    password string
+ *	    argument count
+ *	    argument vector
+ * Returns: passwd struct if password validated, NIL otherwise
+ */
+
+struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[])
+{
+  return (authenticate_user (pw,pass,NIL) >= 0) ? pw : NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/crx_nfs.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,79 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Exclusive create of a file, NFS kludge version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	17 December 1999
+ * Last Edited:	30 August 2006
+ */
+
+
+/* SUN-OS had an NFS, As kludgy as an albatross;
+ * And everywhere that it was installed, It was a total loss.
+ *  -- MRC 9/25/91
+ */
+
+/* Exclusive create of a file
+ * Accepts: file name
+ * Return: T if success, NIL if failed, -1 if retry
+ */
+
+long crexcl (char *name)
+{
+  long ret = -1;
+  int i;
+  char hitch[MAILTMPLEN];
+  struct stat sb;
+  int mask = umask (0);
+				/* build hitching post file name */
+  sprintf (hitch,"%s.%lu.%d.",name,(unsigned long) time (0),getpid ());
+  i = strlen (hitch);		/* append local host name */
+  gethostname (hitch + i,(MAILTMPLEN - i) - 1);
+				/* try to get hitching-post file */
+  if ((i = open (hitch,O_WRONLY|O_CREAT|O_EXCL,(int) shlock_mode)) >= 0) {
+    close (i);			/* close the hitching-post */
+    /* Note: link() may return an error even if it actually succeeded.  So we
+     * always check for success via the link count, and ignore the error if
+     * the link count is right.
+     */
+				/* tie hitching-post to lock */
+    i = link (hitch,name) ? errno : 0;
+				/* success if link count now 2 */
+    if (!stat (hitch,&sb) && (sb.st_nlink == 2)) ret = LONGT;
+    else if (i == EPERM) {	/* links not allowed? */
+      /* Probably a FAT filesystem on Linux.  It can't be NFS, so try creating
+       * the lock file directly.
+       */
+      if ((i = open (name,O_WRONLY|O_CREAT|O_EXCL,(int) shlock_mode)) >= 0){
+	close (i);		/* close the file */
+	ret = LONGT;		/* success */
+      }
+				/* fail unless error is EEXIST */
+      else if (errno != EEXIST) ret = NIL;
+    }
+    unlink (hitch);		/* flush hitching post */
+  }
+				/* fail unless error is EEXIST */
+  else if (errno != EEXIST) ret = NIL;
+  umask (mask);			/* restore previous mask */
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/crx_std.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,45 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Exclusive create of a file
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	17 December 1999
+ * Last Edited:	30 August 2006
+ */
+
+/* Exclusive create of a file
+ * Accepts: file name
+ * Return: T if success, NIL if failed, -1 if retry
+ */
+
+long crexcl (char *name)
+{
+  int i;
+  int mask = umask (0);
+  long ret = LONGT;
+				/* try to get the lock */
+  if ((i = open (name,O_WRONLY|O_CREAT|O_EXCL,(int) shlock_mode)) < 0)
+    ret = (errno == EEXIST) ? -1 : NIL;
+  else close (i);		/* made the file, now close it */
+  umask (mask);			/* restore previous mask */
+  return LONGT;			/* success */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/drivers	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,36 @@
+#!/bin/sh
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+# Program:	Driver Linkage Generator
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		11 October 1989
+# Last Edited:	30 August 2006
+
+
+# Erase old driver linkage
+rm -f linkage.[ch]
+
+# Now define the new list
+for driver
+ do
+  echo "extern DRIVER "$driver"driver;" >> linkage.h
+  echo "  mail_link (&"$driver"driver);		/* link in the $driver driver */" | cat >> linkage.c
+done
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/dummy.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,809 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Dummy routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	9 May 1991
+ * Last Edited:	1 June 2007
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "mail.h"
+#include "osdep.h"
+#include <pwd.h>
+#include <sys/stat.h>
+#include "dummy.h"
+#include "misc.h"
+
+/* Function prototypes */
+
+DRIVER *dummy_valid (char *name);
+void *dummy_parameters (long function,void *value);
+void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents,
+		      long level);
+long dummy_listed (MAILSTREAM *stream,char delimiter,char *name,
+		   long attributes,char *contents);
+long dummy_subscribe (MAILSTREAM *stream,char *mailbox);
+MAILSTREAM *dummy_open (MAILSTREAM *stream);
+void dummy_close (MAILSTREAM *stream,long options);
+long dummy_ping (MAILSTREAM *stream);
+void dummy_check (MAILSTREAM *stream);
+long dummy_expunge (MAILSTREAM *stream,char *sequence,long options);
+long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+/* Dummy routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER dummydriver = {
+  "dummy",			/* driver name */
+  DR_LOCAL|DR_MAIL,		/* driver flags */
+  (DRIVER *) NIL,		/* next driver */
+  dummy_valid,			/* mailbox is valid for us */
+  dummy_parameters,		/* manipulate parameters */
+  dummy_scan,			/* scan mailboxes */
+  dummy_list,			/* list mailboxes */
+  dummy_lsub,			/* list subscribed mailboxes */
+  dummy_subscribe,		/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  dummy_create,			/* create mailbox */
+  dummy_delete,			/* delete mailbox */
+  dummy_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  dummy_open,			/* open mailbox */
+  dummy_close,			/* close mailbox */
+  NIL,				/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message structure */
+  NIL,				/* fetch header */
+  NIL,				/* fetch text */
+  NIL,				/* fetch message data */
+  NIL,				/* unique identifier */
+  NIL,				/* message number from UID */
+  NIL,				/* modify flags */
+  NIL,				/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  dummy_ping,			/* ping mailbox to see if still alive */
+  dummy_check,			/* check for new messages */
+  dummy_expunge,		/* expunge deleted messages */
+  dummy_copy,			/* copy messages to another mailbox */
+  dummy_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM dummyproto = {&dummydriver};
+
+/* Dummy validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *dummy_valid (char *name)
+{
+  char *s,tmp[MAILTMPLEN];
+  struct stat sbuf;
+				/* must be valid local mailbox */
+  if (name && *name && (*name != '{') && (s = mailboxfile (tmp,name))) {
+				/* indeterminate clearbox INBOX */
+    if (!*s) return &dummydriver;
+    else if (!stat (s,&sbuf)) switch (sbuf.st_mode & S_IFMT) {
+    case S_IFREG:
+    case S_IFDIR:
+      return &dummydriver;
+    }
+				/* blackbox INBOX does not exist yet */
+    else if (!compare_cstring (name,"INBOX")) return &dummydriver;
+  }
+  return NIL;
+}
+
+
+/* Dummy manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *dummy_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case GET_INBOXPATH:
+    if (value) ret = dummy_file ((char *) value,"INBOX");
+    break;
+  }
+  return ret;
+}
+
+/* Dummy scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  DRIVER *drivers;
+  char *s,test[MAILTMPLEN],file[MAILTMPLEN];
+  long i;
+  if (!pat || !*pat) {		/* empty pattern? */
+    if (dummy_canonicalize (test,ref,"*")) {
+				/* tie off name at root */
+      if (s = strchr (test,'/')) *++s = '\0';
+      else test[0] = '\0';
+      dummy_listed (stream,'/',test,LATT_NOSELECT,NIL);
+    }
+  }
+				/* get canonical form of name */
+  else if (dummy_canonicalize (test,ref,pat)) {
+				/* found any wildcards? */
+    if (s = strpbrk (test,"%*")) {
+				/* yes, copy name up to that point */
+      strncpy (file,test,i = s - test);
+      file[i] = '\0';		/* tie off */
+    }
+    else strcpy (file,test);	/* use just that name then */
+    if (s = strrchr (file,'/')){/* find directory name */
+      *++s = '\0';		/* found, tie off at that point */
+      s = file;
+    }
+				/* silly case */
+    else if ((file[0] == '~') || (file[0] == '#')) s = file;
+				/* do the work */
+    dummy_list_work (stream,s,test,contents,0);
+				/* always an INBOX */
+    if (pmatch ("INBOX",ucase (test))) {
+				/* done if have a dirfmt INBOX */
+      for (drivers = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL);
+	   drivers && !(!(drivers->flags & DR_DISABLE) &&
+			(drivers->flags & DR_DIRFMT) &&
+			(*drivers->valid) ("INBOX")); drivers = drivers->next);
+				/* list INBOX appropriately */
+      dummy_listed (stream,drivers ? '/' : NIL,"INBOX",
+		    drivers ? NIL : LATT_NOINFERIORS,contents);
+    }
+  }
+}
+
+
+/* Dummy list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void dummy_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  dummy_scan (stream,ref,pat,NIL);
+}
+
+/* Dummy list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  void *sdb = NIL;
+  char *s,*t,test[MAILTMPLEN],tmp[MAILTMPLEN];
+  int showuppers = pat[strlen (pat) - 1] == '%';
+				/* get canonical form of name */
+  if (dummy_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) do
+    if (*s != '{') {
+      if (!compare_cstring (s,"INBOX") &&
+	  pmatch ("INBOX",ucase (strcpy (tmp,test))))
+	mm_lsub (stream,NIL,s,LATT_NOINFERIORS);
+      else if (pmatch_full (s,test,'/')) mm_lsub (stream,'/',s,NIL);
+      else while (showuppers && (t = strrchr (s,'/'))) {
+	*t = '\0';		/* tie off the name */
+	if (pmatch_full (s,test,'/')) mm_lsub (stream,'/',s,LATT_NOSELECT);
+      }
+    }
+  while (s = sm_read (&sdb));	/* until no more subscriptions */
+}
+
+
+/* Dummy subscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to add to subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_subscribe (MAILSTREAM *stream,char *mailbox)
+{
+  char *s,tmp[MAILTMPLEN];
+  struct stat sbuf;
+				/* must be valid local mailbox */
+  if ((s = mailboxfile (tmp,mailbox)) && *s && !stat (s,&sbuf))
+    switch (sbuf.st_mode & S_IFMT) {
+    case S_IFDIR:		/* allow but snarl */
+      sprintf (tmp,"CLIENT BUG DETECTED: subscribe of non-mailbox directory %.80s",
+	       mailbox);
+      MM_NOTIFY (stream,tmp,WARN);
+    case S_IFREG:
+      return sm_subscribe (mailbox);
+    }
+  sprintf (tmp,"Can't subscribe %.80s: not a mailbox",mailbox);
+  MM_LOG (tmp,ERROR);
+  return NIL;
+}
+
+/* Dummy list mailboxes worker routine
+ * Accepts: mail stream
+ *	    directory name to search
+ *	    search pattern
+ *	    string to scan
+ *	    search level
+ */
+
+void dummy_list_work (MAILSTREAM *stream,char *dir,char *pat,char *contents,
+		      long level)
+{
+  DRIVER *drivers;
+  dirfmttest_t dt;
+  DIR *dp;
+  struct direct *d;
+  struct stat sbuf;
+  char tmp[MAILTMPLEN],path[MAILTMPLEN];
+  size_t len = 0;
+				/* punt if bogus name */
+  if (!mailboxdir (tmp,dir,NIL)) return;
+  if (dp = opendir (tmp)) {	/* do nothing if can't open directory */
+				/* see if a non-namespace directory format */
+    for (drivers = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL), dt = NIL;
+	 dir && !dt && drivers; drivers = drivers->next)
+      if (!(drivers->flags & DR_DISABLE) && (drivers->flags & DR_DIRFMT) &&
+	  (*drivers->valid) (dir))
+	dt = mail_parameters ((*drivers->open) (NIL),GET_DIRFMTTEST,NIL);
+				/* list it if at top-level */
+    if (!level && dir && pmatch_full (dir,pat,'/') && !pmatch (dir,"INBOX"))
+      dummy_listed (stream,'/',dir,dt ? NIL : LATT_NOSELECT,contents);
+
+				/* scan directory, ignore . and .. */
+    if (!dir || dir[(len = strlen (dir)) - 1] == '/') while (d = readdir (dp))
+      if ((!(dt && (*dt) (d->d_name))) &&
+	  ((d->d_name[0] != '.') ||
+	   (((long) mail_parameters (NIL,GET_HIDEDOTFILES,NIL)) ? NIL :
+	    (d->d_name[1] && (((d->d_name[1] != '.') || d->d_name[2]))))) &&
+	  ((len + strlen (d->d_name)) <= NETMAXMBX)) {
+				/* see if name is useful */
+	if (dir) sprintf (tmp,"%s%s",dir,d->d_name);
+	else strcpy (tmp,d->d_name);
+				/* make sure useful and can get info */
+	if ((pmatch_full (strcpy (path,tmp),pat,'/') ||
+	     pmatch_full (strcat (path,"/"),pat,'/') ||
+	     dmatch (path,pat,'/')) &&
+	    mailboxdir (path,dir,"x") && (len = strlen (path)) &&
+	    strcpy (path+len-1,d->d_name) && !stat (path,&sbuf)) {
+				/* only interested in file type */
+	  switch (sbuf.st_mode & S_IFMT) {
+	  case S_IFDIR:		/* directory? */
+				/* form with trailing / */
+	    sprintf (path,"%s/",tmp);
+				/* skip listing if INBOX */
+	    if (!pmatch (tmp,"INBOX")) {
+	      if (pmatch_full (tmp,pat,'/')) {
+		if (!dummy_listed (stream,'/',tmp,LATT_NOSELECT,contents))
+		  break;
+	      }
+				/* try again with trailing / */
+	      else if (pmatch_full (path,pat,'/') &&
+		       !dummy_listed (stream,'/',path,LATT_NOSELECT,contents))
+		break;
+	    }
+	    if (dmatch (path,pat,'/') &&
+		(level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL)))
+	      dummy_list_work (stream,path,pat,contents,level+1);
+	    break;
+	  case S_IFREG:		/* ordinary name */
+	    /* Must use ctime for systems that don't update mtime properly */
+	    if (pmatch_full (tmp,pat,'/') && compare_cstring (tmp,"INBOX"))
+	      dummy_listed (stream,'/',tmp,LATT_NOINFERIORS +
+			    ((sbuf.st_size && (sbuf.st_atime < sbuf.st_ctime))?
+			     LATT_MARKED : LATT_UNMARKED),contents);
+	    break;
+	  }
+	}
+      }
+    closedir (dp);		/* all done, flush directory */
+  }
+}
+
+/* Scan file for contents
+ * Accepts: driver to use
+ *	    file name
+ *	    desired contents
+ *	    length of contents
+ *	    size of file
+ * Returns: NIL if contents not found, T if found
+ */
+
+long scan_contents (DRIVER *dtb,char *name,char *contents,
+		    unsigned long csiz,unsigned long fsiz)
+{
+  scancontents_t sc = dtb ?
+    (scancontents_t) (*dtb->parameters) (GET_SCANCONTENTS,NIL) : NIL;
+  return (*(sc ? sc : dummy_scan_contents)) (name,contents,csiz,fsiz);
+}
+
+
+/* Scan file for contents
+ * Accepts: file name
+ *	    desired contents
+ *	    length of contents
+ *	    size of file
+ * Returns: NIL if contents not found, T if found
+ */
+
+#define BUFSIZE 4*MAILTMPLEN
+
+long dummy_scan_contents (char *name,char *contents,unsigned long csiz,
+			  unsigned long fsiz)
+{
+  int fd;
+  unsigned long ssiz,bsiz;
+  char *buf;
+				/* forget it if can't select or open */
+  if ((fd = open (name,O_RDONLY,NIL)) >= 0) {
+				/* get buffer including slop */    
+    buf = (char *) fs_get (BUFSIZE + (ssiz = 4 * ((csiz / 4) + 1)) + 1);
+    memset (buf,'\0',ssiz);	/* no slop area the first time */
+    while (fsiz) {		/* until end of file */
+      read (fd,buf+ssiz,bsiz = min (fsiz,BUFSIZE));
+      if (search ((unsigned char *) buf,bsiz+ssiz,
+		  (unsigned char *) contents,csiz)) break;
+      memcpy (buf,buf+BUFSIZE,ssiz);
+      fsiz -= bsiz;		/* note that we read that much */
+    }
+    fs_give ((void **) &buf);	/* flush buffer */
+    close (fd);			/* finished with file */
+    if (fsiz) return T;		/* found */
+  }
+  return NIL;			/* not found */
+}
+
+/* Mailbox found
+ * Accepts: MAIL stream
+ *	    hierarchy delimiter
+ *	    mailbox name
+ *	    attributes
+ *	    contents to search before calling mm_list()
+ * Returns: NIL if should abort hierarchy search, else T (currently always)
+ */
+
+long dummy_listed (MAILSTREAM *stream,char delimiter,char *name,
+		   long attributes,char *contents)
+{
+  DRIVER *d;
+  DIR *dp;
+  struct direct *dr;
+  dirfmttest_t dt;
+  unsigned long csiz;
+  struct stat sbuf;
+  int nochild;
+  char *s,tmp[MAILTMPLEN];
+  if (!(attributes & LATT_NOINFERIORS) && mailboxdir (tmp,name,NIL) &&
+      (dp = opendir (tmp))) {	/* if not \NoInferiors */
+				/* locate dirfmttest if any */
+    for (d = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL), dt = NIL;
+	 !dt && d; d = d->next)
+      if (!(d->flags & DR_DISABLE) && (d->flags & DR_DIRFMT) &&
+	  (*d->valid) (name))
+	dt = mail_parameters ((*d->open) (NIL),GET_DIRFMTTEST,NIL);
+				/* scan directory for children */
+    for (nochild = T; nochild && (dr = readdir (dp)); )
+      if ((!(dt && (*dt) (dr->d_name))) &&
+	  ((dr->d_name[0] != '.') ||
+	   (((long) mail_parameters (NIL,GET_HIDEDOTFILES,NIL)) ? NIL :
+	    (dr->d_name[1] && ((dr->d_name[1] != '.') || dr->d_name[2])))))
+	nochild = NIL;
+    attributes |= nochild ? LATT_HASNOCHILDREN : LATT_HASCHILDREN;
+    closedir (dp);		/* all done, flush directory */
+  }
+  d = NIL;			/* don't \NoSelect dir if it has a driver */
+  if ((attributes & LATT_NOSELECT) && (d = mail_valid (NIL,name,NIL)) &&
+      (d != &dummydriver)) attributes &= ~LATT_NOSELECT;
+  if (!contents ||		/* notify main program */
+      (!(attributes & LATT_NOSELECT) && (csiz = strlen (contents)) &&
+       (s = mailboxfile (tmp,name)) &&
+       (*s || (s = mail_parameters (NIL,GET_INBOXPATH,tmp))) &&
+       !stat (s,&sbuf) && (d || (csiz <= sbuf.st_size)) &&
+       SAFE_SCAN_CONTENTS (d,tmp,contents,csiz,sbuf.st_size)))
+    mm_list (stream,delimiter,name,attributes);
+  return T;
+}
+
+/* Dummy create mailbox
+ * Accepts: mail stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_create (MAILSTREAM *stream,char *mailbox)
+{
+  char *s,tmp[MAILTMPLEN];
+  long ret = NIL;
+				/* validate name */
+  if (!(compare_cstring (mailbox,"INBOX") && (s = dummy_file (tmp,mailbox)))) {
+    sprintf (tmp,"Can't create %.80s: invalid name",mailbox);
+    MM_LOG (tmp,ERROR);
+  }
+				/* create the name, done if made directory */
+  else if ((ret = dummy_create_path (stream,tmp,get_dir_protection(mailbox)))&&
+	   (s = strrchr (s,'/')) && !s[1]) return T;
+  return ret ? set_mbx_protections (mailbox,tmp) : NIL;
+}
+
+/* Dummy create path
+ * Accepts: mail stream
+ *	    path name to create
+ *	    directory mode
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode)
+{
+  struct stat sbuf;
+  char c,*s,tmp[MAILTMPLEN];
+  int fd;
+  long ret = NIL;
+  char *t = strrchr (path,'/');
+  int wantdir = t && !t[1];
+  int mask = umask (0);
+  if (wantdir) *t = '\0';	/* flush trailing delimiter for directory */
+  if (s = strrchr (path,'/')) {	/* found superior to this name? */
+    c = *++s;			/* remember first character of inferior */
+    *s = '\0';			/* tie off to get just superior */
+				/* name doesn't exist, create it */
+    if ((stat (path,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+	!dummy_create_path (stream,path,dirmode)) {
+      umask (mask);		/* restore mask */
+      return NIL;
+    }
+    *s = c;			/* restore full name */
+  }
+  if (wantdir) {		/* want to create directory? */
+    ret = !mkdir (path,(int) dirmode);
+    *t = '/';			/* restore directory delimiter */
+  }
+				/* create file */
+  else if ((fd = open (path,O_WRONLY|O_CREAT|O_EXCL,
+		       (long) mail_parameters(NIL,GET_MBXPROTECTION,NIL))) >=0)
+    ret = !close (fd);
+  if (!ret) {			/* error? */
+    sprintf (tmp,"Can't create mailbox node %.80s: %.80s",path,strerror (errno));
+    MM_LOG (tmp,ERROR);
+  }
+  umask (mask);			/* restore mask */
+  return ret;			/* return status */
+}
+
+/* Dummy delete mailbox
+ * Accepts: mail stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_delete (MAILSTREAM *stream,char *mailbox)
+{
+  struct stat sbuf;
+  char *s,tmp[MAILTMPLEN];
+  if (!(s = dummy_file (tmp,mailbox))) {
+    sprintf (tmp,"Can't delete - invalid name: %.80s",s);
+    MM_LOG (tmp,ERROR);
+  }
+				/* no trailing / (workaround BSD kernel bug) */
+  if ((s = strrchr (tmp,'/')) && !s[1]) *s = '\0';
+  if (stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) == S_IFDIR) ?
+      rmdir (tmp) : unlink (tmp)) {
+    sprintf (tmp,"Can't delete mailbox %.80s: %.80s",mailbox,strerror (errno));
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+  return T;			/* return success */
+}
+
+/* Mail rename mailbox
+ * Accepts: mail stream
+ *	    old mailbox name
+ *	    new mailbox name
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  struct stat sbuf;
+  char c,*s,tmp[MAILTMPLEN],mbx[MAILTMPLEN],oldname[MAILTMPLEN];
+				/* no trailing / allowed */
+  if (!dummy_file (oldname,old) || !(s = dummy_file (mbx,newname)) ||
+      stat (oldname,&sbuf) || ((s = strrchr (s,'/')) && !s[1] &&
+			       ((sbuf.st_mode & S_IFMT) != S_IFDIR))) {
+    sprintf (mbx,"Can't rename %.80s to %.80s: invalid name",old,newname);
+    MM_LOG (mbx,ERROR);
+    return NIL;
+  }
+  if (s) {			/* found a directory delimiter? */
+    if (!s[1]) *s = '\0';	/* ignore trailing delimiter */
+    else {			/* found superior to destination name? */
+      c = *++s;			/* remember first character of inferior */
+      *s = '\0';		/* tie off to get just superior */
+				/* name doesn't exist, create it */
+      if ((stat (mbx,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+	  !dummy_create (stream,mbx)) return NIL;
+      *s = c;			/* restore full name */
+    }
+  }
+				/* rename of non-ex INBOX creates dest */
+  if (!compare_cstring (old,"INBOX") && stat (oldname,&sbuf))
+    return dummy_create (NIL,mbx);
+  if (rename (oldname,mbx)) {
+    sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %.80s",old,newname,
+	     strerror (errno));
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+  return T;			/* return success */
+}
+
+/* Dummy open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *dummy_open (MAILSTREAM *stream)
+{
+  int fd;
+  char err[MAILTMPLEN],tmp[MAILTMPLEN];
+  struct stat sbuf;
+				/* OP_PROTOTYPE call */
+  if (!stream) return &dummyproto;
+  err[0] = '\0';		/* no error message yet */
+				/* can we open the file? */
+  if (!dummy_file (tmp,stream->mailbox))
+    sprintf (err,"Can't open this name: %.80s",stream->mailbox);
+  else if ((fd = open (tmp,O_RDONLY,NIL)) < 0) {
+				/* no, error unless INBOX */
+    if (compare_cstring (stream->mailbox,"INBOX"))
+      sprintf (err,"%.80s: %.80s",strerror (errno),stream->mailbox);
+  }
+  else {			/* file had better be empty then */
+    fstat (fd,&sbuf);		/* sniff at its size */
+    close (fd);
+    if ((sbuf.st_mode & S_IFMT) != S_IFREG)
+      sprintf (err,"Can't open %.80s: not a selectable mailbox",
+	       stream->mailbox);
+    else if (sbuf.st_size)	/* bogus format if non-empty */
+      sprintf (err,"Can't open %.80s (file %.80s): not in valid mailbox format",
+	       stream->mailbox,tmp);
+  }
+  if (err[0]) {			/* if an error happened */
+    MM_LOG (err,stream->silent ? WARN : ERROR);
+    return NIL;
+  }
+  else if (!stream->silent) {	/* only if silence not requested */
+    mail_exists (stream,0);	/* say there are 0 messages */
+    mail_recent (stream,0);	/* and certainly no recent ones! */
+    stream->uid_validity = time (0);
+  }
+  stream->inbox = T;		/* note that it's an INBOX */
+  return stream;		/* return success */
+}
+
+
+/* Dummy close
+ * Accepts: MAIL stream
+ *	    options
+ */
+
+void dummy_close (MAILSTREAM *stream,long options)
+{
+				/* return silently */
+}
+
+/* Dummy ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ */
+
+long dummy_ping (MAILSTREAM *stream)
+{
+  MAILSTREAM *test;
+  if (time (0) >=		/* time to do another test? */
+      ((time_t) (stream->gensym +
+		 (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL)))) {
+				/* has mailbox format changed? */
+    if ((test = mail_open (NIL,stream->mailbox,OP_PROTOTYPE)) &&
+	(test->dtb != stream->dtb) &&
+	(test = mail_open (NIL,stream->mailbox,NIL))) {
+				/* preserve some resources */
+      test->original_mailbox = stream->original_mailbox;
+      stream->original_mailbox = NIL;
+      test->sparep = stream->sparep;
+      stream->sparep = NIL;
+      test->sequence = stream->sequence;
+      mail_close ((MAILSTREAM *) /* flush resources used by dummy stream */
+		  memcpy (fs_get (sizeof (MAILSTREAM)),stream,
+			  sizeof (MAILSTREAM)));
+				/* swap the streams */
+      memcpy (stream,test,sizeof (MAILSTREAM));
+      fs_give ((void **) &test);/* flush test now that copied */
+				/* make sure application knows */
+      mail_exists (stream,stream->recent = stream->nmsgs);
+    }
+				/* still hasn't changed */
+    else stream->gensym = time (0);
+  }
+  return T;
+}
+
+
+/* Dummy check mailbox
+ * Accepts: MAIL stream
+ * No-op for readonly files, since read/writer can expunge it from under us!
+ */
+
+void dummy_check (MAILSTREAM *stream)
+{
+  dummy_ping (stream);		/* invoke ping */
+}
+
+
+/* Dummy expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long dummy_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  return LONGT;
+}
+
+/* Dummy copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    options
+ * Returns: T if copy successful, else NIL
+ */
+
+long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+      mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy");
+  return NIL;
+}
+
+
+/* Dummy append message string
+ * Accepts: mail stream
+ *	    destination mailbox
+ *	    append callback function
+ *	    data for callback
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct stat sbuf;
+  int fd = -1;
+  int e;
+  char tmp[MAILTMPLEN];
+  MAILSTREAM *ts = default_proto (T);
+				/* append to INBOX? */
+  if (!compare_cstring (mailbox,"INBOX")) {
+				/* yes, if no empty proto try creating */
+    if (!ts && !(*(ts = default_proto (NIL))->dtb->create) (ts,"INBOX"))
+      ts = NIL;
+  }
+  else if (dummy_file (tmp,mailbox) && ((fd = open (tmp,O_RDONLY,NIL)) < 0)) {
+    if ((e = errno) == ENOENT) /* failed, was it no such file? */
+      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+    sprintf (tmp,"%.80s: %.80s",strerror (e),mailbox);
+    MM_LOG (tmp,ERROR);		/* pass up error */
+    return NIL;			/* always fails */
+  }
+  else if (fd >= 0) {		/* found file? */
+    fstat (fd,&sbuf);		/* get its size */
+    close (fd);			/* toss out the fd */
+    if (sbuf.st_size) ts = NIL; /* non-empty file? */
+  }
+  if (ts) return (*ts->dtb->append) (stream,mailbox,af,data);
+  sprintf (tmp,"Indeterminate mailbox format: %.80s",mailbox);
+  MM_LOG (tmp,ERROR);
+  return NIL;
+}
+
+/* Dummy mail generate file string
+ * Accepts: temporary buffer to write into
+ *	    mailbox name string
+ * Returns: local file string or NIL if failure
+ */
+
+char *dummy_file (char *dst,char *name)
+{
+  char *s = mailboxfile (dst,name);
+				/* return our standard inbox */
+  return (s && !*s) ? strcpy (dst,sysinbox ()) : s;
+}
+
+
+/* Dummy canonicalize name
+ * Accepts: buffer to write name
+ *	    reference
+ *	    pattern
+ * Returns: T if success, NIL if failure
+ */
+
+long dummy_canonicalize (char *tmp,char *ref,char *pat)
+{
+  unsigned long i;
+  char *s;
+  if (ref) {			/* preliminary reference check */
+    if (*ref == '{') return NIL;/* remote reference not allowed */
+    else if (!*ref) ref = NIL;	/* treat empty reference as no reference */
+  }
+  switch (*pat) {
+  case '#':			/* namespace name */
+    if (mailboxfile (tmp,pat)) strcpy (tmp,pat);
+    else return NIL;		/* unknown namespace */
+    break;
+  case '{':			/* remote names not allowed */
+    return NIL;
+  case '/':			/* rooted name */
+  case '~':			/* home directory name */
+    if (!ref || (*ref != '#')) {/* non-namespace reference? */
+      strcpy (tmp,pat);		/* yes, ignore */
+      break;
+    }
+				/* fall through */
+  default:			/* apply reference for all other names */
+    if (!ref) strcpy (tmp,pat);	/* just copy if no namespace */
+    else if ((*ref != '#') || mailboxfile (tmp,ref)) {
+				/* wants root of name? */
+      if (*pat == '/') strcpy (strchr (strcpy (tmp,ref),'/'),pat);
+				/* otherwise just append */
+      else sprintf (tmp,"%s%s",ref,pat);
+    }
+    else return NIL;		/* unknown namespace */
+  }
+				/* count wildcards */
+  for (i = 0, s = tmp; *s; *s++) if ((*s == '*') || (*s == '%')) ++i;
+  if (i > MAXWILDCARDS) {	/* ridiculous wildcarding? */
+    MM_LOG ("Excessive wildcards in LIST/LSUB",ERROR);
+    return NIL;
+  }
+  return T;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/dummy.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,43 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Dummy routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	9 May 1991
+ * Last Edited:	30 August 2006
+ */
+
+/* Exported function prototypes */
+
+void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void dummy_list (MAILSTREAM *stream,char *ref,char *pat);
+void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long scan_contents (DRIVER *dtb,char *name,char *contents,
+		    unsigned long csiz,unsigned long fsiz);
+long dummy_scan_contents (char *name,char *contents,unsigned long csiz,
+			  unsigned long fsiz);
+long dummy_create (MAILSTREAM *stream,char *mailbox);
+long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode);
+long dummy_delete (MAILSTREAM *stream,char *mailbox);
+long dummy_rename (MAILSTREAM *stream,char *old,char *newname);
+char *dummy_file (char *dst,char *name);
+long dummy_canonicalize (char *tmp,char *ref,char *pat);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/env_unix.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1847 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX environment routines
+ *
+ * Author:	Mark Crispin
+ *		UW Technology
+ *		University of Washington
+ *		Seattle, WA  98195
+ *		Internet: MRC@Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	15 May 2008
+ */
+
+#include <grp.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+
+/* in case stat.h is ancient */
+
+#ifndef S_IRUSR
+#define S_IRUSR S_IREAD
+#endif
+#ifndef S_IWUSR
+#define S_IWUSR S_IWRITE
+#endif
+#ifndef S_IXUSR
+#define S_IXUSR S_IEXEC
+#endif
+#ifndef S_IRGRP
+#define S_IRGRP (S_IREAD >> 3)
+#endif
+#ifndef S_IWGRP
+#define S_IWGRP (S_IWRITE >> 3)
+#endif
+#ifndef S_IXGRP
+#define S_IXGRP (S_IEXEC >> 3)
+#endif
+#ifndef S_IROTH
+#define S_IROTH (S_IREAD >> 6)
+#endif
+#ifndef S_IWOTH
+#define S_IWOTH (S_IWRITE >> 6)
+#endif
+#ifndef S_IXOTH
+#define S_IXOTH (S_IEXEC >> 6)
+#endif
+
+/* c-client environment parameters */
+
+static char *myUserName = NIL;	/* user name */
+static char *myHomeDir = NIL;	/* home directory name */
+static char *myServerName = NIL;/* server name */
+static char *myLocalHost = NIL;	/* local host name */
+static char *myNewsrc = NIL;	/* newsrc file name */
+static char *mailsubdir = NIL;	/* mailbox subdirectory name */
+static char *sysInbox = NIL;	/* system inbox name */
+static char *newsActive = NIL;	/* news active file */
+static char *newsSpool = NIL;	/* news spool */
+static char *blackBoxDir = NIL;	/* black box directory name */
+				/* black box default home directory */
+static char *blackBoxDefaultHome = NIL;
+static char *sslCApath = NIL;	/* non-standard CA path */
+static short anonymous = NIL;	/* is anonymous */
+static short blackBox = NIL;	/* is a black box */
+static short closedBox = NIL;	/* is a closed box (uses chroot() jail) */
+static short restrictBox = NIL;	/* is a restricted box */
+static short has_no_life = NIL;	/* is a cretin with no life */
+				/* block environment init */
+static short block_env_init = NIL;
+static short hideDotFiles = NIL;/* hide files whose names start with . */
+				/* advertise filesystem root */
+static short advertisetheworld = NIL;
+				/* only advertise own mailboxes and #shared */
+static short limitedadvertise = NIL;
+				/* disable automatic shared namespaces */
+static short noautomaticsharedns = NIL;
+static short no822tztext = NIL;	/* disable RFC [2]822 timezone text */
+				/* client principals include service name */
+static short kerb_cp_svr_name = NIL;
+static long locktimeout = 5;	/* default lock timeout in minutes */
+				/* default prototypes */
+static MAILSTREAM *createProto = NIL;
+static MAILSTREAM *appendProto = NIL;
+				/* default user flags */
+static char *userFlags[NUSERFLAGS] = {NIL};
+static NAMESPACE *nslist[3];	/* namespace list */
+static int logtry = 3;		/* number of server login tries */
+				/* block notification */
+static blocknotify_t mailblocknotify = mm_blocknotify;
+				/* logout function */
+static logouthook_t maillogouthook = NIL;
+				/* logout data */
+static void *maillogoutdata = NIL;
+				/* allow user config files */
+static short allowuserconfig = NIL;
+				/* 1 = disable plaintext, 2 = if not SSL */
+static long disablePlaintext = NIL;
+static long list_max_level = 20;/* maximum level of list recursion */
+				/* facility for syslog */
+static int syslog_facility = LOG_MAIL;
+
+/* Path of the privileged system lock program (mlock).  Normally set by
+ * logic test.
+ */
+
+static char *lockpgm = LOCKPGM;
+
+/* Directory used for shared locks.  MUST be the same for all users of the
+ * system, and MUST be protected 1777.  /var/tmp may be preferable on some
+ * systems.
+ */
+
+static const char *tmpdir = "/tmp";
+
+/* Do not change shlock_mode.  Doing so can cause mailbox corruption and
+ * denial of service.  It also defeats the entire purpose of the shared
+ * lock mechanism.  The right way to avoid shared locks is to set up a
+ * closed box (see the closedBox setting).
+ */
+
+				/* shared lock mode */
+static const int shlock_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
+
+
+/* It is STRONGLY recommended that you do not change dotlock_mode.  Doing so
+ * can cause denial of service with old dot-lock files left lying around.
+ * However, since dot-locks are only used with traditional UNIX and MMDF
+ * formats which are not normally shared, it is much less harmful to tamper
+ * with this than with shlock_mode.
+ */
+
+				/* dot-lock mode */
+static long dotlock_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
+
+/* File/directory access and protection policies */
+
+/* Unlike shlock_mode, the ????_protection modes are intended to be fully
+ * customizable according to site policy.  The values here are recommended
+ * settings, based upon the documented purposes of the namespaces.
+ */
+
+	/* user space - only owner can read/write */
+static char *myMailboxDir = NIL;/* user space directory name */
+				/* default file protection */
+static long mbx_protection = S_IRUSR|S_IWUSR;
+				/* default directory protection */
+static long dir_protection = S_IRUSR|S_IWUSR|S_IXUSR;
+
+	/* user space for user "anonymous" */
+				/* anonymous home directory */
+static char *anonymousHome = NIL;
+
+	/* #ftp - everybody can read, only owner can write */
+static char *ftpHome = NIL;	/* ftp export home directory */
+				/* default ftp file protection */
+static long ftp_protection = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
+static long ftp_dir_protection =/* default ftp directory protection */
+  S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
+
+	/* #public - everybody can read/write */
+static char *publicHome = NIL;	/* public home directory */
+static long public_protection =	/* default public file protection */
+  S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
+				/* default public directory protection */
+static long public_dir_protection =
+  S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH;
+
+	/* #shared/ - owner and group members can read/write */
+static char *sharedHome = NIL;	/* shared home directory */
+				/* default shared file protection */
+static long shared_protection = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP;
+				/* default shared directory protection */
+static long shared_dir_protection =
+  S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP;
+
+/* OS bug workarounds - should be avoided at all cost */
+
+
+/* Don't set fcntlhangbug unless you really have to, since it risks mailbox
+ * corruption.  The flocksim.c mechanism is designed to detect NFS access
+ * and no-op in that cases only, so this flag should be unnecessary.
+ */
+
+static short fcntlhangbug = NIL;/* flock() emulator using fcntl() is a no-op */
+
+
+/* Don't set netfsstatbug unless you really have to, since it dramatically
+ * slows down traditional UNIX and MMDF mailbox performance.
+ */
+
+static short netfsstatbug = NIL;/* compensate for broken stat() on network
+				 * filesystems (AFS and old NFS)
+				 */
+
+
+/* Note: setting disableLockWarning means that you assert that the
+ * so-modified copy of this software will NEVER be used:
+ *  1) in conjunction with any software which expects .lock files
+ *  2) to access NFS-mounted files and directories
+ *
+ * Unless both of these conditions apply, then do not set this flag.
+ * Instead, read the FAQ (item 7.10) and either use 1777 protection
+ * on the mail spool, or install mlock.
+ *
+ * In addition, by setting this flag you also agree that you are fully
+ * legally and morally responsible when (not if) mail files are damaged
+ * as the result of your choice.
+ *
+ * The mlock tool exists for a reason.  Use it.
+ */
+				/* disable warning if can't make .lock file */
+static short disableLockWarning = NIL;
+
+/* UNIX Namespaces */
+
+				/* personal mh namespace */
+static NAMESPACE nsmhf = {"#mh/",'/',NIL,NIL};
+static NAMESPACE nsmh = {"#mhinbox",NIL,NIL,&nsmhf};
+				/* home namespace */
+static NAMESPACE nshome = {"",'/',NIL,&nsmh};
+				/* UNIX other user namespace */
+static NAMESPACE nsunixother = {"~",'/',NIL,NIL};
+				/* black box other user namespace */
+static NAMESPACE nsblackother = {"/",'/',NIL,NIL};
+				/* public (anonymous OK) namespace */
+static NAMESPACE nspublic = {"#public/",'/',NIL,NIL};
+				/* netnews namespace */
+static NAMESPACE nsnews = {"#news.",'.',NIL,&nspublic};
+				/* FTP export namespace */
+static NAMESPACE nsftp = {"#ftp/",'/',NIL,&nsnews};
+				/* shared (no anonymous) namespace */
+static NAMESPACE nsshared = {"#shared/",'/',NIL,&nsftp};
+				/* world namespace */
+static NAMESPACE nsworld = {"/",'/',NIL,&nsshared};
+				/* only shared and public namespaces */
+static NAMESPACE nslimited = {"#shared/",'/',NIL,&nspublic};
+
+
+
+#include "write.c"		/* include safe writing routines */
+#include "crexcl.c"		/* include exclusive create */
+#include "pmatch.c"		/* include wildcard pattern matcher */
+
+/* Get all authenticators */
+
+#include "auths.c"
+
+/* Environment manipulate parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *env_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case GET_NAMESPACE:
+    ret = (void *) nslist;
+    break;
+  case SET_USERNAME:
+    if (myUserName) fs_give ((void **) &myUserName);
+    myUserName = cpystr ((char *) value);
+  case GET_USERNAME:
+    ret = (void *) myUserName;
+    break;
+  case SET_HOMEDIR:
+    if (myHomeDir) fs_give ((void **) &myHomeDir);
+    myHomeDir = cpystr ((char *) value);
+  case GET_HOMEDIR:
+    ret = (void *) myHomeDir;
+    break;
+  case SET_LOCALHOST:
+    if (myLocalHost) fs_give ((void **) &myLocalHost);
+    myLocalHost = cpystr ((char *) value);
+  case GET_LOCALHOST:
+    ret = (void *) myLocalHost;
+    break;
+  case SET_NEWSRC:
+    if (myNewsrc) fs_give ((void **) &myNewsrc);
+    myNewsrc = cpystr ((char *) value);
+  case GET_NEWSRC:
+    ret = (void *) myNewsrc;
+    break;
+  case SET_NEWSACTIVE:
+    if (newsActive) fs_give ((void **) &newsActive);
+    newsActive = cpystr ((char *) value);
+  case GET_NEWSACTIVE:
+    ret = (void *) newsActive;
+    break;
+  case SET_NEWSSPOOL:
+    if (newsSpool) fs_give ((void **) &newsSpool);
+    newsSpool = cpystr ((char *) value);
+  case GET_NEWSSPOOL:
+    ret = (void *) newsSpool;
+    break;
+
+  case SET_ANONYMOUSHOME:
+    if (anonymousHome) fs_give ((void **) &anonymousHome);
+    anonymousHome = cpystr ((char *) value);
+  case GET_ANONYMOUSHOME:
+    if (!anonymousHome) anonymousHome = cpystr (ANONYMOUSHOME);
+    ret = (void *) anonymousHome;
+    break;
+  case SET_FTPHOME:
+    if (ftpHome) fs_give ((void **) &ftpHome);
+    ftpHome = cpystr ((char *) value);
+  case GET_FTPHOME:
+    ret = (void *) ftpHome;
+    break;
+  case SET_PUBLICHOME:
+    if (publicHome) fs_give ((void **) &publicHome);
+    publicHome = cpystr ((char *) value);
+  case GET_PUBLICHOME:
+    ret = (void *) publicHome;
+    break;
+  case SET_SHAREDHOME:
+    if (sharedHome) fs_give ((void **) &sharedHome);
+    sharedHome = cpystr ((char *) value);
+  case GET_SHAREDHOME:
+    ret = (void *) sharedHome;
+    break;
+  case SET_SYSINBOX:
+    if (sysInbox) fs_give ((void **) &sysInbox);
+    sysInbox = cpystr ((char *) value);
+  case GET_SYSINBOX:
+    ret = (void *) sysInbox;
+    break;
+  case SET_SSLCAPATH:		/* this can be set null */
+    if (sslCApath) fs_give ((void **) &sslCApath);
+    sslCApath = value ? cpystr ((char *) value) : value;
+    break;
+  case GET_SSLCAPATH:
+    ret = (void *) sslCApath;
+    break;
+  case SET_LISTMAXLEVEL:
+    list_max_level = (long) value;
+  case GET_LISTMAXLEVEL:
+    ret = (void *) list_max_level;
+    break;
+
+  case SET_MBXPROTECTION:
+    mbx_protection = (long) value;
+  case GET_MBXPROTECTION:
+    ret = (void *) mbx_protection;
+    break;
+  case SET_DIRPROTECTION:
+    dir_protection = (long) value;
+  case GET_DIRPROTECTION:
+    ret = (void *) dir_protection;
+    break;
+  case SET_LOCKPROTECTION:
+    dotlock_mode = (long) value;
+  case GET_LOCKPROTECTION:
+    ret = (void *) dotlock_mode;
+    break;
+  case SET_FTPPROTECTION:
+    ftp_protection = (long) value;
+  case GET_FTPPROTECTION:
+    ret = (void *) ftp_protection;
+    break;
+  case SET_PUBLICPROTECTION:
+    public_protection = (long) value;
+  case GET_PUBLICPROTECTION:
+    ret = (void *) public_protection;
+    break;
+  case SET_SHAREDPROTECTION:
+    shared_protection = (long) value;
+  case GET_SHAREDPROTECTION:
+    ret = (void *) shared_protection;
+    break;
+  case SET_FTPDIRPROTECTION:
+    ftp_dir_protection = (long) value;
+  case GET_FTPDIRPROTECTION:
+    ret = (void *) ftp_dir_protection;
+    break;
+  case SET_PUBLICDIRPROTECTION:
+    public_dir_protection = (long) value;
+  case GET_PUBLICDIRPROTECTION:
+    ret = (void *) public_dir_protection;
+    break;
+  case SET_SHAREDDIRPROTECTION:
+    shared_dir_protection = (long) value;
+  case GET_SHAREDDIRPROTECTION:
+    ret = (void *) shared_dir_protection;
+    break;
+
+  case SET_LOCKTIMEOUT:
+    locktimeout = (long) value;
+  case GET_LOCKTIMEOUT:
+    ret = (void *) locktimeout;
+    break;
+  case SET_DISABLEFCNTLLOCK:
+    fcntlhangbug = value ? T : NIL;
+  case GET_DISABLEFCNTLLOCK:
+    ret = (void *) (fcntlhangbug ? VOIDT : NIL);
+    break;
+  case SET_LOCKEACCESERROR:
+    disableLockWarning = value ? NIL : T;
+  case GET_LOCKEACCESERROR:
+    ret = (void *) (disableLockWarning ? NIL : VOIDT);
+    break;
+  case SET_HIDEDOTFILES:
+    hideDotFiles = value ? T : NIL;
+  case GET_HIDEDOTFILES:
+    ret = (void *) (hideDotFiles ? VOIDT : NIL);
+    break;
+  case SET_DISABLEPLAINTEXT:
+    disablePlaintext = (long) value;
+  case GET_DISABLEPLAINTEXT:
+    ret = (void *) disablePlaintext;
+    break;
+  case SET_CHROOTSERVER:
+    closedBox = value ? T : NIL;
+  case GET_CHROOTSERVER:
+    ret = (void *) (closedBox ? VOIDT : NIL);
+    break;
+  case SET_ADVERTISETHEWORLD:
+    advertisetheworld = value ? T : NIL;
+  case GET_ADVERTISETHEWORLD:
+    ret = (void *) (advertisetheworld ? VOIDT : NIL);
+    break;
+  case SET_LIMITEDADVERTISE:
+    limitedadvertise = value ? T : NIL;
+  case GET_LIMITEDADVERTISE:
+    ret = (void *) (limitedadvertise ? VOIDT : NIL);
+    break;
+  case SET_DISABLEAUTOSHAREDNS:
+    noautomaticsharedns = value ? T : NIL;
+  case GET_DISABLEAUTOSHAREDNS:
+    ret = (void *) (noautomaticsharedns ? VOIDT : NIL);
+    break;
+  case SET_DISABLE822TZTEXT:
+    no822tztext = value ? T : NIL;
+  case GET_DISABLE822TZTEXT:
+    ret = (void *) (no822tztext ? VOIDT : NIL);
+    break;
+
+  case SET_USERHASNOLIFE:
+    has_no_life = value ? T : NIL;
+  case GET_USERHASNOLIFE:
+    ret = (void *) (has_no_life ? VOIDT : NIL);
+    break;
+  case SET_KERBEROS_CP_SVR_NAME:
+    kerb_cp_svr_name = value ? T : NIL;
+  case GET_KERBEROS_CP_SVR_NAME:
+    ret = (void *) (kerb_cp_svr_name ? VOIDT : NIL);
+    break;
+  case SET_NETFSSTATBUG:
+    netfsstatbug = value ? T : NIL;
+  case GET_NETFSSTATBUG:
+    ret = (void *) (netfsstatbug ? VOIDT : NIL);
+    break;
+  case SET_BLOCKENVINIT:
+    block_env_init = value ? T : NIL;
+  case GET_BLOCKENVINIT:
+    ret = (void *) (block_env_init ? VOIDT : NIL);
+    break;
+  case SET_BLOCKNOTIFY:
+    mailblocknotify = (blocknotify_t) value;
+  case GET_BLOCKNOTIFY:
+    ret = (void *) mailblocknotify;
+    break;
+  case SET_LOGOUTHOOK:
+    maillogouthook = (logouthook_t) value;
+  case GET_LOGOUTHOOK:
+    ret = maillogouthook;
+    break;
+  case SET_LOGOUTDATA:
+    maillogoutdata = (void *) value;
+  case GET_LOGOUTDATA:
+    ret = maillogoutdata;
+  }
+  return ret;
+}
+
+/* Write current time
+ * Accepts: destination string
+ *	    optional format of day-of-week prefix
+ *	    format of date and time
+ *	    flag whether to append symbolic timezone
+ */
+
+static void do_date (char *date,char *prefix,char *fmt,int suffix)
+{
+  time_t tn = time (0);
+  struct tm *t = gmtime (&tn);
+  int zone = t->tm_hour * 60 + t->tm_min;
+  int julian = t->tm_yday;
+  t = localtime (&tn);		/* get local time now */
+				/* minus UTC minutes since midnight */
+  zone = t->tm_hour * 60 + t->tm_min - zone;
+  /* julian can be one of:
+   *  36x  local time is December 31, UTC is January 1, offset -24 hours
+   *    1  local time is 1 day ahead of UTC, offset +24 hours
+   *    0  local time is same day as UTC, no offset
+   *   -1  local time is 1 day behind UTC, offset -24 hours
+   * -36x  local time is January 1, UTC is December 31, offset +24 hours
+   */
+  if (julian = t->tm_yday -julian)
+    zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
+  if (prefix) {			/* want day of week? */
+    sprintf (date,prefix,days[t->tm_wday]);
+    date += strlen (date);	/* make next sprintf append */
+  }
+				/* output the date */
+  sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
+	   t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
+				/* append timezone suffix if desired */
+  if (suffix) rfc822_timezone (date,(void *) t);
+}
+
+/* Write current time in RFC 822 format
+ * Accepts: destination string
+ */
+
+void rfc822_date (char *date)
+{
+  do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d",
+	   no822tztext ? NIL : T);
+}
+
+
+/* Write current time in fixed-width RFC 822 format
+ * Accepts: destination string
+ */
+
+void rfc822_fixed_date (char *date)
+{
+  do_date (date,NIL,"%02d %s %4d %02d:%02d:%02d %+03d%02d",NIL);
+}
+
+
+/* Write current time in internal format
+ * Accepts: destination string
+ */
+
+void internal_date (char *date)
+{
+  do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL);
+}
+
+/* Initialize server
+ * Accepts: server name for syslog or NIL
+ *	    /etc/services service name or NIL
+ *	    alternate /etc/services service name or NIL
+ *	    clock interrupt handler
+ *	    kiss-of-death interrupt handler
+ *	    hangup interrupt handler
+ *	    termination interrupt handler
+ */
+
+void server_init (char *server,char *service,char *sslservice,
+		  void *clkint,void *kodint,void *hupint,void *trmint,
+		  void *staint)
+{
+  int onceonly = server && service && sslservice;
+  if (onceonly) {		/* set server name in syslog */
+    int mask;
+    openlog (myServerName = cpystr (server),LOG_PID,syslog_facility);
+    fclose (stderr);		/* possibly save a process ID */
+    dorc (NIL,NIL);		/* do systemwide configuration */
+    switch (mask = umask (022)){/* check old umask */
+    case 0:			/* definitely unreasonable */
+    case 022:			/* don't need to change it */
+      break;
+    default:			/* already was a reasonable value */
+      umask (mask);		/* so change it back */
+    }
+  }
+  arm_signal (SIGALRM,clkint);	/* prepare for clock interrupt */
+  arm_signal (SIGUSR2,kodint);	/* prepare for Kiss Of Death */
+  arm_signal (SIGHUP,hupint);	/* prepare for hangup */
+  arm_signal (SIGPIPE,hupint);	/* alternative hangup */
+  arm_signal (SIGTERM,trmint);	/* prepare for termination */
+				/* status dump */
+  if (staint) arm_signal (SIGUSR1,staint);
+  if (onceonly) {		/* set up network and maybe SSL */
+    long port;
+    struct servent *sv;
+    /* Use SSL if SSL service, or if server starts with "s" and not service */
+    if (((port = tcp_serverport ()) >= 0)) {
+      if ((sv = getservbyname (service,"tcp")) && (port == ntohs (sv->s_port)))
+	syslog (LOG_DEBUG,"%s service init from %s",service,tcp_clientaddr ());
+      else if ((sv = getservbyname (sslservice,"tcp")) &&
+	       (port == ntohs (sv->s_port))) {
+	syslog (LOG_DEBUG,"%s SSL service init from %s",sslservice,
+		tcp_clientaddr ());
+	ssl_server_init (server);
+      }
+      else {			/* not service or SSL service port */
+	syslog (LOG_DEBUG,"port %ld service init from %s",port,
+		tcp_clientaddr ());
+	if (*server == 's') ssl_server_init (server);
+      }
+    }
+  }
+}
+
+/* Wait for stdin input
+ * Accepts: timeout in seconds
+ * Returns: T if have input on stdin, else NIL
+ */
+
+long server_input_wait (long seconds)
+{
+  fd_set rfd,efd;
+  struct timeval tmo;
+  FD_ZERO (&rfd);
+  FD_ZERO (&efd);
+  FD_SET (0,&rfd);
+  FD_SET (0,&efd);
+  tmo.tv_sec = seconds; tmo.tv_usec = 0;
+  return select (1,&rfd,0,&efd,&tmo) ? LONGT : NIL;
+}
+
+/* Return UNIX password entry for user name
+ * Accepts: user name string
+ * Returns: password entry
+ *
+ * Tries all-lowercase form of user name if given user name fails
+ */
+
+static struct passwd *pwuser (unsigned char *user)
+{
+  unsigned char *s;
+  struct passwd *pw = getpwnam (user);
+  if (!pw) {			/* failed, see if any uppercase characters */
+    for (s = user; *s && ((*s < 'A') || (*s > 'Z')); s++);
+    if (*s) {			/* yes, try all lowercase form */
+      pw = getpwnam (s = lcase (cpystr (user)));
+      fs_give ((void **) &s);
+    }
+  }
+  return pw;
+}
+
+
+/* Validate password for user name
+ * Accepts: user name string
+ *	    password string
+ *	    argument count
+ *	    argument vector
+ * Returns: password entry if validated
+ *
+ * Tries password+1 if password fails and starts with space
+ */
+
+static struct passwd *valpwd (char *user,char *pwd,int argc,char *argv[])
+{
+  char *s;
+  struct passwd *pw;
+  struct passwd *ret = NIL;
+  if (auth_md5.server) {	/* using CRAM-MD5 authentication? */
+    if (s = auth_md5_pwd (user)) {
+      if (!strcmp (s,pwd) || ((*pwd == ' ') && pwd[1] && !strcmp (s,pwd+1)))
+	ret = pwuser (user);	/* validated, get passwd entry for user */
+      memset (s,0,strlen (s));	/* erase sensitive information */
+      fs_give ((void **) &s);
+    }
+  }
+  else if (pw = pwuser (user)) {/* can get user? */
+    s = cpystr (pw->pw_name);	/* copy returned name in case we need it */
+    if (*pwd && !(ret = checkpw (pw,pwd,argc,argv)) &&
+	(*pwd == ' ') && pwd[1] && (ret = pwuser (s)))
+      ret = checkpw (pw,pwd+1,argc,argv);
+    fs_give ((void **) &s);	/* don't need copy of name any more */
+  }
+  return ret;
+}
+
+/* Server log in
+ * Accepts: user name string
+ *	    password string
+ *	    authenticating user name string
+ *	    argument count
+ *	    argument vector
+ * Returns: T if password validated, NIL otherwise
+ */
+
+long server_login (char *user,char *pwd,char *authuser,int argc,char *argv[])
+{
+  struct passwd *pw = NIL;
+  int level = LOG_NOTICE;
+  char *err = "failed";
+				/* cretins still haven't given up */
+  if ((strlen (user) >= NETMAXUSER) ||
+      (authuser && (strlen (authuser) >= NETMAXUSER))) {
+    level = LOG_ALERT;		/* escalate this alert */
+    err = "SYSTEM BREAK-IN ATTEMPT";
+    logtry = 0;			/* render this session useless */
+  }
+  else if (logtry-- <= 0) err = "excessive login failures";
+  else if (disablePlaintext) err = "disabled";
+  else if (!(authuser && *authuser)) pw = valpwd (user,pwd,argc,argv);
+  else if (valpwd (authuser,pwd,argc,argv)) pw = pwuser (user);
+  if (pw && pw_login (pw,authuser,pw->pw_name,NIL,argc,argv)) return T;
+  syslog (level|LOG_AUTH,"Login %s user=%.64s auth=%.64s host=%.80s",err,
+	  user,(authuser && *authuser) ? authuser : user,tcp_clienthost ());
+  sleep (3);			/* slow down possible cracker */
+  return NIL;
+}
+
+/* Authenticated server log in
+ * Accepts: user name string
+ *	    authenticating user name string
+ *	    argument count
+ *	    argument vector
+ * Returns: T if password validated, NIL otherwise
+ */
+
+long authserver_login (char *user,char *authuser,int argc,char *argv[])
+{
+  return pw_login (pwuser (user),authuser,user,NIL,argc,argv);
+}
+
+
+/* Log in as anonymous daemon
+ * Accepts: argument count
+ *	    argument vector
+ * Returns: T if successful, NIL if error
+ */
+
+long anonymous_login (int argc,char *argv[])
+{
+				/* log in Mr. A. N. Onymous */
+  return pw_login (getpwnam (ANONYMOUSUSER),NIL,NIL,
+		   (char *) mail_parameters (NIL,GET_ANONYMOUSHOME,NIL),
+		   argc,argv);
+}
+
+/* Finish log in and environment initialization
+ * Accepts: passwd struct for loginpw()
+ *	    optional authentication user name
+ *	    user name (NIL for anonymous)
+ *	    home directory (NIL to use directory from passwd struct)
+ *	    argument count
+ *	    argument vector
+ * Returns: T if successful, NIL if error
+ */
+
+long pw_login (struct passwd *pw,char *auser,char *user,char *home,int argc,
+	       char *argv[])
+{
+  struct group *gr;
+  char **t;
+  long ret = NIL;
+  if (pw && pw->pw_uid) {	/* must have passwd struct for non-UID 0 */
+				/* make safe copies of user and home */
+    if (user) user = cpystr (pw->pw_name);
+    home = cpystr (home ? home : pw->pw_dir);
+				/* authorization ID .NE. authentication ID? */
+    if (user && auser && *auser && compare_cstring (auser,user)) {
+				/* scan list of mail administrators */
+      if ((gr = getgrnam (ADMINGROUP)) && (t = gr->gr_mem)) while (*t && !ret)
+	if (!compare_cstring (auser,*t++))
+	  ret = pw_login (pw,NIL,user,home,argc,argv);
+      syslog (LOG_NOTICE|LOG_AUTH,"%s %.80s override of user=%.80s host=%.80s",
+	      ret ? "Admin" : "Failed",auser,user,tcp_clienthost ());
+    }
+    else if (closedBox) {	/* paranoid site, lock out other directories */
+      if (chdir (home) || chroot (home))
+	syslog (LOG_NOTICE|LOG_AUTH,
+		"Login %s failed: unable to set chroot=%.80s host=%.80s",
+		pw->pw_name,home,tcp_clienthost ());
+      else if (loginpw (pw,argc,argv)) ret = env_init (user,NIL);
+      else fatal ("Login failed after chroot");
+    }
+				/* normal login */
+    else if (((pw->pw_uid == geteuid ()) || loginpw (pw,argc,argv)) &&
+	     (ret = env_init (user,home))) chdir (myhomedir ());
+    fs_give ((void **) &home);	/* clean up */
+    if (user) fs_give ((void **) &user);
+  }
+  endpwent ();			/* in case shadow passwords in pw data */
+  return ret;			/* return status */
+}
+
+/* Initialize environment
+ * Accepts: user name (NIL for anonymous)
+ *	    home directory name
+ * Returns: T, always
+ */
+
+long env_init (char *user,char *home)
+{
+  extern MAILSTREAM CREATEPROTO;
+  extern MAILSTREAM EMPTYPROTO;
+  struct passwd *pw;
+  struct stat sbuf;
+  char tmp[MAILTMPLEN];
+				/* don't init if blocked */
+  if (block_env_init) return LONGT;
+  if (myUserName) fatal ("env_init called twice!");
+				/* initially nothing in namespace list */
+  nslist[0] = nslist[1] = nslist[2] = NIL;
+				/* myUserName must be set before dorc() call */
+  myUserName = cpystr (user ? user : ANONYMOUSUSER);
+				/* force default prototypes to be set */
+  if (!createProto) createProto = &CREATEPROTO;
+  if (!appendProto) appendProto = &EMPTYPROTO;
+  dorc (NIL,NIL);		/* do systemwide configuration */
+  if (!home) {			/* closed box server */
+				/* standard user can only reference home */
+    if (user) nslist[0] = &nshome;
+    else {			/* anonymous user */
+      nslist[0] = &nsblackother; /* set root */
+      anonymous = T;		/* flag as anonymous */
+    }
+    myHomeDir = cpystr ("");	/* home directory is root */
+    sysInbox = cpystr ("INBOX");/* make system INBOX */
+  }
+  else {			/* open or black box */
+    closedBox = NIL;		/* definitely not a closed box */
+    if (user) {			/* remember user name and home directory */
+      if (blackBoxDir) {	/* build black box directory name */
+	sprintf (tmp,"%s/%s",blackBoxDir,myUserName);
+				/* must exist */
+	if (!((!stat (home = tmp,&sbuf) && (sbuf.st_mode & S_IFDIR)) ||
+	      (blackBoxDefaultHome &&
+	       !stat (home = blackBoxDefaultHome,&sbuf) &&
+	       (sbuf.st_mode & S_IFDIR)))) fatal ("no home");
+	sysInbox = (char *) fs_get (strlen (home) + 7);
+				/* set system INBOX */
+	sprintf (sysInbox,"%s/INBOX",home);
+	blackBox = T;		/* mark that it's a black box */
+				/* mbox meaningless if black box */
+	mail_parameters (NIL,DISABLE_DRIVER,(void *) "mbox");
+      }
+      nslist[0] = &nshome;	/* home namespace */
+				/* limited advertise namespaces */
+      if (limitedadvertise) nslist[2] = &nslimited;
+      else if (blackBox) {	/* black box namespaces */
+	nslist[1] = &nsblackother;
+	nslist[2] = &nsshared;
+      }
+      else {			/* open box namespaces */
+	nslist[1] = &nsunixother;
+	nslist[2] = advertisetheworld ? &nsworld : &nsshared;
+      }
+    }
+    else {
+      nslist[2] = &nsftp;	/* anonymous user */
+      sprintf (tmp,"%s/INBOX",
+	       home = (char *) mail_parameters (NIL,GET_ANONYMOUSHOME,NIL));
+      sysInbox = cpystr (tmp);	/* make system INBOX */
+      anonymous = T;		/* flag as anonymous */
+    }
+    myHomeDir = cpystr (home);	/* set home directory */
+  }
+
+  if (allowuserconfig) {	/* allow user config files */
+    dorc (strcat (strcpy (tmp,myHomeDir),"/.mminit"),T);
+    dorc (strcat (strcpy (tmp,myHomeDir),"/.imaprc"),NIL);
+  }
+  if (!closedBox && !noautomaticsharedns) {
+				/* #ftp namespace */
+    if (!ftpHome && (pw = getpwnam ("ftp"))) ftpHome = cpystr (pw->pw_dir);
+				/* #public namespace */
+    if (!publicHome && (pw = getpwnam ("imappublic")))
+      publicHome = cpystr (pw->pw_dir);
+				/* #shared namespace */
+    if (!anonymous && !sharedHome && (pw = getpwnam ("imapshared")))
+      sharedHome = cpystr (pw->pw_dir);
+  }
+  if (!myLocalHost) mylocalhost ();
+  if (!myNewsrc) myNewsrc = cpystr(strcat (strcpy (tmp,myHomeDir),"/.newsrc"));
+  if (!newsActive) newsActive = cpystr (ACTIVEFILE);
+  if (!newsSpool) newsSpool = cpystr (NEWSSPOOL);
+				/* re-do open action to get flags */
+  (*createProto->dtb->open) (NIL);
+  endpwent ();			/* close pw database */
+  return T;
+}
+ 
+/* Return my user name
+ * Accepts: pointer to optional flags
+ * Returns: my user name
+ */
+
+char *myusername_full (unsigned long *flags)
+{
+  struct passwd *pw;
+  struct stat sbuf;
+  char *s;
+  unsigned long euid;
+  char *ret = UNLOGGEDUSER;
+				/* no user name yet and not root? */
+  if (!myUserName && (euid = geteuid ())) {
+				/* yes, look up getlogin() user name or EUID */
+    if (((s = (char *) getlogin ()) && *s && (strlen (s) < NETMAXUSER) &&
+	 (pw = getpwnam (s)) && (pw->pw_uid == euid)) ||
+	(pw = getpwuid (euid))) {
+      if (block_env_init) {	/* don't env_init if blocked */
+	if (flags) *flags = MU_LOGGEDIN;
+	return pw->pw_name;
+      }
+      env_init (pw->pw_name,
+		((s = getenv ("HOME")) && *s && (strlen (s) < NETMAXMBX) &&
+		 !stat (s,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) ?
+		s : pw->pw_dir);
+    }
+    else fatal ("Unable to look up user name");
+  }
+  if (myUserName) {		/* logged in? */
+    if (flags) *flags = anonymous ? MU_ANONYMOUS : MU_LOGGEDIN;
+    ret = myUserName;		/* return user name */
+  }
+  else if (flags) *flags = MU_NOTLOGGEDIN;
+  return ret;
+}
+
+
+/* Return my local host name
+ * Returns: my local host name
+ */
+
+char *mylocalhost ()
+{
+  if (!myLocalHost) {
+    char *s,tmp[MAILTMPLEN];
+    char *t = "unknown";
+    tmp[0] = tmp[MAILTMPLEN-1] = '\0';
+    if (!gethostname (tmp,MAILTMPLEN-1) && tmp[0]) {
+				/* sanity check of name */
+      for (s = tmp; (*s > 0x20) && (*s < 0x7f); ++s);
+      if (!*s) t = tcp_canonical (tmp);
+    }
+    myLocalHost = cpystr (t);
+  }
+  return myLocalHost;
+}
+
+/* Return my home directory name
+ * Returns: my home directory name
+ */
+
+char *myhomedir ()
+{
+  if (!myHomeDir) myusername ();/* initialize if first time */
+  return myHomeDir ? myHomeDir : "";
+}
+
+
+/* Return my home mailbox name
+ * Returns: my home directory name
+ */
+
+static char *mymailboxdir ()
+{
+  char *home = myhomedir ();
+				/* initialize if first time */
+  if (!myMailboxDir && myHomeDir) {
+    if (mailsubdir) {
+      char tmp[MAILTMPLEN];
+      sprintf (tmp,"%s/%s",home,mailsubdir);
+      myMailboxDir = cpystr (tmp);/* use pre-defined subdirectory of home */
+    }
+    else myMailboxDir = cpystr (home);
+  }
+  return myMailboxDir ? myMailboxDir : "";
+}
+
+
+/* Return system standard INBOX
+ * Accepts: buffer string
+ */
+
+char *sysinbox ()
+{
+  char tmp[MAILTMPLEN];
+  if (!sysInbox) {		/* initialize if first time */
+    sprintf (tmp,"%s/%s",MAILSPOOL,myusername ());
+    sysInbox = cpystr (tmp);	/* system inbox is from mail spool */
+  }
+  return sysInbox;
+}
+
+/* Return mailbox directory name
+ * Accepts: destination buffer
+ *	    directory prefix
+ *	    name in directory
+ * Returns: file name or NIL if error
+ */
+
+char *mailboxdir (char *dst,char *dir,char *name)
+{
+  char tmp[MAILTMPLEN];
+  if (dir || name) {		/* if either argument provided */
+    if (dir) {
+      if (strlen (dir) > NETMAXMBX) return NIL;
+      strcpy (tmp,dir);		/* write directory prefix */
+    }
+    else tmp[0] = '\0';		/* otherwise null string */
+    if (name) {
+      if (strlen (name) > NETMAXMBX) return NIL;
+      strcat (tmp,name);	/* write name in directory */
+    }
+				/* validate name, return its name */
+    if (!mailboxfile (dst,tmp)) return NIL;
+  }
+				/* no arguments, wants mailbox directory */
+  else strcpy (dst,mymailboxdir ());
+  return dst;			/* return the name */
+}
+
+/* Return mailbox file name
+ * Accepts: destination buffer
+ *	    mailbox name
+ * Returns: file name or empty string for driver-selected INBOX or NIL if error
+ */
+
+char *mailboxfile (char *dst,char *name)
+{
+  struct passwd *pw;
+  char *s;
+  if (!name || !*name || (*name == '{') || (strlen (name) > NETMAXMBX) ||
+      ((anonymous || blackBox || restrictBox || (*name == '#')) &&
+       (strstr (name,"..") || strstr (name,"//") || strstr (name,"/~"))))
+    dst = NIL;			/* invalid name */
+  else switch (*name) {		/* determine mailbox type based upon name */
+  case '#':			/* namespace name */
+				/* #ftp/ namespace */
+    if (((name[1] == 'f') || (name[1] == 'F')) &&
+	((name[2] == 't') || (name[2] == 'T')) &&
+	((name[3] == 'p') || (name[3] == 'P')) &&
+	(name[4] == '/') && ftpHome) sprintf (dst,"%s/%s",ftpHome,name+5);
+				/* #public/ and #shared/ namespaces */
+    else if ((((name[1] == 'p') || (name[1] == 'P')) &&
+	      ((name[2] == 'u') || (name[2] == 'U')) &&
+	      ((name[3] == 'b') || (name[3] == 'B')) &&
+	      ((name[4] == 'l') || (name[4] == 'L')) &&
+	      ((name[5] == 'i') || (name[5] == 'I')) &&
+	      ((name[6] == 'c') || (name[6] == 'C')) &&
+	      (name[7] == '/') && (s = publicHome)) ||
+	     (!anonymous && ((name[1] == 's') || (name[1] == 'S')) &&
+	      ((name[2] == 'h') || (name[2] == 'H')) &&
+	      ((name[3] == 'a') || (name[3] == 'A')) &&
+	      ((name[4] == 'r') || (name[4] == 'R')) &&
+	      ((name[5] == 'e') || (name[5] == 'E')) &&
+	      ((name[6] == 'd') || (name[6] == 'D')) &&
+	      (name[7] == '/') && (s = sharedHome)))
+      sprintf (dst,"%s/%s",s,compare_cstring (name+8,"INBOX") ?
+	       name+8 : "INBOX");
+    else dst = NIL;		/* unknown namespace */
+    break;
+
+  case '/':			/* root access */
+    if (anonymous) dst = NIL;	/* anonymous forbidden to do this */
+    else if (blackBox) {	/* other user access if blackbox */
+      if (restrictBox & RESTRICTOTHERUSER) dst = NIL;
+				/* see if other user INBOX */
+      else if ((s = strchr (name+1,'/')) && !compare_cstring (s+1,"INBOX")) {
+	*s = '\0';		/* temporarily tie off string */
+	sprintf (dst,"%s/%s/INBOX",blackBoxDir,name+1);
+	*s = '/';		/* in case caller cares */
+      }
+      else sprintf (dst,"%s/%s",blackBoxDir,name+1);
+    }
+    else if ((restrictBox & RESTRICTROOT) && strcmp (name,sysinbox ()))
+      dst = NIL;		/* restricted and not access to sysinbox */
+    else strcpy (dst,name);	/* unrestricted, copy root name */
+    break;
+  case '~':			/* other user access */
+				/* bad syntax or anonymous can't win */
+    if (!*++name || anonymous) dst = NIL;
+				/* ~/ equivalent to ordinary name */
+    else if (*name == '/') sprintf (dst,"%s/%s",mymailboxdir (),name+1);
+				/* other user forbidden if closed/restricted */
+    else if (closedBox || (restrictBox & RESTRICTOTHERUSER)) dst = NIL;
+    else if (blackBox) {	/* black box form of other user */
+				/* see if other user INBOX */
+      if ((s = strchr (name,'/')) && compare_cstring (s+1,"INBOX")) {
+	*s = '\0';		/* temporarily tie off string */
+	sprintf (dst,"%s/%s/INBOX",blackBoxDir,name);
+	*s = '/';		/* in case caller cares */
+      }
+      else sprintf (dst,"%s/%s",blackBoxDir,name);
+    }
+    else {			/* clear box other user */
+				/* copy user name */
+      for (s = dst; *name && (*name != '/'); *s++ = *name++);
+      *s++ = '\0';		/* tie off user name, look up in passwd file */
+      if ((pw = getpwnam (dst)) && pw->pw_dir) {
+	if (*name) name++;	/* skip past the slash */
+				/* canonicalize case of INBOX */
+	if (!compare_cstring (name,"INBOX")) name = "INBOX";
+				/* remove trailing / from directory */
+	if ((s = strrchr (pw->pw_dir,'/')) && !s[1]) *s = '\0';
+				/* don't allow ~root/ if restricted root */
+	if ((restrictBox & RESTRICTROOT) && !*pw->pw_dir) dst = NIL;
+				/* build final name w/ subdir if needed */
+	else if (mailsubdir) sprintf (dst,"%s/%s/%s",pw->pw_dir,mailsubdir,name);
+	else sprintf (dst,"%s/%s",pw->pw_dir,name);
+      }
+      else dst = NIL;		/* no such user */
+    }
+    break;
+
+  case 'I': case 'i':		/* possible INBOX */
+    if (!compare_cstring (name+1,"NBOX")) {
+				/* if restricted, use INBOX in mailbox dir */
+      if (anonymous || blackBox || closedBox)
+	sprintf (dst,"%s/INBOX",mymailboxdir ());
+      else *dst = '\0';		/* otherwise driver selects the name */
+      break;
+    }
+				/* drop into to ordinary name case */
+  default:			/* ordinary name is easy */
+    sprintf (dst,"%s/%s",mymailboxdir (),name);
+    break;
+  }
+  return dst;			/* return final name */
+}
+
+/* Dot-lock file locker
+ * Accepts: file name to lock
+ *	    destination buffer for lock file name
+ *	    open file description on file name to lock
+ * Returns: T if success, NIL if failure
+ */
+
+long dotlock_lock (char *file,DOTLOCK *base,int fd)
+{
+  int i = locktimeout * 60;
+  int j,mask,retry,pi[2],po[2];
+  char *s,tmp[MAILTMPLEN];
+  struct stat sb;
+				/* flush absurd file name */
+  if (strlen (file) > 512) return NIL;
+				/* build lock filename */
+  sprintf (base->lock,"%s.lock",file);
+				/* assume no pipe */
+  base->pipei = base->pipeo = -1;
+  do {				/* make sure not symlink */
+    if (!(j = chk_notsymlink (base->lock,&sb))) return NIL;
+				/* time out if file older than 5 minutes */
+    if ((j > 0) && ((time (0)) >= (sb.st_ctime + locktimeout * 60))) i = 0;
+				/* try to create the lock */
+    switch (retry = crexcl (base->lock)) {
+    case -1:			/* OK to retry */
+      if (!(i%15)) {		/* time to notify? */
+	sprintf (tmp,"Mailbox %.80s is locked, will override in %d seconds...",
+		 file,i);
+	MM_LOG (tmp,WARN);
+      }
+      sleep (1);		/* wait 1 second before next try */
+      break;
+    case NIL:			/* failure, can't retry */
+      i = 0;
+      break;
+    case T:			/* success, make sure others can break lock */
+      chmod (base->lock,(int) dotlock_mode);
+      return LONGT;
+    }
+  } while (i--);		/* until out of retries */
+  if (retry < 0) {		/* still returning retry after locktimeout? */
+    if (!(j = chk_notsymlink (base->lock,&sb))) return NIL;
+    if ((j > 0) && ((time (0)) < (sb.st_ctime + locktimeout * 60))) {
+      sprintf (tmp,"Mailbox vulnerable - seizing %ld second old lock",
+	       (long) (time (0) - sb.st_ctime));
+      MM_LOG (tmp,WARN);
+    }
+    mask = umask (0);		/* want our lock protection */
+    unlink (base->lock);	/* try to remove the old file */
+				/* seize the lock */
+    if ((i = open (base->lock,O_WRONLY|O_CREAT,(int) dotlock_mode)) >= 0) {
+      close (i);		/* don't need descriptor any more */
+      sprintf (tmp,"Mailbox %.80s lock overridden",file);
+      MM_LOG (tmp,NIL);
+      chmod (base->lock,(int) dotlock_mode);
+      umask (mask);		/* restore old umask */
+      return LONGT;
+    }
+    umask (mask);		/* restore old umask */
+  }
+
+  if (fd >= 0) switch (errno) {
+  case EACCES:			/* protection failure? */
+    MM_CRITICAL (NIL);		/* go critical */
+    if (closedBox || !lockpgm);	/* can't do on closed box or disabled */
+    else if ((*lockpgm && stat (lockpgm,&sb)) ||
+	     (!*lockpgm && stat (lockpgm = LOCKPGM1,&sb) &&
+	      stat (lockpgm = LOCKPGM2,&sb) && stat (lockpgm = LOCKPGM3,&sb)))
+      lockpgm = NIL;		/* disable if can't find lockpgm */
+    else if (pipe (pi) >= 0) {	/* make command pipes */
+      long cf;
+      char *argv[4],arg[20];
+				/* if input pipes usable create output pipes */
+      if ((pi[0] < FD_SETSIZE) && (pi[1] < FD_SETSIZE) && (pipe (po) >= 0)) {
+				/* make sure output pipes are usable */
+	if ((po[0] >= FD_SETSIZE) || (po[1] >= FD_SETSIZE));
+				/* all is good, make inferior process */
+	else if (!(j = fork ())) {
+	  if (!fork ()) {	/* make grandchild so it's inherited by init */
+				/* prepare argument vector */
+	    sprintf (arg,"%d",fd);
+	    argv[0] = lockpgm; argv[1] = arg;
+	    argv[2] = file; argv[3] = NIL;
+				/* set parent's I/O to my O/I */
+	    dup2 (pi[1],1); dup2 (pi[1],2); dup2 (po[0],0);
+				/* close all unnecessary descriptors */
+	    for (cf = max (20,max (max (pi[0],pi[1]),max(po[0],po[1])));
+		 cf >= 3; --cf) if (cf != fd) close (cf);
+				/* be our own process group */
+	    setpgrp (0,getpid ());
+				/* now run it */
+	    _exit (execv (argv[0],argv));
+	  }
+	  _exit (1);		/* child is done */
+	}
+	else if (j > 0) {	/* parent process */
+	  fd_set rfd;
+	  struct timeval tmo;
+	  FD_ZERO (&rfd);
+	  FD_SET (pi[0],&rfd);
+	  tmo.tv_sec = locktimeout * 60;
+	  grim_pid_reap (j,NIL);/* reap child; grandchild now owned by init */
+				/* read response from locking program */
+	  if (select (pi[0]+1,&rfd,0,0,&tmo) &&
+	      (read (pi[0],tmp,1) == 1) && (tmp[0] == '+')) {
+				/* success, record pipes */
+	    base->pipei = pi[0]; base->pipeo = po[1];
+				/* close child's side of the pipes */
+	    close (pi[1]); close (po[0]);
+	    MM_NOCRITICAL (NIL);/* no longer critical */
+	    return LONGT;
+	  }
+	}
+	close (po[0]); close (po[1]);
+      }
+      close (pi[0]); close (pi[1]);
+    }
+
+    MM_NOCRITICAL (NIL);	/* no longer critical */
+				/* find directory/file delimiter */
+    if (s = strrchr (base->lock,'/')) {
+      *s = '\0';		/* tie off at directory */
+      sprintf(tmp,		/* generate default message */
+	      "Mailbox vulnerable - directory %.80s must have 1777 protection",
+	      base->lock);
+				/* definitely not 1777 if can't stat */
+      mask = stat (base->lock,&sb) ? 0 : (sb.st_mode & 1777);
+      *s = '/';			/* restore lock name */
+      if (mask != 1777) {	/* default warning if not 1777 */
+	if (!disableLockWarning) MM_LOG (tmp,WARN);
+	break;
+      }
+    }
+  default:
+    sprintf (tmp,"Mailbox vulnerable - error creating %.80s: %s",
+	     base->lock,strerror (errno));
+    if (!disableLockWarning) MM_LOG (tmp,WARN);
+    break;
+  }
+  base->lock[0] = '\0';		/* don't use lock files */
+  return NIL;
+}
+
+/* Dot-lock file unlocker
+ * Accepts: lock file name
+ * Returns: T if success, NIL if failure
+ */
+
+long dotlock_unlock (DOTLOCK *base)
+{
+  long ret = LONGT;
+  if (base && base->lock[0]) {
+    if (base->pipei >= 0) {	/* if running through a pipe unlocker */
+      ret = (write (base->pipeo,"+",1) == 1);
+				/* nuke the pipes */
+      close (base->pipei); close (base->pipeo);
+    }
+    else ret = !unlink (base->lock);
+  }
+  return ret;
+}
+
+/* Lock file name
+ * Accepts: scratch buffer
+ *	    file name
+ *	    type of locking operation (LOCK_SH or LOCK_EX)
+ *	    pointer to return PID of locker
+ * Returns: file descriptor of lock or negative if error
+ */
+
+int lockname (char *lock,char *fname,int op,long *pid)
+{
+  struct stat sbuf;
+  *pid = 0;			/* no locker PID */
+  return stat (fname,&sbuf) ? -1 : lock_work (lock,&sbuf,op,pid);
+}
+
+
+/* Lock file descriptor
+ * Accepts: file descriptor
+ *	    lock file name buffer
+ *	    type of locking operation (LOCK_SH or LOCK_EX)
+ * Returns: file descriptor of lock or negative if error
+ */
+
+int lockfd (int fd,char *lock,int op)
+{
+  struct stat sbuf;
+  return fstat (fd,&sbuf) ? -1 : lock_work (lock,&sbuf,op,NIL);
+}
+
+/* Lock file name worker
+ * Accepts: lock file name
+ *	    pointer to stat() buffer
+ *	    type of locking operation (LOCK_SH or LOCK_EX)
+ *	    pointer to return PID of locker
+ * Returns: file descriptor of lock or negative if error
+ */
+
+int lock_work (char *lock,void *sb,int op,long *pid)
+{
+  struct stat lsb,fsb;
+  struct stat *sbuf = (struct stat *) sb;
+  char tmp[MAILTMPLEN];
+  long i;
+  int fd;
+  int mask = umask (0);
+  if (pid) *pid = 0;		/* initialize return PID */
+				/* make temporary lock file name */
+  sprintf (lock,"%s/.%lx.%lx",closedBox ? "" : tmpdir,
+	   (unsigned long) sbuf->st_dev,(unsigned long) sbuf->st_ino);
+  while (T) {			/* until get a good lock */
+    do switch ((int) chk_notsymlink (lock,&lsb)) {
+    case 1:			/* exists just once */
+      if (((fd = open (lock,O_RDWR,shlock_mode)) >= 0) ||
+	  (errno != ENOENT) || (chk_notsymlink (lock,&lsb) >= 0)) break;
+    case -1:			/* name doesn't exist */
+      fd = open (lock,O_RDWR|O_CREAT|O_EXCL,shlock_mode);
+      break;
+    default:			/* multiple hard links */
+      MM_LOG ("hard link to lock name",ERROR);
+      syslog (LOG_CRIT,"SECURITY PROBLEM: hard link to lock name: %.80s",lock);
+    case 0:			/* symlink (already did syslog) */
+      umask (mask);		/* restore old mask */
+      return -1;		/* fail: no lock file */
+    } while ((fd < 0) && (errno == EEXIST));
+    if (fd < 0) {		/* failed to get file descriptor */
+      syslog (LOG_INFO,"Mailbox lock file %s open failure: %s",lock,
+	      strerror (errno));
+      if (!closedBox) {		/* more explicit snarl for bad configuration */
+	if (stat (tmpdir,&lsb))
+	  syslog (LOG_CRIT,"SYSTEM ERROR: no %s: %s",tmpdir,strerror (errno));
+	else if ((lsb.st_mode & 01777) != 01777) {
+	  sprintf (tmp,"Can't lock for write: %.80s must have 1777 protection",
+		   tmpdir);
+	  MM_LOG (tmp,WARN);
+	}
+      }
+      umask (mask);		/* restore old mask */
+      return -1;		/* fail: can't open lock file */
+    }
+
+				/* non-blocking form */
+    if (op & LOCK_NB) i = flock (fd,op);
+    else {			/* blocking form */
+      (*mailblocknotify) (BLOCK_FILELOCK,NIL);
+      i = flock (fd,op);
+      (*mailblocknotify) (BLOCK_NONE,NIL);
+    }
+    if (i) {			/* failed, get other process' PID */
+      if (pid && !fstat (fd,&fsb) && (i = min (fsb.st_size,MAILTMPLEN-1)) &&
+	  (read (fd,tmp,i) == i) && !(tmp[i] = 0) && ((i = atol (tmp)) > 0))
+	*pid = i;
+      close (fd);		/* failed, give up on lock */
+      umask (mask);		/* restore old mask */
+      return -1;		/* fail: can't lock */
+    }
+				/* make sure this lock is good for us */
+    if (!lstat (lock,&lsb) && ((lsb.st_mode & S_IFMT) != S_IFLNK) &&
+	!fstat (fd,&fsb) && (lsb.st_dev == fsb.st_dev) &&
+	(lsb.st_ino == fsb.st_ino) && (fsb.st_nlink == 1)) break;
+    close (fd);			/* lock not right, drop fd and try again */
+  }
+  chmod (lock,shlock_mode);	/* make sure mode OK (don't use fchmod()) */
+  umask (mask);			/* restore old mask */
+  return fd;			/* success */
+}
+
+/* Check to make sure not a symlink
+ * Accepts: file name
+ *	    stat buffer
+ * Returns: -1 if doesn't exist, NIL if symlink, else number of hard links
+ */
+
+long chk_notsymlink (char *name,void *sb)
+{
+  struct stat *sbuf = (struct stat *) sb;
+				/* name exists? */
+  if (lstat (name,sbuf)) return -1;
+				/* forbid symbolic link */
+  if ((sbuf->st_mode & S_IFMT) == S_IFLNK) {
+    MM_LOG ("symbolic link on lock name",ERROR);
+    syslog (LOG_CRIT,"SECURITY PROBLEM: symbolic link on lock name: %.80s",
+	    name);
+    return NIL;
+  }
+  return (long) sbuf->st_nlink;	/* return number of hard links */
+}
+
+
+/* Unlock file descriptor
+ * Accepts: file descriptor
+ *	    lock file name from lockfd()
+ */
+
+void unlockfd (int fd,char *lock)
+{
+				/* delete the file if no sharers */
+  if (!flock (fd,LOCK_EX|LOCK_NB)) unlink (lock);
+  flock (fd,LOCK_UN);		/* unlock it */
+  close (fd);			/* close it */
+}
+
+/* Set proper file protection for mailbox
+ * Accepts: mailbox name
+ *	    actual file path name
+ * Returns: T, always
+ */
+
+long set_mbx_protections (char *mailbox,char *path)
+{
+  struct stat sbuf;
+  int mode = (int) mbx_protection;
+  if (*mailbox == '#') {	/* possible namespace? */
+      if (((mailbox[1] == 'f') || (mailbox[1] == 'F')) &&
+	  ((mailbox[2] == 't') || (mailbox[2] == 'T')) &&
+	  ((mailbox[3] == 'p') || (mailbox[3] == 'P')) &&
+	  (mailbox[4] == '/')) mode = (int) ftp_protection;
+      else if (((mailbox[1] == 'p') || (mailbox[1] == 'P')) &&
+	       ((mailbox[2] == 'u') || (mailbox[2] == 'U')) &&
+	       ((mailbox[3] == 'b') || (mailbox[3] == 'B')) &&
+	       ((mailbox[4] == 'l') || (mailbox[4] == 'L')) &&
+	       ((mailbox[5] == 'i') || (mailbox[5] == 'I')) &&
+	       ((mailbox[6] == 'c') || (mailbox[6] == 'C')) &&
+	       (mailbox[7] == '/')) mode = (int) public_protection;
+      else if (((mailbox[1] == 's') || (mailbox[1] == 'S')) &&
+	       ((mailbox[2] == 'h') || (mailbox[2] == 'H')) &&
+	       ((mailbox[3] == 'a') || (mailbox[3] == 'A')) &&
+	       ((mailbox[4] == 'r') || (mailbox[4] == 'R')) &&
+	       ((mailbox[5] == 'e') || (mailbox[5] == 'E')) &&
+	       ((mailbox[6] == 'd') || (mailbox[6] == 'D')) &&
+	       (mailbox[7] == '/')) mode = (int) shared_protection;
+  }
+				/* if a directory */
+  if (!stat (path,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) {
+				/* set owner search if allow read or write */
+    if (mode & 0600) mode |= 0100;
+    if (mode & 060) mode |= 010;/* set group search if allow read or write */
+    if (mode & 06) mode |= 01;	/* set world search if allow read or write */
+				/* preserve directory SGID bit */
+    if (sbuf.st_mode & S_ISGID) mode |= S_ISGID;
+  }
+  chmod (path,mode);		/* set the new protection, ignore failure */
+  return LONGT;
+}
+
+/* Get proper directory protection
+ * Accepts: mailbox name
+ * Returns: directory mode, always
+ */
+
+long get_dir_protection (char *mailbox)
+{
+  if (*mailbox == '#') {	/* possible namespace? */
+      if (((mailbox[1] == 'f') || (mailbox[1] == 'F')) &&
+	  ((mailbox[2] == 't') || (mailbox[2] == 'T')) &&
+	  ((mailbox[3] == 'p') || (mailbox[3] == 'P')) &&
+	  (mailbox[4] == '/')) return ftp_dir_protection;
+      else if (((mailbox[1] == 'p') || (mailbox[1] == 'P')) &&
+	       ((mailbox[2] == 'u') || (mailbox[2] == 'U')) &&
+	       ((mailbox[3] == 'b') || (mailbox[3] == 'B')) &&
+	       ((mailbox[4] == 'l') || (mailbox[4] == 'L')) &&
+	       ((mailbox[5] == 'i') || (mailbox[5] == 'I')) &&
+	       ((mailbox[6] == 'c') || (mailbox[6] == 'C')) &&
+	       (mailbox[7] == '/')) return public_dir_protection;
+      else if (((mailbox[1] == 's') || (mailbox[1] == 'S')) &&
+	       ((mailbox[2] == 'h') || (mailbox[2] == 'H')) &&
+	       ((mailbox[3] == 'a') || (mailbox[3] == 'A')) &&
+	       ((mailbox[4] == 'r') || (mailbox[4] == 'R')) &&
+	       ((mailbox[5] == 'e') || (mailbox[5] == 'E')) &&
+	       ((mailbox[6] == 'd') || (mailbox[6] == 'D')) &&
+	       (mailbox[7] == '/')) return shared_dir_protection;
+  }
+  return dir_protection;
+}
+
+/* Determine default prototype stream to user
+ * Accepts: type (NIL for create, T for append)
+ * Returns: default prototype stream
+ */
+
+MAILSTREAM *default_proto (long type)
+{
+  myusername ();		/* make sure initialized */
+				/* return default driver's prototype */
+  return type ? appendProto : createProto;
+}
+
+
+/* Set up user flags for stream
+ * Accepts: MAIL stream
+ * Returns: MAIL stream with user flags set up
+ */
+
+MAILSTREAM *user_flags (MAILSTREAM *stream)
+{
+  int i;
+  myusername ();		/* make sure initialized */
+  for (i = 0; i < NUSERFLAGS && userFlags[i]; ++i)
+    if (!stream->user_flags[i]) stream->user_flags[i] = cpystr (userFlags[i]);
+  return stream;
+}
+
+
+/* Return nth user flag
+ * Accepts: user flag number
+ * Returns: flag
+ */
+
+char *default_user_flag (unsigned long i)
+{
+  myusername ();		/* make sure initialized */
+  return userFlags[i];
+}
+
+/* Process rc file
+ * Accepts: file name
+ *	    .mminit flag
+ * Don't use this feature.
+ */
+
+void dorc (char *file,long flag)
+{
+  int i;
+  char *s,*t,*k,*r,tmp[MAILTMPLEN],tmpx[MAILTMPLEN];
+  extern MAILSTREAM CREATEPROTO;
+  extern MAILSTREAM EMPTYPROTO;
+  DRIVER *d;
+  FILE *f;
+  if ((f = fopen (file ? file : SYSCONFIG,"r")) &&
+      (s = fgets (tmp,MAILTMPLEN,f)) && (t = strchr (s,'\n'))) do {
+    *t++ = '\0';		/* tie off line, find second space */
+    if ((k = strchr (s,' ')) && (k = strchr (++k,' '))) {
+      *k++ = '\0';		/* tie off two words */
+      if (!compare_cstring (s,"set keywords") && !userFlags[0]) {
+				/* yes, get first keyword */
+	k = strtok_r (k,", ",&r);
+				/* copy keyword list */
+	for (i = 0; k && i < NUSERFLAGS; ++i) if (strlen (k) <= MAXUSERFLAG) {
+	  if (userFlags[i]) fs_give ((void **) &userFlags[i]);
+	  userFlags[i] = cpystr (k);
+	  k = strtok_r (NIL,", ",&r);
+	}
+	if (flag) break;	/* found "set keywords" in .mminit */
+      }
+
+      else if (!flag) {		/* none of these valid in .mminit */
+	if (myUserName) {	/* only valid if logged in */
+	  if (!compare_cstring (s,"set new-mailbox-format") ||
+	      !compare_cstring (s,"set new-folder-format")) {
+	    if (!compare_cstring (k,"same-as-inbox")) {
+	      if (d = mail_valid (NIL,"INBOX",NIL)) {
+		if (!compare_cstring (d->name,"mbox"))
+		  d = (DRIVER *) mail_parameters (NIL,GET_DRIVER,
+						  (void *) "unix");
+		else if (!compare_cstring (d->name,"dummy")) d = NIL;
+	      }
+	      createProto = d ? ((*d->open) (NIL)) : &CREATEPROTO;
+	    }
+	    else if (!compare_cstring (k,"system-standard"))
+	      createProto = &CREATEPROTO;
+	    else {		/* canonicalize mbox to unix */
+	      if (!compare_cstring (k,"mbox")) k = "unix";
+				/* see if a driver name */
+	      if (d = (DRIVER *) mail_parameters (NIL,GET_DRIVER,(void *) k))
+		createProto = (*d->open) (NIL);
+	      else {		/* duh... */
+		sprintf (tmpx,"Unknown new mailbox format in %s: %s",
+			 file ? file : SYSCONFIG,k);
+		MM_LOG (tmpx,WARN);
+	      }
+	    }
+	  }
+	  if (!compare_cstring (s,"set empty-mailbox-format") ||
+	      !compare_cstring (s,"set empty-folder-format")) {
+	    if (!compare_cstring (k,"invalid")) appendProto = NIL;
+	    else if (!compare_cstring (k,"same-as-inbox"))
+	      appendProto = ((d = mail_valid (NIL,"INBOX",NIL)) &&
+			     compare_cstring (d->name,"dummy")) ?
+			       ((*d->open) (NIL)) : &EMPTYPROTO;
+	    else if (!compare_cstring (k,"system-standard"))
+	      appendProto = &EMPTYPROTO;
+	    else {		/* see if a driver name */
+	      for (d = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL);
+		   d && compare_cstring (d->name,k); d = d->next);
+	      if (d) appendProto = (*d->open) (NIL);
+	      else {		/* duh... */
+		sprintf (tmpx,"Unknown empty mailbox format in %s: %s",
+			 file ? file : SYSCONFIG,k);
+		MM_LOG (tmpx,WARN);
+	      }
+	    }
+	  }
+	}
+
+	if (!compare_cstring (s,"set local-host")) {
+	  fs_give ((void **) &myLocalHost);
+	  myLocalHost = cpystr (k);
+	}
+	else if (!compare_cstring (s,"set news-active-file")) {
+	  fs_give ((void **) &newsActive);
+	  newsActive = cpystr (k);
+	}
+	else if (!compare_cstring (s,"set news-spool-directory")) {
+	  fs_give ((void **) &newsSpool);
+	  newsSpool = cpystr (k);
+	}
+	else if (!compare_cstring (s,"set mh-path"))
+	  mail_parameters (NIL,SET_MHPATH,(void *) k);
+	else if (!compare_cstring (s,"set mh-allow-inbox"))
+	  mail_parameters (NIL,SET_MHALLOWINBOX,(void *) atol (k));
+	else if (!compare_cstring (s,"set news-state-file")) {
+	  fs_give ((void **) &myNewsrc);
+	  myNewsrc = cpystr (k);
+	}
+	else if (!compare_cstring (s,"set ftp-export-directory")) {
+	  fs_give ((void **) &ftpHome);
+	  ftpHome = cpystr (k);
+	}
+	else if (!compare_cstring (s,"set public-home-directory")) {
+	  fs_give ((void **) &publicHome);
+	  publicHome = cpystr (k);
+	}
+	else if (!compare_cstring (s,"set shared-home-directory")) {
+	  fs_give ((void **) &sharedHome);
+	  sharedHome = cpystr (k);
+	}
+	else if (!compare_cstring (s,"set system-inbox")) {
+	  fs_give ((void **) &sysInbox);
+	  sysInbox = cpystr (k);
+	}
+	else if (!compare_cstring (s,"set mail-subdirectory")) {
+	  fs_give ((void **) &mailsubdir);
+	  mailsubdir = cpystr (k);
+	}
+	else if (!compare_cstring (s,"set from-widget"))
+	  mail_parameters (NIL,SET_FROMWIDGET,
+			   compare_cstring (k,"header-only") ?
+			   VOIDT : NIL);
+
+	else if (!compare_cstring (s,"set rsh-command"))
+	  mail_parameters (NIL,SET_RSHCOMMAND,(void *) k);
+	else if (!compare_cstring (s,"set rsh-path"))
+	  mail_parameters (NIL,SET_RSHPATH,(void *) k);
+	else if (!compare_cstring (s,"set ssh-command"))
+	  mail_parameters (NIL,SET_SSHCOMMAND,(void *) k);
+	else if (!compare_cstring (s,"set ssh-path"))
+	  mail_parameters (NIL,SET_SSHPATH,(void *) k);
+	else if (!compare_cstring (s,"set tcp-open-timeout"))
+	  mail_parameters (NIL,SET_OPENTIMEOUT,(void *) atol (k));
+	else if (!compare_cstring (s,"set tcp-read-timeout"))
+	  mail_parameters (NIL,SET_READTIMEOUT,(void *) atol (k));
+	else if (!compare_cstring (s,"set tcp-write-timeout"))
+	  mail_parameters (NIL,SET_WRITETIMEOUT,(void *) atol (k));
+	else if (!compare_cstring (s,"set rsh-timeout"))
+	  mail_parameters (NIL,SET_RSHTIMEOUT,(void *) atol (k));
+	else if (!compare_cstring (s,"set ssh-timeout"))
+	  mail_parameters (NIL,SET_SSHTIMEOUT,(void *) atol (k));
+	else if (!compare_cstring (s,"set maximum-login-trials"))
+	  mail_parameters (NIL,SET_MAXLOGINTRIALS,(void *) atol (k));
+	else if (!compare_cstring (s,"set lookahead"))
+	  mail_parameters (NIL,SET_LOOKAHEAD,(void *) atol (k));
+	else if (!compare_cstring (s,"set prefetch"))
+	  mail_parameters (NIL,SET_PREFETCH,(void *) atol (k));
+	else if (!compare_cstring (s,"set close-on-error"))
+	  mail_parameters (NIL,SET_CLOSEONERROR,(void *) atol (k));
+	else if (!compare_cstring (s,"set imap-port"))
+	  mail_parameters (NIL,SET_IMAPPORT,(void *) atol (k));
+	else if (!compare_cstring (s,"set pop3-port"))
+	  mail_parameters (NIL,SET_POP3PORT,(void *) atol (k));
+	else if (!compare_cstring (s,"set uid-lookahead"))
+	  mail_parameters (NIL,SET_UIDLOOKAHEAD,(void *) atol (k));
+	else if (!compare_cstring (s,"set try-ssl-first"))
+	  mail_parameters (NIL,SET_TRYSSLFIRST,(void *) atol (k));
+
+	else if (!compare_cstring (s,"set mailbox-protection"))
+	  mbx_protection = atol (k);
+	else if (!compare_cstring (s,"set directory-protection"))
+	  dir_protection = atol (k);
+	else if (!compare_cstring (s,"set lock-protection"))
+	  dotlock_mode = atol (k);
+	else if (!compare_cstring (s,"set ftp-protection"))
+	  ftp_protection = atol (k);
+	else if (!compare_cstring (s,"set public-protection"))
+	  public_protection = atol (k);
+	else if (!compare_cstring (s,"set shared-protection"))
+	  shared_protection = atol (k);
+	else if (!compare_cstring (s,"set ftp-directory-protection"))
+	  ftp_dir_protection = atol (k);
+	else if (!compare_cstring (s,"set public-directory-protection"))
+	  public_dir_protection = atol (k);
+	else if (!compare_cstring (s,"set shared-directory-protection"))
+	  shared_dir_protection = atol (k);
+	else if (!compare_cstring (s,"set dot-lock-file-timeout"))
+	  locktimeout = atoi (k);
+	else if (!compare_cstring (s,"set disable-fcntl-locking"))
+	  fcntlhangbug = atoi (k);
+	else if (!compare_cstring (s,"set disable-lock-warning"))
+	  disableLockWarning = atoi (k);
+	else if (!compare_cstring (s,"set disable-unix-UIDs-and-keywords"))
+	  has_no_life = atoi (k);
+	else if (!compare_cstring (s,"set hide-dot-files"))
+	  hideDotFiles = atoi (k);
+	else if (!compare_cstring (s,"set list-maximum-level"))
+	  list_max_level = atol (k);
+	else if (!compare_cstring (s,"set trust-dns"))
+	  mail_parameters (NIL,SET_TRUSTDNS,(void *) atol (k));
+	else if (!compare_cstring (s,"set sasl-uses-ptr-name"))
+	  mail_parameters (NIL,SET_SASLUSESPTRNAME,(void *) atol (k));
+	else if (!compare_cstring (s,"set network-filesystem-stat-bug"))
+	  netfsstatbug = atoi (k);
+	else if (!compare_cstring (s,"set nntp-range"))
+	  mail_parameters (NIL,SET_NNTPRANGE,(void *) atol (k));
+
+	else if (!file) {	/* only allowed in system init */
+	  if (!compare_cstring (s,"set black-box-directory") &&
+	      !blackBoxDir) blackBoxDir = cpystr (k);
+	  else if (!compare_cstring(s,"set black-box-default-home-directory")&&
+		   blackBoxDir && !blackBoxDefaultHome)
+	    blackBoxDefaultHome = cpystr (k);
+	  else if (!compare_cstring (s,"set anonymous-home-directory") &&
+		   !anonymousHome) anonymousHome = cpystr (k);
+				/* It's tempting to allow setting the CA path
+				 * in a user init.  However, that opens up a
+				 * vector of attack big enough to drive a
+				 * truck through...  Resist the temptation.
+				 */
+	  else if (!compare_cstring (s,"set CA-certificate-path"))
+	    sslCApath = cpystr (k);
+	  else if (!compare_cstring (s,"set disable-plaintext"))
+	    disablePlaintext = atoi (k);
+	  else if (!compare_cstring (s,"set allowed-login-attempts"))
+	    logtry = atoi (k);
+	  else if (!compare_cstring (s,"set chroot-server"))
+	    closedBox = atoi (k);
+	  else if (!compare_cstring (s,"set restrict-mailbox-access"))
+	    for (k = strtok_r (k,", ",&r); k; k = strtok_r (NIL,", ",&r)) {
+	      if (!compare_cstring (k,"root")) restrictBox |= RESTRICTROOT;
+	      else if (!compare_cstring (k,"otherusers"))
+		restrictBox |= RESTRICTOTHERUSER;
+	      else if (!compare_cstring (k,"all")) restrictBox = -1;
+	    }
+	  else if (!compare_cstring (s,"set advertise-the-world"))
+	    advertisetheworld = atoi (k);
+	  else if (!compare_cstring (s,"set limited-advertise"))
+	    limitedadvertise = atoi (k);
+	  else if (!compare_cstring
+		   (s,"set disable-automatic-shared-namespaces"))
+	    noautomaticsharedns = atoi (k);
+	  else if (!compare_cstring (s,"set allow-user-config"))
+	    allowuserconfig = atoi (k);
+	  else if (!compare_cstring (s,"set allow-reverse-dns"))
+	    mail_parameters (NIL,SET_ALLOWREVERSEDNS,(void *) atol (k));
+	  else if (!compare_cstring (s,"set k5-cp-uses-service-name"))
+	    kerb_cp_svr_name = atoi (k);
+				/* must appear in file after any
+				 * "set disable-plaintext" command! */
+	  else if (!compare_cstring (s,"set plaintext-allowed-clients")) {
+	    for (k = strtok_r (k,", ",&r); k && !tcp_isclienthost (k);
+		 k = strtok_r (NIL,", ",&r));
+	    if (k) disablePlaintext = 0;
+	  }
+	}
+      }
+    }
+  } while ((s = fgets (tmp,MAILTMPLEN,f)) && (t = strchr (s,'\n')));
+  if (f) fclose (f);		/* flush the file */
+}
+
+/* INBOX create function for tmail/dmail use only
+ * Accepts: mail stream
+ *	    path name buffer, preloaded with driver-dependent path
+ * Returns: T on success, NIL on failure
+ *
+ * This routine is evil and a truly incredible kludge.  It is private for
+ * tmail/dmail and is not supported for any other application.
+ */
+
+long path_create (MAILSTREAM *stream,char *path)
+{
+  long ret;
+  short rsave = restrictBox;
+  restrictBox = NIL;		/* can't restrict */
+  if (blackBox) {		/* if black box */
+				/* toss out driver dependent names */
+    printf (path,"%s/INBOX",mymailboxdir ());
+    blackBox = NIL;		/* well that's evil - evil is going on */
+    ret = mail_create (stream,path);
+    blackBox = T;		/* restore the box */
+  }
+				/* easy thing otherwise */
+  else ret = mail_create (stream,path);
+  restrictBox = rsave;		/* restore restrictions */
+  return ret;
+}
+
+/* Default block notify routine
+ * Accepts: reason for calling
+ *	    data
+ * Returns: data
+ */
+
+void *mm_blocknotify (int reason,void *data)
+{
+  void *ret = data;
+  switch (reason) {
+  case BLOCK_SENSITIVE:		/* entering sensitive code */
+    ret = (void *) (unsigned long) alarm (0);
+    break;
+  case BLOCK_NONSENSITIVE:	/* exiting sensitive code */
+    if ((unsigned long) data) alarm ((unsigned long) data);
+    break;
+  default:			/* ignore all other reasons */
+    break;
+  }
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/env_unix.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,95 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX environment routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+typedef struct dotlock_base {
+  char lock[MAILTMPLEN];
+  int pipei;
+  int pipeo;
+} DOTLOCK;
+
+
+/* Bits that can be set in restrictBox */
+
+#define RESTRICTROOT 0x1	/* restricted box doesn't allow root */
+#define RESTRICTOTHERUSER 0x2	/* restricted box doesn't allow other user */
+
+/* Subscription definitions for UNIX */
+
+#define SUBSCRIPTIONFILE(t) sprintf (t,"%s/.mailboxlist",myhomedir ())
+#define SUBSCRIPTIONTEMP(t) sprintf (t,"%s/.mlbxlsttmp",myhomedir ())
+
+
+/* dorc() options */
+
+#define SYSCONFIG "/etc/c-client.cf"
+
+
+/* Special users */
+
+#define ANONYMOUSUSER "nobody"	/* anonymous user */
+#define UNLOGGEDUSER "root"	/* unlogged-in user */
+#define ADMINGROUP "mailadm"	/* mail administrator group */
+
+/* Function prototypes */
+
+#include "env.h"
+
+void rfc822_fixed_date (char *date);
+long env_init (char *user,char *home);
+char *myusername_full (unsigned long *flags);
+#define MU_LOGGEDIN 0
+#define MU_NOTLOGGEDIN 1
+#define MU_ANONYMOUS 2
+#define myusername() \
+  myusername_full (NIL)
+char *sysinbox ();
+char *mailboxdir (char *dst,char *dir,char *name);
+long dotlock_lock (char *file,DOTLOCK *base,int fd);
+long dotlock_unlock (DOTLOCK *base);
+int lockname (char *lock,char *fname,int op,long *pid);
+int lockfd (int fd,char *lock,int op);
+int lock_work (char *lock,void *sbuf,int op,long *pid);
+long chk_notsymlink (char *name,void *sbuf);
+void unlockfd (int fd,char *lock);
+long set_mbx_protections (char *mailbox,char *path);
+long get_dir_protection (char *mailbox);
+MAILSTREAM *user_flags (MAILSTREAM *stream);
+char *default_user_flag (unsigned long i);
+void dorc (char *file,long flag);
+long path_create (MAILSTREAM *stream,char *mailbox);
+void grim_pid_reap_status (int pid,int killreq,void *status);
+#define grim_pid_reap(pid,killreq) \
+  grim_pid_reap_status (pid,killreq,NIL)
+long safe_write (int fd,char *buf,long nbytes);
+void *arm_signal (int sig,void *action);
+struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]);
+long loginpw (struct passwd *pw,int argc,char *argv[]);
+long pw_login (struct passwd *pw,char *auser,char *user,char *home,int argc,
+	       char *argv[]);
+void *mm_blocknotify (int reason,void *data);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/fdstring.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,99 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	File descriptor string routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	15 April 1997
+ * Last Edited:	4 April 2007
+ */
+
+#include "mail.h"
+#include "osdep.h"
+#include "misc.h"
+#include "fdstring.h"
+
+/* String driver for fd stringstructs */
+
+static void fd_string_init (STRING *s,void *data,unsigned long size);
+static char fd_string_next (STRING *s);
+static void fd_string_setpos (STRING *s,unsigned long i);
+
+STRINGDRIVER fd_string = {
+  fd_string_init,		/* initialize string structure */
+  fd_string_next,		/* get next byte in string structure */
+  fd_string_setpos		/* set position in string structure */
+};
+
+
+/* Initialize string structure for fd stringstruct
+ * Accepts: string structure
+ *	    pointer to string
+ *	    size of string
+ */
+
+static void fd_string_init (STRING *s,void *data,unsigned long size)
+{
+  FDDATA *d = (FDDATA *) data;
+				/* note fd */
+  s->data = (void *) (unsigned long) d->fd;
+  s->data1 = d->pos;		/* note file offset */
+  s->size = size;		/* note size */
+  s->curpos = s->chunk = d->chunk;
+  s->chunksize = (unsigned long) d->chunksize;
+  s->offset = 0;		/* initial position */
+				/* and size of data */
+  s->cursize = min (s->chunksize,size);
+				/* move to that position in the file */
+  lseek (d->fd,d->pos,L_SET);
+  read (d->fd,s->chunk,(size_t) s->cursize);
+}
+
+/* Get next character from fd stringstruct
+ * Accepts: string structure
+ * Returns: character, string structure chunk refreshed
+ */
+
+static char fd_string_next (STRING *s)
+{
+  char c = *s->curpos++;	/* get next byte */
+  SETPOS (s,GETPOS (s));	/* move to next chunk */
+  return c;			/* return the byte */
+}
+
+
+/* Set string pointer position for fd stringstruct
+ * Accepts: string structure
+ *	    new position
+ */
+
+static void fd_string_setpos (STRING *s,unsigned long i)
+{
+  if (i > s->size) i = s->size;	/* don't permit setting beyond EOF */
+  s->offset = i;		/* set new offset */
+  s->curpos = s->chunk;		/* reset position */
+				/* set size of data */
+  if (s->cursize = min (s->chunksize,SIZE (s))) {
+				/* move to that position in the file */
+    lseek ((long) s->data,s->data1 + s->offset,L_SET);
+    read ((long) s->data,s->curpos,(size_t) s->cursize);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/fdstring.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,39 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	File descriptor string routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	15 April 1997
+ * Last Edited:	30 August 2006
+ */
+
+/* Driver-dependent data passed to init method */
+
+typedef struct fd_data {
+  int fd;			/* file descriptor */
+  unsigned long pos;		/* initial position */
+  char *chunk;			/* I/O buffer chunk */
+  unsigned long chunksize;	/* I/O buffer chunk length */
+} FDDATA;
+
+
+extern STRINGDRIVER fd_string;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/flockcyg.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,92 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	flock emulation via fcntl() locking
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 April 2001
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Cygwin does not seem to have the design flaw in fcntl() locking that
+ * most other systems do (see flocksim.c for details).  If some cretin
+ * decides to implement that design flaw, then Cygwin will have to use
+ * flocksim.  Also, we don't test NFS either.
+ *
+ * However, Cygwin does have the Windows misfeature (introduced in NT 4.0)
+ * that you can not write to any segment which has a shared lock, and you
+ * can't lock a zero-byte segment either.  This screws up the shared-write
+ * mailbox drivers (mbx, mtx, mx, and tenex).  As a workaround, we'll only
+ * lock the first byte of the file, meaning that you can't write that byte
+ * shared.  It's been suggested to lock the maximum off_t type, but that
+ * risks having a future version of Windows (or Cygwin) deciding that this
+ * also means "no lock".
+ */
+
+#undef flock			/* name is used as a struct for fcntl */
+
+/* Emulator for flock() call
+ * Accepts: file descriptor
+ *	    operation bitmask
+ * Returns: 0 if successful, -1 if failure under BSD conditions
+ */
+
+int flocksim (int fd,int op)
+{
+  char tmp[MAILTMPLEN];
+  int logged = 0;
+  struct flock fl;
+				/* lock one bytes at byte 0 */
+  fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 1;
+  fl.l_pid = getpid ();		/* shouldn't be necessary */
+  switch (op & ~LOCK_NB) {	/* translate to fcntl() operation */
+  case LOCK_EX:			/* exclusive */
+    fl.l_type = F_WRLCK;
+    break;
+  case LOCK_SH:			/* shared */
+    fl.l_type = F_RDLCK;
+    break;
+  case LOCK_UN:			/* unlock */
+    fl.l_type = F_UNLCK;
+    break;
+  default:			/* default */
+    errno = EINVAL;
+    return -1;
+  }
+  while (fcntl (fd,(op & LOCK_NB) ? F_SETLK : F_SETLKW,&fl))
+    if (errno != EINTR) {
+      /* Can't use switch here because these error codes may resolve to the
+       * same value on some systems.
+       */
+      if ((errno != EWOULDBLOCK) && (errno != EAGAIN) && (errno != EACCES)) {
+	sprintf (tmp,"Unexpected file locking failure: %s",strerror (errno));
+				/* give the user a warning of what happened */
+	MM_NOTIFY (NIL,tmp,WARN);
+	if (!logged++) syslog (LOG_ERR,"%s",tmp);
+	if (op & LOCK_NB) return -1;
+	sleep (5);		/* slow things down for loops */
+      }
+				/* return failure for non-blocking lock */
+      else if (op & LOCK_NB) return -1;
+    }
+  return 0;			/* success */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/flockcyg.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,50 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	flock() emulation via fcntl() locking
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 April 2001
+ * Last Edited:	30 August 2006
+ */
+
+/* Cygwin does not seem to have the design flaw in fcntl() locking that
+ * most other systems do (see flocksim.c for details).  If some cretin
+ * decides to implement that design flaw, then Cygwin will have to use
+ * flocksim.  Also, we don't test NFS either
+ */
+
+
+#define flock flocksim		/* use ours instead of theirs */
+
+#undef LOCK_SH
+#define LOCK_SH 1		/* shared lock */
+#undef LOCK_EX
+#define LOCK_EX 2		/* exclusive lock */
+#undef LOCK_NB
+#define LOCK_NB 4		/* no blocking */
+#undef LOCK_UN
+#define LOCK_UN 8		/* unlock */
+
+
+/* Function prototypes */
+
+int flocksim (int fd,int operation);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/flocklnx.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,76 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Safe File Lock for Linux
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	20 April 2005
+ * Last Edited:	30 August 2006
+ */
+ 
+#undef flock
+
+#include <sys/vfs.h>
+#ifndef NFS_SUPER_MAGIC
+#define NFS_SUPER_MAGIC 0x6969
+#endif
+
+int safe_flock (int fd,int op)
+{
+  struct statfs sfbuf;
+  char tmp[MAILTMPLEN];
+  int e;
+  int logged = 0;
+  /* Check for NFS because Linux 2.6 broke flock() on NFS.  Instead of being
+   * a no-op, flock() on NFS now returns ENOLCK.  Read
+   *   https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=123415
+   * for the gruesome details.
+   */
+				/* check filesystem type */
+  while ((e = fstatfs (fd,&sfbuf)) && (errno == EINTR));
+  if (!e) switch (sfbuf.f_type) {
+  case NFS_SUPER_MAGIC:		/* always a fast no-op on NFS */
+    break;
+  default:			/* allow on other filesystem types */
+				/* do the lock */
+    while (flock (fd,op)) switch (errno) {
+    case EINTR:			/* interrupt */
+      break;
+    case ENOLCK:		/* lock table is full */
+      sprintf (tmp,"File locking failure: %s",strerror (errno));
+      mm_log (tmp,WARN);	/* give the user a warning of what happened */
+      if (!logged++) syslog (LOG_ERR,tmp);
+				/* return failure if non-blocking lock */
+      if (op & LOCK_NB) return -1;
+      sleep (5);		/* slow down in case it loops */
+      break;
+    case EWOULDBLOCK:		/* file is locked, LOCK_NB should be set */
+      if (op & LOCK_NB) return -1;
+    case EBADF:			/* not valid open file descriptor */
+    case EINVAL:		/* invalid operator */
+    default:			/* other error code? */
+      sprintf (tmp,"Unexpected file locking failure: %s",strerror (errno));
+      fatal (tmp);
+    }
+    break;
+  }
+  return 0;			/* success */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/flocksim.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,920 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	flock emulation via fcntl() locking
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 April 2001
+ * Last Edited:	11 October 2007
+ */
+ 
+#undef flock			/* name is used as a struct for fcntl */
+
+#ifndef NOFSTATVFS		/* thank you, SUN.  NOT! */
+# ifndef NOFSTATVFS64
+#  ifndef _LARGEFILE64_SOURCE
+#   define _LARGEFILE64_SOURCE
+#  endif	/* _LARGEFILE64_SOURCE */
+# endif		/* NOFSTATVFFS64 */
+#include <sys/statvfs.h>
+#endif		/* NOFSTATVFS */
+
+#ifndef NSIG			/* don't know if this can happen */
+#define NSIG 32			/* a common maximum */
+#endif
+
+/* Emulator for flock() call
+ * Accepts: file descriptor
+ *	    operation bitmask
+ * Returns: 0 if successful, -1 if failure under BSD conditions
+ */
+
+int flocksim (int fd,int op)
+{
+  char tmp[MAILTMPLEN];
+  int logged = 0;
+  struct stat sbuf;
+  struct ustat usbuf;
+  struct flock fl;
+				/* lock zero bytes at byte 0 */
+  fl.l_whence = SEEK_SET; fl.l_start = fl.l_len = 0;
+  fl.l_pid = getpid ();		/* shouldn't be necessary */
+  switch (op & ~LOCK_NB) {	/* translate to fcntl() operation */
+  case LOCK_EX:			/* exclusive */
+    fl.l_type = F_WRLCK;
+    break;
+  case LOCK_SH:			/* shared */
+    fl.l_type = F_RDLCK;
+    break;
+  case LOCK_UN:			/* unlock */
+    fl.l_type = F_UNLCK;
+    break;
+  default:			/* default */
+    errno = EINVAL;
+    return -1;
+  }
+				/* always return success if disabled */
+  if (mail_parameters (NIL,GET_DISABLEFCNTLLOCK,NIL)) return 0;
+
+  /*  Make fcntl() locking of NFS files be a no-op the way it is with flock()
+   * on BSD.  This is because the rpc.statd/rpc.lockd daemons don't work very
+   * well and cause cluster-wide hangs if you exercise them at all.  The
+   * result of this is that you lose the ability to detect shared mail_open()
+   * on NFS-mounted files.  If you are wise, you'll use IMAP instead of NFS
+   * for mail files.
+   *
+   *  Sun alleges that it doesn't matter, and that they have fixed all the
+   * rpc.statd/rpc.lockd bugs.  As of October 2006, that is still false.
+   *
+   *  We need three tests for three major historical variants in SVR4:
+   *  1) In NFSv2, ustat() would return -1 in f_tinode for NFS.
+   *  2) When fstatvfs() was introduced with NFSv3, ustat() was "fixed".
+   *  3) When 64-bit filesystems were introduced, fstatvfs() would return
+   *	 EOVERFLOW; you have to use fstatvfs64() even though you don't care
+   *	 about any of the affected values.
+   *
+   * We can't use fstatfs() because fstatfs():
+   * . is documented as being deprecated in SVR4.
+   * . has inconsistent calling conventions (there are two additional int
+   *   arguments on Solaris and I don't know what they do).
+   * . returns inconsistent statfs structs.  On Solaris, the file system type
+   *   is a short called f_fstyp.  On AIX, it's an int called f_type that is
+   *   documented as always being 0!
+   *
+   * For what it's worth, here's the scoop on fstatfs() elsewhere:
+   *
+   *  On Linux, the file system type is a long called f_type that has a file
+   * system type code.  A different module (flocklnx.c) uses this because
+   * some knothead "improved" flock() to return ENOLCK on NFS files instead
+   * of being a successful no-op.  This "improvement" apparently has been
+   * reverted, but not before it got to many systems in the field.
+   *
+   *  On BSD, it's a short called either f_otype or f_type that is documented
+   * as always being zero.  Fortunately, BSD has flock() the way it's supposed
+   * to be, and none of this nonsense is necessary.
+   */
+  if (!fstat (fd,&sbuf))	{ /* no hope of working if can't fstat()! */
+    /* Any base type that begins with "nfs" or "afs" is considered to be a
+     * network filesystem.
+     */
+#ifndef NOFSTATVFS
+    struct statvfs vsbuf;
+#ifndef NOFSTATVFS64
+    struct statvfs64 vsbuf64;
+    if (!fstatvfs64 (fd,&vsbuf64) && (vsbuf64.f_basetype[1] == 'f') &&
+	(vsbuf64.f_basetype[2] == 's') &&
+	((vsbuf64.f_basetype[0] == 'n') || (vsbuf64.f_basetype[0] == 'a')))
+      return 0;
+#endif		/* NOFSTATVFS64 */
+    if (!fstatvfs (fd,&vsbuf) && (vsbuf.f_basetype[1] == 'f') &&
+	(vsbuf.f_basetype[2] == 's') &&
+	((vsbuf.f_basetype[0] == 'n') || (vsbuf.f_basetype[0] == 'a')))
+      return 0;
+#endif		/* NOFSTATVFS */
+    if (!ustat (sbuf.st_dev,&usbuf) && !++usbuf.f_tinode) return 0;
+  }
+
+				/* do the lock */
+  while (fcntl (fd,(op & LOCK_NB) ? F_SETLK : F_SETLKW,&fl))
+    if (errno != EINTR) {
+      /* Can't use switch here because these error codes may resolve to the
+       * same value on some systems.
+       */
+      if ((errno != EWOULDBLOCK) && (errno != EAGAIN) && (errno != EACCES)) {
+	sprintf (tmp,"Unexpected file locking failure: %.100s",
+		 strerror (errno));
+				/* give the user a warning of what happened */
+	MM_NOTIFY (NIL,tmp,WARN);
+	if (!logged++) syslog (LOG_ERR,"%s",tmp);
+	if (op & LOCK_NB) return -1;
+	sleep (5);		/* slow things down for loops */
+      }
+				/* return failure for non-blocking lock */
+      else if (op & LOCK_NB) return -1;
+    }
+  return 0;			/* success */
+}
+
+/* Master/slave procedures for safe fcntl() locking.
+ *
+ *  The purpose of this nonsense is to work around a bad bug in fcntl()
+ * locking.  The cretins who designed it decided that a close() should
+ * release any locks made by that process on the file opened on that
+ * file descriptor.  Never mind that the lock wasn't made on that file
+ * descriptor, but rather on some other file descriptor.
+ *
+ *  This bug is on every implementation of fcntl() locking that I have
+ * tested.  Fortunately, on BSD systems, OSF/1, and Linux, we can use the
+ * flock() system call which doesn't have this bug.
+ *
+ *  Note that OSF/1, Linux, and some BSD systems have both broken fcntl()
+ * locking and the working flock() locking.
+ *
+ *  The program below can be used to demonstrate this problem.  Be sure to
+ * let it run long enough for all the sleep() calls to finish.
+ */
+
+#if 0
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/file.h>
+
+main ()
+{
+  struct flock fl;
+  int fd,fd2;
+  char *file = "a.a";
+  if ((fd = creat (file,0666)) < 0)
+    perror ("TEST FAILED: can't create test file"),_exit (errno);
+  close (fd);
+  if (fork ()) {		/* parent */
+    if ((fd = open (file,O_RDWR,0)) < 0) abort();
+				/* lock applies to entire file */
+    fl.l_whence = fl.l_start = fl.l_len = 0;
+    fl.l_pid = getpid ();	/* shouldn't be necessary */
+    fl.l_type = F_RDLCK;
+    if (fcntl (fd,F_SETLKW,&fl) == -1) abort ();
+    sleep (5);
+    if ((fd2 = open (file,O_RDWR,0)) < 0) abort ();
+    sleep (1);
+    puts ("parent test ready -- will hang here if locking works correctly");
+    close (fd2);
+    wait (0);
+    puts ("OS BUG: child terminated");
+    _exit (0);
+  }
+  else {			/* child */
+    sleep (2);
+    if ((fd = open (file,O_RDWR,0666)) < 0) abort ();
+    puts ("child test ready -- child will hang if no bug");
+				/* lock applies to entire file */
+    fl.l_whence = fl.l_start = fl.l_len = 0;
+    fl.l_pid = getpid ();	/* shouldn't be necessary */
+    fl.l_type = F_WRLCK;
+    if (fcntl (fd,F_SETLKW,&fl) == -1) abort ();
+    puts ("OS BUG: child got lock");
+  }
+}
+#endif
+
+/*  Beware of systems such as AIX which offer flock() as a compatibility
+ * function that is just a jacket into fcntl() locking.  The program below
+ * is a variant of the program above, only using flock().  It can be used
+ * to test to see if your system has real flock() or just a jacket into
+ * fcntl().
+ *
+ *  Be sure to let it run long enough for all the sleep() calls to finish.
+ * If the program hangs, then flock() works and you can dispense with the
+ * use of this module (you lucky person!).
+ */
+
+#if 0
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/file.h>
+
+main ()
+{
+  int fd,fd2;
+  char *file = "a.a";
+  if ((fd = creat (file,0666)) < 0)
+    perror ("TEST FAILED: can't create test file"),_exit (errno);
+  close (fd);
+  if (fork ()) {		/* parent */
+    if ((fd = open (file,O_RDWR,0)) < 0) abort();
+    if (flock (fd,LOCK_SH) == -1) abort ();
+    sleep (5);
+    if ((fd2 = open (file,O_RDWR,0)) < 0) abort ();
+    sleep (1);
+    puts ("parent test ready -- will hang here if flock() works correctly");
+    close (fd2);
+    wait (0);
+    puts ("OS BUG: child terminated");
+    _exit (0);
+  }
+  else {			/* child */
+    sleep (2);
+    if ((fd = open (file,O_RDWR,0666)) < 0) abort ();
+    puts ("child test ready -- child will hang if no bug");
+    if (flock (fd,LOCK_EX) == -1) abort ();
+    puts ("OS BUG: child got lock");
+  }
+}
+#endif
+
+/* Master/slave details
+ *
+ *  On broken systems, we invoke an inferior fork to execute any driver
+ * dispatches which are likely to tickle this bug; specifically, any
+ * dispatch which may fiddle with a mailbox that is already selected.  As
+ * of this writing, these are: delete, rename, status, scan, copy, and append.
+ *
+ *  Delete and rename are pretty marginal, yet there are certain clients
+ * (e.g. Outlook Express) that really want to delete or rename the selected
+ * mailbox.  The same is true of status, but there are people (such as the
+ * authors of Entourage) who don't understand why status of the selected
+ * mailbox is bad news.
+ *
+ *  However, in copy and append it is reasonable to do this to a selected
+ * mailbox.  Although scanning the selected mailbox isn't particularly
+ * sensible, it's hard to avoid due to wildcards.
+ *
+ *  It is still possible for an application to trigger the bug by doing
+ * mail_open() on the same mailbox twice.  Don't do it.
+ *
+ *  Once the slave is invoked, the master only has to read events from the
+ * slave's output (see below for these events) and translate these events
+ * to the appropriate c-client callback.  When end of file occurs on the pipe,
+ * the master reads the slave's exit status and uses that as the function
+ * return.  The append master is slightly more complicated because it has to
+ * send data back to the slave (see below).
+ *
+ *  The slave takes callback events from the driver which otherwise would
+ * pass to the main program.  Only those events which a slave can actually
+ * encounter are covered here; for example mm_searched() and mm_list() are
+ * not covered since a slave never does the operations that trigger these.
+ * Certain other events (mm_exists(), mm_expunged(), mm_flags()) are discarded
+ * by the slave since the master will generate these events for itself.
+ *
+ *  The other events cause the slave to write a newline-terminated string to
+ * its output.  The first character of string indicates the event: S for
+ * mm_status(), N for mm_notify(), L for mm_log(), C for mm_critical(), X for
+ * mm_nocritical(), D for mm_diskerror(), F for mm_fatal(), and "A" for append
+ * argument callback.  Most of these events also carry data, which carried as
+ * text space-delimited in the string.
+ *
+ *  Append argument callback requires the master to provide the slave with
+ * data in the slave's input.  The first thing that the master provides is
+ * either a "+" (master has data for the slave) or a "-" (master has no data).
+ * If the master has data, it will then send the flags, internal date, and
+ * message text, each as <text octet count><SPACE><text>.
+ */
+
+/*  It should be alright for lockslavep to be a global, since it will always
+ * be zero in the master (which is where threads would be).  The slave won't
+ * ever thread, since any driver which threads in its methods probably can't
+ * use fcntl() locking so won't have DR_LOCKING in its driver flags 
+ *
+ *  lockslavep can not be a static, since it's used by the dispatch macros.
+ */
+
+int lockslavep = 0;		/* non-zero means slave process for locking */
+static int lockproxycopy = 0;	/* non-zero means redo copy as proxy */
+FILE *slavein = NIL;		/* slave input */
+FILE *slaveout = NIL;		/* slave output */
+
+
+/* Common master
+ * Accepts: permitted stream
+ *	    append callback (append calls only, else NIL)
+ *	    data for callback (append calls only, else NIL)
+ * Returns: (master) T if slave succeeded, NIL if slave failed
+ *	    (slave) NIL always, with lockslavep non-NIL
+ */
+
+static long master (MAILSTREAM *stream,append_t af,void *data)
+{
+  MAILSTREAM *st;
+  MAILSTATUS status;
+  STRING *message;
+  FILE *pi,*po;
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  long ret = NIL;
+  unsigned long i,j;
+  int c,pid,pipei[2],pipeo[2];
+  char *s,*t,event[MAILTMPLEN],tmp[MAILTMPLEN];
+  lockproxycopy = NIL;		/* not doing a lock proxycopy */
+				/* make pipe from slave */
+  if (pipe (pipei) < 0) mm_log ("Can't create input pipe",ERROR);
+  else if (pipe (pipeo) < 0) {
+    mm_log ("Can't create output pipe",ERROR);
+    close (pipei[0]); close (pipei[1]);
+  }
+  else if ((pid = fork ()) < 0) {/* make slave */
+    mm_log ("Can't create execution process",ERROR);
+    close (pipei[0]); close (pipei[1]);
+    close (pipeo[0]); close (pipeo[1]);
+  }
+  else if (lockslavep = !pid) {	/* are we slave or master? */
+    alarm (0);			/* slave doesn't have alarms or signals */
+    for (c = 0; c < NSIG; c++) signal (c,SIG_DFL);
+    if (!(slavein = fdopen (pipeo[0],"r")) ||
+	!(slaveout = fdopen (pipei[1],"w")))
+      fatal ("Can't do slave pipe buffered I/O");
+    close (pipei[0]);		/* close parent's side of the pipes */
+    close (pipeo[1]);
+  }
+
+  else {			/* master process */
+    void *blockdata = (*bn) (BLOCK_SENSITIVE,NIL);
+    close (pipei[1]);		/* close slave's side of the pipes */
+    close (pipeo[0]);
+    if (!(pi = fdopen (pipei[0],"r")) || !(po = fdopen (pipeo[1],"w")))
+      fatal ("Can't do master pipe buffered I/O");
+				/* do slave events until EOF */
+				/* read event */
+    while (fgets (event,MAILTMPLEN-1,pi)) {
+      if (!(s = strchr (event,'\n'))) {
+	sprintf (tmp,"Execution process event string too long: %.500s",event);
+	fatal (tmp);
+      }
+      *s = '\0';		/* tie off event at end of line */
+      switch (event[0]) {	/* analyze event */
+      case 'A':			/* append callback */
+	if ((*af) (NIL,data,&s,&t,&message)) {
+	  if (i = message ? SIZE (message) : 0) {
+	    if (!s) s = "";	/* default values */
+	    if (!t) t = "";
+	  }
+	  else s = t = "";	/* no flags or date if no message */
+	  errno = NIL;		/* reset last error */
+				/* build response */
+	  if (fprintf (po,"+%lu %s%lu %s%lu ",strlen (s),s,strlen (t),t,i) < 0)
+	    fatal ("Failed to pipe append command");
+				/* write message text */
+	  if (i) do if (putc (c = 0xff & SNX (message),po) == EOF) {
+	    sprintf (tmp,"Failed to pipe %lu bytes (of %lu), last=%u: %.100s",
+		     i,message->size,c,strerror (errno));
+	    fatal (tmp);
+	  } while (--i);
+	}
+	else putc ('-',po);	/* append error */
+	fflush (po);
+	break;
+      case '&':			/* slave wants a proxycopy? */
+	lockproxycopy = T;
+	break;
+
+      case 'L':			/* mm_log() */
+	i = strtoul (event+1,&s,10);
+	if (!s || (*s++ != ' ')) {
+	  sprintf (tmp,"Invalid log event arguments: %.500s",event);
+	  fatal (tmp);
+	}
+	mm_log (s,i);
+	break;
+      case 'N':			/* mm_notify() */
+	st = (MAILSTREAM *) strtoul (event+1,&s,16);
+	if (s && (*s++ == ' ')) {
+	  i = strtoul (s,&s,10);/* get severity */
+	  if (s && (*s++ == ' ')) {
+	    mm_notify ((st == stream) ? stream : NIL,s,i);
+	    break;
+	  }
+	}
+	sprintf (tmp,"Invalid notify event arguments: %.500s",event);
+	fatal (tmp);
+
+      case 'S':			/* mm_status() */
+	st = (MAILSTREAM *) strtoul (event+1,&s,16);
+	if (s && (*s++ == ' ')) {
+	  status.flags = strtoul (s,&s,10);
+	  if (s && (*s++ == ' ')) {
+	    status.messages = strtoul (s,&s,10);
+	    if (s && (*s++ == ' ')) {
+	      status.recent = strtoul (s,&s,10);
+	      if (s && (*s++ == ' ')) {
+		status.unseen = strtoul (s,&s,10);
+		if (s && (*s++ == ' ')) {
+		  status.uidnext = strtoul (s,&s,10);
+		  if (s && (*s++ == ' ')) {
+		    status.uidvalidity = strtoul (s,&s,10);
+		    if (s && (*s++ == ' ')) {
+		      mm_status ((st == stream) ? stream : NIL,s,&status);
+		      break;
+		    }
+		  }
+		}
+	      }
+	    }
+	  }
+	}
+	sprintf (tmp,"Invalid status event arguments: %.500s",event);
+	fatal (tmp);
+      case 'C':			/* mm_critical() */
+	st = (MAILSTREAM *) strtoul (event+1,&s,16);
+	mm_critical ((st == stream) ? stream : NIL);
+	break;
+      case 'X':			/* mm_nocritical() */
+	st = (MAILSTREAM *) strtoul (event+1,&s,16);
+	mm_nocritical ((st == stream) ? stream : NIL);
+	break;
+
+      case 'D':			/* mm_diskerror() */
+	st = (MAILSTREAM *) strtoul (event+1,&s,16);
+	if (s && (*s++ == ' ')) {
+	  i = strtoul (s,&s,10);
+	  if (s && (*s++ == ' ')) {
+	    j = (long) strtoul (s,NIL,10);
+	    if (st == stream)	/* let's hope it's on usable stream */
+	      putc (mm_diskerror (stream,(long) i,j) ? '+' : '-',po);
+	    else if (j) {	/* serious diskerror on slave-created stream */
+	      mm_log ("Retrying disk write to avoid mailbox corruption!",WARN);
+	      sleep (5);	/* give some time for it to clear up */
+	      putc ('-',po);	/* don't abort */
+	    }
+	    else {		/* recoverable on slave-created stream */
+	      mm_log ("Error on disk write",ERROR);
+	      putc ('+',po);	/* so abort it */
+	    }
+	    fflush (po);	/* force it out either way */
+	    break;
+	  }
+	}
+	sprintf (tmp,"Invalid diskerror event arguments: %.500s",event);
+	fatal (tmp);
+      case 'F':			/* mm_fatal() */
+	mm_fatal (event+1);
+	break;
+      default:			/* random lossage */
+	sprintf (tmp,"Unknown event from execution process: %.500s",event);
+	fatal (tmp);
+      }
+    }
+    fclose (pi); fclose (po);	/* done with the pipes */
+				/* get slave status */
+    grim_pid_reap_status (pid,NIL,&ret);
+    if (ret & 0177) {		/* signal or stopped */
+      sprintf (tmp,"Execution process terminated abnormally (%lx)",ret);
+      mm_log (tmp,ERROR);
+      ret = NIL;
+    }
+    else ret >>= 8;		/* return exit code */
+    (*bn) (BLOCK_NONSENSITIVE,blockdata);
+  }
+  return ret;			/* return status */
+}
+
+/* Safe driver calls */
+
+
+/* Safely delete mailbox
+ * Accepts: driver to call under slave
+ *	    MAIL stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long safe_delete (DRIVER *dtb,MAILSTREAM *stream,char *mbx)
+{
+  long ret = master (stream,NIL,NIL);
+  if (lockslavep) exit ((*dtb->mbxdel) (stream,mbx));
+  return ret;
+}
+
+
+/* Safely rename mailbox
+ * Accepts: driver to call under slave
+ *	    MAIL stream
+ *	    old mailbox name
+ *	    new mailbox name (or NIL for delete)
+ * Returns: T on success, NIL on failure
+ */
+
+long safe_rename (DRIVER *dtb,MAILSTREAM *stream,char *old,char *newname)
+{
+  long ret = master (stream,NIL,NIL);
+  if (lockslavep) exit ((*dtb->mbxren) (stream,old,newname));
+  return ret;
+}
+
+
+/* Safely get status of mailbox
+ * Accepts: driver to call under slave
+ *	    MAIL stream
+ *	    mailbox name
+ *	    status flags
+ * Returns: T on success, NIL on failure
+ */
+
+long safe_status (DRIVER *dtb,MAILSTREAM *stream,char *mbx,long flags)
+{
+  long ret = master (stream,NIL,NIL);
+  if (lockslavep) exit ((*dtb->status) (stream,mbx,flags));
+  return ret;
+}
+
+
+/* Scan file for contents
+ * Accepts: driver to call under slave
+ *	    file name
+ *	    desired contents
+ *	    length of contents
+ *	    length of file
+ * Returns: NIL if contents not found, T if found
+ */
+
+long safe_scan_contents (DRIVER *dtb,char *name,char *contents,
+			 unsigned long csiz,unsigned long fsiz)
+{
+  long ret = master (NIL,NIL,NIL);
+  if (lockslavep) exit (scan_contents (dtb,name,contents,csiz,fsiz));
+  return ret;
+}
+
+/* Safely copy message to mailbox
+ * Accepts: driver to call under slave
+ *	    MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if success, NIL if failed
+ */
+
+long safe_copy (DRIVER *dtb,MAILSTREAM *stream,char *seq,char *mbx,long flags)
+{
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+  long ret = master (stream,NIL,NIL);
+  if (lockslavep) {
+				/* don't do proxycopy in slave */
+    if (pc) mail_parameters (stream,SET_MAILPROXYCOPY,(void *) slaveproxycopy);
+    exit ((*dtb->copy) (stream,seq,mbx,flags));
+  }
+				/* do any proxycopy in master */
+  if (lockproxycopy && pc) return (*pc) (stream,seq,mbx,flags);
+  return ret;
+}
+
+
+/* Append package for slave */
+
+typedef struct append_data {
+  int first;			/* flag indicating first message */
+  char *flags;			/* message flags */
+  char *date;			/* message date */
+  char *msg;			/* message text */
+  STRING message;		/* message stringstruct */
+} APPENDDATA;
+
+
+/* Safely append message to mailbox
+ * Accepts: driver to call under slave
+ *	    MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long safe_append (DRIVER *dtb,MAILSTREAM *stream,char *mbx,append_t af,
+		  void *data)
+{
+  long ret = master (stream,af,data);
+  if (lockslavep) {
+    APPENDDATA ad;
+    ad.first = T;		/* initialize initial append package */
+    ad.flags = ad.date = ad.msg = NIL;
+    exit ((*dtb->append) (stream,mbx,slave_append,&ad));
+  }
+  return ret;
+}
+
+/* Slave callbacks */
+
+
+/* Message exists (i.e. there are that many messages in the mailbox)
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void slave_exists (MAILSTREAM *stream,unsigned long number)
+{
+  /* this event never passed by slaves */
+}
+
+
+/* Message expunged
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void slave_expunged (MAILSTREAM *stream,unsigned long number)
+{
+  /* this event never passed by slaves */
+}
+
+
+/* Message status changed
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void slave_flags (MAILSTREAM *stream,unsigned long number)
+{
+  /* this event never passed by slaves */
+}
+
+/* Mailbox status
+ * Accepts: MAIL stream
+ *	    mailbox name
+ *	    mailbox status
+ */
+
+void slave_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
+{
+  int i,c;
+  fprintf (slaveout,"S%lx %lu %lu %lu %lu %lu %lu ",
+	  (unsigned long) stream,status->flags,status->messages,status->recent,
+	  status->unseen,status->uidnext,status->uidvalidity,mailbox);
+				/* yow!  are we paranoid enough yet? */
+  for (i = 0; (i < 500) && (c = *mailbox++); ++i) switch (c) {
+  case '\r': case '\n':		/* newline in a mailbox name? */
+    c = ' ';
+  default:
+    putc (c,slaveout);
+  }
+  putc ('\n',slaveout);
+  fflush (slaveout);
+}
+
+/* Notification event
+ * Accepts: MAIL stream
+ *	    string to log
+ *	    error flag
+ */
+
+void slave_notify (MAILSTREAM *stream,char *string,long errflg)
+{
+  int i,c;
+  fprintf (slaveout,"N%lx %lu ",(unsigned long) stream,errflg);
+				/* prevent more than 500 bytes */
+  for (i = 0; (i < 500) && (c = *string++); ++i) switch (c) {
+  case '\r': case '\n':		/* or embedded newline */
+    c = ' ';
+  default:
+    putc (c,slaveout);
+  }
+  putc ('\n',slaveout);
+  fflush (slaveout);
+}
+
+
+/* Log an event for the user to see
+ * Accepts: string to log
+ *	    error flag
+ */
+
+void slave_log (char *string,long errflg)
+{
+  int i,c;
+  fprintf (slaveout,"L%lu ",errflg);
+				/* prevent more than 500 bytes */
+  for (i = 0; (i < 500) && (c = *string++); ++i) switch (c) {
+  case '\r': case '\n':		/* or embedded newline */
+    c = ' ';
+  default:
+    putc (c,slaveout);
+  }
+  putc ('\n',slaveout);
+  fflush (slaveout);
+}
+
+/* About to enter critical code
+ * Accepts: stream
+ */
+
+void slave_critical (MAILSTREAM *stream)
+{
+  fprintf (slaveout,"C%lx\n",(unsigned long) stream);
+  fflush (slaveout);
+}
+
+
+/* About to exit critical code
+ * Accepts: stream
+ */
+
+void slave_nocritical (MAILSTREAM *stream)
+{
+  fprintf (slaveout,"X%lx\n",(unsigned long) stream);
+  fflush (slaveout);
+}
+
+/* Disk error found
+ * Accepts: stream
+ *	    system error code
+ *	    flag indicating that mailbox may be clobbered
+ * Returns: abort flag
+ */
+
+long slave_diskerror (MAILSTREAM *stream,long errcode,long serious)
+{
+  char tmp[MAILTMPLEN];
+  int c;
+  long ret = NIL;
+  fprintf (slaveout,"D%lx %lu %lu\n",(unsigned long) stream,errcode,serious);
+  fflush (slaveout);
+  switch (c = getc (slavein)) {
+  case EOF:			/* pipe broken */
+    slave_fatal ("Pipe broken reading diskerror response");
+  case '+':			/* user wants to abort */
+    ret = LONGT;
+  case '-':			/* no abort */
+    break;
+  default:
+    sprintf (tmp,"Unknown master response for diskerror: %c",c);
+    slave_fatal (tmp);
+  }
+  return ret;
+}
+
+
+/* Log a fatal error event
+ * Accepts: string to log
+ * Does not return
+ */
+
+void slave_fatal (char *string)
+{
+  int i,c;
+  syslog (LOG_ALERT,"IMAP toolkit slave process crash: %.500s",string);
+  putc ('F',slaveout);
+				/* prevent more than 500 bytes */
+  for (i = 0; (i < 500) && (c = *string++); ++i) switch (c) {
+  case '\r': case '\n':		/* newline in a mailbox name? */
+    c = ' ';
+  default:
+    putc (c,slaveout);
+  }
+  putc ('\n',slaveout);
+  fflush (slaveout);
+  abort ();			/* die */
+}
+
+/* Append read buffer
+ * Accepts: number of bytes to read
+ *	    error message if fails
+ * Returns: read-in string
+ */
+
+static char *slave_append_read (unsigned long n,char *error)
+{
+#if 0
+  unsigned long i;
+#endif
+  int c;
+  char *t,tmp[MAILTMPLEN];
+  char *s = (char *) fs_get (n + 1);
+  s[n] = '\0';
+#if 0
+  /* This doesn't work on Solaris with GCC.  I think that it's a C library
+   * bug, since the problem only shows up if the application does fread()
+   * on some other file
+   */
+  for (t = s; n && ((i = fread (t,1,n,slavein)); t += i,n -= i);
+#else
+  for (t = s; n && ((c = getc (slavein)) != EOF); *t++ = c,--n);
+#endif
+  if (n) {
+    sprintf(tmp,"Pipe broken reading %.100s with %lu bytes remaining",error,n);
+    slave_fatal (tmp);
+  }
+  return s;
+}
+
+/* Append message callback
+ * Accepts: MAIL stream
+ *	    append data package
+ *	    pointer to return initial flags
+ *	    pointer to return message internal date
+ *	    pointer to return stringstruct of message or NIL to stop
+ * Returns: T if success (have message or stop), NIL if error
+ */
+
+long slave_append (MAILSTREAM *stream,void *data,char **flags,char **date,
+		   STRING **message)
+{
+  char tmp[MAILTMPLEN];
+  unsigned long n;
+  int c;
+  APPENDDATA *ad = (APPENDDATA *) data;
+				/* flush text of previous message */
+  if (ad->flags) fs_give ((void **) &ad->flags);
+  if (ad->date) fs_give ((void **) &ad->date);
+  if (ad->msg) fs_give ((void **) &ad->msg);
+  *flags = *date = NIL;		/* assume no flags or date */
+  fputs ("A\n",slaveout);	/* tell master we're doing append callback */
+  fflush (slaveout);
+  switch (c = getc (slavein)) {	/* what did master say? */
+  case '+':			/* have message, get size of flags */
+    for (n = 0; isdigit (c = getc (slavein)); n *= 10, n += (c - '0'));
+    if (c != ' ') {
+      if (c == EOF) sprintf (tmp,"Pipe broken after flag size %lu",n);
+      sprintf (tmp,"Missing delimiter after flag size %lu: %c",n,c);
+      slave_fatal (tmp);
+    }
+    if (n) *flags = ad->flags = slave_append_read (n,"flags");
+				/* get size of date */
+    for (n = 0; isdigit (c = getc (slavein)); n *= 10, n += (c - '0'));
+    if (c != ' ') {
+      if (c == EOF) sprintf (tmp,"Pipe broken after date size %lu",n);
+      else sprintf (tmp,"Missing delimiter after date size %lu: %c",n,c);
+      slave_fatal (tmp);
+    }
+    if (n) *date = ad->date = slave_append_read (n,"date");
+				/* get size of message */
+    for (n = 0; isdigit (c = getc (slavein)); n *= 10, n += (c - '0'));
+    if (c != ' ') {
+      if (c == EOF) sprintf (tmp,"Pipe broken after message size %lu",n);
+      sprintf (tmp,"Missing delimiter after message size %lu: %c",n,c);
+      slave_fatal (tmp);
+    }
+    if (n) {			/* make buffer for message */
+      ad->msg = slave_append_read (n,"message");
+				/* initialize stringstruct */
+      INIT (&ad->message,mail_string,(void *) ad->msg,n);
+      ad->first = NIL;		/* no longer first message */
+      *message = &ad->message;	/* return message */
+    }
+    else *message = NIL;	/* empty message */
+    return LONGT;
+  case '-':			/* error */
+    *message = NIL;		/* set stop */
+    break;
+  case EOF:			/* end of file */
+    slave_fatal ("Pipe broken reading append response");
+  default:			/* unknown event */
+    sprintf (tmp,"Unknown master response for append: %c",c);
+    slave_fatal (tmp);
+  }
+  return NIL;			/* return failure */
+}
+
+/* Proxy copy across mailbox formats
+ * Accepts: mail stream
+ *	    sequence to copy on this stream
+ *	    destination mailbox
+ *	    option flags
+ * Returns: T if success, else NIL
+ */
+
+long slaveproxycopy (MAILSTREAM *stream,char *sequence,char *mailbox,
+		     long options)
+{
+  fputs ("&\n",slaveout);	/* redo copy as append */
+  fflush (slaveout);
+  return NIL;			/* failure for now */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/flocksim.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,117 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	flock() emulation via fcntl() locking
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 April 2001
+ * Last Edited:	20 December 2006
+ */
+
+
+#include "dummy.h"		/* get scan_contents() prototype */
+
+#define flock flocksim		/* use ours instead of theirs */
+
+#undef LOCK_SH
+#define LOCK_SH 1		/* shared lock */
+#undef LOCK_EX
+#define LOCK_EX 2		/* exclusive lock */
+#undef LOCK_NB
+#define LOCK_NB 4		/* no blocking */
+#undef LOCK_UN
+#define LOCK_UN 8		/* unlock */
+
+/* Safe locking definitions */
+
+extern int lockslavep;		/* non-zero means slave process */
+
+#undef SAFE_DELETE
+#define SAFE_DELETE(dtb,stream,mbx) (dtb->flags & DR_LOCKING) ? \
+  safe_delete (dtb,stream,mbx) : (*dtb->mbxdel) (stream,mbx)
+#undef SAFE_RENAME
+#define SAFE_RENAME(dtb,stream,old,newname) (dtb->flags & DR_LOCKING) ? \
+  safe_rename (dtb,stream,old,newname) : (*dtb->mbxren) (stream,old,newname)
+#undef SAFE_STATUS
+#define SAFE_STATUS(dtb,stream,mbx,bits) (dtb->flags & DR_LOCKING) ? \
+  safe_status (dtb,stream,mbx,bits) : (*dtb->status) (stream,mbx,bits)
+#undef SAFE_SCAN_CONTENTS
+#define SAFE_SCAN_CONTENTS(dtb,name,contents,csiz,fsiz) \
+  (!dtb || (dtb->flags & DR_LOCKING)) ? \
+   safe_scan_contents (dtb,name,contents,csiz,fsiz) : \
+   scan_contents (dtb,name,contents,csiz,fsiz)
+#undef SAFE_COPY
+#define SAFE_COPY(dtb,stream,seq,mbx,bits) (dtb->flags & DR_LOCKING) ? \
+  safe_copy (dtb,stream,seq,mbx,bits) : (*dtb->copy) (stream,seq,mbx,bits)
+#undef SAFE_APPEND
+#define SAFE_APPEND(dtb,stream,mbx,af,data) (dtb->flags & DR_LOCKING) ? \
+  safe_append (dtb,stream,mbx,af,data) : (*dtb->append) (stream,mbx,af,data)
+
+#undef MM_EXISTS
+#define MM_EXISTS (lockslavep ? slave_exists : mm_exists)
+#undef MM_EXPUNGED
+#define MM_EXPUNGED (lockslavep ? slave_expunged : mm_expunged)
+#undef MM_FLAGS
+#define MM_FLAGS (lockslavep ? slave_flags : mm_flags)
+#undef MM_NOTIFY
+#define MM_NOTIFY (lockslavep ? slave_notify : mm_notify)
+#undef MM_STATUS
+#define MM_STATUS (lockslavep ? slave_status : mm_status)
+#undef MM_LOG
+#define MM_LOG (lockslavep ? slave_log : mm_log)
+#undef MM_CRITICAL
+#define MM_CRITICAL (lockslavep ? slave_critical : mm_critical)
+#undef MM_NOCRITICAL
+#define MM_NOCRITICAL (lockslavep ? slave_nocritical : mm_nocritical)
+#undef MM_DISKERROR
+#define MM_DISKERROR (lockslavep ? slave_diskerror : mm_diskerror)
+#undef MM_FATAL
+#define MM_FATAL (lockslavep ? slave_fatal : mm_fatal)
+#undef MM_APPEND
+#define MM_APPEND(af) (lockslavep ? slave_append : (*af))
+
+/* Function prototypes */
+
+int flocksim (int fd,int operation);
+
+long safe_delete (DRIVER *dtb,MAILSTREAM *stream,char *mbx);
+long safe_rename (DRIVER *dtb,MAILSTREAM *stream,char *old,char *newname);
+long safe_status (DRIVER *dtb,MAILSTREAM *stream,char *mbx,long flags);
+long safe_scan_contents (DRIVER *dtb,char *name,char *contents,
+			 unsigned long csiz,unsigned long fsiz);
+long safe_copy (DRIVER *dtb,MAILSTREAM *stream,char *seq,char *mbx,long flags);
+long safe_append (DRIVER *dtb,MAILSTREAM *stream,char *mbx,append_t af,
+		  void *data);
+
+void slave_exists (MAILSTREAM *stream,unsigned long number);
+void slave_expunged (MAILSTREAM *stream,unsigned long number);
+void slave_flags (MAILSTREAM *stream,unsigned long number);
+void slave_notify (MAILSTREAM *stream,char *string,long errflg);
+void slave_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status);
+void slave_log (char *string,long errflg);
+void slave_critical (MAILSTREAM *stream);
+void slave_nocritical (MAILSTREAM *stream);
+long slave_diskerror (MAILSTREAM *stream,long errcode,long serious);
+void slave_fatal (char *string);
+long slave_append (MAILSTREAM *stream,void *data,char **flags,char **date,
+		   STRING **message);
+long slaveproxycopy (MAILSTREAM *stream,char *sequence,char *mailbox,
+		     long options);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/fs_unix.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,71 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Free storage management routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Get a block of free storage
+ * Accepts: size of desired block
+ * Returns: free storage block
+ */
+
+void *fs_get (size_t size)
+{
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  void *data = (*bn) (BLOCK_SENSITIVE,NIL);
+  void *block = malloc (size ? size : (size_t) 1);
+  if (!block) fatal ("Out of memory");
+  (*bn) (BLOCK_NONSENSITIVE,data);
+  return (block);
+}
+
+
+/* Resize a block of free storage
+ * Accepts: ** pointer to current block
+ *	    new size
+ */
+
+void fs_resize (void **block,size_t size)
+{
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  void *data = (*bn) (BLOCK_SENSITIVE,NIL);
+  if (!(*block = realloc (*block,size ? size : (size_t) 1)))
+    fatal ("Can't resize memory");
+  (*bn) (BLOCK_NONSENSITIVE,data);
+}
+
+
+/* Return a block of free storage
+ * Accepts: ** pointer to free storage block
+ */
+
+void fs_give (void **block)
+{
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  void *data = (*bn) (BLOCK_SENSITIVE,NIL);
+  free (*block);
+  *block = NIL;
+  (*bn) (BLOCK_NONSENSITIVE,data);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/fsync.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,39 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	File sync emulator
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	3 May 1995
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Emulator for BSD fsync() call
+ * Accepts: file name
+ * Returns: 0 if successful, -1 if failure
+ */
+
+int fsync (int fd)
+{
+  sync ();
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ftl_unix.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,39 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX crash management routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Report a fatal error
+ * Accepts: string to output
+ */
+
+void fatal (char *string)
+{
+  MM_FATAL (string);		/* pass up the string */
+  syslog (LOG_ALERT,"IMAP toolkit crash: %.100s",string);
+  abort ();			/* die horribly */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/gethstid.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,38 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Get host ID emulator
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	3 May 1995
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Emulator for BSD gethostid() call
+ * Returns: unique identifier for this machine
+ */
+
+long gethostid (void)
+{
+  /* No gethostid() here, so just fake it and hope things turn out okay. */
+  return 0xdeadface;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/getspnam.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,65 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	64-bit getsockname()/getpeername() emulator
+ *
+ * Author:	Mark Crispin from code contributed by Chris Ross
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	5 November 2004
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Jacket into getpeername()
+ * Accepts: socket
+ *	    pointer to socket address
+ *	    void pointer to len
+ * Returns: 0 if success, -1 if error
+ */
+
+int Getpeername (int s,struct sockaddr *name,size_t *namelen)
+{
+  int ret;
+  socklen_t len = (socklen_t) *namelen;
+  ret = getpeername (s,name,&len);
+  *namelen = (size_t) len;
+  return ret;
+}
+
+
+/* Jacket into getsockname()
+ * Accepts: socket
+ *	    pointer to socket address
+ *	    void pointer to len
+ * Returns: 0 if success, -1 if error
+ */
+
+int Getsockname (int s,struct sockaddr *name,size_t *namelen)
+{
+  int ret;
+  socklen_t len = (socklen_t) *namelen;
+  ret = getsockname (s,name,&len);
+  *namelen = (size_t) len;
+  return ret;
+}
+
+
+#define getpeername Getpeername
+#define getsockname Getsockname
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/gr_wait.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,46 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX Grim PID Reaper -- wait() version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	30 November 1993
+ * Last Edited:	30 August 2006
+ */
+ 
+/* Grim PID reaper
+ * Accepts: process ID
+ *	    kill request flag
+ *	    status return value
+ */
+
+void grim_pid_reap_status (int pid,int killreq,void *status)
+{
+  int r;
+  if (killreq) {
+    kill (pid,SIGHUP);		/* kill if not already dead */
+    alarm (10);			/* in case we get hosed */
+    while (((r = wait (NIL)) != pid) &&
+	   ((r > 0) || ((errno != ECHILD) && (errno != EINTR))));
+    alarm (0);			/* cancel the alarm */
+  }
+  else while (((r = wait (status)) != pid) && ((r > 0) || (errno != ECHILD)));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/gr_wait4.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,39 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX Grim PID Reaper -- wait4() version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	30 November 1993
+ * Last Edited:	30 August 2006
+ */
+ 
+/* Grim PID reaper
+ * Accepts: process ID
+ *	    kill request flag
+ *	    status return value
+ */
+
+void grim_pid_reap_status (int pid,int killreq,void *status)
+{
+  if (killreq) kill(pid,SIGHUP);/* kill if not already dead */
+  while ((wait4 (pid,status,NIL,NIL) < 0) && (errno != ECHILD));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/gr_waitp.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,39 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX Grim PID Reaper -- waitpid() version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	30 November 1993
+ * Last Edited:	30 August 2006
+ */
+ 
+/* Grim PID reaper
+ * Accepts: process ID
+ *	    kill request flag
+ *	    status return value
+ */
+
+void grim_pid_reap_status (int pid,int killreq,void *status)
+{
+  if (killreq) kill(pid,SIGHUP);/* kill if not already dead */
+  while ((waitpid (pid,status,NIL) < 0) && (errno != ECHILD));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ip4_unix.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,184 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX IPv4 routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	18 December 2003
+ * Last Edited:	30 August 2006
+ */
+
+#define SADRLEN sizeof (struct sockaddr)
+
+#define SADR4(sadr) ((struct sockaddr_in *) sadr)
+#define SADR4LEN sizeof (struct sockaddr_in)
+#define SADR4ADR(sadr) SADR4 (sadr)->sin_addr
+#define ADR4LEN sizeof (struct in_addr)
+#define SADR4PORT(sadr) SADR4 (sadr)->sin_port
+
+
+/* IP abstraction layer */
+
+char *ip_sockaddrtostring (struct sockaddr *sadr);
+long ip_sockaddrtoport (struct sockaddr *sadr);
+void *ip_stringtoaddr (char *text,size_t *len,int *family);
+struct sockaddr *ip_newsockaddr (size_t *len);
+struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen,
+			      unsigned short port,size_t *len);
+char *ip_sockaddrtoname (struct sockaddr *sadr);
+void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical,
+		     void **next);
+
+/* Return IP address string from socket address
+ * Accepts: socket address
+ * Returns: IP address as name string
+ */
+
+char *ip_sockaddrtostring (struct sockaddr *sadr)
+{
+  return (sadr->sa_family == PF_INET) ?
+    inet_ntoa (SADR4ADR (sadr)) : "NON-IPv4";
+}
+
+
+/* Return port from socket address
+ * Accepts: socket address
+ * Returns: port number or -1 if can't determine it
+ */
+
+long ip_sockaddrtoport (struct sockaddr *sadr)
+{
+  return (sadr->sa_family == PF_INET) ? ntohs (SADR4PORT (sadr)) : -1;
+}
+
+
+/* Return IP address from string
+ * Accepts: name string
+ *	    pointer to returned length
+ *	    pointer to returned address family
+ * Returns: address if valid, length and family updated, or NIL
+ */
+
+void *ip_stringtoaddr (char *text,size_t *len,int *family)
+{
+  unsigned long adr;
+  struct in_addr *ret;
+				/* get address */
+  if ((adr = inet_addr (text)) == -1) ret = NIL;
+  else {			/* make in_addr */
+    ret = (struct in_addr *) fs_get (*len = ADR4LEN);
+    *family = AF_INET;		/* IPv4 */
+    ret->s_addr = adr;		/* set address */
+  }
+  return (void *) ret;
+}
+
+/* Create a maximum-size socket address
+ * Accepts: pointer to return maximum socket address length
+ * Returns: new, empty socket address of maximum size
+ */
+
+struct sockaddr *ip_newsockaddr (size_t *len)
+{
+  return (struct sockaddr *) memset (fs_get (SADRLEN),0,*len = SADRLEN);
+}
+
+
+/* Stuff a socket address
+ * Accepts: address family
+ *	    IPv4 address
+ *	    length of address (always 4 in IPv4)
+ *	    port number
+ *	    pointer to return socket address length
+ * Returns: socket address or NIL if error
+ */
+
+struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen,
+			      unsigned short port,size_t *len)
+{
+  struct sockaddr *sadr = ip_newsockaddr (len);
+  switch (family) {		/* build socket address based upon family */
+  case AF_INET:			/* IPv4 */
+    sadr->sa_family = PF_INET;
+				/* copy host address */
+    memcpy (&SADR4ADR (sadr),adr,adrlen);
+				/* copy port number in network format */
+    SADR4PORT (sadr) = htons (port);
+    *len = SADR4LEN;
+    break;
+  default:			/* non-IP?? */
+    sadr->sa_family = PF_UNSPEC;
+    break;
+  }
+  return sadr;
+}
+
+/* Return name from socket address
+ * Accepts: socket address
+ * Returns: canonical name for that address or NIL if none
+ */
+
+char *ip_sockaddrtoname (struct sockaddr *sadr)
+{
+  struct hostent *he;
+  return ((sadr->sa_family == PF_INET) &&
+	  (he = gethostbyaddr ((char *) &SADR4ADR (sadr),ADR4LEN,AF_INET))) ?
+    (char *) he->h_name : NIL;
+}
+
+
+/* Return address from name
+ * Accepts: name or NIL to return next address
+ *	    pointer to previous/returned length
+ *	    pointer to previous/returned address family
+ *	    pointer to previous/returned canonical name
+ *	    pointer to previous/return state for next-address calls
+ * Returns: address with length/family/canonical updated if needed, or NIL
+ */
+
+void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical,
+		     void **next)
+{
+  char **adl,tmp[MAILTMPLEN];
+  struct hostent *he;
+  if (name) {			/* first lookup? */
+				/* yes, do case-independent lookup */
+    if ((strlen (name) < MAILTMPLEN) &&
+	(he = gethostbyname (lcase (strcpy (tmp,name))))) {
+      adl = he->h_addr_list;
+      if (len) *len = he->h_length;
+      if (family) *family = he->h_addrtype;
+      if (canonical) *canonical = (char *) he->h_name;
+      if (next) *next = (void *) adl;
+    }
+    else {			/* error */
+      adl = NIL;
+      if (len) *len = 0;
+      if (family) *family = 0;
+      if (canonical) *canonical = NIL;
+      if (next) *next = NIL;
+    }
+  }
+				/* return next in series */
+  else if (next && (adl = (char **) *next)) *next = ++adl;
+  else adl = NIL;		/* failure */
+  return adl ? (void *) *adl : NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ip6_unix.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,288 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX IPv6 routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	18 December 2003
+ * Last Edited:	30 August 2006
+ */
+
+
+/*
+ * There is some amazingly bad design in IPv6 sockets.
+ *
+ * Supposedly, the new getnameinfo() and getaddrinfo() functions create an
+ * abstraction that is not dependent upon IPv4 or IPv6.  However, the
+ * definition of getnameinfo() requires that the caller pass the length of
+ * the sockaddr instead of deriving it from sa_family.  The man page says
+ * that there's an sa_len member in the sockaddr, but actually there isn't.
+ * This means that any caller to getnameinfo() and getaddrinfo() has to know
+ * the size for the protocol family used by that sockaddr.
+ *
+ * The new sockaddr_in6 is bigger than the generic sockaddr (which is what
+ * connect(), accept(), bind(), getpeername(), getsockname(), etc. expect).
+ * Rather than increase the size of sockaddr, there's a new sockaddr_storage
+ * which is only usable for allocating space.
+ */
+
+#define SADRLEN sizeof (struct sockaddr_storage)
+
+#define SADR4(sadr) ((struct sockaddr_in *) sadr)
+#define SADR4LEN sizeof (struct sockaddr_in)
+#define SADR4ADR(sadr) SADR4 (sadr)->sin_addr
+#define ADR4LEN sizeof (struct in_addr)
+#define SADR4PORT(sadr) SADR4 (sadr)->sin_port
+
+#define SADR6(sadr) ((struct sockaddr_in6 *) sadr)
+#define SADR6LEN sizeof (struct sockaddr_in6)
+#define SADR6ADR(sadr) SADR6 (sadr)->sin6_addr
+#define ADR6LEN sizeof (struct in6_addr)
+#define SADR6PORT(sadr) SADR6 (sadr)->sin6_port
+
+
+/* IP abstraction layer */
+
+char *ip_sockaddrtostring (struct sockaddr *sadr);
+long ip_sockaddrtoport (struct sockaddr *sadr);
+void *ip_stringtoaddr (char *text,size_t *len,int *family);
+struct sockaddr *ip_newsockaddr (size_t *len);
+struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen,
+			      unsigned short port,size_t *len);
+char *ip_sockaddrtoname (struct sockaddr *sadr);
+void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical,
+		     void **next);
+
+/* Return IP address string from socket address
+ * Accepts: socket address
+ * Returns: IP address as name string
+ */
+
+char *ip_sockaddrtostring (struct sockaddr *sadr)
+{
+  static char tmp[NI_MAXHOST];
+  switch (sadr->sa_family) {
+  case PF_INET:			/* IPv4 */
+    if (!getnameinfo (sadr,SADR4LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NUMERICHOST))
+      return tmp;
+    break;
+  case PF_INET6:		/* IPv6 */
+    if (!getnameinfo (sadr,SADR6LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NUMERICHOST))
+      return tmp;
+    break;
+  }
+  return "NON-IP";
+}
+
+
+/* Return port from socket address
+ * Accepts: socket address
+ * Returns: port number or -1 if can't determine it
+ */
+
+long ip_sockaddrtoport (struct sockaddr *sadr)
+{
+  switch (sadr->sa_family) {
+  case PF_INET:
+    return ntohs (SADR4PORT (sadr));
+  case PF_INET6:
+    return ntohs (SADR6PORT (sadr));
+  }
+  return -1;
+}
+
+/* Return IP address from string
+ * Accepts: name string
+ *	    pointer to returned length
+ *	    pointer to returned address family
+ * Returns: address if valid, length and family updated, or NIL
+ */
+
+void *ip_stringtoaddr (char *text,size_t *len,int *family)
+
+{
+  char tmp[MAILTMPLEN];
+  static struct addrinfo *hints;
+  struct addrinfo *ai;
+  void *adr = NIL;
+  if (!hints) {			/* hints set up yet? */
+    hints = (struct addrinfo *) /* one-time setup */
+      memset (fs_get (sizeof (struct addrinfo)),0,sizeof (struct addrinfo));
+    hints->ai_family = AF_UNSPEC;/* allow any address family */
+    hints->ai_socktype = SOCK_STREAM;
+				/* numeric name only */
+    hints->ai_flags = AI_NUMERICHOST;
+  }
+				/* case-independent lookup */
+  if (text && (strlen (text) < MAILTMPLEN) &&
+      (!getaddrinfo (lcase (strcpy (tmp,text)),NIL,hints,&ai))) {
+    switch (*family = ai->ai_family) {
+    case AF_INET:		/* IPv4 */
+      adr = fs_get (*len = ADR4LEN);
+      memcpy (adr,(void *) &SADR4ADR (ai->ai_addr),*len);
+      break;
+    case AF_INET6:		/* IPv6 */
+      adr = fs_get (*len = ADR6LEN);
+      memcpy (adr,(void *) &SADR6ADR (ai->ai_addr),*len);
+      break;
+    }
+    freeaddrinfo (ai);		/* free addrinfo */
+  }
+  return adr;
+}
+
+/* Create a maximum-size socket address
+ * Accepts: pointer to return maximum socket address length
+ * Returns: new, empty socket address of maximum size
+ */
+
+struct sockaddr *ip_newsockaddr (size_t *len)
+{
+  return (struct sockaddr *) memset (fs_get (SADRLEN),0,*len = SADRLEN);
+}
+
+
+/* Stuff a socket address
+ * Accepts: address family
+ *	    IPv4 address
+ *	    length of address
+ *	    port number
+ *	    pointer to return socket address length
+ * Returns: socket address
+ */
+
+struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen,
+			      unsigned short port,size_t *len)
+{
+  struct sockaddr *sadr = ip_newsockaddr (len);
+  switch (family) {		/* build socket address based upon family */
+  case AF_INET:			/* IPv4 */
+    sadr->sa_family = PF_INET;
+				/* copy host address */
+    memcpy (&SADR4ADR (sadr),adr,adrlen);
+				/* copy port number in network format */
+    SADR4PORT (sadr) = htons (port);
+    *len = SADR4LEN;
+    break;
+  case AF_INET6:		/* IPv6 */
+    sadr->sa_family = PF_INET6;
+				/* copy host address */
+    memcpy (&SADR6ADR (sadr),adr,adrlen);
+				/* copy port number in network format */
+    SADR6PORT (sadr) = htons (port);
+    *len = SADR6LEN;
+    break;
+  default:			/* non-IP?? */
+    sadr->sa_family = PF_UNSPEC;
+    break;
+  }
+  return sadr;
+}
+
+/* Return name from socket address
+ * Accepts: socket address
+ * Returns: canonical name for that address or NIL if none
+ */
+
+char *ip_sockaddrtoname (struct sockaddr *sadr)
+{
+  static char tmp[NI_MAXHOST];
+  switch (sadr->sa_family) {
+  case PF_INET:			/* IPv4 */
+    if (!getnameinfo (sadr,SADR4LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NAMEREQD))
+      return tmp;
+    break;
+  case PF_INET6:		/* IPv6 */
+    if (!getnameinfo (sadr,SADR6LEN,tmp,NI_MAXHOST,NIL,NIL,NI_NAMEREQD))
+      return tmp;
+    break;
+  }
+  return NIL;
+}
+
+/* Return address from name
+ * Accepts: name or NIL to return next address
+ *	    pointer to previous/returned length
+ *	    pointer to previous/returned address family
+ *	    pointer to previous/returned canonical name
+ *	    pointer to previous/return state for next-address calls
+ * Returns: address with length/family/canonical updated if needed, or NIL
+ */
+
+void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical,
+		     void **next)
+{
+  struct addrinfo *cur = NIL;
+  static struct addrinfo *hints;
+  static struct addrinfo *ai = NIL;
+  static char lcname[MAILTMPLEN];
+  if (!hints) {			/* hints set up yet? */
+    hints = (struct addrinfo *) /* one-time setup */
+      memset (fs_get (sizeof (struct addrinfo)),0,sizeof (struct addrinfo));
+				/* allow any address family */
+    hints->ai_family = AF_UNSPEC;
+    hints->ai_socktype = SOCK_STREAM;
+				/* need canonical name */
+    hints->ai_flags = AI_CANONNAME;
+  }
+  if (name) {			/* name supplied? */
+    if (ai) {
+      freeaddrinfo (ai);	/* free old addrinfo */
+      ai = NIL;
+    }
+				/* case-independent lookup */
+    if ((strlen (name) < MAILTMPLEN) &&
+	(!getaddrinfo (lcase (strcpy (lcname,name)),NIL,hints,&ai))) {
+      cur = ai;			/* current block */
+      if (canonical)		/* set canonical name */
+	*canonical = cur->ai_canonname ? cur->ai_canonname : lcname;
+				/* remember as next block */
+      if (next) *next = (void *) ai;
+    }
+    else {			/* error */
+      cur = NIL;
+      if (len) *len = 0;
+      if (family) *family = 0;
+      if (canonical) *canonical = NIL;
+      if (next) *next = NIL;
+    }
+  }
+				/* return next in series */
+  else if (next && (cur = ((struct addrinfo *) *next)->ai_next)) {
+    *next = cur;		/* set as last address */
+				/* set canonical in case changed */
+    if (canonical && cur->ai_canonname) *canonical = cur->ai_canonname;
+  }
+
+  if (cur) {			/* got data? */
+    if (family) *family = cur->ai_family;
+    switch (cur->ai_family) {
+    case AF_INET:
+      if (len) *len = ADR4LEN;
+      return (void *) &SADR4ADR (cur->ai_addr);
+    case AF_INET6:
+      if (len) *len = ADR6LEN;
+      return (void *) &SADR6ADR (cur->ai_addr);
+    }
+  }
+  if (len) *len = 0;		/* error return */
+  return NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ipo_unix.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,181 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX IPv4 old routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	18 December 2003
+ * Last Edited:	30 August 2006
+ */
+
+#define SADRLEN sizeof (struct sockaddr)
+
+#define SADR4(sadr) ((struct sockaddr_in *) sadr)
+#define SADR4LEN sizeof (struct sockaddr_in)
+#define SADR4ADR(sadr) SADR4 (sadr)->sin_addr
+#define ADR4LEN sizeof (struct in_addr)
+#define SADR4PORT(sadr) SADR4 (sadr)->sin_port
+
+
+/* IP abstraction layer */
+
+char *ip_sockaddrtostring (struct sockaddr *sadr);
+long ip_sockaddrtoport (struct sockaddr *sadr);
+void *ip_stringtoaddr (char *text,size_t *len,int *family);
+struct sockaddr *ip_newsockaddr (size_t *len);
+struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen,
+			      unsigned short port,size_t *len);
+char *ip_sockaddrtoname (struct sockaddr *sadr);
+void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical,
+		     void **next);
+
+/* Return IP address string from socket address
+ * Accepts: socket address
+ * Returns: IP address as name string
+ */
+
+char *ip_sockaddrtostring (struct sockaddr *sadr)
+{
+  return (sadr->sa_family == PF_INET) ?
+    inet_ntoa (SADR4ADR (sadr)) : "NON-IPv4";
+}
+
+
+/* Return port from socket address
+ * Accepts: socket address
+ * Returns: port number or -1 if can't determine it
+ */
+
+long ip_sockaddrtoport (struct sockaddr *sadr)
+{
+  return (sadr->sa_family == PF_INET) ? ntohs (SADR4PORT (sadr)) : -1;
+}
+
+
+/* Return IP address from string
+ * Accepts: name string
+ *	    pointer to returned length
+ *	    pointer to returned address family
+ * Returns: address if valid, length and family updated, or NIL
+ */
+
+void *ip_stringtoaddr (char *text,size_t *len,int *family)
+{
+  unsigned long adr;
+  struct in_addr *ret;
+				/* get address */
+  if ((adr = inet_addr (text)) == -1) ret = NIL;
+  else {			/* make in_addr */
+    ret = (struct in_addr *) fs_get (*len = ADR4LEN);
+    *family = AF_INET;		/* IPv4 */
+    ret->s_addr = adr;		/* set address */
+  }
+  return (void *) ret;
+}
+
+/* Create a maximum-size socket address
+ * Accepts: pointer to return maximum socket address length
+ * Returns: new, empty socket address of maximum size
+ */
+
+struct sockaddr *ip_newsockaddr (size_t *len)
+{
+  return (struct sockaddr *) memset (fs_get (SADRLEN),0,*len = SADRLEN);
+}
+
+
+/* Stuff a socket address
+ * Accepts: address family
+ *	    IPv4 address
+ *	    length of address (always 4 in IPv4)
+ *	    port number
+ *	    pointer to return socket address length
+ * Returns: socket address or NIL if error
+ */
+
+struct sockaddr *ip_sockaddr (int family,void *adr,size_t adrlen,
+			      unsigned short port,size_t *len)
+{
+  struct sockaddr *sadr = ip_newsockaddr (len);
+  switch (family) {		/* build socket address based upon family */
+  case AF_INET:			/* IPv4 */
+    sadr->sa_family = PF_INET;
+				/* copy host address */
+    memcpy (&SADR4ADR (sadr),adr,adrlen);
+				/* copy port number in network format */
+    SADR4PORT (sadr) = htons (port);
+    *len = SADR4LEN;
+    break;
+  default:			/* non-IP?? */
+    sadr->sa_family = PF_UNSPEC;
+    break;
+  }
+  return sadr;
+}
+
+/* Return name from socket address
+ * Accepts: socket address
+ * Returns: canonical name for that address or NIL if none
+ */
+
+char *ip_sockaddrtoname (struct sockaddr *sadr)
+{
+  struct hostent *he;
+  return ((sadr->sa_family == PF_INET) &&
+	  (he = gethostbyaddr ((char *) &SADR4ADR (sadr),ADR4LEN,AF_INET))) ?
+    (char *) he->h_name : NIL;
+}
+
+
+/* Return address from name
+ * Accepts: name or NIL to return next address
+ *	    pointer to previous/returned length
+ *	    pointer to previous/returned address family
+ *	    pointer to previous/returned canonical name
+ *	    pointer to previous/return state for next-address calls
+ * Returns: address with length/family/canonical updated if needed, or NIL
+ */
+
+void *ip_nametoaddr (char *name,size_t *len,int *family,char **canonical,
+		     void **next)
+{
+  char tmp[MAILTMPLEN];
+  struct hostent *he;
+  void *ret = NIL;
+  if (name) {			/* first lookup? */
+				/* yes, do case-independent lookup */
+    if ((strlen (name) < MAILTMPLEN) &&
+	(he = gethostbyname (lcase (strcpy (tmp,name))))) {
+      if (len) *len = he->h_length;
+      if (family) *family = he->h_addrtype;
+      if (canonical) *canonical = (char *) he->h_name;
+      if (next) *next = 0;
+      ret = he->h_addr;		/* set result to this one and only block */
+    }
+    else {			/* error */
+      if (len) *len = 0;
+      if (family) *family = 0;
+      if (canonical) *canonical = NIL;
+      if (next) *next = NIL;
+    }
+  }
+  return ret;			/* return result */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/kerb_mit.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,111 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	MIT Kerberos routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	4 March 2003
+ * Last Edited:	30 August 2006
+ */
+
+#define PROTOTYPE(x) x
+#include <gssapi/gssapi_generic.h>
+#include <gssapi/gssapi_krb5.h>
+
+
+long kerberos_server_valid (void);
+long kerberos_try_kinit (OM_uint32 error);
+char *kerberos_login (char *user,char *authuser,int argc,char *argv[]);
+
+/* Kerberos server valid check
+ * Returns: T if have keytab, NIL otherwise
+ *
+ * Note that this routine will probably return T only if the process is root.
+ * This is alright since the server is probably still root at this point.
+ */
+
+long kerberos_server_valid ()
+{
+  krb5_context ctx;
+  krb5_keytab kt;
+  krb5_kt_cursor csr;
+  long ret = NIL;
+				/* make a context */
+  if (!krb5_init_context (&ctx)) {
+				/* get default keytab */
+    if (!krb5_kt_default (ctx,&kt)) {
+				/* can do server if have good keytab */
+      if (!krb5_kt_start_seq_get (ctx,kt,&csr) &&
+	  !krb5_kt_end_seq_get (ctx,kt,&csr)) ret = LONGT;
+      krb5_kt_close (ctx,kt);	/* finished with keytab */
+    }
+    krb5_free_context (ctx);	/* finished with context */
+  }
+  return ret;
+}
+
+
+/* Kerberos check for missing or expired credentials
+ * Returns: T if should suggest running kinit, NIL otherwise
+ */
+
+long kerberos_try_kinit (OM_uint32 error)
+{
+  switch (error) {
+  case KRB5KRB_AP_ERR_TKT_EXPIRED:
+  case KRB5_FCC_NOFILE:		/* MIT */
+  case KRB5_CC_NOTFOUND:	/* Heimdal */
+    return LONGT;
+  }
+  return NIL;
+}
+
+/* Kerberos server log in
+ * Accepts: authorization ID as user name
+ *	    authentication ID as Kerberos principal
+ *	    argument count
+ *	    argument vector
+ * Returns: logged in user name if logged in, NIL otherwise
+ */
+
+char *kerberos_login (char *user,char *authuser,int argc,char *argv[])
+{
+  krb5_context ctx;
+  krb5_principal prnc;
+  char kuser[NETMAXUSER];
+  char *ret = NIL;
+				/* make a context */
+  if (!krb5_init_context (&ctx)) {
+				/* build principal */
+    if (!krb5_parse_name (ctx,authuser,&prnc)) {
+				/* can get local name for this principal? */
+      if (!krb5_aname_to_localname (ctx,prnc,NETMAXUSER-1,kuser)) {
+				/* yes, local name permitted login as user?  */
+	if (authserver_login (user,kuser,argc,argv) ||
+	    authserver_login (lcase (user),kuser,argc,argv))
+	  ret = myusername ();	/* yes, return user name */
+      }
+      krb5_free_principal (ctx,prnc);
+    }
+    krb5_free_context (ctx);	/* finished with context */
+  }
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/log_bsi.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,55 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	BSI login
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Log in
+ * Accepts: login passwd struct
+ *	    argument count
+ *	    argument vector
+ * Returns: T if success, NIL otherwise
+ */
+
+long loginpw (struct passwd *pw,int argc,char *argv[])
+{
+  long ret = NIL;
+  uid_t euid = geteuid ();
+  login_cap_t *lc = login_getclass (pw->pw_class);
+				/* have class and can become user? */
+  if (lc && !seteuid (pw->pw_uid)) {
+				/* ask for approval */
+    if (auth_approve (lc,pw->pw_name,
+		      (char *) mail_parameters (NIL,GET_SERVICENAME,NIL)) <= 0)
+      seteuid (euid);		/* not approved, restore root euid */
+    else {			/* approved */
+      seteuid (euid);		/* restore former root euid first */
+      setsid ();		/* ensure we are session leader */
+				/* log the guy in */
+      ret = !setusercontext (lc,pw,pw->pw_uid,LOGIN_SETALL&~LOGIN_SETPATH);
+    }
+  }
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/log_cyg.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,46 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Cygwin login
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Log in
+ * Accepts: login passwd struct
+ *	    argument count
+ *	    argument vector
+ * Returns: T if success, NIL otherwise
+ */
+
+long loginpw (struct passwd *pw,int argc,char *argv[])
+{
+  uid_t uid = pw->pw_uid;
+				/* must be same user name as last checkpw() */
+  if (!(cyg_user && !strcmp (pw->pw_name,cyg_user))) return NIL;
+				/* do the ImpersonateLoggedOnUser() */
+  cygwin_set_impersonation_token (cyg_hdl);
+
+  return !(setgid (pw->pw_gid) || initgroups (cyg_user,pw->pw_gid) ||
+	   setuid (uid));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/log_old.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,39 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Standard login for very old UNIX systems
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Log in
+ * Accepts: login passwd struct
+ *	    argument count
+ *	    argument vector
+ * Returns: T if success, NIL otherwise
+ */
+
+long loginpw (struct passwd *pw,int argc,char *argv[])
+{
+  return !(setgid (pw->pw_gid) || setuid (pw->pw_uid));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/log_os4.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,58 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	OSF/1 (Digital UNIX) 4 login
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Log in
+ * Accepts: login passwd struct
+ *	    argument count
+ *	    argument vector
+ * Returns: T if success, NIL otherwise
+ */
+
+long loginpw (struct passwd *pw,int argc,char *argv[])
+{
+  int i;
+  char *s;
+  char *name = cpystr (pw->pw_name);
+  char *host = cpystr (tcp_clienthost ());
+  uid_t uid = pw->pw_uid;
+  long ret = NIL;
+				/* tie off address */
+  if (s = strchr (host,' ')) *s = '\0';
+  if (*host == '[') {		/* convert [a.b.c.d] to a.b.c.d */
+    memmove (host,host+1,i = strlen (host + 2));
+    host[i] = '\0';
+  }
+  if (sia_become_user (checkpw_collect,argc,argv,host,name,NIL,NIL,NIL,NIL,
+		       SIA_BEU_REALLOGIN|SIA_BEU_OKROOTDIR) != SIASUCCESS)
+    setreuid (0,0);		/* make sure have root again */
+				/* probable success, complete login */
+  else ret = (!setreuid (0,0) && !setuid (uid));
+  fs_give ((void **) &name);
+  fs_give ((void **) &host);
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/log_sec.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,44 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	SecureWare login
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Log in
+ * Accepts: login passwd struct
+ *	    argument count
+ *	    argument vector
+ * Returns: T if success, NIL otherwise
+ */
+
+long loginpw (struct passwd *pw,int argc,char *argv[])
+{
+  uid_t uid = pw->pw_uid;
+  char *name = cpystr (pw->pw_name);
+  long ret = !(setluid (uid) || setgid (pw->pw_gid) ||
+	       initgroups (name,pw->pw_gid) || setuid (uid));
+  fs_give ((void **) &name);
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/log_std.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,44 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Standard login
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Log in
+ * Accepts: login passwd struct
+ *	    argument count
+ *	    argument vector
+ * Returns: T if success, NIL otherwise
+ */
+
+long loginpw (struct passwd *pw,int argc,char *argv[])
+{
+  uid_t uid = pw->pw_uid;
+  char *name = cpystr (pw->pw_name);
+  long ret = !(setgid (pw->pw_gid) || initgroups (name,pw->pw_gid) ||
+	       setuid (uid));
+  fs_give ((void **) &name);
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/log_sv4.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,43 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	SVR4 login
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Log in
+ * Accepts: login passwd struct
+ *	    argument count
+ *	    argument vector
+ * Returns: T if success, NIL otherwise
+ */
+
+long loginpw (struct passwd *pw,int argc,char *argv[])
+{
+  uid_t uid = pw->pw_uid;
+  char *name = cpystr (pw->pw_name);
+  long ret = !(setgid (pw->pw_gid) || initgroups (name) || setuid (uid));
+  fs_give ((void **) &name);
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/mbx.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1855 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	MBX mail routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	3 October 1995
+ * Last Edited:	11 October 2007
+ */
+
+
+/*				FILE TIME SEMANTICS
+ *
+ * The atime is the last read time of the file.
+ * The mtime is the last flags update time of the file.
+ * The ctime is the last write time of the file.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "mail.h"
+#include "osdep.h"
+#include <pwd.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "misc.h"
+#include "dummy.h"
+#include "fdstring.h"
+
+
+/* Build parameters */
+
+#define HDRSIZE 2048
+
+
+/* Kludge to make Cygwin happy */
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+/* MBX I/O stream local data */
+	
+typedef struct mbx_local {
+  unsigned int flagcheck: 1;	/* if ping should sweep for flags */
+  unsigned int expok: 1;	/* if expunging OK in ping */
+  unsigned int expunged : 1;	/* if one or more expunged messages */
+  int fd;			/* file descriptor for I/O */
+  int ld;			/* lock file descriptor */
+  int ffuserflag;		/* first free user flag */
+  off_t filesize;		/* file size parsed */
+  time_t filetime;		/* last file time */
+  time_t lastsnarf;		/* last snarf time */
+  unsigned long lastpid;	/* PID of last writer */
+  unsigned char *buf;		/* temporary buffer */
+  unsigned long buflen;		/* current size of temporary buffer */
+  char lock[MAILTMPLEN];	/* buffer to write lock name */
+} MBXLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((MBXLOCAL *) stream->local)
+
+/* Function prototypes */
+
+DRIVER *mbx_valid (char *name);
+int mbx_isvalid (MAILSTREAM **stream,char *name,char *tmp,int *ld,char *lock,
+		 long flags);
+void *mbx_parameters (long function,void *value);
+void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void mbx_list (MAILSTREAM *stream,char *ref,char *pat);
+void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long mbx_create (MAILSTREAM *stream,char *mailbox);
+long mbx_delete (MAILSTREAM *stream,char *mailbox);
+long mbx_rename (MAILSTREAM *stream,char *old,char *newname);
+long mbx_status (MAILSTREAM *stream,char *mbx,long flags);
+MAILSTREAM *mbx_open (MAILSTREAM *stream);
+void mbx_close (MAILSTREAM *stream,long options);
+void mbx_abort (MAILSTREAM *stream);
+void mbx_flags (MAILSTREAM *stream,char *sequence,long flags);
+char *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
+		  long flags);
+long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
+void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
+long mbx_ping (MAILSTREAM *stream);
+void mbx_check (MAILSTREAM *stream);
+long mbx_expunge (MAILSTREAM *stream,char *sequence,long options);
+void mbx_snarf (MAILSTREAM *stream);
+long mbx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long mbx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+char *mbx_file (char *dst,char *name);
+long mbx_parse (MAILSTREAM *stream);
+MESSAGECACHE *mbx_elt (MAILSTREAM *stream,unsigned long msgno,long expok);
+unsigned long mbx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt);
+void mbx_update_header (MAILSTREAM *stream);
+void mbx_update_status (MAILSTREAM *stream,unsigned long msgno,long flags);
+unsigned long mbx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			  unsigned long *size,char **hdr);
+unsigned long mbx_rewrite (MAILSTREAM *stream,unsigned long *reclaimed,
+			   long flags);
+long mbx_flaglock (MAILSTREAM *stream);
+
+/* MBX mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER mbxdriver = {
+  "mbx",			/* driver name */
+  DR_LOCAL|DR_MAIL|DR_CRLF|DR_LOCKING,
+				/* driver flags */
+  (DRIVER *) NIL,		/* next driver */
+  mbx_valid,			/* mailbox is valid for us */
+  mbx_parameters,		/* manipulate parameters */
+  mbx_scan,			/* scan mailboxes */
+  mbx_list,			/* list mailboxes */
+  mbx_lsub,			/* list subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  mbx_create,			/* create mailbox */
+  mbx_delete,			/* delete mailbox */
+  mbx_rename,			/* rename mailbox */
+  mbx_status,			/* status of mailbox */
+  mbx_open,			/* open mailbox */
+  mbx_close,			/* close mailbox */
+  mbx_flags,			/* fetch message "fast" attributes */
+  mbx_flags,			/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  mbx_header,			/* fetch message header */
+  mbx_text,			/* fetch message body */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  mbx_flag,			/* modify flags */
+  mbx_flagmsg,			/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  mbx_ping,			/* ping mailbox to see if still alive */
+  mbx_check,			/* check for new messages */
+  mbx_expunge,			/* expunge deleted messages */
+  mbx_copy,			/* copy messages to another mailbox */
+  mbx_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM mbxproto = {&mbxdriver};
+
+/* MBX mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *mbx_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+  int fd = mbx_isvalid (NIL,name,tmp,NIL,NIL,NIL);
+  if (fd < 0) return NIL;
+  close (fd);			/* don't need the fd now */
+  return &mbxdriver;
+}
+
+
+/* MBX mail test for valid mailbox
+ * Accepts: returned stream with valid mailbox keywords
+ *	    mailbox name
+ *	    scratch buffer
+ *	    returned lock fd
+ *	    returned lock name
+ *	    RW flags or NIL for readonly
+ * Returns: file descriptor if valid, NIL otherwise
+ */
+
+#define MBXISVALIDNOUID 0x1	/* RW, don't do UID action */
+#define MBXISVALIDUID 0x2	/* RW, do UID action */
+
+int mbx_isvalid (MAILSTREAM **stream,char *name,char *tmp,int *ld,char *lock,
+		 long flags)
+{
+  int fd,upd;
+  int ret = -1;
+  unsigned long i;
+  long j,k;
+  off_t pos;
+  char c,*s,*t,hdr[HDRSIZE];
+  struct stat sbuf;
+  time_t tp[2];
+  int error = EINVAL;		/* assume invalid argument */
+  if (ld) *ld = -1;		/* initially no lock */
+  if ((s = mbx_file (tmp,name)) && !stat (s,&sbuf) &&
+      ((fd = open (tmp,(flags ? O_RDWR : O_RDONLY)|O_BINARY,NIL)) >= 0)) {
+    error = -1;			/* bogus format */
+		/* I love cretinous C compilers -- don't you? */
+    if (read (fd,hdr,HDRSIZE) == HDRSIZE)
+      if ((hdr[0] == '*') && (hdr[1] == 'm') && (hdr[2] == 'b') &&
+	  (hdr[3] == 'x') && (hdr[4] == '*') && (hdr[5] == '\015') &&
+	  (hdr[6] == '\012') && isxdigit (hdr[7]) && isxdigit (hdr[8]))
+	if (isxdigit (hdr[9]) && isxdigit (hdr[10]) && isxdigit (hdr[11]) &&
+	    isxdigit (hdr[12]) && isxdigit (hdr[13]) && isxdigit (hdr[14]) &&
+	    isxdigit (c = hdr[15]) && isxdigit (hdr[16]))
+	  if (isxdigit (hdr[17]) && isxdigit (hdr[18]) &&
+	      isxdigit (hdr[19]) && isxdigit (hdr[20]) &&
+	      isxdigit (hdr[21]) && isxdigit (hdr[22]) &&
+	      (hdr[23] == '\015') && (hdr[24] == '\012')) {
+	    ret = fd;		/* mbx format */
+
+	    if (stream) {	/* lock if making mini-stream */
+	      if (flock (fd,LOCK_SH) ||
+		  (flags && ((*ld = lockfd (fd,lock,LOCK_EX)) < 0))) ret = -1;
+				/* reread data now that locked */
+	      else if (lseek (fd,0,L_SET) ||
+		       (read (fd,hdr,HDRSIZE) != HDRSIZE)) ret = -1;
+	      else {
+		*stream = (MAILSTREAM *) memset (fs_get (sizeof (MAILSTREAM)),
+						 0,sizeof (MAILSTREAM));
+		hdr[15] = '\0';	/* tie off UIDVALIDITY */
+		(*stream)->uid_validity = strtoul (hdr+7,NIL,16);
+		hdr[15] = c;	/* now get UIDLAST */
+		(*stream)->uid_last = strtoul (hdr+15,NIL,16);
+				/* parse user flags */
+		for (i = 0, s = hdr + 25;
+		     (i < NUSERFLAGS) && (t = strchr (s,'\015')) && (t - s);
+		     i++, s = t + 2) {
+		  *t = '\0';	/* tie off flag */
+		  if (strlen (s) <= MAXUSERFLAG)
+		    (*stream)->user_flags[i] = cpystr (s);
+		}
+				/* make sure have true UIDLAST */
+		if (flags & MBXISVALIDUID) {
+		  for (upd = NIL,pos = 2048, k = 0; pos < sbuf.st_size;
+		       pos += (j + k)) {
+				/* read header for this message */
+		    lseek (fd,pos,L_SET);
+		    if ((j = read (fd,hdr,64)) >= 0) {
+		      hdr[j] = '\0';
+		      if ((s = strchr (hdr,'\015')) && (s[1] == '\012')) {
+			*s = '\0';
+			k = s + 2 - hdr;
+			if ((s = strchr (hdr,',')) &&
+			    (j = strtol (s+1,&s,10)) && (*s == ';') &&
+			    (s = strchr (s+1,'-'))) {
+				/* get UID if there is any */
+			  i = strtoul (++s,&t,16);
+			  if (!*t && (t == (s + 8)) &&
+			      (i <= (*stream)->uid_last)) {
+			    if (!i) {
+			      lseek (fd,pos + s - hdr,L_SET);
+			      sprintf (hdr,"%08lx",++(*stream)->uid_last);
+			      write (fd,hdr,8);
+			      upd = T;
+			    }
+			    continue;
+			  }
+			}
+		      }
+		      ret = -1;	/* error, give up */
+		      *stream = mail_close (*stream);
+		      pos = sbuf.st_size + 1;
+		      j = k = 0;
+		    }
+		  }
+
+		  if (upd) {	/* need to update hdr with new UIDLAST? */
+		    lseek (fd,15,L_SET);
+		    sprintf (hdr,"%08lx",(*stream)->uid_last);
+		    write (fd,hdr,8);
+		  }
+		}
+	      }
+	    }
+	  }
+    if (ret != fd) close (fd);	/* close the file */
+    else lseek (fd,0,L_SET);	/* else rewind to start */
+				/* \Marked status? */
+    if (sbuf.st_ctime > sbuf.st_atime) {
+      tp[0] = sbuf.st_atime;	/* preserve atime and mtime */
+      tp[1] = sbuf.st_mtime;
+      utime (tmp,tp);		/* set the times */
+    }
+  }
+				/* in case INBOX but not mbx format */
+  else if (((error = errno) == ENOENT) && !compare_cstring (name,"INBOX"))
+    error = -1;
+  if ((ret < 0) && ld && (*ld >= 0)) {
+    unlockfd (*ld,lock);
+    *ld = -1;
+  }
+  errno = error;		/* return as last error */
+  return ret;			/* return what we should */
+}
+
+/* MBX manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *mbx_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case GET_INBOXPATH:
+    if (value) ret = mbx_file ((char *) value,"INBOX");
+    break;
+  case SET_ONETIMEEXPUNGEATPING:
+    if (value) ((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expok = T;
+  case GET_ONETIMEEXPUNGEATPING:
+    if (value) ret = (void *)
+      (((MBXLOCAL *) ((MAILSTREAM *) value)->local)->expok ? VOIDT : NIL);
+    break;
+  }
+  return ret;
+}
+
+
+/* MBX mail scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void mbx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* MBX mail list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mbx_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_list (NIL,ref,pat);
+}
+
+
+/* MBX mail list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mbx_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_lsub (NIL,ref,pat);
+}
+
+/* MBX mail create mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long mbx_create (MAILSTREAM *stream,char *mailbox)
+{
+  char *s,*t,mbx[MAILTMPLEN],tmp[HDRSIZE];
+  long ret = NIL;
+  int i,fd;
+  if (!(s = mbx_file (mbx,mailbox))) {
+    sprintf (mbx,"Can't create %.80s: invalid name",mailbox);
+    MM_LOG (mbx,ERROR);
+  }
+				/* create underlying file */
+  else if (dummy_create_path (stream,s,get_dir_protection (mailbox))) {
+				/* done if made directory */
+    if ((s = strrchr (s,'/')) && !s[1]) return T;
+    if ((fd = open (mbx,O_WRONLY|O_BINARY,NIL)) < 0) {
+      sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno));
+      MM_LOG (tmp,ERROR);
+      unlink (mbx);		/* delete the file */
+    }
+    else {
+      memset (tmp,'\0',HDRSIZE);/* initialize header */
+      sprintf (s = tmp,"*mbx*\015\012%08lx00000000\015\012",
+	       (unsigned long) time (0));
+      for (i = 0; i < NUSERFLAGS; ++i) {
+	t = (stream && stream->user_flags[i]) ? stream->user_flags[i] :
+	  ((t = default_user_flag (i)) ? t : "");
+	sprintf (s += strlen (s),"%s\015\012",t);
+      }
+      if (write (fd,tmp,HDRSIZE) != HDRSIZE) {
+	sprintf (tmp,"Can't initialize mailbox node %.80s: %s",
+		 mbx,strerror (errno));
+	MM_LOG (tmp,ERROR);
+	unlink (mbx);		/* delete the file */
+      }
+      else ret = T;		/* success */
+      close (fd);		/* close file */
+    }
+  }
+				/* set proper protections */
+  return ret ? set_mbx_protections (mailbox,mbx) : NIL;
+}
+
+
+/* MBX mail delete mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long mbx_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return mbx_rename (stream,mailbox,NIL);
+}
+
+/* MBX mail rename mailbox
+ * Accepts: MAIL stream
+ *	    old mailbox name
+ *	    new mailbox name (or NIL for delete)
+ * Returns: T on success, NIL on failure
+ */
+
+long mbx_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  long ret = LONGT;
+  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  int fd,ld;
+  struct stat sbuf;
+  if (!mbx_file (file,old) ||
+      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
+		   ((s = strrchr (tmp,'/')) && !s[1])))) {
+    sprintf (tmp,newname ?
+	     "Can't rename mailbox %.80s to %.80s: invalid name" :
+	     "Can't delete mailbox %.80s: invalid name",
+	     old,newname);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+  else if ((fd = open (file,O_RDWR|O_BINARY,NIL)) < 0) {
+    sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno));
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+				/* get parse/append permission */
+  if ((ld = lockfd (fd,lock,LOCK_EX)) < 0) {
+    MM_LOG ("Unable to lock rename mailbox",ERROR);
+    return NIL;
+  }
+				/* lock out other users */
+  if (flock (fd,LOCK_EX|LOCK_NB)) {
+    close (fd);			/* couldn't lock, give up on it then */
+    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
+    MM_LOG (tmp,ERROR);
+    unlockfd (ld,lock);		/* release exclusive parse/append permission */
+    return NIL;
+  }
+
+  if (newname) {		/* want rename? */
+				/* found superior to destination name? */
+    if (s = strrchr (tmp,'/')) {
+      c = *++s;			/* remember first character of inferior */
+      *s = '\0';		/* tie off to get just superior */
+				/* superior name doesn't exist, create it */
+      if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+	  !dummy_create_path (stream,tmp,get_dir_protection (newname)))
+	ret = NIL;
+      else *s = c;		/* restore full name */
+    }
+				/* rename the file */
+    if (ret && rename (file,tmp)) {
+      sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
+	       strerror (errno));
+      MM_LOG (tmp,ERROR);
+      ret = NIL;		/* set failure */
+    }
+  }
+  else if (unlink (file)) {
+    sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
+    MM_LOG (tmp,ERROR);
+    ret = NIL;			/* set failure */
+  }
+  flock (fd,LOCK_UN);		/* release lock on the file */
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+  close (fd);			/* close the file */
+				/* recreate file if renamed INBOX */
+  if (ret && !compare_cstring (old,"INBOX")) mbx_create (NIL,"INBOX");
+  return ret;			/* return success */
+}
+
+/* MBX Mail status
+ * Accepts: mail stream
+ *	    mailbox name
+ *	    status flags
+ * Returns: T on success, NIL on failure
+ */
+
+long mbx_status (MAILSTREAM *stream,char *mbx,long flags)
+{
+  MAILSTATUS status;
+  unsigned long i;
+  MAILSTREAM *tstream = NIL;
+  MAILSTREAM *systream = NIL;
+				/* make temporary stream (unless this mbx) */
+  if (!stream && !(stream = tstream =
+		   mail_open (NIL,mbx,OP_READONLY|OP_SILENT)))
+    return NIL;
+  status.flags = flags;		/* return status values */
+  status.messages = stream->nmsgs;
+  status.recent = stream->recent;
+  if (flags & SA_UNSEEN)	/* must search to get unseen messages */
+    for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++)
+      if (!mail_elt (stream,i)->seen) status.unseen++;
+  status.uidnext = stream->uid_last + 1;
+  status.uidvalidity = stream->uid_validity;
+				/* calculate post-snarf results */
+  if (!status.recent && stream->inbox &&
+      (systream = mail_open (NIL,sysinbox (),OP_READONLY|OP_SILENT))) {
+    status.messages += systream->nmsgs;
+    status.recent += systream->recent;
+    if (flags & SA_UNSEEN)	/* must search to get unseen messages */
+      for (i = 1; i <= systream->nmsgs; i++)
+	if (!mail_elt (systream,i)->seen) status.unseen++;
+				/* kludge but probably good enough */
+    status.uidnext += systream->nmsgs;
+  }
+  MM_STATUS(stream,mbx,&status);/* pass status to main program */
+  if (tstream) mail_close (tstream);
+  if (systream) mail_close (systream);
+  return T;			/* success */
+}
+
+/* MBX mail open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *mbx_open (MAILSTREAM *stream)
+{
+  int fd,ld;
+  short silent;
+  char tmp[MAILTMPLEN];
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return user_flags (&mbxproto);
+  if (stream->local) fatal ("mbx recycle stream");
+				/* canonicalize the mailbox name */
+  if (!mbx_file (tmp,stream->mailbox)) {
+    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
+    MM_LOG (tmp,ERROR);
+  }
+  if (stream->rdonly ||
+      (fd = open (tmp,O_RDWR|O_BINARY,NIL)) < 0) {
+    if ((fd = open (tmp,O_RDONLY|O_BINARY,NIL)) < 0) {
+      sprintf (tmp,"Can't open mailbox: %s",strerror (errno));
+      MM_LOG (tmp,ERROR);
+      return NIL;
+    }
+    else if (!stream->rdonly) {	/* got it, but readonly */
+      MM_LOG ("Can't get write access to mailbox, access is readonly",WARN);
+      stream->rdonly = T;
+    }
+  }
+
+  stream->local = memset (fs_get (sizeof (MBXLOCAL)),NIL,sizeof (MBXLOCAL));
+  LOCAL->fd = fd;		/* bind the file */
+  LOCAL->ld = -1;		/* no flaglock */
+  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
+  LOCAL->buflen = CHUNKSIZE - 1;
+				/* note if an INBOX or not */
+  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
+  fs_give ((void **) &stream->mailbox);
+  stream->mailbox = cpystr (tmp);
+				/* get parse/append permission */
+  if ((ld = lockfd (LOCAL->fd,tmp,LOCK_EX)) < 0) {
+    MM_LOG ("Unable to lock open mailbox",ERROR);
+    return NIL;
+  }
+  (*bn) (BLOCK_FILELOCK,NIL);
+  flock (LOCAL->fd,LOCK_SH);	/* lock the file */
+  (*bn) (BLOCK_NONE,NIL);
+  unlockfd (ld,tmp);		/* release shared parse permission */
+  LOCAL->filesize = HDRSIZE;	/* initialize parsed file size */
+				/* time not set up yet */
+  LOCAL->lastsnarf = LOCAL->filetime = 0;
+  LOCAL->expok = LOCAL->flagcheck = NIL;
+  stream->sequence++;		/* bump sequence number */
+				/* parse mailbox */
+  stream->nmsgs = stream->recent = 0;
+  silent = stream->silent;	/* defer events */
+  stream->silent = T;
+  if (mbx_ping (stream) && !stream->nmsgs)
+    MM_LOG ("Mailbox is empty",(long) NIL);
+  stream->silent = silent;	/* now notify upper level */
+  mail_exists (stream,stream->nmsgs);
+  mail_recent (stream,stream->recent);
+  if (!LOCAL) return NIL;	/* failure if stream died */
+  stream->perm_seen = stream->perm_deleted = stream->perm_flagged =
+    stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T;
+  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
+  stream->kwd_create = (stream->user_flags[NUSERFLAGS-1] || stream->rdonly) ?
+    NIL : T;			/* can we create new user flags? */
+  return stream;		/* return stream to caller */
+}
+
+/* MBX mail close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void mbx_close (MAILSTREAM *stream,long options)
+{
+  if (stream && LOCAL) {	/* only if a file is open */
+    int silent = stream->silent;
+    stream->silent = T;		/* note this stream is dying */
+				/* do an expunge if requested */
+    if (options & CL_EXPUNGE) mbx_expunge (stream,NIL,NIL);
+    else {			/* otherwise do a checkpoint to purge */
+      LOCAL->expok = T;		/*  possible expunged messages */
+      mbx_ping (stream);
+    }
+    stream->silent = silent;	/* restore previous status */
+    mbx_abort (stream);
+  }
+}
+
+
+/* MBX mail abort stream
+ * Accepts: MAIL stream
+ */
+
+void mbx_abort (MAILSTREAM *stream)
+{
+  if (stream && LOCAL) {	/* only if a file is open */
+    flock (LOCAL->fd,LOCK_UN);	/* unlock local file */
+    close (LOCAL->fd);		/* close the local file */
+				/* free local text buffer */
+    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+
+/* MBX mail fetch flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ * Sniffs at file to see if some other process changed the flags
+ */
+
+void mbx_flags (MAILSTREAM *stream,char *sequence,long flags)
+{
+  MESSAGECACHE *elt;
+  unsigned long i;
+  if (mbx_ping (stream) && 	/* ping mailbox, get new status for messages */
+      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
+       mail_sequence (stream,sequence)))
+    for (i = 1; i <= stream->nmsgs; i++) 
+      if ((elt = mail_elt (stream,i))->sequence && !elt->valid)
+	mbx_elt (stream,i,NIL);
+}
+
+/* MBX mail fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+char *mbx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
+		  long flags)
+{
+  unsigned long i;
+  char *s;
+  *length = 0;			/* default to empty */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+				/* get header position, possibly header */
+  i = mbx_hdrpos (stream,msgno,length,&s);
+  if (!s) {			/* mbx_hdrpos() returned header? */
+    lseek (LOCAL->fd,i,L_SET);	/* no, get to header position */
+				/* is buffer big enough? */
+    if (*length > LOCAL->buflen) {
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get ((LOCAL->buflen = *length) + 1);
+    }
+				/* slurp the data */
+    read (LOCAL->fd,s = LOCAL->buf,*length);
+  }
+  s[*length] = '\0';		/* tie off string */
+  return s;
+}
+
+/* MBX mail fetch message text (body only)
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: T on success, NIL on failure
+ */
+
+long mbx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  FDDATA d;
+  unsigned long i,j;
+  MESSAGECACHE *elt;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+				/* get message status */
+  elt = mbx_elt (stream,msgno,NIL);
+				/* if message not seen */
+  if (!(flags & FT_PEEK) && !elt->seen && mbx_flaglock (stream)) {
+    elt->seen = T;		/* mark message as seen */
+				/* recalculate status */
+    mbx_update_status (stream,msgno,NIL);
+    MM_FLAGS (stream,msgno);
+				/* update flags */
+    mbx_flag (stream,NIL,NIL,NIL);
+  }
+  if (!LOCAL) return NIL;	/* mbx_flaglock() could have aborted */
+				/* find header position */
+  i = mbx_hdrpos (stream,msgno,&j,NIL);
+  d.fd = LOCAL->fd;		/* set up file descriptor */
+  d.pos = i + j;
+  d.chunk = LOCAL->buf;	/* initial buffer chunk */
+  d.chunksize = CHUNKSIZE;
+  INIT (bs,fd_string,&d,elt->rfc822_size - j);
+  return LONGT;			/* success */
+}
+
+/* MBX mail modify flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    flag(s)
+ *	    option flags
+ * Unlocks flag lock
+ */
+
+void mbx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
+{
+  time_t tp[2];
+  struct stat sbuf;
+  unsigned long oldpid = LOCAL->lastpid;
+				/* make sure the update takes */
+  if (!stream->rdonly && LOCAL && (LOCAL->fd >= 0) && (LOCAL->ld >= 0)) {
+    fsync (LOCAL->fd);
+    fstat (LOCAL->fd,&sbuf);	/* get current write time */
+    tp[1] = LOCAL->filetime = sbuf.st_mtime;
+				/* we are the last flag updater */
+    LOCAL->lastpid = (unsigned long) getpid ();
+				/* update header if needed */
+    if (((LOCAL->ffuserflag < NUSERFLAGS) &&
+	 stream->user_flags[LOCAL->ffuserflag]) || (oldpid != LOCAL->lastpid))
+      mbx_update_header (stream);
+    tp[0] = time (0);		/* make sure read comes after all that */
+    utime (stream->mailbox,tp);
+  }
+  if (LOCAL->ld >= 0) {		/* unlock now */
+    unlockfd (LOCAL->ld,LOCAL->lock);
+    LOCAL->ld = -1;
+  }
+}
+
+
+/* MBX mail per-message modify flags
+ * Accepts: MAIL stream
+ *	    message cache element
+ */
+
+void mbx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  if (mbx_flaglock (stream)) mbx_update_status (stream,elt->msgno,NIL);
+}
+
+/* MBX mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream still alive, NIL if not
+ */
+
+long mbx_ping (MAILSTREAM *stream)
+{
+  unsigned long i,pos;
+  long ret = NIL;
+  int ld;
+  char lock[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  struct stat sbuf;
+  if (stream && LOCAL) {	/* only if stream already open */
+    int snarf = stream->inbox && !stream->rdonly;
+    ret = LONGT;		/* assume OK */
+    fstat (LOCAL->fd,&sbuf);	/* get current file poop */
+				/* allow expunge if permitted at ping */
+    if (mail_parameters (NIL,GET_EXPUNGEATPING,NIL)) LOCAL->expok = T;
+				/* if external modification */
+    if (LOCAL->filetime && (LOCAL->filetime < sbuf.st_mtime))
+      LOCAL->flagcheck = T;	/* upgrade to flag checking */
+				/* new mail or flagcheck handling needed? */
+    if (((sbuf.st_size - LOCAL->filesize) || LOCAL->flagcheck ||
+	 !stream->nmsgs || snarf) &&
+	((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) >= 0)) {
+				/* reparse header if not flagchecking */
+      if (!LOCAL->flagcheck) ret = mbx_parse (stream);
+				/* sweep mailbox for changed message status */
+      else if (ret = mbx_parse (stream)) {
+	unsigned long recent = 0;
+	LOCAL->filetime = sbuf.st_mtime;
+	for (i = 1; i <= stream->nmsgs; )
+	  if (elt = mbx_elt (stream,i,LOCAL->expok)) {
+	    if (elt->recent) ++recent;
+	    ++i;
+	  }
+	mail_recent (stream,recent);
+	LOCAL->flagcheck = NIL;	/* got all the updates */
+      }
+				/* always reparse header at least */
+      if (ret && snarf) {	/* snarf new messages if still OK */
+	mbx_snarf (stream);
+				/* parse snarfed messages */
+	ret = mbx_parse (stream);
+      }
+      unlockfd (ld,lock);	/* release shared parse/append permission */
+    }
+    if (ret) {			/* must still be alive */
+      if (!LOCAL->expunged)	/* look for holes if none known yet */
+	for (i = 1, pos = HDRSIZE;
+	     !LOCAL->expunged && (i <= stream->nmsgs);
+	     i++, pos += elt->private.special.text.size + elt->rfc822_size)
+	  if ((elt = mail_elt (stream,i))->private.special.offset != pos)
+	    LOCAL->expunged = T;/* found a hole */
+				/* burp any holes */
+      if (LOCAL->expunged && !stream->rdonly) {
+	if (mbx_rewrite (stream,&i,NIL)) fatal ("expunge on check");
+	if (i) {		/* any space reclaimed? */
+	  LOCAL->expunged = NIL;/* no more pending expunge */
+	  sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",i);
+	  MM_LOG (LOCAL->buf,(long) NIL);
+	}
+      }
+      LOCAL->expok = NIL;	/* no more expok */
+    }
+  }
+  return ret;			/* return result of the parse */
+}
+
+/* MBX mail check mailbox (reparses status too)
+ * Accepts: MAIL stream
+ */
+
+void mbx_check (MAILSTREAM *stream)
+{
+  if (LOCAL) LOCAL->expok = T;	/* mark that a check is desired */
+  if (mbx_ping (stream)) MM_LOG ("Check completed",(long) NIL);
+}
+
+
+/* MBX mail expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T if success, NIL if failure
+ */
+
+long mbx_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  long ret;
+  unsigned long nexp,reclaimed;
+  if (ret = sequence ? ((options & EX_UID) ?
+			mail_uid_sequence (stream,sequence) :
+			mail_sequence (stream,sequence)) : LONGT) {
+    if (!mbx_ping (stream));	/* do nothing if stream dead */
+    else if (stream->rdonly)	/* won't do on readonly files! */
+      MM_LOG ("Expunge ignored on readonly mailbox",WARN);
+				/* if expunged any messages */
+    else if (nexp = mbx_rewrite (stream,&reclaimed,sequence ? -1 : 1)) {
+      sprintf (LOCAL->buf,"Expunged %lu messages",nexp);
+      MM_LOG (LOCAL->buf,(long) NIL);
+    }
+    else if (reclaimed) {	 /* or if any prior expunged space reclaimed */
+      sprintf (LOCAL->buf,"Reclaimed %lu bytes of expunged space",reclaimed);
+      MM_LOG (LOCAL->buf,(long) NIL);
+    }
+    else MM_LOG ("No messages deleted, so no update needed",(long) NIL);
+  }
+  return ret;
+}
+
+/* MBX mail snarf messages from system inbox
+ * Accepts: MAIL stream, already locked
+ */
+
+void mbx_snarf (MAILSTREAM *stream)
+{
+  unsigned long i = 0;
+  unsigned long j,r,hdrlen,txtlen;
+  struct stat sbuf;
+  char *hdr,*txt,tmp[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  MAILSTREAM *sysibx = NIL;
+				/* give up if can't get exclusive permission */
+  if ((time (0) >= (LOCAL->lastsnarf +
+		    (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL))) &&
+      strcmp (sysinbox (),stream->mailbox)) {
+    MM_CRITICAL (stream);	/* go critical */
+				/* sizes match and anything in sysinbox? */
+    if (!stat (sysinbox (),&sbuf) && sbuf.st_size &&
+	!fstat (LOCAL->fd,&sbuf) && (sbuf.st_size == LOCAL->filesize) && 
+	(sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) &&
+	(!sysibx->rdonly) && (r = sysibx->nmsgs)) {
+				/* yes, go to end of file in our mailbox */
+      lseek (LOCAL->fd,sbuf.st_size,L_SET);
+				/* for each message in sysibx mailbox */
+      while (r && (++i <= sysibx->nmsgs)) {
+				/* snarf message from system INBOX */
+	hdr = cpystr (mail_fetchheader_full (sysibx,i,NIL,&hdrlen,NIL));
+	txt = mail_fetchtext_full (sysibx,i,&txtlen,FT_PEEK);
+				/* if have a message */
+	if (j = hdrlen + txtlen) {
+				/* build header line */
+	  mail_date (LOCAL->buf,elt = mail_elt (sysibx,i));
+	  sprintf (LOCAL->buf + strlen (LOCAL->buf),
+		   ",%lu;00000000%04x-00000000\015\012",j,(unsigned)
+		   ((fSEEN * elt->seen) +
+		    (fDELETED * elt->deleted) + (fFLAGGED * elt->flagged) +
+		    (fANSWERED * elt->answered) + (fDRAFT * elt->draft)));
+				/* copy message */
+	  if ((write (LOCAL->fd,LOCAL->buf,strlen (LOCAL->buf)) < 0) ||
+	      (write (LOCAL->fd,hdr,hdrlen) < 0) ||
+	      (write (LOCAL->fd,txt,txtlen) < 0)) r = 0;
+	}
+	fs_give ((void **) &hdr);
+      }
+
+				/* make sure all the updates take */
+      if (fsync (LOCAL->fd)) r = 0;
+      if (r) {			/* delete all the messages we copied */
+	if (r == 1) strcpy (tmp,"1");
+	else sprintf (tmp,"1:%lu",r);
+	mail_setflag (sysibx,tmp,"\\Deleted");
+	mail_expunge (sysibx);	/* now expunge all those messages */
+      }
+      else {
+	sprintf (LOCAL->buf,"Can't copy new mail: %s",strerror (errno));
+	MM_LOG (LOCAL->buf,WARN);
+	ftruncate (LOCAL->fd,sbuf.st_size);
+      }
+      fstat (LOCAL->fd,&sbuf);	/* yes, get current file size */
+      LOCAL->filetime = sbuf.st_mtime;
+    }
+    if (sysibx) mail_close (sysibx);
+    MM_NOCRITICAL (stream);	/* release critical */
+    LOCAL->lastsnarf = time (0);/* note time of last snarf */
+  }
+}
+
+/* MBX mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if success, NIL if failed
+ */
+
+long mbx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  struct stat sbuf;
+  time_t tp[2];
+  MESSAGECACHE *elt;
+  unsigned long i,j,k,m;
+  long ret = LONGT;
+  int fd,ld;
+  char *s,*t,file[MAILTMPLEN],lock[MAILTMPLEN];
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+  copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL);
+  SEARCHSET *source = cu ? mail_newsearchset () : NIL;
+  SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
+  MAILSTREAM *dstream = NIL;
+  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+	mail_sequence (stream,sequence))) return NIL;
+				/* make sure valid mailbox */
+  if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock,
+			 cu ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0)
+    switch (errno) {
+    case ENOENT:		/* no such file? */
+      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
+      return NIL;
+    case EACCES:		/* file protected */
+      sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
+      MM_LOG (LOCAL->buf,ERROR);
+      return NIL;
+    case EINVAL:
+      if (pc) return (*pc) (stream,sequence,mailbox,options);
+      sprintf (LOCAL->buf,"Invalid MBX-format mailbox name: %.80s",mailbox);
+      MM_LOG (LOCAL->buf,ERROR);
+      return NIL;
+    default:
+      if (pc) return (*pc) (stream,sequence,mailbox,options);
+      sprintf (LOCAL->buf,"Not a MBX-format mailbox: %.80s",mailbox);
+      MM_LOG (LOCAL->buf,ERROR);
+      return NIL;
+    }
+  MM_CRITICAL (stream);		/* go critical */
+  fstat (fd,&sbuf);		/* get current file size */
+  lseek (fd,sbuf.st_size,L_SET);/* move to end of file */
+
+				/* for each requested message */
+  for (i = 1; ret && (i <= stream->nmsgs); i++) 
+    if ((elt = mail_elt (stream,i))->sequence) {
+      lseek (LOCAL->fd,elt->private.special.offset +
+	     elt->private.special.text.size,L_SET);
+      mail_date(LOCAL->buf,elt);/* build target header */
+				/* get target keyword mask */
+      for (j = elt->user_flags, k = 0; j; )
+	if (s = stream->user_flags[find_rightmost_bit (&j)])
+	  for (m = 0; (m < NUSERFLAGS) && (t = dstream->user_flags[m]); m++)
+	    if (!compare_cstring (s,t) && (k |= 1 << m)) break;
+      sprintf (LOCAL->buf+strlen(LOCAL->buf),",%lu;%08lx%04x-%08lx\015\012",
+	       elt->rfc822_size,k,(unsigned)
+	       ((fSEEN * elt->seen) + (fDELETED * elt->deleted) +
+		(fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
+		(fDRAFT * elt->draft)),cu ? ++dstream->uid_last : 0);
+				/* write target header */
+      if (ret = (write (fd,LOCAL->buf,strlen (LOCAL->buf)) > 0)) {
+	for (k = elt->rfc822_size; ret && (j = min (k,LOCAL->buflen)); k -= j){
+	  read (LOCAL->fd,LOCAL->buf,j);
+	  ret = write (fd,LOCAL->buf,j) >= 0;
+	}
+	if (cu) {		/* need to pass back new UID? */
+	  mail_append_set (source,mail_uid (stream,i));
+	  mail_append_set (dest,dstream->uid_last);
+	}
+      }
+    }
+
+				/* make sure all the updates take */
+  if (!(ret && (ret = !fsync (fd)))) {
+    sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno));
+    MM_LOG (LOCAL->buf,ERROR);
+    ftruncate (fd,sbuf.st_size);
+  }
+  if (cu && ret) {		/* return sets if doing COPYUID */
+    (*cu) (stream,mailbox,dstream->uid_validity,source,dest);
+    lseek (fd,15,L_SET);	/* update UIDLAST */
+    sprintf (LOCAL->buf,"%08lx",dstream->uid_last);
+    write (fd,LOCAL->buf,8);
+  }
+  else {			/* flush any sets we may have built */
+    mail_free_searchset (&source);
+    mail_free_searchset (&dest);
+  }
+  if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */
+				/* else preserve \Marked status */
+  else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0);
+  tp[1] = sbuf.st_mtime;	/* preserve mtime */
+  utime (file,tp);		/* set the times */
+  close (fd);			/* close the file */
+  MM_NOCRITICAL (stream);	/* release critical */
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+				/* delete all requested messages */
+  if (ret && (options & CP_MOVE) && mbx_flaglock (stream)) {
+    for (i = 1; i <= stream->nmsgs; i++) if (mail_elt (stream,i)->sequence) {
+				/* mark message deleted */
+      mbx_elt (stream,i,NIL)->deleted = T;
+				/* recalculate status */
+      mbx_update_status (stream,i,NIL);
+    }
+				/* update flags */
+    mbx_flag (stream,NIL,NIL,NIL);
+  }
+  if (dstream != stream) mail_close (dstream);
+  return ret;
+}
+
+/* MBX mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long mbx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct stat sbuf;
+  int fd,ld;
+  char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  time_t tp[2];
+  FILE *df;
+  MESSAGECACHE elt;
+  long f;
+  unsigned long i,uf;
+  STRING *message;
+  long ret = NIL;
+  MAILSTREAM *dstream = NIL;
+  appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL);
+  SEARCHSET *dst = au ? mail_newsearchset () : NIL;
+				/* make sure valid mailbox */
+  if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock,
+			 au ? MBXISVALIDUID : MBXISVALIDNOUID)) < 0)
+    switch (errno) {
+    case ENOENT:		/* no such file? */
+      if (compare_cstring (mailbox,"INBOX")) {
+	MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+	return NIL;
+      }
+				/* can create INBOX here */
+      mbx_create (dstream = stream ? stream : user_flags (&mbxproto),"INBOX");
+      if ((fd = mbx_isvalid (&dstream,mailbox,file,&ld,lock,
+			     au ? MBXISVALIDUID : MBXISVALIDNOUID)) >= 0)
+	break;
+    case EACCES:		/* file protected */
+      sprintf (tmp,"Can't access destination: %.80s",mailbox);
+      MM_LOG (tmp,ERROR);
+      return NIL;
+    case EINVAL:
+      sprintf (tmp,"Invalid MBX-format mailbox name: %.80s",mailbox);
+      MM_LOG (tmp,ERROR);
+      return NIL;
+    default:
+      sprintf (tmp,"Not a MBX-format mailbox: %.80s",mailbox);
+      MM_LOG (tmp,ERROR);
+      return NIL;
+    }
+
+				/* get first message */
+  if (!MM_APPEND (af) (dstream,data,&flags,&date,&message)) close (fd);
+  else if (!(df = fdopen (fd,"r+b"))) {
+    MM_LOG ("Unable to reopen append mailbox",ERROR);
+    close (fd);
+  }
+  else {
+    MM_CRITICAL (dstream);	/* go critical */
+    fstat (fd,&sbuf);		/* get current file size */
+    fseek (df,sbuf.st_size,SEEK_SET);
+    errno = 0;
+    for (ret = LONGT; ret && message; ) {
+      if (!SIZE (message)) {	/* guard against zero-length */
+	MM_LOG ("Append of zero-length message",ERROR);
+	ret = NIL;
+	break;
+      }
+      f = mail_parse_flags (dstream,flags,&uf);
+      if (date) {		/* parse date if given */
+	if (!mail_parse_date (&elt,date)) {
+	  sprintf (tmp,"Bad date in append: %.80s",date);
+	  MM_LOG (tmp,ERROR);
+	  ret = NIL;		/* mark failure */
+	  break;
+	}
+	mail_date (tmp,&elt);	/* write preseved date */
+      }
+      else internal_date (tmp);	/* get current date in IMAP format */
+				/* write header */
+      if (fprintf (df,"%s,%lu;%08lx%04lx-%08lx\015\012",tmp,i = SIZE (message),
+		   uf,(unsigned long) f,au ? ++dstream->uid_last : 0) < 0)
+	ret = NIL;
+      else {			/* write message */
+	size_t j;
+	if (!message->cursize) SETPOS (message,GETPOS (message));
+	while (i && (j = fwrite (message->curpos,1,message->cursize,df))) {
+	  i -= j;
+	  SETPOS (message,GETPOS (message) + j);
+	}
+				/* get next message */
+	if (i || !MM_APPEND (af) (dstream,data,&flags,&date,&message))
+	  ret = NIL;
+	else if (au) mail_append_set (dst,dstream->uid_last);
+      }
+    }
+
+				/* if error... */
+    if (!ret || (fflush (df) == EOF)) {
+				/* revert file */
+      ftruncate (fd,sbuf.st_size);
+      close (fd);		/* make sure fclose() doesn't corrupt us */
+      if (errno) {
+	sprintf (tmp,"Message append failed: %s",strerror (errno));
+	MM_LOG (tmp,ERROR);
+      }
+      ret = NIL;
+    }
+    if (au && ret) {		/* return sets if doing APPENDUID */
+      (*au) (mailbox,dstream->uid_validity,dst);
+      fseek (df,15,SEEK_SET);	/* update UIDLAST */
+      fprintf (df,"%08lx",dstream->uid_last);
+    }
+    else mail_free_searchset (&dst);
+				/* set atime to now-1 if successful copy */
+    if (ret) tp[0] = time (0) - 1;
+				/* else preserve \Marked status */
+    else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0);
+    tp[1] = sbuf.st_mtime;	/* preserve mtime */
+    utime (file,tp);		/* set the times */
+    fclose (df);		/* close the file */
+    MM_NOCRITICAL (dstream);	/* release critical */
+  }
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+  if (dstream != stream) mail_close (dstream);
+  return ret;
+}
+
+/* Internal routines */
+
+
+/* MBX mail generate file string
+ * Accepts: temporary buffer to write into
+ *	    mailbox name string
+ * Returns: local file string or NIL if failure
+ */
+
+char *mbx_file (char *dst,char *name)
+{
+  char *s = mailboxfile (dst,name);
+  return (s && !*s) ? mailboxfile (dst,"~/INBOX") : s;
+}
+
+/* MBX mail parse mailbox
+ * Accepts: MAIL stream
+ * Returns: T if parse OK
+ *	    NIL if failure, stream aborted
+ */
+
+long mbx_parse (MAILSTREAM *stream)
+{
+  struct stat sbuf;
+  MESSAGECACHE *elt = NIL;
+  unsigned char c,*s,*t,*x;
+  char tmp[MAILTMPLEN];
+  unsigned long i,j,k,m;
+  off_t curpos = LOCAL->filesize;
+  unsigned long nmsgs = stream->nmsgs;
+  unsigned long recent = stream->recent;
+  unsigned long lastuid = 0;
+  short dirty = NIL;
+  short added = NIL;
+  short silent = stream->silent;
+  short uidwarn = T;
+  fstat (LOCAL->fd,&sbuf);	/* get status */
+  if (sbuf.st_size < curpos) {	/* sanity check */
+    sprintf (tmp,"Mailbox shrank from %lu to %lu!",
+	     (unsigned long) curpos,(unsigned long) sbuf.st_size);
+    MM_LOG (tmp,ERROR);
+    mbx_abort (stream);
+    return NIL;
+  }
+  lseek (LOCAL->fd,0,L_SET);	/* rewind file */
+				/* read internal header */
+  read (LOCAL->fd,LOCAL->buf,HDRSIZE);
+  LOCAL->buf[HDRSIZE] = '\0';	/* tie off header */
+  c = LOCAL->buf[15];		/* save first character of last UID */
+  LOCAL->buf[15] = '\0';
+				/* parse UID validity */
+  stream->uid_validity = strtoul (LOCAL->buf + 7,NIL,16);
+  LOCAL->buf[15] = c;		/* restore first character of last UID */
+				/* parse last UID */
+  i = strtoul (LOCAL->buf + 15,NIL,16);
+  stream->uid_last = stream->rdonly ? max (i,stream->uid_last) : i;
+				/* parse user flags */
+  for (i = 0, s = LOCAL->buf + 25;
+       (i < NUSERFLAGS) && (t = strchr (s,'\015')) && (t - s);
+       i++, s = t + 2) {
+    *t = '\0';			/* tie off flag */
+    if (!stream->user_flags[i] && (strlen (s) <= MAXUSERFLAG))
+      stream->user_flags[i] = cpystr (s);
+  }
+  LOCAL->ffuserflag = (int) i;	/* first free user flag */
+
+				/* get current last flag updater PID */
+  i = (isxdigit (LOCAL->buf[HDRSIZE-10]) && isxdigit (LOCAL->buf[HDRSIZE-9]) &&
+       isxdigit (LOCAL->buf[HDRSIZE-8]) && isxdigit (LOCAL->buf[HDRSIZE-7]) &&
+       isxdigit (LOCAL->buf[HDRSIZE-6]) && isxdigit (LOCAL->buf[HDRSIZE-5]) &&
+       isxdigit (LOCAL->buf[HDRSIZE-4]) && isxdigit (LOCAL->buf[HDRSIZE-3]) &&
+       (LOCAL->buf[HDRSIZE-2] == '\015') && (LOCAL->buf[HDRSIZE-1] == '\012'))?
+    strtoul (LOCAL->buf + HDRSIZE - 8,NIL,16) : 0;
+				/* set flagcheck if lastpid changed */
+  if (LOCAL->lastpid && (LOCAL->lastpid != i)) LOCAL->flagcheck = T;
+  LOCAL->lastpid = i;		/* set as last PID */
+  stream->silent = T;		/* don't pass up exists events yet */
+  while (sbuf.st_size - curpos){/* while there is stuff to parse */
+				/* get to that position in the file */
+    lseek (LOCAL->fd,curpos,L_SET);
+    if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) {
+      sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s",
+	       (unsigned long) curpos,(unsigned long) sbuf.st_size,
+	       i ? strerror (errno) : "no data read");
+      MM_LOG (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+    LOCAL->buf[i] = '\0';	/* tie off buffer just in case */
+    if (!((s = strchr (LOCAL->buf,'\015')) && (s[1] == '\012'))) {
+      sprintf (tmp,"Unable to find CRLF at %lu in %lu bytes, text: %.80s",
+	       (unsigned long) curpos,i,(char *) LOCAL->buf);
+      MM_LOG (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+    *s = '\0';			/* tie off header line */
+    i = (s + 2) - LOCAL->buf;	/* note start of text offset */
+    if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) {
+      sprintf (tmp,"Unable to parse internal header at %lu: %.80s",
+	       (unsigned long) curpos,(char *) LOCAL->buf);
+      MM_LOG (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+    if (!(isxdigit (t[1]) && isxdigit (t[2]) && isxdigit (t[3]) &&
+	  isxdigit (t[4]) && isxdigit (t[5]) && isxdigit (t[6]) &&
+	  isxdigit (t[7]) && isxdigit (t[8]) && isxdigit (t[9]) &&
+	  isxdigit (t[10]) && isxdigit (t[11]) && isxdigit (t[12]))) {
+      sprintf (tmp,"Unable to parse message flags at %lu: %.80s",
+	       (unsigned long) curpos,(char *) LOCAL->buf);
+      MM_LOG (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+    if ((t[13] != '-') || t[22] ||
+	!(isxdigit (t[14]) && isxdigit (t[15]) && isxdigit (t[16]) &&
+	  isxdigit (t[17]) && isxdigit (t[18]) && isxdigit (t[19]) &&
+	  isxdigit (t[20]) && isxdigit (t[21]))) {
+      sprintf (tmp,"Unable to parse message UID at %lu: %.80s",
+	       (unsigned long) curpos,(char *) LOCAL->buf);
+      MM_LOG (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+
+    *s++ = '\0'; *t++ = '\0';	/* break up fields */
+				/* get message size */
+    if (!(j = strtoul (s,(char **) &x,10)) && (!(x && *x))) {
+      sprintf (tmp,"Unable to parse message size at %lu: %.80s,%.80s;%.80s",
+	       (unsigned long) curpos,(char *) LOCAL->buf,(char *) s,
+	       (char *) t);
+      MM_LOG (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+				/* make sure didn't run off end of file */
+    if (((off_t) (curpos + i + j)) > sbuf.st_size) {
+      sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
+	       (unsigned long) curpos,(unsigned long) (curpos + i + j),
+	       (unsigned long) sbuf.st_size);
+      MM_LOG (tmp,ERROR);
+      mbx_abort (stream);
+      return NIL;
+    }
+				/* parse UID */
+    if ((m = strtoul (t+13,NIL,16)) &&
+	((m <= lastuid) || (m > stream->uid_last))) {
+      if (uidwarn) {
+	sprintf (tmp,"Invalid UID %08lx in message %lu, rebuilding UIDs",
+		 m,nmsgs+1);
+	MM_LOG (tmp,WARN);
+	uidwarn = NIL;
+				/* restart UID validity */
+	stream->uid_validity = time (0);
+      }
+      m = 0;			/* lose this UID */
+      dirty = T;		/* mark dirty, set new lastuid */
+      stream->uid_last = lastuid;
+    }
+
+    t[12] = '\0';		/* parse system flags */
+    if ((k = strtoul (t+8,NIL,16)) & fEXPUNGED) {
+      if (m) lastuid = m;	/* expunge message, update last UID seen */
+      else {			/* no UID assigned? */
+	lastuid = ++stream->uid_last;
+	dirty = T;
+      }
+    }
+    else {			/* not expunged, swell the cache */
+      added = T;		/* note that a new message was added */
+      mail_exists (stream,++nmsgs);
+				/* instantiate an elt for this message */
+      (elt = mail_elt (stream,nmsgs))->valid = T;
+				/* parse the date */
+      if (!mail_parse_date (elt,LOCAL->buf)) {
+	sprintf (tmp,"Unable to parse message date at %lu: %.80s",
+		 (unsigned long) curpos,(char *) LOCAL->buf);
+	MM_LOG (tmp,ERROR);
+	mbx_abort (stream);
+	return NIL;
+      }
+				/* note file offset of header */
+      elt->private.special.offset = curpos;
+				/* and internal header size */
+      elt->private.special.text.size = i;
+				/* header size not known yet */
+      elt->private.msg.header.text.size = 0;
+      elt->rfc822_size = j;	/* note message size */
+				/* calculate system flags */
+      if (k & fSEEN) elt->seen = T;
+      if (k & fDELETED) elt->deleted = T;
+      if (k & fFLAGGED) elt->flagged = T;
+      if (k & fANSWERED) elt->answered = T;
+      if (k & fDRAFT) elt->draft = T;
+      t[8] = '\0';		/* get user flags value */
+      elt->user_flags = strtoul (t,NIL,16);
+				/* UID already assigned? */
+      if (!(elt->private.uid = m) || !(k & fOLD)) {
+	elt->recent = T;	/* no, mark as recent */
+	++recent;		/* count up a new recent message */
+	dirty = T;		/* and must rewrite header */
+				/* assign new UID */
+	if (!elt->private.uid) elt->private.uid = ++stream->uid_last;
+	mbx_update_status (stream,elt->msgno,NIL);
+      }
+				/* update last parsed UID */
+      lastuid = elt->private.uid;
+    }
+    curpos += i + j;		/* update position */
+  }
+
+  if (dirty && !stream->rdonly){/* update header */
+    mbx_update_header (stream);
+    fsync (LOCAL->fd);		/* make sure all the UID updates take */
+  }
+				/* update parsed file size and time */
+  LOCAL->filesize = sbuf.st_size;
+  fstat (LOCAL->fd,&sbuf);	/* get status again to ensure time is right */
+  LOCAL->filetime = sbuf.st_mtime;
+  if (added && !stream->rdonly){/* make sure atime updated */
+    time_t tp[2];
+    tp[0] = time (0);
+    tp[1] = LOCAL->filetime;
+    utime (stream->mailbox,tp);
+  }
+  stream->silent = silent;	/* can pass up events now */
+  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
+  mail_recent (stream,recent);	/* and of change in recent messages */
+  return LONGT;			/* return the winnage */
+}
+
+/* MBX get cache element with status updating from file
+ * Accepts: MAIL stream
+ *	    message number
+ *	    expunge OK flag
+ * Returns: cache element
+ */
+
+MESSAGECACHE *mbx_elt (MAILSTREAM *stream,unsigned long msgno,long expok)
+{
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  struct {			/* old flags */
+    unsigned int seen : 1;
+    unsigned int deleted : 1;
+    unsigned int flagged : 1;
+    unsigned int answered : 1;
+    unsigned int draft : 1;
+    unsigned long user_flags;
+  } old;
+  old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged;
+  old.answered = elt->answered; old.draft = elt->draft;
+  old.user_flags = elt->user_flags;
+				/* get new flags */
+  if (mbx_read_flags (stream,elt) && expok) {
+    mail_expunged (stream,elt->msgno);
+    return NIL;			/* return this message was expunged */
+  }
+  if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
+      (old.flagged != elt->flagged) || (old.answered != elt->answered) ||
+      (old.draft != elt->draft) || (old.user_flags != elt->user_flags))
+    MM_FLAGS (stream,msgno);	/* let top level know */
+  return elt;
+}
+
+/* MBX read flags from file
+ * Accepts: MAIL stream
+ *	    cache element
+ * Returns: non-NIL if message expunged
+ */
+
+unsigned long mbx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  unsigned long i;
+  struct stat sbuf;
+  fstat (LOCAL->fd,&sbuf);	/* get status */
+				/* make sure file size is good */
+  if (sbuf.st_size < LOCAL->filesize) {
+    sprintf (LOCAL->buf,"Mailbox shrank from %lu to %lu in flag read!",
+	     (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
+    fatal (LOCAL->buf);
+  }
+				/* set the seek pointer */
+  lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	 elt->private.special.text.size - 24,L_SET);
+				/* read the new flags */
+  if (read (LOCAL->fd,LOCAL->buf,14) < 0) {
+    sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno));
+    fatal (LOCAL->buf);
+  }
+  if ((LOCAL->buf[0] != ';') || (LOCAL->buf[13] != '-')) {
+    LOCAL->buf[14] = '\0';	/* tie off buffer for error message */
+    sprintf (LOCAL->buf+50,"Invalid flags for message %lu (%lu %lu): %s",
+	     elt->msgno,elt->private.special.offset,
+	     elt->private.special.text.size,(char *) LOCAL->buf);
+    fatal (LOCAL->buf+50);
+  }
+  LOCAL->buf[13] = '\0';	/* tie off buffer */
+				/* calculate system flags */
+  i = strtoul (LOCAL->buf+9,NIL,16);
+  elt->seen = i & fSEEN ? T : NIL;
+  elt->deleted = i & fDELETED ? T : NIL;
+  elt->flagged = i & fFLAGGED ? T : NIL;
+  elt->answered = i & fANSWERED ? T : NIL;
+  elt->draft = i & fDRAFT ? T : NIL;
+  LOCAL->expunged |= i & fEXPUNGED ? T : NIL;
+  LOCAL->buf[9] = '\0';		/* tie off flags */
+				/* get user flags value */
+  elt->user_flags = strtoul (LOCAL->buf+1,NIL,16);
+  elt->valid = T;		/* have valid flags now */
+  return i & fEXPUNGED;
+}
+
+/* MBX update header
+ * Accepts: MAIL stream
+ */
+
+#ifndef CYGKLUDGEOFFSET
+#define CYGKLUDGEOFFSET 0
+#endif
+
+void mbx_update_header (MAILSTREAM *stream)
+{
+  int i;
+  char *s = LOCAL->buf;
+  memset (s,'\0',HDRSIZE);	/* initialize header */
+  sprintf (s,"*mbx*\015\012%08lx%08lx\015\012",
+	   stream->uid_validity,stream->uid_last);
+  for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i]; ++i)
+    sprintf (s += strlen (s),"%s\015\012",stream->user_flags[i]);
+  LOCAL->ffuserflag = i;	/* first free user flag */
+				/* can we create more user flags? */
+  stream->kwd_create = (i < NUSERFLAGS) ? T : NIL;
+				/* write reserved lines */
+  while (i++ < NUSERFLAGS) strcat (s,"\015\012");
+  sprintf (LOCAL->buf + HDRSIZE - 10,"%08lx\015\012",LOCAL->lastpid);
+  while (T) {			/* rewind file */
+    lseek (LOCAL->fd,CYGKLUDGEOFFSET,L_SET);
+				/* write new header */
+    if (write (LOCAL->fd,LOCAL->buf + CYGKLUDGEOFFSET,
+	       HDRSIZE - CYGKLUDGEOFFSET) > 0) break;
+    MM_NOTIFY (stream,strerror (errno),WARN);
+    MM_DISKERROR (stream,errno,T);
+  }
+}
+
+/* MBX update status string
+ * Accepts: MAIL stream
+ *	    message number
+ *	    flags
+ */
+
+void mbx_update_status (MAILSTREAM *stream,unsigned long msgno,long flags)
+{
+  struct stat sbuf;
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+				/* readonly */
+  if (stream->rdonly || !elt->valid) mbx_read_flags (stream,elt);
+  else {			/* readwrite */
+    fstat (LOCAL->fd,&sbuf);	/* get status */
+				/* make sure file size is good */
+    if (sbuf.st_size < LOCAL->filesize) {
+      sprintf (LOCAL->buf,"Mailbox shrank from %lu to %lu in flag update!",
+	       (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
+      fatal (LOCAL->buf);
+    }
+				/* set the seek pointer */
+    lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	   elt->private.special.text.size - 24,L_SET);
+				/* read the new flags */
+    if (read (LOCAL->fd,LOCAL->buf,14) < 0) {
+      sprintf (LOCAL->buf,"Unable to read old status: %s",strerror (errno));
+      fatal (LOCAL->buf);
+    }
+    if ((LOCAL->buf[0] != ';') || (LOCAL->buf[13] != '-')) {
+      LOCAL->buf[14] = '\0';	/* tie off buffer for error message */
+      sprintf (LOCAL->buf+50,"Invalid flags for message %lu (%lu %lu): %s",
+	       elt->msgno,elt->private.special.offset,
+	       elt->private.special.text.size,(char *) LOCAL->buf);
+      fatal (LOCAL->buf+50);
+    }
+				/* print new flag string */
+    sprintf (LOCAL->buf,"%08lx%04x-%08lx",elt->user_flags,(unsigned)
+	     (((elt->deleted && flags) ?
+	       fEXPUNGED : (strtoul (LOCAL->buf+9,NIL,16)) & fEXPUNGED) +
+	      (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
+	      (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
+	      (fDRAFT * elt->draft) + fOLD),elt->private.uid);
+    while (T) {			/* get to that place in the file */
+      lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	     elt->private.special.text.size - 23,L_SET);
+				/* write new flags and UID */
+      if (write (LOCAL->fd,LOCAL->buf,21) > 0) break;
+      MM_NOTIFY (stream,strerror (errno),WARN);
+      MM_DISKERROR (stream,errno,T);
+    }
+  }
+}
+
+/* MBX locate header for a message
+ * Accepts: MAIL stream
+ *	    message number
+ *	    pointer to returned header size
+ *	    pointer to possible returned header
+ * Returns: position of header in file
+ */
+
+#define HDRBUFLEN 16384		/* good enough for most headers */
+#define SLOP 4			/* CR LF CR LF */
+
+unsigned long mbx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			  unsigned long *size,char **hdr)
+{
+  unsigned long siz,done;
+  long i;
+  unsigned char *s,*t,*te;
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  unsigned long ret = elt->private.special.offset +
+    elt->private.special.text.size;
+  if (hdr) *hdr = NIL;		/* assume no header returned */
+				/* is header size known? */ 
+  if (*size = elt->private.msg.header.text.size) return ret;
+				/* paranoia check */
+  if (LOCAL->buflen < (HDRBUFLEN + SLOP))
+    fatal ("LOCAL->buf smaller than HDRBUFLEN");
+  lseek (LOCAL->fd,ret,L_SET);	/* get to header position */
+				/* read HDRBUFLEN chunks with 4 byte slop */
+  for (done = siz = 0, s = LOCAL->buf;
+       (i = min ((long) (elt->rfc822_size - done),(long) HDRBUFLEN)) &&
+       (read (LOCAL->fd,s,i) == i);
+       done += i, siz += (t - LOCAL->buf) - SLOP, s = LOCAL->buf + SLOP) {
+    te = (t = s + i) - 12;	/* calculate end of fast scan */
+				/* fast scan for CR */
+    for (s = LOCAL->buf; s < te;)
+      if (((*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') ||
+	   (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') ||
+	   (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015') ||
+	   (*s++ == '\015') || (*s++ == '\015') || (*s++ == '\015')) &&
+	  (*s == '\012') && (*++s == '\015') && (*++s == '\012')) {
+	*size = elt->private.msg.header.text.size = siz + (++s - LOCAL->buf);
+	if (hdr) *hdr = LOCAL->buf;
+	return ret;
+      }
+    for (te = t - 3; (s < te);)	/* final character-at-a-time scan */
+      if ((*s++ == '\015') && (*s == '\012') && (*++s == '\015') &&
+	  (*++s == '\012')) {
+	*size = elt->private.msg.header.text.size = siz + (++s - LOCAL->buf);
+	if (hdr) *hdr = LOCAL->buf;
+	return ret;
+      }
+    if (i <= SLOP) break;	/* end of data */
+				/* slide over last 4 bytes */
+    memmove (LOCAL->buf,t - SLOP,SLOP);
+    hdr = NIL;			/* can't return header this way */
+  }
+				/* not found: header consumes entire message */
+  elt->private.msg.header.text.size = *size = elt->rfc822_size;
+  if (hdr) *hdr = LOCAL->buf;	/* possibly return header too */
+  return ret;
+}
+
+/* MBX mail rewrite mailbox
+ * Accepts: MAIL stream
+ *	    pointer to return reclaimed size
+ *	    flags (0 = no expunge, 1 = expunge deleted, -1 = expunge sequence)
+ * Returns: number of expunged messages
+ */
+
+unsigned long mbx_rewrite (MAILSTREAM *stream,unsigned long *reclaimed,
+			   long flags)
+{
+  time_t tp[2];
+  struct stat sbuf;
+  off_t pos,ppos;
+  int ld;
+  unsigned long i,j,k,m,delta;
+  unsigned long n = *reclaimed = 0;
+  unsigned long recent = 0;
+  char lock[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  /* The cretins who designed flock() created a window of vulnerability in
+   * upgrading locks from shared to exclusive or downgrading from exclusive
+   * to shared.  Rather than maintain the lock at shared status at a minimum,
+   * flock() actually *releases* the former lock.  Obviously they never talked
+   * to any database guys.  Fortunately, we have the parse/append permission
+   * lock.  If we require this lock before going exclusive on the mailbox,
+   * another process can not sneak in and steal the exclusive mailbox lock on
+   * us, because it will block on trying to get parse/append permission first.
+   */
+				/* get parse/append permission */
+  if ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) < 0) {
+    MM_LOG ("Unable to lock mailbox for rewrite",ERROR);
+    return 0;
+  }
+  fstat (LOCAL->fd,&sbuf);	/* get current write time */
+  if (LOCAL->filetime && !LOCAL->flagcheck &&
+      (LOCAL->filetime < sbuf.st_mtime)) LOCAL->flagcheck = T;
+  if (!mbx_parse (stream)) {	/* make sure see any newly-arrived messages */
+    unlockfd (ld,lock);		/* failed?? */
+    return 0;
+  }
+  if (LOCAL->flagcheck) {	/* sweep flags if need flagcheck */
+    LOCAL->filetime = sbuf.st_mtime;
+    for (i = 1; i <= stream->nmsgs; ++i) mbx_elt (stream,i,NIL);
+    LOCAL->flagcheck = NIL;
+  }
+
+				/* get exclusive access */
+  if (!flock (LOCAL->fd,LOCK_EX|LOCK_NB)) {
+    MM_CRITICAL (stream);	/* go critical */
+    for (i = 1,delta = 0,pos = ppos = HDRSIZE; i <= stream->nmsgs; ) {
+				/* note if message not at predicted location */
+      if (m = (elt = mbx_elt (stream,i,NIL))->private.special.offset - ppos) {
+	ppos = elt->private.special.offset;
+	*reclaimed += m;	/* note reclaimed message space */
+	delta += m;		/* and as expunge delta  */
+      }
+				/* number of bytes to smash or preserve */
+      ppos += (k = elt->private.special.text.size + elt->rfc822_size);
+				/* if need to expunge this message*/
+      if (flags && elt->deleted && ((flags > 0) || elt->sequence)) {
+	delta += k;		/* number of bytes to delete */
+	mail_expunged(stream,i);/* notify upper levels */
+	n++;			/* count up one more expunged message */
+      }
+      else {			/* preserved message */
+	i++;			/* count this message */
+	if (elt->recent) ++recent;
+	if (delta) {		/* moved, note first byte to preserve */
+	  j = elt->private.special.offset;
+	  do {			/* read from source position */
+	    m = min (k,LOCAL->buflen);
+	    lseek (LOCAL->fd,j,L_SET);
+	    read (LOCAL->fd,LOCAL->buf,m);
+	    pos = j - delta;	/* write to destination position */
+	    while (T) {
+	      lseek (LOCAL->fd,pos,L_SET);
+	      if (write (LOCAL->fd,LOCAL->buf,m) > 0) break;
+	      MM_NOTIFY (stream,strerror (errno),WARN);
+	      MM_DISKERROR (stream,errno,T);
+	    }
+	    pos += m;		/* new position */
+	    j += m;		/* next chunk, perhaps */
+	  } while (k -= m);	/* until done */
+				/* note the new address of this text */
+	  elt->private.special.offset -= delta;
+	}
+				/* preserved but no deleted messages yet */
+	else pos = elt->private.special.offset + k;
+      }
+    }
+				/* deltaed file size match position? */
+    if (m = (LOCAL->filesize -= delta) - pos) {
+      *reclaimed += m;		/* probably an fEXPUNGED msg */
+      LOCAL->filesize = pos;	/* set correct size */
+    }
+				/* truncate file after last message */
+    ftruncate (LOCAL->fd,LOCAL->filesize);
+    fsync (LOCAL->fd);		/* force disk update */
+    MM_NOCRITICAL (stream);	/* release critical */
+    (*bn) (BLOCK_FILELOCK,NIL);
+    flock (LOCAL->fd,LOCK_SH);	/* allow sharers again */
+    (*bn) (BLOCK_NONE,NIL);
+  }
+
+  else {			/* can't get exclusive */
+    (*bn) (BLOCK_FILELOCK,NIL);
+    flock (LOCAL->fd,LOCK_SH);	/* recover previous shared mailbox lock */
+    (*bn) (BLOCK_NONE,NIL);
+				/* do hide-expunge when shared */
+    if (flags) for (i = 1; i <= stream->nmsgs; ) {
+      if (elt = mbx_elt (stream,i,T)) {
+				/* make the message invisible */
+	if (elt->deleted && ((flags > 0) || elt->sequence)) {
+	  mbx_update_status (stream,elt->msgno,LONGT);
+				/* notify upper levels */
+	  mail_expunged (stream,i);
+	  n++;			/* count up one more expunged message */
+	}
+	else {
+	  i++;			/* preserved message */
+	  if (elt->recent) ++recent;
+	}
+      }
+      else n++;			/* count up one more expunged message */
+    }
+    fsync (LOCAL->fd);		/* force disk update */
+  }
+  fstat (LOCAL->fd,&sbuf);	/* get new write time */
+  tp[1] = LOCAL->filetime = sbuf.st_mtime;
+  tp[0] = time (0);		/* reset atime to now */
+  utime (stream->mailbox,tp);
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+				/* notify upper level of new mailbox size */
+  mail_exists (stream,stream->nmsgs);
+  mail_recent (stream,recent);
+  return n;			/* return number of expunged messages */
+}
+
+/* MBX mail lock for flag updating
+ * Accepts: stream
+ * Returns: T if successful, NIL if failure
+ */
+
+long mbx_flaglock (MAILSTREAM *stream)
+{
+  struct stat sbuf;
+  unsigned long i;
+  int ld;
+  char lock[MAILTMPLEN];
+				/* no-op if readonly or already locked */
+  if (!stream->rdonly && LOCAL && (LOCAL->fd >= 0) && (LOCAL->ld < 0)) {
+				/* lock now */
+    if ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) < 0) return NIL;
+    if (!LOCAL->flagcheck) {	/* don't do this if flagcheck already needed */
+      if (LOCAL->filetime) {	/* know previous time? */
+	fstat (LOCAL->fd,&sbuf);/* get current write time */
+	if (LOCAL->filetime < sbuf.st_mtime) LOCAL->flagcheck = T;
+	LOCAL->filetime = 0;	/* don't do this test for any other messages */
+      }
+      if (!mbx_parse (stream)) {/* parse mailbox */
+	unlockfd (ld,lock);	/* shouldn't happen */
+	return NIL;
+      }
+      if (LOCAL->flagcheck)	/* invalidate cache if flagcheck */
+	for (i = 1; i <= stream->nmsgs; ++i) mail_elt (stream,i)->valid = NIL;
+    }
+    LOCAL->ld = ld;		/* copy to stream for subsequent calls */
+    memcpy (LOCAL->lock,lock,MAILTMPLEN);
+  }
+  return LONGT;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/mh.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1283 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	MH mail routines
+ *
+ * Author(s):	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	23 February 1992
+ * Last Edited:	11 October 2007
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "mail.h"
+#include "osdep.h"
+#include <pwd.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "misc.h"
+#include "dummy.h"
+#include "fdstring.h"
+
+
+/* Build parameters */
+
+#define MHINBOX "#mhinbox"	/* corresponds to namespace in env_unix.c */
+#define MHINBOXDIR "inbox"
+#define MHPROFILE ".mh_profile"
+#define MHCOMMA ','
+#define MHSEQUENCE ".mh_sequence"
+#define MHSEQUENCES ".mh_sequences"
+#define MHPATH "Mail"
+
+
+/* mh_load_message() flags */
+
+#define MLM_HEADER 0x1		/* load message text */
+#define MLM_TEXT 0x2		/* load message text */
+
+/* MH I/O stream local data */
+	
+typedef struct mh_local {
+  char *dir;			/* spool directory name */
+  unsigned char buf[CHUNKSIZE];	/* temporary buffer */
+  unsigned long cachedtexts;	/* total size of all cached texts */
+  time_t scantime;		/* last time directory scanned */
+} MHLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((MHLOCAL *) stream->local)
+
+
+/* Function prototypes */
+
+DRIVER *mh_valid (char *name);
+int mh_isvalid (char *name,char *tmp,long synonly);
+int mh_namevalid (char *name);
+char *mh_path (char *tmp);
+void *mh_parameters (long function,void *value);
+long mh_dirfmttest (char *name);
+void mh_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void mh_list (MAILSTREAM *stream,char *ref,char *pat);
+void mh_lsub (MAILSTREAM *stream,char *ref,char *pat);
+void mh_list_work (MAILSTREAM *stream,char *dir,char *pat,long level);
+long mh_subscribe (MAILSTREAM *stream,char *mailbox);
+long mh_unsubscribe (MAILSTREAM *stream,char *mailbox);
+long mh_create (MAILSTREAM *stream,char *mailbox);
+long mh_delete (MAILSTREAM *stream,char *mailbox);
+long mh_rename (MAILSTREAM *stream,char *old,char *newname);
+MAILSTREAM *mh_open (MAILSTREAM *stream);
+void mh_close (MAILSTREAM *stream,long options);
+void mh_fast (MAILSTREAM *stream,char *sequence,long flags);
+void mh_load_message (MAILSTREAM *stream,unsigned long msgno,long flags);
+char *mh_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
+		 long flags);
+long mh_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+long mh_ping (MAILSTREAM *stream);
+void mh_check (MAILSTREAM *stream);
+long mh_expunge (MAILSTREAM *stream,char *sequence,long options);
+long mh_copy (MAILSTREAM *stream,char *sequence,char *mailbox,
+	      long options);
+long mh_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+int mh_select (struct direct *name);
+int mh_numsort (const void *d1,const void *d2);
+char *mh_file (char *dst,char *name);
+long mh_canonicalize (char *pattern,char *ref,char *pat);
+void mh_setdate (char *file,MESSAGECACHE *elt);
+
+/* MH mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER mhdriver = {
+  "mh",				/* driver name */
+				/* driver flags */
+  DR_MAIL|DR_LOCAL|DR_NOFAST|DR_NAMESPACE|DR_NOSTICKY|DR_DIRFMT,
+  (DRIVER *) NIL,		/* next driver */
+  mh_valid,			/* mailbox is valid for us */
+  mh_parameters,		/* manipulate parameters */
+  mh_scan,			/* scan mailboxes */
+  mh_list,			/* find mailboxes */
+  mh_lsub,			/* find subscribed mailboxes */
+  mh_subscribe,			/* subscribe to mailbox */
+  mh_unsubscribe,		/* unsubscribe from mailbox */
+  mh_create,			/* create mailbox */
+  mh_delete,			/* delete mailbox */
+  mh_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  mh_open,			/* open mailbox */
+  mh_close,			/* close mailbox */
+  mh_fast,			/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  mh_header,			/* fetch message header */
+  mh_text,			/* fetch message body */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  NIL,				/* modify flags */
+  NIL,				/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  mh_ping,			/* ping mailbox to see if still alive */
+  mh_check,			/* check for new messages */
+  mh_expunge,			/* expunge deleted messages */
+  mh_copy,			/* copy messages to another mailbox */
+  mh_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM mhproto = {&mhdriver};
+
+
+static char *mh_profile = NIL;	/* holds MH profile */
+static char *mh_pathname = NIL;	/* holds MH path name */
+static long mh_once = 0;	/* already snarled once */
+static long mh_allow_inbox =NIL;/* allow INBOX as well as MHINBOX */
+
+/* MH mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *mh_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+  return mh_isvalid (name,tmp,T) ? &mhdriver : NIL;
+}
+
+
+/* MH mail test for valid mailbox
+ * Accepts: mailbox name
+ *	    temporary buffer to use
+ *	    syntax only test flag
+ * Returns: T if valid, NIL otherwise
+ */
+
+int mh_isvalid (char *name,char *tmp,long synonly)
+{
+  struct stat sbuf;
+  char *s,*t,altname[MAILTMPLEN];
+  unsigned long i;
+  int ret = NIL;
+  errno = NIL;			/* zap any error condition */
+				/* mh name? */
+  if ((mh_allow_inbox && !compare_cstring (name,"INBOX")) ||
+      !compare_cstring (name,MHINBOX) ||
+      ((name[0] == '#') && ((name[1] == 'm') || (name[1] == 'M')) &&
+       ((name[2] == 'h') || (name[2] == 'H')) && (name[3] == '/') && name[4])){
+    if (mh_path (tmp))		/* validate name if INBOX or not synonly */
+      ret = (synonly && compare_cstring (name,"INBOX")) ?
+	T : ((stat (mh_file (tmp,name),&sbuf) == 0) &&
+	     (sbuf.st_mode & S_IFMT) == S_IFDIR);
+    else if (!mh_once++) {	/* only report error once */
+      sprintf (tmp,"%.900s not found, mh format names disabled",mh_profile);
+      mm_log (tmp,WARN);
+    }
+  }
+				/* see if non-NS name within mh hierarchy */
+  else if ((name[0] != '#') && (s = mh_path (tmp)) && (i = strlen (s)) &&
+	   (t = mailboxfile (tmp,name)) && !strncmp (t,s,i) &&
+	   (tmp[i] == '/') && tmp[i+1]) {
+    sprintf (altname,"#mh%.900s",tmp+i);
+				/* can't do synonly here! */
+    ret = mh_isvalid (altname,tmp,NIL);
+  }
+  else errno = EINVAL;		/* bogus name */
+  return ret;
+}
+
+/* MH mail test for valid mailbox
+ * Accepts: mailbox name
+ * Returns: T if valid, NIL otherwise
+ */
+
+int mh_namevalid (char *name)
+{
+  char *s;
+  if (name[0] == '#' && (name[1] == 'm' || name[1] == 'M') &&
+      (name[2] == 'h' || name[2] == 'H') && name[3] == '/')
+    for (s = name; s && *s;) {	/* make sure no all-digit nodes */
+      if (isdigit (*s)) s++;	/* digit, check this node further... */
+      else if (*s == '/') break;/* all digit node, barf */
+				/* non-digit, skip to next node or return */
+      else if (!((s = strchr (s+1,'/')) && *++s)) return T;
+    }
+  return NIL;			/* all numeric or empty node */
+}
+
+/* Return MH path
+ * Accepts: temporary buffer
+ * Returns: MH path or NIL if MH disabled
+ */
+
+char *mh_path (char *tmp)
+{
+  char *s,*t,*v,*r;
+  int fd;
+  struct stat sbuf;
+  if (!mh_profile) {		/* build mh_profile and mh_pathname now */
+    sprintf (tmp,"%s/%s",myhomedir (),MHPROFILE);
+    if ((fd = open (mh_profile = cpystr (tmp),O_RDONLY,NIL)) >= 0) {
+      fstat (fd,&sbuf);		/* yes, get size and read file */
+      read (fd,(t = (char *) fs_get (sbuf.st_size + 1)),sbuf.st_size);
+      close (fd);		/* don't need the file any more */
+      t[sbuf.st_size] = '\0';	/* tie it off */
+				/* parse profile file */
+      for (s = strtok_r (t,"\r\n",&r); s && *s; s = strtok_r (NIL,"\r\n",&r)) {
+				/* found space in line? */
+	if (v = strpbrk (s," \t")) {
+	  *v++ = '\0';		/* tie off, is keyword "Path:"? */
+	  if (!compare_cstring (s,"Path:")) {
+				/* skip whitespace */
+	    while ((*v == ' ') || (*v == '\t')) ++v;
+				/* absolute path? */
+	    if (*v == '/') s = v;
+	    else sprintf (s = tmp,"%s/%s",myhomedir (),v);
+				/* copy name */
+	    mh_pathname = cpystr (s);
+	    break;		/* don't need to look at rest of file */
+	  }
+	}
+      }
+      fs_give ((void **) &t);	/* flush profile text */
+      if (!mh_pathname) {	/* default path if not in the profile */
+	sprintf (tmp,"%s/%s",myhomedir (),MHPATH);
+	mh_pathname = cpystr (tmp);
+      }
+    }
+  }
+  return mh_pathname;
+}
+
+/* MH manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *mh_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case GET_INBOXPATH:
+    if (value) ret = mh_file ((char *) value,"INBOX");
+    break;
+  case GET_DIRFMTTEST:
+    ret = (void *) mh_dirfmttest;
+    break;
+  case SET_MHPROFILE:
+    if (mh_profile) fs_give ((void **) &mh_profile);
+    mh_profile = cpystr ((char *) value);
+  case GET_MHPROFILE:
+    ret = (void *) mh_profile;
+    break;
+  case SET_MHPATH:
+    if (mh_pathname) fs_give ((void **) &mh_pathname);
+    mh_pathname = cpystr ((char *) value);
+  case GET_MHPATH:
+    ret = (void *) mh_pathname;
+    break;
+  case SET_MHALLOWINBOX:
+    mh_allow_inbox = value ? T : NIL;
+  case GET_MHALLOWINBOX:
+    ret = (void *) (mh_allow_inbox ? VOIDT : NIL);
+  }
+  return ret;
+}
+
+
+/* MH test for directory format internal node
+ * Accepts: candidate node name
+ * Returns: T if internal name, NIL otherwise
+ */
+
+long mh_dirfmttest (char *s)
+{
+  int c;
+				/* sequence(s) file is an internal name */
+  if (strcmp (s,MHSEQUENCE) && strcmp (s,MHSEQUENCES)) {
+    if (*s == MHCOMMA) ++s;	/* else comma + all numeric name */
+				/* success if all-numeric */
+    while (c = *s++) if (!isdigit (c)) return NIL;
+  }
+  return LONGT;
+}
+
+/* MH scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void mh_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  char *s,test[MAILTMPLEN],file[MAILTMPLEN];
+  long i = 0;
+  if (!pat || !*pat) {		/* empty pattern? */
+    if (mh_canonicalize (test,ref,"*")) {
+				/* tie off name at root */
+      if (s = strchr (test,'/')) *++s = '\0';
+      else test[0] = '\0';
+      mm_list (stream,'/',test,LATT_NOSELECT);
+    }
+  }
+				/* get canonical form of name */
+  else if (mh_canonicalize (test,ref,pat)) {
+    if (contents) {		/* maybe I'll implement this someday */
+      mm_log ("Scan not valid for mh mailboxes",ERROR);
+      return;
+    }
+    if (test[3] == '/') {	/* looking down levels? */
+				/* yes, found any wildcards? */
+      if (s = strpbrk (test,"%*")) {
+				/* yes, copy name up to that point */
+	strncpy (file,test+4,i = s - (test+4));
+	file[i] = '\0';		/* tie off */
+      }
+      else strcpy (file,test+4);/* use just that name then */
+				/* find directory name */
+      if (s = strrchr (file,'/')) {
+	*s = '\0';		/* found, tie off at that point */
+	s = file;
+      }
+				/* do the work */
+      mh_list_work (stream,s,test,0);
+    }
+				/* always an INBOX */
+    if (!compare_cstring (test,MHINBOX))
+      mm_list (stream,NIL,MHINBOX,LATT_NOINFERIORS);
+  }
+}
+
+/* MH list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mh_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  mh_scan (stream,ref,pat,NIL);
+}
+
+
+/* MH list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mh_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  void *sdb = NIL;
+  char *s,test[MAILTMPLEN];
+				/* get canonical form of name */
+  if (mh_canonicalize (test,ref,pat) && (s = sm_read (&sdb))) {
+    do if (pmatch_full (s,test,'/')) mm_lsub (stream,'/',s,NIL);
+    while (s = sm_read (&sdb)); /* until no more subscriptions */
+  }
+}
+
+/* MH list mailboxes worker routine
+ * Accepts: mail stream
+ *	    directory name to search
+ *	    search pattern
+ *	    search level
+ */
+
+void mh_list_work (MAILSTREAM *stream,char *dir,char *pat,long level)
+{
+  DIR *dp;
+  struct direct *d;
+  struct stat sbuf;
+  char *cp,*np,curdir[MAILTMPLEN],name[MAILTMPLEN];
+				/* build MH name to search */
+  if (dir) sprintf (name,"#mh/%s/",dir);
+  else strcpy (name,"#mh/");
+				/* make directory name, punt if bogus */
+  if (!mh_file (curdir,name)) return;
+  cp = curdir + strlen (curdir);/* end of directory name */
+  np = name + strlen (name);	/* end of MH name */
+  if (dp = opendir (curdir)) {	/* open directory */
+    while (d = readdir (dp))	/* scan, ignore . and numeric names */
+      if ((d->d_name[0] != '.') && !mh_select (d)) {
+	strcpy (cp,d->d_name);	/* make directory name */
+	if (!stat (curdir,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) {
+	  strcpy (np,d->d_name);/* make mh name of directory name */
+				/* yes, an MH name if full match */
+	  if (pmatch_full (name,pat,'/')) mm_list (stream,'/',name,NIL);
+				/* check if should recurse */
+	  if (dmatch (name,pat,'/') &&
+	      (level < (long) mail_parameters (NIL,GET_LISTMAXLEVEL,NIL)))
+	    mh_list_work (stream,name+4,pat,level+1);
+	}
+      }
+    closedir (dp);		/* all done, flush directory */
+  }
+}
+
+/* MH mail subscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to add to subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long mh_subscribe (MAILSTREAM *stream,char *mailbox)
+{
+  return sm_subscribe (mailbox);
+}
+
+
+/* MH mail unsubscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to delete from subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long mh_unsubscribe (MAILSTREAM *stream,char *mailbox)
+{
+  return sm_unsubscribe (mailbox);
+}
+
+/* MH mail create mailbox
+ * Accepts: mail stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long mh_create (MAILSTREAM *stream,char *mailbox)
+{
+  char tmp[MAILTMPLEN];
+  if (!mh_namevalid (mailbox))	/* validate name */
+    sprintf (tmp,"Can't create mailbox %.80s: invalid MH-format name",mailbox);
+				/* must not already exist */
+  else if (mh_isvalid (mailbox,tmp,NIL))
+    sprintf (tmp,"Can't create mailbox %.80s: mailbox already exists",mailbox);
+  else if (!mh_path (tmp)) return NIL;
+				/* try to make it */
+  else if (!(mh_file (tmp,mailbox) &&
+	     dummy_create_path (stream,strcat (tmp,"/"),
+				get_dir_protection (mailbox))))
+    sprintf (tmp,"Can't create mailbox %.80s: %s",mailbox,strerror (errno));
+  else return LONGT;		/* success */
+  mm_log (tmp,ERROR);
+  return NIL;
+}
+
+/* MH mail delete mailbox
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long mh_delete (MAILSTREAM *stream,char *mailbox)
+{
+  DIR *dirp;
+  struct direct *d;
+  int i;
+  char tmp[MAILTMPLEN];
+				/* is mailbox valid? */
+  if (!mh_isvalid (mailbox,tmp,NIL)) {
+    sprintf (tmp,"Can't delete mailbox %.80s: no such mailbox",mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* get name of directory */
+  i = strlen (mh_file (tmp,mailbox));
+  if (dirp = opendir (tmp)) {	/* open directory */
+    tmp[i++] = '/';		/* now apply trailing delimiter */
+				/* massacre all mh owned files */
+    while (d = readdir (dirp)) if (mh_dirfmttest (d->d_name)) {
+      strcpy (tmp + i,d->d_name);
+      unlink (tmp);		/* sayonara */
+    }
+    closedir (dirp);		/* flush directory */
+  }
+				/* try to remove the directory */
+  if (rmdir (mh_file (tmp,mailbox))) {
+    sprintf (tmp,"Can't delete mailbox %.80s: %s",mailbox,strerror (errno));
+    mm_log (tmp,WARN);
+  }
+  return T;			/* return success */
+}
+
+/* MH mail rename mailbox
+ * Accepts: MH mail stream
+ *	    old mailbox name
+ *	    new mailbox name
+ * Returns: T on success, NIL on failure
+ */
+
+long mh_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  char c,*s,tmp[MAILTMPLEN],tmp1[MAILTMPLEN];
+  struct stat sbuf;
+				/* old mailbox name must be valid */
+  if (!mh_isvalid (old,tmp,NIL))
+    sprintf (tmp,"Can't rename mailbox %.80s: no such mailbox",old);
+  else if (!mh_namevalid (newname))
+    sprintf (tmp,"Can't rename to mailbox %.80s: invalid MH-format name",
+	     newname);
+				/* new mailbox name must not be valid */
+  else if (mh_isvalid (newname,tmp,NIL))
+    sprintf (tmp,"Can't rename to mailbox %.80s: destination already exists",
+	     newname);
+				/* success if can rename the directory */
+  else {			/* found superior to destination name? */
+    if (s = strrchr (mh_file (tmp1,newname),'/')) {
+      c = *++s;			/* remember first character of inferior */
+      *s = '\0';		/* tie off to get just superior */
+				/* name doesn't exist, create it */
+      if ((stat (tmp1,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+	  !dummy_create_path (stream,tmp1,get_dir_protection (newname)))
+	return NIL;
+      *s = c;			/* restore full name */
+    }
+    if (!rename (mh_file (tmp,old),tmp1)) return T;
+    sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",
+	     old,newname,strerror (errno));
+  }
+  mm_log (tmp,ERROR);		/* something failed */
+  return NIL;
+}
+
+/* MH mail open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *mh_open (MAILSTREAM *stream)
+{
+  char tmp[MAILTMPLEN];
+  if (!stream) return &mhproto;	/* return prototype for OP_PROTOTYPE call */
+  if (stream->local) fatal ("mh recycle stream");
+  stream->local = fs_get (sizeof (MHLOCAL));
+  /* INBOXness is one of the following:
+   * #mhinbox (case-independent)
+   * #mh/inbox (mh is case-independent, inbox is case-dependent)
+   * INBOX (case-independent
+   */		
+  stream->inbox =		/* note if an INBOX or not */
+    (!compare_cstring (stream->mailbox,MHINBOX) ||
+     ((stream->mailbox[0] == '#') &&
+      ((stream->mailbox[1] == 'm') || (stream->mailbox[1] == 'M')) &&
+      ((stream->mailbox[2] == 'h') || (stream->mailbox[2] == 'H')) &&
+      (stream->mailbox[3] == '/') && !strcmp (stream->mailbox+4,MHINBOXDIR)) ||
+     !compare_cstring (stream->mailbox,"INBOX")) ? T : NIL;
+  mh_file (tmp,stream->mailbox);/* get directory name */
+  LOCAL->dir = cpystr (tmp);	/* copy directory name for later */
+  LOCAL->scantime = 0;		/* not scanned yet */
+  LOCAL->cachedtexts = 0;	/* no cached texts */
+  stream->sequence++;		/* bump sequence number */
+				/* parse mailbox */
+  stream->nmsgs = stream->recent = 0;
+  if (!mh_ping (stream)) return NIL;
+  if (!(stream->nmsgs || stream->silent))
+    mm_log ("Mailbox is empty",(long) NIL);
+  return stream;		/* return stream to caller */
+}
+
+/* MH mail close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void mh_close (MAILSTREAM *stream,long options)
+{
+  if (LOCAL) {			/* only if a file is open */
+    int silent = stream->silent;
+    stream->silent = T;		/* note this stream is dying */
+    if (options & CL_EXPUNGE) mh_expunge (stream,NIL,NIL);
+    if (LOCAL->dir) fs_give ((void **) &LOCAL->dir);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+    stream->silent = silent;	/* reset silent state */
+  }
+}
+
+
+/* MH mail fetch fast information
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ */
+
+void mh_fast (MAILSTREAM *stream,char *sequence,long flags)
+{
+  MESSAGECACHE *elt;
+  unsigned long i;
+				/* set up metadata for all messages */
+  if (stream && LOCAL && ((flags & FT_UID) ?
+			  mail_uid_sequence (stream,sequence) :
+			  mail_sequence (stream,sequence)))
+    for (i = 1; i <= stream->nmsgs; i++)
+      if ((elt = mail_elt (stream,i))->sequence &&
+	  !(elt->day && elt->rfc822_size)) mh_load_message (stream,i,NIL);
+}
+
+/* MH load message into cache
+ * Accepts: MAIL stream
+ *	    message #
+ *	    option flags
+ */
+
+void mh_load_message (MAILSTREAM *stream,unsigned long msgno,long flags)
+{
+  unsigned long i,j,nlseen;
+  int fd;
+  unsigned char c,*t;
+  struct stat sbuf;
+  MESSAGECACHE *elt;
+  FDDATA d;
+  STRING bs;
+  elt = mail_elt (stream,msgno);/* get elt */
+				/* build message file name */
+  sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid);
+				/* anything we need not currently cached? */
+  if ((!elt->day || !elt->rfc822_size ||
+       ((flags & MLM_HEADER) && !elt->private.msg.header.text.data) ||
+       ((flags & MLM_TEXT) && !elt->private.msg.text.text.data)) &&
+      ((fd = open (LOCAL->buf,O_RDONLY,NIL)) >= 0)) {
+    fstat (fd,&sbuf);		/* get file metadata */
+    d.fd = fd;			/* set up file descriptor */
+    d.pos = 0;			/* start of file */
+    d.chunk = LOCAL->buf;
+    d.chunksize = CHUNKSIZE;
+    INIT (&bs,fd_string,&d,sbuf.st_size);
+    if (!elt->day) {		/* set internaldate to file date */
+      struct tm *tm = gmtime (&sbuf.st_mtime);
+      elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1;
+      elt->year = tm->tm_year + 1900 - BASEYEAR;
+      elt->hours = tm->tm_hour; elt->minutes = tm->tm_min;
+      elt->seconds = tm->tm_sec;
+      elt->zhours = 0; elt->zminutes = 0;
+    }
+
+    if (!elt->rfc822_size) {	/* know message size yet? */
+      for (i = 0, j = SIZE (&bs), nlseen = 0; j--; ) switch (SNX (&bs)) {
+      case '\015':		/* unlikely carriage return */
+	if (!j || (CHR (&bs) != '\012')) {
+	  i++;			/* ugh, raw CR */
+	  nlseen = NIL;
+	  break;
+	}
+	SNX (&bs);		/* eat the line feed, drop in */
+	--j;
+      case '\012':		/* line feed? */
+	i += 2;			/* count a CRLF */
+				/* header size known yet? */
+	if (!elt->private.msg.header.text.size && nlseen) {
+				/* note position in file */
+	  elt->private.special.text.size = GETPOS (&bs);
+				/* and CRLF-adjusted size */
+	  elt->private.msg.header.text.size = i;
+	}
+	nlseen = T;		/* note newline seen */
+	break;
+      default:			/* ordinary chararacter */
+	i++;
+	nlseen = NIL;
+	break;
+      }
+      SETPOS (&bs,0);		/* restore old position */
+      elt->rfc822_size = i;	/* note that we have size now */
+				/* header is entire message if no delimiter */
+      if (!elt->private.msg.header.text.size)
+	elt->private.msg.header.text.size = elt->rfc822_size;
+				/* text is remainder of message */
+      elt->private.msg.text.text.size =
+	elt->rfc822_size - elt->private.msg.header.text.size;
+    }
+				/* need to load cache with message data? */
+    if (((flags & MLM_HEADER) && !elt->private.msg.header.text.data) ||
+	((flags & MLM_TEXT) && !elt->private.msg.text.text.data)) {
+				/* purge cache if too big */
+      if (LOCAL->cachedtexts > max (stream->nmsgs * 4096,2097152)) {
+				/* just can't keep that much */
+	mail_gc (stream,GC_TEXTS);
+	LOCAL->cachedtexts = 0;
+      }
+
+      if ((flags & MLM_HEADER) && !elt->private.msg.header.text.data) {
+	t = elt->private.msg.header.text.data =
+	  (unsigned char *) fs_get (elt->private.msg.header.text.size + 1);
+	LOCAL->cachedtexts += elt->private.msg.header.text.size;
+				/* read in message header */
+	for (i = 0; i < elt->private.msg.header.text.size; i++)
+	  switch (c = SNX (&bs)) {
+	  case '\015':		/* unlikely carriage return */
+	    *t++ = c;
+	    if ((CHR (&bs) == '\012')) {
+	      *t++ = SNX (&bs);
+	      i++;
+	    }
+	    break;
+	  case '\012':		/* line feed? */
+	    *t++ = '\015';
+	    i++;
+	  default:
+	    *t++ = c;
+	    break;
+	  }
+	*t = '\0';		/* tie off string */
+	if ((t - elt->private.msg.header.text.data) !=
+	    elt->private.msg.header.text.size) fatal ("mh hdr size mismatch");
+      }
+      if ((flags & MLM_TEXT) && !elt->private.msg.text.text.data) {
+	t = elt->private.msg.text.text.data =
+	  (unsigned char *) fs_get (elt->private.msg.text.text.size + 1);
+	SETPOS (&bs,elt->private.special.text.size);
+	LOCAL->cachedtexts += elt->private.msg.text.text.size;
+				/* read in message text */
+	for (i = 0; i < elt->private.msg.text.text.size; i++)
+	  switch (c = SNX (&bs)) {
+	  case '\015':		/* unlikely carriage return */
+	    *t++ = c;
+	    if ((CHR (&bs) == '\012')) {
+	      *t++ = SNX (&bs);
+	      i++;
+	    }
+	    break;
+	  case '\012':		/* line feed? */
+	    *t++ = '\015';
+	    i++;
+	  default:
+	    *t++ = c;
+	    break;
+	  }
+	*t = '\0';		/* tie off string */
+	if ((t - elt->private.msg.text.text.data) !=
+	    elt->private.msg.text.text.size) fatal ("mh txt size mismatch");
+      }
+    }
+    close (fd);			/* flush message file */
+  }
+}
+
+/* MH mail fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+char *mh_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
+		 long flags)
+{
+  MESSAGECACHE *elt;
+  *length = 0;			/* default to empty */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+  elt = mail_elt (stream,msgno);/* get elt */
+  if (!elt->private.msg.header.text.data)
+    mh_load_message (stream,msgno,MLM_HEADER);
+  *length = elt->private.msg.header.text.size;
+  return (char *) elt->private.msg.header.text.data;
+}
+
+
+/* MH mail fetch message text (body only)
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned stringstruct
+ *	    option flags
+ * Returns: T on success, NIL on failure
+ */
+
+long mh_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  MESSAGECACHE *elt;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+  elt = mail_elt (stream,msgno);/* get elt */
+				/* snarf message if don't have it yet */
+  if (!elt->private.msg.text.text.data) {
+    mh_load_message (stream,msgno,MLM_TEXT);
+    if (!elt->private.msg.text.text.data) return NIL;
+  }
+  if (!(flags & FT_PEEK)) {	/* mark as seen */
+    mail_elt (stream,msgno)->seen = T;
+    mm_flags (stream,msgno);
+  }
+  INIT (bs,mail_string,elt->private.msg.text.text.data,
+	elt->private.msg.text.text.size);
+  return T;
+}
+
+/* MH mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ */
+
+long mh_ping (MAILSTREAM *stream)
+{
+  MAILSTREAM *sysibx = NIL;
+  MESSAGECACHE *elt,*selt;
+  struct stat sbuf;
+  char *s,tmp[MAILTMPLEN];
+  int fd;
+  unsigned long i,j,r;
+  unsigned long old = stream->uid_last;
+  long nmsgs = stream->nmsgs;
+  long recent = stream->recent;
+  int silent = stream->silent;
+  if (stat (LOCAL->dir,&sbuf)) {/* directory exists? */
+    if (stream->inbox &&	/* no, create if INBOX */
+	dummy_create_path (stream,strcat (mh_file (tmp,MHINBOX),"/"),
+			   get_dir_protection ("INBOX"))) return T;
+    sprintf (tmp,"Can't open mailbox %.80s: no such mailbox",stream->mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+  stream->silent = T;		/* don't pass up mm_exists() events yet */
+  if (sbuf.st_ctime != LOCAL->scantime) {
+    struct direct **names = NIL;
+    long nfiles = scandir (LOCAL->dir,&names,mh_select,mh_numsort);
+    if (nfiles < 0) nfiles = 0;	/* in case error */
+				/* note scanned now */
+    LOCAL->scantime = sbuf.st_ctime;
+				/* scan directory */
+    for (i = 0; i < nfiles; ++i) {
+				/* if newly seen, add to list */
+      if ((j = atoi (names[i]->d_name)) > old) {
+	mail_exists (stream,++nmsgs);
+	stream->uid_last = (elt = mail_elt (stream,nmsgs))->private.uid = j;
+	elt->valid = T;		/* note valid flags */
+	if (old) {		/* other than the first pass? */
+	  elt->recent = T;	/* yup, mark as recent */
+	  recent++;		/* bump recent count */
+	}
+	else {			/* see if already read */
+	  sprintf (tmp,"%s/%s",LOCAL->dir,names[i]->d_name);
+	  if (!stat (tmp,&sbuf) && (sbuf.st_atime > sbuf.st_mtime))
+	    elt->seen = T;
+	}
+      }
+      fs_give ((void **) &names[i]);
+    }
+				/* free directory */
+    if (s = (void *) names) fs_give ((void **) &s);
+  }
+
+				/* if INBOX, snarf from system INBOX  */
+  if (stream->inbox && strcmp (sysinbox (),stream->mailbox)) {
+    old = stream->uid_last;
+    mm_critical (stream);	/* go critical */
+				/* see if anything in system inbox */
+    if (!stat (sysinbox (),&sbuf) && sbuf.st_size &&
+	(sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) &&
+	!sysibx->rdonly && (r = sysibx->nmsgs)) {
+      for (i = 1; i <= r; ++i) {/* for each message in sysinbox mailbox */
+				/* build file name we will use */
+	sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,++old);
+				/* snarf message from Berkeley mailbox */
+	selt = mail_elt (sysibx,i);
+	if (((fd = open (LOCAL->buf,O_WRONLY|O_CREAT|O_EXCL,
+			 (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL)))
+	     >= 0) &&
+	    (s = mail_fetchheader_full (sysibx,i,NIL,&j,FT_INTERNAL)) &&
+	    (write (fd,s,j) == j) &&
+	    (s = mail_fetchtext_full (sysibx,i,&j,FT_INTERNAL|FT_PEEK)) &&
+	    (write (fd,s,j) == j) && !fsync (fd) && !close (fd)) {
+				/* swell the cache */
+	  mail_exists (stream,++nmsgs);
+	  stream->uid_last =	/* create new elt, note its file number */
+	    (elt = mail_elt (stream,nmsgs))->private.uid = old;
+	  recent++;		/* bump recent count */
+				/* set up initial flags and date */
+	  elt->valid = elt->recent = T;
+	  elt->seen = selt->seen;
+	  elt->deleted = selt->deleted;
+	  elt->flagged = selt->flagged;
+	  elt->answered = selt->answered;
+	  elt->draft = selt->draft;
+	  elt->day = selt->day;elt->month = selt->month;elt->year = selt->year;
+	  elt->hours = selt->hours;elt->minutes = selt->minutes;
+	  elt->seconds = selt->seconds;
+	  elt->zhours = selt->zhours; elt->zminutes = selt->zminutes;
+	  elt->zoccident = selt->zoccident;
+	  mh_setdate (LOCAL->buf,elt);
+	  sprintf (tmp,"%lu",i);/* delete it from the sysinbox */
+	  mail_flag (sysibx,tmp,"\\Deleted",ST_SET);
+	}
+
+	else {			/* failed to snarf */
+	  if (fd) {		/* did it ever get opened? */
+	    close (fd);		/* close descriptor */
+	    unlink (LOCAL->buf);/* flush this file */
+	  }
+	  sprintf (tmp,"Message copy to MH mailbox failed: %.80s",
+		   s,strerror (errno));
+	  mm_log (tmp,ERROR);
+	  r = 0;		/* stop the snarf in its tracks */
+	}
+      }
+				/* update scan time */
+      if (!stat (LOCAL->dir,&sbuf)) LOCAL->scantime = sbuf.st_ctime;      
+      mail_expunge (sysibx);	/* now expunge all those messages */
+    }
+    if (sysibx) mail_close (sysibx);
+    mm_nocritical (stream);	/* release critical */
+  }
+  stream->silent = silent;	/* can pass up events now */
+  mail_exists (stream,nmsgs);	/* notify upper level of mailbox size */
+  mail_recent (stream,recent);
+  return T;			/* return that we are alive */
+}
+
+/* MH mail check mailbox
+ * Accepts: MAIL stream
+ */
+
+void mh_check (MAILSTREAM *stream)
+{
+  /* Perhaps in the future this will preserve flags */
+  if (mh_ping (stream)) mm_log ("Check completed",(long) NIL);
+}
+
+
+/* MH mail expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long mh_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  long ret;
+  MESSAGECACHE *elt;
+  unsigned long i = 1;
+  unsigned long n = 0;
+  unsigned long recent = stream->recent;
+  if (ret = sequence ? ((options & EX_UID) ?
+			mail_uid_sequence (stream,sequence) :
+			mail_sequence (stream,sequence)) : LONGT) {
+    mm_critical (stream);	/* go critical */
+    while (i <= stream->nmsgs) {/* for each message */
+      elt = mail_elt (stream,i);/* if deleted, need to trash it */
+      if (elt->deleted && (sequence ? elt->sequence : T)) {
+	sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid);
+	if (unlink (LOCAL->buf)) {/* try to delete the message */
+	  sprintf (LOCAL->buf,"Expunge of message %lu failed, aborted: %s",i,
+		   strerror (errno));
+	  mm_log (LOCAL->buf,(long) NIL);
+	  break;
+	}
+				/* note uncached */
+	LOCAL->cachedtexts -= ((elt->private.msg.header.text.data ?
+				elt->private.msg.header.text.size : 0) +
+			       (elt->private.msg.text.text.data ?
+				elt->private.msg.text.text.size : 0));
+	mail_gc_msg (&elt->private.msg,GC_ENV | GC_TEXTS);
+				/* if recent, note one less recent message */
+	if (elt->recent) --recent;
+				/* notify upper levels */
+	mail_expunged (stream,i);
+	n++;			/* count up one more expunged message */
+      }
+      else i++;			/* otherwise try next message */
+    }
+    if (n) {			/* output the news if any expunged */
+      sprintf (LOCAL->buf,"Expunged %lu messages",n);
+      mm_log (LOCAL->buf,(long) NIL);
+    }
+    else mm_log ("No messages deleted, so no update needed",(long) NIL);
+    mm_nocritical (stream);	/* release critical */
+				/* notify upper level of new mailbox size */
+    mail_exists (stream,stream->nmsgs);
+    mail_recent (stream,recent);
+  }
+  return ret;
+}
+
+/* MH mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if copy successful, else NIL
+ */
+
+long mh_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  FDDATA d;
+  STRING st;
+  MESSAGECACHE *elt;
+  struct stat sbuf;
+  int fd;
+  unsigned long i;
+  char flags[MAILTMPLEN],date[MAILTMPLEN];
+  appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL);
+  long ret = NIL;
+				/* copy the messages */
+  if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+      mail_sequence (stream,sequence))
+    for (i = 1; i <= stream->nmsgs; i++) 
+      if ((elt = mail_elt (stream,i))->sequence) {
+	sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid);
+	if ((fd = open (LOCAL->buf,O_RDONLY,NIL)) < 0) return NIL;
+	fstat (fd,&sbuf);	/* get size of message */
+	if (!elt->day) {	/* set internaldate to file date if needed */
+	  struct tm *tm = gmtime (&sbuf.st_mtime);
+	  elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1;
+	  elt->year = tm->tm_year + 1900 - BASEYEAR;
+	  elt->hours = tm->tm_hour; elt->minutes = tm->tm_min;
+	  elt->seconds = tm->tm_sec;
+	  elt->zhours = 0; elt->zminutes = 0;
+	}
+	d.fd = fd;		/* set up file descriptor */
+	d.pos = 0;		/* start of file */
+	d.chunk = LOCAL->buf;
+	d.chunksize = CHUNKSIZE;
+				/* kludge; mh_append would just strip CRs */
+	INIT (&st,fd_string,&d,sbuf.st_size);
+				/* init flag string */
+	flags[0] = flags[1] = '\0';
+	if (elt->seen) strcat (flags," \\Seen");
+	if (elt->deleted) strcat (flags," \\Deleted");
+	if (elt->flagged) strcat (flags," \\Flagged");
+	if (elt->answered) strcat (flags," \\Answered");
+	if (elt->draft) strcat (flags," \\Draft");
+	flags[0] = '(';		/* open list */
+	strcat (flags,")");	/* close list */
+	mail_date (date,elt);	/* generate internal date */
+	if (au) mail_parameters (NIL,SET_APPENDUID,NIL);
+	if ((ret = mail_append_full (NIL,mailbox,flags,date,&st)) &&
+	    (options & CP_MOVE)) elt->deleted = T;
+	if (au) mail_parameters (NIL,SET_APPENDUID,(void *) au);
+	close (fd);
+      }
+  if (ret && mail_parameters (NIL,GET_COPYUID,NIL))
+    mm_log ("Can not return meaningful COPYUID with this mailbox format",WARN);
+  return ret;			/* return success */
+}
+
+/* MH mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long mh_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct direct **names = NIL;
+  int fd;
+  char c,*flags,*date,*s,tmp[MAILTMPLEN];
+  STRING *message;
+  MESSAGECACHE elt;
+  FILE *df;
+  long i,size,last,nfiles;
+  long ret = LONGT;
+				/* default stream to prototype */
+  if (!stream) stream = &mhproto;
+				/* make sure valid mailbox */
+  if (!mh_isvalid (mailbox,tmp,NIL)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    if (!((!compare_cstring (mailbox,MHINBOX) ||
+	   !compare_cstring (mailbox,"INBOX")) &&
+	  (mh_file (tmp,MHINBOX) &&
+	   dummy_create_path (stream,strcat (tmp,"/"),
+			      get_dir_protection (mailbox))))) {
+      mm_notify (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+      return NIL;
+    }
+				/* falls through */
+  case 0:			/* merely empty file? */
+    break;
+  case EINVAL:
+    sprintf (tmp,"Invalid MH-format mailbox name: %.80s",mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;
+  default:
+    sprintf (tmp,"Not a MH-format mailbox: %.80s",mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* get first message */
+  if (!(*af) (stream,data,&flags,&date,&message)) return NIL;
+  if ((nfiles = scandir (tmp,&names,mh_select,mh_numsort)) > 0) {
+				/* largest number */
+    last = atoi (names[nfiles-1]->d_name);    
+    for (i = 0; i < nfiles; ++i) /* free directory */
+      fs_give ((void **) &names[i]);
+  }
+  else last = 0;		/* no messages here yet */
+  if (s = (void *) names) fs_give ((void **) &s);
+
+  mm_critical (stream);		/* go critical */
+  do {
+    if (!SIZE (message)) {	/* guard against zero-length */
+      mm_log ("Append of zero-length message",ERROR);
+      ret = NIL;
+      break;
+    }
+    if (date) {			/* want to preserve date? */
+				/* yes, parse date into an elt */
+      if (!mail_parse_date (&elt,date)) {
+	sprintf (tmp,"Bad date in append: %.80s",date);
+	mm_log (tmp,ERROR);
+	ret = NIL;
+	break;
+      }
+    }
+    mh_file (tmp,mailbox);	/* build file name we will use */
+    sprintf (tmp + strlen (tmp),"/%ld",++last);
+    if (((fd = open (tmp,O_WRONLY|O_CREAT|O_EXCL,
+		     (long)mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0)||
+	!(df = fdopen (fd,"ab"))) {
+      sprintf (tmp,"Can't open append message: %s",strerror (errno));
+      mm_log (tmp,ERROR);
+      ret = NIL;
+      break;
+    }
+				/* copy the data w/o CR's */
+    for (size = 0,i = SIZE (message); i && ret; --i)
+      if (((c = SNX (message)) != '\015') && (putc (c,df) == EOF)) ret = NIL;
+				/* close the file */
+    if (!ret || fclose (df)) {
+      unlink (tmp);		/* delete message */
+      sprintf (tmp,"Message append failed: %s",strerror (errno));
+      mm_log (tmp,ERROR);
+      ret = NIL;
+    }
+    if (ret) {			/* set the date for this message */
+      if (date) mh_setdate (tmp,&elt);
+				/* get next message */
+      if (!(*af) (stream,data,&flags,&date,&message)) ret = NIL;
+    }
+  } while (ret && message);
+  mm_nocritical (stream);	/* release critical */
+  if (ret && mail_parameters (NIL,GET_APPENDUID,NIL))
+    mm_log ("Can not return meaningful APPENDUID with this mailbox format",
+	    WARN);
+  return ret;
+}
+
+/* Internal routines */
+
+
+/* MH file name selection test
+ * Accepts: candidate directory entry
+ * Returns: T to use file name, NIL to skip it
+ */
+
+int mh_select (struct direct *name)
+{
+  char c;
+  char *s = name->d_name;
+  while (c = *s++) if (!isdigit (c)) return NIL;
+  return T;
+}
+
+
+/* MH file name comparision
+ * Accepts: first candidate directory entry
+ *	    second candidate directory entry
+ * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2
+ */
+
+int mh_numsort (const void *d1,const void *d2)
+{
+  return atoi ((*(struct direct **) d1)->d_name) -
+    atoi ((*(struct direct **) d2)->d_name);
+}
+
+
+/* MH mail build file name
+ * Accepts: destination string
+ *          source
+ * Returns: destination
+ */
+
+char *mh_file (char *dst,char *name)
+{
+  char *s;
+  char *path = mh_path (dst);
+  if (!path) fatal ("No mh path in mh_file()!");
+				/* INBOX becomes "inbox" in the MH path */
+  if (!compare_cstring (name,MHINBOX) || !compare_cstring (name,"INBOX"))
+    sprintf (dst,"%.900s/%.80s",path,MHINBOXDIR);
+				/* #mh names skip past prefix */
+  else if (*name == '#') sprintf (dst,"%.100s/%.900s",path,name + 4);
+  else mailboxfile (dst,name);	/* all other names */
+				/* tie off unnecessary trailing / */
+  if ((s = strrchr (dst,'/')) && !s[1] && (s[-1] == '/')) *s = '\0';
+  return dst;
+}
+
+/* MH canonicalize name
+ * Accepts: buffer to write name
+ *	    reference
+ *	    pattern
+ * Returns: T if success, NIL if failure
+ */
+
+long mh_canonicalize (char *pattern,char *ref,char *pat)
+{
+  unsigned long i;
+  char *s,tmp[MAILTMPLEN];
+  if (ref && *ref) {		/* have a reference */
+    strcpy (pattern,ref);	/* copy reference to pattern */
+				/* # overrides mailbox field in reference */
+    if (*pat == '#') strcpy (pattern,pat);
+				/* pattern starts, reference ends, with / */
+    else if ((*pat == '/') && (pattern[strlen (pattern) - 1] == '/'))
+      strcat (pattern,pat + 1);	/* append, omitting one of the period */
+    else strcat (pattern,pat);	/* anything else is just appended */
+  }
+  else strcpy (pattern,pat);	/* just have basic name */
+  if (mh_isvalid (pattern,tmp,T)) {
+				/* count wildcards */
+    for (i = 0, s = pattern; *s; *s++) if ((*s == '*') || (*s == '%')) ++i;
+				/* success if not too many */
+    if (i <= MAXWILDCARDS) return LONGT;
+    mm_log ("Excessive wildcards in LIST/LSUB",ERROR);
+  }
+  return NIL;
+}
+
+/* Set date for message
+ * Accepts: file name
+ *	    elt containing date
+ */
+
+void mh_setdate (char *file,MESSAGECACHE *elt)
+{
+  time_t tp[2];
+  tp[0] = time (0);		/* atime is now */
+  tp[1] = mail_longdate (elt);	/* modification time */
+  utime (file,tp);		/* set the times */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/mix.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,2834 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	MIX mail routines
+ *
+ * Author(s):	Mark Crispin
+ *		UW Technology
+ *		University of Washington
+ *		Seattle, WA  98195
+ *		Internet: MRC@Washington.EDU
+ *
+ * Date:	1 March 2006
+ * Last Edited:	7 May 2008
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "mail.h"
+#include "osdep.h"
+#include <pwd.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "misc.h"
+#include "dummy.h"
+#include "fdstring.h"
+
+/* MIX definitions */
+
+#define MEGABYTE (1024*1024)
+
+#define MIXDATAROLL MEGABYTE	/* size at which we roll to a new file */
+
+
+/* MIX files */
+
+#define MIXNAME ".mix"		/* prefix for all MIX file names */
+#define MIXMETA "meta"		/* suffix for metadata */
+#define MIXINDEX "index"	/* suffix for index */
+#define MIXSTATUS "status"	/* suffix for status */
+#define MIXSORTCACHE "sortcache"/* suffix for sortcache */
+#define METAMAX (MEGABYTE-1)	/* maximum metadata file size (sanity check) */
+
+
+/* MIX file formats */
+
+				/* sequence format (all but msg files) */
+#define SEQFMT "S%08lx\015\012"
+				/* metadata file format */
+#define MTAFMT "V%08lx\015\012L%08lx\015\012N%08lx\015\012"
+				/* index file record format */
+#define IXRFMT ":%08lx:%04d%02d%02d%02d%02d%02d%c%02d%02d:%08lx:%08lx:%08lx:%08lx:%08lx:\015\012"
+				/* status file record format */
+#define STRFMT ":%08lx:%08lx:%04x:%08lx:\015\012"
+				/* message file header format */
+#define MSRFMT "%s%08lx:%04d%02d%02d%02d%02d%02d%c%02d%02d:%08lx:\015\012"
+#define MSGTOK ":msg:"
+#define MSGTSZ (sizeof(MSGTOK)-1)
+				/* sortcache file record format */
+#define SCRFMT ":%08lx:%08lx:%08lx:%08lx:%08lx:%c%08lx:%08lx:%08lx:\015\012"
+
+/* MIX I/O stream local data */
+	
+typedef struct mix_local {
+  unsigned long curmsg;		/* current message file number */
+  unsigned long newmsg;		/* current new message file number */
+  time_t lastsnarf;		/* last snarf time */
+  int msgfd;			/* file description of current msg file */
+  int mfd;			/* file descriptor of open metadata */
+  unsigned long metaseq;	/* metadata sequence */
+  char *index;			/* mailbox index name */
+  unsigned long indexseq;	/* index sequence */
+  char *status;			/* mailbox status name */
+  unsigned long statusseq;	/* status sequence */
+  char *sortcache;		/* mailbox sortcache name */
+  unsigned long sortcacheseq;	/* sortcache sequence */
+  unsigned char *buf;		/* temporary buffer */
+  unsigned long buflen;		/* current size of temporary buffer */
+  unsigned int expok : 1;	/* non-zero if expunge reports OK */
+  unsigned int internal : 1;	/* internally opened, do not validate */
+} MIXLOCAL;
+
+
+#define MIXBURP struct mix_burp
+
+MIXBURP {
+  unsigned long fileno;		/* message file number */
+  char *name;			/* message file name */
+  SEARCHSET *tail;		/* tail of ranges */
+  SEARCHSET set;		/* set of retained ranges */
+  MIXBURP *next;		/* next file to burp */
+};
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((MIXLOCAL *) stream->local)
+
+/* Function prototypes */
+
+DRIVER *mix_valid (char *name);
+long mix_isvalid (char *name,char *meta);
+void *mix_parameters (long function,void *value);
+long mix_dirfmttest (char *name);
+void mix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+long mix_scan_contents (char *name,char *contents,unsigned long csiz,
+			unsigned long fsiz);
+void mix_list (MAILSTREAM *stream,char *ref,char *pat);
+void mix_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long mix_subscribe (MAILSTREAM *stream,char *mailbox);
+long mix_unsubscribe (MAILSTREAM *stream,char *mailbox);
+long mix_create (MAILSTREAM *stream,char *mailbox);
+long mix_delete (MAILSTREAM *stream,char *mailbox);
+long mix_rename (MAILSTREAM *stream,char *old,char *newname);
+int mix_rselect (struct direct *name);
+MAILSTREAM *mix_open (MAILSTREAM *stream);
+void mix_close (MAILSTREAM *stream,long options);
+void mix_abort (MAILSTREAM *stream);
+char *mix_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
+		  long flags);
+long mix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+void mix_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
+unsigned long *mix_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
+			 SORTPGM *pgm,long flags);
+THREADNODE *mix_thread (MAILSTREAM *stream,char *type,char *charset,
+			SEARCHPGM *spg,long flags);
+long mix_ping (MAILSTREAM *stream);
+void mix_check (MAILSTREAM *stream);
+long mix_expunge (MAILSTREAM *stream,char *sequence,long options);
+int mix_select (struct direct *name);
+int mix_msgfsort (const void *d1,const void *d2);
+long mix_addset (SEARCHSET **set,unsigned long start,unsigned long size);
+long mix_burp (MAILSTREAM *stream,MIXBURP *burp,unsigned long *reclaimed);
+long mix_burp_check (SEARCHSET *set,size_t size,char *file);
+long mix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,
+	       long options);
+long mix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+long mix_append_msg (MAILSTREAM *stream,FILE *f,char *flags,MESSAGECACHE *delt,
+		     STRING *msg,SEARCHSET *set,unsigned long seq);
+
+FILE *mix_parse (MAILSTREAM *stream,FILE **idxf,long iflags,long sflags);
+char *mix_meta_slurp (MAILSTREAM *stream,unsigned long *seq);
+long mix_meta_update (MAILSTREAM *stream);
+long mix_index_update (MAILSTREAM *stream,FILE *idxf,long flag);
+long mix_status_update (MAILSTREAM *stream,FILE *statf,long flag);
+FILE *mix_data_open (MAILSTREAM *stream,int *fd,long *size,
+		     unsigned long newsize);
+FILE *mix_sortcache_open (MAILSTREAM *stream);
+long mix_sortcache_update (MAILSTREAM *stream,FILE **sortcache);
+char *mix_read_record (FILE *f,char *buf,unsigned long buflen,char *type);
+unsigned long mix_read_sequence (FILE *f);
+char *mix_dir (char *dst,char *name);
+char *mix_file (char *dst,char *dir,char *name);
+char *mix_file_data (char *dst,char *dir,unsigned long data);
+unsigned long mix_modseq (unsigned long oldseq);
+
+/* MIX mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER mixdriver = {
+  "mix",			/* driver name */
+				/* driver flags */
+  DR_MAIL|DR_LOCAL|DR_NOFAST|DR_CRLF|DR_LOCKING|DR_DIRFMT|DR_MODSEQ,
+  (DRIVER *) NIL,		/* next driver */
+  mix_valid,			/* mailbox is valid for us */
+  mix_parameters,		/* manipulate parameters */
+  mix_scan,			/* scan mailboxes */
+  mix_list,			/* find mailboxes */
+  mix_lsub,			/* find subscribed mailboxes */
+  mix_subscribe,		/* subscribe to mailbox */
+  mix_unsubscribe,		/* unsubscribe from mailbox */
+  mix_create,			/* create mailbox */
+  mix_delete,			/* delete mailbox */
+  mix_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  mix_open,			/* open mailbox */
+  mix_close,			/* close mailbox */
+  NIL,				/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  mix_header,			/* fetch message header only */
+  mix_text,			/* fetch message body only */
+  NIL,				/* fetch partial message test */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  mix_flag,			/* modify flags */
+  NIL,				/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  mix_sort,			/* sort messages */
+  mix_thread,			/* thread messages */
+  mix_ping,			/* ping mailbox to see if still alive */
+  mix_check,			/* check for new messages */
+  mix_expunge,			/* expunge deleted messages */
+  mix_copy,			/* copy messages to another mailbox */
+  mix_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM mixproto = {&mixdriver};
+
+/* MIX mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *mix_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+  return mix_isvalid (name,tmp) ? &mixdriver : NIL;
+}
+
+
+/* MIX mail test for valid mailbox
+ * Accepts: mailbox name
+ *	    buffer to return meta name
+ * Returns: T if valid, NIL otherwise, metadata name written in both cases
+ */
+
+long mix_isvalid (char *name,char *meta)
+{
+  char dir[MAILTMPLEN];
+  struct stat sbuf;
+				/* validate name as directory */
+  if (!(errno = ((strlen (name) > NETMAXMBX) ? ENAMETOOLONG : NIL)) &&
+      *mix_dir (dir,name) && mix_file (meta,dir,MIXMETA) &&
+      !stat (dir,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) {
+				/* name is directory; is it mix? */
+    if (!stat (meta,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG))
+      return LONGT;
+    else errno = NIL;		/* directory but not mix */
+  }
+  return NIL;
+}
+
+/* MIX manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *mix_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case GET_INBOXPATH:
+    if (value) ret = mailboxfile ((char *) value,"~/INBOX");
+    break;
+  case GET_DIRFMTTEST:
+    ret = (void *) mix_dirfmttest;
+    break;
+  case GET_SCANCONTENTS:
+    ret = (void *) mix_scan_contents;
+    break;
+  case SET_ONETIMEEXPUNGEATPING:
+    if (value) ((MIXLOCAL *) ((MAILSTREAM *) value)->local)->expok = T;
+  case GET_ONETIMEEXPUNGEATPING:
+    if (value) ret = (void *)
+      (((MIXLOCAL *) ((MAILSTREAM *) value)->local)->expok ? VOIDT : NIL);
+    break;
+  }
+  return ret;
+}
+
+
+/* MIX test for directory format internal node
+ * Accepts: candidate node name
+ * Returns: T if internal name, NIL otherwise
+ */
+
+long mix_dirfmttest (char *name)
+{
+				/* belongs to MIX if starts with .mix */
+  return strncmp (name,MIXNAME,sizeof (MIXNAME) - 1) ? NIL : LONGT;
+}
+
+/* MIX mail scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void mix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* MIX scan mailbox for contents
+ * Accepts: mailbox name
+ *	    desired contents
+ *	    contents size
+ *	    file size (ignored)
+ * Returns: NIL if contents not found, T if found
+ */
+
+long mix_scan_contents (char *name,char *contents,unsigned long csiz,
+			unsigned long fsiz)
+{
+  long i,nfiles;
+  void *a;
+  char *s;
+  long ret = NIL;
+  size_t namelen = strlen (name);
+  struct stat sbuf;
+  struct direct **names = NIL;
+  if ((nfiles = scandir (name,&names,mix_select,mix_msgfsort)) > 0)
+    for (i = 0; i < nfiles; ++i) {
+      if (!ret) {
+	sprintf (s = (char *) fs_get (namelen + strlen (names[i]->d_name) + 2),
+		 "%s/%s",name,names[i]->d_name);
+	if (!stat (s,&sbuf) && (csiz <= sbuf.st_size))
+	  ret = dummy_scan_contents (s,contents,csiz,sbuf.st_size);
+	fs_give ((void **) &s);
+      }
+      fs_give ((void **) &names[i]);
+    }
+				/* free directory list */
+  if (a = (void *) names) fs_give ((void **) &a);
+  return ret;
+}
+
+/* MIX list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mix_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_list (NIL,ref,pat);
+}
+
+
+/* MIX list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mix_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_lsub (NIL,ref,pat);
+}
+
+/* MIX mail subscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to add to subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long mix_subscribe (MAILSTREAM *stream,char *mailbox)
+{
+  return sm_subscribe (mailbox);
+}
+
+
+/* MIX mail unsubscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to delete from subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long mix_unsubscribe (MAILSTREAM *stream,char *mailbox)
+{
+  return sm_unsubscribe (mailbox);
+}
+
+/* MIX mail create mailbox
+ * Accepts: mail stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long mix_create (MAILSTREAM *stream,char *mailbox)
+{
+  DRIVER *test;
+  FILE *f;
+  int c,i;
+  char *t,tmp[MAILTMPLEN],file[MAILTMPLEN];
+  char *s = strrchr (mailbox,'/');
+  unsigned long now = time (NIL);
+  long ret = NIL;
+				/* always create \NoSelect if trailing /  */
+  if (s && !s[1]) return dummy_create (stream,mailbox);
+				/* validate name */
+  if (mix_dirfmttest (s ? s + 1 : mailbox))
+    sprintf(tmp,"Can't create mailbox %.80s: invalid MIX-format name",mailbox);
+				/* must not already exist */
+  else if ((test = mail_valid (NIL,mailbox,NIL)) &&
+	   strcmp (test->name,"dummy"))
+    sprintf (tmp,"Can't create mailbox %.80s: mailbox already exists",mailbox);
+				/* create directory and metadata */
+  else if (!dummy_create_path (stream,
+			       mix_file (file,mix_dir (tmp,mailbox),MIXMETA),
+			       get_dir_protection (mailbox)))
+    sprintf (tmp,"Can't create mailbox %.80s: %.80s",mailbox,strerror (errno));
+  else if (!(f = fopen (file,"w")))
+    sprintf (tmp,"Can't re-open metadata %.80s: %.80s",mailbox,
+	     strerror (errno));
+  else {			/* success, write initial metadata */
+    fprintf (f,SEQFMT,now);
+    fprintf (f,MTAFMT,now,0,now);
+    for (i = 0, c = 'K'; (i < NUSERFLAGS) &&
+	   (t = (stream && stream->user_flags[i]) ? stream->user_flags[i] :
+	    default_user_flag (i)) && *t; ++i) {
+      putc (c,f);		/* write another keyword */
+      fputs (t,f);
+      c = ' ';			/* delimiter is now space */
+    }
+    fclose (f);
+    set_mbx_protections (mailbox,file);
+				/* point to suffix */
+    s = file + strlen (file) - (sizeof (MIXMETA) - 1);
+    strcpy (s,MIXINDEX);	/* create index */
+    if (!dummy_create_path (stream,file,get_dir_protection (mailbox)))
+      sprintf (tmp,"Can't create mix mailbox index: %.80s",strerror (errno));
+    else {
+      set_mbx_protections (mailbox,file);
+      strcpy (s,MIXSTATUS);	/* create status */
+      if (!dummy_create_path (stream,file,get_dir_protection (mailbox)))
+	sprintf (tmp,"Can't create mix mailbox status: %.80s",
+		 strerror (errno));
+      else {
+	set_mbx_protections (mailbox,file);
+	sprintf (s,"%08lx",now);/* message file */
+	if (!dummy_create_path (stream,file,get_dir_protection (mailbox)))
+	  sprintf (tmp,"Can't create mix mailbox data: %.80s",
+		   strerror (errno));
+	else {
+	  set_mbx_protections (mailbox,file);
+	  ret = LONGT;	/* declare success at this point */
+	}
+      }
+    }
+  }
+  if (!ret) MM_LOG (tmp,ERROR);	/* some error */
+  return ret;
+}
+
+/* MIX mail delete mailbox
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long mix_delete (MAILSTREAM *stream,char *mailbox)
+{
+  DIR *dirp;
+  struct direct *d;
+  int fd = -1;
+  char *s,tmp[MAILTMPLEN];
+  if (!mix_isvalid (mailbox,tmp))
+    sprintf (tmp,"Can't delete mailbox %.80s: no such mailbox",mailbox);
+  else if (((fd = open (tmp,O_RDWR,NIL)) < 0) || flock (fd,LOCK_EX|LOCK_NB))
+    sprintf (tmp,"Can't lock mailbox for delete: %.80s",mailbox);
+				/* delete metadata */
+  else if (unlink (tmp)) sprintf (tmp,"Can't delete mailbox %.80s index: %80s",
+				  mailbox,strerror (errno));
+  else {
+    close (fd);			/* close descriptor on deleted metadata */
+				/* get directory name */
+    *(s = strrchr (tmp,'/')) = '\0';
+    if (dirp = opendir (tmp)) {	/* open directory */
+      *s++ = '/';		/* restore delimiter */
+				/* massacre messages */
+      while (d = readdir (dirp)) if (mix_dirfmttest (d->d_name)) {
+	strcpy (s,d->d_name);	/* make path */
+	unlink (tmp);		/* sayonara */
+      }
+      closedir (dirp);		/* flush directory */
+      *(s = strrchr (tmp,'/')) = '\0';
+      if (rmdir (tmp)) {	/* try to remove the directory */
+	sprintf (tmp,"Can't delete name %.80s: %.80s",
+		 mailbox,strerror (errno));
+	MM_LOG (tmp,WARN);
+      }
+    }
+    return T;			/* always success */
+  }
+  if (fd >= 0) close (fd);	/* close any descriptor on metadata */
+  MM_LOG (tmp,ERROR);		/* something failed */
+  return NIL;
+}
+
+/* MIX mail rename mailbox
+ * Accepts: MIX mail stream
+ *	    old mailbox name
+ *	    new mailbox name
+ * Returns: T on success, NIL on failure
+ */
+
+long mix_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  char c,*s,tmp[MAILTMPLEN],tmp1[MAILTMPLEN];
+  struct stat sbuf;
+  int fd = -1;
+  if (!mix_isvalid (old,tmp))
+    sprintf (tmp,"Can't rename mailbox %.80s: no such mailbox",old);
+  else if (((fd = open (tmp,O_RDWR,NIL)) < 0) || flock (fd,LOCK_EX|LOCK_NB))
+    sprintf (tmp,"Can't lock mailbox for rename: %.80s",old);
+  else if (mix_dirfmttest ((s = strrchr (newname,'/')) ? s + 1 : newname))
+    sprintf (tmp,"Can't rename to mailbox %.80s: invalid MIX-format name",
+	     newname);
+				/* new mailbox name must not be valid */
+  else if (mix_isvalid (newname,tmp))
+    sprintf (tmp,"Can't rename to mailbox %.80s: destination already exists",
+	     newname);
+  else {
+    mix_dir (tmp,old);		/* build old directory name */
+    mix_dir (tmp1,newname);	/* and new directory name */
+				/* easy if not INBOX */
+    if (compare_cstring (old,"INBOX")) {
+				/* found superior to destination name? */
+      if (s = strrchr (tmp1,'/')) {
+	c = *++s;		/* remember first character of inferior */
+	*s = '\0';		/* tie off to get just superior */
+				/* name doesn't exist, create it */
+	if ((stat (tmp1,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+	    !dummy_create_path (stream,tmp1,get_dir_protection (newname)))
+	  return NIL;
+	*s = c;			/* restore full name */
+      }
+      if (!rename (tmp,tmp1)) {
+	close (fd);		/* close descriptor on metadata */
+	return LONGT;
+      }
+    }
+
+				/* RFC 3501 requires this */
+    else if (dummy_create_path (stream,strcat (tmp1,"/"),
+				get_dir_protection (newname))) {
+      void *a;
+      int i,n,lasterror;
+      char *src,*dst;
+      struct direct **names = NIL;
+      size_t srcl = strlen (tmp);
+      size_t dstl = strlen (tmp1);
+				/* rename each mix file to new directory */
+      for (i = lasterror = 0,n = scandir (tmp,&names,mix_rselect,alphasort);
+	   i < n; ++i) {
+	size_t len = strlen (names[i]->d_name);
+	sprintf (src = (char *) fs_get (srcl + len + 2),"%s/%s",
+		 tmp,names[i]->d_name);
+	sprintf (dst = (char *) fs_get (dstl + len + 1),"%s%s",
+		 tmp1,names[i]->d_name);
+	if (rename (src,dst)) lasterror = errno;
+	fs_give ((void **) &src);
+	fs_give ((void **) &dst);
+	fs_give ((void **) &names[i]);
+      }
+				/* free directory list */
+      if (a = (void *) names) fs_give ((void **) &a);
+      if (lasterror) errno = lasterror;
+      else {
+	close (fd);		/* close descriptor on metadata */
+	return mix_create (NIL,"INBOX");
+      }
+    }
+    sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %.80s",
+	     old,newname,strerror (errno));
+  }
+  if (fd >= 0) close (fd);	/* close any descriptor on metadata */
+  MM_LOG (tmp,ERROR);		/* something failed */
+  return NIL;
+}
+
+
+/* MIX test for mix name
+ * Accepts: candidate directory name
+ * Returns: T if mix file name, NIL otherwise
+ */
+
+int mix_rselect (struct direct *name)
+{
+  return mix_dirfmttest (name->d_name);
+}
+
+/* MIX mail open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *mix_open (MAILSTREAM *stream)
+{
+  short silent;
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return user_flags (&mixproto);
+  if (stream->local) fatal ("mix recycle stream");
+  stream->local = memset (fs_get (sizeof (MIXLOCAL)),0,sizeof (MIXLOCAL));
+				/* note if an INBOX or not */
+  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
+				/* make temporary buffer */
+  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
+  LOCAL->buflen = CHUNKSIZE - 1;
+				/* set stream->mailbox to be directory name */
+  mix_dir (LOCAL->buf,stream->mailbox);
+  fs_give ((void **) &stream->mailbox);
+  stream->mailbox = cpystr (LOCAL->buf);
+  LOCAL->msgfd = -1;		/* currently no file open */
+  if (!(((!stream->rdonly &&	/* open metadata file */
+	  ((LOCAL->mfd = open (mix_file (LOCAL->buf,stream->mailbox,MIXMETA),
+			       O_RDWR,NIL)) >= 0)) ||
+	 ((stream->rdonly = T) &&
+	  ((LOCAL->mfd = open (mix_file (LOCAL->buf,stream->mailbox,MIXMETA),
+			       O_RDONLY,NIL)) >= 0))) &&
+	!flock (LOCAL->mfd,LOCK_SH))) {
+    MM_LOG ("Error opening mix metadata file",ERROR);
+    mix_abort (stream);
+    stream = NIL;		/* open fails */
+  }
+  else {			/* metadata open, complete open */
+    LOCAL->index = cpystr (mix_file (LOCAL->buf,stream->mailbox,MIXINDEX));
+    LOCAL->status = cpystr (mix_file (LOCAL->buf,stream->mailbox,MIXSTATUS));
+    LOCAL->sortcache = cpystr (mix_file (LOCAL->buf,stream->mailbox,
+					 MIXSORTCACHE));
+    stream->sequence++;		/* bump sequence number */
+				/* parse mailbox */
+    stream->nmsgs = stream->recent = 0;
+    if (silent = stream->silent) LOCAL->internal = T;
+    stream->silent = T;
+    if (mix_ping (stream)) {	/* do initial ping */
+				/* try burping in case we are exclusive */
+      if (!stream->rdonly) mix_expunge (stream,"",NIL);
+      if (!(stream->nmsgs || stream->silent))
+	MM_LOG ("Mailbox is empty",(long) NIL);
+      stream->silent = silent;	/* now notify upper level */
+      mail_exists (stream,stream->nmsgs);
+      stream->perm_seen = stream->perm_deleted = stream->perm_flagged =
+	stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T;
+      stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
+      stream->kwd_create =	/* can we create new user flags? */
+	(stream->user_flags[NUSERFLAGS-1] || stream->rdonly) ? NIL : T;
+    }
+    else {			/* got murdelyzed in ping */
+      mix_abort (stream);
+      stream = NIL;
+    }
+  }
+  return stream;		/* return stream to caller */
+}
+
+/* MIX mail close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void mix_close (MAILSTREAM *stream,long options)
+{
+  if (LOCAL) {			/* only if a file is open */
+    int silent = stream->silent;
+    stream->silent = T;		/* note this stream is dying */
+				/* burp-only or expunge */
+    mix_expunge (stream,(options & CL_EXPUNGE) ? NIL : "",NIL);
+    mix_abort (stream);
+    stream->silent = silent;	/* reset silent state */
+  }
+}
+
+
+/* MIX mail abort stream
+ * Accepts: MAIL stream
+ */
+
+void mix_abort (MAILSTREAM *stream)
+{
+  if (LOCAL) {			/* only if a file is open */
+				/* close current message file if open */
+    if (LOCAL->msgfd >= 0) close (LOCAL->msgfd);
+				/* close current metadata file if open */
+    if (LOCAL->mfd >= 0) close (LOCAL->mfd);
+    if (LOCAL->index) fs_give ((void **) &LOCAL->index);
+    if (LOCAL->status) fs_give ((void **) &LOCAL->status);
+    if (LOCAL->sortcache) fs_give ((void **) &LOCAL->sortcache);
+				/* free local scratch buffer */
+    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+/* MIX mail fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+char *mix_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
+		  long flags)
+{
+  unsigned long i,j,k;
+  int fd;
+  char *s,tmp[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  if (length) *length = 0;	/* default return */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+  elt = mail_elt (stream,msgno);/* get elt */
+				/* is message in current message file? */
+  if ((LOCAL->msgfd < 0) || (elt->private.spare.data != LOCAL->curmsg)) {
+    if (LOCAL->msgfd >= 0) close (LOCAL->msgfd);
+    if ((LOCAL->msgfd = open (mix_file_data (LOCAL->buf,stream->mailbox,
+					     elt->private.spare.data),
+					     O_RDONLY,NIL)) < 0) return "";
+				/* got file */
+    LOCAL->curmsg = elt->private.spare.data;
+  }    
+  lseek (LOCAL->msgfd,elt->private.special.offset,L_SET);
+				/* size of special data and header */
+  j = elt->private.msg.header.offset + elt->private.msg.header.text.size;
+  if (j > LOCAL->buflen) {	/* is buffer big enough? */
+				/* no, make one that is */
+    fs_give ((void **) &LOCAL->buf);
+    LOCAL->buf = (char *) fs_get ((LOCAL->buflen = j) + 1);
+  }
+  /* Maybe someday validate internaldate too */
+				/* slurp special data + header, validate */
+  if ((read (LOCAL->msgfd,LOCAL->buf,j) == j) &&
+      !strncmp (LOCAL->buf,MSGTOK,MSGTSZ) &&
+      (elt->private.uid == strtoul ((char *) LOCAL->buf + MSGTSZ,&s,16)) &&
+      (*s++ == ':') && (s = strchr (s,':')) &&
+      (k = strtoul (s+1,&s,16)) && (*s++ == ':') &&
+      (s < (char *) (LOCAL->buf + elt->private.msg.header.offset))) {
+				/* won, set offset and size of message */
+    i = elt->private.msg.header.offset;
+    *length = elt->private.msg.header.text.size;
+    if (k != elt->rfc822_size) {
+      sprintf (tmp,"Inconsistency in mix message size, uid=%lx (%lu != %lu)",
+	       elt->private.uid,elt->rfc822_size,k);
+      MM_LOG (tmp,WARN);
+    }
+  }
+  else {			/* document the problem */
+    LOCAL->buf[100] = '\0';	/* tie off buffer at no more than 100 octets */
+				/* or at newline, whichever is first */
+    if (s = strpbrk (LOCAL->buf,"\015\012")) *s = '\0';
+    sprintf (tmp,"Error reading mix message header, uid=%lx, s=%.0lx, h=%s",
+	     elt->private.uid,elt->rfc822_size,LOCAL->buf);
+    MM_LOG (tmp,ERROR);
+    *length = i = j = 0;	/* default to empty */
+  }
+  LOCAL->buf[j] = '\0';		/* tie off buffer at the end */
+  return (char *) LOCAL->buf + i;
+}
+
+/* MIX mail fetch message text (body only)
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned stringstruct
+ *	    option flags
+ * Returns: T on success, NIL on failure
+ */
+
+long mix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  unsigned long i;
+  FDDATA d;
+  MESSAGECACHE *elt;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+  elt = mail_elt (stream,msgno);
+				/* is message in current message file? */
+  if ((LOCAL->msgfd < 0) || (elt->private.spare.data != LOCAL->curmsg)) {
+    if (LOCAL->msgfd >= 0) close (LOCAL->msgfd);
+    if ((LOCAL->msgfd = open (mix_file_data (LOCAL->buf,stream->mailbox,
+					     elt->private.spare.data),
+					     O_RDONLY,NIL)) < 0) return NIL;
+				/* got file */
+    LOCAL->curmsg = elt->private.spare.data;
+  }    
+				/* doing non-peek fetch? */
+  if (!(flags & FT_PEEK) && !elt->seen) {
+    FILE *idxf;			/* yes, process metadata/index/status */
+    FILE *statf = mix_parse (stream,&idxf,NIL,LONGT);
+    elt->seen = T;		/* mark as seen */
+    MM_FLAGS (stream,elt->msgno);
+				/* update status file if possible */
+    if (statf && !stream->rdonly) {
+      elt->private.mod = LOCAL->statusseq = mix_modseq (LOCAL->statusseq);
+      mix_status_update (stream,statf,NIL);
+    }
+    if (idxf) fclose (idxf);	/* release index and status file */
+    if (statf) fclose (statf);
+  } 
+  d.fd = LOCAL->msgfd;		/* set up file descriptor */
+				/* offset of message text */
+  d.pos = elt->private.special.offset + elt->private.msg.header.offset +
+    elt->private.msg.header.text.size;
+  d.chunk = LOCAL->buf;		/* initial buffer chunk */
+  d.chunksize = CHUNKSIZE;	/* chunk size */
+  INIT (bs,fd_string,&d,elt->rfc822_size - elt->private.msg.header.text.size);
+  return T;
+}
+
+/* MIX mail modify flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    flag(s)
+ *	    option flags
+ */
+
+void mix_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
+{
+  MESSAGECACHE *elt;
+  unsigned long i,uf,ffkey;
+  long f;
+  short nf;
+  FILE *idxf;
+  FILE *statf = mix_parse (stream,&idxf,NIL,LONGT);
+  unsigned long seq = mix_modseq (LOCAL->statusseq);
+				/* find first free key */
+  for (ffkey = 0; (ffkey < NUSERFLAGS) && stream->user_flags[ffkey]; ++ffkey);
+				/* parse sequence and flags */
+  if (((flags & ST_UID) ? mail_uid_sequence (stream,sequence) :
+       mail_sequence (stream,sequence)) &&
+      ((f = mail_parse_flags (stream,flag,&uf)) || uf)) {
+				/* alter flags */
+    for (i = 1,nf = (flags & ST_SET) ? T : NIL; i <= stream->nmsgs; i++)
+      if ((elt = mail_elt (stream,i))->sequence) {
+	struct {		/* old flags */
+	  unsigned int seen : 1;
+	  unsigned int deleted : 1;
+	  unsigned int flagged : 1;
+	  unsigned int answered : 1;
+	  unsigned int draft : 1;
+	  unsigned long user_flags;
+	} old;
+	old.seen = elt->seen; old.deleted = elt->deleted;
+	old.flagged = elt->flagged; old.answered = elt->answered;
+	old.draft = elt->draft; old.user_flags = elt->user_flags;
+	if (f&fSEEN) elt->seen = nf;
+	if (f&fDELETED) elt->deleted = nf;
+	if (f&fFLAGGED) elt->flagged = nf;
+	if (f&fANSWERED) elt->answered = nf;
+	if (f&fDRAFT) elt->draft = nf;
+				/* user flags */
+	if (flags & ST_SET) elt->user_flags |= uf;
+	else elt->user_flags &= ~uf;
+	if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
+	    (old.flagged != elt->flagged) ||
+	    (old.answered != elt->answered) || (old.draft != elt->draft) ||
+	    (old.user_flags != elt->user_flags)) {
+	  if (!stream->rdonly) elt->private.mod = LOCAL->statusseq = seq;
+	  MM_FLAGS (stream,elt->msgno);
+	}
+      }
+				/* update status file after change */
+    if (statf && (seq == LOCAL->statusseq))
+      mix_status_update (stream,statf,NIL);
+				/* update metadata if created a keyword */
+    if ((ffkey < NUSERFLAGS) && stream->user_flags[ffkey] &&
+	!mix_meta_update (stream))
+      MM_LOG ("Error updating mix metadata after keyword creation",ERROR);
+  }
+  if (statf) fclose (statf);	/* release status file if still open */
+  if (idxf) fclose (idxf);	/* release index file */
+}
+
+/* MIX mail sort messages
+ * Accepts: mail stream
+ *	    character set
+ *	    search program
+ *	    sort program
+ *	    option flags
+ * Returns: vector of sorted message sequences or NIL if error
+ */
+
+unsigned long *mix_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg,
+			 SORTPGM *pgm,long flags)
+{
+  unsigned long *ret;
+  FILE *sortcache = mix_sortcache_open (stream);
+  ret = mail_sort_msgs (stream,charset,spg,pgm,flags);
+  mix_sortcache_update (stream,&sortcache);
+  return ret;
+}
+
+
+/* MIX mail thread messages
+ * Accepts: mail stream
+ *	    thread type
+ *	    character set
+ *	    search program
+ *	    option flags
+ * Returns: thread node tree or NIL if error
+ */
+
+THREADNODE *mix_thread (MAILSTREAM *stream,char *type,char *charset,
+			SEARCHPGM *spg,long flags)
+{
+  THREADNODE *ret;
+  FILE *sortcache = mix_sortcache_open (stream);
+  ret = mail_thread_msgs (stream,type,charset,spg,flags,mail_sort_msgs);
+  mix_sortcache_update (stream,&sortcache);
+  return ret;
+}
+
+/* MIX mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ */
+
+static int snarfing = 0;	/* lock against recursive snarfing */
+
+long mix_ping (MAILSTREAM *stream)
+{
+  FILE *idxf,*statf;
+  struct stat sbuf;
+  STRING msg;
+  MESSAGECACHE *elt;
+  int mfd,ifd,sfd;
+  unsigned long i,msglen;
+  char *message,date[MAILTMPLEN],flags[MAILTMPLEN];
+  MAILSTREAM *sysibx = NIL;
+  long ret = NIL;
+  long snarfok = LONGT;
+				/* time to snarf? */
+  if (stream->inbox && !stream->rdonly && !snarfing &&
+      (time (0) >= (LOCAL->lastsnarf +
+		    (time_t) mail_parameters (NIL,GET_SNARFINTERVAL,NIL)))) {
+    appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL);
+    copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL);
+    MM_CRITICAL (stream);	/* go critical */
+    snarfing = T;		/* don't recursively snarf */
+				/* disable APPENDUID/COPYUID callbacks */
+    mail_parameters (NIL,SET_APPENDUID,NIL);
+    mail_parameters (NIL,SET_COPYUID,NIL);
+				/* sizes match and anything in sysinbox? */
+    if (!stat (sysinbox (),&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFREG) &&
+	sbuf.st_size &&	(sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) &&
+	!sysibx->rdonly && sysibx->nmsgs) {
+				/* for each message in sysibx mailbox */
+      for (i = 1; snarfok && (i <= sysibx->nmsgs); ++i)
+	if (!(elt = mail_elt (sysibx,i))->deleted &&
+	    (message = mail_fetch_message (sysibx,i,&msglen,FT_PEEK)) &&
+	    msglen) {
+	  mail_date (date,elt);	/* make internal date string */
+				/* make flag string */
+	  flags[0] = flags[1] = '\0';
+	  if (elt->seen) strcat (flags," \\Seen");
+	  if (elt->flagged) strcat (flags," \\Flagged");
+	  if (elt->answered) strcat (flags," \\Answered");
+	  if (elt->draft) strcat (flags," \\Draft");
+	  flags[0] = '(';
+	  strcat (flags,")");
+	  INIT (&msg,mail_string,message,msglen);
+	  if (snarfok = mail_append_full (stream,"INBOX",flags,date,&msg)) {
+	    char sequence[15];
+	    sprintf (sequence,"%lu",i);
+	    mail_flag (sysibx,sequence,"\\Deleted",ST_SET);
+	  }
+	}
+
+				/* now expunge all those messages */
+      if (snarfok) mail_expunge (sysibx);
+      else {
+	sprintf (LOCAL->buf,"Can't copy new mail at message: %lu",i - 1);
+	MM_LOG (LOCAL->buf,WARN);
+      }
+    }
+    if (sysibx) mail_close (sysibx);
+				/* reenable APPENDUID/COPYUID */
+    mail_parameters (NIL,SET_APPENDUID,(void *) au);
+    mail_parameters (NIL,SET_COPYUID,(void *) cu);
+    snarfing = NIL;		/* no longer snarfing */
+    MM_NOCRITICAL (stream);	/* release critical */
+    LOCAL->lastsnarf = time (0);/* note time of last snarf */
+  }
+				/* expunging OK if global flag set */
+  if (mail_parameters (NIL,GET_EXPUNGEATPING,NIL)) LOCAL->expok = T;
+				/* process metadata/index/status */
+  if (statf = mix_parse (stream,&idxf,LONGT,
+			 (LOCAL->internal ? NIL : LONGT))) {
+    fclose (statf);		/* just close the status file */
+    ret = LONGT;		/* declare success */
+  }
+  if (idxf) fclose (idxf);	/* release index file */
+  LOCAL->expok = NIL;		/* expunge no longer OK */
+  if (!ret) mix_abort (stream);	/* murdelyze stream if ping fails */
+  return ret;
+}
+
+
+/* MIX mail checkpoint mailbox (burp only)
+ * Accepts: MAIL stream
+ */
+
+void mix_check (MAILSTREAM *stream)
+{
+  if (stream->rdonly)		/* won't do on readonly files! */
+    MM_LOG ("Checkpoint ignored on readonly mailbox",NIL);
+				/* do burp-only expunge action */
+  if (mix_expunge (stream,"",NIL)) MM_LOG ("Check completed",(long) NIL);
+}
+
+/* MIX mail expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL, empty string for burp only
+ *	    expunge options
+ * Returns: T on success, NIL if failure
+ */
+
+long mix_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  FILE *idxf = NIL;
+  FILE *statf = NIL;
+  MESSAGECACHE *elt;
+  int ifd,sfd;
+  long ret;
+  unsigned long i;
+  unsigned long nexp = 0;
+  unsigned long reclaimed = 0;
+  int burponly = (sequence && !*sequence);
+  LOCAL->expok = T;		/* expunge during ping is OK */
+  if (!(ret = burponly || !sequence ||
+	((options & EX_UID) ?
+	 mail_uid_sequence (stream,sequence) :
+	 mail_sequence (stream,sequence))) || stream->rdonly);
+				/* read index and open status exclusive */
+  else if (statf = mix_parse (stream,&idxf,LONGT,
+			      LOCAL->internal ? NIL : LONGT)) {
+				/* expunge unless just burping */
+    if (!burponly) for (i = 1; i <= stream->nmsgs;) {
+      elt = mail_elt (stream,i);/* need to expunge this message? */
+      if (sequence ? elt->sequence : elt->deleted) {
+	++nexp;			/* yes, make it so */
+	mail_expunged (stream,i);
+      }
+      else ++i;		       /* otherwise advance to next message */
+    }
+
+				/* burp if can get exclusive access */
+    if (!flock (LOCAL->mfd,LOCK_EX|LOCK_NB)) {
+      void *a;
+      struct direct **names = NIL;
+      long nfiles = scandir (stream->mailbox,&names,mix_select,mix_msgfsort);
+      if (nfiles > 0) {		/* if have message files */
+	MIXBURP *burp,*cur;
+				/* initialize burp list */
+	for (i = 0, burp = cur = NIL; i < nfiles; ++i) {
+	  MIXBURP *nxt = (MIXBURP *) memset (fs_get (sizeof (MIXBURP)),0,
+					     sizeof (MIXBURP));
+				/* another file found */
+	  if (cur) cur = cur->next = nxt;
+	  else cur = burp = nxt;
+	  cur->name = names[i]->d_name;
+	  cur->fileno = strtoul (cur->name + sizeof (MIXNAME) - 1,NIL,16);
+	  cur->tail = &cur->set;
+	  fs_give ((void **) &names[i]);
+	}
+				/* now load ranges */
+	for (i = 1, cur = burp; ret && (i <= stream->nmsgs); i++) {
+				/* is this message in current set? */
+	  elt = mail_elt (stream,i);
+	  if (cur && (elt->private.spare.data != cur->fileno)) {
+				/* restart if necessary */
+	    if (elt->private.spare.data < cur->fileno) cur = burp;
+				/* hunt for appropriate mailbox */
+	    while (cur && (elt->private.spare.data > cur->fileno))
+	      cur = cur->next;
+				/* ought to have found it now... */
+	    if (cur && (elt->private.spare.data != cur->fileno)) cur = NIL;
+	  }
+				/* if found, add to set */
+	  if (cur) ret = mix_addset (&cur->tail,elt->private.special.offset,
+				     elt->private.msg.header.offset +
+				     elt->rfc822_size);
+	  else {		/* uh-oh */
+	    sprintf (LOCAL->buf,"Can't locate mix message file %.08lx",
+		     elt->private.spare.data);
+	    MM_LOG (LOCAL->buf,ERROR);
+	    ret = NIL;
+	  }
+	}
+	if (ret) 		/* if no errors, burp all files */
+	  for (cur = burp; ret && cur; cur = cur->next) {
+				/* if non-empty, burp it */
+	    if (cur->set.last) ret = mix_burp (stream,cur,&reclaimed);
+				/* empty, delete it unless new msg file */
+	    else if (mix_file_data (LOCAL->buf,stream->mailbox,cur->fileno) &&
+		     ((cur->fileno == LOCAL->newmsg) ?
+		      truncate (LOCAL->buf,0) : unlink (LOCAL->buf))) {
+	      sprintf (LOCAL->buf,
+		       "Can't delete empty message file %.80s: %.80s",
+		       cur->name,strerror (errno));
+	      MM_LOG (LOCAL->buf,WARN);
+	    }
+	  }
+      }
+      else MM_LOG ("No mix message files found during expunge",WARN);
+				/* free directory list */
+      if (a = (void *) names) fs_give ((void **) &a);
+    }
+
+				/* either way, re-acquire shared lock */
+    if (flock (LOCAL->mfd,LOCK_SH|LOCK_NB))
+      fatal ("Unable to re-acquire metadata shared lock!");
+    /* Do this step even if ret is NIL (meaning some burp problem)! */
+    if (nexp || reclaimed) {	/* rewrite index and status if changed */
+      LOCAL->indexseq = mix_modseq (LOCAL->indexseq);
+      if (mix_index_update (stream,idxf,NIL)) {
+	LOCAL->statusseq = mix_modseq (LOCAL->statusseq);
+				/* set failure if update fails */
+	ret = mix_status_update (stream,statf,NIL);
+      }
+    }
+  }
+  if (statf) fclose (statf);	/* close status if still open */
+  if (idxf) fclose (idxf);	/* close index if still open */
+  LOCAL->expok = NIL;		/* cancel expok */
+  if (ret) {			/* only if success */
+    char *s = NIL;
+    if (nexp) sprintf (s = LOCAL->buf,"Expunged %lu messages",nexp);
+    else if (reclaimed)
+      sprintf (s=LOCAL->buf,"Reclaimed %lu bytes of expunged space",reclaimed);
+    else if (!burponly)
+      s = stream->rdonly ? "Expunge ignored on readonly mailbox" :
+	   "No messages deleted, so no update needed";
+    if (s) MM_LOG (s,(long) NIL);
+  }
+  return ret;
+}
+
+/* MIX test for message file name
+ * Accepts: candidate directory name
+ * Returns: T if message file name, NIL otherwise
+ *
+ * ".mix" with no suffix was used by experimental versions
+ */
+
+int mix_select (struct direct *name)
+{
+  char c,*s;
+				/* make sure name has prefix */
+  if (mix_dirfmttest (name->d_name)) {
+    for (c = *(s = name->d_name + sizeof (MIXNAME) - 1); c && isxdigit (c);
+	 c = *s++);
+    if (!c) return T;		/* all-hex or no suffix */
+  }
+  return NIL;			/* not suffix or non-hex */
+}
+
+
+/* MIX msg file name comparision
+ * Accepts: first candidate directory entry
+ *	    second candidate directory entry
+ * Returns: -1 if d1 < d2, 0 if d1 == d2, 1 d1 > d2
+ */
+
+int mix_msgfsort (const void *d1,const void *d2)
+{
+  char *n1 = (*(struct direct **) d1)->d_name + sizeof (MIXNAME) - 1;
+  char *n2 = (*(struct direct **) d2)->d_name + sizeof (MIXNAME) - 1;
+  return compare_ulong (*n1 ? strtoul (n1,NIL,16) : 0,
+			*n2 ? strtoul (n2,NIL,16) : 0);
+}
+
+
+/* MIX add a range to a set
+ * Accepts: pointer to set to add
+ *	    start of set
+ *	    size of set
+ * Returns: T if success, set updated, NIL otherwise
+ */
+
+long mix_addset (SEARCHSET **set,unsigned long start,unsigned long size)
+{
+  SEARCHSET *s = *set;
+  if (start < s->last) {	/* sanity check */
+    char tmp[MAILTMPLEN];
+    sprintf (tmp,"Backwards-running mix index %lu < %lu",start,s->last);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+				/* range initially empty? */
+  if (!s->last) s->first = start;
+  else if (start > s->last)	/* no, start new range if can't append */
+    (*set = s = s->next = mail_newsearchset ())->first = start;
+  s->last = start + size;	/* end of current range */
+  return LONGT;
+}
+
+/* MIX burp message file
+ * Accepts: MAIL stream
+ *	    current burp block for this message
+ * Returns: T if successful, NIL if failed
+ */
+
+static char *staterr = "Error in stat of mix message file %.80s: %.80s";
+static char *truncerr = "Error truncating mix message file %.80s: %.80s";
+
+long mix_burp (MAILSTREAM *stream,MIXBURP *burp,unsigned long *reclaimed)
+{
+  MESSAGECACHE *elt;
+  SEARCHSET *set;
+  struct stat sbuf;
+  off_t rpos,wpos;
+  size_t size,wsize,wpending,written;
+  int fd;
+  FILE *f;
+  void *s;
+  unsigned long i;
+  long ret = NIL;
+				/* build file name */
+  mix_file_data (LOCAL->buf,stream->mailbox,burp->fileno);
+				/* need to burp at start or multiple ranges? */
+  if (!burp->set.first && !burp->set.next) {
+				/* easy case, single range at start of file */
+    if (stat (LOCAL->buf,&sbuf)) {
+      sprintf (LOCAL->buf,staterr,burp->name,strerror (errno));
+      MM_LOG (LOCAL->buf,ERROR);
+    }
+				/* is this range sane? */
+    else if (mix_burp_check (&burp->set,sbuf.st_size,LOCAL->buf)) {
+				/* if matches range then no burp needed! */
+      if (burp->set.last == sbuf.st_size) ret = LONGT;
+				/* just need to remove cruft at end */
+      else if (ret = !truncate (LOCAL->buf,burp->set.last))
+	*reclaimed += sbuf.st_size - burp->set.last;
+      else {
+	sprintf (LOCAL->buf,truncerr,burp->name,strerror (errno));
+	MM_LOG (LOCAL->buf,ERROR);
+      }
+    }
+  }
+				/* have to do more work, get the file */
+  else if (((fd = open (LOCAL->buf,O_RDWR,NIL)) < 0) ||
+	   !(f = fdopen (fd,"r+b"))) {
+    sprintf (LOCAL->buf,"Error opening mix message file %.80s: %.80s",
+	     burp->name,strerror (errno));
+    MM_LOG (LOCAL->buf,ERROR);
+    if (fd >= 0) close (fd);	/* in case fdopen() failure */
+  }
+  else if (fstat (fd,&sbuf)) {	/* get file size */
+    sprintf (LOCAL->buf,staterr,burp->name,strerror (errno));
+    MM_LOG (LOCAL->buf,ERROR);
+    fclose (f);
+  }
+
+				/* only if sane */
+  else if (mix_burp_check (&burp->set,sbuf.st_size,LOCAL->buf)) {
+				/* make sure each range starts with token */
+    for (set = &burp->set; set; set = set->next)
+      if (fseek (f,set->first,SEEK_SET) ||
+	  (fread (LOCAL->buf,1,MSGTSZ,f) != MSGTSZ) ||
+	  strncmp (LOCAL->buf,MSGTOK,MSGTSZ)) {
+	sprintf (LOCAL->buf,"Bad message token in mix message file at %lu",
+		 set->first);
+	MM_LOG (LOCAL->buf,ERROR);
+	fclose (f);
+	return NIL;		/* burp fails for this file */
+      }
+				/* burp out each old message */
+    for (set = &burp->set, wpos = 0; set; set = set->next) {
+				/* move down this range */
+      for (rpos = set->first, size = set->last - set->first;
+	   size; size -= wsize) {
+	if (rpos != wpos) {	/* data to skip at start? */
+				/* no, slide this buffer down */
+	  wsize = min (size,LOCAL->buflen);
+				/* failure is not an option here */
+	  while (fseek (f,rpos,SEEK_SET) ||
+		 (fread (LOCAL->buf,1,wsize,f) != wsize)) {
+	    MM_NOTIFY (stream,strerror (errno),WARN);
+	    MM_DISKERROR (stream,errno,T);
+	  }
+				/* nor here */
+	  while (fseek (f,wpos,SEEK_SET)) {
+	    MM_NOTIFY (stream,strerror (errno),WARN);
+	    MM_DISKERROR (stream,errno,T);
+	  }
+				/* and especially not here */
+	  for (s = LOCAL->buf, wpending = wsize; wpending; wpending -= written)
+	    if (!(written = fwrite (LOCAL->buf,1,wpending,f))) {
+	      MM_NOTIFY (stream,strerror (errno),WARN);
+	      MM_DISKERROR (stream,errno,T);
+	    }
+	}
+	else wsize = size;	/* nothing to skip, say we wrote it all */
+	rpos += wsize; wpos += wsize;
+      }
+    }
+
+    while (fflush (f)) {	/* failure also not an option here... */
+      MM_NOTIFY (stream,strerror (errno),WARN);
+      MM_DISKERROR (stream,errno,T);
+    }
+    if (ftruncate (fd,wpos)) {	/* flush cruft at end of file */
+      sprintf (LOCAL->buf,truncerr,burp->name,strerror (errno));
+      MM_LOG (LOCAL->buf,WARN);
+    }
+    else *reclaimed += rpos - wpos;
+    ret = !fclose (f);		/* close file */
+				/* slide down message positions in index */
+    for (i = 1,rpos = 0; i <= stream->nmsgs; ++i)
+      if ((elt = mail_elt (stream,i))->private.spare.data == burp->fileno) {
+	elt->private.special.offset = rpos;
+	rpos += elt->private.msg.header.offset + elt->rfc822_size;
+      }
+				/* debugging */
+    if (rpos != wpos) fatal ("burp size consistency check!");
+  }
+  return ret;
+}
+
+
+/* MIX burp sanity check to make sure not burping off end of file
+ * Accepts: burp set
+ *	    file size
+ *	    file name
+ * Returns: T if sane, NIL if insane
+ */
+
+long mix_burp_check (SEARCHSET *set,size_t size,char *file)
+{
+  do if (set->last > size) {	/* sanity check */
+    char tmp[MAILTMPLEN];
+    sprintf (tmp,"Unexpected short mix message file %.80s %lu < %lu",
+	     file,size,set->last);
+    MM_LOG (tmp,ERROR);
+    return NIL;			/* don't burp this file at all */
+  } while (set = set->next);
+  return LONGT;
+}
+
+/* MIX mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if copy successful, else NIL
+ */
+
+long mix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  FDDATA d;
+  STRING st;
+  char tmp[2*MAILTMPLEN];
+  long ret = mix_isvalid (mailbox,LOCAL->buf);
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+  MAILSTREAM *astream = NIL;
+  FILE *idxf = NIL;
+  FILE *msgf = NIL;
+  FILE *statf = NIL;
+  if (!ret) switch (errno) {	/* make sure valid mailbox */
+  case NIL:			/* no error in stat() */
+    if (pc) return (*pc) (stream,sequence,mailbox,options);
+    sprintf (tmp,"Not a MIX-format mailbox: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    break;
+  default:			/* some stat() error */
+    MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
+    break;
+  }
+				/* get sequence to copy */
+  else if (!(ret = ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+		    mail_sequence (stream,sequence))));
+				/* acquire stream to append */
+  else if (ret = ((astream = mail_open (NIL,mailbox,OP_SILENT)) &&
+		  !astream->rdonly &&
+		  (((MIXLOCAL *) astream->local)->expok = T) &&
+		  (statf = mix_parse (astream,&idxf,LONGT,NIL))) ?
+	   LONGT : NIL) {
+    int fd;
+    unsigned long i;
+    MESSAGECACHE *elt;
+    unsigned long newsize,hdrsize,size;
+    MIXLOCAL *local = (MIXLOCAL *) astream->local;
+    unsigned long seq = mix_modseq (local->metaseq);
+				/* make sure new modseq fits */
+    if (local->indexseq > seq) seq = local->indexseq + 1;
+    if (local->statusseq > seq) seq = local->statusseq + 1;
+				/* calculate size of per-message header */
+    sprintf (local->buf,MSRFMT,MSGTOK,0,0,0,0,0,0,0,'+',0,0,0);
+    hdrsize = strlen (local->buf);
+
+    MM_CRITICAL (stream);	/* go critical */
+    astream->silent = T;	/* no events here */
+				/* calculate size that will be added */
+    for (i = 1, newsize = 0; i <= stream->nmsgs; ++i)
+      if ((elt = mail_elt (stream,i))->sequence)
+	newsize += hdrsize + elt->rfc822_size;
+				/* open data file */
+    if (msgf = mix_data_open (astream,&fd,&size,newsize)) {
+      char *t;
+      unsigned long j,uid,uidv;
+      copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL);
+      SEARCHSET *source = cu ? mail_newsearchset () : NIL;
+      SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
+      for (i = 1,uid = uidv = 0; ret && (i <= stream->nmsgs); ++i) 
+	if (((elt = mail_elt (stream,i))->sequence) && elt->rfc822_size) {
+				/* is message in current message file? */
+	  if ((LOCAL->msgfd < 0) ||
+	      (elt->private.spare.data != LOCAL->curmsg)) {
+	    if (LOCAL->msgfd >= 0) close (LOCAL->msgfd);
+	    if ((LOCAL->msgfd = open (mix_file_data (LOCAL->buf,
+						     stream->mailbox,
+						     elt->private.spare.data),
+				      O_RDONLY,NIL)) >= 0)
+	      LOCAL->curmsg = elt->private.spare.data;
+	  }
+	  if (LOCAL->msgfd < 0) ret = NIL;
+	  else {		/* got file */
+	    d.fd = LOCAL->msgfd;/* set up file descriptor */
+				/* start of message */
+	    d.pos = elt->private.special.offset +
+	      elt->private.msg.header.offset;
+	    d.chunk = LOCAL->buf;
+	    d.chunksize = CHUNKSIZE;
+	    INIT (&st,fd_string,&d,elt->rfc822_size);
+				/* init flag string */
+	    tmp[0] = tmp[1] = '\0';
+	    if (j = elt->user_flags) do
+	      if ((t = stream->user_flags[find_rightmost_bit (&j)]) && *t)
+		strcat (strcat (tmp," "),t);
+	    while (j);
+	    if (elt->seen) strcat (tmp," \\Seen");
+	    if (elt->deleted) strcat (tmp," \\Deleted");
+	    if (elt->flagged) strcat (tmp," \\Flagged");
+	    if (elt->answered) strcat (tmp," \\Answered");
+	    if (elt->draft) strcat (tmp," \\Draft");
+	    tmp[0] = '(';	/* wrap list */
+	    strcat (tmp,")");
+				/* if append OK, add to source set */
+	    if ((ret = mix_append_msg (astream,msgf,tmp,elt,&st,dest,
+				       seq)) &&	source)
+	      mail_append_set (source,mail_uid (stream,i));
+	  }
+	}
+
+				/* finish write if success */
+      if (ret && (ret = !fflush (msgf))) {
+	fclose (msgf);		/* all good, close the msg file now */
+				/* write new metadata, index, and status */
+	local->metaseq = local->indexseq = local->statusseq = seq;
+	if (ret = (mix_meta_update (astream) &&
+		   mix_index_update (astream,idxf,LONGT))) {
+				/* success, delete if doing a move */
+	  if (options & CP_MOVE)
+	    for (i = 1; i <= stream->nmsgs; i++)
+	      if ((elt = mail_elt (stream,i))->sequence) {
+		elt->deleted = T;
+		if (!stream->rdonly) elt->private.mod = LOCAL->statusseq = seq;
+		MM_FLAGS (stream,elt->msgno);
+	      }
+				/* done with status file now */
+	  mix_status_update (astream,statf,LONGT);
+				/* return sets if doing COPYUID */
+	  if (cu) (*cu) (stream,mailbox,astream->uid_validity,source,dest);
+	  source = dest = NIL;	/* don't free these sets now */
+	}
+      }
+      else {			/* error */
+	if (errno) {		/* output error message if system call error */
+	  sprintf (tmp,"Message copy failed: %.80s",strerror (errno));
+	  MM_LOG (tmp,ERROR);
+	}
+	ftruncate (fd,size);	/* revert file */
+	close (fd);		/* make sure that fclose doesn't corrupt us */
+	fclose (msgf);		/* free the stdio resources */
+      }
+				/* flush any sets remaining */
+      mail_free_searchset (&source);
+      mail_free_searchset (&dest);
+    }
+    else {			/* message file open failed */
+      sprintf (tmp,"Error opening copy message file: %.80s",
+	       strerror (errno));
+      MM_LOG (tmp,ERROR);
+      ret = NIL;
+    }
+    MM_NOCRITICAL (stream);
+  }
+  else MM_LOG ("Can't open copy mailbox",ERROR);
+  if (statf) fclose (statf);	/* close status if still open */
+  if (idxf) fclose (idxf);	/* close index if still open */
+				/* finished with append stream */
+  if (astream) mail_close (astream);
+  return ret;			/* return state */
+}
+
+/* MIX mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long mix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  STRING *message;
+  char *flags,*date,tmp[MAILTMPLEN];
+				/* N.B.: can't use LOCAL->buf for tmp */
+  long ret = mix_isvalid (mailbox,tmp);
+				/* default stream to prototype */
+  if (!stream) stream = user_flags (&mixproto);
+  if (!ret) switch (errno) {	/* if not valid mailbox */
+  case ENOENT:			/* no such file? */
+    if (ret = compare_cstring (mailbox,"INBOX") ?
+	NIL : mix_create (NIL,"INBOX"))
+      break;
+    MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+    break;
+  default:
+    sprintf (tmp,"Not a MIX-format mailbox: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    break;
+  }
+
+				/* get first message */
+  if (ret && MM_APPEND (af) (stream,data,&flags,&date,&message)) {
+    MAILSTREAM *astream;
+    FILE *idxf = NIL;
+    FILE *msgf = NIL;
+    FILE *statf = NIL;
+    if (ret = ((astream = mail_open (NIL,mailbox,OP_SILENT)) &&
+	       !astream->rdonly &&
+	       (((MIXLOCAL *) astream->local)->expok = T) &&
+	       (statf = mix_parse (astream,&idxf,LONGT,NIL))) ?
+	LONGT : NIL) {
+      int fd;
+      unsigned long size,hdrsize;
+      MESSAGECACHE elt;
+      MIXLOCAL *local = (MIXLOCAL *) astream->local;
+      unsigned long seq = mix_modseq (local->metaseq);
+				/* make sure new modseq fits */
+      if (local->indexseq > seq) seq = local->indexseq + 1;
+      if (local->statusseq > seq) seq = local->statusseq + 1;
+				/* calculate size of per-message header */
+      sprintf (local->buf,MSRFMT,MSGTOK,0,0,0,0,0,0,0,'+',0,0,0);
+      hdrsize = strlen (local->buf);
+      MM_CRITICAL (astream);	/* go critical */
+      astream->silent = T;	/* no events here */
+				/* open data file */
+      if (msgf = mix_data_open (astream,&fd,&size,hdrsize + SIZE (message))) {
+	appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL);
+	SEARCHSET *dst = au ? mail_newsearchset () : NIL;
+	while (ret && message) {/* while good to go and have messages */
+	  errno = NIL;		/* in case one of these causes failure */
+				/* guard against zero-length */
+	  if (!(ret = SIZE (message)))
+	    MM_LOG ("Append of zero-length message",ERROR);
+	  else if (date && !(ret = mail_parse_date (&elt,date))) {
+	    sprintf (tmp,"Bad date in append: %.80s",date);
+	    MM_LOG (tmp,ERROR);
+	  }
+	  else {
+	    if (!date) {	/* if date not specified, use now */
+	      internal_date (tmp);
+	      mail_parse_date (&elt,tmp);
+	    }
+	    ret = mix_append_msg (astream,msgf,flags,&elt,message,dst,seq) &&
+	      MM_APPEND (af) (stream,data,&flags,&date,&message);
+	  }
+	}
+
+				/* finish write if success */
+	if (ret && (ret = !fflush (msgf))) {
+	  fclose (msgf);	/* all good, close the msg file now */
+				/* write new metadata, index, and status */
+	  local->metaseq = local->indexseq = local->statusseq = seq;
+	  if ((ret = (mix_meta_update (astream) &&
+		      mix_index_update (astream,idxf,LONGT) &&
+		      mix_status_update (astream,statf,LONGT))) && au) {
+	      (*au) (mailbox,astream->uid_validity,dst);
+	      dst = NIL;	/* don't free this set now */
+	  }
+	}
+	else {			/* failure */
+	  if (errno) {		/* output error message if system call error */
+	    sprintf (tmp,"Message append failed: %.80s",strerror (errno));
+	    MM_LOG (tmp,ERROR);
+	  }
+	  ftruncate (fd,size);	/* revert all writes to file*/
+	  close (fd);		/* make sure that fclose doesn't corrupt us */
+	  fclose (msgf);	/* free the stdio resources */
+	}
+				/* flush any set remaining */
+	mail_free_searchset (&dst);
+      }
+      else {			/* message file open failed */
+	sprintf (tmp,"Error opening append message file: %.80s",
+		 strerror (errno));
+	MM_LOG (tmp,ERROR);
+	ret = NIL;
+      }
+      MM_NOCRITICAL (astream);	/* release critical */
+    }
+    else MM_LOG ("Can't open append mailbox",ERROR);
+    if (statf) fclose (statf);	/* close status if still open */
+    if (idxf) fclose (idxf);	/* close index if still open */
+    if (astream) mail_close (astream);
+  }
+  return ret;
+}
+
+/* MIX mail append single message
+ * Accepts: MAIL stream
+ *	    flags for new message if non-NIL
+ *	    elt with source date if non-NIL
+ *	    stringstruct of message text
+ *	    searchset to place UID
+ *	    modseq of message
+ * Returns: T if success, NIL if failure
+ */
+
+long mix_append_msg (MAILSTREAM *stream,FILE *f,char *flags,MESSAGECACHE *delt,
+		     STRING *msg,SEARCHSET *set,unsigned long seq)
+{
+  MESSAGECACHE *elt;
+  int c,cs;
+  unsigned long i,j,k,uf,hoff;
+  long sf;
+  stream->kwd_create = NIL;	/* don't copy unknown keywords */
+  sf = mail_parse_flags (stream,flags,&uf);
+				/* swell the cache */
+  mail_exists (stream,++stream->nmsgs);
+				/* assign new UID from metadata */
+  (elt = mail_elt (stream,stream->nmsgs))->private.uid = ++stream->uid_last;
+  elt->private.mod = seq;	/* set requested modseq in status */
+  elt->rfc822_size = SIZE (msg);/* copy message size and date to index */
+  elt->year = delt->year; elt->month = delt->month; elt->day = delt->day;
+  elt->hours = delt->hours; elt->minutes = delt->minutes;
+  elt->seconds = delt->seconds; elt->zoccident = delt->zoccident;
+  elt->zhours = delt->zhours; elt->zminutes = delt->zminutes;
+  /*
+   * Do NOT set elt->valid here!  mix_status_update() uses it to determine
+   * whether a message should be marked as old.
+   */
+  if (sf&fSEEN) elt->seen = T;	/* copy flags to status */
+  if (sf&fDELETED) elt->deleted = T;
+  if (sf&fFLAGGED) elt->flagged = T;
+  if (sf&fANSWERED) elt->answered = T;
+  if (sf&fDRAFT) elt->draft = T;
+  elt->user_flags |= uf;
+				/* message is in new message file */
+  elt->private.spare.data = LOCAL->newmsg;
+
+				/* offset to message internal header */
+  elt->private.special.offset = ftell (f);
+				/* build header for message */
+  fprintf (f,MSRFMT,MSGTOK,elt->private.uid,
+	   elt->year + BASEYEAR,elt->month,elt->day,
+	   elt->hours,elt->minutes,elt->seconds,
+	   elt->zoccident ? '-' : '+',elt->zhours,elt->zminutes,
+	   elt->rfc822_size);
+				/* offset to header from  internal header */
+  elt->private.msg.header.offset = ftell (f) - elt->private.special.offset;
+  for (cs = 0; SIZE (msg); ) {	/* copy message */
+    if (elt->private.msg.header.text.size) {
+      if (msg->cursize)		/* blat entire chunk if have it */
+	for (j = msg->cursize; j; j -= k)
+	  if (!(k = fwrite (msg->curpos,1,j,f))) return NIL;
+      SETPOS (msg,GETPOS (msg) + msg->cursize);
+    }
+    else {			/* still searching for delimiter */
+      c = 0xff & SNX (msg);	/* get source character */
+      if (putc (c,f) == EOF) return NIL;
+      switch (cs) {		/* decide what to do based on state */
+      case 0:			/* previous char ordinary */
+	if (c == '\015') cs = 1;/* advance if CR */
+	break;
+      case 1:			/* previous CR, advance if LF */
+	cs = (c == '\012') ? 2 : 0;
+	break;
+      case 2:			/* previous CRLF, advance if CR */
+	cs = (c == '\015') ? 3 : 0;
+	break;
+      case 3:			/* previous CRLFCR, done if LF */
+	if (c == '\012') elt->private.msg.header.text.size =
+			   elt->rfc822_size - SIZE (msg);
+	cs = 0;			/* reset mechanism */
+	break;
+      }
+    }
+  }
+				/* if no delimiter, header is entire msg */
+  if (!elt->private.msg.header.text.size)
+    elt->private.msg.header.text.size = elt->rfc822_size;
+				/* add this message to set */
+  mail_append_set (set,elt->private.uid);
+  return LONGT;			/* success */
+}
+
+/* MIX mail read metadata, index, and status
+ * Accepts: MAIL stream
+ *	    returned index file
+ *	    index file flags (non-NIL if want to add/remove messages)
+ *	    status file flags (non-NIL if want to update elt->valid and old)
+ * Returns: open status file, or NIL if failure
+ *
+ * Note that this routine can return an open index file even if it fails!
+ */
+
+static char *shortmsg =
+  "message %lu (UID=%.08lx) truncated by %lu byte(s) (%lu < %lu)";
+
+FILE *mix_parse (MAILSTREAM *stream,FILE **idxf,long iflags,long sflags)
+{
+  int fd;
+  unsigned long i;
+  char *s,*t;
+  struct stat sbuf;
+  FILE *statf = NIL;
+  short metarepairneeded = 0;
+  short indexrepairneeded = 0;
+  short silent = stream->silent;
+  *idxf = NIL;			/* in case error */
+				/* readonly means no updates */
+  if (stream->rdonly) iflags = sflags = NIL;
+				/* open index file */
+  if ((fd = open (LOCAL->index,iflags ? O_RDWR : O_RDONLY,NIL)) < 0)
+    MM_LOG ("Error opening mix index file",ERROR);
+				/* acquire exclusive access and FILE */
+  else if (!flock (fd,iflags ? LOCK_EX : LOCK_SH) &&
+	   !(*idxf = fdopen (fd,iflags ? "r+b" : "rb"))) {
+    MM_LOG ("Error obtaining stream on mix index file",ERROR);
+    flock (fd,LOCK_UN);		/* relinquish lock */
+    close (fd);
+  }
+
+				/* slurp metadata */
+  else if (s = mix_meta_slurp (stream,&i)) {
+    unsigned long j = 0;	/* non-zero if UIDVALIDITY/UIDLAST changed */
+    if (i != LOCAL->metaseq) {	/* metadata changed? */
+      char *t,*k;
+      LOCAL->metaseq = i;	/* note new metadata sequence */
+      while (s && *s) {		/* parse entire metadata file */
+				/* locate end of line */
+	if (s = strstr (t = s,"\015\012")) {
+	  *s = '\0';		/* tie off line */
+	  s += 2;		/* skip past CRLF */
+	  switch (*t++) {	/* parse line */
+	  case 'V':		/* UIDVALIDITY */
+	    if (!isxdigit (*t) || !(i = strtoul (t,&t,16))) {
+	      MM_LOG ("Error in mix metadata file UIDVALIDITY record",ERROR);
+	      return NIL;	/* give up */
+	    }
+	    if (i != stream->uid_validity) j = stream->uid_validity = i;
+	    break;
+	  case 'L':		/* new UIDLAST */
+	    if (!isxdigit (*t)) {
+	      MM_LOG ("Error in mix metadata file UIDLAST record",ERROR);
+	      return NIL;	/* give up */
+	    }
+	    if ((i = strtoul (t,&t,16)) != stream->uid_last)
+	      j = stream->uid_last = i;
+	    break;
+	  case 'N':		/* new message file */
+	    if (!isxdigit (*t)) {
+	      MM_LOG ("Error in mix metadata file new msg record",ERROR);
+	      return NIL;	/* give up */
+	    }
+	    if ((i = strtoul (t,&t,16)) != stream->uid_last)
+	      LOCAL->newmsg = i;
+	    break;
+	  case 'K':		/* new keyword list */
+	    for (i = 0; t && *t && (i < NUSERFLAGS); ++i) {
+	      if (t = strchr (k = t,' ')) *t++ = '\0';
+				/* make sure keyword non-empty */
+	      if (*k && (strlen (k) <= MAXUSERFLAG)) {
+				/* in case value changes (shouldn't happen) */
+		if (stream->user_flags[i] && strcmp (stream->user_flags[i],k)){
+		  char tmp[MAILTMPLEN];
+		  sprintf (tmp,"flag rename old=%.80s new=%.80s",
+			   stream->user_flags[i],k);
+		  MM_LOG (tmp,WARN);
+		  fs_give ((void **) &stream->user_flags[i]);
+		}
+		if (!stream->user_flags[i]) stream->user_flags[i] = cpystr (k);
+	      }
+	      else break;	/* empty keyword */
+	    }
+	    if ((i < NUSERFLAGS) && stream->user_flags[i]) {
+	      MM_LOG ("Error in mix metadata file keyword record",ERROR);
+	      return NIL;	/* give up */
+	    }
+	    else if (i == NUSERFLAGS) stream->kwd_create = NIL;
+	    break;
+	  }
+	}
+	if (t && *t) {		/* junk in line */
+	  MM_LOG ("Error in mix metadata record",ERROR);
+	  return NIL;		/* give up */
+	}
+      }
+    }
+
+				/* get sequence */
+    if (!(i = mix_read_sequence (*idxf)) || (i < LOCAL->indexseq)) {
+      MM_LOG ("Error in mix index file sequence record",ERROR);
+      return NIL;		/* give up */
+    }
+				/* sequence changed from last time? */
+    else if (j || (i > LOCAL->indexseq)) {
+      unsigned long uid,nmsgs,curfile,curfilesize,curpos;
+      char *t,*msg,tmp[MAILTMPLEN];
+				/* start with no messages */
+      curfile = curfilesize = curpos = nmsgs = 0;
+				/* update sequence iff expunging OK */
+      if (LOCAL->expok) LOCAL->indexseq = i;
+				/* get first elt */
+      while ((s = mix_read_record (*idxf,LOCAL->buf,LOCAL->buflen,"index")) &&
+	     *s)
+	switch (*s) {
+	case ':':		/* message record */
+	  if (!(isxdigit (*++s) && (uid = strtoul (s,&t,16)))) msg = "UID";
+	  else if (!((*t++ == ':') && isdigit (*t) && isdigit (t[1]) &&
+		     isdigit (t[2]) && isdigit (t[3]) && isdigit (t[4]) &&
+		     isdigit (t[5]) && isdigit (t[6]) && isdigit (t[7]) &&
+		     isdigit (t[8]) && isdigit (t[9]) && isdigit (t[10]) &&
+		     isdigit (t[11]) && isdigit (t[12]) && isdigit (t[13]) &&
+		     ((t[14] == '+') || (t[14] == '-')) && 
+		     isdigit (t[15]) && isdigit (t[16]) && isdigit (t[17]) &&
+		     isdigit (t[18]))) msg = "internaldate";
+	  else if ((*(s = t+19) != ':') || !isxdigit (*++s)) msg = "size";
+	  else {
+	    unsigned int y = (((*t - '0') * 1000) + ((t[1] - '0') * 100) +
+			      ((t[2] - '0') * 10) + t[3] - '0') - BASEYEAR;
+	    unsigned int m = ((t[4] - '0') * 10) + t[5] - '0';
+	    unsigned int d = ((t[6] - '0') * 10) + t[7] - '0';
+	    unsigned int hh = ((t[8] - '0') * 10) + t[9] - '0';
+	    unsigned int mm = ((t[10] - '0') * 10) + t[11] - '0';
+	    unsigned int ss = ((t[12] - '0') * 10) + t[13] - '0';
+	    unsigned int z = (t[14] == '-') ? 1 : 0;
+	    unsigned int zh = ((t[15] - '0') * 10) + t[16] - '0';
+	    unsigned int zm = ((t[17] - '0') * 10) + t[18] - '0';
+	    unsigned long size = strtoul (s,&s,16);
+	    if ((*s++ == ':') && isxdigit (*s)) {
+	      unsigned long file = strtoul (s,&s,16);
+	      if ((*s++ == ':') && isxdigit (*s)) {
+		unsigned long pos = strtoul (s,&s,16);
+		if ((*s++ == ':') && isxdigit (*s)) {
+		  unsigned long hpos = strtoul (s,&s,16);
+		  if ((*s++ == ':') && isxdigit (*s)) {
+		    unsigned long hsiz = strtoul (s,&s,16);
+		    if (uid > stream->uid_last) {
+		      sprintf (tmp,"mix index invalid UID (%08lx < %08lx)",
+			       uid,stream->uid_last);
+		      if (stream->rdonly) {
+			MM_LOG (tmp,ERROR);
+			return NIL;
+		      }
+		      strcat (tmp,", repaired");
+		      MM_LOG (tmp,WARN);
+		      stream->uid_last = uid;
+		      metarepairneeded = T;
+		    }
+
+				/* ignore expansion values */
+		    if (*s++ == ':') {
+		      MESSAGECACHE *elt;
+		      ++nmsgs;	/* this is another mesage */
+				/* within current known range of messages? */
+		      while (nmsgs <= stream->nmsgs) {
+				/* yes, get corresponding elt */
+			elt = mail_elt (stream,nmsgs);
+				/* existing message with matching data? */
+			if (uid == elt->private.uid) {
+				/* beware of Dracula's resurrection */
+			  if (elt->private.ghost) {
+			    sprintf (tmp,"mix index data unexpunged UID: %lx",
+				     uid);
+			    MM_LOG (tmp,ERROR);
+			    return NIL;
+			  }
+				/* also of static data changing */
+			  if ((size != elt->rfc822_size) ||
+			      (file != elt->private.spare.data) ||
+			      (pos != elt->private.special.offset) ||
+			      (hpos != elt->private.msg.header.offset) ||
+			      (hsiz != elt->private.msg.header.text.size) ||
+			      (y != elt->year) || (m != elt->month) ||
+			      (d != elt->day) || (hh != elt->hours) ||
+			      (mm != elt->minutes) || (ss != elt->seconds) ||
+			      (z != elt->zoccident) || (zh != elt->zhours) ||
+			      (zm != elt->zminutes)) {
+			    sprintf (tmp,"mix index data mismatch: %lx",uid);
+			    MM_LOG (tmp,ERROR);
+			    return NIL;
+			  }
+			  break;
+			}
+				/* existing msg with lower UID is expunged */
+			else if (uid > elt->private.uid) {
+			  if (LOCAL->expok) mail_expunged (stream,nmsgs);
+			  else {/* message expunged, but not yet for us */
+			    ++nmsgs;
+			    elt->private.ghost = T;
+			  }
+			}
+			else {	/* unexpected message record */
+			  sprintf (tmp,"mix index UID mismatch (%lx < %lx)",
+				   uid,elt->private.uid);
+			  MM_LOG (tmp,ERROR);
+			  return NIL;
+			}
+		      }
+
+				/* time to create a new message? */
+		      if (nmsgs > stream->nmsgs) {
+				/* defer announcing until later */
+			stream->silent = T;
+			mail_exists (stream,nmsgs);
+			stream->silent = silent;
+			(elt = mail_elt (stream,nmsgs))->recent = T;
+			elt->private.uid = uid; elt->rfc822_size = size;
+			elt->private.spare.data = file;
+			elt->private.special.offset = pos;
+			elt->private.msg.header.offset = hpos;
+			elt->private.msg.header.text.size = hsiz;
+			elt->year = y; elt->month = m; elt->day = d;
+			elt->hours = hh; elt->minutes = mm;
+			elt->seconds = ss; elt->zoccident = z;
+			elt->zhours = zh; elt->zminutes = zm;
+				/* message in same file? */
+			if (curfile == file) {
+			  if (pos < curpos) {
+			    MESSAGECACHE *plt = mail_elt (stream,elt->msgno-1);
+				/* uh-oh, calculate delta? */
+			    i = curpos - pos;
+			    sprintf (tmp,shortmsg,plt->msgno,plt->private.uid,
+				     i,pos,curpos);
+				/* possible to fix? */
+			    if (!stream->rdonly && LOCAL->expok &&
+				(i < plt->rfc822_size)) {
+			      plt->rfc822_size -= i;
+			      if (plt->rfc822_size <
+				  plt->private.msg.header.text.size)
+				plt->private.msg.header.text.size =
+				  plt->rfc822_size;
+			      strcat (tmp,", repaired");
+			      indexrepairneeded = T;
+			    }
+			    MM_LOG (tmp,WARN);
+			  }
+			}
+			else {	/* new file, restart */
+			  if (stat (mix_file_data (LOCAL->buf,stream->mailbox,
+						   curfile = file),&sbuf)) {
+			    sprintf (tmp,"Missing mix data file: %.500s",
+				     LOCAL->buf);
+			    MM_LOG (tmp,ERROR);
+			    return NIL;
+			  }
+			  curfile = file;
+			  curfilesize = sbuf.st_size;
+			}
+
+				/* position of message in file */
+			curpos = pos + elt->private.msg.header.offset +
+			  elt->rfc822_size;
+				/* short file? */
+			if (curfilesize < curpos) {
+				/* uh-oh, calculate delta? */
+			    i = curpos - curfilesize;
+			    sprintf (tmp,shortmsg,elt->msgno,elt->private.uid,
+				     i,curfilesize,curpos);
+				/* possible to fix? */
+			    if (!stream->rdonly && LOCAL->expok &&
+				(i < elt->rfc822_size)) {
+			      elt->rfc822_size -= i;
+			      if (elt->rfc822_size <
+				  elt->private.msg.header.text.size)
+				elt->private.msg.header.text.size =
+				  elt->rfc822_size;
+			      strcat (tmp,", repaired");
+			      indexrepairneeded = T;
+			    }
+			    MM_LOG (tmp,WARN);
+			}
+		      }
+		      break;
+		    }
+		    else msg = "expansion";
+		  }
+		  else msg = "header size";
+		}
+		else msg = "header position";
+	      }
+	      else msg = "message position";
+	    }
+	    else msg = "file#";
+	  }
+	  sprintf (tmp,"Error in %s in mix index file: %.500s",msg,s);
+	  MM_LOG (tmp,ERROR);
+	  return NIL;
+	default:
+	  sprintf (tmp,"Unknown record in mix index file: %.500s",s);
+	  MM_LOG (tmp,ERROR);
+	  return NIL;
+	}
+      if (!s) return NIL;	/* barfage from mix_read_record() */
+				/* expunge trailing messages not in index */
+      if (LOCAL->expok) while (nmsgs < stream->nmsgs)
+	mail_expunged (stream,stream->nmsgs);
+    }
+
+				/* repair metadata and index if needed */
+    if ((metarepairneeded ? mix_meta_update (stream) : T) &&
+	(indexrepairneeded ? mix_index_update (stream,*idxf,NIL) : T)) {
+      MESSAGECACHE *elt;
+      int fd;
+      unsigned long uid,uf,sf,mod;
+      char *s;
+      int updatep = NIL;
+				/* open status file */
+      if ((fd = open (LOCAL->status,
+		      stream->rdonly ? O_RDONLY : O_RDWR,NIL)) < 0)
+	MM_LOG ("Error opening mix status file",ERROR);
+				/* acquire exclusive access and FILE */
+      else if (!flock (fd,stream->rdonly ? LOCK_SH : LOCK_EX) &&
+	       !(statf = fdopen (fd,stream->rdonly ? "rb" : "r+b"))) {
+	MM_LOG ("Error obtaining stream on mix status file",ERROR);
+	flock (fd,LOCK_UN);	/* relinquish lock */
+	close (fd);
+      }
+				/* get sequence */
+      else if (!(i = mix_read_sequence (statf)) ||
+	       ((i < LOCAL->statusseq) && stream->nmsgs && (i != 1))) {
+	sprintf (LOCAL->buf,
+		 "Error in mix status sequence record, i=%lx, seq=%lx",
+		 i,LOCAL->statusseq);
+	MM_LOG (LOCAL->buf,ERROR);
+      }
+				/* sequence changed from last time? */
+      else if (i != LOCAL->statusseq) {
+				/* update sequence, get first elt */
+	if (i > LOCAL->statusseq) LOCAL->statusseq = i;
+	if (stream->nmsgs) {
+	  elt = mail_elt (stream,i = 1);
+
+				/* read message records */
+	  while ((t = s = mix_read_record (statf,LOCAL->buf,LOCAL->buflen,
+					   "status")) && *s && (*s++ == ':') &&
+		 isxdigit (*s)) {
+	    uid = strtoul (s,&s,16);
+	    if ((*s++ == ':') && isxdigit (*s)) {
+	      uf = strtoul (s,&s,16);
+	      if ((*s++ == ':') && isxdigit (*s)) {
+		sf = strtoul (s,&s,16);
+		if ((*s++ == ':') && isxdigit (*s)) {
+		  mod = strtoul (s,&s,16);
+				/* ignore expansion values */
+		  if (*s++ == ':') {
+				/* need to move ahead to next elt? */
+		    while ((uid > elt->private.uid) && (i < stream->nmsgs))
+		      elt = mail_elt (stream,++i);
+				/* update elt if altered */
+		    if ((uid == elt->private.uid) &&
+			(!elt->valid || (mod != elt->private.mod))) {
+		      elt->user_flags = uf;
+		      elt->private.mod = mod;
+		      elt->seen = (sf & fSEEN) ? T : NIL;
+		      elt->deleted = (sf & fDELETED) ? T : NIL;
+		      elt->flagged = (sf & fFLAGGED) ? T : NIL;
+		      elt->answered = (sf & fANSWERED) ? T : NIL;
+		      elt->draft = (sf & fDRAFT) ? T : NIL;
+				/* announce if altered existing message */
+		      if (elt->valid) MM_FLAGS (stream,elt->msgno);
+				/* first time, is old message? */
+		      else if (sf & fOLD) {
+				/* yes, clear recent and set valid */
+			elt->recent = NIL;
+			elt->valid = T;
+		      }
+				/* recent, allowed to update its status? */
+		      else if (sflags) {
+				/* yes, set valid and check in status */
+			elt->valid = T;
+			elt->private.mod = mix_modseq (elt->private.mod);
+			updatep = T;
+		      }
+		      /* leave valid unset and recent if sflags not set */
+		    }
+		    continue;	/* everything looks good */
+		  }
+		}
+	      }
+	    }
+	    break;		/* error somewhere */
+	  }
+
+	  if (t && *t) {	/* non-null means bogus record */
+	    char msg[MAILTMPLEN];
+	    sprintf (msg,"Error in mix status file message record%s: %.80s",
+		     stream->rdonly ? "" : ", fixing",t);
+	    MM_LOG (msg,WARN);
+				/* update it if not readonly */
+	    if (!stream->rdonly) updatep = T;
+	  }
+	  if (updatep) {		/* need to update? */
+	    LOCAL->statusseq = mix_modseq (LOCAL->statusseq);
+	    mix_status_update (stream,statf,LONGT);
+	  }
+	}
+      }
+    }
+  }
+  if (statf) {			/* still happy? */
+    unsigned long j;
+    stream->silent = silent;	/* now notify upper level */
+    mail_exists (stream,stream->nmsgs);
+    for (i = 1, j = 0; i <= stream->nmsgs; ++i)
+      if (mail_elt (stream,i)->recent) ++j;
+    mail_recent (stream,j);
+  }
+  return statf;
+}
+
+/* MIX metadata file routines */
+
+/* MIX read metadata
+ * Accepts: MAIL stream
+ *	    return pointer for modseq
+ * Returns: pointer to metadata after modseq or NIL if failure
+ */
+
+char *mix_meta_slurp (MAILSTREAM *stream,unsigned long *seq)
+{
+  struct stat sbuf;
+  char *s;
+  char *ret = NIL;
+  if (fstat (LOCAL->mfd,&sbuf))
+    MM_LOG ("Error obtaining size of mix metatdata file",ERROR);
+  if (sbuf.st_size > LOCAL->buflen) {
+				/* should be just a few dozen bytes */
+    if (sbuf.st_size > METAMAX) fatal ("absurd mix metadata file size");
+    fs_give ((void **) &LOCAL->buf);
+    LOCAL->buf = (char *) fs_get ((LOCAL->buflen = sbuf.st_size) + 1);
+  }
+				/* read current metadata file */
+  LOCAL->buf[sbuf.st_size] = '\0';
+  if (lseek (LOCAL->mfd,0,L_SET) ||
+      (read (LOCAL->mfd,s = LOCAL->buf,sbuf.st_size) != sbuf.st_size))
+    MM_LOG ("Error reading mix metadata file",ERROR);
+  else if ((*s != 'S') || !isxdigit (s[1]) ||
+	   ((*seq = strtoul (s+1,&s,16)) < LOCAL->metaseq) ||
+	   (*s++ != '\015') || (*s++ != '\012'))
+    MM_LOG ("Error in mix metadata file sequence record",ERROR);
+  else ret = s;
+  return ret;
+}
+
+/* MIX update metadata
+ * Accepts: MAIL stream
+ * Returns: T on success, NIL if error
+ *
+ * Index MUST be locked!!
+ */
+
+long mix_meta_update (MAILSTREAM *stream)
+{
+  long ret;
+				/* do nothing if stream readonly */
+  if (stream->rdonly) ret = LONGT;
+  else {
+    unsigned char c,*s,*ss,*t;
+    unsigned long i;
+    /* The worst-case metadata is limited to:
+     *    4 * (1 + 8 + 2) + (NUSERFLAGS * (MAXUSERFLAG + 1))
+     * which comes out to 1994 octets.  This is much smaller than the normal
+     * CHUNKSIZE definition of 64K, and CHUNKSIZE is the smallest size of
+     * LOCAL->buf.
+     *
+     * If more stuff gets added to the metadata, or if you change the value
+     * of NUSERFLAGS, MAXUSERFLAG or CHUNKSIZE, be sure to recalculate the
+     * above assertation.
+     */
+    sprintf (LOCAL->buf,SEQFMT,LOCAL->metaseq = mix_modseq (LOCAL->metaseq));
+    sprintf (LOCAL->buf + strlen (LOCAL->buf),MTAFMT,
+	     stream->uid_validity,stream->uid_last,LOCAL->newmsg);
+    for (i = 0, c = 'K', s = ss = LOCAL->buf + strlen (LOCAL->buf);
+	 (i < NUSERFLAGS) && (t = stream->user_flags[i]); ++i) {
+      if (!*t) fatal ("impossible empty keyword");
+      *s++ = c;			/* write delimiter */
+      while (*t) *s++ = *t++;	/* write keyword */
+      c = ' ';			/* delimiter is now space */
+    }
+    if (s != ss) {		/* tie off keywords line */
+      *s++ = '\015'; *s++ = '\012';
+    }
+				/* calculate length of metadata */
+    if ((i = s - LOCAL->buf) > LOCAL->buflen)
+      fatal ("impossible buffer overflow");
+    lseek (LOCAL->mfd,0,L_SET);	/* rewind file */
+				/* write new metadata */
+    ret = (write (LOCAL->mfd,LOCAL->buf,i) == i) ? LONGT : NIL;
+    ftruncate (LOCAL->mfd,i);	/* and tie off at that point */
+  }
+  return ret;
+}
+
+/* MIX index file routines */
+
+
+/* MIX update index
+ * Accepts: MAIL stream
+ *	    open FILE
+ *	    expansion check flag
+ * Returns: T on success, NIL if error
+ */
+
+long mix_index_update (MAILSTREAM *stream,FILE *idxf,long flag)
+{
+  unsigned long i;
+  long ret = LONGT;
+  if (!stream->rdonly) {	/* do nothing if stream readonly */
+    if (flag) {			/* need to do expansion check? */
+      char tmp[MAILTMPLEN];
+      size_t size;
+      struct stat sbuf;
+				/* calculate file size we need */
+      for (i = 1, size = 0; i <= stream->nmsgs; ++i)
+	if (!mail_elt (stream,i)->private.ghost) ++size;
+      if (size) {		/* Winston Smith's first dairy entry */
+	sprintf (tmp,IXRFMT,0,14,4,4,13,0,0,'+',0,0,0,0,0,0,0);
+	size *= strlen (tmp);
+      }
+				/* calculate file size we need */
+      sprintf (tmp,SEQFMT,LOCAL->indexseq);
+      size += strlen (tmp);
+				/* get current file size */
+      if (fstat (fileno (idxf),&sbuf)) {
+	MM_LOG ("Error getting size of mix index file",ERROR);
+	ret = NIL;
+      }
+				/* need to write additional space? */
+      else if (sbuf.st_size < size) {
+	void *buf = fs_get (size -= sbuf.st_size);
+	memset (buf,0,size);
+	if (fseek (idxf,0,SEEK_END) || (fwrite (buf,1,size,idxf) != size) ||
+	    fflush (idxf)) {
+	  fseek (idxf,sbuf.st_size,SEEK_SET);
+	  ftruncate (fileno (idxf),sbuf.st_size);
+	  MM_LOG ("Error extending mix index file",ERROR);
+	  ret = NIL;
+	}
+	fs_give ((void **) &buf);
+      }
+    }
+
+    if (ret) {			/* if still good to go */
+      rewind (idxf);		/* let's start at the very beginning */
+				/* write modseq first */
+      fprintf (idxf,SEQFMT,LOCAL->indexseq);
+				/* then write all messages */
+      for (i = 1; ret && (i <= stream->nmsgs); i++) {
+	MESSAGECACHE *elt = mail_elt (stream,i);
+	if (!elt->private.ghost)/* only write living messages */
+	  fprintf (idxf,IXRFMT,elt->private.uid,
+		   elt->year + BASEYEAR,elt->month,elt->day,
+		   elt->hours,elt->minutes,elt->seconds,
+		   elt->zoccident ? '-' : '+',elt->zhours,elt->zminutes,
+		   elt->rfc822_size,elt->private.spare.data,
+		   elt->private.special.offset,
+		   elt->private.msg.header.offset,
+		   elt->private.msg.header.text.size);
+	if (ferror (idxf)) {
+	  MM_LOG ("Error updating mix index file",ERROR);
+	  ret = NIL;
+	}
+      }
+      if (fflush (idxf)) {
+	MM_LOG ("Error flushing mix index file",ERROR);
+	ret = NIL;
+      }
+      if (ret) ftruncate (fileno (idxf),ftell (idxf));
+    }
+  }
+  return ret;
+}
+
+/* MIX status file routines */
+
+
+/* MIX update status
+ * Accepts: MAIL stream
+ *	    pointer to open FILE
+ *	    expansion check flag
+ * Returns: T on success, NIL if error
+ */
+
+long mix_status_update (MAILSTREAM *stream,FILE *statf,long flag)
+{
+  unsigned long i;
+  char tmp[MAILTMPLEN];
+  long ret = LONGT;
+  if (!stream->rdonly) {	/* do nothing if stream readonly */
+    if (flag) {			/* need to do expansion check? */
+      char tmp[MAILTMPLEN];
+      size_t size;
+      struct stat sbuf;
+				/* calculate file size we need */
+      for (i = 1, size = 0; i <= stream->nmsgs; ++i)
+	if (!mail_elt (stream,i)->private.ghost) ++size;
+      if (size) {		/* number of living messages */
+	sprintf (tmp,STRFMT,0,0,0,0);
+	size *= strlen (tmp);
+      }
+      sprintf (tmp,SEQFMT,LOCAL->statusseq);
+      size += strlen (tmp);
+				/* get current file size */
+      if (fstat (fileno (statf),&sbuf)) {
+	MM_LOG ("Error getting size of mix status file",ERROR);
+	ret = NIL;
+      }
+				/* need to write additional space? */
+      else if (sbuf.st_size < size) {
+	void *buf = fs_get (size -= sbuf.st_size);
+	memset (buf,0,size);
+	if (fseek (statf,0,SEEK_END) || (fwrite (buf,1,size,statf) != size) ||
+	    fflush (statf)) {
+	  fseek (statf,sbuf.st_size,SEEK_SET);
+	  ftruncate (fileno (statf),sbuf.st_size);
+	  MM_LOG ("Error extending mix status file",ERROR);
+	  ret = NIL;
+	}
+	fs_give ((void **) &buf);
+      }
+    }
+
+    if (ret) {			/* if still good to go */
+      rewind (statf);		/* let's start at the very beginning */
+				/* write sequence */
+      fprintf (statf,SEQFMT,LOCAL->statusseq);
+				/* write message status records */
+      for (i = 1; ret && (i <= stream->nmsgs); ++i) {
+	MESSAGECACHE *elt = mail_elt (stream,i);
+				/* make sure all messages have a modseq */
+	if (!elt->private.mod) elt->private.mod = LOCAL->statusseq;
+	if (!elt->private.ghost)/* only write living messages */
+	  fprintf (statf,STRFMT,elt->private.uid,elt->user_flags,
+		   (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
+		   (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
+		   (fDRAFT * elt->draft) + (elt->valid ? fOLD : NIL),
+		   elt->private.mod);
+	if (ferror (statf)) {
+	  sprintf (tmp,"Error updating mix status file: %.80s",
+		   strerror (errno));
+	  MM_LOG (tmp,ERROR);
+	  ret = NIL;
+	}
+      }
+      if (ret && fflush (statf)) {
+	MM_LOG ("Error flushing mix status file",ERROR);
+	ret = NIL;
+      }
+      if (ret) ftruncate (fileno (statf),ftell (statf));
+    }
+  }
+  return ret;
+}
+
+/* MIX data file routines */
+
+
+/* MIX open data file
+ * Accepts: MAIL stream
+ *	    pointer to returned fd if success
+ *	    pointer to returned size if success
+ *	    size of new data to be added
+ * Returns: open FILE, or NIL if failure
+ *
+ * The curend test assumes that the last message of the mailbox is the furthest
+ * point that the current data file extends, and thus that is all that needs to
+ * be tested for short file prevention.
+ */
+
+FILE *mix_data_open (MAILSTREAM *stream,int *fd,long *size,
+		     unsigned long newsize)
+{
+  FILE *msgf = NIL;
+  struct stat sbuf;
+  MESSAGECACHE *elt = stream->nmsgs ? mail_elt (stream,stream->nmsgs) : NIL;
+  unsigned long curend = (elt && (elt->private.spare.data == LOCAL->newmsg)) ?
+    elt->private.special.offset + elt->private.msg.header.offset +
+    elt->rfc822_size : 0;
+				/* allow create if curend 0 */
+  if ((*fd = open (mix_file_data (LOCAL->buf,stream->mailbox,LOCAL->newmsg),
+		   O_RDWR | (curend ? NIL : O_CREAT),NIL)) >= 0) {
+    fstat (*fd,&sbuf);		/* get current file size */
+				/* can we use this file? */
+    if ((curend <= sbuf.st_size) &&
+	(!sbuf.st_size || ((sbuf.st_size + newsize) <= MIXDATAROLL)))
+      *size = sbuf.st_size;	/* yes, return current size */
+    else {			/* short file or becoming too long */
+      if (curend > sbuf.st_size) {
+	char tmp[MAILTMPLEN];
+	sprintf (tmp,"short mix message file %.08lx (%ld > %ld), rolling",
+		 LOCAL->newmsg,curend,sbuf.st_size);
+	MM_LOG (tmp,WARN);	/* shouldn't happen */
+      }
+      close (*fd);		/* roll to a new file */
+      while ((*fd = open (mix_file_data
+			  (LOCAL->buf,stream->mailbox,
+			   LOCAL->newmsg = mix_modseq (LOCAL->newmsg)),
+			  O_RDWR | O_CREAT | O_EXCL,sbuf.st_mode)) < 0);
+      *size = 0;		/* brand new file */
+      fchmod (*fd,sbuf.st_mode);/* with same mode as previous file */
+    }
+  }
+  if (*fd >= 0) {		/* have a data file? */
+				/* yes, get stdio and set position */
+    if (msgf = fdopen (*fd,"r+b")) fseek (msgf,*size,SEEK_SET);
+    else close (*fd);		/* fdopen() failed? */
+  }
+  return msgf;			/* return results */
+}
+
+/* MIX open sortcache
+ * Accepts: MAIL stream
+ * Returns: open FILE, or NIL if failure or could only get readonly sortcache
+ */
+
+FILE *mix_sortcache_open (MAILSTREAM *stream)
+{
+  int fd,refwd;
+  unsigned long i,uid,sentdate,fromlen,tolen,cclen,subjlen,msgidlen,reflen;
+  char *s,*t,*msg,tmp[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  SORTCACHE *sc;
+  STRINGLIST *sl;
+  struct stat sbuf;
+  int rdonly = NIL;
+  FILE *srtcf = NIL;
+  mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL);
+  fstat (LOCAL->mfd,&sbuf);
+  if (!stream->nmsgs);		/* do nothing if mailbox empty */
+				/* open sortcache file */
+  else if (((fd = open (LOCAL->sortcache,O_RDWR|O_CREAT,sbuf.st_mode)) < 0) &&
+	   !(rdonly = ((fd = open (LOCAL->sortcache,O_RDONLY,NIL)) >= 0)))
+    MM_LOG ("Error opening mix sortcache file",WARN);
+				/* acquire lock and FILE */
+  else if (!flock (fd,rdonly ? LOCK_SH : LOCK_EX) &&
+	   !(srtcf = fdopen (fd,rdonly ? "rb" : "r+b"))) {
+    MM_LOG ("Error obtaining stream on mix sortcache file",WARN);
+    flock (fd,LOCK_UN);		/* relinquish lock */
+    close (fd);
+  }
+  else if (!(i = mix_read_sequence (srtcf)) || (i < LOCAL->sortcacheseq))
+    MM_LOG ("Error in mix sortcache file sequence record",WARN);
+				/* sequence changed from last time? */
+  else if (i > LOCAL->sortcacheseq) {
+    LOCAL->sortcacheseq = i;	/* update sequence */
+    while ((s = t = mix_read_record (srtcf,LOCAL->buf,LOCAL->buflen,
+				     "sortcache")) && *s &&
+	   (msg = "uid") && (*s++ == ':') && isxdigit (*s)) {
+      uid = strtoul (s,&s,16);
+      if ((*s++ == ':') && isxdigit (*s)) {
+	sentdate = strtoul (s,&s,16);
+	if ((*s++ == ':') && isxdigit (*s)) {
+	  fromlen = strtoul (s,&s,16);
+	  if ((*s++ == ':') && isxdigit (*s)) {
+	    tolen = strtoul (s,&s,16);
+	    if ((*s++ == ':') && isxdigit (*s)) {
+	      cclen = strtoul (s,&s,16);
+	      if ((*s++ == ':') && ((*s == 'R') || (*s == ' ')) &&
+		  isxdigit (s[1])) {
+		refwd = (*s++ == 'R') ? T : NIL;
+		subjlen = strtoul (s,&s,16);
+		if ((*s++ == ':') && isxdigit (*s)) {
+		  msgidlen = strtoul (s,&s,16);
+		  if ((*s++ == ':') && isxdigit (*s)) {
+		    reflen = strtoul (s,&s,16);
+				/* ignore expansion values */
+		    if (*s++ == ':') {
+
+		      if (i = mail_msgno (stream,uid)) {
+			sc = (SORTCACHE *) (*mc) (stream,i,CH_SORTCACHE);
+			sc->size = (elt = mail_elt (stream,i))->rfc822_size;
+			sc->date = sentdate;
+			sc->arrival = elt->day ? mail_longdate (elt) : 1;
+			if (refwd) sc->refwd = T;
+			if (fromlen) {
+			  if (sc->from) fseek (srtcf,fromlen + 2,SEEK_CUR);
+			  else if ((getc (srtcf) != 'F') ||
+				   (fread (sc->from = (char *) fs_get(fromlen),
+					   1,fromlen-1,srtcf) != (fromlen-1))||
+				   (sc->from[fromlen-1] = '\0') ||
+				   (getc (srtcf) != '\015') ||
+				   (getc (srtcf) != '\012')) {
+			    msg = "from data";
+			    break;
+			  }
+			}
+			if (tolen) {
+			  if (sc->to) fseek (srtcf,tolen + 2,SEEK_CUR);
+			  else if ((getc (srtcf) != 'T') ||
+				   (fread (sc->to = (char *) fs_get (tolen),
+					   1,tolen-1,srtcf) != (tolen - 1)) ||
+				   (sc->to[tolen-1] = '\0') ||
+				   (getc (srtcf) != '\015') ||
+				   (getc (srtcf) != '\012')) {
+			    msg = "to data";
+			    break;
+			  }
+			}
+			if (cclen) {
+			  if (sc->cc) fseek (srtcf,cclen + 2,SEEK_CUR);
+			  else if ((getc (srtcf) != 'C') ||
+				   (fread (sc->cc = (char *) fs_get (cclen),
+					   1,cclen-1,srtcf) != (cclen - 1)) ||
+				   (sc->cc[cclen-1] = '\0') ||
+				   (getc (srtcf) != '\015') ||
+				   (getc (srtcf) != '\012')) {
+			    msg = "cc data";
+			    break;
+			  }
+			}
+			if (subjlen) {
+			  if (sc->subject) fseek (srtcf,subjlen + 2,SEEK_CUR);
+			  else if ((getc (srtcf) != 'S') ||
+				     (fread (sc->subject =
+					     (char *) fs_get (subjlen),1,
+					     subjlen-1,srtcf) != (subjlen-1))||
+				   (sc->subject[subjlen-1] = '\0') ||
+				   (getc (srtcf) != '\015') ||
+				   (getc (srtcf) != '\012')) {
+			    msg = "subject data";
+			    break;
+			  }
+			}
+
+			if (msgidlen) {
+			  if (sc->message_id)
+			    fseek (srtcf,msgidlen + 2,SEEK_CUR);
+			  else if ((getc (srtcf) != 'M') ||
+				   (fread (sc->message_id = 
+					   (char *) fs_get (msgidlen),1,
+					   msgidlen-1,srtcf) != (msgidlen-1))||
+				   (sc->message_id[msgidlen-1] = '\0') ||
+				   (getc (srtcf) != '\015') ||
+				   (getc (srtcf) != '\012')) {
+			    msg = "message-id data";
+			    break;
+			  }
+			}
+			if (reflen) {
+			  if (sc->references) fseek(srtcf,reflen + 2,SEEK_CUR);
+				/* make sure it fits */
+			  else {
+			    if (reflen >= LOCAL->buflen) {
+			      fs_give ((void **) &LOCAL->buf);
+			      LOCAL->buf = (char *)
+				fs_get ((LOCAL->buflen = reflen) + 1);
+			      }
+			    if ((getc (srtcf) != 'R') ||
+				(fread (LOCAL->buf,1,reflen-1,srtcf) !=
+				 (reflen - 1)) ||
+				(LOCAL->buf[reflen-1] = '\0') ||
+				(getc (srtcf) != '\015') ||
+				(getc (srtcf) != '\012')) {
+			      msg = "references data";
+			      break;
+			    }
+			    for (s = LOCAL->buf,sl = NIL,
+				   sc->references = mail_newstringlist ();
+				 s && *s; s += i + 1) {
+			      if ((i = strtoul (s,&s,16)) && (*s++ == ':') &&
+				  (s[i] == ':')) {
+				if (sl) sl = sl->next = mail_newstringlist();
+				else sl = sc->references;
+				s[i] = '\0';
+				sl->text.data = cpystr (s);
+				sl->text.size = i;
+			      }
+			      else s = NIL;
+			    }
+			    if (!s || *s ||
+				(s != ((char *) LOCAL->buf + reflen - 1))) {
+			      msg = "references length consistency check";
+			      break;
+			    }
+			  }
+			}
+		      }
+
+				/* UID not found, ignore this message */
+		      else fseek (srtcf,((fromlen ? fromlen + 2 : 0) +
+					 (tolen ? tolen + 2 : 0) +
+					 (cclen ? cclen + 2 : 0) +
+					 (subjlen ? subjlen + 2 : 0) +
+					 (msgidlen ? msgidlen + 2 : 0) +
+					 (reflen ? reflen + 2 : 0)),
+				  SEEK_CUR);
+		      continue;
+		    }
+		    else msg = "expansion";
+		  }
+		  else msg = "references";
+		}
+		else msg = "message-id";
+	      }
+	      else msg = "subject";
+	    }
+	    else msg = "cc";
+	  }
+	  else msg = "to";
+	}
+	else msg = "from";
+      }
+      else msg = "sentdate";
+      break;			/* error somewhere */
+    }
+    if (!t || *t) {		/* error detected? */
+      if (t) {			/* non-null means bogus record */
+	sprintf (tmp,"Error in %s in mix sortcache record: %.500s",msg,t);
+	MM_LOG (tmp,WARN);
+      }
+      fclose (srtcf);		/* either way, must punt */
+      srtcf = NIL;
+    }
+  }
+  if (rdonly && srtcf) {	/* can't update if readonly */
+    unlink (LOCAL->sortcache);	/* try deleting it */
+    fclose (srtcf);		/* so close it and return as if error */
+    srtcf = NIL;
+  }
+  else fchmod (fd,sbuf.st_mode);
+  return srtcf;
+}
+
+/* MIX update and close sortcache
+ * Accepts: MAIL stream
+ *	    pointer to open FILE (if FILE is NIL, do nothing)
+ * Returns: T on success, NIL on error
+ */
+
+long mix_sortcache_update (MAILSTREAM *stream,FILE **sortcache)
+{
+  FILE *f = *sortcache;
+  long ret = LONGT;
+  if (f) {			/* ignore if no file */
+    unsigned long i,j;
+    mailcache_t mc = (mailcache_t) mail_parameters (NIL,GET_CACHE,NIL);
+    for (i = 1; (i <= stream->nmsgs) &&
+	   !((SORTCACHE *) (*mc) (stream,i,CH_SORTCACHE))->dirty; ++i);
+    if (i <= stream->nmsgs) {	/* only update if some entry is dirty */
+      rewind (f);		/* let's start at the very beginning */
+				/* write sequence */
+      fprintf (f,SEQFMT,LOCAL->sortcacheseq = mix_modseq(LOCAL->sortcacheseq));
+      for (i = 1; ret && (i <= stream->nmsgs); ++i) {
+	MESSAGECACHE *elt = mail_elt (stream,i);
+	SORTCACHE *s = (SORTCACHE *) (*mc) (stream,i,CH_SORTCACHE);
+	STRINGLIST *sl;
+	s->dirty = NIL;		/* no longer dirty */
+	if (sl = s->references)	/* count length of references */
+	  for (j = 1; sl && sl->text.data; sl = sl->next)
+	    j += 10 + sl->text.size;
+	else j = 0;		/* no references yet */
+	fprintf (f,SCRFMT,elt->private.uid,s->date,
+		 s->from ? strlen (s->from) + 1 : 0,
+		 s->to ? strlen (s->to) + 1 : 0,s->cc ? strlen (s->cc) + 1 : 0,
+		 s->refwd ? 'R' : ' ',s->subject ? strlen (s->subject) + 1: 0,
+		 s->message_id ? strlen (s->message_id) + 1 : 0,j);
+	if (s->from) fprintf (f,"F%s\015\012",s->from);
+	if (s->to) fprintf (f,"T%s\015\012",s->to);
+	if (s->cc) fprintf (f,"C%s\015\012",s->cc);
+	if (s->subject) fprintf (f,"S%s\015\012",s->subject);
+	if (s->message_id) fprintf (f,"M%s\015\012",s->message_id);
+	if (j) {		/* any references to write? */
+	  fputc ('R',f);	/* yes, do so */
+	  for (sl = s->references; sl && sl->text.data; sl = sl->next)
+	    fprintf (f,"%08lx:%s:",sl->text.size,sl->text.data);
+	  fputs ("\015\012",f);
+	}
+	if (ferror (f)) {
+	  MM_LOG ("Error updating mix sortcache file",WARN);
+	  ret = NIL;
+	}
+      }
+      if (ret && fflush (f)) {
+	MM_LOG ("Error flushing mix sortcache file",WARN);
+	ret = NIL;
+      }
+      if (ret) ftruncate (fileno (f),ftell (f));
+    }
+    if (fclose (f)) {
+      MM_LOG ("Error closing mix sortcache file",WARN);
+      ret = NIL;
+    }
+  }
+  return ret;
+}
+
+/* MIX generic file routines */
+
+/* MIX read record
+ * Accepts: open FILE
+ *	    buffer
+ *	    buffer length
+ *	    record type
+ * Returns: buffer if success, else NIL (zero-length buffer means EOF)
+ */
+
+char *mix_read_record (FILE *f,char *buf,unsigned long buflen,char *type)
+{
+  char *s,tmp[MAILTMPLEN];
+				/* ensure string tied off */
+  buf[buflen-2] = buf[buflen-1] = '\0';
+  while (fgets (buf,buflen-1,f)) {
+    if (s = strchr (buf,'\012')) {
+      if ((s != buf) && (s[-1] == '\015')) --s;
+      *s = '\0';		/* tie off buffer */
+      if (s != buf) return buf;	/* return if non-empty buffer */
+      sprintf (tmp,"Empty mix %s record",type);
+      MM_LOG (tmp,WARN);
+    }
+    else if (buf[buflen-2]) {	/* overlong record is bad news */
+      sprintf (tmp,"Oversize mix %s record: %.512s",type,buf);
+      MM_LOG (tmp,ERROR);
+      return NIL;
+    }
+    else {
+      sprintf (tmp,"Truncated mix %s record: %.512s",type,buf);
+      MM_LOG (tmp,WARN);
+      return buf;		/* pass to caller anyway */
+    }
+  }
+  buf[0] = '\0';		/* return empty buffer on EOF */
+  return buf;
+}
+
+/* MIX read sequence record
+ * Accepts: open FILE
+ * Returns: sequence value, or NIL if failure
+ */
+
+unsigned long mix_read_sequence (FILE *f)
+{
+  unsigned long ret;
+  char *s,tmp[MAILTMPLEN];
+  if (!mix_read_record (f,tmp,MAILTMPLEN-1,"sequence")) return NIL;
+  switch (tmp[0]) {		/* examine record */
+  case '\0':			/* end of file */
+    ret = 1;			/* start a new sequence regime */
+    break;
+  case 'S':			/* sequence record */
+    if (isxdigit (tmp[1])) {	/* must be followed by hex value */
+      ret = strtoul (tmp+1,&s,16);
+      if (!*s) break;		/* and nothing more */
+    }
+				/* drop into default case */
+  default:			/* anything else is an error */
+    return NIL;			/* return error */
+  }
+  return ret;
+}
+
+/* MIX internal routines */
+
+
+/* MIX mail build directory name
+ * Accepts: destination string
+ *          source
+ * Returns: destination or empty string if error
+ */
+
+char *mix_dir (char *dst,char *name)
+{
+  char *s;
+				/* empty string if mailboxfile fails */
+  if (!mailboxfile (dst,name)) *dst = '\0';
+				/* driver-selected INBOX  */
+  else if (!*dst) mailboxfile (dst,"~/INBOX");
+				/* tie off unnecessary trailing / */
+  else if ((s = strrchr (dst,'/')) && !s[1]) *s = '\0';
+  return dst;
+}
+
+
+/* MIX mail build file name
+ * Accepts: destination string
+ *	    directory name
+ *	    file name
+ * Returns: destination
+ */
+
+char *mix_file (char *dst,char *dir,char *name)
+{
+  sprintf (dst,"%.500s/%.80s%.80s",dir,MIXNAME,name);
+  return dst;
+}
+
+
+/* MIX mail build file name from data file number
+ * Accepts: destination string
+ *	    directory name
+ *	    data file number
+ * Returns: destination
+ */
+
+char *mix_file_data (char *dst,char *dir,unsigned long data)
+{
+  char tmp[MAILTMPLEN];
+  if (data) sprintf (tmp,"%08lx",data);
+  else tmp[0] = '\0';		/* compatibility with experimental version */
+  return mix_file (dst,dir,tmp);
+}
+
+/* MIX mail get new modseq
+ * Accepts: old modseq
+ * Returns: new modseq value
+ */
+
+unsigned long mix_modseq (unsigned long oldseq)
+{
+				/* normally time now */
+  unsigned long ret = (unsigned long) time (NIL);
+				/* ensure that modseq doesn't go backwards */
+  if (ret <= oldseq) ret = oldseq + 1;
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/mkauths	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,40 @@
+#!/bin/sh
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+# Program:	Authenticator Linkage Generator
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		5 December 1995
+# Last Edited:	30 August 2006
+
+# Erase old authenticators list
+rm -f auths.c
+touch auths.c
+
+# Now define the new list
+for authenticator
+ do
+  if [ -f Makefile."$authenticator" ]; then
+    make -f Makefile."$authenticator" `cat SPECIALS`
+  fi
+  echo "extern AUTHENTICATOR auth_"$authenticator";" >> linkage.h
+  echo "  auth_link (&auth_"$authenticator");		/* link in the $authenticator authenticator */" | cat >> linkage.c
+  echo "#include \"auth_"$authenticator".c\"" >> auths.c
+done
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/mmdf.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,2549 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	MMDF mail routines
+ *
+ * Author:	Mark Crispin
+ *		UW Technology
+ *		University of Washington
+ *		Seattle, WA  98195
+ *		Internet: MRC@Washington.EDU
+ *
+ * Date:	20 December 1989
+ * Last Edited:	27 March 2008
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <signal.h>
+#include "mail.h"
+#include "osdep.h"
+#include <time.h>
+#include <sys/stat.h>
+#include "pseudo.h"
+#include "fdstring.h"
+#include "misc.h"
+#include "dummy.h"
+
+/* Supposedly, this page has everything the MMDF driver needs to know about
+ * the MMDF delimiter.  By changing these macros, the MMDF driver should
+ * change with it.  Note that if you change the length of MMDFHDRTXT you
+ * also need to change the ISMMDF and RETIFMMDFWRD macros to reflect the new
+ * size.
+ */
+
+
+/* Useful MMDF constants */
+
+#define MMDFCHR '\01'		/* MMDF character */
+#define MMDFCHRS 0x01010101	/* MMDF header character spread in a word */
+				/* MMDF header text */
+#define MMDFHDRTXT "\01\01\01\01\n"
+				/* length of MMDF header text */
+#define MMDFHDRLEN (sizeof (MMDFHDRTXT) - 1)
+
+
+/* Validate MMDF header
+ * Accepts: pointer to candidate string to validate as an MMDF header
+ * Returns: T if valid; else NIL
+ */
+
+#define ISMMDF(s)							\
+  ((*(s) == MMDFCHR) && ((s)[1] == MMDFCHR) && ((s)[2] == MMDFCHR) &&	\
+   ((s)[3] == MMDFCHR) && ((s)[4] == '\n'))
+
+
+/* Return if a 32-bit word has the start of an MMDF header
+ * Accepts: pointer to word of four bytes to validate as an MMDF header
+ * Returns: pointer to MMDF header, else proceeds
+ */
+
+#define RETIFMMDFWRD(s) {						\
+  if (s[3] == MMDFCHR) {						\
+    if ((s[4] == MMDFCHR) && (s[5] == MMDFCHR) && (s[6] == MMDFCHR) &&	\
+	(s[7] == '\n')) return s + 3;					\
+    else if (s[2] == MMDFCHR) {						\
+      if ((s[4] == MMDFCHR) && (s[5] == MMDFCHR) && (s[6] == '\n'))	\
+	return s + 2;							\
+      else if (s[1] == MMDFCHR) {					\
+	if ((s[4] == MMDFCHR) && (s[5] == '\n')) return s + 1;		\
+	else if ((*s == MMDFCHR) && (s[4] == '\n')) return s;		\
+      }									\
+    }									\
+  }									\
+}
+
+/* Validate line
+ * Accepts: pointer to candidate string to validate as a From header
+ *	    return pointer to end of date/time field
+ *	    return pointer to offset from t of time (hours of ``mmm dd hh:mm'')
+ *	    return pointer to offset from t of time zone (if non-zero)
+ * Returns: t,ti,zn set if valid From string, else ti is NIL
+ */
+
+#define VALID(s,x,ti,zn) {						\
+  ti = 0;								\
+  if ((*s == 'F') && (s[1] == 'r') && (s[2] == 'o') && (s[3] == 'm') &&	\
+      (s[4] == ' ')) {							\
+    for (x = s + 5; *x && *x != '\n'; x++);				\
+    if (*x) {								\
+      if (x - s >= 41) {						\
+	for (zn = -1; x[zn] != ' '; zn--);				\
+	if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') &&	\
+	    (x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') &&	\
+	    (x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') &&	\
+	    (x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))\
+	  x += zn - 12;							\
+      }									\
+      if (x - s >= 27) {						\
+	if (x[-5] == ' ') {						\
+	  if (x[-8] == ':') zn = 0,ti = -5;				\
+	  else if (x[-9] == ' ') ti = zn = -9;				\
+	  else if ((x[-11] == ' ') && ((x[-10]=='+') || (x[-10]=='-')))	\
+	    ti = zn = -11;						\
+	}								\
+	else if (x[-4] == ' ') {					\
+	  if (x[-9] == ' ') zn = -4,ti = -9;				\
+	}								\
+	else if (x[-6] == ' ') {					\
+	  if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-')))	\
+	    zn = -6,ti = -11;						\
+	}								\
+	if (ti && !((x[ti - 3] == ':') &&				\
+		    (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') &&	\
+		    (x[ti - 3] == ' ') && (x[ti - 7] == ' ') &&		\
+		    (x[ti - 11] == ' '))) ti = 0;			\
+      }									\
+    }									\
+  }									\
+}
+
+/* You are not expected to understand this macro, but read the next page if
+ * you are not faint of heart.
+ *
+ * Known formats to the VALID macro are:
+ *		From user Wed Dec  2 05:53 1992
+ * BSD		From user Wed Dec  2 05:53:22 1992
+ * SysV		From user Wed Dec  2 05:53 PST 1992
+ * rn		From user Wed Dec  2 05:53:22 PST 1992
+ *		From user Wed Dec  2 05:53 -0700 1992
+ * emacs	From user Wed Dec  2 05:53:22 -0700 1992
+ *		From user Wed Dec  2 05:53 1992 PST
+ *		From user Wed Dec  2 05:53:22 1992 PST
+ *		From user Wed Dec  2 05:53 1992 -0700
+ * Solaris	From user Wed Dec  2 05:53:22 1992 -0700
+ *
+ * Plus all of the above with `` remote from xxx'' after it. Thank you very
+ * much, smail and Solaris, for making my life considerably more complicated.
+ */
+
+/*
+ * What?  You want to understand the VALID macro anyway?  Alright, since you
+ * insist.  Actually, it isn't really all that difficult, provided that you
+ * take it step by step.
+ *
+ * Line 1	Initializes the return ti value to failure (0);
+ * Lines 2-3	Validates that the 1st-5th characters are ``From ''.
+ * Lines 4-5	Validates that there is an end of line and points x at it.
+ * Lines 6-13	First checks to see if the line is at least 41 characters long.
+ *		If so, it scans backwards to find the rightmost space.  From
+ *		that point, it scans backwards to see if the string matches
+ *		`` remote from''.  If so, it sets x to point to the space at
+ *		the start of the string.
+ * Line 14	Makes sure that there are at least 27 characters in the line.
+ * Lines 15-20	Checks if the date/time ends with the year (there is a space
+ *		five characters back).  If there is a colon three characters
+ *		further back, there is no timezone field, so zn is set to 0
+ *		and ti is set in front of the year.  Otherwise, there must
+ *		either to be a space four characters back for a three-letter
+ *		timezone, or a space six characters back followed by a + or -
+ *		for a numeric timezone; in either case, zn and ti become the
+ *		offset of the space immediately before it.
+ * Lines 21-23	Are the failure case for line 14.  If there is a space four
+ *		characters back, it is a three-letter timezone; there must be a
+ *		space for the year nine characters back.  zn is the zone
+ *		offset; ti is the offset of the space.
+ * Lines 24-27	Are the failure case for line 20.  If there is a space six
+ *		characters back, it is a numeric timezone; there must be a
+ *		space eleven characters back and a + or - five characters back.
+ *		zn is the zone offset; ti is the offset of the space.
+ * Line 28-31	If ti is valid, make sure that the string before ti is of the
+ *		form www mmm dd hh:mm or www mmm dd hh:mm:ss, otherwise
+ *		invalidate ti.  There must be a colon three characters back
+ *		and a space six or nine	characters back (depending upon
+ *		whether or not the character six characters back is a colon).
+ *		There must be a space three characters further back (in front
+ *		of the day), one seven characters back (in front of the month),
+ *		and one eleven characters back (in front of the day of week).
+ *		ti is set to be the offset of the space before the time.
+ *
+ * Why a macro?  It gets invoked a *lot* in a tight loop.  On some of the
+ * newer pipelined machines it is faster being open-coded than it would be if
+ * subroutines are called.
+ *
+ * Why does it scan backwards from the end of the line, instead of doing the
+ * much easier forward scan?  There is no deterministic way to parse the
+ * ``user'' field, because it may contain unquoted spaces!  Yes, I tested it to
+ * see if unquoted spaces were possible.  They are, and I've encountered enough
+ * evil mail to be totally unwilling to trust that ``it will never happen''.
+ */
+
+/* Build parameters */
+
+#define KODRETRY 15		/* kiss-of-death retry in seconds */
+#define LOCKTIMEOUT 5		/* lock timeout in minutes */
+
+
+/* MMDF I/O stream local data */
+
+typedef struct mmdf_local {
+  unsigned int dirty : 1;	/* disk copy needs updating */
+  unsigned int ddirty : 1;	/* double-dirty, ping becomes checkpoint */
+  unsigned int pseudo : 1;	/* uses a pseudo message */
+  unsigned int appending : 1;	/* don't mark new messages as old */
+  int fd;			/* mailbox file descriptor */
+  int ld;			/* lock file descriptor */
+  char *lname;			/* lock file name */
+  off_t filesize;		/* file size parsed */
+  time_t filetime;		/* last file time */
+  unsigned char *buf;		/* temporary buffer */
+  unsigned long buflen;		/* current size of temporary buffer */
+  unsigned long uid;		/* current text uid */
+  SIZEDTEXT text;		/* current text */
+  unsigned long textlen;	/* current text length */
+  char *line;			/* returned line */
+  char *linebuf;		/* line readin buffer */
+  unsigned long linebuflen;	/* current line readin buffer length */
+} MMDFLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((MMDFLOCAL *) stream->local)
+
+
+/* MMDF protected file structure */
+
+typedef struct mmdf_file {
+  MAILSTREAM *stream;		/* current stream */
+  off_t curpos;			/* current file position */
+  off_t protect;		/* protected position */
+  off_t filepos;		/* current last written file position */
+  char *buf;			/* overflow buffer */
+  size_t buflen;		/* current overflow buffer length */
+  char *bufpos;			/* current buffer position */
+} MMDFFILE;
+
+/* Function prototypes */
+
+DRIVER *mmdf_valid (char *name);
+long mmdf_isvalid (char *name,char *tmp);
+long mmdf_isvalid_fd (int fd,char *tmp);
+void *mmdf_parameters (long function,void *value);
+void mmdf_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void mmdf_list (MAILSTREAM *stream,char *ref,char *pat);
+void mmdf_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long mmdf_create (MAILSTREAM *stream,char *mailbox);
+long mmdf_delete (MAILSTREAM *stream,char *mailbox);
+long mmdf_rename (MAILSTREAM *stream,char *old,char *newname);
+MAILSTREAM *mmdf_open (MAILSTREAM *stream);
+void mmdf_close (MAILSTREAM *stream,long options);
+char *mmdf_header (MAILSTREAM *stream,unsigned long msgno,
+		   unsigned long *length,long flags);
+long mmdf_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+char *mmdf_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
+		      unsigned long *length,long flags);
+void mmdf_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
+long mmdf_ping (MAILSTREAM *stream);
+void mmdf_check (MAILSTREAM *stream);
+long mmdf_expunge (MAILSTREAM *stream,char *sequence,long options);
+long mmdf_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long mmdf_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+int mmdf_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
+		     STRING *msg);
+int mmdf_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set);
+
+void mmdf_abort (MAILSTREAM *stream);
+char *mmdf_file (char *dst,char *name);
+int mmdf_lock (char *file,int flags,int mode,DOTLOCK *lock,int op);
+void mmdf_unlock (int fd,MAILSTREAM *stream,DOTLOCK *lock);
+int mmdf_parse (MAILSTREAM *stream,DOTLOCK *lock,int op);
+char *mmdf_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size);
+unsigned long mmdf_pseudo (MAILSTREAM *stream,char *hdr);
+unsigned long mmdf_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt,
+			    unsigned long uid,long flag);
+long mmdf_rewrite (MAILSTREAM *stream,unsigned long *nexp,DOTLOCK *lock,
+		   long flags);
+long mmdf_extend (MAILSTREAM *stream,unsigned long size);
+void mmdf_write (MMDFFILE *f,char *s,unsigned long i);
+void mmdf_phys_write (MMDFFILE *f,char *buf,size_t size);
+
+/* MMDF mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER mmdfdriver = {
+  "mmdf",			/* driver name */
+				/* driver flags */
+  DR_LOCAL|DR_MAIL|DR_LOCKING|DR_NONEWMAILRONLY|DR_XPOINT,
+  (DRIVER *) NIL,		/* next driver */
+  mmdf_valid,			/* mailbox is valid for us */
+  mmdf_parameters,		/* manipulate parameters */
+  mmdf_scan,			/* scan mailboxes */
+  mmdf_list,			/* list mailboxes */
+  mmdf_lsub,			/* list subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  mmdf_create,			/* create mailbox */
+  mmdf_delete,			/* delete mailbox */
+  mmdf_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  mmdf_open,			/* open mailbox */
+  mmdf_close,			/* close mailbox */
+  NIL,				/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  mmdf_header,			/* fetch message header */
+  mmdf_text,			/* fetch message text */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  NIL,				/* modify flags */
+  mmdf_flagmsg,			/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  mmdf_ping,			/* ping mailbox to see if still alive */
+  mmdf_check,			/* check for new messages */
+  mmdf_expunge,			/* expunge deleted messages */
+  mmdf_copy,			/* copy messages to another mailbox */
+  mmdf_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM mmdfproto = {&mmdfdriver};
+
+char *mmdfhdr = MMDFHDRTXT;	/* MMDF header */
+
+/* MMDF mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *mmdf_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+  return mmdf_isvalid (name,tmp) ? &mmdfdriver : NIL;
+}
+
+
+/* MMDF mail test for valid mailbox name
+ * Accepts: mailbox name
+ *	    scratch buffer
+ * Returns: T if valid, NIL otherwise
+ */
+
+long mmdf_isvalid (char *name,char *tmp)
+{
+  int fd;
+  int ret = NIL;
+  char *t,file[MAILTMPLEN];
+  struct stat sbuf;
+  time_t tp[2];
+  errno = EINVAL;		/* assume invalid argument */
+				/* must be non-empty file */
+  if ((t = dummy_file (file,name)) && !stat (t,&sbuf)) {
+    if (!sbuf.st_size)errno = 0;/* empty file */
+    else if ((fd = open (file,O_RDONLY,NIL)) >= 0) {
+				/* error -1 for invalid format */
+      if (!(ret = mmdf_isvalid_fd (fd,tmp))) errno = -1;
+      close (fd);		/* close the file */
+				/* \Marked status? */
+      if ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) {
+	tp[0] = sbuf.st_atime;	/* preserve atime and mtime */
+	tp[1] = sbuf.st_mtime;
+	utime (file,tp);	/* set the times */
+      }
+    }
+  }
+  return ret;			/* return what we should */
+}
+
+/* MMDF mail test for valid mailbox
+ * Accepts: file descriptor
+ *	    scratch buffer
+ * Returns: T if valid, NIL otherwise
+ */
+
+long mmdf_isvalid_fd (int fd,char *tmp)
+{
+  int ret = NIL;
+  memset (tmp,'\0',MAILTMPLEN);
+  if (read (fd,tmp,MAILTMPLEN-1) >= 0) ret = ISMMDF (tmp) ? T : NIL;
+  return ret;			/* return what we should */
+}
+
+
+/* MMDF manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *mmdf_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case GET_INBOXPATH:
+    if (value) ret = dummy_file ((char *) value,"INBOX");
+    break;
+  }
+  return ret;
+}
+
+/* MMDF mail scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void mmdf_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* MMDF mail list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mmdf_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_list (NIL,ref,pat);
+}
+
+
+/* MMDF mail list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mmdf_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_lsub (NIL,ref,pat);
+}
+
+/* MMDF mail create mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long mmdf_create (MAILSTREAM *stream,char *mailbox)
+{
+  char *s,mbx[MAILTMPLEN],tmp[MAILTMPLEN];
+  long ret = NIL;
+  int i,fd;
+  time_t ti = time (0);
+  if (!(s = dummy_file (mbx,mailbox))) {
+    sprintf (tmp,"Can't create %.80s: invalid name",mailbox);
+    MM_LOG (tmp,ERROR);
+  }
+				/* create underlying file */
+  else if (dummy_create_path (stream,s,get_dir_protection (mailbox))) {
+				/* done if dir-only or whiner */
+    if (((s = strrchr (s,'/')) && !s[1]) ||
+	mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) ret = T;
+    else if ((fd = open (mbx,O_WRONLY,
+		    (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0) {
+      sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno));
+      MM_LOG (tmp,ERROR);
+      unlink (mbx);		/* delete the file */
+    }
+    else {			/* initialize header */
+      memset (tmp,'\0',MAILTMPLEN);
+      sprintf (tmp,"%sFrom %s %sDate: ",mmdfhdr,pseudo_from,ctime (&ti));
+      rfc822_date (s = tmp + strlen (tmp));
+      sprintf (s += strlen (s),	/* write the pseudo-header */
+	       "\nFrom: %s <%s@%s>\nSubject: %s\nX-IMAP: %010lu 0000000000",
+	       pseudo_name,pseudo_from,mylocalhost (),pseudo_subject,
+	       (unsigned long) ti);
+      for (i = 0; i < NUSERFLAGS; ++i) if (default_user_flag (i))
+	sprintf (s += strlen (s)," %s",default_user_flag (i));
+      sprintf (s += strlen (s),"\nStatus: RO\n\n%s\n%s",pseudo_msg,mmdfhdr);
+      if (write (fd,tmp,strlen (tmp)) > 0) ret = T;
+      else {
+	sprintf (tmp,"Can't initialize mailbox node %.80s: %s",mbx,
+		 strerror (errno));
+	MM_LOG (tmp,ERROR);
+	unlink (mbx);		/* delete the file */
+      }
+      close (fd);		/* close file */
+    }
+  }
+				/* set proper protections */
+  return ret ? set_mbx_protections (mailbox,mbx) : NIL;
+}
+
+/* MMDF mail delete mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long mmdf_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return mmdf_rename (stream,mailbox,NIL);
+}
+
+
+/* MMDF mail rename mailbox
+ * Accepts: MAIL stream
+ *	    old mailbox name
+ *	    new mailbox name (or NIL for delete)
+ * Returns: T on success, NIL on failure
+ */
+
+long mmdf_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  long ret = NIL;
+  char c,*s = NIL;
+  char tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  DOTLOCK lockx;
+  int fd,ld;
+  long i;
+  struct stat sbuf;
+  MM_CRITICAL (stream);	/* get the c-client lock */
+  if (!dummy_file (file,old) ||
+      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
+		   ((s = strrchr (tmp,'/')) && !s[1]))))
+    sprintf (tmp,newname ?
+	     "Can't rename mailbox %.80s to %.80s: invalid name" :
+	     "Can't delete mailbox %.80s: invalid name",
+	     old,newname);
+				/* lock out other c-clients */
+  else if ((ld = lockname (lock,file,LOCK_EX|LOCK_NB,&i)) < 0)
+    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
+
+  else {
+    if ((fd = mmdf_lock (file,O_RDWR,
+			 (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
+			 &lockx,LOCK_EX)) < 0)
+       sprintf (tmp,"Can't lock mailbox %.80s: %s",old,strerror (errno));
+    else {
+      if (newname) {		/* want rename? */
+				/* found superior to destination name? */
+	if (s = strrchr (s,'/')) {
+	  c = *++s;		/* remember first character of inferior */
+	  *s = '\0';		/* tie off to get just superior */
+				/* name doesn't exist, create it */
+	  if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+	      !dummy_create_path (stream,tmp,get_dir_protection (newname))) {
+	    mmdf_unlock (fd,NIL,&lockx);
+	    mmdf_unlock (ld,NIL,NIL);
+	    unlink (lock);
+	    MM_NOCRITICAL (stream);
+	    return ret;		/* return success or failure */
+	  }
+	  *s = c;		/* restore full name */
+	}
+	if (rename (file,tmp))
+	  sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
+		   strerror (errno));
+	else ret = T;		/* set success */
+      }
+      else if (unlink (file))
+	sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
+      else ret = T;		/* set success */
+      mmdf_unlock (fd,NIL,&lockx);
+    }
+    mmdf_unlock (ld,NIL,NIL);	/* flush the lock */
+    unlink (lock);
+  }
+  MM_NOCRITICAL (stream);	/* no longer critical */
+  if (!ret) MM_LOG (tmp,ERROR);	/* log error */
+  return ret;			/* return success or failure */
+}
+
+/* MMDF mail open
+ * Accepts: Stream to open
+ * Returns: Stream on success, NIL on failure
+ */
+
+MAILSTREAM *mmdf_open (MAILSTREAM *stream)
+{
+  long i;
+  int fd;
+  char tmp[MAILTMPLEN];
+  DOTLOCK lock;
+  long retry;
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return user_flags (&mmdfproto);
+  retry = stream->silent ? 1 : KODRETRY;
+  if (stream->local) fatal ("mmdf recycle stream");
+  stream->local = memset (fs_get (sizeof (MMDFLOCAL)),0,sizeof (MMDFLOCAL));
+				/* note if an INBOX or not */
+  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
+				/* canonicalize the stream mailbox name */
+  if (!dummy_file (tmp,stream->mailbox)) {
+    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+				/* flush old name */
+  fs_give ((void **) &stream->mailbox);
+				/* save canonical name */
+  stream->mailbox = cpystr (tmp);
+  LOCAL->fd = LOCAL->ld = -1;	/* no file or state locking yet */
+  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
+  LOCAL->buflen = CHUNKSIZE - 1;
+  LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE);
+  LOCAL->text.size = CHUNKSIZE - 1;
+  LOCAL->linebuf = (char *) fs_get (CHUNKSIZE);
+  LOCAL->linebuflen = CHUNKSIZE - 1;
+  stream->sequence++;		/* bump sequence number */
+
+				/* make lock for read/write access */
+  if (!stream->rdonly) while (retry) {
+				/* try to lock file */
+    if ((fd = lockname (tmp,stream->mailbox,LOCK_EX|LOCK_NB,&i)) < 0) {
+				/* suppressing kiss-of-death? */
+      if (stream->nokod) retry = 0;
+				/* no, first time through? */
+      else if (retry-- == KODRETRY) {
+				/* learned other guy's PID and can signal? */
+	if (i && !kill ((int) i,SIGUSR2)) {
+	  sprintf (tmp,"Trying to get mailbox lock from process %ld",i);
+	  MM_LOG (tmp,WARN);
+	}
+	else retry = 0;		/* give up */
+      }
+      if (!stream->silent) {	/* nothing if silent stream */
+	if (retry) sleep (1);	/* wait a second before trying again */
+	else MM_LOG ("Mailbox is open by another process, access is readonly",
+		     WARN);
+      }
+    }
+    else {			/* got the lock, nobody else can alter state */
+      LOCAL->ld = fd;		/* note lock's fd and name */
+      LOCAL->lname = cpystr (tmp);
+				/* make sure mode OK (don't use fchmod()) */
+      chmod (LOCAL->lname,(long) mail_parameters (NIL,GET_LOCKPROTECTION,NIL));
+      if (stream->silent) i = 0;/* silent streams won't accept KOD */
+      else {			/* note our PID in the lock */
+	sprintf (tmp,"%d",getpid ());
+	write (fd,tmp,(i = strlen (tmp))+1);
+      }
+      ftruncate (fd,i);		/* make sure tied off */
+      fsync (fd);		/* make sure it's available */
+      retry = 0;		/* no more need to try */
+    }
+  }
+
+				/* parse mailbox */
+  stream->nmsgs = stream->recent = 0;
+				/* will we be able to get write access? */
+  if ((LOCAL->ld >= 0) && access (stream->mailbox,W_OK) && (errno == EACCES)) {
+    MM_LOG ("Can't get write access to mailbox, access is readonly",WARN);
+    flock (LOCAL->ld,LOCK_UN);	/* release the lock */
+    close (LOCAL->ld);		/* close the lock file */
+    LOCAL->ld = -1;		/* no more lock fd */
+    unlink (LOCAL->lname);	/* delete it */
+  }
+				/* reset UID validity */
+  stream->uid_validity = stream->uid_last = 0;
+  if (stream->silent && !stream->rdonly && (LOCAL->ld < 0))
+    mmdf_abort (stream);	/* abort if can't get RW silent stream */
+				/* parse mailbox */
+  else if (mmdf_parse (stream,&lock,LOCK_SH)) {
+    mmdf_unlock (LOCAL->fd,stream,&lock);
+    mail_unlock (stream);
+    MM_NOCRITICAL (stream);	/* done with critical */
+  }
+  if (!LOCAL) return NIL;	/* failure if stream died */
+				/* make sure upper level knows readonly */
+  stream->rdonly = (LOCAL->ld < 0);
+				/* notify about empty mailbox */
+  if (!(stream->nmsgs || stream->silent)) MM_LOG ("Mailbox is empty",NIL);
+  if (!stream->rdonly) {	/* flags stick if readwrite */
+    stream->perm_seen = stream->perm_deleted =
+      stream->perm_flagged = stream->perm_answered = stream->perm_draft = T;
+    if (!stream->uid_nosticky) {/* users with lives get permanent keywords */
+      stream->perm_user_flags = 0xffffffff;
+				/* and maybe can create them too! */
+      stream->kwd_create = stream->user_flags[NUSERFLAGS-1] ? NIL : T;
+    }
+  }
+  return stream;		/* return stream alive to caller */
+}
+
+
+/* MMDF mail close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void mmdf_close (MAILSTREAM *stream,long options)
+{
+  int silent = stream->silent;
+  stream->silent = T;		/* go silent */
+				/* expunge if requested */
+  if (options & CL_EXPUNGE) mmdf_expunge (stream,NIL,NIL);
+				/* else dump final checkpoint */
+  else if (LOCAL->dirty) mmdf_check (stream);
+  stream->silent = silent;	/* restore old silence state */
+  mmdf_abort (stream);		/* now punt the file and local data */
+}
+
+/* MMDF mail fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+				/* lines to filter from header */
+static STRINGLIST *mmdf_hlines = NIL;
+
+char *mmdf_header (MAILSTREAM *stream,unsigned long msgno,
+		   unsigned long *length,long flags)
+{
+  MESSAGECACHE *elt;
+  unsigned char *s,*t,*tl;
+  *length = 0;			/* default to empty */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+  elt = mail_elt (stream,msgno);/* get cache */
+  if (!mmdf_hlines) {		/* once only code */
+    STRINGLIST *lines = mmdf_hlines = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "Status"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-Status"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-Keywords"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-UID"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-IMAP"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-IMAPbase"));
+  }
+				/* go to header position */
+  lseek (LOCAL->fd,elt->private.special.offset +
+	 elt->private.msg.header.offset,L_SET);
+
+  if (flags & FT_INTERNAL) {	/* initial data OK? */
+    if (elt->private.msg.header.text.size > LOCAL->buflen) {
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
+				     elt->private.msg.header.text.size) + 1);
+    }
+				/* read message */
+    read (LOCAL->fd,LOCAL->buf,elt->private.msg.header.text.size);
+				/* got text, tie off string */
+    LOCAL->buf[*length = elt->private.msg.header.text.size] = '\0';
+				/* squeeze out CRs (in case from PC) */
+    for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++)
+      if (*t != '\r') *s++ = *t;
+    *s = '\0';
+    *length = s - LOCAL->buf;	/* adjust length */
+  }
+  else {			/* need to make a CRLF version */
+    read (LOCAL->fd,s = (char *) fs_get (elt->private.msg.header.text.size+1),
+	  elt->private.msg.header.text.size);
+				/* tie off string, and convert to CRLF */
+    s[elt->private.msg.header.text.size] = '\0';
+    *length = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen,s,
+			  elt->private.msg.header.text.size);
+    fs_give ((void **) &s);	/* free readin buffer */
+				/* squeeze out spurious CRs */
+    for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++)
+      if ((*t != '\r') || (t[1] == '\n')) *s++ = *t;
+    *s = '\0';
+    *length = s - LOCAL->buf;	/* adjust length */
+  }
+  *length = mail_filter (LOCAL->buf,*length,mmdf_hlines,FT_NOT);
+  return (char *) LOCAL->buf;	/* return processed copy */
+}
+
+/* MMDF mail fetch message text
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned stringstruct
+ *	    option flags
+ * Returns: T on success, NIL if failure
+ */
+
+long mmdf_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  char *s;
+  unsigned long i;
+  MESSAGECACHE *elt;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+  elt = mail_elt (stream,msgno);/* get cache element */
+				/* if message not seen */
+  if (!(flags & FT_PEEK) && !elt->seen) {
+				/* mark message seen and dirty */
+    elt->seen = elt->private.dirty = LOCAL->dirty = T;
+    MM_FLAGS (stream,msgno);
+  }
+  s = mmdf_text_work (stream,elt,&i,flags);
+  INIT (bs,mail_string,s,i);	/* set up stringstruct */
+  return T;			/* success */
+}
+
+/* MMDF mail fetch message text worker routine
+ * Accepts: MAIL stream
+ *	    message cache element
+ *	    pointer to returned header text length
+ *	    option flags
+ */
+
+char *mmdf_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
+		      unsigned long *length,long flags)
+{
+  FDDATA d;
+  STRING bs;
+  unsigned char c,*s,*t,*tl,tmp[CHUNKSIZE];
+				/* go to text position */
+  lseek (LOCAL->fd,elt->private.special.offset +
+	 elt->private.msg.text.offset,L_SET);
+  if (flags & FT_INTERNAL) {	/* initial data OK? */
+    if (elt->private.msg.text.text.size > LOCAL->buflen) {
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
+				     elt->private.msg.text.text.size) + 1);
+    }
+				/* read message */
+    read (LOCAL->fd,LOCAL->buf,elt->private.msg.text.text.size);
+				/* got text, tie off string */
+    LOCAL->buf[*length = elt->private.msg.text.text.size] = '\0';
+				/* squeeze out CRs (in case from PC) */
+    for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++)
+      if (*t != '\r') *s++ = *t;
+    *s = '\0';
+    *length = s - LOCAL->buf;	/* adjust length */
+    return (char *) LOCAL->buf;
+  }
+
+				/* have it cached already? */
+  if (elt->private.uid != LOCAL->uid) {
+				/* not cached, cache it now */
+    LOCAL->uid = elt->private.uid;
+				/* is buffer big enough? */
+    if (elt->rfc822_size > LOCAL->text.size) {
+      /* excessively conservative, but the right thing is too hard to do */
+      fs_give ((void **) &LOCAL->text.data);
+      LOCAL->text.data = (unsigned char *)
+	fs_get ((LOCAL->text.size = elt->rfc822_size) + 1);
+    }
+    d.fd = LOCAL->fd;		/* yes, set up file descriptor */
+    d.pos = elt->private.special.offset + elt->private.msg.text.offset;
+    d.chunk = tmp;		/* initial buffer chunk */
+    d.chunksize = CHUNKSIZE;	/* file chunk size */
+    INIT (&bs,fd_string,&d,elt->private.msg.text.text.size);
+    for (s = (char *) LOCAL->text.data; SIZE (&bs);) switch (c = SNX (&bs)) {
+    case '\r':			/* carriage return seen */
+      break;
+    case '\n':
+      *s++ = '\r';		/* insert a CR */
+    default:
+      *s++ = c;			/* copy characters */
+    }
+    *s = '\0';			/* tie off buffer */
+				/* calculate length of cached data */
+    LOCAL->textlen = s - LOCAL->text.data;
+  }
+  *length = LOCAL->textlen;	/* return from cache */
+  return (char *) LOCAL->text.data;
+}
+
+/* MMDF per-message modify flag
+ * Accepts: MAIL stream
+ *	    message cache element
+ */
+
+void mmdf_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+				/* only after finishing */
+  if (elt->valid) elt->private.dirty = LOCAL->dirty = T;
+}
+
+
+/* MMDF mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ */
+
+long mmdf_ping (MAILSTREAM *stream)
+{
+  DOTLOCK lock;
+  struct stat sbuf;
+  long reparse;
+				/* big no-op if not readwrite */
+  if (LOCAL && (LOCAL->ld >= 0) && !stream->lock) {
+    if (stream->rdonly) {	/* does he want to give up readwrite? */
+				/* checkpoint if we changed something */
+      if (LOCAL->dirty) mmdf_check (stream);
+      flock (LOCAL->ld,LOCK_UN);/* release readwrite lock */
+      close (LOCAL->ld);	/* close the readwrite lock file */
+      LOCAL->ld = -1;		/* no more readwrite lock fd */
+      unlink (LOCAL->lname);	/* delete the readwrite lock file */
+    }
+    else {			/* see if need to reparse */
+      if (!(reparse = (long) mail_parameters (NIL,GET_NETFSSTATBUG,NIL))) {
+				/* get current mailbox size */
+	if (LOCAL->fd >= 0) fstat (LOCAL->fd,&sbuf);
+	else if (stat (stream->mailbox,&sbuf)) {
+	  sprintf (LOCAL->buf,"Mailbox stat failed, aborted: %s",
+		   strerror (errno));
+	  MM_LOG (LOCAL->buf,ERROR);
+	  mmdf_abort (stream);
+	  return NIL;
+	}
+	reparse = (sbuf.st_size != LOCAL->filesize);
+      }
+				/* parse if mailbox changed */
+      if ((LOCAL->ddirty || reparse) && mmdf_parse (stream,&lock,LOCK_EX)) {
+				/* force checkpoint if double-dirty */
+	if (LOCAL->ddirty) mmdf_rewrite (stream,NIL,&lock,NIL);
+				/* unlock mailbox */
+	else mmdf_unlock (LOCAL->fd,stream,&lock);
+	mail_unlock (stream);	/* and stream */
+				/* done with critical */
+	MM_NOCRITICAL (stream);
+      }
+    }
+  }
+  return LOCAL ? LONGT : NIL;	/* return if still alive */
+}
+
+/* MMDF mail check mailbox
+ * Accepts: MAIL stream
+ */
+
+void mmdf_check (MAILSTREAM *stream)
+{
+  DOTLOCK lock;
+				/* parse and lock mailbox */
+  if (LOCAL && (LOCAL->ld >= 0) && !stream->lock &&
+      mmdf_parse (stream,&lock,LOCK_EX)) {
+				/* any unsaved changes? */
+    if (LOCAL->dirty && mmdf_rewrite (stream,NIL,&lock,NIL)) {
+      if (!stream->silent) MM_LOG ("Checkpoint completed",NIL);
+    }
+				/* no checkpoint needed, just unlock */
+    else mmdf_unlock (LOCAL->fd,stream,&lock);
+    mail_unlock (stream);	/* unlock the stream */
+    MM_NOCRITICAL (stream);	/* done with critical */
+  }
+}
+
+
+/* MMDF mail expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long mmdf_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  long ret;
+  unsigned long i;
+  DOTLOCK lock;
+  char *msg = NIL;
+  if (ret = (sequence ? ((options & EX_UID) ?
+			 mail_uid_sequence (stream,sequence) :
+			 mail_sequence (stream,sequence)) : LONGT) &&
+      LOCAL && (LOCAL->ld >= 0) && !stream->lock &&
+      mmdf_parse (stream,&lock,LOCK_EX)) {
+				/* check expunged messages if not dirty */
+    for (i = 1; !LOCAL->dirty && (i <= stream->nmsgs); i++) {
+      MESSAGECACHE *elt = mail_elt (stream,i);
+      if (mail_elt (stream,i)->deleted) LOCAL->dirty = T;
+    }
+    if (!LOCAL->dirty) {	/* not dirty and no expunged messages */
+      mmdf_unlock (LOCAL->fd,stream,&lock);
+      msg = "No messages deleted, so no update needed";
+    }
+    else if (mmdf_rewrite (stream,&i,&lock,sequence ? LONGT : NIL)) {
+      if (i) sprintf (msg = LOCAL->buf,"Expunged %lu messages",i);
+      else msg = "Mailbox checkpointed, but no messages expunged";
+    }
+				/* rewrite failed */
+    else mmdf_unlock (LOCAL->fd,stream,&lock);
+    mail_unlock (stream);	/* unlock the stream */
+    MM_NOCRITICAL (stream);	/* done with critical */
+    if (msg && !stream->silent) MM_LOG (msg,NIL);
+  }
+  else if (!stream->silent)
+    MM_LOG ("Expunge ignored on readonly mailbox",WARN);
+  return ret;
+}
+
+/* MMDF mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if copy successful, else NIL
+ */
+
+long mmdf_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  struct stat sbuf;
+  int fd;
+  char *s,file[MAILTMPLEN];
+  DOTLOCK lock;
+  time_t tp[2];
+  unsigned long i,j;
+  MESSAGECACHE *elt;
+  long ret = T;
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+  copyuid_t cu = (copyuid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ?
+			      NIL : mail_parameters (NIL,GET_COPYUID,NIL));
+  SEARCHSET *source = cu ? mail_newsearchset () : NIL;
+  SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
+  MAILSTREAM *tstream = NIL;
+  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+	mail_sequence (stream,sequence))) return NIL;
+				/* make sure destination is valid */
+  if (!(mmdf_valid (mailbox) || !errno))
+    switch (errno) {
+    case ENOENT:		/* no such file? */
+      if (compare_cstring (mailbox,"INBOX")) {
+	MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
+	return NIL;
+      }
+      if (pc) return (*pc) (stream,sequence,mailbox,options);
+      mmdf_create (NIL,"INBOX");/* create empty INBOX */
+    case EACCES:		/* file protected */
+      sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
+      MM_LOG (LOCAL->buf,ERROR);
+      return NIL;
+    case EINVAL:
+      if (pc) return (*pc) (stream,sequence,mailbox,options);
+      sprintf (LOCAL->buf,"Invalid MMDF-format mailbox name: %.80s",mailbox);
+      MM_LOG (LOCAL->buf,ERROR);
+      return NIL;
+    default:
+      if (pc) return (*pc) (stream,sequence,mailbox,options);
+      sprintf (LOCAL->buf,"Not a MMDF-format mailbox: %.80s",mailbox);
+      MM_LOG (LOCAL->buf,ERROR);
+      return NIL;
+    }
+
+				/* try to open rewrite for UIDPLUS */
+  if ((tstream = mail_open_work (&mmdfdriver,NIL,mailbox,
+				 OP_SILENT|OP_NOKOD)) && tstream->rdonly)
+    tstream = mail_close (tstream);
+  if (cu && !tstream) {		/* wanted a COPYUID? */
+    sprintf (LOCAL->buf,"Unable to write-open mailbox for COPYUID: %.80s",
+	     mailbox);
+    MM_LOG (LOCAL->buf,WARN);
+    cu = NIL;			/* don't try to do COPYUID */
+  }
+  LOCAL->buf[0] = '\0';
+  MM_CRITICAL (stream);		/* go critical */
+  if ((fd = mmdf_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND,
+		       (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
+		       &lock,LOCK_EX)) < 0) {
+    MM_NOCRITICAL (stream);	/* done with critical */
+    sprintf (LOCAL->buf,"Can't open destination mailbox: %s",strerror (errno));
+    MM_LOG (LOCAL->buf,ERROR);	/* log the error */
+    return NIL;			/* failed */
+  }
+  fstat (fd,&sbuf);		/* get current file size */
+				/* write all requested messages to mailbox */
+  for (i = 1; ret && (i <= stream->nmsgs); i++)
+    if ((elt = mail_elt (stream,i))->sequence) {
+      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
+      read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size);
+      if (write (fd,LOCAL->buf,elt->private.special.text.size) < 0) ret = NIL;
+      else {			/* internal header succeeded */
+	s = mmdf_header (stream,i,&j,FT_INTERNAL);
+				/* header size, sans trailing newline */
+	if (j && (s[j - 2] == '\n')) j--;
+	if (write (fd,s,j) < 0) ret = NIL;
+	else {			/* message header succeeded */
+	  j = tstream ?		/* write UIDPLUS data if have readwrite */
+	    mmdf_xstatus (stream,LOCAL->buf,elt,++(tstream->uid_last),LONGT) :
+	    mmdf_xstatus (stream,LOCAL->buf,elt,NIL,NIL);
+	  if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
+	  else {		/* message status succeeded */
+	    s = mmdf_text_work (stream,elt,&j,FT_INTERNAL);
+	    if ((write (fd,s,j) < 0) || (write (fd,mmdfhdr,MMDFHDRLEN) < 0))
+	      ret = NIL;
+	    else if (cu) {	/* need to pass back new UID? */
+	      mail_append_set (source,mail_uid (stream,i));
+	      mail_append_set (dest,tstream->uid_last);
+	    }
+	  }
+	}
+      }
+    }
+
+  if (!ret || fsync (fd)) {	/* force out the update */
+    sprintf (LOCAL->buf,"Message copy failed: %s",strerror (errno));
+    ftruncate (fd,sbuf.st_size);
+    ret = NIL;
+  }
+				/* force UIDVALIDITY assignment now */
+  if (tstream && !tstream->uid_validity) tstream->uid_validity = time (0);
+				/* return sets if doing COPYUID */
+  if (cu && ret) (*cu) (stream,mailbox,tstream->uid_validity,source,dest);
+  else {			/* flush any sets we may have built */
+    mail_free_searchset (&source);
+    mail_free_searchset (&dest);
+  }
+  tp[1] = time (0);		/* set mtime to now */
+  if (ret) tp[0] = tp[1] - 1;	/* set atime to now-1 if successful copy */
+  else tp[0] =			/* else preserve \Marked status */
+	 ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ?
+	 sbuf.st_atime : tp[1];
+  utime (file,tp);		/* set the times */
+  mmdf_unlock (fd,NIL,&lock);	/* unlock and close mailbox */
+  if (tstream) {		/* update last UID if we can */
+    MMDFLOCAL *local = (MMDFLOCAL *) tstream->local;
+    local->dirty = T;		/* do a rewrite */
+    local->appending = T;	/* but not at the cost of marking as old */
+    tstream = mail_close (tstream);
+  }
+				/* log the error */
+  if (!ret) MM_LOG (LOCAL->buf,ERROR);
+				/* delete if requested message */
+  else if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++)
+    if ((elt = mail_elt (stream,i))->sequence)
+      elt->deleted = elt->private.dirty = LOCAL->dirty = T;
+  MM_NOCRITICAL (stream);	/* release critical */
+  return ret;
+}
+
+/* MMDF mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+#define BUFLEN 8*MAILTMPLEN
+
+long mmdf_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct stat sbuf;
+  int fd;
+  unsigned long i;
+  char *flags,*date,buf[BUFLEN],tmp[MAILTMPLEN],file[MAILTMPLEN];
+  time_t tp[2];
+  FILE *sf,*df;
+  MESSAGECACHE elt;
+  DOTLOCK lock;
+  STRING *message;
+  unsigned long uidlocation = 0;
+  appenduid_t au = (appenduid_t)
+    (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL :
+     mail_parameters (NIL,GET_APPENDUID,NIL));
+  SEARCHSET *dst = au ? mail_newsearchset () : NIL;
+  long ret = LONGT;
+  MAILSTREAM *tstream = NIL;
+				/* default stream to prototype */
+  if (!stream) {		/* stream specified? */
+    stream = &mmdfproto;	/* no, default stream to prototype */
+    for (i = 0; i < NUSERFLAGS && stream->user_flags[i]; ++i)
+      fs_give ((void **) &stream->user_flags[i]);
+  }
+  if (!mmdf_valid (mailbox)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    if (compare_cstring (mailbox,"INBOX")) {
+      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+      return NIL;
+    }
+    mmdf_create (NIL,"INBOX");	/* create empty INBOX */
+  case 0:			/* merely empty file? */
+    tstream = stream;
+    break;
+  case EACCES:			/* file protected */
+    sprintf (tmp,"Can't access destination: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  case EINVAL:
+    sprintf (tmp,"Invalid MMDF-format mailbox name: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  default:
+    sprintf (tmp,"Not a MMDF-format mailbox: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+				/* get sniffing stream for keywords */
+  else if (!(tstream = mail_open (NIL,mailbox,
+				  OP_READONLY|OP_SILENT|OP_NOKOD|OP_SNIFF))) {
+    sprintf (tmp,"Unable to examine mailbox for APPEND: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+
+				/* get first message */
+  if (!MM_APPEND (af) (tstream,data,&flags,&date,&message)) return NIL;
+  if (!(sf = tmpfile ())) {	/* must have scratch file */
+    sprintf (tmp,".%lx.%lx",(unsigned long) time (0),(unsigned long)getpid ());
+    if (!stat (tmp,&sbuf) || !(sf = fopen (tmp,"wb+"))) {
+      sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno));
+      MM_LOG (tmp,ERROR);
+      return NIL;
+    }
+    unlink (tmp);
+  }
+  do {				/* parse date */
+    if (!date) rfc822_date (date = tmp);
+    if (!mail_parse_date (&elt,date)) {
+      sprintf (tmp,"Bad date in append: %.80s",date);
+      MM_LOG (tmp,ERROR);
+    }
+    else {			/* user wants to suppress time zones? */
+      if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) {
+	time_t when = mail_longdate (&elt);
+	date = ctime (&when);	/* use traditional date */
+      }
+				/* use POSIX-style date */
+      else date = mail_cdate (tmp,&elt);
+      if (!SIZE (message)) MM_LOG ("Append of zero-length message",ERROR);
+      else if (!mmdf_collect_msg (tstream,sf,flags,date,message)) {
+	sprintf (tmp,"Error writing scratch file: %.80s",strerror (errno));
+	MM_LOG (tmp,ERROR);
+      }
+				/* get next message */
+      else if (MM_APPEND (af) (tstream,data,&flags,&date,&message)) continue;
+    }
+    fclose (sf);		/* punt scratch file */
+    return NIL;			/* give up */
+  } while (message);		/* until no more messages */
+  if (fflush (sf)) {
+    sprintf (tmp,"Error finishing scratch file: %.80s",strerror (errno));
+    MM_LOG (tmp,ERROR);
+    fclose (sf);		/* punt scratch file */
+    return NIL;			/* give up */
+  }
+  i = ftell (sf);		/* size of scratch file */
+  if (tstream != stream) tstream = mail_close (tstream);
+
+  MM_CRITICAL (stream);		/* go critical */
+				/* try to open readwrite for UIDPLUS */
+  if ((tstream = mail_open_work (&mmdfdriver,NIL,mailbox,
+				 OP_SILENT|OP_NOKOD)) && tstream->rdonly)
+    tstream = mail_close (tstream);
+  if (au && !tstream) {		/* wanted an APPENDUID? */
+    sprintf (tmp,"Unable to re-open mailbox for APPENDUID: %.80s",mailbox);
+    MM_LOG (tmp,WARN);
+    au = NIL;
+  }
+  if (((fd = mmdf_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND,
+			(long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
+			&lock,LOCK_EX)) < 0) ||
+      !(df = fdopen (fd,"ab"))) {
+    MM_NOCRITICAL (stream);	/* done with critical */
+    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+  fstat (fd,&sbuf);		/* get current file size */
+  rewind (sf);
+  tp[1] = time (0);		/* set mtime to now */
+				/* write all messages */
+  if (!mmdf_append_msgs (tstream,sf,df,au ? dst : NIL) ||
+      (fflush (df) == EOF) || fsync (fd)) {
+    sprintf (buf,"Message append failed: %s",strerror (errno));
+    MM_LOG (buf,ERROR);
+    ftruncate (fd,sbuf.st_size);
+    tp[0] =			/* preserve \Marked status */
+      ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ?
+      sbuf.st_atime : tp[1];
+    ret = NIL;			/* return error */
+  }
+  else tp[0] = tp[1] - 1;	/* set atime to now-1 if successful copy */
+  utime (file,tp);		/* set the times */
+  fclose (sf);			/* done with scratch file */
+				/* force UIDVALIDITY assignment now */
+  if (tstream && !tstream->uid_validity) tstream->uid_validity = time (0);
+				/* return sets if doing APPENDUID */
+  if (au && ret) (*au) (mailbox,tstream->uid_validity,dst);
+  else mail_free_searchset (&dst);
+  mmdf_unlock (fd,NIL,&lock);	/* unlock and close mailbox */
+  fclose (df);
+  if (tstream) {		/* update last UID if we can */
+    MMDFLOCAL *local = (MMDFLOCAL *) tstream->local;
+    local->dirty = T;		/* do a rewrite */
+    local->appending = T;	/* but not at the cost of marking as old */
+    tstream = mail_close (tstream);
+  }
+  MM_NOCRITICAL (stream);	/* release critical */
+  return ret;
+}
+
+/* Collect and write single message to append scratch file
+ * Accepts: MAIL stream
+ *	    scratch file
+ *	    flags
+ *	    date
+ *	    message stringstruct
+ * Returns: NIL if write error, else T
+ */
+
+int mmdf_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
+  		     STRING *msg)
+{
+  unsigned char *s,*t;
+  unsigned long uf;
+  long f = mail_parse_flags (stream,flags,&uf);
+				/* write metadata, note date ends with NL */
+  if (fprintf (sf,"%ld %lu %s",f,SIZE (msg) + 1,date) < 0) return NIL;
+  while (uf)			/* write user flags */    
+    if ((s = stream->user_flags[find_rightmost_bit (&uf)]) &&
+	(fprintf (sf," %s",s) < 0)) return NIL;
+  if (putc ('\n',sf) == EOF) return NIL;
+  while (SIZE (msg)) {		/* copy text to scratch file */
+    for (s = (unsigned char *) msg->curpos, t = s + msg->cursize; s < t; ++s)
+      if (!*s) *s = 0x80;	/* disallow NUL */
+				/* write buffered text */
+    if (fwrite (msg->curpos,1,msg->cursize,sf) == msg->cursize)
+      SETPOS (msg,GETPOS (msg) + msg->cursize);
+    else return NIL;		/* failed */
+  }
+				/* write trailing newline and return */
+  return (putc ('\n',sf) == EOF) ? NIL : T;
+}
+
+/* Append messages from scratch file to mailbox
+ * Accepts: MAIL stream
+ *	    source file
+ *	    destination file
+ *	    uidset to update if non-NIL
+ * Returns: T if success, NIL if failure
+ */
+
+int mmdf_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set)
+{
+  int c;
+  long f;
+  unsigned long i,j;
+  char *x,tmp[MAILTMPLEN];
+  int hdrp = T;
+				/* get message metadata line */
+  while (fgets (tmp,MAILTMPLEN,sf)) {
+    if (!(isdigit (tmp[0]) && strchr (tmp,'\n'))) return NIL;
+    f = strtol (tmp,&x,10);	/* get flags */
+    if (!((*x++ == ' ') && isdigit (*x))) return NIL;
+    i = strtoul (x,&x,10);	/* get message size */
+    if ((*x++ != ' ') ||	/* build initial header */
+	(fprintf (df,"%sFrom %s@%s %sStatus: ",mmdfhdr,myusername(),
+		  mylocalhost(),x) < 0) ||
+	(f&fSEEN && (putc ('R',df) == EOF)) ||
+	(fputs ("\nX-Status: ",df) == EOF) ||
+	(f&fDELETED && (putc ('D',df) == EOF)) ||
+	(f&fFLAGGED && (putc ('F',df) == EOF)) ||
+	(f&fANSWERED && (putc ('A',df) == EOF)) ||
+	(f&fDRAFT && (putc ('T',df) == EOF)) ||
+	(fputs ("\nX-Keywords:",df) == EOF)) return NIL;
+				/* copy keywords */
+    while ((c = getc (sf)) != '\n') switch (c) {
+    case EOF:
+      return NIL;
+    default:
+      if (putc (c,df) == EOF) return NIL;
+    }
+    if ((putc ('\n',df) == EOF) ||
+	(set && (fprintf (df,"X-UID: %lu\n",++(stream->uid_last)) < 0)))
+      return NIL;
+
+    for (c = '\n'; i && fgets (tmp,MAILTMPLEN,sf); c = tmp[j-1]) {
+				/* get read line length */
+      if (i < (j = strlen (tmp))) fatal ("mmdf_append_msgs overrun");
+      i -= j;			/* number of bytes left */
+				/* squish out ^A and CRs (note copies NUL) */
+      for (x = tmp; x = strpbrk (x,"\01\r"); --j) memmove (x,x+1,j-(x-tmp));
+      if (!j) continue;		/* do nothing if line emptied */
+				/* start of line? */
+      if ((c == '\n')) switch (tmp[0]) {
+      case 'S': case 's':	/* possible "Status:" */
+	if (hdrp && (j > 6) && ((tmp[1] == 't') || (tmp[1] == 'T')) &&
+	    ((tmp[2] == 'a') || (tmp[2] == 'A')) &&
+	    ((tmp[3] == 't') || (tmp[3] == 'T')) &&
+	    ((tmp[4] == 'u') || (tmp[4] == 'U')) &&
+	    ((tmp[5] == 's') || (tmp[5] == 'S')) && (tmp[6] == ':') &&
+	    (fputs ("X-Original-",df) == EOF)) return NIL;
+	break;
+      case 'X': case 'x':	/* possible X-??? header */
+	if (hdrp && (tmp[1] == '-') &&
+				/* possible X-UID: */
+	    (((j > 5) && ((tmp[2] == 'U') || (tmp[2] == 'u')) &&
+	      ((tmp[3] == 'I') || (tmp[3] == 'i')) &&
+	      ((tmp[4] == 'D') || (tmp[4] == 'd')) && (tmp[5] == ':')) ||
+				/* possible X-IMAP: */
+	     ((j > 6) && ((tmp[2] == 'I') || (tmp[2] == 'i')) &&
+	      ((tmp[3] == 'M') || (tmp[3] == 'm')) &&
+	      ((tmp[4] == 'A') || (tmp[4] == 'a')) &&
+	      ((tmp[5] == 'P') || (tmp[5] == 'p')) &&
+	      ((tmp[6] == ':') ||
+				/* or X-IMAPbase: */
+	       ((j > 10) && ((tmp[6] == 'b') || (tmp[6] == 'B')) &&
+		((tmp[7] == 'a') || (tmp[7] == 'A')) &&
+		((tmp[8] == 's') || (tmp[8] == 'S')) &&
+		((tmp[9] == 'e') || (tmp[9] == 'E')) && (tmp[10] == ':')))) ||
+				/* possible X-Status: */
+	     ((j > 8) && ((tmp[2] == 'S') || (tmp[2] == 's')) &&
+	      ((tmp[3] == 't') || (tmp[3] == 'T')) &&
+	      ((tmp[4] == 'a') || (tmp[4] == 'A')) &&
+	      ((tmp[5] == 't') || (tmp[5] == 'T')) &&
+	      ((tmp[6] == 'u') || (tmp[6] == 'U')) &&
+	      ((tmp[7] == 's') || (tmp[7] == 'S')) && (tmp[8] == ':')) ||
+				/* possible X-Keywords: */
+	     ((j > 10) && ((tmp[2] == 'K') || (tmp[2] == 'k')) &&
+	      ((tmp[3] == 'e') || (tmp[3] == 'E')) &&
+	      ((tmp[4] == 'y') || (tmp[4] == 'Y')) &&
+	      ((tmp[5] == 'w') || (tmp[5] == 'W')) &&
+	      ((tmp[6] == 'o') || (tmp[6] == 'O')) &&
+	      ((tmp[7] == 'r') || (tmp[7] == 'R')) &&
+	      ((tmp[8] == 'd') || (tmp[8] == 'D')) &&
+	      ((tmp[9] == 's') || (tmp[9] == 'S')) && (tmp[10] == ':'))) &&
+	    (fputs ("X-Original-",df) == EOF)) return NIL;
+	break;
+      case '\n':		/* blank line */
+	hdrp = NIL;
+	break;
+      default:			/* nothing to do */
+	break;
+      }
+				/* just write the line */
+      if (fwrite (tmp,1,j,df) != j) return NIL;
+    }
+				/* make sure read entire msg & wrote trailer */
+    if (i || (fputs (mmdfhdr,df) == EOF)) return NIL;
+				/* update set */
+    if (stream) mail_append_set (set,stream->uid_last);
+  }
+  return T;
+}
+
+/* Internal routines */
+
+
+/* MMDF mail abort stream
+ * Accepts: MAIL stream
+ */
+
+void mmdf_abort (MAILSTREAM *stream)
+{
+  if (LOCAL) {			/* only if a file is open */
+    if (LOCAL->fd >= 0) close (LOCAL->fd);
+    if (LOCAL->ld >= 0) {	/* have a mailbox lock? */
+      flock (LOCAL->ld,LOCK_UN);/* yes, release the lock */
+      close (LOCAL->ld);	/* close the lock file */
+      unlink (LOCAL->lname);	/* and delete it */
+    }
+    if (LOCAL->lname) fs_give ((void **) &LOCAL->lname);
+				/* free local text buffers */
+    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+    if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data);
+    if (LOCAL->linebuf) fs_give ((void **) &LOCAL->linebuf);
+    if (LOCAL->line) fs_give ((void **) &LOCAL->line);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+/* MMDF open and lock mailbox
+ * Accepts: file name to open/lock
+ *	    file open mode
+ *	    destination buffer for lock file name
+ *	    type of locking operation (LOCK_SH or LOCK_EX)
+ */
+
+int mmdf_lock (char *file,int flags,int mode,DOTLOCK *lock,int op)
+{
+  int fd;
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  (*bn) (BLOCK_FILELOCK,NIL);
+				/* try locking the easy way */
+  if (dotlock_lock (file,lock,-1)) {
+				/* got dotlock file, easy open */
+    if ((fd = open (file,flags,mode)) >= 0) flock (fd,op);
+    else dotlock_unlock (lock);	/* open failed, free the dotlock */
+  }
+				/* no dot lock file, open file now */
+  else if ((fd = open (file,flags,mode)) >= 0) {
+				/* try paranoid way to make a dot lock file */
+    if (dotlock_lock (file,lock,fd)) {
+      close (fd);		/* get fresh fd in case of timing race */
+      if ((fd = open (file,flags,mode)) >= 0) flock (fd,op);
+				/* open failed, free the dotlock */
+      else dotlock_unlock (lock);
+    }
+    else flock (fd,op);		/* paranoid way failed, just flock() it */
+  }
+  (*bn) (BLOCK_NONE,NIL);
+  return fd;
+}
+
+/* MMDF unlock and close mailbox
+ * Accepts: file descriptor
+ *	    (optional) mailbox stream to check atime/mtime
+ *	    (optional) lock file name
+ */
+
+void mmdf_unlock (int fd,MAILSTREAM *stream,DOTLOCK *lock)
+{
+  if (stream) {			/* need to muck with times? */
+    struct stat sbuf;
+    time_t tp[2];
+    time_t now = time (0);
+    fstat (fd,&sbuf);		/* get file times */
+    if (LOCAL->ld >= 0) {	/* yes, readwrite session? */
+      tp[0] = now;		/* set atime to now */
+				/* set mtime to (now - 1) if necessary */
+      tp[1] = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1;
+    }
+    else if (stream->recent) {	/* readonly with recent messages */
+      if ((sbuf.st_atime >= sbuf.st_mtime) ||
+	  (sbuf.st_atime >= sbuf.st_ctime))
+				/* keep past mtime, whack back atime */
+	tp[0] = (tp[1] = (sbuf.st_mtime < now) ? sbuf.st_mtime : now) - 1;
+      else now = 0;		/* no time change needed */
+    }
+				/* readonly with no recent messages */
+    else if ((sbuf.st_atime < sbuf.st_mtime) ||
+	     (sbuf.st_atime < sbuf.st_ctime)) {
+      tp[0] = now;		/* set atime to now */
+				/* set mtime to (now - 1) if necessary */
+      tp[1] = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1;
+    }
+    else now = 0;		/* no time change needed */
+				/* set the times, note change */
+    if (now && !utime (stream->mailbox,tp)) LOCAL->filetime = tp[1];
+  }
+  flock (fd,LOCK_UN);		/* release flock'ers */
+  if (!stream) close (fd);	/* close the file if no stream */
+  dotlock_unlock (lock);	/* flush the lock file if any */
+}
+
+/* MMDF mail parse and lock mailbox
+ * Accepts: MAIL stream
+ *	    space to write lock file name
+ *	    type of locking operation
+ * Returns: T if parse OK, critical & mailbox is locked shared; NIL if failure
+ */
+
+int mmdf_parse (MAILSTREAM *stream,DOTLOCK *lock,int op)
+{
+  int ti,zn,m;
+  unsigned long i,j,k;
+  unsigned char c,*s,*t,*u,tmp[MAILTMPLEN],date[30];
+  int retain = T;
+  unsigned long nmsgs = stream->nmsgs;
+  unsigned long prevuid = nmsgs ? mail_elt (stream,nmsgs)->private.uid : 0;
+  unsigned long recent = stream->recent;
+  unsigned long oldnmsgs = stream->nmsgs;
+  short silent = stream->silent;
+  short pseudoseen = NIL;
+  struct stat sbuf;
+  STRING bs;
+  FDDATA d;
+  MESSAGECACHE *elt;
+  mail_lock (stream);		/* guard against recursion or pingers */
+				/* toss out previous descriptor */
+  if (LOCAL->fd >= 0) close (LOCAL->fd);
+  MM_CRITICAL (stream);		/* open and lock mailbox (shared OK) */
+  if ((LOCAL->fd = mmdf_lock (stream->mailbox,(LOCAL->ld >= 0) ?
+			      O_RDWR : O_RDONLY,
+			      (long)mail_parameters(NIL,GET_MBXPROTECTION,NIL),
+			      lock,op)) < 0) {
+    sprintf (tmp,"Mailbox open failed, aborted: %s",strerror (errno));
+    MM_LOG (tmp,ERROR);
+    mmdf_abort (stream);
+    mail_unlock (stream);
+    MM_NOCRITICAL (stream);	/* done with critical */
+    return NIL;
+  }
+  fstat (LOCAL->fd,&sbuf);	/* get status */
+				/* validate change in size */
+  if (sbuf.st_size < LOCAL->filesize) {
+    sprintf (tmp,"Mailbox shrank from %lu to %lu bytes, aborted",
+	     (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
+    MM_LOG (tmp,ERROR);		/* this is pretty bad */
+    mmdf_unlock (LOCAL->fd,stream,lock);
+    mmdf_abort (stream);
+    mail_unlock (stream);
+    MM_NOCRITICAL (stream);	/* done with critical */
+    return NIL;
+  }
+
+				/* new data? */
+  else if (i = sbuf.st_size - LOCAL->filesize) {
+    d.fd = LOCAL->fd;		/* yes, set up file descriptor */
+    d.pos = LOCAL->filesize;	/* get to that position in the file */
+    d.chunk = LOCAL->buf;	/* initial buffer chunk */
+    d.chunksize = CHUNKSIZE;	/* file chunk size */
+    INIT (&bs,fd_string,&d,i);	/* initialize stringstruct */
+				/* skip leading whitespace for broken MTAs */
+    while (((c = CHR (&bs)) == '\n') || (c == '\r') ||
+	   (c == ' ') || (c == '\t')) SNX (&bs);
+    if (SIZE (&bs)) {		/* read new data */
+				/* remember internal header position */
+      j = LOCAL->filesize + GETPOS (&bs);
+      s = mmdf_mbxline (stream,&bs,&i);
+      stream->silent = T;	/* quell main program new message events */
+      do {			/* read MMDF header */
+	if (!(i && ISMMDF (s))){/* see if valid MMDF header */
+	  sprintf (tmp,"Unexpected changes to mailbox (try restarting): %.20s",
+		   (char *) s);
+				/* see if we can back up to a line */
+	  if (i && (j > MMDFHDRLEN)) {
+	    SETPOS (&bs,j -= MMDFHDRLEN);
+				/* read previous line */
+	    s = mmdf_mbxline (stream,&bs,&i);
+				/* kill the error if it looks good */
+	    if (i && ISMMDF (s)) tmp[0] = '\0';
+	  }
+	  if (tmp[0]) {
+	    MM_LOG (tmp,ERROR);
+	    mmdf_unlock (LOCAL->fd,stream,lock);
+	    mmdf_abort (stream);
+	    mail_unlock (stream);
+	    MM_NOCRITICAL (stream);
+	    return NIL;
+	  }
+	}
+				/* instantiate first new message */
+	mail_exists (stream,++nmsgs);
+	(elt = mail_elt (stream,nmsgs))->valid = T;
+	recent++;		/* assume recent by default */
+	elt->recent = T;
+				/* note position/size of internal header */
+	elt->private.special.offset = j;
+	elt->private.special.text.size = i;
+
+	s = mmdf_mbxline (stream,&bs,&i);
+	ti = 0;			/* assume not a valid date */
+	zn = 0,t = NIL;
+	if (i) VALID (s,t,ti,zn);
+	if (ti) {		/* generate plausible IMAPish date string */
+				/* this is also part of header */
+	  elt->private.special.text.size += i;
+	  date[2] = date[6] = date[20] = '-'; date[11] = ' ';
+	  date[14] = date[17] = ':';
+				/* dd */
+	  date[0] = t[ti - 2]; date[1] = t[ti - 1];
+				/* mmm */
+	  date[3] = t[ti - 6]; date[4] = t[ti - 5]; date[5] = t[ti - 4];
+				/* hh */
+	  date[12] = t[ti + 1]; date[13] = t[ti + 2];
+				/* mm */
+	  date[15] = t[ti + 4]; date[16] = t[ti + 5];
+	  if (t[ti += 6]==':'){	/* ss */
+	    date[18] = t[++ti]; date[19] = t[++ti];
+	    ti++;		/* move to space */
+	  }
+	  else date[18] = date[19] = '0';
+				/* yy -- advance over timezone if necessary */
+	  if (zn == ti) ti += (((t[zn+1] == '+') || (t[zn+1] == '-')) ? 6 : 4);
+	  date[7] = t[ti + 1]; date[8] = t[ti + 2];
+	  date[9] = t[ti + 3]; date[10] = t[ti + 4];
+				/* zzz */
+	  t = zn ? (t + zn + 1) : (unsigned char *) "LCL";
+	  date[21] = *t++; date[22] = *t++; date[23] = *t++;
+	  if ((date[21] != '+') && (date[21] != '-')) date[24] = '\0';
+	  else {		/* numeric time zone */
+	    date[24] = *t++; date[25] = *t++;
+	    date[26] = '\0'; date[20] = ' ';
+	  }
+				/* set internal date */
+	  if (!mail_parse_date (elt,date)) {
+	    sprintf (tmp,"Unable to parse internal date: %s",(char *) date);
+	    MM_LOG (tmp,WARN);
+	  }
+	}
+	else {			/* make date from file date */
+	  struct tm *tm = gmtime (&sbuf.st_mtime);
+	  elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1;
+	  elt->year = tm->tm_year + 1900 - BASEYEAR;
+	  elt->hours = tm->tm_hour; elt->minutes = tm->tm_min;
+	  elt->seconds = tm->tm_sec;
+	  elt->zhours = 0; elt->zminutes = 0;
+	  t = NIL;		/* suppress line read */
+	}
+				/* header starts here */
+	elt->private.msg.header.offset = elt->private.special.text.size;
+
+	do {			/* look for message body */
+	  j = GETPOS (&bs);	/* note position before line */
+	  if (t) s = t = mmdf_mbxline (stream,&bs,&i);
+	  else t = s;		/* this line read was suppressed */
+	  if (ISMMDF (s)) {	/* found terminator in header? */
+	    SETPOS (&bs,j);	/* oops, back up before line */
+				/* must insert a newline */
+	    elt->private.spare.data++;
+	    break;		/* punt */
+	  }
+				/* this line is part of header */
+	  elt->private.msg.header.text.size += i;
+	  if (i) switch (*s) {	/* check header lines */
+	  case 'X':		/* possible X-???: line */
+	    if (s[1] == '-') {	/* must be immediately followed by hyphen */
+				/* X-Status: becomes Status: in S case */
+	      if (s[2] == 'S' && s[3] == 't' && s[4] == 'a' && s[5] == 't' &&
+		  s[6] == 'u' && s[7] == 's' && s[8] == ':') s += 2;
+				/* possible X-Keywords */
+	      else if (s[2] == 'K' && s[3] == 'e' && s[4] == 'y' &&
+		       s[5] == 'w' && s[6] == 'o' && s[7] == 'r' &&
+		       s[8] == 'd' && s[9] == 's' && s[10] == ':') {
+		SIZEDTEXT uf;
+		retain = NIL;	/* don't retain continuation */
+		s += 11;	/* flush leading whitespace */
+		while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n'))){
+		  while (*s == ' ') s++;
+				/* find end of keyword */
+		  if (!(u = strpbrk (s," \n\r"))) u = s + strlen (s);
+				/* got a keyword? */
+		  if ((k = (u - s)) && (k <= MAXUSERFLAG)) {
+		    uf.data = (unsigned char *) s;
+		    uf.size = k;
+		    for (j = 0; (j < NUSERFLAGS) && stream->user_flags[j]; ++j)
+		      if (!compare_csizedtext (stream->user_flags[j],&uf)) {
+			elt->user_flags |= ((long) 1) << j;
+			break;
+		      }
+		  }
+		  s = u;	/* advance to next keyword */
+		}
+		break;
+	      }
+
+				/* possible X-IMAP */
+	      else if ((s[2] == 'I') && (s[3] == 'M') && (s[4] == 'A') &&
+		       (s[5] == 'P') && ((m = (s[6] == ':')) ||
+					 ((s[6] == 'b') && (s[7] == 'a') &&
+					  (s[8] == 's') && (s[9] == 'e') &&
+					  (s[10] == ':')))) {
+		retain = NIL;	/* don't retain continuation */
+		if ((nmsgs == 1) && !stream->uid_validity) {
+				/* advance to data */
+		  s += m ? 7 : 11;
+				/* flush whitespace */
+		  while (*s == ' ') s++;
+		  j = 0;	/* slurp UID validity */
+				/* found a digit? */
+		  while (isdigit (*s)) {
+		    j *= 10;	/* yes, add it in */
+		    j += *s++ - '0';
+		  }
+				/* flush whitespace */
+		  while (*s == ' ') s++;
+				/* must have valid UID validity and UID last */
+		  if (j && isdigit (*s)) {
+				/* pseudo-header seen if X-IMAP */
+		    if (m) pseudoseen = LOCAL->pseudo = T;
+				/* save UID validity */
+		    stream->uid_validity = j;
+		    j = 0;	/* slurp UID last */
+		    while (isdigit (*s)) {
+		      j *= 10;	/* yes, add it in */
+		      j += *s++ - '0';
+		    }
+				/* save UID last */
+		    stream->uid_last = j;
+				/* process keywords */
+		    for (j = 0; (*s != '\n') && ((*s != '\r')||(s[1] != '\n'));
+			 s = u,j++) {
+				/* flush leading whitespace */
+		      while (*s == ' ') s++;
+		      u = strpbrk (s," \n\r");
+				/* got a keyword? */
+		      if ((j < NUSERFLAGS) && (k = (u - s)) &&
+			  (k <= MAXUSERFLAG)) {
+			if (stream->user_flags[j])
+			  fs_give ((void **) &stream->user_flags[j]);
+			stream->user_flags[j] = (char *) fs_get (k + 1);
+			strncpy (stream->user_flags[j],s,k);
+			stream->user_flags[j][k] = '\0';
+		      }
+		    }
+		  }
+		}
+		break;
+	      }
+
+				/* possible X-UID */
+	      else if (s[2] == 'U' && s[3] == 'I' && s[4] == 'D' &&
+		       s[5] == ':') {
+		retain = NIL;	/* don't retain continuation */
+				/* only believe if have a UID validity */
+		if (stream->uid_validity && ((nmsgs > 1) || !pseudoseen)) {
+		  s += 6;	/* advance to UID value */
+				/* flush whitespace */
+		  while (*s == ' ') s++;
+		  j = 0;
+				/* found a digit? */
+		  while (isdigit (*s)) {
+		    j *= 10;	/* yes, add it in */
+		    j += *s++ - '0';
+		  }
+				/* flush remainder of line */
+		  while (*s != '\n') s++;
+				/* make sure not duplicated */
+		  if (elt->private.uid)
+		    sprintf (tmp,"Message %lu UID %lu already has UID %lu",
+			     pseudoseen ? elt->msgno - 1 : elt->msgno,
+			     j,elt->private.uid);
+				/* make sure UID doesn't go backwards */
+		  else if (j <= prevuid)
+		    sprintf (tmp,"Message %lu UID %lu less than %lu",
+			     pseudoseen ? elt->msgno - 1 : elt->msgno,
+			     j,prevuid + 1);
+#if 0	/* this is currently broken by UIDPLUS */
+				/* or skip by mailbox's recorded last */
+		  else if (j > stream->uid_last)
+		    sprintf (tmp,"Message %lu UID %lu greater than last %lu",
+			     pseudoseen ? elt->msgno - 1 : elt->msgno,
+			     j,stream->uid_last);
+#endif
+		  else {	/* normal UID case */
+		    prevuid = elt->private.uid = j;
+#if 1	/* temporary kludge for UIDPLUS */
+		    if (prevuid > stream->uid_last) {
+		      stream->uid_last = prevuid;
+		      LOCAL->ddirty = LOCAL->dirty = T;
+		    }		    
+#endif
+		    break;	/* exit this cruft */
+		  }
+		  MM_LOG (tmp,WARN);
+				/* invalidate UID validity */
+		  stream->uid_validity = 0;
+		  elt->private.uid = 0;
+		}
+		break;
+	      }
+	    }
+				/* otherwise fall into S case */
+
+	  case 'S':		/* possible Status: line */
+	    if (s[0] == 'S' && s[1] == 't' && s[2] == 'a' && s[3] == 't' &&
+		s[4] == 'u' && s[5] == 's' && s[6] == ':') {
+	      retain = NIL;	/* don't retain continuation */
+	      s += 6;		/* advance to status flags */
+	      do switch (*s++) {/* parse flags */
+	      case 'R':		/* message read */
+		elt->seen = T;
+		break;
+	      case 'O':		/* message old */
+		if (elt->recent) {
+		  elt->recent = NIL;
+		  recent--;	/* it really wasn't recent */
+		}
+		break;
+	      case 'D':		/* message deleted */
+		elt->deleted = T;
+		break;
+	      case 'F':		/* message flagged */
+		elt->flagged = T;
+		break;
+	      case 'A':		/* message answered */
+		elt->answered = T;
+		break;
+	      case 'T':		/* message is a draft */
+		elt->draft = T;
+		break;
+	      default:		/* some other crap */
+		break;
+	      } while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n')));
+	      break;		/* all done */
+	    }
+				/* otherwise fall into default case */
+
+	  default:		/* ordinary header line */
+	    if ((*s == 'S') || (*s == 's') ||
+		(((*s == 'X') || (*s == 'x')) && (s[1] == '-'))) {
+	      unsigned char *e,*v;
+				/* must match what mail_filter() does */
+	      for (u = s,v = tmp,e = u + min (i,MAILTMPLEN - 1);
+		   (u < e) && ((c = (*u ? *u : (*u = ' '))) != ':') &&
+		   ((c > ' ') || ((c != ' ') && (c != '\t') &&
+				  (c != '\r') && (c != '\n')));
+		   *v++ = *u++);
+	      *v = '\0';	/* tie off */
+				/* matches internal header? */
+	      if (!compare_cstring (tmp,"STATUS") ||
+		  !compare_cstring (tmp,"X-STATUS") ||
+		  !compare_cstring (tmp,"X-KEYWORDS") ||
+		  !compare_cstring (tmp,"X-UID") ||
+		  !compare_cstring (tmp,"X-IMAP") ||
+		  !compare_cstring (tmp,"X-IMAPBASE")) {
+		char err[MAILTMPLEN];
+		sprintf (err,"Discarding bogus %s header in message %lu",
+			 (char *) tmp,elt->msgno);
+		MM_LOG (err,WARN);
+		retain = NIL;	/* don't retain continuation */
+		break;		/* different case or something */
+	      }
+	    }
+				/* retain or non-continuation? */
+	    if (retain || ((*s != ' ') && (*s != '\t'))) {
+	      retain = T;	/* retaining continuation now */
+				/* line length in LF format newline */
+	      for (j = k = 0; j < i; ++j) if (s[j] != '\r') ++k;
+				/* "internal" header size */
+	      elt->private.spare.data += k;
+				/* message size */
+	      elt->rfc822_size += k + 1;
+	    }
+	    else {
+	      char err[MAILTMPLEN];
+	      sprintf (err,"Discarding bogus continuation in msg %lu: %.80s",
+		      elt->msgno,(char *) s);
+	      if (u = strpbrk (err,"\r\n")) *u = '\0';
+	      MM_LOG (err,WARN);
+	      break;		/* different case or something */
+	    }
+	    break;
+	  }
+	} while (i && (*t != '\n') && ((*t != '\r') || (t[1] != '\n')));
+				/* "internal" header sans trailing newline */
+	if (i) elt->private.spare.data--;
+				/* assign a UID if none found */
+	if (((nmsgs > 1) || !pseudoseen) && !elt->private.uid) {
+	  prevuid = elt->private.uid = ++stream->uid_last;
+	  elt->private.dirty = T;
+	}
+	else elt->private.dirty = elt->recent;
+
+				/* note size of header, location of text */
+	elt->private.msg.header.text.size =
+	  (elt->private.msg.text.offset =
+	   (LOCAL->filesize + GETPOS (&bs)) - elt->private.special.offset) -
+	     elt->private.special.text.size;
+				/* note current position */
+	j = LOCAL->filesize + GETPOS (&bs);
+	if (i) do {		/* look for next message */
+	  s = mmdf_mbxline (stream,&bs,&i);
+	  if (i) {		/* got new data? */
+	    if (ISMMDF (s)) break;
+	    else {		/* not a header line, add it to message */
+	      elt->rfc822_size += i;
+	      for (j = 0; j < i; ++j) switch (s[j]) {
+	      case '\r':	/* squeeze out CRs */
+		elt->rfc822_size -= 1;
+		break;
+	      case '\n':	/* LF becomes CRLF */
+		elt->rfc822_size += 1;
+		break;
+	      default:
+		break;
+	      }
+				/* update current position */
+	      j = LOCAL->filesize + GETPOS (&bs);
+	    }
+	  }
+	} while (i);		/* until found a header */
+	elt->private.msg.text.text.size = j -
+	  (elt->private.special.offset + elt->private.msg.text.offset);
+	if (i) {		/* get next header line */
+				/* remember first internal header position */
+	  j = LOCAL->filesize + GETPOS (&bs);
+	  s = mmdf_mbxline (stream,&bs,&i);
+	}
+				/* until end of buffer */
+      } while (!stream->sniff && i);
+      if (pseudoseen) {		/* flush pseudo-message if present */
+				/* decrement recent count */
+	if (mail_elt (stream,1)->recent) recent--;
+				/* and the exists count */
+	mail_exists (stream,nmsgs--);
+	mail_expunged(stream,1);/* fake an expunge of that message */
+      }
+				/* need to start a new UID validity? */
+      if (!stream->uid_validity) {
+	stream->uid_validity = time (0);
+				/* in case a whiner with no life */
+	if (mail_parameters (NIL,GET_USERHASNOLIFE,NIL))
+	  stream->uid_nosticky = T;
+	else if (nmsgs) {	/* don't bother if empty file */
+				/* make dirty to restart UID epoch */
+	  LOCAL->ddirty = LOCAL->dirty = T;
+				/* need to rewrite msg 1 if not pseudo */
+	  if (!LOCAL->pseudo) mail_elt (stream,1)->private.dirty = T;
+	  MM_LOG ("Assigning new unique identifiers to all messages",NIL);
+	}
+      }
+      stream->nmsgs = oldnmsgs;	/* whack it back down */
+      stream->silent = silent;	/* restore old silent setting */
+				/* notify upper level of new mailbox sizes */
+      mail_exists (stream,nmsgs);
+      mail_recent (stream,recent);
+				/* mark dirty so O flags are set */
+      if (recent) LOCAL->dirty = T;
+    }
+  }
+				/* no change, don't babble if never got time */
+  else if (LOCAL->filetime && LOCAL->filetime != sbuf.st_mtime)
+    MM_LOG ("New mailbox modification time but apparently no changes",WARN);
+				/* update parsed file size and time */
+  LOCAL->filesize = sbuf.st_size;
+  LOCAL->filetime = sbuf.st_mtime;
+  return T;			/* return the winnage */
+}
+
+/* MMDF read line from mailbox
+ * Accepts: mail stream
+ *	    stringstruct
+ *	    pointer to line size
+ * Returns: pointer to input line
+ */
+
+char *mmdf_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size)
+{
+  unsigned long i,j,k,m;
+  char *s,*t,*te;
+  char *ret = "";
+				/* flush old buffer */
+  if (LOCAL->line) fs_give ((void **) &LOCAL->line);
+				/* if buffer needs refreshing */
+  if (!bs->cursize) SETPOS (bs,GETPOS (bs));
+  if (SIZE (bs)) {		/* find newline */
+				/* end of fast scan */
+    te = (t = (s = bs->curpos) + bs->cursize) - 12;
+    while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) {
+      --s;			/* back up */
+      break;			/* exit loop */
+    }
+				/* final character-at-a-time scan */
+    while ((s < t) && (*s != '\n')) ++s;
+				/* difficult case if line spans buffer */
+    if ((i = s - bs->curpos) == bs->cursize) {
+				/* have space in line buffer? */
+      if (i > LOCAL->linebuflen) {
+	fs_give ((void **) &LOCAL->linebuf);
+	LOCAL->linebuf = (char *) fs_get (LOCAL->linebuflen = i);
+      }
+				/* remember what we have so far */
+      memcpy (LOCAL->linebuf,bs->curpos,i);
+				/* load next buffer */
+      SETPOS (bs,k = GETPOS (bs) + i);
+				/* end of fast scan */
+      te = (t = (s = bs->curpos) + bs->cursize) - 12;
+				/* fast scan in overlap buffer */
+      while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) {
+	--s;			/* back up */
+	break;			/* exit loop */
+      }
+
+				/* final character-at-a-time scan */
+      while ((s < t) && (*s != '\n')) ++s;
+				/* huge line? */
+      if ((j = s - bs->curpos) == bs->cursize) {
+	SETPOS (bs,GETPOS (bs) + j);
+				/* look for end of line (s-l-o-w!!) */
+	for (m = SIZE (bs); m && (SNX (bs) != '\n'); --m,++j);
+	SETPOS (bs,k);		/* go back to where it started */
+      }
+				/* got size of data, make buffer for return */
+      ret = LOCAL->line = (char *) fs_get (i + j + 2);
+				/* copy first chunk */
+      memcpy (ret,LOCAL->linebuf,i);
+      while (j) {		/* copy remainder */
+	if (!bs->cursize) SETPOS (bs,GETPOS (bs));
+	memcpy (ret + i,bs->curpos,k = min (j,bs->cursize));
+	i += k;			/* account for this much read in */
+	j -= k;
+	bs->curpos += k;	/* increment new position */
+	bs->cursize -= k;	/* eat that many bytes */
+      }
+				/* read newline at end */
+      if (SIZE (bs)) ret[i++] = SNX (bs);
+      ret[i] = '\0';		/* makes debugging easier */
+    }
+    else {			/* this is easy */
+      ret = bs->curpos;		/* string it at this position */
+      bs->curpos += ++i;	/* increment new position */
+      bs->cursize -= i;		/* eat that many bytes */
+    }
+    *size = i;			/* return that to user */
+  }
+  else *size = 0;		/* end of data, return empty */
+				/* embedded MMDF header at end of line? */
+  if ((*size > sizeof (MMDFHDRTXT)) &&
+      (s = ret + *size - (i = sizeof (MMDFHDRTXT) - 1)) && ISMMDF (s)) {
+    SETPOS (bs,GETPOS (bs) - i);/* back up to start of MMDF header */
+    *size -= i;			/* reduce length of line */
+    ret[*size - 1] = '\n';	/* force newline at end */
+  }
+  return ret;
+}
+
+/* MMDF make pseudo-header
+ * Accepts: MAIL stream
+ *	    buffer to write pseudo-header
+ * Returns: length of pseudo-header
+ */
+
+unsigned long mmdf_pseudo (MAILSTREAM *stream,char *hdr)
+{
+  int i;
+  char *s,tmp[MAILTMPLEN];
+  time_t now = time (0);
+  rfc822_fixed_date (tmp);
+  sprintf (hdr,"%sFrom %s %.24s\nDate: %s\nFrom: %s <%s@%.80s>\nSubject: %s\nMessage-ID: <%lu@%.80s>\nX-IMAP: %010lu %010lu",
+	   mmdfhdr,pseudo_from,ctime (&now),
+	   tmp,pseudo_name,pseudo_from,mylocalhost (),pseudo_subject,
+	   (unsigned long) now,mylocalhost (),stream->uid_validity,
+	   stream->uid_last);
+  for (s = hdr + strlen (hdr),i = 0; i < NUSERFLAGS; ++i)
+    if (stream->user_flags[i])
+      sprintf (s += strlen (s)," %s",stream->user_flags[i]);
+  sprintf (s += strlen (s),"\nStatus: RO\n\n%s\n%s",pseudo_msg,mmdfhdr);
+  return strlen (hdr);
+}
+
+/* MMDF make status string
+ * Accepts: MAIL stream
+ *	    destination string to write
+ *	    message cache entry
+ *	    UID to write if non-zero (else use elt->private.uid)
+ *	    non-zero flag to write UID (.LT. 0 to write UID base info too)
+ * Returns: length of string
+ */
+
+unsigned long mmdf_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt,
+			    unsigned long uid,long flag)
+{
+  char *t,stack[64];
+  char *s = status;
+  unsigned long n;
+  int pad = 50;
+  int sticky = uid ? T : !stream->uid_nosticky;
+  /* This used to use sprintf(), but thanks to certain cretinous C libraries
+     with horribly slow implementations of sprintf() I had to change it to this
+     mess.  At least it should be fast. */
+  if ((flag < 0) && sticky) {	/* need to write X-IMAPbase: header? */
+    *s++ = 'X'; *s++ = '-'; *s++ = 'I'; *s++ = 'M'; *s++ = 'A'; *s++ = 'P';
+    *s++ = 'b'; *s++ = 'a'; *s++ = 's'; *s++ = 'e'; *s++ = ':'; *s++ = ' ';
+    t = stack;
+    n = stream->uid_validity;	/* push UID validity digits on the stack */
+    do *t++ = (char) (n % 10) + '0';
+    while (n /= 10);
+				/* pop UID validity digits from stack */
+    while (t > stack) *s++ = *--t;
+   *s++ = ' ';
+    n = stream->uid_last;	/* push UID last digits on the stack */
+    do *t++ = (char) (n % 10) + '0';
+    while (n /= 10);
+				/* pop UID last digits from stack */
+    while (t > stack) *s++ = *--t;
+    for (n = 0; n < NUSERFLAGS; ++n) if (t = stream->user_flags[n])
+      for (*s++ = ' '; *t; *s++ = *t++);
+    *s++ = '\n';
+    pad += 30;			/* increased padding if have IMAPbase */
+  }
+  *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't'; *s++ = 'u'; *s++ = 's';
+  *s++ = ':'; *s++ = ' ';
+  if (elt->seen) *s++ = 'R';
+				/* only write O if have a UID */
+  if (flag && (!elt->recent || !LOCAL->appending)) *s++ = 'O';
+  *s++ = '\n';
+  *s++ = 'X'; *s++ = '-'; *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't';
+  *s++ = 'u'; *s++ = 's'; *s++ = ':'; *s++ = ' ';
+  if (elt->deleted) *s++ = 'D';
+  if (elt->flagged) *s++ = 'F';
+  if (elt->answered) *s++ = 'A';
+  if (elt->draft) *s++ = 'T';
+    *s++ = '\n';
+
+  if (sticky) {			/* only do this if UIDs sticky */
+    *s++ = 'X'; *s++ = '-'; *s++ = 'K'; *s++ = 'e'; *s++ = 'y'; *s++ = 'w';
+    *s++ = 'o'; *s++ = 'r'; *s++ = 'd'; *s++ = 's'; *s++ = ':';
+    if (n = elt->user_flags) do {
+      *s++ = ' ';
+      for (t = stream->user_flags[find_rightmost_bit (&n)]; *t; *s++ = *t++);
+    } while (n);
+    n = s - status;		/* get size of stuff so far */
+				/* pad X-Keywords to make size constant */
+    if (n < pad) for (n = pad - n; n > 0; --n) *s++ = ' ';
+    *s++ = '\n';
+    if (flag) {			/* want to include UID? */
+      t = stack;
+				/* push UID digits on the stack */
+      n = uid ? uid : elt->private.uid;
+      do *t++ = (char) (n % 10) + '0';
+      while (n /= 10);
+      *s++ = 'X'; *s++ = '-'; *s++ = 'U'; *s++ = 'I'; *s++ = 'D'; *s++ = ':';
+      *s++ = ' ';
+				/* pop UID from stack */
+      while (t > stack) *s++ = *--t;
+      *s++ = '\n';
+    }
+  }
+  *s++ = '\n'; *s = '\0';	/* end of extended message status */
+  return s - status;		/* return size of resulting string */
+}
+
+/* Rewrite mailbox file
+ * Accepts: MAIL stream, must be critical and locked
+ *	    return pointer to number of expunged messages if want expunge
+ *	    lock file name
+ *	    expunge sequence, not deleted flag
+ * Returns: T if success and mailbox unlocked, NIL if failure
+ */
+
+#define OVERFLOWBUFLEN 8192	/* initial overflow buffer length */
+
+long mmdf_rewrite (MAILSTREAM *stream,unsigned long *nexp,DOTLOCK *lock,
+		   long flags)
+{
+  MESSAGECACHE *elt;
+  MMDFFILE f;
+  char *s;
+  time_t tp[2];
+  long ret,flag;
+  unsigned long i,j;
+  unsigned long recent = stream->recent;
+  unsigned long size = LOCAL->pseudo ? mmdf_pseudo (stream,LOCAL->buf) : 0;
+  if (nexp) *nexp = 0;		/* initially nothing expunged */
+				/* calculate size of mailbox after rewrite */
+  for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs; i++) {
+    elt = mail_elt (stream,i);	/* get cache */
+    if (!(nexp && elt->deleted && (flags ? elt->sequence : T))) {
+				/* add RFC822 size of this message */
+      size += elt->private.special.text.size + elt->private.spare.data +
+	mmdf_xstatus (stream,LOCAL->buf,elt,NIL,flag) +
+	  elt->private.msg.text.text.size + MMDFHDRLEN;
+      flag = 1;			/* only count X-IMAPbase once */
+    }
+  }
+				/* no messages, has a life, and no pseudo */
+  if (!size && !mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) {
+    LOCAL->pseudo = T;		/* so make a pseudo-message now */
+    size = mmdf_pseudo (stream,LOCAL->buf);
+  }
+				/* extend the file as necessary */
+  if (ret = mmdf_extend (stream,size)) {
+    /* Set up buffered I/O file structure
+     * curpos	current position being written through buffering
+     * filepos	current position being written physically to the disk
+     * bufpos	current position being written in the buffer
+     * protect	current maximum position that can be written to the disk
+     *		before buffering is forced
+     * The code tries to buffer so that that disk is written in multiples of
+     * OVERBLOWBUFLEN bytes.
+     */
+    f.stream = stream;		/* note mail stream */
+    f.curpos = f.filepos = 0;	/* start of file */
+    f.protect = stream->nmsgs ?	/* initial protection pointer */
+    mail_elt (stream,1)->private.special.offset : 8192;
+    f.bufpos = f.buf = (char *) fs_get (f.buflen = OVERFLOWBUFLEN);
+
+    if (LOCAL->pseudo)		/* update pseudo-header */
+      mmdf_write (&f,LOCAL->buf,mmdf_pseudo (stream,LOCAL->buf));
+				/* loop through all messages */
+    for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs;) {
+      elt = mail_elt (stream,i);/* get cache */
+				/* expunge this message? */
+      if (nexp && elt->deleted && (flags ? elt->sequence : T)) {
+				/* one less recent message */
+	if (elt->recent) --recent;
+	mail_expunged(stream,i);/* notify upper levels */
+	++*nexp;		/* count up one more expunged message */
+      }
+      else {			/* preserve this message */
+	i++;			/* advance to next message */
+	if ((flag < 0) ||	/* need to rewrite message? */
+	    elt->private.dirty || (f.curpos != elt->private.special.offset) ||
+	    (elt->private.msg.header.text.size !=
+	     (elt->private.spare.data +
+	      mmdf_xstatus (stream,LOCAL->buf,elt,NIL,flag)))) {
+	  unsigned long newoffset = f.curpos;
+				/* yes, seek to internal header */
+	  lseek (LOCAL->fd,elt->private.special.offset,L_SET);
+	  read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size);
+				/* see if need to squeeze out a CR */
+	  if (LOCAL->buf[elt->private.special.text.size - 2] == '\r') {
+	    LOCAL->buf[--elt->private.special.text.size - 1] = '\n';
+	    --size;		/* squeezed out a CR from PC */
+	  }
+				/* protection pointer moves to RFC822 header */
+	  f.protect = elt->private.special.offset +
+	    elt->private.msg.header.offset;
+				/* write internal header */
+	  mmdf_write (&f,LOCAL->buf,elt->private.special.text.size);
+				/* get RFC822 header */
+	  s = mmdf_header (stream,elt->msgno,&j,FT_INTERNAL);
+				/* in case this got decremented */
+	  elt->private.msg.header.offset = elt->private.special.text.size;
+				/* header size, sans trailing newline */
+	  if ((j < 2) || (s[j - 2] == '\n')) j--;
+				/* this can happen if CRs were squeezed */
+	  if (j < elt->private.spare.data) {
+				/* so fix up counts */
+	    size -= elt->private.spare.data - j;
+	    elt->private.spare.data = j;
+	  }
+	  else if (j != elt->private.spare.data)
+	    fatal ("header size inconsistent");
+				/* protection pointer moves to RFC822 text */
+	  f.protect = elt->private.special.offset +
+	    elt->private.msg.text.offset;
+	  mmdf_write (&f,s,j);	/* write RFC822 header */
+				/* write status and UID */
+	  mmdf_write (&f,LOCAL->buf,
+		      j = mmdf_xstatus (stream,LOCAL->buf,elt,NIL,flag));
+	  flag = 1;		/* only write X-IMAPbase once */
+				/* new file header size */
+	  elt->private.msg.header.text.size = elt->private.spare.data + j;
+
+				/* did text move? */
+	  if (f.curpos != f.protect) {
+				/* get message text */
+	    s = mmdf_text_work (stream,elt,&j,FT_INTERNAL);
+				/* this can happen if CRs were squeezed */
+	    if (j < elt->private.msg.text.text.size) {
+				/* so fix up counts */
+	      size -= elt->private.msg.text.text.size - j;
+	      elt->private.msg.text.text.size = j;
+	    }
+				/* can't happen it says here */
+	    else if (j > elt->private.msg.text.text.size)
+	      fatal ("text size inconsistent");
+				/* new text offset, status/UID may change it */
+	    elt->private.msg.text.offset = f.curpos - newoffset;
+				/* protection pointer moves to next message */
+	    f.protect = (i <= stream->nmsgs) ?
+	      mail_elt (stream,i)->private.special.offset :
+		(f.curpos + j + MMDFHDRLEN);
+	    mmdf_write (&f,s,j);/* write text */
+				/* write trailing newline */
+	    mmdf_write (&f,mmdfhdr,MMDFHDRLEN);
+	  }
+	  else {		/* tie off header and status */
+	    mmdf_write (&f,NIL,NIL);
+	    f.curpos = f.protect =/* restart everything at end of message */
+	      f.filepos += elt->private.msg.text.text.size + MMDFHDRLEN;
+	  }
+				/* new internal header offset */
+	  elt->private.special.offset = newoffset;
+	  elt->private.dirty =NIL;/* message is now clean */
+	}
+	else {			/* no need to rewrite this message */
+				/* tie off previous message if needed */
+	  mmdf_write (&f,NIL,NIL);
+	  f.curpos = f.protect =/* restart everything at end of message */
+	    f.filepos += elt->private.special.text.size +
+	      elt->private.msg.header.text.size +
+		elt->private.msg.text.text.size + MMDFHDRLEN;
+	}
+      }
+    }
+
+    mmdf_write (&f,NIL,NIL);	/* tie off final message */
+    if (size != f.filepos) fatal ("file size inconsistent");
+    fs_give ((void **) &f.buf);	/* free buffer */
+				/* make sure tied off */
+    ftruncate (LOCAL->fd,LOCAL->filesize = size);
+    fsync (LOCAL->fd);		/* make sure the updates take */
+    if (size && (flag < 0)) fatal ("lost UID base information");
+				/* no longer dirty */
+    LOCAL->ddirty = LOCAL->dirty = NIL;
+  				/* notify upper level of new mailbox sizes */
+    mail_exists (stream,stream->nmsgs);
+    mail_recent (stream,recent);
+				/* set atime to now, mtime a second earlier */
+    tp[1] = (tp[0] = time (0)) - 1;
+				/* set the times, note change */
+    if (!utime (stream->mailbox,tp)) LOCAL->filetime = tp[1];
+    close (LOCAL->fd);		/* close and reopen file */
+    if ((LOCAL->fd = open (stream->mailbox,O_RDWR,
+			   (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL)))
+	< 0) {
+      sprintf (LOCAL->buf,"Mailbox open failed, aborted: %s",strerror (errno));
+      MM_LOG (LOCAL->buf,ERROR);
+      mmdf_abort (stream);
+    }
+    dotlock_unlock (lock);	/* flush the lock file */
+  }
+  return ret;			/* return state from algorithm */
+}
+
+/* Extend MMDF mailbox file
+ * Accepts: MAIL stream
+ *	    new desired size
+ * Return: T if success, else NIL
+ */
+
+long mmdf_extend (MAILSTREAM *stream,unsigned long size)
+{
+  unsigned long i = (size > LOCAL->filesize) ? size - LOCAL->filesize : 0;
+  if (i) {			/* does the mailbox need to grow? */
+    if (i > LOCAL->buflen) {	/* make sure have enough space */
+				/* this user won the lottery all right */
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get ((LOCAL->buflen = i) + 1);
+    }
+    memset (LOCAL->buf,'\0',i);	/* get a block of nulls */
+    while (T) {			/* until write successful or punt */
+      lseek (LOCAL->fd,LOCAL->filesize,L_SET);
+      if ((write (LOCAL->fd,LOCAL->buf,i) >= 0) && !fsync (LOCAL->fd)) break;
+      else {
+	long e = errno;		/* note error before doing ftruncate */
+	ftruncate (LOCAL->fd,LOCAL->filesize);
+	if (MM_DISKERROR (stream,e,NIL)) {
+	  fsync (LOCAL->fd);	/* user chose to punt */
+	  sprintf (LOCAL->buf,"Unable to extend mailbox: %s",strerror (e));
+	  if (!stream->silent) MM_LOG (LOCAL->buf,ERROR);
+	  return NIL;
+	}
+      }
+    }
+  }
+  return LONGT;
+}
+
+/* Write data to buffered file
+ * Accepts: buffered file pointer
+ *	    file data or NIL to indicate "flush buffer"
+ *	    date size (ignored for "flush buffer")
+ * Does not return until success
+ */
+
+void mmdf_write (MMDFFILE *f,char *buf,unsigned long size)
+{
+  unsigned long i,j,k;
+  if (buf) {			/* doing buffered write? */
+    i = f->bufpos - f->buf;	/* yes, get size of current buffer data */
+				/* yes, have space in current buffer chunk? */
+    if (j = i ? ((f->buflen - i) % OVERFLOWBUFLEN) : f->buflen) {
+				/* yes, fill up buffer as much as we can */
+      memcpy (f->bufpos,buf,k = min (j,size));
+      f->bufpos += k;		/* new buffer position */
+      f->curpos += k;		/* new current position */
+      if (j -= k) return;	/* all done if still have buffer free space */
+      buf += k;			/* full, get new unwritten data pointer */
+      size -= k;		/* new data size */
+      i += k;			/* new buffer data size */
+    }
+    /* This chunk of the buffer is full.  See if can make some space by
+     * writing to the disk, if there's enough unprotected space to do so.
+     * Try to fill out any unaligned chunk, along with any subsequent full
+     * chunks that will fit in unprotected space.
+     */
+				/* any unprotected space we can write to? */
+    if (j = min (i,f->protect - f->filepos)) {
+				/* yes, filepos not at chunk boundary? */
+      if ((k = f->filepos % OVERFLOWBUFLEN) && ((k = OVERFLOWBUFLEN - k) < j))
+	j -= k;			/* yes, and can write out partial chunk */
+      else k = 0;		/* no partial chunk to write */
+				/* if at least a chunk free, write that too */
+      if (j > OVERFLOWBUFLEN) k += j - (j % OVERFLOWBUFLEN);
+      if (k) {			/* write data if there is anything we can */
+	mmdf_phys_write (f,f->buf,k);
+				/* slide buffer */
+	if (i -= k) memmove (f->buf,f->buf + k,i);
+	f->bufpos = f->buf + i;	/* new end of buffer */
+      }
+    }
+
+    /* Have flushed the buffer as best as possible.  All done if no more
+     * data to write.  Otherwise, if the buffer is empty AND if the unwritten
+     * data is larger than a chunk AND the unprotected space is also larger
+     * than a chunk, then write as many chunks as we can directly from the
+     * data.  Buffer the rest, expanding the buffer as needed.
+     */
+    if (size) {			/* have more data that we need to buffer? */
+				/* can write any of it to disk instead? */
+      if ((f->bufpos == f->buf) && 
+	  ((j = min (f->protect - f->filepos,size)) > OVERFLOWBUFLEN)) {
+				/* write as much as we can right now */
+	mmdf_phys_write (f,buf,j -= (j % OVERFLOWBUFLEN));
+	buf += j;		/* new data pointer */
+	size -= j;		/* new data size */
+	f->curpos += j;		/* advance current pointer */
+      }
+      if (size) {		/* still have data that we need to buffer? */
+				/* yes, need to expand the buffer? */
+	if ((i = ((f->bufpos + size) - f->buf)) > f->buflen) {
+				/* note current position in buffer */
+	  j = f->bufpos - f->buf;
+	  i += OVERFLOWBUFLEN;	/* yes, grow another chunk */
+	  fs_resize ((void **) &f->buf,f->buflen = i - (i % OVERFLOWBUFLEN));
+				/* in case buffer relocated */
+	  f->bufpos = f->buf + j;
+	}
+				/* buffer remaining data */
+	memcpy (f->bufpos,buf,size);
+	f->bufpos += size;	/* new end of buffer */
+	f->curpos += size;	/* advance current pointer */
+      }
+    }
+  }
+  else {			/* flush buffer to disk */
+    mmdf_phys_write (f,f->buf,i = f->bufpos - f->buf);
+    f->bufpos = f->buf;		/* reset buffer */
+				/* update positions */
+    f->curpos = f->protect = f->filepos;
+  }
+}
+
+/* Physical disk write
+ * Accepts: buffered file pointer
+ *	    buffer address
+ *	    buffer size
+ * Does not return until success
+ */
+
+void mmdf_phys_write (MMDFFILE *f,char *buf,size_t size)
+{
+  MAILSTREAM *stream = f->stream;
+				/* write data at desired position */
+  while (size && ((lseek (LOCAL->fd,f->filepos,L_SET) < 0) ||
+		  (write (LOCAL->fd,buf,size) < 0))) {
+    int e;
+    char tmp[MAILTMPLEN];
+    sprintf (tmp,"Unable to write to mailbox: %s",strerror (e = errno));
+    MM_LOG (tmp,ERROR);
+    MM_DISKERROR (NIL,e,T);	/* serious problem, must retry */
+  }
+  f->filepos += size;		/* update file position */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/mtx.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1371 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	MTX mail routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	22 May 1990
+ * Last Edited:	11 October 2007
+ */
+
+
+/*				FILE TIME SEMANTICS
+ *
+ * The atime is the last read time of the file.
+ * The mtime is the last flags update time of the file.
+ * The ctime is the last write time of the file.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "mail.h"
+#include "osdep.h"
+#include <pwd.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "misc.h"
+#include "dummy.h"
+#include "fdstring.h"
+
+/* MTX I/O stream local data */
+	
+typedef struct mtx_local {
+  unsigned int shouldcheck: 1;	/* if ping should do a check instead */
+  unsigned int mustcheck: 1;	/* if ping must do a check instead */
+  int fd;			/* file descriptor for I/O */
+  off_t filesize;		/* file size parsed */
+  time_t filetime;		/* last file time */
+  time_t lastsnarf;		/* last snarf time */
+  unsigned char *buf;		/* temporary buffer */
+  unsigned long buflen;		/* current size of temporary buffer */
+} MTXLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((MTXLOCAL *) stream->local)
+
+
+/* Function prototypes */
+
+DRIVER *mtx_valid (char *name);
+int mtx_isvalid (char *name,char *tmp);
+void *mtx_parameters (long function,void *value);
+void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void mtx_list (MAILSTREAM *stream,char *ref,char *pat);
+void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long mtx_create (MAILSTREAM *stream,char *mailbox);
+long mtx_delete (MAILSTREAM *stream,char *mailbox);
+long mtx_rename (MAILSTREAM *stream,char *old,char *newname);
+long mtx_status (MAILSTREAM *stream,char *mbx,long flags);
+MAILSTREAM *mtx_open (MAILSTREAM *stream);
+void mtx_close (MAILSTREAM *stream,long options);
+void mtx_flags (MAILSTREAM *stream,char *sequence,long flags);
+char *mtx_header (MAILSTREAM *stream,unsigned long msgno,
+		  unsigned long *length,long flags);
+long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+void mtx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
+void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
+long mtx_ping (MAILSTREAM *stream);
+void mtx_check (MAILSTREAM *stream);
+void mtx_snarf (MAILSTREAM *stream);
+long mtx_expunge (MAILSTREAM *stream,char *sequence,long options);
+long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+char *mtx_file (char *dst,char *name);
+long mtx_parse (MAILSTREAM *stream);
+MESSAGECACHE *mtx_elt (MAILSTREAM *stream,unsigned long msgno);
+void mtx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt);
+void mtx_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag);
+unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			  unsigned long *size);
+
+/* MTX mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER mtxdriver = {
+  "mtx",			/* driver name */
+				/* driver flags */
+  DR_LOCAL|DR_MAIL|DR_CRLF|DR_NOSTICKY|DR_LOCKING,
+  (DRIVER *) NIL,		/* next driver */
+  mtx_valid,			/* mailbox is valid for us */
+  mtx_parameters,		/* manipulate parameters */
+  mtx_scan,			/* scan mailboxes */
+  mtx_list,			/* list mailboxes */
+  mtx_lsub,			/* list subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  dummy_create,			/* create mailbox */
+  mtx_delete,			/* delete mailbox */
+  mtx_rename,			/* rename mailbox */
+  mtx_status,			/* status of mailbox */
+  mtx_open,			/* open mailbox */
+  mtx_close,			/* close mailbox */
+  mtx_flags,			/* fetch message "fast" attributes */
+  mtx_flags,			/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  mtx_header,			/* fetch message header */
+  mtx_text,			/* fetch message body */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  mtx_flag,			/* modify flags */
+  mtx_flagmsg,			/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  mtx_ping,			/* ping mailbox to see if still alive */
+  mtx_check,			/* check for new messages */
+  mtx_expunge,			/* expunge deleted messages */
+  mtx_copy,			/* copy messages to another mailbox */
+  mtx_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM mtxproto = {&mtxdriver};
+
+/* MTX mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *mtx_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+  return mtx_isvalid (name,tmp) ? &mtxdriver : NIL;
+}
+
+
+/* MTX mail test for valid mailbox
+ * Accepts: mailbox name
+ * Returns: T if valid, NIL otherwise
+ */
+
+int mtx_isvalid (char *name,char *tmp)
+{
+  int fd;
+  int ret = NIL;
+  char *s,file[MAILTMPLEN];
+  struct stat sbuf;
+  time_t tp[2];
+  errno = EINVAL;		/* assume invalid argument */
+				/* if file, get its status */
+  if ((s = mtx_file (file,name)) && !stat (s,&sbuf)) {
+    if (!sbuf.st_size) {	/* allow empty file if INBOX */
+      if ((s = mailboxfile (tmp,name)) && !*s) ret = T;
+      else errno = 0;		/* empty file */
+    }
+    else if ((fd = open (file,O_RDONLY,NIL)) >= 0) {
+      memset (tmp,'\0',MAILTMPLEN);
+      if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\015')) &&
+	  (s[1] == '\012')) {	/* valid format? */
+	*s = '\0';		/* tie off header */
+				/* must begin with dd-mmm-yy" */
+	ret = (((tmp[2] == '-' && tmp[6] == '-') ||
+		(tmp[1] == '-' && tmp[5] == '-')) &&
+	       (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL;
+      }
+      else errno = -1;		/* bogus format */
+      close (fd);		/* close the file */
+				/* \Marked status? */
+      if (sbuf.st_ctime > sbuf.st_atime) {
+	tp[0] = sbuf.st_atime;	/* preserve atime and mtime */
+	tp[1] = sbuf.st_mtime;
+	utime (file,tp);	/* set the times */
+      }
+    }
+  }
+				/* in case INBOX but not mtx format */
+  else if ((errno == ENOENT) && !compare_cstring (name,"INBOX")) errno = -1;
+  return ret;			/* return what we should */
+}
+
+/* MTX manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *mtx_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case GET_INBOXPATH:
+    if (value) ret = mtx_file ((char *) value,"INBOX");
+    break;
+  }
+  return ret;
+}
+
+
+/* MTX mail scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void mtx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* MTX mail list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mtx_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_list (NIL,ref,pat);
+}
+
+
+/* MTX mail list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mtx_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_lsub (NIL,ref,pat);
+}
+
+/* MTX mail delete mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long mtx_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return mtx_rename (stream,mailbox,NIL);
+}
+
+
+/* MTX mail rename mailbox
+ * Accepts: MAIL stream
+ *	    old mailbox name
+ *	    new mailbox name (or NIL for delete)
+ * Returns: T on success, NIL on failure
+ */
+
+long mtx_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  long ret = T;
+  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  int fd,ld;
+  struct stat sbuf;
+  if (!mtx_file (file,old) ||
+      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
+		   ((s = strrchr (tmp,'/')) && !s[1])))) {
+    sprintf (tmp,newname ?
+	     "Can't rename mailbox %.80s to %.80s: invalid name" :
+	     "Can't delete mailbox %.80s: invalid name",
+	     old,newname);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+  else if ((fd = open (file,O_RDWR,NIL)) < 0) {
+    sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno));
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+				/* get exclusive parse/append permission */
+  if ((ld = lockfd (fd,lock,LOCK_EX)) < 0) {
+    MM_LOG ("Unable to lock rename mailbox",ERROR);
+    return NIL;
+  }
+				/* lock out other users */
+  if (flock (fd,LOCK_EX|LOCK_NB)) {
+    close (fd);			/* couldn't lock, give up on it then */
+    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
+    MM_LOG (tmp,ERROR);
+    unlockfd (ld,lock);		/* release exclusive parse/append permission */
+    return NIL;
+  }
+
+  if (newname) {		/* want rename? */
+    if (s = strrchr (tmp,'/')) {/* found superior to destination name? */
+      c = *++s;			/* remember first character of inferior */
+      *s = '\0';		/* tie off to get just superior */
+				/* name doesn't exist, create it */
+      if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+	  !dummy_create_path (stream,tmp,get_dir_protection (newname)))
+	ret = NIL;
+      else *s = c;		/* restore full name */
+    }
+				/* rename the file */
+    if (ret && rename (file,tmp)) {
+      sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
+	       strerror (errno));
+      MM_LOG (tmp,ERROR);
+      ret = NIL;		/* set failure */
+    }
+  }
+  else if (unlink (file)) {
+    sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
+    MM_LOG (tmp,ERROR);
+    ret = NIL;			/* set failure */
+  }
+  flock (fd,LOCK_UN);		/* release lock on the file */
+  close (fd);			/* close the file */
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+				/* recreate file if renamed INBOX */
+  if (ret && !compare_cstring (old,"INBOX")) dummy_create (NIL,"INBOX.MTX");
+  return ret;			/* return success */
+}
+
+/* Mtx Mail status
+ * Accepts: mail stream
+ *	    mailbox name
+ *	    status flags
+ * Returns: T on success, NIL on failure
+ */
+
+long mtx_status (MAILSTREAM *stream,char *mbx,long flags)
+{
+  MAILSTATUS status;
+  unsigned long i;
+  MAILSTREAM *tstream = NIL;
+  MAILSTREAM *systream = NIL;
+				/* make temporary stream (unless this mbx) */
+  if (!stream && !(stream = tstream =
+		   mail_open (NIL,mbx,OP_READONLY|OP_SILENT))) return NIL;
+  status.flags = flags;		/* return status values */
+  status.messages = stream->nmsgs;
+  status.recent = stream->recent;
+  if (flags & SA_UNSEEN)	/* must search to get unseen messages */
+    for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++)
+      if (!mail_elt (stream,i)->seen) status.unseen++;
+  status.uidnext = stream->uid_last + 1;
+  status.uidvalidity = stream->uid_validity;
+				/* calculate post-snarf results */
+  if (!status.recent && stream->inbox &&
+      (systream = mail_open (NIL,sysinbox (),OP_READONLY|OP_SILENT))) {
+    status.messages += systream->nmsgs;
+    status.recent += systream->recent;
+    if (flags & SA_UNSEEN)	/* must search to get unseen messages */
+      for (i = 1; i <= systream->nmsgs; i++)
+	if (!mail_elt (systream,i)->seen) status.unseen++;
+				/* kludge but probably good enough */
+    status.uidnext += systream->nmsgs;
+  }
+  MM_STATUS(stream,mbx,&status);/* pass status to main program */
+  if (tstream) mail_close (tstream);
+  if (systream) mail_close (systream);
+  return T;			/* success */
+}
+
+/* MTX mail open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *mtx_open (MAILSTREAM *stream)
+{
+  int fd,ld;
+  char tmp[MAILTMPLEN];
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return user_flags (&mtxproto);
+  if (stream->local) fatal ("mtx recycle stream");
+  user_flags (stream);		/* set up user flags */
+				/* canonicalize the mailbox name */
+  if (!mtx_file (tmp,stream->mailbox)) {
+    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
+    MM_LOG (tmp,ERROR);
+  }
+  if (stream->rdonly ||
+      (fd = open (tmp,O_RDWR,NIL)) < 0) {
+    if ((fd = open (tmp,O_RDONLY,NIL)) < 0) {
+      sprintf (tmp,"Can't open mailbox: %.80s",strerror (errno));
+      MM_LOG (tmp,ERROR);
+      return NIL;
+    }
+    else if (!stream->rdonly) {	/* got it, but readonly */
+      MM_LOG ("Can't get write access to mailbox, access is readonly",WARN);
+      stream->rdonly = T;
+    }
+  }
+  stream->local = fs_get (sizeof (MTXLOCAL));
+  LOCAL->fd = fd;		/* bind the file */
+  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
+  LOCAL->buflen = CHUNKSIZE - 1;
+				/* note if an INBOX or not */
+  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
+  fs_give ((void **) &stream->mailbox);
+  stream->mailbox = cpystr (tmp);
+				/* get shared parse permission */
+  if ((ld = lockfd (fd,tmp,LOCK_SH)) < 0) {
+    MM_LOG ("Unable to lock open mailbox",ERROR);
+    return NIL;
+  }
+  (*bn) (BLOCK_FILELOCK,NIL);
+  flock (LOCAL->fd,LOCK_SH);	/* lock the file */
+  (*bn) (BLOCK_NONE,NIL);
+  unlockfd (ld,tmp);		/* release shared parse permission */
+  LOCAL->filesize = 0;		/* initialize parsed file size */
+				/* time not set up yet */
+  LOCAL->lastsnarf = LOCAL->filetime = 0;
+  LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
+  stream->sequence++;		/* bump sequence number */
+				/* parse mailbox */
+  stream->nmsgs = stream->recent = 0;
+  if (mtx_ping (stream) && !stream->nmsgs)
+    MM_LOG ("Mailbox is empty",(long) NIL);
+  if (!LOCAL) return NIL;	/* failure if stream died */
+  stream->perm_seen = stream->perm_deleted =
+    stream->perm_flagged = stream->perm_answered = stream->perm_draft =
+      stream->rdonly ? NIL : T;
+  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
+  return stream;		/* return stream to caller */
+}
+
+/* MTX mail close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void mtx_close (MAILSTREAM *stream,long options)
+{
+  if (stream && LOCAL) {	/* only if a file is open */
+    int silent = stream->silent;
+    stream->silent = T;		/* note this stream is dying */
+    if (options & CL_EXPUNGE) mtx_expunge (stream,NIL,NIL);
+    stream->silent = silent;	/* restore previous status */
+    flock (LOCAL->fd,LOCK_UN);	/* unlock local file */
+    close (LOCAL->fd);		/* close the local file */
+				/* free local text buffer */
+    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+
+/* MTX mail fetch flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ * Sniffs at file to see if some other process changed the flags
+ */
+
+void mtx_flags (MAILSTREAM *stream,char *sequence,long flags)
+{
+  unsigned long i;
+  if (mtx_ping (stream) && 	/* ping mailbox, get new status for messages */
+      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
+       mail_sequence (stream,sequence)))
+    for (i = 1; i <= stream->nmsgs; i++) 
+      if (mail_elt (stream,i)->sequence) mtx_elt (stream,i);
+}
+
+/* MTX mail fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+char *mtx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
+		  long flags)
+{
+  *length = 0;			/* default to empty */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+				/* get to header position */
+  lseek (LOCAL->fd,mtx_hdrpos (stream,msgno,length),L_SET);
+				/* is buffer big enough? */
+  if (*length > LOCAL->buflen) {
+    fs_give ((void **) &LOCAL->buf);
+    LOCAL->buf = (char *) fs_get ((LOCAL->buflen = *length) + 1);
+  }
+  LOCAL->buf[*length] = '\0';	/* tie off string */
+				/* slurp the data */
+  read (LOCAL->fd,LOCAL->buf,*length);
+  return (char *) LOCAL->buf;
+}
+
+/* MTX mail fetch message text (body only)
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: T, always
+ */
+
+long mtx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  FDDATA d;
+  unsigned long i,j;
+  MESSAGECACHE *elt;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+  elt = mtx_elt (stream,msgno);	/* get message status */
+				/* if message not seen */
+  if (!(flags & FT_PEEK) && !elt->seen) {
+    elt->seen = T;		/* mark message as seen */
+				/* recalculate status */
+    mtx_update_status (stream,msgno,NIL);
+    MM_FLAGS (stream,msgno);
+  }
+				/* find header position */
+  i = mtx_hdrpos (stream,msgno,&j);
+  d.fd = LOCAL->fd;		/* set up file descriptor */
+  d.pos = i + j;
+  d.chunk = LOCAL->buf;		/* initial buffer chunk */
+  d.chunksize = CHUNKSIZE;
+  INIT (bs,fd_string,&d,elt->rfc822_size - j);
+  return T;			/* success */
+}
+
+/* MTX mail modify flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    flag(s)
+ *	    option flags
+ */
+
+void mtx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
+{
+  time_t tp[2];
+  struct stat sbuf;
+  if (!stream->rdonly) {	/* make sure the update takes */
+    fsync (LOCAL->fd);
+    fstat (LOCAL->fd,&sbuf);	/* get current write time */
+    tp[1] = LOCAL->filetime = sbuf.st_mtime;
+    tp[0] = time (0);		/* make sure read comes after all that */
+    utime (stream->mailbox,tp);
+  }
+}
+
+
+/* MTX mail per-message modify flags
+ * Accepts: MAIL stream
+ *	    message cache element
+ */
+
+void mtx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  struct stat sbuf;
+				/* maybe need to do a checkpoint? */
+  if (LOCAL->filetime && !LOCAL->shouldcheck) {
+    fstat (LOCAL->fd,&sbuf);	/* get current write time */
+    if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
+    LOCAL->filetime = 0;	/* don't do this test for any other messages */
+  }
+				/* recalculate status */
+  mtx_update_status (stream,elt->msgno,NIL);
+}
+
+/* MTX mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream still alive, NIL if not
+ */
+
+long mtx_ping (MAILSTREAM *stream)
+{
+  unsigned long i = 1;
+  long r = T;
+  int ld;
+  char lock[MAILTMPLEN];
+  struct stat sbuf;
+  if (stream && LOCAL) {	/* only if stream already open */
+    fstat (LOCAL->fd,&sbuf);	/* get current file poop */
+    if (LOCAL->filetime && !(LOCAL->mustcheck || LOCAL->shouldcheck) &&
+	(LOCAL->filetime < sbuf.st_mtime)) LOCAL->shouldcheck = T;
+				/* check for changed message status */
+    if (LOCAL->mustcheck || LOCAL->shouldcheck) {
+      LOCAL->filetime = sbuf.st_mtime;
+      if (LOCAL->shouldcheck)	/* babble when we do this unilaterally */
+	MM_NOTIFY (stream,"[CHECK] Checking for flag updates",NIL);
+      while (i <= stream->nmsgs) mtx_elt (stream,i++);
+      LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
+    }
+				/* get shared parse/append permission */
+    if ((sbuf.st_size != LOCAL->filesize) &&
+	((ld = lockfd (LOCAL->fd,lock,LOCK_SH)) >= 0)) {
+				/* parse resulting mailbox */
+      r = (mtx_parse (stream)) ? T : NIL;
+      unlockfd (ld,lock);	/* release shared parse/append permission */
+    }
+    if (LOCAL) {		/* stream must still be alive */
+				/* snarf if this is a read-write inbox */
+      if (stream->inbox && !stream->rdonly) {
+	mtx_snarf (stream);
+	fstat (LOCAL->fd,&sbuf);/* see if file changed now */
+	if ((sbuf.st_size != LOCAL->filesize) &&
+	    ((ld = lockfd (LOCAL->fd,lock,LOCK_SH)) >= 0)) {
+				/* parse resulting mailbox */
+	  r = (mtx_parse (stream)) ? T : NIL;
+	  unlockfd (ld,lock);	/* release shared parse/append permission */
+	}
+      }
+    }
+  }
+  return r;			/* return result of the parse */
+}
+
+
+/* MTX mail check mailbox (reparses status too)
+ * Accepts: MAIL stream
+ */
+
+void mtx_check (MAILSTREAM *stream)
+{
+				/* mark that a check is desired */
+  if (LOCAL) LOCAL->mustcheck = T;
+  if (mtx_ping (stream)) MM_LOG ("Check completed",(long) NIL);
+}
+
+/* MTX mail snarf messages from system inbox
+ * Accepts: MAIL stream
+ */
+
+void mtx_snarf (MAILSTREAM *stream)
+{
+  unsigned long i = 0;
+  unsigned long j,r,hdrlen,txtlen;
+  struct stat sbuf;
+  char *hdr,*txt,lock[MAILTMPLEN],tmp[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  MAILSTREAM *sysibx = NIL;
+  int ld;
+				/* give up if can't get exclusive permission */
+  if ((time (0) >= (LOCAL->lastsnarf +
+		    (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL))) &&
+      strcmp (sysinbox (),stream->mailbox) &&
+      ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) >= 0)) {
+    MM_CRITICAL (stream);	/* go critical */
+				/* sizes match and anything in sysinbox? */
+    if (!stat (sysinbox (),&sbuf) && sbuf.st_size &&
+	!fstat (LOCAL->fd,&sbuf) && (sbuf.st_size == LOCAL->filesize) && 
+	(sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) &&
+	(!sysibx->rdonly) && (r = sysibx->nmsgs)) {
+				/* yes, go to end of file in our mailbox */
+      lseek (LOCAL->fd,sbuf.st_size,L_SET);
+				/* for each message in sysibx mailbox */
+      while (r && (++i <= sysibx->nmsgs)) {
+				/* snarf message from system INBOX */
+	hdr = cpystr (mail_fetchheader_full (sysibx,i,NIL,&hdrlen,NIL));
+	txt = mail_fetchtext_full (sysibx,i,&txtlen,FT_PEEK);
+				/* if have a message */
+	if (j = hdrlen + txtlen) {
+				/* calculate header line */
+	  mail_date (LOCAL->buf,elt = mail_elt (sysibx,i));
+	  sprintf (LOCAL->buf + strlen (LOCAL->buf),
+		   ",%lu;0000000000%02o\015\012",j,(unsigned)
+		   ((fSEEN * elt->seen) + (fDELETED * elt->deleted) +
+		    (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
+		    (fDRAFT * elt->draft)));
+				/* copy message */
+	  if ((write (LOCAL->fd,LOCAL->buf,strlen (LOCAL->buf)) < 0) ||
+	      (write (LOCAL->fd,hdr,hdrlen) < 0) ||
+	      (write (LOCAL->fd,txt,txtlen) < 0)) r = 0;
+	}
+	fs_give ((void **) &hdr);
+      }
+
+				/* make sure all the updates take */
+      if (fsync (LOCAL->fd)) r = 0;
+      if (r) {			/* delete all the messages we copied */
+	if (r == 1) strcpy (tmp,"1");
+	else sprintf (tmp,"1:%lu",r);
+	mail_flag (sysibx,tmp,"\\Deleted",ST_SET);
+	mail_expunge (sysibx);	/* now expunge all those messages */
+      }
+      else {
+	sprintf (LOCAL->buf,"Can't copy new mail: %s",strerror (errno));
+	MM_LOG (LOCAL->buf,WARN);
+	ftruncate (LOCAL->fd,sbuf.st_size);
+      }
+      fstat (LOCAL->fd,&sbuf);	/* yes, get current file size */
+      LOCAL->filetime = sbuf.st_mtime;
+    }
+    if (sysibx) mail_close (sysibx);
+    MM_NOCRITICAL (stream);	/* release critical */
+    unlockfd (ld,lock);		/* release exclusive parse/append permission */
+    LOCAL->lastsnarf = time (0);/* note time of last snarf */
+  }
+}
+
+/* MTX mail expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long mtx_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  long ret;
+  time_t tp[2];
+  struct stat sbuf;
+  off_t pos = 0;
+  int ld;
+  unsigned long i = 1;
+  unsigned long j,k,m,recent;
+  unsigned long n = 0;
+  unsigned long delta = 0;
+  char lock[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  if (!(ret = (sequence ? ((options & EX_UID) ?
+			   mail_uid_sequence (stream,sequence) :
+			   mail_sequence (stream,sequence)) : LONGT) &&
+	mtx_ping (stream)));	/* parse sequence if given, ping stream */
+  else if (stream->rdonly) MM_LOG ("Expunge ignored on readonly mailbox",WARN);
+  else {
+    if (LOCAL->filetime && !LOCAL->shouldcheck) {
+      fstat (LOCAL->fd,&sbuf);	/* get current write time */
+      if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
+    }
+  /* The cretins who designed flock() created a window of vulnerability in
+   * upgrading locks from shared to exclusive or downgrading from exclusive
+   * to shared.  Rather than maintain the lock at shared status at a minimum,
+   * flock() actually *releases* the former lock.  Obviously they never talked
+   * to any database guys.  Fortunately, we have the parse/append permission
+   * lock.  If we require this lock before going exclusive on the mailbox,
+   * another process can not sneak in and steal the exclusive mailbox lock on
+   * us, because it will block on trying to get parse/append permission first.
+   */
+				/* get exclusive parse/append permission */
+    if ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) < 0)
+      MM_LOG ("Unable to lock expunge mailbox",ERROR);
+				/* make sure see any newly-arrived messages */
+    else if (!mtx_parse (stream));
+				/* get exclusive access */
+    else if (flock (LOCAL->fd,LOCK_EX|LOCK_NB)) {
+      (*bn) (BLOCK_FILELOCK,NIL);
+      flock (LOCAL->fd,LOCK_SH);/* recover previous lock */
+      (*bn) (BLOCK_NONE,NIL);
+      MM_LOG ("Can't expunge because mailbox is in use by another process",
+	      ERROR);
+      unlockfd (ld,lock);	/* release exclusive parse/append permission */
+    }
+
+    else {
+      MM_CRITICAL (stream);	/* go critical */
+      recent = stream->recent;	/* get recent now that pinged and locked */
+				/* for each message */
+      while (i <= stream->nmsgs) {
+				/* get cache element */
+	elt = mtx_elt (stream,i);
+				/* number of bytes to smash or preserve */
+	k = elt->private.special.text.size + elt->rfc822_size;
+				/* if need to expunge this message */
+	if (elt->deleted && (sequence ? elt->sequence : T)) {
+				/* if recent, note one less recent message */
+	  if (elt->recent) --recent;
+	  delta += k;		/* number of bytes to delete */
+				/* notify upper levels */
+	  mail_expunged (stream,i);
+	  n++;			/* count up one more expunged message */
+	}
+	else if (i++ && delta) {/* preserved message */
+				/* first byte to preserve */
+	  j = elt->private.special.offset;
+	  do {			/* read from source position */
+	    m = min (k,LOCAL->buflen);
+	    lseek (LOCAL->fd,j,L_SET);
+	    read (LOCAL->fd,LOCAL->buf,m);
+	    pos = j - delta;	/* write to destination position */
+	    lseek (LOCAL->fd,pos,L_SET);
+	    while (T) {
+	      lseek (LOCAL->fd,pos,L_SET);
+	      if (write (LOCAL->fd,LOCAL->buf,m) > 0) break;
+	      MM_NOTIFY (stream,strerror (errno),WARN);
+	      MM_DISKERROR (stream,errno,T);
+	    }
+	    pos += m;		/* new position */
+	    j += m;		/* next chunk, perhaps */
+	  } while (k -= m);	/* until done */
+				/* note the new address of this text */
+	  elt->private.special.offset -= delta;
+	}
+				/* preserved but no deleted messages */
+	else pos = elt->private.special.offset + k;
+      }
+      if (n) {			/* truncate file after last message */
+	if (pos != (LOCAL->filesize -= delta)) {
+	  sprintf (LOCAL->buf,
+		   "Calculated size mismatch %lu != %lu, delta = %lu",
+		   (unsigned long) pos,(unsigned long) LOCAL->filesize,delta);
+	  MM_LOG (LOCAL->buf,WARN);
+	  LOCAL->filesize = pos;/* fix it then */
+	}
+	ftruncate (LOCAL->fd,LOCAL->filesize);
+	sprintf (LOCAL->buf,"Expunged %lu messages",n);
+				/* output the news */
+	MM_LOG (LOCAL->buf,(long) NIL);
+      }
+      else MM_LOG ("No messages deleted, so no update needed",(long) NIL);
+      fsync (LOCAL->fd);	/* force disk update */
+      fstat (LOCAL->fd,&sbuf);	/* get new write time */
+      tp[1] = LOCAL->filetime = sbuf.st_mtime;
+      tp[0] = time (0);		/* reset atime to now */
+      utime (stream->mailbox,tp);
+      MM_NOCRITICAL (stream);	/* release critical */
+				/* notify upper level of new mailbox size */
+      mail_exists (stream,stream->nmsgs);
+      mail_recent (stream,recent);
+      (*bn) (BLOCK_FILELOCK,NIL);
+      flock (LOCAL->fd,LOCK_SH);/* allow sharers again */
+      (*bn) (BLOCK_NONE,NIL);
+      unlockfd (ld,lock);	/* release exclusive parse/append permission */
+    }
+  }
+  return ret;
+}
+
+/* MTX mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if success, NIL if failed
+ */
+
+long mtx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  struct stat sbuf;
+  time_t tp[2];
+  MESSAGECACHE *elt;
+  unsigned long i,j,k;
+  long ret = LONGT;
+  int fd,ld;
+  char file[MAILTMPLEN],lock[MAILTMPLEN];
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+				/* make sure valid mailbox */
+  if (!mtx_isvalid (mailbox,LOCAL->buf)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
+    return NIL;
+  case 0:			/* merely empty file? */
+    break;
+  case EACCES:			/* file protected */
+    sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
+    MM_LOG (LOCAL->buf,ERROR);
+    return NIL;
+  case EINVAL:
+    if (pc) return (*pc) (stream,sequence,mailbox,options);
+    sprintf (LOCAL->buf,"Invalid MTX-format mailbox name: %.80s",mailbox);
+    MM_LOG (LOCAL->buf,ERROR);
+    return NIL;
+  default:
+    if (pc) return (*pc) (stream,sequence,mailbox,options);
+    sprintf (LOCAL->buf,"Not a MTX-format mailbox: %.80s",mailbox);
+    MM_LOG (LOCAL->buf,ERROR);
+    return NIL;
+  }
+  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+	mail_sequence (stream,sequence))) return NIL;
+				/* got file? */  
+  if ((fd = open (mtx_file (file,mailbox),O_RDWR,NIL)) < 0) {
+    sprintf (LOCAL->buf,"Unable to open copy mailbox: %s",strerror (errno));
+    MM_LOG (LOCAL->buf,ERROR);
+    return NIL;
+  }
+  MM_CRITICAL (stream);		/* go critical */
+				/* get exclusive parse/append permission */
+  if (flock (fd,LOCK_SH) || ((ld = lockfd (fd,lock,LOCK_EX)) < 0)) {
+    MM_LOG ("Unable to lock copy mailbox",ERROR);
+    MM_NOCRITICAL (stream);
+    return NIL;
+  }
+  fstat (fd,&sbuf);		/* get current file size */
+  lseek (fd,sbuf.st_size,L_SET);/* move to end of file */
+
+				/* for each requested message */
+  for (i = 1; ret && (i <= stream->nmsgs); i++) 
+    if ((elt = mail_elt (stream,i))->sequence) {
+      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
+				/* number of bytes to copy */
+      k = elt->private.special.text.size + elt->rfc822_size;
+      do {			/* read from source position */
+	j = min (k,LOCAL->buflen);
+	read (LOCAL->fd,LOCAL->buf,j);
+	if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
+      } while (ret && (k -= j));/* until done */
+    }
+				/* make sure all the updates take */
+  if (!(ret && (ret = !fsync (fd)))) {
+    sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno));
+    MM_LOG (LOCAL->buf,ERROR);
+    ftruncate (fd,sbuf.st_size);
+  }
+  if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */
+				/* else preserve \Marked status */
+  else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0);
+  tp[1] = sbuf.st_mtime;	/* preserve mtime */
+  utime (file,tp);		/* set the times */
+  close (fd);			/* close the file */
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+  MM_NOCRITICAL (stream);	/* release critical */
+				/* delete all requested messages */
+  if (ret && (options & CP_MOVE)) {
+    for (i = 1; i <= stream->nmsgs; i++)
+      if ((elt = mtx_elt (stream,i))->sequence) {
+	elt->deleted = T;	/* mark message deleted */
+				/* recalculate status */
+	mtx_update_status (stream,i,NIL);
+      }
+    if (!stream->rdonly) {	/* make sure the update takes */
+      fsync (LOCAL->fd);
+      fstat (LOCAL->fd,&sbuf);	/* get current write time */
+      tp[1] = LOCAL->filetime = sbuf.st_mtime;
+      tp[0] = time (0);		/* make sure atime remains greater */
+      utime (stream->mailbox,tp);
+    }
+  }
+  if (ret && mail_parameters (NIL,GET_COPYUID,NIL))
+    MM_LOG ("Can not return meaningful COPYUID with this mailbox format",WARN);
+  return ret;
+}
+
+/* MTX mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long mtx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct stat sbuf;
+  int fd,ld,c;
+  char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  time_t tp[2];
+  FILE *df;
+  MESSAGECACHE elt;
+  long f;
+  unsigned long i,uf;
+  STRING *message;
+  long ret = LONGT;
+				/* default stream to prototype */
+  if (!stream) stream = user_flags (&mtxproto);
+				/* make sure valid mailbox */
+  if (!mtx_isvalid (mailbox,tmp)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    if (!compare_cstring (mailbox,"INBOX")) dummy_create (NIL,"INBOX.MTX");
+    else {
+      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+      return NIL;
+    }
+				/* falls through */
+  case 0:			/* merely empty file? */
+    break;
+  case EACCES:			/* file protected */
+    sprintf (tmp,"Can't access destination: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  case EINVAL:
+    sprintf (tmp,"Invalid MTX-format mailbox name: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  default:
+    sprintf (tmp,"Not a MTX-format mailbox: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+				/* get first message */
+  if (!MM_APPEND (af) (stream,data,&flags,&date,&message)) return NIL;
+
+				/* open destination mailbox */
+  if (((fd = open (mtx_file (file,mailbox),O_WRONLY|O_APPEND,NIL)) < 0) ||
+      !(df = fdopen (fd,"ab"))) {
+    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+				/* get parse/append permission */
+  if (flock (fd,LOCK_SH) || ((ld = lockfd (fd,lock,LOCK_EX)) < 0)) {
+    MM_LOG ("Unable to lock append mailbox",ERROR);
+    close (fd);
+    return NIL;
+  }
+  MM_CRITICAL (stream);		/* go critical */
+  fstat (fd,&sbuf);		/* get current file size */
+  errno = 0;
+  do {				/* parse flags */
+    if (!SIZE (message)) {	/* guard against zero-length */
+      MM_LOG ("Append of zero-length message",ERROR);
+      ret = NIL;
+      break;
+    }
+    f = mail_parse_flags (stream,flags,&i);
+				/* reverse bits (dontcha wish we had CIRC?) */
+    for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i)));
+    if (date) {			/* parse date if given */
+      if (!mail_parse_date (&elt,date)) {
+	sprintf (tmp,"Bad date in append: %.80s",date);
+	MM_LOG (tmp,ERROR);
+	ret = NIL;		/* mark failure */
+	break;
+      }
+      mail_date (tmp,&elt);	/* write preseved date */
+    }
+    else internal_date (tmp);	/* get current date in IMAP format */
+				/* write header */
+    if (fprintf (df,"%s,%lu;%010lo%02lo\015\012",tmp,i = SIZE (message),uf,
+		 (unsigned long) f) < 0) ret = NIL;
+    else {			/* write message */
+      if (i) do c = 0xff & SNX (message);
+      while ((putc (c,df) != EOF) && --i);
+				/* get next message */
+      if (i || !MM_APPEND (af) (stream,data,&flags,&date,&message)) ret = NIL;
+    }
+  } while (ret && message);
+				/* if error... */
+  if (!ret || (fflush (df) == EOF)) {
+    ftruncate (fd,sbuf.st_size);/* revert file */
+    close (fd);			/* make sure fclose() doesn't corrupt us */
+    if (errno) {
+      sprintf (tmp,"Message append failed: %s",strerror (errno));
+      MM_LOG (tmp,ERROR);
+    }
+    ret = NIL;
+  }
+  if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */
+				/* else preserve \Marked status */
+  else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0);
+  tp[1] = sbuf.st_mtime;	/* preserve mtime */
+  utime (file,tp);		/* set the times */
+  fclose (df);			/* close the file */
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+  MM_NOCRITICAL (stream);	/* release critical */
+  if (ret && mail_parameters (NIL,GET_APPENDUID,NIL))
+    MM_LOG ("Can not return meaningful APPENDUID with this mailbox format",
+	    WARN);
+  return ret;
+}
+
+/* Internal routines */
+
+
+/* MTX mail generate file string
+ * Accepts: temporary buffer to write into
+ *	    mailbox name string
+ * Returns: local file string or NIL if failure
+ */
+
+char *mtx_file (char *dst,char *name)
+{
+  char tmp[MAILTMPLEN];
+  char *s = mailboxfile (dst,name);
+				/* return our standard inbox */
+  return (s && !*s) ? mailboxfile (dst,mtx_isvalid ("~/INBOX",tmp) ?
+				   "~/INBOX" : "INBOX.MTX") : s;
+}
+
+/* MTX mail parse mailbox
+ * Accepts: MAIL stream
+ * Returns: T if parse OK
+ *	    NIL if failure, stream aborted
+ */
+
+long mtx_parse (MAILSTREAM *stream)
+{
+  struct stat sbuf;
+  MESSAGECACHE *elt = NIL;
+  unsigned char c,*s,*t,*x;
+  char tmp[MAILTMPLEN];
+  unsigned long i,j;
+  long curpos = LOCAL->filesize;
+  long nmsgs = stream->nmsgs;
+  long recent = stream->recent;
+  short added = NIL;
+  short silent = stream->silent;
+  fstat (LOCAL->fd,&sbuf);	/* get status */
+  if (sbuf.st_size < curpos) {	/* sanity check */
+    sprintf (tmp,"Mailbox shrank from %lu to %lu!",
+	     (unsigned long) curpos,(unsigned long) sbuf.st_size);
+    MM_LOG (tmp,ERROR);
+    mtx_close (stream,NIL);
+    return NIL;
+  }
+  stream->silent = T;		/* don't pass up exists events yet */
+  while (sbuf.st_size - curpos){/* while there is stuff to parse */
+				/* get to that position in the file */
+    lseek (LOCAL->fd,curpos,L_SET);
+    if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) {
+      sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s",
+	       (unsigned long) curpos,(unsigned long) sbuf.st_size,
+	       i ? strerror (errno) : "no data read");
+      MM_LOG (tmp,ERROR);
+      mtx_close (stream,NIL);
+      return NIL;
+    }
+    LOCAL->buf[i] = '\0';	/* tie off buffer just in case */
+    if (!((s = strchr (LOCAL->buf,'\015')) && (s[1] == '\012'))) {
+      sprintf (tmp,"Unable to find CRLF at %lu in %lu bytes, text: %s",
+	       (unsigned long) curpos,i,(char *) LOCAL->buf);
+      MM_LOG (tmp,ERROR);
+      mtx_close (stream,NIL);
+      return NIL;
+    }
+    *s = '\0';			/* tie off header line */
+    i = (s + 2) - LOCAL->buf;	/* note start of text offset */
+    if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) {
+      sprintf (tmp,"Unable to parse internal header at %lu: %s",
+	       (unsigned long) curpos,(char *) LOCAL->buf);
+      MM_LOG (tmp,ERROR);
+      mtx_close (stream,NIL);
+      return NIL;
+    }
+    *s++ = '\0'; *t++ = '\0';	/* tie off fields */
+
+    added = T;			/* note that a new message was added */
+				/* swell the cache */
+    mail_exists (stream,++nmsgs);
+				/* instantiate an elt for this message */
+    (elt = mail_elt (stream,nmsgs))->valid = T;
+    elt->private.uid = ++stream->uid_last;
+				/* note file offset of header */
+    elt->private.special.offset = curpos;
+				/* in case error */
+    elt->private.special.text.size = 0;
+				/* header size not known yet */
+    elt->private.msg.header.text.size = 0;
+    x = s;			/* parse the header components */
+    if (mail_parse_date (elt,LOCAL->buf) &&
+	(elt->rfc822_size = strtoul (s,(char **) &s,10)) && (!(s && *s)) &&
+	isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) &&
+	isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) &&
+	isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) &&
+	isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12])
+      elt->private.special.text.size = i;
+    else {			/* oops */
+      sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s",
+	       curpos,(char *) LOCAL->buf,(char *) x,(char *) t);
+      MM_LOG (tmp,ERROR);
+      mtx_close (stream,NIL);
+      return NIL;
+    }
+				/* make sure didn't run off end of file */
+    if ((curpos += (elt->rfc822_size + i)) > sbuf.st_size) {
+      sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
+	       elt->private.special.offset,(unsigned long) curpos,
+	       (unsigned long) sbuf.st_size);
+      MM_LOG (tmp,ERROR);
+      mtx_close (stream,NIL);
+      return NIL;
+    }
+    c = t[10];			/* remember first system flags byte */
+    t[10] = '\0';		/* tie off flags */
+    j = strtoul (t,NIL,8);	/* get user flags value */
+    t[10] = c;			/* restore first system flags byte */
+				/* set up all valid user flags (reversed!) */
+    while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
+		  stream->user_flags[i]) elt->user_flags |= 1 << i;
+				/* calculate system flags */
+    if ((j = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T;
+    if (j & fDELETED) elt->deleted = T;
+    if (j & fFLAGGED) elt->flagged = T;
+    if (j & fANSWERED) elt->answered = T;
+    if (j & fDRAFT) elt->draft = T;
+    if (!(j & fOLD)) {		/* newly arrived message? */
+      elt->recent = T;
+      recent++;			/* count up a new recent message */
+				/* mark it as old */
+      mtx_update_status (stream,nmsgs,NIL);
+    }
+  }
+  fsync (LOCAL->fd);		/* make sure all the fOLD flags take */
+				/* update parsed file size and time */
+  LOCAL->filesize = sbuf.st_size;
+  fstat (LOCAL->fd,&sbuf);	/* get status again to ensure time is right */
+  LOCAL->filetime = sbuf.st_mtime;
+  if (added && !stream->rdonly){/* make sure atime updated */
+    time_t tp[2];
+    tp[0] = time (0);
+    tp[1] = LOCAL->filetime;
+    utime (stream->mailbox,tp);
+  }
+  stream->silent = silent;	/* can pass up events now */
+  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
+  mail_recent (stream,recent);	/* and of change in recent messages */
+  return LONGT;			/* return the winnage */
+}
+
+/* MTX get cache element with status updating from file
+ * Accepts: MAIL stream
+ *	    message number
+ * Returns: cache element
+ */
+
+MESSAGECACHE *mtx_elt (MAILSTREAM *stream,unsigned long msgno)
+{
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  struct {			/* old flags */
+    unsigned int seen : 1;
+    unsigned int deleted : 1;
+    unsigned int flagged : 1;
+    unsigned int answered : 1;
+    unsigned int draft : 1;
+    unsigned long user_flags;
+  } old;
+  old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged;
+  old.answered = elt->answered; old.draft = elt->draft;
+  old.user_flags = elt->user_flags;
+  mtx_read_flags (stream,elt);
+  if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
+      (old.flagged != elt->flagged) || (old.answered != elt->answered) ||
+      (old.draft != elt->draft) || (old.user_flags != elt->user_flags))
+    MM_FLAGS (stream,msgno);	/* let top level know */
+  return elt;
+}
+
+/* MTX read flags from file
+ * Accepts: MAIL stream
+ * Returns: cache element
+ */
+
+void mtx_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  unsigned long i,j;
+				/* noop if readonly and have valid flags */
+  if (stream->rdonly && elt->valid) return;
+				/* set the seek pointer */
+  lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	 elt->private.special.text.size - 14,L_SET);
+				/* read the new flags */
+  if (read (LOCAL->fd,LOCAL->buf,12) < 0) {
+    sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno));
+    fatal (LOCAL->buf);
+  }
+				/* calculate system flags */
+  i = (((LOCAL->buf[10]-'0') * 8) + LOCAL->buf[11]-'0');
+  elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL;
+  elt->flagged = i & fFLAGGED ? T : NIL;
+  elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL;
+  LOCAL->buf[10] = '\0';	/* tie off flags */
+  j = strtoul(LOCAL->buf,NIL,8);/* get user flags value */
+				/* set up all valid user flags (reversed!) */
+  while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
+		stream->user_flags[i]) elt->user_flags |= 1 << i;
+  elt->valid = T;		/* have valid flags now */
+}
+
+/* MTX update status string
+ * Accepts: MAIL stream
+ *	    message number
+ *	    flag saying whether or not to sync
+ */
+
+void mtx_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag)
+{
+  time_t tp[2];
+  struct stat sbuf;
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  unsigned long j,k = 0;
+				/* readonly */
+  if (stream->rdonly || !elt->valid) mtx_read_flags (stream,elt);
+  else {			/* readwrite */
+    j = elt->user_flags;	/* get user flags */
+				/* reverse bits (dontcha wish we had CIRC?) */
+    while (j) k |= 1 << (29 - find_rightmost_bit (&j));
+				/* print new flag string */
+    sprintf (LOCAL->buf,"%010lo%02o",k,(unsigned)
+	     (fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
+	      (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
+	      (fDRAFT * elt->draft)));
+				/* get to that place in the file */
+    lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	   elt->private.special.text.size - 14,L_SET);
+				/* write new flags */
+    write (LOCAL->fd,LOCAL->buf,12);
+    if (syncflag) {		/* sync if requested */
+      fsync (LOCAL->fd);
+      fstat (LOCAL->fd,&sbuf);	/* get new write time */
+      tp[1] = LOCAL->filetime = sbuf.st_mtime;
+      tp[0] = time (0);		/* make sure read is later */
+      utime (stream->mailbox,tp);
+    }
+  }
+}
+
+/* MTX locate header for a message
+ * Accepts: MAIL stream
+ *	    message number
+ *	    pointer to returned header size
+ * Returns: position of header in file
+ */
+
+unsigned long mtx_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			  unsigned long *size)
+{
+  unsigned long siz;
+  long i = 0;
+  int q = 0;
+  char *s,tmp[MAILTMPLEN];
+  MESSAGECACHE *elt = mtx_elt (stream,msgno);
+  unsigned long ret = elt->private.special.offset +
+    elt->private.special.text.size;
+				/* is header size known? */
+  if (!(*size = elt->private.msg.header.text.size)) {
+    lseek (LOCAL->fd,ret,L_SET);/* get to header position */
+				/* search message for CRLF CRLF */
+    for (siz = 1,s = tmp; siz <= elt->rfc822_size; siz++) {
+				/* read another buffer as necessary */
+      if ((--i <= 0) &&		/* buffer empty? */
+	  (read (LOCAL->fd,s = tmp,
+		 i = min (elt->rfc822_size - siz,(long) MAILTMPLEN)) < 0))
+	return ret;		/* I/O error? */
+      switch (q) {		/* sniff at buffer */
+      case 0:			/* first character */
+	q = (*s++ == '\015') ? 1 : 0;
+	break;
+      case 1:			/* second character */
+	q = (*s++ == '\012') ? 2 : 0;
+	break;
+      case 2:			/* third character */
+	q = (*s++ == '\015') ? 3 : 0;
+	break;
+      case 3:			/* fourth character */
+	if (*s++ == '\012') {	/* have the sequence? */
+				/* yes, note for later */
+	  elt->private.msg.header.text.size = *size = siz;
+	  return ret;
+	}
+	q = 0;			/* lost... */
+	break;
+      }
+    }
+				/* header consumes entire message */
+    elt->private.msg.header.text.size = *size = elt->rfc822_size;
+  }
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/mx.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1287 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	MX mail routines
+ *
+ * Author(s):	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	3 May 1996
+ * Last Edited:	6 January 2008
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "mail.h"
+#include "osdep.h"
+#include <pwd.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "misc.h"
+#include "dummy.h"
+#include "fdstring.h"
+
+/* Index file */
+
+#define MXINDEXNAME "/.mxindex"
+#define MXINDEX(d,s) strcat (mx_file (d,s),MXINDEXNAME)
+
+
+/* MX I/O stream local data */
+	
+typedef struct mx_local {
+  int fd;			/* file descriptor of open index */
+  unsigned char *buf;		/* temporary buffer */
+  unsigned long buflen;		/* current size of temporary buffer */
+  unsigned long cachedtexts;	/* total size of all cached texts */
+  time_t scantime;		/* last time directory scanned */
+} MXLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((MXLOCAL *) stream->local)
+
+
+/* Function prototypes */
+
+DRIVER *mx_valid (char *name);
+int mx_isvalid (char *name,char *tmp);
+int mx_namevalid (char *name);
+void *mx_parameters (long function,void *value);
+long mx_dirfmttest (char *name);
+void mx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+long mx_scan_contents (char *name,char *contents,unsigned long csiz,
+		       unsigned long fsiz);
+void mx_list (MAILSTREAM *stream,char *ref,char *pat);
+void mx_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long mx_subscribe (MAILSTREAM *stream,char *mailbox);
+long mx_unsubscribe (MAILSTREAM *stream,char *mailbox);
+long mx_create (MAILSTREAM *stream,char *mailbox);
+long mx_delete (MAILSTREAM *stream,char *mailbox);
+long mx_rename (MAILSTREAM *stream,char *old,char *newname);
+int mx_rename_work (char *src,size_t srcl,char *dst,size_t dstl,char *name);
+MAILSTREAM *mx_open (MAILSTREAM *stream);
+void mx_close (MAILSTREAM *stream,long options);
+void mx_fast (MAILSTREAM *stream,char *sequence,long flags);
+char *mx_fast_work (MAILSTREAM *stream,MESSAGECACHE *elt);
+char *mx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
+		 long flags);
+long mx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+void mx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
+void mx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
+long mx_ping (MAILSTREAM *stream);
+void mx_check (MAILSTREAM *stream);
+long mx_expunge (MAILSTREAM *stream,char *sequence,long options);
+long mx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,
+	      long options);
+long mx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+long mx_append_msg (MAILSTREAM *stream,char *flags,MESSAGECACHE *elt,
+		    STRING *st,SEARCHSET *set);
+
+int mx_select (struct direct *name);
+int mx_numsort (const void *d1,const void *d2);
+char *mx_file (char *dst,char *name);
+long mx_lockindex (MAILSTREAM *stream);
+void mx_unlockindex (MAILSTREAM *stream);
+void mx_setdate (char *file,MESSAGECACHE *elt);
+
+
+/* MX mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER mxdriver = {
+  "mx",				/* driver name */
+				/* driver flags */
+  DR_MAIL|DR_LOCAL|DR_NOFAST|DR_CRLF|DR_LOCKING|DR_DIRFMT,
+  (DRIVER *) NIL,		/* next driver */
+  mx_valid,			/* mailbox is valid for us */
+  mx_parameters,		/* manipulate parameters */
+  mx_scan,			/* scan mailboxes */
+  mx_list,			/* find mailboxes */
+  mx_lsub,			/* find subscribed mailboxes */
+  mx_subscribe,			/* subscribe to mailbox */
+  mx_unsubscribe,		/* unsubscribe from mailbox */
+  mx_create,			/* create mailbox */
+  mx_delete,			/* delete mailbox */
+  mx_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  mx_open,			/* open mailbox */
+  mx_close,			/* close mailbox */
+  mx_fast,			/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  mx_header,			/* fetch message header only */
+  mx_text,			/* fetch message body only */
+  NIL,				/* fetch partial message test */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  mx_flag,			/* modify flags */
+  mx_flagmsg,			/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  mx_ping,			/* ping mailbox to see if still alive */
+  mx_check,			/* check for new messages */
+  mx_expunge,			/* expunge deleted messages */
+  mx_copy,			/* copy messages to another mailbox */
+  mx_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM mxproto = {&mxdriver};
+
+/* MX mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *mx_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+  return mx_isvalid (name,tmp) ? &mxdriver : NIL;
+}
+
+
+/* MX mail test for valid mailbox
+ * Accepts: mailbox name
+ *	    temporary buffer to use
+ * Returns: T if valid, NIL otherwise with errno holding dir stat error
+ */
+
+int mx_isvalid (char *name,char *tmp)
+{
+  struct stat sbuf;
+  errno = NIL;			/* zap error */
+  if ((strlen (name) <= NETMAXMBX) && *mx_file (tmp,name) &&
+      !stat (tmp,&sbuf) && ((sbuf.st_mode & S_IFMT) == S_IFDIR)) {
+				/* name is directory; is it mx? */
+    if (!stat (MXINDEX (tmp,name),&sbuf) &&
+	((sbuf.st_mode & S_IFMT) == S_IFREG)) return T;
+    errno = NIL;		/* directory but not mx */
+  }
+  else if (!compare_cstring (name,"INBOX")) errno = NIL;
+  return NIL;
+}
+
+
+/* MX mail test for valid mailbox
+ * Accepts: mailbox name
+ * Returns: T if valid, NIL otherwise
+ */
+
+int mx_namevalid (char *name)
+{
+  char *s = (*name == '/') ? name + 1 : name;
+  while (s && *s) {		/* make sure valid name */
+    if (isdigit (*s)) s++;	/* digit, check this node further... */
+    else if (*s == '/') break;	/* all digit node, barf */
+				/* non-digit, skip to next node or return */
+    else if (!((s = strchr (s+1,'/')) && *++s)) return T;
+  }
+  return NIL;			/* all numeric or empty node */
+}
+
+/* MX manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *mx_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case GET_INBOXPATH:
+    if (value) ret = mailboxfile ((char *) value,"~/INBOX");
+    break;
+  case GET_DIRFMTTEST:
+    ret = (void *) mx_dirfmttest;
+    break;
+  case GET_SCANCONTENTS:
+    ret = (void *) mx_scan_contents;
+    break;
+  }
+  return ret;
+}
+
+
+/* MX test for directory format internal node
+ * Accepts: candidate node name
+ * Returns: T if internal name, NIL otherwise
+ */
+
+long mx_dirfmttest (char *name)
+{
+  int c;
+				/* success if index name or all-numberic */
+  if (strcmp (name,MXINDEXNAME+1))
+    while (c = *name++) if (!isdigit (c)) return NIL;
+  return LONGT;
+}
+
+/* MX scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void mx_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* MX scan mailbox for contents
+ * Accepts: mailbox name
+ *	    desired contents
+ *	    contents size
+ *	    file size (ignored)
+ * Returns: NIL if contents not found, T if found
+ */
+
+long mx_scan_contents (char *name,char *contents,unsigned long csiz,
+			unsigned long fsiz)
+{
+  long i,nfiles;
+  void *a;
+  char *s;
+  long ret = NIL;
+  size_t namelen = strlen (name);
+  struct stat sbuf;
+  struct direct **names = NIL;
+  if ((nfiles = scandir (name,&names,mx_select,mx_numsort)) > 0)
+    for (i = 0; i < nfiles; ++i) {
+      if (!ret) {
+	sprintf (s = (char *) fs_get (namelen + strlen (names[i]->d_name) + 2),
+		 "%s/%s",name,names[i]->d_name);
+	if (!stat (s,&sbuf) && (csiz <= sbuf.st_size))
+	  ret = dummy_scan_contents (s,contents,csiz,sbuf.st_size);
+	fs_give ((void **) &s);
+      }
+      fs_give ((void **) &names[i]);
+    }
+				/* free directory list */
+  if (a = (void *) names) fs_give ((void **) &a);
+  return ret;
+}
+
+/* MX list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mx_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_list (NIL,ref,pat);
+}
+
+
+/* MX list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void mx_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_lsub (NIL,ref,pat);
+}
+
+/* MX mail subscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to add to subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long mx_subscribe (MAILSTREAM *stream,char *mailbox)
+{
+  return sm_subscribe (mailbox);
+}
+
+
+/* MX mail unsubscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to delete from subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long mx_unsubscribe (MAILSTREAM *stream,char *mailbox)
+{
+  return sm_unsubscribe (mailbox);
+}
+
+/* MX mail create mailbox
+ * Accepts: mail stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long mx_create (MAILSTREAM *stream,char *mailbox)
+{
+  DRIVER *test;
+  int fd;
+  char *s,tmp[MAILTMPLEN];
+  int mask = umask (0);
+  long ret = NIL;
+  if (!mx_namevalid (mailbox))	/* validate name */
+    sprintf (tmp,"Can't create mailbox %.80s: invalid MX-format name",mailbox);
+				/* must not already exist */
+  else if ((test = mail_valid (NIL,mailbox,NIL)) &&
+	   strcmp (test->name,"dummy"))
+    sprintf (tmp,"Can't create mailbox %.80s: mailbox already exists",mailbox);
+				/* create directory */
+  else if (!dummy_create_path (stream,MXINDEX (tmp,mailbox),
+			       get_dir_protection (mailbox)))
+    sprintf (tmp,"Can't create mailbox %.80s: %s",mailbox,strerror (errno));
+  else {			/* success */
+				/* set index protection */
+    set_mbx_protections (mailbox,tmp);
+				/* tie off directory name */
+    *(s = strrchr (tmp,'/') + 1) = '\0';
+				/* set directory protection */
+    set_mbx_protections (mailbox,tmp);
+    ret = LONGT;
+  }
+  umask (mask);			/* restore mask */
+  if (!ret) MM_LOG (tmp,ERROR);	/* some error */
+  return ret;
+}
+
+/* MX mail delete mailbox
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long mx_delete (MAILSTREAM *stream,char *mailbox)
+{
+  DIR *dirp;
+  struct direct *d;
+  char *s;
+  char tmp[MAILTMPLEN];
+  if (!mx_isvalid (mailbox,tmp))
+    sprintf (tmp,"Can't delete mailbox %.80s: no such mailbox",mailbox);
+				/* delete index */
+  else if (unlink (MXINDEX (tmp,mailbox)))
+    sprintf (tmp,"Can't delete mailbox %.80s index: %s",
+	     mailbox,strerror (errno));
+  else {			/* get directory name */
+    *(s = strrchr (tmp,'/')) = '\0';
+    if (dirp = opendir (tmp)) {	/* open directory */
+      *s++ = '/';		/* restore delimiter */
+				/* massacre messages */
+      while (d = readdir (dirp)) if (mx_select (d)) {
+	strcpy (s,d->d_name);	/* make path */
+	unlink (tmp);		/* sayonara */
+      }
+      closedir (dirp);		/* flush directory */
+      *(s = strrchr (tmp,'/')) = '\0';
+      if (rmdir (tmp)) {	/* try to remove the directory */
+	sprintf (tmp,"Can't delete name %.80s: %s",mailbox,strerror (errno));
+	MM_LOG (tmp,WARN);
+      }
+    }
+    return T;			/* always success */
+  }
+  MM_LOG (tmp,ERROR);		/* something failed */
+  return NIL;
+}
+
+/* MX mail rename mailbox
+ * Accepts: MX mail stream
+ *	    old mailbox name
+ *	    new mailbox name
+ * Returns: T on success, NIL on failure
+ */
+
+long mx_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  char c,*s,tmp[MAILTMPLEN],tmp1[MAILTMPLEN];
+  struct stat sbuf;
+  if (!mx_isvalid (old,tmp))
+    sprintf (tmp,"Can't rename mailbox %.80s: no such mailbox",old);
+  else if (!mx_namevalid (newname))
+    sprintf (tmp,"Can't rename to mailbox %.80s: invalid MX-format name",
+	     newname);
+				/* new mailbox name must not be valid */
+  else if (mx_isvalid (newname,tmp))
+    sprintf (tmp,"Can't rename to mailbox %.80s: destination already exists",
+	     newname);
+  else {
+    mx_file (tmp,old);		/* build old directory name */
+    mx_file (tmp1,newname);	/* and new directory name */
+				/* easy if not INBOX */
+    if (compare_cstring (old,"INBOX")) {
+				/* found superior to destination name? */
+      if (s = strrchr (mx_file (tmp1,newname),'/')) {
+	c = *++s;	    /* remember first character of inferior */
+	*s = '\0';		/* tie off to get just superior */
+				/* name doesn't exist, create it */
+	if ((stat (tmp1,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+	    !dummy_create_path (stream,tmp1,get_dir_protection (newname)))
+	  return NIL;
+	*s = c;			/* restore full name */
+      }
+      if (!rename (tmp,tmp1)) return LONGT;
+    }
+
+				/* RFC 3501 requires this */
+    else if (dummy_create_path (stream,strcat (tmp1,"/"),
+				get_dir_protection (newname))) {
+      void *a;
+      int i,n,lasterror;
+      struct direct **names = NIL;
+      size_t srcl = strlen (tmp);
+      size_t dstl = strlen (tmp1);
+				/* rename each mx file to new directory */
+      for (i = lasterror = 0,n = scandir (tmp,&names,mx_select,mx_numsort);
+	   i < n; ++i) {
+	if (mx_rename_work (tmp,srcl,tmp1,dstl,names[i]->d_name))
+	  lasterror = errno;
+	fs_give ((void **) &names[i]);
+      }
+				/* free directory list */
+      if (a = (void *) names) fs_give ((void **) &a);
+      if (lasterror || mx_rename_work (tmp,srcl,tmp1,dstl,MXINDEXNAME+1))
+	errno = lasterror;
+      else return mx_create (NIL,"INBOX");
+    }
+    sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",
+	     old,newname,strerror (errno));
+  }
+  MM_LOG (tmp,ERROR);		/* something failed */
+  return NIL;
+}
+
+
+/* MX rename worker routine
+ * Accepts: source directory name
+ *	    source directory name length
+ *	    destination directory name
+ *	    destination directory name length
+ *	    name of node to move
+ * Returns: zero if success, non-zero if error
+ */
+
+int mx_rename_work (char *src,size_t srcl,char *dst,size_t dstl,char *name)
+{
+  int ret;
+  size_t len = strlen (name);
+  char *s = (char *) fs_get (srcl + len + 2);
+  char *d = (char *) fs_get (dstl + len + 1);
+  sprintf (s,"%s/%s",src,name);
+  sprintf (d,"%s%s",dst,name);
+  ret = rename (s,d);
+  fs_give ((void **) &s);
+  fs_give ((void **) &d);
+  return ret;
+}
+
+/* MX mail open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *mx_open (MAILSTREAM *stream)
+{
+  char tmp[MAILTMPLEN];
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return user_flags (&mxproto);
+  if (stream->local) fatal ("mx recycle stream");
+  stream->local = fs_get (sizeof (MXLOCAL));
+				/* note if an INBOX or not */
+  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
+  mx_file (tmp,stream->mailbox);/* get directory name */
+				/* canonicalize mailbox name */
+  fs_give ((void **) &stream->mailbox);
+  stream->mailbox = cpystr (tmp);
+				/* make temporary buffer */
+  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
+  LOCAL->buflen = CHUNKSIZE - 1;
+  LOCAL->scantime = 0;		/* not scanned yet */
+  LOCAL->fd = -1;		/* no index yet */
+  LOCAL->cachedtexts = 0;	/* no cached texts */
+  stream->sequence++;		/* bump sequence number */
+				/* parse mailbox */
+  stream->nmsgs = stream->recent = 0;
+  if (mx_ping (stream) && !(stream->nmsgs || stream->silent))
+    MM_LOG ("Mailbox is empty",(long) NIL);
+  stream->perm_seen = stream->perm_deleted = stream->perm_flagged =
+    stream->perm_answered = stream->perm_draft = stream->rdonly ? NIL : T;
+  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
+  stream->kwd_create = (stream->user_flags[NUSERFLAGS-1] || stream->rdonly) ?
+    NIL : T;			/* can we create new user flags? */
+  return stream;		/* return stream to caller */
+}
+
+/* MX mail close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void mx_close (MAILSTREAM *stream,long options)
+{
+  if (LOCAL) {			/* only if a file is open */
+    int silent = stream->silent;
+    stream->silent = T;		/* note this stream is dying */
+    if (options & CL_EXPUNGE) mx_expunge (stream,NIL,NIL);
+				/* free local scratch buffer */
+    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+    stream->silent = silent;	/* reset silent state */
+  }
+}
+
+/* MX mail fetch fast information
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ */
+
+void mx_fast (MAILSTREAM *stream,char *sequence,long flags)
+{
+  unsigned long i;
+  MESSAGECACHE *elt;
+  if (stream && LOCAL &&
+      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
+       mail_sequence (stream,sequence)))
+    for (i = 1; i <= stream->nmsgs; i++)
+      if ((elt = mail_elt (stream,i))->sequence) mx_fast_work (stream,elt);
+}
+
+
+/* MX mail fetch fast information
+ * Accepts: MAIL stream
+ *	    message cache element
+ * Returns: name of message file
+ */
+
+char *mx_fast_work (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  struct stat sbuf;
+  struct tm *tm;
+				/* build message file name */
+  sprintf (LOCAL->buf,"%s/%lu",stream->mailbox,elt->private.uid);
+				/* have size yet? */
+  if (!elt->rfc822_size && !stat (LOCAL->buf,&sbuf)) {
+				/* make plausible IMAPish date string */
+    tm = gmtime (&sbuf.st_mtime);
+    elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1;
+    elt->year = tm->tm_year + 1900 - BASEYEAR;
+    elt->hours = tm->tm_hour; elt->minutes = tm->tm_min;
+    elt->seconds = tm->tm_sec;
+    elt->zhours = 0; elt->zminutes = 0; elt->zoccident = 0;
+    elt->rfc822_size = sbuf.st_size;
+  }
+  return (char *) LOCAL->buf;	/* return file name */
+}
+
+/* MX mail fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+char *mx_header (MAILSTREAM *stream,unsigned long msgno,unsigned long *length,
+		 long flags)
+{
+  unsigned long i;
+  int fd;
+  MESSAGECACHE *elt;
+  *length = 0;			/* default to empty */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+  elt = mail_elt (stream,msgno);/* get elt */
+  if (!elt->private.msg.header.text.data) {
+				/* purge cache if too big */
+    if (LOCAL->cachedtexts > max (stream->nmsgs * 4096,2097152)) {
+      mail_gc (stream,GC_TEXTS);/* just can't keep that much */
+      LOCAL->cachedtexts = 0;
+    }
+    if ((fd = open (mx_fast_work (stream,elt),O_RDONLY,NIL)) < 0) return "";
+				/* is buffer big enough? */
+    if (elt->rfc822_size > LOCAL->buflen) {
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get ((LOCAL->buflen = elt->rfc822_size) + 1);
+    }
+				/* slurp message */
+    read (fd,LOCAL->buf,elt->rfc822_size);
+				/* tie off file */
+    LOCAL->buf[elt->rfc822_size] = '\0';
+    close (fd);			/* flush message file */
+				/* find end of header */
+    if (elt->rfc822_size < 4) i = 0;
+    else for (i = 4; (i < elt->rfc822_size) &&
+	      !((LOCAL->buf[i - 4] == '\015') &&
+		(LOCAL->buf[i - 3] == '\012') &&
+		(LOCAL->buf[i - 2] == '\015') &&
+		(LOCAL->buf[i - 1] == '\012')); i++);
+				/* copy header */
+    cpytxt (&elt->private.msg.header.text,LOCAL->buf,i);
+    cpytxt (&elt->private.msg.text.text,LOCAL->buf+i,elt->rfc822_size - i);
+				/* add to cached size */
+    LOCAL->cachedtexts += elt->rfc822_size;
+  }
+  *length = elt->private.msg.header.text.size;
+  return (char *) elt->private.msg.header.text.data;
+}
+
+/* MX mail fetch message text (body only)
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned stringstruct
+ *	    option flags
+ * Returns: T on success, NIL on failure
+ */
+
+long mx_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  unsigned long i;
+  MESSAGECACHE *elt;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+  elt = mail_elt (stream,msgno);
+				/* snarf message if don't have it yet */
+  if (!elt->private.msg.text.text.data) {
+    mx_header (stream,msgno,&i,flags);
+    if (!elt->private.msg.text.text.data) return NIL;
+  }
+				/* mark as seen */
+  if (!(flags & FT_PEEK) && mx_lockindex (stream)) {
+    elt->seen = T;
+    mx_unlockindex (stream);
+    MM_FLAGS (stream,msgno);
+  }
+  INIT (bs,mail_string,elt->private.msg.text.text.data,
+	elt->private.msg.text.text.size);
+  return T;
+}
+
+/* MX mail modify flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    flag(s)
+ *	    option flags
+ */
+
+void mx_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
+{
+  mx_unlockindex (stream);	/* finished with index */
+}
+
+
+/* MX per-message modify flags
+ * Accepts: MAIL stream
+ *	    message cache element
+ */
+
+void mx_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  mx_lockindex (stream);	/* lock index if not already locked */
+}
+
+/* MX mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ */
+
+long mx_ping (MAILSTREAM *stream)
+{
+  MAILSTREAM *sysibx = NIL;
+  MESSAGECACHE *elt,*selt;
+  struct stat sbuf;
+  char *s,tmp[MAILTMPLEN];
+  int fd;
+  unsigned long i,j,r,old;
+  long nmsgs = stream->nmsgs;
+  long recent = stream->recent;
+  int silent = stream->silent;
+  if (stat (stream->mailbox,&sbuf)) return NIL;
+  stream->silent = T;		/* don't pass up exists events yet */
+  if (sbuf.st_ctime != LOCAL->scantime) {
+    struct direct **names = NIL;
+    long nfiles = scandir (stream->mailbox,&names,mx_select,mx_numsort);
+    if (nfiles < 0) nfiles = 0;	/* in case error */
+    old = stream->uid_last;
+				/* note scanned now */
+    LOCAL->scantime = sbuf.st_ctime;
+				/* scan directory */
+    for (i = 0; i < nfiles; ++i) {
+				/* if newly seen, add to list */
+      if ((j = atoi (names[i]->d_name)) > old) {
+				/* swell the cache */
+	mail_exists (stream,++nmsgs);
+	stream->uid_last = (elt = mail_elt (stream,nmsgs))->private.uid = j;
+	elt->valid = T;		/* note valid flags */
+	if (old) {		/* other than the first pass? */
+	  elt->recent = T;	/* yup, mark as recent */
+	  recent++;		/* bump recent count */
+	}
+      }
+      fs_give ((void **) &names[i]);
+    }
+				/* free directory */
+    if (s = (void *) names) fs_give ((void **) &s);
+  }
+  stream->nmsgs = nmsgs;	/* don't upset mail_uid() */
+
+				/* if INBOX, snarf from system INBOX  */
+  if (mx_lockindex (stream) && stream->inbox &&
+      !strcmp (sysinbox (),stream->mailbox)) {
+    old = stream->uid_last;
+    MM_CRITICAL (stream);	/* go critical */
+				/* see if anything in system inbox */
+    if (!stat (sysinbox (),&sbuf) && sbuf.st_size &&
+	(sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) &&
+	!sysibx->rdonly && (r = sysibx->nmsgs)) {
+      for (i = 1; i <= r; ++i) {/* for each message in sysinbox mailbox */
+				/* build file name we will use */
+	sprintf (LOCAL->buf,"%s/%lu",stream->mailbox,++old);
+				/* snarf message from Berkeley mailbox */
+	selt = mail_elt (sysibx,i);
+	if (((fd = open (LOCAL->buf,O_WRONLY|O_CREAT|O_EXCL,
+			 (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL)))
+	     >= 0) &&
+	    (s = mail_fetchheader_full (sysibx,i,NIL,&j,FT_PEEK)) &&
+	    (write (fd,s,j) == j) &&
+	    (s = mail_fetchtext_full (sysibx,i,&j,FT_PEEK)) &&
+	    (write (fd,s,j) == j) && !fsync (fd) && !close (fd)) {
+				/* swell the cache */
+	  mail_exists (stream,++nmsgs);
+	  stream->uid_last =	/* create new elt, note its file number */
+	    (elt = mail_elt (stream,nmsgs))->private.uid = old;
+	  recent++;		/* bump recent count */
+				/* set up initial flags and date */
+	  elt->valid = elt->recent = T;
+	  elt->seen = selt->seen;
+	  elt->deleted = selt->deleted;
+	  elt->flagged = selt->flagged;
+	  elt->answered = selt->answered;
+	  elt->draft = selt->draft;
+	  elt->day = selt->day;elt->month = selt->month;elt->year = selt->year;
+	  elt->hours = selt->hours;elt->minutes = selt->minutes;
+	  elt->seconds = selt->seconds;
+	  elt->zhours = selt->zhours; elt->zminutes = selt->zminutes;
+	  elt->zoccident = selt->zoccident;
+	  mx_setdate (LOCAL->buf,elt);
+	  sprintf (tmp,"%lu",i);/* delete it from the sysinbox */
+	  mail_flag (sysibx,tmp,"\\Deleted",ST_SET);
+	}
+	else {			/* failed to snarf */
+	  if (fd) {		/* did it ever get opened? */
+	    close (fd);		/* close descriptor */
+	    unlink (LOCAL->buf);/* flush this file */
+	  }
+	  sprintf (tmp,"Message copy to MX mailbox failed: %.80s",
+		   s,strerror (errno));
+	  MM_LOG (tmp,ERROR);
+	  r = 0;		/* stop the snarf in its tracks */
+	}
+      }
+				/* update scan time */
+      if (!stat (stream->mailbox,&sbuf)) LOCAL->scantime = sbuf.st_ctime;      
+      mail_expunge (sysibx);	/* now expunge all those messages */
+    }
+    if (sysibx) mail_close (sysibx);
+    MM_NOCRITICAL (stream);	/* release critical */
+  }
+  mx_unlockindex (stream);	/* done with index */
+  stream->silent = silent;	/* can pass up events now */
+  mail_exists (stream,nmsgs);	/* notify upper level of mailbox size */
+  mail_recent (stream,recent);
+  return T;			/* return that we are alive */
+}
+
+/* MX mail check mailbox
+ * Accepts: MAIL stream
+ */
+
+void mx_check (MAILSTREAM *stream)
+{
+  if (mx_ping (stream)) MM_LOG ("Check completed",(long) NIL);
+}
+
+
+/* MX mail expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long mx_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  long ret;
+  MESSAGECACHE *elt;
+  unsigned long i = 1;
+  unsigned long n = 0;
+  unsigned long recent = stream->recent;
+  if (ret = (sequence ? ((options & EX_UID) ?
+			 mail_uid_sequence (stream,sequence) :
+			 mail_sequence (stream,sequence)) : LONGT) &&
+      mx_lockindex (stream)) {	/* lock the index */
+    MM_CRITICAL (stream);	/* go critical */
+    while (i <= stream->nmsgs) {/* for each message */
+      elt = mail_elt (stream,i);/* if deleted, need to trash it */
+      if (elt->deleted && (sequence ? elt->sequence : T)) {
+	sprintf (LOCAL->buf,"%s/%lu",stream->mailbox,elt->private.uid);
+	if (unlink (LOCAL->buf)) {/* try to delete the message */
+	  sprintf (LOCAL->buf,"Expunge of message %lu failed, aborted: %s",i,
+		   strerror (errno));
+	  MM_LOG (LOCAL->buf,(long) NIL);
+	  break;
+	}
+				/* note uncached */
+	LOCAL->cachedtexts -= ((elt->private.msg.header.text.data ?
+				elt->private.msg.header.text.size : 0) +
+			       (elt->private.msg.text.text.data ?
+				elt->private.msg.text.text.size : 0));
+	mail_gc_msg (&elt->private.msg,GC_ENV | GC_TEXTS);
+	if(elt->recent)--recent;/* if recent, note one less recent message */
+	mail_expunged(stream,i);/* notify upper levels */
+	n++;			/* count up one more expunged message */
+      }
+      else i++;			/* otherwise try next message */
+    }
+    if (n) {			/* output the news if any expunged */
+      sprintf (LOCAL->buf,"Expunged %lu messages",n);
+      MM_LOG (LOCAL->buf,(long) NIL);
+    }
+    else MM_LOG ("No messages deleted, so no update needed",(long) NIL);
+    MM_NOCRITICAL (stream);	/* release critical */
+    mx_unlockindex (stream);	/* finished with index */
+				/* notify upper level of new mailbox size */
+    mail_exists (stream,stream->nmsgs);
+    mail_recent (stream,recent);
+  }
+  return ret;
+}
+
+/* MX mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if copy successful, else NIL
+ */
+
+long mx_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  FDDATA d;
+  STRING st;
+  MESSAGECACHE *elt;
+  MAILSTREAM *astream;
+  struct stat sbuf;
+  int fd;
+  unsigned long i,j,uid,uidv;
+  char *t,tmp[MAILTMPLEN];
+  long ret;
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+				/* make sure valid mailbox */
+  if (!mx_valid (mailbox)) switch (errno) {
+  case NIL:			/* no error in stat() */
+    if (pc) return (*pc) (stream,sequence,mailbox,options);
+    sprintf (LOCAL->buf,"Not a MX-format mailbox: %.80s",mailbox);
+    MM_LOG (LOCAL->buf,ERROR);
+    return NIL;
+  default:			/* some stat() error */
+    MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
+    return NIL;
+  }
+				/* copy the messages */
+  if (!(ret = ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+	       mail_sequence (stream,sequence))));
+				/* acquire stream to append to */
+  else if (!(astream = mail_open (NIL,mailbox,OP_SILENT))) {
+    MM_LOG ("Can't open copy mailbox",ERROR);
+    ret = NIL;
+  }
+  else {
+    MM_CRITICAL (stream);	/* go critical */
+    if (!(ret = mx_lockindex (astream)))
+      MM_LOG ("Message copy failed: unable to lock index",ERROR);
+    else {
+
+      copyuid_t cu = (copyuid_t) mail_parameters (NIL,GET_COPYUID,NIL);
+      SEARCHSET *source = cu ? mail_newsearchset () : NIL;
+      SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
+      for (i = 1,uid = uidv = 0; ret && (i <= stream->nmsgs); i++) 
+      if ((elt = mail_elt (stream,i))->sequence) {
+	if (ret = ((fd = open (mx_fast_work (stream,elt),O_RDONLY,NIL))
+		   >= 0)) {
+	  fstat (fd,&sbuf);	/* get size of message */
+	  d.fd = fd;		/* set up file descriptor */
+	  d.pos = 0;		/* start of file */
+	  d.chunk = LOCAL->buf;
+	  d.chunksize = CHUNKSIZE;
+	  INIT (&st,fd_string,&d,sbuf.st_size);
+				/* init flag string */
+	  tmp[0] = tmp[1] = '\0';
+	  if (j = elt->user_flags) do
+	    if (t = stream->user_flags[find_rightmost_bit (&j)])
+	      strcat (strcat (tmp," "),t);
+	  while (j);
+	  if (elt->seen) strcat (tmp," \\Seen");
+	  if (elt->deleted) strcat (tmp," \\Deleted");
+	  if (elt->flagged) strcat (tmp," \\Flagged");
+	  if (elt->answered) strcat (tmp," \\Answered");
+	  if (elt->draft) strcat (tmp," \\Draft");
+	  tmp[0] = '(';		/* open list */
+	  strcat (tmp,")");	/* close list */
+	  if (ret = mx_append_msg (astream,tmp,elt,&st,dest)) {
+				/* add to source set if needed */
+	    if (source) mail_append_set (source,mail_uid (stream,i));
+				/* delete if doing a move */
+	    if (options & CP_MOVE) elt->deleted = T;
+	  }
+	}
+      }
+				/* return sets if doing COPYUID */
+      if (cu && ret) (*cu) (stream,mailbox,astream->uid_validity,source,dest);
+      else {			/* flush any sets we may have built */
+	mail_free_searchset (&source);
+	mail_free_searchset (&dest);
+      }
+      mx_unlockindex (astream);	/* unlock index */
+    }
+    MM_NOCRITICAL (stream);
+    mail_close (astream);	/* finished with append stream */
+  }
+  return ret;			/* return success */
+}
+
+/* MX mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long mx_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  MESSAGECACHE elt;
+  MAILSTREAM *astream;
+  char *flags,*date,tmp[MAILTMPLEN];
+  STRING *message;
+  long ret = LONGT;
+				/* default stream to prototype */
+  if (!stream) stream = user_flags (&mxproto);
+				/* N.B.: can't use LOCAL->buf for tmp */
+				/* make sure valid mailbox */
+  if (!mx_isvalid (mailbox,tmp)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    if (!compare_cstring (mailbox,"INBOX")) mx_create (NIL,"INBOX");
+    else {
+      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+      return NIL;
+    }
+				/* falls through */
+  case 0:			/* merely empty file? */
+    break;
+  case EINVAL:
+    sprintf (tmp,"Invalid MX-format mailbox name: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  default:
+    sprintf (tmp,"Not a MX-format mailbox: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+
+				/* get first message */
+  if (!MM_APPEND (af) (stream,data,&flags,&date,&message)) return NIL;
+  if (!(astream = mail_open (NIL,mailbox,OP_SILENT))) {
+    MM_LOG ("Can't open append mailbox",ERROR);
+    return NIL;
+  }
+  MM_CRITICAL (astream);	/* go critical */
+				/* lock the index */
+  if (!(ret = mx_lockindex (astream)))
+    MM_LOG ("Message append failed: unable to lock index",ERROR);
+  else {
+    appenduid_t au = (appenduid_t) mail_parameters (NIL,GET_APPENDUID,NIL);
+    SEARCHSET *dst = au ? mail_newsearchset () : NIL;
+    do {
+				/* guard against zero-length */
+      if (!(ret = SIZE (message)))
+	MM_LOG ("Append of zero-length message",ERROR);
+      else if (date && !(ret = mail_parse_date (&elt,date))) {
+	sprintf (tmp,"Bad date in append: %.80s",date);
+	MM_LOG (tmp,ERROR);
+      }
+      else ret = mx_append_msg (astream,flags,date ? &elt : NIL,message,dst)&&
+	     MM_APPEND (af) (stream,data,&flags,&date,&message);
+    } while (ret && message);
+				/* return sets if doing APPENDUID */
+    if (au && ret) (*au) (mailbox,astream->uid_validity,dst);
+    else mail_free_searchset (&dst);
+    mx_unlockindex (astream);	/* unlock index */
+  }
+  MM_NOCRITICAL (astream);	/* release critical */
+  mail_close (astream);
+  return ret;
+}
+
+/* MX mail append single message
+ * Accepts: MAIL stream
+ *	    flags for new message if non-NIL
+ *	    elt with source date if non-NIL
+ *	    stringstruct of message text
+ *	    searchset to place UID
+ * Returns: T if success, NIL if failure
+ */
+
+long mx_append_msg (MAILSTREAM *stream,char *flags,MESSAGECACHE *elt,
+		    STRING *st,SEARCHSET *set)
+{
+  char tmp[MAILTMPLEN];
+  int fd;
+  unsigned long uf;
+  long f = mail_parse_flags (stream,flags,&uf);
+				/* make message file name */
+  sprintf (tmp,"%s/%lu",stream->mailbox,++stream->uid_last);
+  if ((fd = open (tmp,O_WRONLY|O_CREAT|O_EXCL,
+		  (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0) {
+    sprintf (tmp,"Can't create append message: %s",strerror (errno));
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+  while (SIZE (st)) {		/* copy the file */
+    if (st->cursize && (write (fd,st->curpos,st->cursize) < 0)) {
+      unlink (tmp);		/* delete file */
+      close (fd);		/* close the file */
+      sprintf (tmp,"Message append failed: %s",strerror (errno));
+      MM_LOG (tmp,ERROR);
+      return NIL;
+    }
+    SETPOS (st,GETPOS (st) + st->cursize);
+  }
+  close (fd);			/* close the file */
+  if (elt) mx_setdate (tmp,elt);/* set file date */
+				/* swell the cache */
+  mail_exists (stream,++stream->nmsgs);
+				/* copy flags */
+  mail_append_set (set,(elt = mail_elt (stream,stream->nmsgs))->private.uid =
+		   stream->uid_last);
+  if (f&fSEEN) elt->seen = T;
+  if (f&fDELETED) elt->deleted = T;
+  if (f&fFLAGGED) elt->flagged = T;
+  if (f&fANSWERED) elt->answered = T;
+  if (f&fDRAFT) elt->draft = T;
+  elt->user_flags |= uf;
+  return LONGT;
+}
+
+/* Internal routines */
+
+
+/* MX file name selection test
+ * Accepts: candidate directory entry
+ * Returns: T to use file name, NIL to skip it
+ */
+
+int mx_select (struct direct *name)
+{
+  char c;
+  char *s = name->d_name;
+  while (c = *s++) if (!isdigit (c)) return NIL;
+  return T;
+}
+
+
+/* MX file name comparision
+ * Accepts: first candidate directory entry
+ *	    second candidate directory entry
+ * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2
+ */
+
+int mx_numsort (const void *d1,const void *d2)
+{
+  return atoi ((*(struct direct **) d1)->d_name) -
+    atoi ((*(struct direct **) d2)->d_name);
+}
+
+
+/* MX mail build file name
+ * Accepts: destination string
+ *          source
+ * Returns: destination
+ */
+
+char *mx_file (char *dst,char *name)
+{
+  char *s;
+				/* empty string if mailboxfile fails */
+  if (!mailboxfile (dst,name)) *dst = '\0';
+				/* driver-selected INBOX  */
+  else if (!*dst) mailboxfile (dst,"~/INBOX");
+				/* tie off unnecessary trailing / */
+  else if ((s = strrchr (dst,'/')) && !s[1]) *s = '\0';
+  return dst;
+}
+
+/* MX read and lock index
+ * Accepts: MAIL stream
+ * Returns: T if success, NIL if failure
+ */
+
+long mx_lockindex (MAILSTREAM *stream)
+{
+  unsigned long uf,sf,uid;
+  int k = 0;
+  unsigned long msgno = 1;
+  struct stat sbuf;
+  char *s,*t,*idx,tmp[2*MAILTMPLEN];
+  MESSAGECACHE *elt;
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  if ((LOCAL->fd < 0) &&	/* get index file, no-op if already have it */
+      (LOCAL->fd = open (strcat (strcpy (tmp,stream->mailbox),MXINDEXNAME),
+			 O_RDWR|O_CREAT,
+			 (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL)))
+      >= 0) {
+    (*bn) (BLOCK_FILELOCK,NIL);
+    flock (LOCAL->fd,LOCK_EX);	/* get exclusive lock */
+    (*bn) (BLOCK_NONE,NIL);
+    fstat (LOCAL->fd,&sbuf);	/* get size of index */
+				/* slurp index */
+    read (LOCAL->fd,s = idx = (char *) fs_get (sbuf.st_size + 1),sbuf.st_size);
+    idx[sbuf.st_size] = '\0';	/* tie off index */
+				/* parse index */
+    if (sbuf.st_size) while (s && *s) switch (*s) {
+    case 'V':			/* UID validity record */
+      stream->uid_validity = strtoul (s+1,&s,16);
+      break;
+    case 'L':			/* UID last record */
+      stream->uid_last = strtoul (s+1,&s,16);
+      break;
+    case 'K':			/* keyword */
+				/* find end of keyword */
+      if (s = strchr (t = ++s,'\n')) {
+	*s++ = '\0';		/* tie off keyword */
+				/* copy keyword */
+	if ((k < NUSERFLAGS) && !stream->user_flags[k] &&
+	    (strlen (t) <= MAXUSERFLAG)) stream->user_flags[k] = cpystr (t);
+	k++;			/* one more keyword */
+      }
+      break;
+
+    case 'M':			/* message status record */
+      uid = strtoul (s+1,&s,16);/* get UID for this message */
+      if (*s == ';') {		/* get user flags */
+	uf = strtoul (s+1,&s,16);
+	if (*s == '.') {	/* get system flags */
+	  sf = strtoul (s+1,&s,16);
+	  while ((msgno <= stream->nmsgs) && (mail_uid (stream,msgno) < uid))
+	    msgno++;		/* find message number for this UID */
+	  if ((msgno <= stream->nmsgs) && (mail_uid (stream,msgno) == uid)) {
+	    (elt = mail_elt (stream,msgno))->valid = T;
+	    elt->user_flags=uf; /* set user and system flags in elt */
+	    if (sf & fSEEN) elt->seen = T;
+	    if (sf & fDELETED) elt->deleted = T;
+	    if (sf & fFLAGGED) elt->flagged = T;
+	    if (sf & fANSWERED) elt->answered = T;
+	    if (sf & fDRAFT) elt->draft = T;
+	  }
+	  break;
+	}
+      }
+    default:			/* bad news */
+      sprintf (tmp,"Error in index: %.80s",s);
+      MM_LOG (tmp,ERROR);
+      *s = NIL;			/* ignore remainder of index */
+    }
+    else {			/* new index */
+      stream->uid_validity = time (0);
+      user_flags (stream);	/* init stream with default user flags */
+    }
+    fs_give ((void **) &idx);	/* flush index */
+  }
+  return (LOCAL->fd >= 0) ? T : NIL;
+}
+
+/* MX write and unlock index
+ * Accepts: MAIL stream
+ */
+
+#define MXIXBUFLEN 2048
+
+void mx_unlockindex (MAILSTREAM *stream)
+{
+  unsigned long i,j;
+  off_t size = 0;
+  char *s,tmp[MXIXBUFLEN + 64];
+  MESSAGECACHE *elt;
+  if (LOCAL->fd >= 0) {
+    lseek (LOCAL->fd,0,L_SET);	/* rewind file */
+				/* write header */
+    sprintf (s = tmp,"V%08lxL%08lx",stream->uid_validity,stream->uid_last);
+    for (i = 0; (i < NUSERFLAGS) && stream->user_flags[i]; ++i)
+      sprintf (s += strlen (s),"K%s\n",stream->user_flags[i]);
+				/* write messages */
+    for (i = 1; i <= stream->nmsgs; i++) {
+				/* filled buffer? */
+      if (((s += strlen (s)) - tmp) > MXIXBUFLEN) {
+	write (LOCAL->fd,tmp,j = s - tmp);
+	size += j;
+	*(s = tmp) = '\0';	/* dump out and restart buffer */
+      }
+      elt = mail_elt (stream,i);
+      sprintf(s,"M%08lx;%08lx.%04x",elt->private.uid,elt->user_flags,(unsigned)
+	      ((fSEEN * elt->seen) + (fDELETED * elt->deleted) +
+	       (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
+	       (fDRAFT * elt->draft)));
+    }
+				/* write tail end of buffer */
+    if ((s += strlen (s)) != tmp) {
+      write (LOCAL->fd,tmp,j = s - tmp);
+      size += j;
+    }
+    ftruncate (LOCAL->fd,size);
+    flock (LOCAL->fd,LOCK_UN);	/* unlock the index */
+    close (LOCAL->fd);		/* finished with file */
+    LOCAL->fd = -1;		/* no index now */
+  }
+}
+
+/* Set date for message
+ * Accepts: file name
+ *	    elt containing date
+ */
+
+void mx_setdate (char *file,MESSAGECACHE *elt)
+{
+  time_t tp[2];
+  tp[0] = time (0);		/* atime is now */
+  tp[1] = mail_longdate (elt);	/* modification time */
+  utime (file,tp);		/* set the times */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/news.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,738 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	News routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	4 September 1991
+ * Last Edited:	30 January 2007
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "mail.h"
+#include "osdep.h"
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "misc.h"
+#include "newsrc.h"
+#include "fdstring.h"
+
+
+/* news_load_message() flags */
+
+#define NLM_HEADER 0x1		/* load message text */
+#define NLM_TEXT 0x2		/* load message text */
+
+/* NEWS I/O stream local data */
+	
+typedef struct news_local {
+  unsigned int dirty : 1;	/* disk copy of .newsrc needs updating */
+  char *dir;			/* spool directory name */
+  char *name;			/* local mailbox name */
+  unsigned char buf[CHUNKSIZE];	/* scratch buffer */
+  unsigned long cachedtexts;	/* total size of all cached texts */
+} NEWSLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((NEWSLOCAL *) stream->local)
+
+
+/* Function prototypes */
+
+DRIVER *news_valid (char *name);
+DRIVER *news_isvalid (char *name,char *mbx);
+void *news_parameters (long function,void *value);
+void news_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void news_list (MAILSTREAM *stream,char *ref,char *pat);
+void news_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long news_canonicalize (char *ref,char *pat,char *pattern);
+long news_subscribe (MAILSTREAM *stream,char *mailbox);
+long news_unsubscribe (MAILSTREAM *stream,char *mailbox);
+long news_create (MAILSTREAM *stream,char *mailbox);
+long news_delete (MAILSTREAM *stream,char *mailbox);
+long news_rename (MAILSTREAM *stream,char *old,char *newname);
+MAILSTREAM *news_open (MAILSTREAM *stream);
+int news_select (struct direct *name);
+int news_numsort (const void *d1,const void *d2);
+void news_close (MAILSTREAM *stream,long options);
+void news_fast (MAILSTREAM *stream,char *sequence,long flags);
+void news_flags (MAILSTREAM *stream,char *sequence,long flags);
+void news_load_message (MAILSTREAM *stream,unsigned long msgno,long flags);
+char *news_header (MAILSTREAM *stream,unsigned long msgno,
+		   unsigned long *length,long flags);
+long news_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+void news_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
+long news_ping (MAILSTREAM *stream);
+void news_check (MAILSTREAM *stream);
+long news_expunge (MAILSTREAM *stream,char *sequence,long options);
+long news_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long news_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+/* News routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER newsdriver = {
+  "news",			/* driver name */
+				/* driver flags */
+  DR_NEWS|DR_READONLY|DR_NOFAST|DR_NAMESPACE|DR_NONEWMAIL|DR_DIRFMT,
+  (DRIVER *) NIL,		/* next driver */
+  news_valid,			/* mailbox is valid for us */
+  news_parameters,		/* manipulate parameters */
+  news_scan,			/* scan mailboxes */
+  news_list,			/* find mailboxes */
+  news_lsub,			/* find subscribed mailboxes */
+  news_subscribe,		/* subscribe to mailbox */
+  news_unsubscribe,		/* unsubscribe from mailbox */
+  news_create,			/* create mailbox */
+  news_delete,			/* delete mailbox */
+  news_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  news_open,			/* open mailbox */
+  news_close,			/* close mailbox */
+  news_fast,			/* fetch message "fast" attributes */
+  news_flags,			/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  news_header,			/* fetch message header */
+  news_text,			/* fetch message body */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  NIL,				/* modify flags */
+  news_flagmsg,			/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  news_ping,			/* ping mailbox to see if still alive */
+  news_check,			/* check for new messages */
+  news_expunge,			/* expunge deleted messages */
+  news_copy,			/* copy messages to another mailbox */
+  news_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM newsproto = {&newsdriver};
+
+/* News validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *news_valid (char *name)
+{
+  int fd;
+  char *s,*t,*u;
+  struct stat sbuf;
+  if ((name[0] == '#') && (name[1] == 'n') && (name[2] == 'e') &&
+      (name[3] == 'w') && (name[4] == 's') && (name[5] == '.') &&
+      !strchr (name,'/') &&
+      !stat ((char *) mail_parameters (NIL,GET_NEWSSPOOL,NIL),&sbuf) &&
+      ((fd = open ((char *) mail_parameters (NIL,GET_NEWSACTIVE,NIL),O_RDONLY,
+		   NIL)) >= 0)) {
+    fstat (fd,&sbuf);		/* get size of active file */
+				/* slurp in active file */
+    read (fd,t = s = (char *) fs_get (sbuf.st_size+1),sbuf.st_size);
+    s[sbuf.st_size] = '\0';	/* tie off file */
+    close (fd);			/* flush file */
+    while (*t && (u = strchr (t,' '))) {
+      *u++ = '\0';		/* tie off at end of name */
+      if (!strcmp (name+6,t)) {
+	fs_give ((void **) &s);	/* flush data */
+	return &newsdriver;
+      }
+      t = 1 + strchr (u,'\n');	/* next line */
+    }
+    fs_give ((void **) &s);	/* flush data */
+  }
+  return NIL;			/* return status */
+}
+
+/* News manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *news_parameters (long function,void *value)
+{
+  return (function == GET_NEWSRC) ? env_parameters (function,value) : NIL;
+}
+
+
+/* News scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void news_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  char tmp[MAILTMPLEN];
+  if (news_canonicalize (ref,pat,tmp))
+    mm_log ("Scan not valid for news mailboxes",ERROR);
+}
+
+/* News find list of newsgroups
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void news_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  int fd;
+  int i;
+  char *s,*t,*u,*r,pattern[MAILTMPLEN],name[MAILTMPLEN];
+  struct stat sbuf;
+  if (!pat || !*pat) {		/* empty pattern? */
+    if (news_canonicalize (ref,"*",pattern)) {
+				/* tie off name at root */
+      if (s = strchr (pattern,'.')) *++s = '\0';
+      else pattern[0] = '\0';
+      mm_list (stream,'.',pattern,LATT_NOSELECT);
+    }
+  }
+  else if (news_canonicalize (ref,pat,pattern) &&
+	   !stat ((char *) mail_parameters (NIL,GET_NEWSSPOOL,NIL),&sbuf) &&
+	   ((fd = open ((char *) mail_parameters (NIL,GET_NEWSACTIVE,NIL),
+			O_RDONLY,NIL)) >= 0)) {
+    fstat (fd,&sbuf);		/* get file size and read data */
+    read (fd,s = (char *) fs_get (sbuf.st_size + 1),sbuf.st_size);
+    close (fd);			/* close file */
+    s[sbuf.st_size] = '\0';	/* tie off string */
+    strcpy (name,"#news.");	/* write initial prefix */
+    i = strlen (pattern);	/* length of pattern */
+    if (pattern[--i] != '%') i = 0;
+    if (t = strtok_r (s,"\n",&r)) do if (u = strchr (t,' ')) {
+      *u = '\0';		/* tie off at end of name */
+      strcpy (name + 6,t);	/* make full form of name */
+      if (pmatch_full (name,pattern,'.')) mm_list (stream,'.',name,NIL);
+      else if (i && (u = strchr (name + i,'.'))) {
+	*u = '\0';		/* tie off at delimiter, see if matches */
+	if (pmatch_full (name,pattern,'.'))
+	  mm_list (stream,'.',name,LATT_NOSELECT);
+      }
+    } while (t = strtok_r (NIL,"\n",&r));
+    fs_give ((void **) &s);
+  }
+}
+
+/* News find list of subscribed newsgroups
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void news_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  char pattern[MAILTMPLEN];
+				/* return data from newsrc */
+  if (news_canonicalize (ref,pat,pattern)) newsrc_lsub (stream,pattern);
+}
+
+
+/* News canonicalize newsgroup name
+ * Accepts: reference
+ *	    pattern
+ *	    returned single pattern
+ * Returns: T on success, NIL on failure
+ */
+
+long news_canonicalize (char *ref,char *pat,char *pattern)
+{
+  unsigned long i;
+  char *s;
+  if (ref && *ref) {		/* have a reference */
+    strcpy (pattern,ref);	/* copy reference to pattern */
+				/* # overrides mailbox field in reference */
+    if (*pat == '#') strcpy (pattern,pat);
+				/* pattern starts, reference ends, with . */
+    else if ((*pat == '.') && (pattern[strlen (pattern) - 1] == '.'))
+      strcat (pattern,pat + 1);	/* append, omitting one of the period */
+    else strcat (pattern,pat);	/* anything else is just appended */
+  }
+  else strcpy (pattern,pat);	/* just have basic name */
+  if ((pattern[0] == '#') && (pattern[1] == 'n') && (pattern[2] == 'e') &&
+      (pattern[3] == 'w') && (pattern[4] == 's') && (pattern[5] == '.') &&
+      !strchr (pattern,'/')) {	/* count wildcards */
+    for (i = 0, s = pattern; *s; *s++) if ((*s == '*') || (*s == '%')) ++i;
+				/* success if not too many */
+    if (i <= MAXWILDCARDS) return LONGT;
+    MM_LOG ("Excessive wildcards in LIST/LSUB",ERROR);
+  }
+  return NIL;
+}
+
+/* News subscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to add to subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long news_subscribe (MAILSTREAM *stream,char *mailbox)
+{
+  return news_valid (mailbox) ? newsrc_update (stream,mailbox+6,':') : NIL;
+}
+
+
+/* NEWS unsubscribe to mailbox
+ * Accepts: mail stream
+ *	    mailbox to delete from subscription list
+ * Returns: T on success, NIL on failure
+ */
+
+long news_unsubscribe (MAILSTREAM *stream,char *mailbox)
+{
+  return news_valid (mailbox) ? newsrc_update (stream,mailbox+6,'!') : NIL;
+}
+
+/* News create mailbox
+ * Accepts: mail stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long news_create (MAILSTREAM *stream,char *mailbox)
+{
+  return NIL;			/* never valid for News */
+}
+
+
+/* News delete mailbox
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long news_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return NIL;			/* never valid for News */
+}
+
+
+/* News rename mailbox
+ * Accepts: mail stream
+ *	    old mailbox name
+ *	    new mailbox name
+ * Returns: T on success, NIL on failure
+ */
+
+long news_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  return NIL;			/* never valid for News */
+}
+
+/* News open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *news_open (MAILSTREAM *stream)
+{
+  long i,nmsgs;
+  char *s,tmp[MAILTMPLEN];
+  struct direct **names = NIL;
+  				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return &newsproto;
+  if (stream->local) fatal ("news recycle stream");
+				/* build directory name */
+  sprintf (s = tmp,"%s/%s",(char *) mail_parameters (NIL,GET_NEWSSPOOL,NIL),
+	   stream->mailbox + 6);
+  while (s = strchr (s,'.')) *s = '/';
+				/* scan directory */
+  if ((nmsgs = scandir (tmp,&names,news_select,news_numsort)) >= 0) {
+    mail_exists (stream,nmsgs);	/* notify upper level that messages exist */
+    stream->local = fs_get (sizeof (NEWSLOCAL));
+    LOCAL->dirty = NIL;		/* no update to .newsrc needed yet */
+    LOCAL->dir = cpystr (tmp);	/* copy directory name for later */
+    LOCAL->name = cpystr (stream->mailbox + 6);
+    for (i = 0; i < nmsgs; ++i) {
+      stream->uid_last = mail_elt (stream,i+1)->private.uid =
+	atoi (names[i]->d_name);
+      fs_give ((void **) &names[i]);
+    }
+    s = (void *) names;		/* stupid language */
+    fs_give ((void **) &s);	/* free directory */
+    LOCAL->cachedtexts = 0;	/* no cached texts */
+    stream->sequence++;		/* bump sequence number */
+    stream->rdonly = stream->perm_deleted = T;
+				/* UIDs are always valid */
+    stream->uid_validity = 0xbeefface;
+				/* read .newsrc entries */
+    mail_recent (stream,newsrc_read (LOCAL->name,stream));
+				/* notify if empty newsgroup */
+    if (!(stream->nmsgs || stream->silent)) {
+      sprintf (tmp,"Newsgroup %s is empty",LOCAL->name);
+      mm_log (tmp,WARN);
+    }
+  }
+  else mm_log ("Unable to scan newsgroup spool directory",ERROR);
+  return LOCAL ? stream : NIL;	/* if stream is alive, return to caller */
+}
+
+/* News file name selection test
+ * Accepts: candidate directory entry
+ * Returns: T to use file name, NIL to skip it
+ */
+
+int news_select (struct direct *name)
+{
+  char c;
+  char *s = name->d_name;
+  while (c = *s++) if (!isdigit (c)) return NIL;
+  return T;
+}
+
+
+/* News file name comparision
+ * Accepts: first candidate directory entry
+ *	    second candidate directory entry
+ * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2
+ */
+
+int news_numsort (const void *d1,const void *d2)
+{
+  return atoi ((*(struct direct **) d1)->d_name) -
+    atoi ((*(struct direct **) d2)->d_name);
+}
+
+
+/* News close
+ * Accepts: MAIL stream
+ *	    option flags
+ */
+
+void news_close (MAILSTREAM *stream,long options)
+{
+  if (LOCAL) {			/* only if a file is open */
+    news_check (stream);	/* dump final checkpoint */
+    if (LOCAL->dir) fs_give ((void **) &LOCAL->dir);
+    if (LOCAL->name) fs_give ((void **) &LOCAL->name);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+/* News fetch fast information
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ */
+
+void news_fast (MAILSTREAM *stream,char *sequence,long flags)
+{
+  MESSAGECACHE *elt;
+  unsigned long i;
+				/* set up metadata for all messages */
+  if (stream && LOCAL && ((flags & FT_UID) ?
+			  mail_uid_sequence (stream,sequence) :
+			  mail_sequence (stream,sequence)))
+    for (i = 1; i <= stream->nmsgs; i++)
+      if ((elt = mail_elt (stream,i))->sequence &&
+	  !(elt->day && elt->rfc822_size)) news_load_message (stream,i,NIL);
+}
+
+
+/* News fetch flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ */
+
+void news_flags (MAILSTREAM *stream,char *sequence,long flags)
+{
+  unsigned long i;
+  if ((flags & FT_UID) ?	/* validate all elts */
+      mail_uid_sequence (stream,sequence) : mail_sequence (stream,sequence))
+    for (i = 1; i <= stream->nmsgs; i++) mail_elt (stream,i)->valid = T;
+}
+
+/* News load message into cache
+ * Accepts: MAIL stream
+ *	    message #
+ *	    option flags
+ */
+
+void news_load_message (MAILSTREAM *stream,unsigned long msgno,long flags)
+{
+  unsigned long i,j,nlseen;
+  int fd;
+  unsigned char c,*t;
+  struct stat sbuf;
+  MESSAGECACHE *elt;
+  FDDATA d;
+  STRING bs;
+  elt = mail_elt (stream,msgno);/* get elt */
+				/* build message file name */
+  sprintf (LOCAL->buf,"%s/%lu",LOCAL->dir,elt->private.uid);
+				/* anything we need not currently cached? */
+  if ((!elt->day || !elt->rfc822_size ||
+       ((flags & NLM_HEADER) && !elt->private.msg.header.text.data) ||
+       ((flags & NLM_TEXT) && !elt->private.msg.text.text.data)) &&
+      ((fd = open (LOCAL->buf,O_RDONLY,NIL)) >= 0)) {
+    fstat (fd,&sbuf);		/* get file metadata */
+    d.fd = fd;			/* set up file descriptor */
+    d.pos = 0;			/* start of file */
+    d.chunk = LOCAL->buf;
+    d.chunksize = CHUNKSIZE;
+    INIT (&bs,fd_string,&d,sbuf.st_size);
+    if (!elt->day) {		/* set internaldate to file date */
+      struct tm *tm = gmtime (&sbuf.st_mtime);
+      elt->day = tm->tm_mday; elt->month = tm->tm_mon + 1;
+      elt->year = tm->tm_year + 1900 - BASEYEAR;
+      elt->hours = tm->tm_hour; elt->minutes = tm->tm_min;
+      elt->seconds = tm->tm_sec;
+      elt->zhours = 0; elt->zminutes = 0;
+    }
+
+    if (!elt->rfc822_size) {	/* know message size yet? */
+      for (i = 0, j = SIZE (&bs), nlseen = 0; j--; ) switch (SNX (&bs)) {
+      case '\015':		/* unlikely carriage return */
+	if (!j || (CHR (&bs) != '\012')) {
+	  i++;			/* ugh, raw CR */
+	  nlseen = NIL;
+	  break;
+	}
+	SNX (&bs);		/* eat the line feed, drop in */
+      case '\012':		/* line feed? */
+	i += 2;			/* count a CRLF */
+				/* header size known yet? */
+	if (!elt->private.msg.header.text.size && nlseen) {
+				/* note position in file */
+	  elt->private.special.text.size = GETPOS (&bs);
+				/* and CRLF-adjusted size */
+	  elt->private.msg.header.text.size = i;
+	}
+	nlseen = T;		/* note newline seen */
+	break;
+      default:			/* ordinary chararacter */
+	i++;
+	nlseen = NIL;
+	break;
+      }
+      SETPOS (&bs,0);		/* restore old position */
+      elt->rfc822_size = i;	/* note that we have size now */
+				/* header is entire message if no delimiter */
+      if (!elt->private.msg.header.text.size)
+	elt->private.msg.header.text.size = elt->rfc822_size;
+				/* text is remainder of message */
+      elt->private.msg.text.text.size =
+	elt->rfc822_size - elt->private.msg.header.text.size;
+    }
+
+				/* need to load cache with message data? */
+    if (((flags & NLM_HEADER) && !elt->private.msg.header.text.data) ||
+	((flags & NLM_TEXT) && !elt->private.msg.text.text.data)) {
+				/* purge cache if too big */
+      if (LOCAL->cachedtexts > max (stream->nmsgs * 4096,2097152)) {
+				/* just can't keep that much */
+	mail_gc (stream,GC_TEXTS);
+	LOCAL->cachedtexts = 0;
+      }
+      if ((flags & NLM_HEADER) && !elt->private.msg.header.text.data) {
+	t = elt->private.msg.header.text.data =
+	  (unsigned char *) fs_get (elt->private.msg.header.text.size + 1);
+	LOCAL->cachedtexts += elt->private.msg.header.text.size;
+				/* read in message header */
+	for (i = 0; i <= elt->private.msg.header.text.size; i++)
+	  switch (c = SNX (&bs)) {
+	  case '\015':		/* unlikely carriage return */
+	    *t++ = c;
+	    if ((CHR (&bs) == '\012')) *t++ = SNX (&bs);
+	    break;
+	  case '\012':		/* line feed? */
+	    *t++ = '\015';
+	  default:
+	    *t++ = c;
+	    break;
+	  }
+	*t = '\0';		/* tie off string */
+      }
+      if ((flags & NLM_TEXT) && !elt->private.msg.text.text.data) {
+	t = elt->private.msg.text.text.data =
+	  (unsigned char *) fs_get (elt->private.msg.text.text.size + 1);
+	SETPOS (&bs,elt->private.msg.header.text.size);
+	LOCAL->cachedtexts += elt->private.msg.text.text.size;
+				/* read in message text */
+	for (i = 0; i <= elt->private.msg.text.text.size; i++)
+	  switch (c = SNX (&bs)) {
+	  case '\015':		/* unlikely carriage return */
+	    *t++ = c;
+	    if ((CHR (&bs) == '\012')) *t++ = SNX (&bs);
+	    break;
+	  case '\012':		/* line feed? */
+	    *t++ = '\015';
+	  default:
+	    *t++ = c;
+	    break;
+	  }
+	*t = '\0';		/* tie off string */
+      }
+    }
+    close (fd);			/* flush message file */
+  }
+}
+
+/* News fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+char *news_header (MAILSTREAM *stream,unsigned long msgno,
+		   unsigned long *length,long flags)
+{
+  MESSAGECACHE *elt;
+  *length = 0;			/* default to empty */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+  elt = mail_elt (stream,msgno);/* get elt */
+  if (!elt->private.msg.header.text.data)
+    news_load_message (stream,msgno,NLM_HEADER);
+  *length = elt->private.msg.header.text.size;
+  return (char *) elt->private.msg.header.text.data;
+}
+
+
+/* News fetch message text (body only)
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned stringstruct
+ *	    option flags
+ * Returns: T on success, NIL on failure
+ */
+
+long news_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  MESSAGECACHE *elt;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+  elt = mail_elt (stream,msgno);/* get elt */
+				/* snarf message if don't have it yet */
+  if (!elt->private.msg.text.text.data) {
+    news_load_message (stream,msgno,NLM_TEXT);
+    if (!elt->private.msg.text.text.data) return NIL;
+  }
+  if (!(flags & FT_PEEK)) {	/* mark as seen */
+    mail_elt (stream,msgno)->seen = T;
+    mm_flags (stream,msgno);
+  }
+  INIT (bs,mail_string,elt->private.msg.text.text.data,
+	elt->private.msg.text.text.size);
+  return T;
+}
+
+/* News per-message modify flag
+ * Accepts: MAIL stream
+ *	    message cache element
+ */
+
+void news_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  if (!LOCAL->dirty) {		/* only bother checking if not dirty yet */
+    if (elt->valid) {		/* if done, see if deleted changed */
+      if (elt->sequence != elt->deleted) LOCAL->dirty = T;
+      elt->sequence = T;	/* leave the sequence set */
+    }
+				/* note current setting of deleted flag */
+    else elt->sequence = elt->deleted;
+  }
+}
+
+
+/* News ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ */
+
+long news_ping (MAILSTREAM *stream)
+{
+  return T;			/* always alive */
+}
+
+
+/* News check mailbox
+ * Accepts: MAIL stream
+ */
+
+void news_check (MAILSTREAM *stream)
+{
+				/* never do if no updates */
+  if (LOCAL->dirty) newsrc_write (LOCAL->name,stream);
+  LOCAL->dirty = NIL;
+}
+
+
+/* News expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T if success, NIL if failure
+ */
+
+long news_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  if (!stream->silent) mm_log ("Expunge ignored on readonly mailbox",NIL);
+  return LONGT;
+}
+
+/* News copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    option flags
+ * Returns: T if copy successful, else NIL
+ */
+
+long news_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+  if (pc) return (*pc) (stream,sequence,mailbox,options);
+  mm_log ("Copy not valid for News",ERROR);
+  return NIL;
+}
+
+
+/* News append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback function
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long news_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  mm_log ("Append not valid for news",ERROR);
+  return NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/nl_unix.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,92 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX/VMS newline routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Copy string with CRLF newlines
+ * Accepts: destination string
+ *	    pointer to size of destination string buffer
+ *	    source string
+ *	    length of source string
+ * Returns: length of copied string
+ */
+
+unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl,
+			  unsigned char *src,unsigned long srcl)
+{
+  long i = srcl * 2,j;
+  unsigned char c,*d = src;
+  if (*dst) {			/* candidate destination provided? */
+				/* count NLs if doesn't fit worst-case */
+    if (i > *dstl) for (i = j = srcl; j; --j) if (*d++ == '\012') i++;
+				/* still too small, must reset destination */
+    if (i > *dstl) fs_give ((void **) dst);
+  }
+				/* make a new buffer if needed */
+  if (!*dst) *dst = (char *) fs_get ((*dstl = i) + 1);
+  d = *dst;			/* destination string */
+  if (srcl) do {		/* main copy loop */
+    if ((c = *src++) < '\016') {
+				/* prepend CR to LF */
+      if (c == '\012') *d++ = '\015';
+				/* unlikely CR */
+      else if ((c == '\015') && (srcl > 1) && (*src == '\012')) {
+	*d++ = c;		/* copy the CR */
+	c = *src++;		/* grab the LF */
+	--srcl;			/* adjust the count */
+      }
+    }
+    *d++ = c;			/* copy character */
+  } while (--srcl);
+  *d = '\0';			/* tie off destination */
+  return d - *dst;		/* return length */
+}
+
+/* Length of string after strcrlfcpy applied
+ * Accepts: source string
+ * Returns: length of string
+ */
+
+unsigned long strcrlflen (STRING *s)
+{
+  unsigned long pos = GETPOS (s);
+  unsigned long i = SIZE (s);
+  unsigned long j = i;
+  while (j--) switch (SNX (s)) {/* search for newlines */
+  case '\015':			/* unlikely carriage return */
+    if (j && (CHR (s) == '\012')) {
+      SNX (s);			/* eat the line feed */
+      j--;
+    }
+    break;
+  case '\012':			/* line feed? */
+    i++;
+  default:			/* ordinary chararacter */
+    break;
+  }
+  SETPOS (s,pos);		/* restore old position */
+  return i;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/opendir.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,79 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Read directories
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	16 December 1993
+ * Last Edited:	30 August 2006
+ */
+
+/* Emulator for BSD opendir() call
+ * Accepts: directory name
+ * Returns: directory structure pointer
+ */
+
+DIR *opendir (char *name)
+{
+  DIR *d = NIL;
+  struct stat sbuf;
+  int fd = open (name,O_RDONLY,NIL);
+  errno = ENOTDIR;		/* default error is bogus directory */
+  if ((fd >= 0) && !(fstat (fd,&sbuf)) && ((sbuf.st_mode&S_IFMT) == S_IFDIR)) {
+    d = (DIR *) fs_get (sizeof (DIR));
+				/* initialize structure */
+    d->dd_loc = 0;
+    read (fd,d->dd_buf = (char *) fs_get (sbuf.st_size),
+	  d->dd_size = sbuf.st_size);
+  }
+  else if (d) fs_give ((void **) &d);
+  if (fd >= 0) close (fd);
+  return d;
+}
+
+
+/* Emulator for BSD closedir() call
+ * Accepts: directory structure pointer
+ */
+
+int closedir (DIR *d)
+{
+				/* free storage */
+  fs_give ((void **) &(d->dd_buf));
+  fs_give ((void **) &d);
+  return NIL;			/* return */
+}
+
+
+/* Emulator for BSD readdir() call
+ * Accepts: directory structure pointer
+ */
+
+struct direct *readdir (DIR *d)
+{
+				/* loop through directory */
+  while (d->dd_loc < d->dd_size) {
+    struct direct *dp = (struct direct *) (d->dd_buf + d->dd_loc);
+    d->dd_loc += sizeof (struct direct);
+    if (dp->d_ino) return dp;	/* if have a good entry return it */
+  }
+  return NIL;			/* all done */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_a32.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,60 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- AIX 3.2 on RS 6000
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+ 
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+#include <sys/select.h>
+
+char *crypt (char *key,char *salt);
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "tz_sv4.c"
+#include "flocksim.c"
+#include "utime.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_a32.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,50 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- AIX on RS6000
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>		/* for struct tm */
+#include <dirent.h>
+#include <fcntl.h>
+#include <utime.h>
+#include <syslog.h>
+#include <sys/file.h>
+#include <ustat.h>
+
+
+#define utime portable_utime
+int portable_utime (char *file,time_t timep[2]);
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+#include "flocksim.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_a41.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,61 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- AIX 4.1 on RS 6000
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+ 
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+#include <sys/select.h>
+#include <stddef.h>		/* needed for authenticate() */
+
+int authenticate (char *UserName,char *Response,int *Reenter,char **Message);
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "tz_sv4.c"
+#include "flocksim.c"
+#include "utime.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_a41.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,50 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- AIX on RS6000
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>		/* for struct tm */
+#include <dirent.h>
+#include <fcntl.h>
+#include <utime.h>
+#include <syslog.h>
+#include <sys/file.h>
+#include <ustat.h>
+
+
+#define utime portable_utime
+int portable_utime (char *file,time_t timep[2]);
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+#include "flocksim.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_aix.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,64 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- AIX version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	16 August 2007
+ */
+ 
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+
+char *crypt (char *key,char *salt);
+
+extern long timezone;
+extern int daylight;
+extern char *tzname[2];
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#define fork vfork
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "memmove.c"
+#include "strerror.c"
+#include "tz_sv4.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_aix.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,47 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- AIX version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <sys/file.h>
+
+
+#define direct dirent
+
+char *strerror (int n);
+void *memmove (void *s,void *ct,size_t n);
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_aos.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,63 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- 4.3BSD version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *
+ * Date:	11 May 1989
+ * Last Edited:	16 August 2007
+ */
+
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+
+
+#define isodigit(c)    (((unsigned)(c)>=060)&((unsigned)(c)<=067))
+#define toint(c)       ((c)-'0')
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#define fork vfork
+#include "tcp_unix.c"
+#include "gr_wait.c"
+#include "memmove.c"
+#include "strerror.c"
+#include "strstr.c"
+#include "strtoul.c"
+#include "tz_bsd.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_aos.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,50 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- AOS version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	30 August 2006
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <sys/file.h>
+
+
+char *getenv (char *name);
+char *strstr (char *cs,char *ct);
+char *strerror (int n);
+void *memmove (void *s,void *ct,size_t n);
+unsigned long strtoul (char *s,char **endp,int base);
+void *malloc (size_t byteSize);
+void free (void *ptr);
+void *realloc (void *oldptr,size_t newsize);
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_art.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,86 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- AIX/RT version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 April 1992
+ * Last Edited:	30 August 2006
+ */
+
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <errno.h>
+extern int errno;
+#include <pwd.h>
+#include <sys/socket.h>
+#include <time.h>
+#define KERNEL
+#include <sys/time.h>
+#undef KERNEL
+#include "misc.h"
+
+#define DIR_SIZE(d) sizeof (DIR)
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+#define toint(c)	((c)-'0')
+#define isodigit(c)	(((unsigned)(c)>=060)&((unsigned)(c)<=067))
+
+#define	NBBY	8	/* number of bits in a byte */
+#define	FD_SETSIZE	256
+
+typedef long	fd_mask;
+#define NFDBITS	(sizeof(fd_mask) * NBBY)
+					/* bits per mask */
+#define	howmany(x, y)	(((x)+((y)-1))/(y))
+
+typedef	struct fd_set {
+  fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)];
+} fd_set;
+
+#define	FD_SET(n, p)	((p)->fds_bits[(n)/NFDBITS] |= \
+					(1 << ((n) % NFDBITS)))
+#define	FD_CLR(n, p)	((p)->fds_bits[(n)/NFDBITS] &= \
+					~(1 << ((n) % NFDBITS)))
+#define	FD_ISSET(n, p)	((p)->fds_bits[(n)/NFDBITS] & \
+					(1 << ((n) % NFDBITS)))
+#define FD_ZERO(p)	bzero((char *)(p), sizeof(*(p)))
+
+
+#include "fs_unix.c" 
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#include "tcp_unix.c"
+#include "gr_wait.c"
+#include "flocksim.c"
+#include "memmove2.c"
+#include "strerror.c"
+#include "tz_sv4.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_art.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,81 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- AIX/RT version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 April 1992
+ * Last Edited:	15 September 2006
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <memory.h>
+#include <sys/types.h>
+#define direct dirent
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/syslog.h>
+#include <sys/file.h>
+#include <ustat.h>
+
+
+/* Different names between BSD and SVR4 */
+
+#define L_SET SEEK_SET
+#define L_INCR SEEK_CUR
+#define L_XTND SEEK_END
+
+#define random lrand48
+
+#define SIGSTOP SIGQUIT
+
+
+/* For setitimer() emulation */
+
+#define ITIMER_REAL 0
+
+struct passwd *getpwent (void);
+struct passwd *getpwuid (int uid);
+struct passwd *getpwnam (char *name);
+char *getenv (char *name);
+long gethostid (void);
+void *memmove (void *s,void *ct,size_t n);
+char *strstr (char *cs,char *ct);
+char *strerror (int n);
+unsigned long strtoul (char *s,char **endp,int base);
+typedef int (*select_t) (struct direct *name);
+typedef int (*compar_t) (void *d1,void *d2);
+int scandir (char *dirname,struct direct ***namelist,select_t select,
+	     compar_t compar);
+int alphasort (void *d1,void *d2);
+void *malloc (size_t byteSize);
+void free (void *ptr);
+void *realloc (void *oldptr,size_t newsize);
+int openlog (ident,logopt,facility);
+int syslog (priority,message,parameters ...);
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+#include "flocksim.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_asv.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,70 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Altos System V version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 April 1992
+ * Last Edited:	30 August 2006
+ */
+
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/tiuser.h>
+#include <sys/stropts.h>
+#include <sys/poll.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <errno.h>
+#include <pwd.h>
+#include <sys/socket.h>
+#include "misc.h"
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+#define toint(c)	((c)-'0')
+#define isodigit(c)	(((unsigned)(c)>=060)&((unsigned)(c)<=067))
+
+#define DIR_SIZE(d) d->d_reclen
+
+#define pid_t short		/* may not be known on all ASV systems */
+
+#include "strstr.c"
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "strerror.c"
+#include "flocksim.c"
+#include "scandir.c"
+#include "strtoul.c"
+#include "tz_sv4.c"
+#include "gethstid.c"
+#include "memmove.c"
+#include "fsync.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_asv.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,76 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Altos System V version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 April 1992
+ * Last Edited:	15 September 2006
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/time.h>
+#include <syslog.h>
+#include <sys/file.h>
+#include <ustat.h>
+
+
+/* Different names, equivalent things in BSD and SysV */
+
+#define L_SET SEEK_SET
+#define L_INCR SEEK_CUR
+#define L_XTND SEEK_END
+
+#define direct dirent
+
+#define ftruncate chsize
+#define random lrand48
+
+
+struct passwd *getpwent (void);
+struct passwd *getpwuid (int uid);
+struct passwd *getpwnam (char *name);
+char *getenv (char *name);
+long gethostid (void);
+void *memmove (void *s,void *ct,size_t n);
+char *strstr (char *cs,char *ct);
+char *strerror (int n);
+unsigned long strtoul (char *s,char **endp,int base);
+typedef int (*select_t) (struct direct *name);
+typedef int (*compar_t) (void *d1,void *d2);
+int scandir (char *dirname,struct direct ***namelist,select_t select,
+	     compar_t compar);
+int alphasort (void *d1,void *d2);
+void *malloc (size_t byteSize);
+void free (void *ptr);
+void *realloc (void *oldptr,size_t newsize);
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+#include "flocksim.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_aux.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,62 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- A/UX version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *
+ * Date:	11 May 1989
+ * Last Edited:	30 August 2006
+ */
+
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <errno.h>
+#include <pwd.h>
+#include "misc.h"
+
+
+#define isodigit(c)    (((unsigned)(c)>=060)&((unsigned)(c)<=067))
+#define toint(c)       ((c)-'0')
+
+extern char *sys_errlist[];
+extern int sys_nerr;
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#include "tcp_unix.c"
+#include "gr_wait.c"
+#include "flocksim.c"
+#include "strerror.c"
+#include "strtoul.c"
+#include "strpbrk.c"		/* the A/UX version is bogus! */
+#include "memmove.c"
+#include "tz_sv4.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_aux.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,51 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- A/UX version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	30 August 2006
+ */
+
+
+#include <sys/types.h>
+#include <sys/dir.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <time.h>
+#include <sys/file.h>
+#include <fcntl.h>
+#include <syslog.h>
+
+
+extern int errno;
+
+char *strerror (int n);
+unsigned long strtoul (char *s,char **endp,int base);
+void *memmove (void *s,void *ct,size_t n);
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+#include "flocksim.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_bsd.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,63 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- 4.3BSD version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *
+ * Date:	11 May 1989
+ * Last Edited:	16 August 2007
+ */
+
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+
+
+#define isodigit(c)    (((unsigned)(c)>=060)&((unsigned)(c)<=067))
+#define toint(c)       ((c)-'0')
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#define fork vfork
+#include "tcp_unix.c"
+#include "gr_wait.c"
+#include "memmove.c"
+#include "strerror.c"
+#include "strstr.c"
+#include "strtoul.c"
+#include "tz_bsd.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_bsd.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,51 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- 4.3BSD version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	30 August 2006
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <sys/file.h>
+#include <machine/endian.h>	/* needed for htons() prototypes */
+
+
+char *getenv (char *name);
+char *strstr (char *cs,char *ct);
+char *strerror (int n);
+void *memmove (void *s,void *ct,size_t n);
+unsigned long strtoul (char *s,char **endp,int base);
+void *malloc (size_t byteSize);
+void free (void *ptr);
+void *realloc (void *oldptr,size_t newsize);
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_bsf.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,54 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- BSDI BSD/386 version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	16 August 2007
+ */
+ 
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#include "getspnam.c"
+#define fork vfork
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "tz_bsd.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_bsf.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,46 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- FreeBSD version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	5 March 1993
+ * Last Edited:	30 August 2006
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <sys/file.h>
+
+
+#define direct dirent
+
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_bsi.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,54 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- BSDI BSD/386 version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	16 August 2007
+ */
+ 
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#include "getspnam.c"
+#define fork vfork
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "tz_bsd.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_bsi.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,43 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- BSDI BSD/386 version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	5 March 1993
+ * Last Edited:	30 August 2006
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <sys/file.h>
+
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_cvx.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,57 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Convex version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *
+ * Date:	11 May 1989
+ * Last Edited:	16 August 2007
+ */
+
+#define isodigit(c)    (((unsigned)(c)>=060)&((unsigned)(c)<=067))
+#define toint(c)       ((c)-'0')
+
+#include <stdio.h>
+
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#define fork vfork
+#include "tcp_unix.c"
+#include "gr_wait.c"
+#include "tz_nul.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_cvx.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,45 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Convex version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	30 August 2006
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+#include <sys/timeb.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <sys/file.h>
+
+
+void *malloc (size_t byteSize);
+void *realloc (void *oldptr,size_t newsize);
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_cyg.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,71 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Cygwin version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+ 
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include <crypt.h>
+#include "misc.h"
+
+
+#define isodigit(c)    (((unsigned)(c)>=060)&((unsigned)(c)<=067))
+#define toint(c)       ((c)-'0')
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#include "tcp_unix.c"
+#include "gr_wait.c"
+#include "tz_nul.c"
+#include "flockcyg.c"
+#include "gethstid.c"
+
+
+/* Emulator for geteuid() call
+ * Returns: effective UID
+ */
+
+#undef geteuid
+
+uid_t Geteuid (void)
+{
+  uid_t ret = geteuid ();
+  return (ret == SYSTEMUID) ? 0 : ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_cyg.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,71 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Cygwin version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <sys/file.h>
+#include <time.h>
+#include <sys/time.h>
+
+#define direct dirent
+
+
+#define CYGKLUDGEOFFSET 1	/* don't write 1st byte of shared-lock files */
+
+/* Cygwin gets this wrong */
+
+#define setpgrp setpgid
+
+#define SYSTEMUID 18		/* Cygwin returns this for SYSTEM */
+#define geteuid Geteuid
+uid_t Geteuid (void);
+
+/* Now Cygwin has reportedly joined this madness.  Use ifndef in case it shares
+   the SVR4 <sys/file.h> silliness too */
+#ifndef L_SET
+#define L_SET SEEK_SET
+#endif
+#ifndef L_INCR
+#define L_INCR SEEK_CUR
+#endif
+#ifndef L_XTND
+#define L_XTND SEEK_END
+#endif
+
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+#include "flockcyg.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_d-g.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,54 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- D-G version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+ 
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "tz_sv4.c"
+#include "flocksim.c"
+#include "utime.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_d-g.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,56 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- D-G version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/dir.h>
+#include <time.h>		/* for struct tm */
+#include <fcntl.h>
+#define _USEC_UTIME_FLAVOR	/* break it for compatibility with */
+#include <utime.h>		/*  the incompatible past */
+#include <syslog.h>
+#include <sys/file.h>
+
+
+/* D-G gets this wrong */
+
+#define setpgrp setpgrp2
+
+
+#define utime portable_utime
+int portable_utime (char *file,time_t timep[2]);
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+#include "flocksim.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_do4.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,58 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Apollo Domain/OS sr10.4
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *
+ * Date:	11 May 1989
+ * Last Edited:	16 August 2007
+ */
+
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+
+
+#define isodigit(c)    (((unsigned)(c)>=060)&((unsigned)(c)<=067))
+#define toint(c)       ((c)-'0')
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#define fork vfork
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "tz_sv4.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_do4.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,47 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Apollo Domain/OS sr10.4
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	30 August 2006
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <sys/dir.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <sys/file.h>
+#ifndef htons
+#include <netinet/in.h>		/* needed for htons() prototypes */
+#endif
+
+extern int daylight;		/* local timzone uses daylight savings time */
+extern long altzone;		/* seconds west of UTC during daylight time */
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_drs.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,57 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- ICL DRS/NX
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+ 
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+
+char *crypt (char *key,char *salt);
+
+#define DIR_SIZE(d) d->d_reclen
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "tz_sv4.c"
+#include "flocksim.c"
+#include "scandir.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_drs.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,59 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- ICL DRS/NX version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	15 September 2006
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+#include <time.h>		/* for struct tm */
+#include <dirent.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <sys/file.h>
+#include <ustat.h>
+
+
+#define random rand
+#define direct dirent
+
+
+long gethostid (void);
+typedef int (*select_t) (struct direct *name);
+typedef int (*compar_t) (void *d1,void *d2);
+int scandir (char *dirname,struct direct ***namelist,select_t select,
+	     compar_t compar);
+int alphasort (void *d1,void *d2);
+
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+#include "flocksim.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_dyn.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,64 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Dynix version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *
+ * Date:	11 May 1989
+ * Last Edited:	16 August 2007
+ */
+
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+#define toint(c)	((c)-'0')
+#define isodigit(c)	(((unsigned)(c)>=060)&((unsigned)(c)<=067))
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#define fork vfork
+#include "tcp_unix.c"
+#include "gr_wait.c"
+#include "memmove.c"
+#include "strerror.c"
+#include "strpbrk.c"
+#include "strstr.c"
+#include "strtoul.c"
+#include "strtok.c"
+#include "tz_nul.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_dyn.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,61 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Dynix version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	30 January 2007
+ */
+
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <sys/file.h>
+
+
+typedef unsigned long size_t;
+
+char *strtok (char *s,char *ct);
+char *strtok_r (char *s,char *ct,char **r);
+char *strstr (char *cs,char *ct);
+char *strpbrk (char *cs,char *ct);
+char *strerror (int n);
+void *memmove (void *s,void *ct,size_t n);
+void *memset (void *s,int c,size_t n);
+unsigned long strtoul (char *s,char **endp,int base);
+void *malloc (size_t byteSize);
+void free (void *ptr);
+void *realloc (void *oldptr,size_t newsize);
+
+int errno;
+
+#define memcpy memmove
+#define strchr index
+#define strrchr rindex
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_hpp.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,77 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- HP/UX version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	16 August 2007
+ */
+
+#define isodigit(c)    (((unsigned)(c)>=060)&((unsigned)(c)<=067))
+#define toint(c)       ((c)-'0')
+
+#include <stdio.h>
+
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/utsname.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+extern char *sys_errlist[];
+extern int sys_nerr;
+#include <pwd.h>
+#include "misc.h"
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#define fork vfork
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "flocksim.c"
+#include "tz_sv4.c"
+#undef setpgrp
+#include "setpgrp.c"
+#include "utime.c"
+
+/* Emulator for BSD gethostid() call
+ * Returns: a unique identifier for the system.  
+ * Even though HP/UX has an undocumented gethostid() system call,
+ * it does not work (at least for non-privileged users).  
+ */
+
+long gethostid (void)
+{
+  struct utsname udata;
+  return (uname (&udata)) ? 0xfeedface : atol (udata.__idnumber);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_hpp.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,63 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- HP/UX version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	20 December 2006
+ */
+
+#include <string.h>
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+#include <utime.h>
+#include <syslog.h>
+#include <sys/file.h>
+#include <ustat.h>
+
+
+#define direct dirent
+#define random lrand48
+
+
+/* Many versions of SysV get this wrong */
+
+#define setpgrp(a,b) Setpgrp(a,b)
+int Setpgrp (int pid,int gid);
+
+
+#define utime portable_utime
+int portable_utime (char *file,time_t timep[2]);
+
+long gethostid (void);
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+#include "flocksim.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_isc.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,68 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- ISC version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 April 1992
+ * Last Edited:	30 August 2006
+ */
+
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/tiuser.h>
+#include <sys/stropts.h>
+#include <sys/poll.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <errno.h>
+#include <net/errno.h>
+#include <pwd.h>
+#include <shadow.h>
+#include <sys/socket.h>
+#include "misc.h"
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+#define toint(c)	((c)-'0')
+#define isodigit(c)	(((unsigned)(c)>=060)&((unsigned)(c)<=067))
+
+#define DIR_SIZE(d) d->d_reclen
+
+#define pid_t short		/* may not be known on all ISC systems */
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "strerror.c"
+#include "flocksim.c"
+#include "scandir.c"
+#include "tz_sv4.c"
+#include "fsync.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_isc.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,70 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- ISC version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 April 1992
+ * Last Edited:	15 September 2006
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/bsdtypes.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+#include <syslog.h>
+#include <sys/file.h>
+#include <ustat.h>
+
+
+/* Different names, equivalent things in BSD and SysV */
+
+/* L_SET is defined for some strange reason in <sys/file.h> on SVR4. */
+#ifndef L_SET
+#define L_SET SEEK_SET
+#endif
+#define L_INCR SEEK_CUR
+#define L_XTND SEEK_END
+
+#define direct dirent
+
+#define ftruncate chsize
+#define random lrand48
+
+long gethostid (void);
+void *memmove (void *s,void *ct,size_t n);
+typedef int (*select_t) (struct direct *name);
+typedef int (*compar_t) (void *d1,void *d2);
+int scandir (char *dirname,struct direct ***namelist,select_t select,
+	     compar_t compar);
+int alphasort (void *d1,void *d2);
+
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+#include "flocksim.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_lnx.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,54 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- old Linux version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1993
+ * Last Edited:	16 August 2007
+ */
+ 
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#define fork vfork
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "tz_sv4.c"
+#include "flocklnx.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_lnx.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,67 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Linux version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 September 1993
+ * Last Edited:	30 August 2006
+ */
+
+/*
+ *** These lines are claimed to be necessary to build on Debian Linux on an
+ *** Alpha.
+ */
+
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 1
+#endif /* _XOPEN_SOURCE */
+#ifndef _BSD_SOURCE
+#define _BSD_SOURCE 1
+#endif /* _BSD_SOURCE */
+
+/* end Debian Linux on Alpha strangeness */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <time.h>		/* for struct tm */
+#include <fcntl.h>
+#include <syslog.h>
+#include <sys/file.h>
+
+
+/* Linux gets this wrong */
+
+#define setpgrp setpgid
+
+#define direct dirent
+
+#define flock safe_flock
+
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_lyn.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,54 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- LynxOS version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+ 
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+
+char *crypt (char *key,char *salt);
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "tz_nul.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_lyn.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,44 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- LynxOS version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	5 March 1993
+ * Last Edited:	30 August 2006
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <sys/file.h>
+
+#define gethostid clock
+
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_mct.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,52 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- MachTen version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	7 December 2006
+ */
+
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#include "tcp_unix.c"
+#include "gr_wait4.c"
+#include "tz_bsd.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_mct.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,44 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- MachTen version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	7 December 2006
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <sys/file.h>
+
+#define unix 1
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_mnt.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,53 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Mint version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	16 August 2007
+ */
+ 
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#define fork vfork
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "tz_nul.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_mnt.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,51 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Mint version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 September 1993
+ * Last Edited:	30 August 2006
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <sys/file.h>
+#include <time.h>
+#include <portlib.h>
+ 
+#define EAGAIN EWOULDBLOCK
+#define FNDELAY O_NDELAY 
+ 
+/* MiNT gets this wrong */
+ 
+#define setpgrp setpgid
+ 
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_nto.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,76 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- QNX Neutrino RTP version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1993
+ * Last Edited:	30 August 2006
+ */
+
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include <shadow.h>
+#include <sys/select.h>
+#include "misc.h"
+
+#define DIR_SIZE(d) d->d_reclen
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#include "tcp_unix.c"
+#include "gr_wait.c"
+#include "tz_sv4.c"
+#include "gethstid.c"
+#include "flocksim.c"
+#include "utime.c"
+
+/* QNX local readdir()
+ * Accepts: directory structure
+ * Returns: direct struct or NIL if failed
+ */
+
+#undef readdir
+
+struct direct *Readdir (DIR *dirp)
+{
+  static struct direct dc;
+  struct dirent *de = readdir (dirp);
+  if (!de) return NIL;		/* end of data */
+  dc.d_fileno = 0;		/* could get from de->stat.st_ino */
+  dc.d_namlen = strlen (strcpy (dc.d_name,de->d_name));
+  dc.d_reclen = sizeof (dc);
+  return &dc;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_nto.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,75 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- QNX Neutrino RTP version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 September 1993
+ * Last Edited:	30 August 2006
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/dir.h>
+#include <sys/types.h>
+#include <time.h>
+#include <utime.h>
+
+
+/* QNX gets these wrong */
+
+#define setpgrp setpgid
+#define readdir Readdir
+#define FNDELAY O_NONBLOCK
+#define d_ino d_fileno
+
+
+/* Different names, equivalent things in BSD and SysV */
+
+#ifndef L_SET
+#define L_SET SEEK_SET
+#endif
+#ifndef L_INCR
+#define L_INCR SEEK_CUR
+#endif
+#ifndef L_XTND
+#define L_XTND SEEK_END
+#endif
+
+
+#define utime portable_utime
+int portable_utime (char *file,time_t timep[2]);
+
+long gethostid (void);
+struct direct *Readdir (DIR *dirp);
+typedef int (*select_t) (struct direct *name);
+typedef int (*compar_t) (void *d1,void *d2);
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+#include "flocksim.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_nxt.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,54 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- NeXT version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	16 August 2007
+ */
+
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#define fork vfork
+#include "tcp_unix.c"
+#include "gr_wait4.c"
+#include "tz_bsd.c"
+#include "strtok.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_nxt.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,50 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- NeXT version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 January 2007
+ */
+
+#include <libc.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <sys/file.h>
+
+/* Use ours instead of theirs */
+
+#define strtok STRTOK
+#define strtok_r STRTOK_R
+
+char *strtok (char *s,char *ct);
+char *strtok_r (char *s,char *ct,char **r);
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_os4.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,57 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- OSF/Digital UNIX/Tru64 4
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+ 
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+#include <sia.h>
+#include <siad.h>
+#include <ustat.h>
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#include "gr_waitp.c"
+#include "tcp_unix.c"
+#include "tz_bsd.c"
+#undef flock
+#include "flocksim.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_os4.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,51 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- OSF/Digital UNIX/Tru64
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <time.h>		/* for struct tm */
+#include <fcntl.h>
+#include <syslog.h>
+#include <sys/file.h>
+
+
+/* OSF/1 gets this wrong */
+
+#define setpgrp setpgid
+
+#define direct dirent
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+#include "flocksim.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_osf.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,55 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- OSF/Digital UNIX/Tru64
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+ 
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+#include <ustat.h>
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#include "gr_waitp.c"
+#include "tcp_unix.c"
+#include "tz_bsd.c"
+#undef flock
+#include "flocksim.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_osf.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,51 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- OSF/Digital UNIX/Tru64
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <time.h>		/* for struct tm */
+#include <fcntl.h>
+#include <syslog.h>
+#include <sys/file.h>
+
+
+/* OSF/1 gets this wrong */
+
+#define setpgrp setpgid
+
+#define direct dirent
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+#include "flocksim.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_osx.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,54 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Mac OS X version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	16 August 2007
+ */
+
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#define fork vfork
+#include "getspnam.c"
+#include "tcp_unix.c"
+#include "gr_wait4.c"
+#include "tz_bsd.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_osx.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,56 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Mac OS X version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	26 October 2007
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <sys/file.h>
+
+
+/* Mac OS X gets this wrong as of Leopard */
+
+#define setpgrp setpgid
+
+
+#define unix 1
+
+/* Mac OS X security framework also has checkpw, and this causes
+ * multiple-definition problems when building Alpine.
+ */
+
+#define checkpw Checkpw
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_ptx.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,115 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- PTX version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	16 August 2007
+ */
+
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/tiuser.h>
+#include <sys/stropts.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <errno.h>
+#include <pwd.h>
+#include <shadow.h>
+#include <sys/select.h>
+#include "misc.h"
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+#define DIR_SIZE(d) d->d_reclen
+
+#define toint(c)	((c)-'0')
+#define isodigit(c)	(((unsigned)(c)>=060)&((unsigned)(c)<=067))
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#define env_init ENV_INIT
+#include "env_unix.c"
+#undef env_init
+#define getpeername Getpeername
+#define fork vfork
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "flocksim.c"
+#include "scandir.c"
+#include "tz_sv4.c"
+#include "utime.c"
+
+/* Jacket around env_init() to work around PTX inetd braindamage */
+
+static char may_need_server_init = T;
+
+long env_init (char *user,char *home)
+{
+  if (may_need_server_init) {	/* maybe need to do server init cruft? */
+    may_need_server_init = NIL;	/* not any more we don't */
+    if (!getuid ()) {		/* if root, we're most likely a server */
+      t_sync (0);		/* PTX inetd is stupid, stupid, stupid */
+      ioctl (0,I_PUSH,"tirdwr");/*  it needs this cruft, else servers won't */
+      dup2 (0,1);		/*  work.  How obnoxious!!! */
+    }
+  }
+  ENV_INIT (user,home);		/* call the real routine */
+}
+
+/* Emulator for BSD gethostid() call
+ * Returns: unique identifier for this machine
+ */
+
+long gethostid (void)
+{
+  struct sockaddr_in sin;
+  int inet = t_open (TLI_TCP, O_RDWR, 0);
+  if (inet < 0) return 0;
+  getmyinaddr (inet,&sin,sizeof (sin));
+  close (inet);
+  return sin.sin_addr.s_addr;
+}
+
+
+/* Replaced version of getpeername() that jackets into getpeerinaddr()
+ * Accepts: file descriptor
+ *	    pointer to Internet socket addr
+ *	    length
+ * Returns: zero if success, data in socket addr
+ */
+
+int Getpeername (int s,struct sockaddr *name,int *namelen)
+{
+  return getpeerinaddr (s,(struct sockaddr_in *) name,*namelen);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_ptx.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,72 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- PTX version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	15 September 2006
+ */
+
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/dir.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+#include <utime.h>
+#include <dirent.h>
+#include <stropts.h>		/* needed in daemons */
+#include <syslog.h>
+#include <sys/file.h>
+#include <ustat.h>
+
+
+/* Different names, equivalent things in BSD and SysV */
+
+#define L_SET SEEK_SET
+#define L_INCR SEEK_CUR
+#define L_XTND SEEK_END
+
+#define direct dirent
+#define random lrand48
+
+
+#define utime portable_utime
+int portable_utime (char *file,time_t timep[2]);
+
+long gethostid (void);
+typedef int (*select_t) (struct direct *name);
+typedef int (*compar_t) (void *d1,void *d2);
+int scandir (char *dirname,struct direct ***namelist,select_t select,
+	     compar_t compar);
+int alphasort (void *d1,void *d2);
+long ENV_INIT (char *user,char *home);
+
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+#include "flocksim.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_pyr.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,61 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Pyramid OSx 4.4c version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *
+ * Date:	11 May 1989
+ * Last Edited:	30 August 2006
+ */
+
+#define isodigit(c)    (((unsigned)(c)>=060)&((unsigned)(c)<=067))
+#define toint(c)       ((c)-'0')
+
+
+#include "tcp_unix.h"           /* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#include "tcp_unix.c"
+#include "gr_wait.c"
+#include "memmove.c"
+#include "memset.c"
+#include "strerror.c"
+#include "strpbrk.c"
+#include "strstr.c"
+#include "strtok.c"
+#include "tz_nul.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_pyr.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,58 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Pyramid OSx 4.4c version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	30 January 2007
+ */
+
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <sys/file.h>
+
+
+char *strtok (char *s,char *ct);
+char *strtok_r (char *s,char *ct,char **r);
+char *strstr (char *cs,char *ct);
+char *strpbrk (char *cs,char *ct);
+char *strerror (int n);
+void *memmove (void *s,void *ct,size_t n);
+void *memset (void *s,int c,size_t n);
+void *malloc (size_t byteSize);
+void free (void *ptr);
+void *realloc (void *oldptr,size_t newsize);
+
+int errno;
+
+#define memcpy memmove
+#define strchr index
+#define strrchr rindex
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_qnx.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,77 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- QNX version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1993
+ * Last Edited:	20 December 2006
+ */
+
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include <shadow.h>
+#include <sys/select.h>
+#include "misc.h"
+
+#define DIR_SIZE(d) d->d_reclen
+
+extern char *crypt (const char *pw, const char *salt);
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "tz_sv4.c"
+#include "gethstid.c"
+#include "scandir.c"
+
+/* QNX local readdir()
+ * Accepts: directory structure
+ * Returns: direct struct or NIL if failed
+ */
+
+#undef readdir
+
+struct direct *Readdir (DIR *dirp)
+{
+  static struct direct dc;
+  struct dirent *de = readdir (dirp);
+  if (!de) return NIL;		/* end of data */
+  dc.d_fileno = 0;		/* could get from de->stat.st_ino */
+  dc.d_namlen = strlen (strcpy (dc.d_name,de->d_name));
+  dc.d_reclen = sizeof (dc);
+  return &dc;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_qnx.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,62 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- QNX version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 September 1993
+ * Last Edited:	20 December 2006
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/file.h>
+#include <sys/dir.h>
+#include <sys/types.h>
+#include </usr/include/unix.h>
+#include <time.h>
+#include <utime.h>
+
+
+/* QNX gets these wrong */
+
+#define setpgrp setpgid
+#define readdir Readdir
+#define FNDELAY O_NONBLOCK
+#define d_ino d_fileno
+
+typedef int (*select_t) (struct direct *name);
+typedef int (*compar_t) (void *d1,void *d2);
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+
+long gethostid(void);
+struct direct *Readdir (DIR *dirp);
+
+extern long random (void);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_s40.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,64 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- SUN-OS 4.0 version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	16 August 2007
+ */
+
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+#define toint(c)	((c)-'0')
+#define isodigit(c)	(((unsigned)(c)>=060)&((unsigned)(c)<=067))
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#define fork vfork
+#include "tcp_unix.c"
+#include "gr_wait4.c"
+#include "memmove.c"
+#include "strerror.c"
+#define strstr Strstr		/* override SUN's broken version */
+#include "strstr.c"
+#include "strtoul.c"
+#include "tz_bsd.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_s40.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,33 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- SUN-OS 4.0 version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	30 August 2006
+ */
+
+void *malloc (size_t byteSize);
+void free (void *ptr);
+void *realloc (void *oldptr,size_t newsize);
+
+#include "os_sun.h"		/* now use regular SUN-OS file */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_sc5.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,63 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- SCO Unix version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+ 
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include <sys/time.h>		/* must be before osdep.h */
+#include "mail.h"
+#include <stdio.h>
+#include "osdep.h"
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+#include "misc.h"
+#define SecureWare		/* protected subsystem */
+#include <sys/security.h>
+#include <sys/audit.h>
+#include <prot.h>
+#include <pwd.h>
+
+#define DIR_SIZE(d) d->d_reclen
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "flocksim.c"
+#include "scandir.c"
+#include "tz_sv4.c"
+#include "gethstid.c"
+#undef setpgrp
+#include "setpgrp.c"
+#include "rename.c"
+#include "utime.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_sc5.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,76 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- SCO Unix version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	20 December 2006
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+#include <utime.h>
+#include <dirent.h>
+#include <syslog.h>
+#include <sys/file.h>
+#include <ustat.h>
+
+/* SCO gets this wrong */
+
+#define setpgrp Setpgrp
+int Setpgrp (int pid,int gid);
+
+#define rename Rename
+
+
+/* Different names, equivalent things in BSD and SysV */
+
+#define L_SET SEEK_SET
+#define L_INCR SEEK_CUR
+#define L_XTND SEEK_END
+
+#define direct dirent
+
+#define utime portable_utime
+int portable_utime (char *file,time_t timep[2]);
+
+
+long gethostid (void);
+typedef int (*select_t) (struct direct *name);
+typedef int (*compar_t) (void *d1,void *d2);
+int scandir (char *dirname,struct direct ***namelist,select_t select,
+	     compar_t compar);
+int alphasort (void *d1,void *d2);
+int fsync (int fd);
+
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+#include "flocksim.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_sco.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,66 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- SCO Unix version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+ 
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include <sys/time.h>		/* must be before osdep.h */
+#include "mail.h"
+#include <stdio.h>
+#include "osdep.h"
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+#include "misc.h"
+#define SecureWare		/* protected subsystem */
+#include <sys/security.h>
+#include <sys/audit.h>
+#include <prot.h>
+#include <pwd.h>
+
+char *bigcrypt (char *key,char *salt);
+
+#define DIR_SIZE(d) d->d_reclen
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "flocksim.c"
+#include "scandir.c"
+#include "tz_sv4.c"
+#include "gethstid.c"
+#include "fsync.c"
+#undef setpgrp
+#include "setpgrp.c"
+#include "rename.c"
+#include "utime.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_sco.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,79 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- SCO Unix version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	20 December 2006
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+#include <utime.h>
+#include <dirent.h>
+#include <syslog.h>
+#include <sys/file.h>
+#include <ustat.h>
+
+/* SCO gets this wrong */
+
+#define setpgrp Setpgrp
+int Setpgrp (int pid,int gid);
+
+#define rename Rename
+
+
+/* Different names, equivalent things in BSD and SysV */
+
+#define L_SET SEEK_SET
+#define L_INCR SEEK_CUR
+#define L_XTND SEEK_END
+
+#define direct dirent
+
+#define utime portable_utime
+int portable_utime (char *file,time_t timep[2]);
+
+#define ftruncate chsize
+#define random rand
+
+
+long gethostid (void);
+typedef int (*select_t) (struct direct *name);
+typedef int (*compar_t) (void *d1,void *d2);
+int scandir (char *dirname,struct direct ***namelist,select_t select,
+	     compar_t compar);
+int alphasort (void *d1,void *d2);
+int fsync (int fd);
+
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+#include "flocksim.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_sgi.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,57 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- SGI version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+ 
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <bstring.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "tz_nul.c"
+#include "flocksim.c"
+#undef setpgrp
+#include "setpgrp.c"
+#include "utime.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_sgi.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,59 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- SGI version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	20 December 2006
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <time.h>		/* for struct tm */
+#include <utime.h>
+#include <fcntl.h>
+#include <sys/syslog.h>
+#include <sys/file.h>
+#include <ustat.h>
+
+/* Many versions of SysV get this wrong */
+
+#define setpgrp(a,b) Setpgrp(a,b)
+int Setpgrp (int pid,int gid);
+
+
+#define direct dirent
+
+#define fatal cclient_fatal
+
+#define utime portable_utime
+int portable_utime (char *file,time_t timep[2]);
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+#include "flocksim.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_shp.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,79 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- HP/UX version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	16 August 2007
+ */
+
+#define isodigit(c)    (((unsigned)(c)>=060)&((unsigned)(c)<=067))
+#define toint(c)       ((c)-'0')
+
+#include <stdio.h>
+
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/utsname.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+extern char *sys_errlist[];
+extern int sys_nerr;
+#include <pwd.h>
+#include <hpsecurity.h>
+#include <prot.h>
+#include "misc.h"
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#define fork vfork
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "flocksim.c"
+#include "tz_sv4.c"
+#undef setpgrp
+#include "setpgrp.c"
+#include "utime.c"
+
+/* Emulator for BSD gethostid() call
+ * Returns: a unique identifier for the system.  
+ * Even though HP/UX has an undocumented gethostid() system call,
+ * it does not work (at least for non-privileged users).  
+ */
+
+long gethostid (void)
+{
+  struct utsname udata;
+  return (uname (&udata)) ? 0xfeedface : atol (udata.__idnumber);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_shp.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,63 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- HP/UX version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	20 December 2006
+ */
+
+#include <string.h>
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+#include <utime.h>
+#include <syslog.h>
+#include <sys/file.h>
+#include <ustat.h>
+
+
+#define direct dirent
+#define random lrand48
+
+
+/* Many versions of SysV get this wrong */
+
+#define setpgrp(a,b) Setpgrp(a,b)
+int Setpgrp (int pid,int gid);
+
+
+#define utime portable_utime
+int portable_utime (char *file,time_t timep[2]);
+
+long gethostid (void);
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+#include "flocksim.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_slx.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,56 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- modern Linux version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1993
+ * Last Edited:	16 August 2007
+ */
+ 
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include <shadow.h>
+#include "misc.h"
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#include "getspnam.c"		/* has socklen_t in spite of man page?? */
+#define fork vfork
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "tz_sv4.c"
+#include "flocklnx.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_slx.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,67 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Linux version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 September 1993
+ * Last Edited:	30 August 2006
+ */
+
+/*
+ *** These lines are claimed to be necessary to build on Debian Linux on an
+ *** Alpha.
+ */
+
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 1
+#endif /* _XOPEN_SOURCE */
+#ifndef _BSD_SOURCE
+#define _BSD_SOURCE 1
+#endif /* _BSD_SOURCE */
+
+/* end Debian Linux on Alpha strangeness */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <time.h>		/* for struct tm */
+#include <fcntl.h>
+#include <syslog.h>
+#include <sys/file.h>
+
+
+/* Linux gets this wrong */
+
+#define setpgrp setpgid
+
+#define direct dirent
+
+#define flock safe_flock
+
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_sol.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,71 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Solaris version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 April 1992
+ * Last Edited:	16 August 2007
+ */
+
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/tiuser.h>
+#include <sys/stropts.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <errno.h>
+#include <pwd.h>
+#include <shadow.h>
+#include <crypt.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include "misc.h"
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+#define DIR_SIZE(d) d->d_reclen
+
+#define toint(c)	((c)-'0')
+#define isodigit(c)	(((unsigned)(c)>=060)&((unsigned)(c)<=067))
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#include "getspnam.c"
+#define fork vfork
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "flocksim.c"
+#include "scandir.c"
+#include "tz_sv4.c"
+#include "gethstid.c"
+#undef setpgrp
+#include "setpgrp.c"
+#include "utime.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_soln.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,87 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Solaris version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	20 December 2006
+ */
+
+#include <string.h>
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+#include <utime.h>
+#include <syslog.h>
+#include <sys/file.h>
+#include <ustat.h>
+
+
+/* Many versions of SysV get this wrong */
+
+#define setpgrp(a,b) Setpgrp(a,b)
+int Setpgrp (int pid,int gid);
+
+
+/* Different names, equivalent things in BSD and SysV */
+
+/* L_SET is defined for some strange reason in <sys/file.h> on SVR4. */
+#ifndef L_SET
+#define L_SET SEEK_SET
+#endif
+#ifndef L_INCR
+#define L_INCR SEEK_CUR
+#endif
+#ifndef L_XTND
+#define L_XTND SEEK_END
+#endif
+
+#define direct dirent
+#define random lrand48
+
+#define scandir Scandir
+#define alphasort Alphasort
+
+#define getpass getpassphrase
+
+
+#define utime portable_utime
+int portable_utime (char *file,time_t timep[2]);
+
+long gethostid (void);
+typedef int (*select_t) (struct direct *name);
+typedef int (*compar_t) (const void *d1,const void *d2);
+int scandir (char *dirname,struct direct ***namelist,select_t select,
+	     compar_t compar);
+int alphasort (void *d1,void *d2);
+
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+#include "flocksim.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_solo.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,84 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Solaris version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	20 December 2006
+ */
+
+#include <string.h>
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+#include <utime.h>
+#include <syslog.h>
+#include <sys/file.h>
+#include <ustat.h>
+
+
+/* Many versions of SysV get this wrong */
+
+#define setpgrp(a,b) Setpgrp(a,b)
+int Setpgrp (int pid,int gid);
+
+
+/* Different names, equivalent things in BSD and SysV */
+
+/* L_SET is defined for some strange reason in <sys/file.h> on SVR4. */
+#ifndef L_SET
+#define L_SET SEEK_SET
+#endif
+#ifndef L_INCR
+#define L_INCR SEEK_CUR
+#endif
+#ifndef L_XTND
+#define L_XTND SEEK_END
+#endif
+
+#define direct dirent
+#define random lrand48
+
+#define scandir Scandir
+#define alphasort Alphasort
+
+#define utime portable_utime
+int portable_utime (char *file,time_t timep[2]);
+
+long gethostid (void);
+typedef int (*select_t) (struct direct *name);
+typedef int (*compar_t) (const void *d1,const void *d2);
+int scandir (char *dirname,struct direct ***namelist,select_t select,
+	     compar_t compar);
+int alphasort (void *d1,void *d2);
+
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+#include "flocksim.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_sos.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,57 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- S OSF/Digital UNIX/Tru64
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+ 
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+#include <sys/security.h>
+#include <prot.h>
+#include <ustat.h>
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "tz_bsd.c"
+#undef flock
+#include "flocksim.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_sos.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,51 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- OSF/Digital UNIX/Tru64
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <time.h>		/* for struct tm */
+#include <fcntl.h>
+#include <syslog.h>
+#include <sys/file.h>
+
+
+/* OSF/1 gets this wrong */
+
+#define setpgrp setpgid
+
+#define direct dirent
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+#include "flocksim.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_sua.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,54 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Windows Vista SUA
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1993
+ * Last Edited:	16 August 2007
+ */
+ 
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#define fork vfork
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "tz_sv4.c"
+#include "gethstid.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_sua.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,50 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Windows Vista SUA
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 September 1993
+ * Last Edited:	4 May 2007
+ */
+
+#define _REENTRANT		/* for strtok_r() */
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <time.h>		/* for struct tm */
+#include <fcntl.h>
+#include <syslog.h>
+#include <sys/file.h>
+
+
+#define setpgrp setpgid
+
+#define direct dirent
+
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_sun.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,64 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- SUN-OS version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	16 August 2007
+ */
+
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+#define toint(c)	((c)-'0')
+#define isodigit(c)	(((unsigned)(c)>=060)&((unsigned)(c)<=067))
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#define fork vfork
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "memmove.c"
+#include "strerror.c"
+#define strstr Strstr		/* override SUN's broken version */
+#include "strstr.c"
+#include "strtoul.c"
+#include "tz_bsd.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_sun.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,51 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- SUN-OS version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	30 August 2006
+ */
+
+#include <sys/types.h>
+#include <sys/dir.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <sys/file.h>
+
+
+#define strstr Strstr		/* override system definition */
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+
+char *Strstr (char *cs,char *ct);
+char *strerror (int n);
+unsigned long strtoul (char *s,char **endp,int base);
+#define memcpy memmove
+void *memmove (void *s,void *ct,size_t n);
+void *memset (void *s,int c,size_t n);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_sv2.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,128 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- SVR2 version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 April 1992
+ * Last Edited:	30 August 2006
+ */
+
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <errno.h>
+extern int errno;
+#include <pwd.h>
+#include <sys/socket.h>
+#include <time.h>
+#define KERNEL
+#include <sys/time.h>
+#undef KERNEL
+#include "misc.h"
+
+#define DIR_SIZE(d) sizeof (DIR)
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+#define toint(c)	((c)-'0')
+#define isodigit(c)	(((unsigned)(c)>=060)&((unsigned)(c)<=067))
+
+#define	NBBY	8	/* number of bits in a byte */
+#define	FD_SETSIZE	256
+
+typedef long	fd_mask;
+#define NFDBITS	(sizeof(fd_mask) * NBBY)
+					/* bits per mask */
+#define	howmany(x, y)	(((x)+((y)-1))/(y))
+
+typedef	struct fd_set {
+  fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)];
+} fd_set;
+
+#define	FD_SET(n, p)	((p)->fds_bits[(n)/NFDBITS] |= \
+					(1 << ((n) % NFDBITS)))
+#define	FD_CLR(n, p)	((p)->fds_bits[(n)/NFDBITS] &= \
+					~(1 << ((n) % NFDBITS)))
+#define	FD_ISSET(n, p)	((p)->fds_bits[(n)/NFDBITS] & \
+					(1 << ((n) % NFDBITS)))
+#define FD_ZERO(p)	bzero((char *)(p), sizeof(*(p)))
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#include "tcp_unix.c"
+#include "gr_wait.c"
+#include "flocksim.c"
+#include "opendir.c"
+#include "scandir.c"
+#include "memmove2.c"
+#include "strstr.c"
+#include "strerror.c"
+#include "strtoul.c"
+#include "tz_sv4.c"
+#include "gethstid.c"
+#include "fsync.c"
+#undef setpgrp
+#include "setpgrp.c"
+
+/* Emulator for BSD syslog() routine
+ * Accepts: priority
+ *	    message
+ *	    parameters
+ */
+
+int syslog (int priority,char *message,char *parameters)
+{
+  /* nothing here for now */
+}
+
+
+/* Emulator for BSD openlog() routine
+ * Accepts: identity
+ *	    options
+ *	    facility
+ */
+
+int openlog (char *ident,int logopt,int facility)
+{
+  /* nothing here for now */
+}
+
+
+/* Emulator for BSD ftruncate() routine
+ * Accepts: file descriptor
+ *	    length
+ */
+
+int ftruncate (int fd,unsigned long length)
+{
+  return -1;			/* gotta figure out how to do this */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_sv2.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,120 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- SVR2 version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 April 1992
+ * Last Edited:	20 December 2006
+ */
+
+#include <unistd.h>
+#include <string.h>
+#define char void
+#include <memory.h>
+#undef char
+#include <sys/types.h>
+#include <sys/dir.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <sys/file.h>
+#include <ustat.h>
+
+
+/* Many versions of SysV get this wrong */
+
+#define setpgrp(a,b) Setpgrp(a,b)
+int Setpgrp (int pid,int gid);
+
+
+/* Different names between BSD and SVR4 */
+
+#define L_SET SEEK_SET
+#define L_INCR SEEK_CUR
+#define L_XTND SEEK_END
+
+#define lstat stat
+#define random lrand48
+
+#define SIGSTOP SIGQUIT
+
+#define S_IFLNK 0120000
+
+
+/* syslog() emulation */
+
+#define LOG_MAIL	(2<<3)	/* mail system */
+#define LOG_DAEMON	(3<<3)	/* system daemons */
+#define LOG_AUTH	(4<<3)	/* security/authorization messages */
+#define LOG_ALERT	1	/* action must be taken immediately */
+#define LOG_CONS	0x02	/* log on the console if errors in sending */
+#define LOG_ODELAY	0x04	/* delay open until syslog() is called */
+#define LOG_NDELAY	0x08	/* don't delay open */
+#define LOG_NOWAIT	0x10	/* if forking to log on console, don't wait() */
+
+
+/* For setitimer() emulation */
+
+#define ITIMER_REAL	0
+
+
+/* For opendir() emulation */
+
+typedef struct _dirdesc {
+  int dd_fd;
+  long dd_loc;
+  long dd_size;
+  char *dd_buf;
+} DIR;
+
+struct passwd *getpwent (void);
+struct passwd *getpwuid (int uid);
+struct passwd *getpwnam (char *name);
+struct group *getgrnam (char *name);
+
+char *getenv (char *name);
+long gethostid (void);
+void *memmove (void *s,void *ct,size_t n);
+char *strstr (char *cs,char *ct);
+char *strerror (int n);
+unsigned long strtoul (char *s,char **endp,int base);
+DIR *opendir (char * name);
+int closedir (DIR *d);
+struct direct *readdir (DIR *d);
+typedef int (*select_t) (struct direct *name);
+typedef int (*compar_t) (void *d1,void *d2);
+int scandir (char *dirname,struct direct ***namelist,select_t select,
+	     compar_t compar);
+int alphasort (void *d1,void *d2);
+int fsync (int fd);
+int openlog (ident,logopt,facility);
+int syslog (priority,message,parameters ...);
+void *malloc (size_t byteSize);
+void free (void *ptr);
+void *realloc (void *oldptr,size_t newsize);
+
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+#include "flocksim.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_sv4.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,68 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- SVR4 version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 April 1992
+ * Last Edited:	30 August 2006
+ */
+
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/tiuser.h>
+#include <sys/stropts.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <errno.h>
+#include <pwd.h>
+#include <shadow.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include "misc.h"
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+#define DIR_SIZE(d) d->d_reclen
+
+#define toint(c)	((c)-'0')
+#define isodigit(c)	(((unsigned)(c)>=060)&((unsigned)(c)<=067))
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "flocksim.c"
+#include "scandir.c"
+#include "tz_sv4.c"
+#include "gethstid.c"
+#undef setpgrp
+#include "setpgrp.c"
+#include "utime.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_sv4.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,78 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- SVR4 version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 April 1992
+ * Last Edited:	20 December 2006
+ */
+
+#include <string.h>
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+#include <utime.h>
+#include <syslog.h>
+#include <sys/file.h>
+#include <ustat.h>
+
+
+/* Many versions of SysV get this wrong */
+
+#define setpgrp(a,b) Setpgrp(a,b)
+int Setpgrp (int pid,int gid);
+
+
+/* Different names, equivalent things in BSD and SysV */
+
+/* L_SET is defined for some strange reason in <sys/file.h> on SVR4. */
+#ifndef L_SET
+#define L_SET SEEK_SET
+#endif
+#define L_INCR SEEK_CUR
+#define L_XTND SEEK_END
+
+#define direct dirent
+#define random lrand48
+
+
+#define utime portable_utime
+int portable_utime (char *file,time_t timep[2]);
+
+long gethostid (void);
+typedef int (*select_t) (struct direct *name);
+typedef int (*compar_t) (void *d1,void *d2);
+int scandir (char *dirname,struct direct ***namelist,select_t select,
+	     compar_t compar);
+int alphasort (void *d1,void *d2);
+
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+#include "flocksim.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_ult.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,52 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Ultrix version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *
+ * Date:	11 May 1989
+ * Last Edited:	16 August 2007
+ */
+
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#define fork vfork
+#include "tcp_unix.c"
+#include "gr_waitp.c"
+#include "tz_bsd.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_ult.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,42 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- Ultrix version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	30 August 2006
+ */
+
+#include <sys/types.h>
+#include <sys/dir.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/syslog.h>
+#include <sys/file.h>
+
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_vu2.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,82 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- VAX Ultrix 2.3 version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *
+ * Date:	11 May 1989
+ * Last Edited:	16 August 2007
+ */
+
+#include "tcp_unix.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <pwd.h>
+#include "misc.h"
+
+#define NFDBITS	(sizeof(long) * 8)
+
+#define	FD_SET(n, p)	((p)->fds_bits[(n)/NFDBITS] |= \
+					(1 << ((n) % NFDBITS)))
+#define	FD_CLR(n, p)	((p)->fds_bits[(n)/NFDBITS] &= \
+					~(1 << ((n) % NFDBITS)))
+#define	FD_ISSET(n, p)	((p)->fds_bits[(n)/NFDBITS] & \
+					(1 << ((n) % NFDBITS)))
+#define FD_ZERO(p)	bzero((char *)(p), sizeof(*(p)))
+
+
+/* Old Ultrix has its own wierd inet_addr() that returns a in_addr struct. */
+
+/* Portable inet_addr () that returns a u_long
+ * Accepts: dotted host string
+ * Returns: u_long
+ */
+
+u_long portable_inet_addr (char *hostname)
+{
+  struct in_addr *in = &inet_addr (hostname);
+  return in->s_addr;
+}
+
+
+#define inet_addr portable_inet_addr
+
+#include "fs_unix.c"
+#include "ftl_unix.c"
+#include "nl_unix.c"
+#include "env_unix.c"
+#define fork vfork
+#include "tcp_unix.c"
+#include "gr_wait.c"
+#include "memmove.c"
+#include "strerror.c"
+#include "strstr.c"
+#include "strtoul.c"
+#include "tz_nul.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/os_vu2.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,79 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- VAX Ultrix 2.3 version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	30 August 2006
+ */
+
+#include <memory.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+#include <string.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <sys/file.h>
+
+
+/* syslog() emulation */
+
+#define LOG_MAIL	(2<<3)	/* mail system */
+#define LOG_DAEMON	(3<<3)	/* system daemons */
+#define LOG_AUTH	(4<<3)	/* security/authorization messages */
+#define LOG_EMERG	0	/* system is unusable */
+#define LOG_ALERT	1	/* action must be taken immediately */
+#define LOG_CRIT	2	/* critical conditions */
+#define LOG_ERR		3	/* error conditions */
+#define LOG_WARNING	4	/* warning conditions */
+#define LOG_NOTICE	5	/* normal but signification condition */
+#define LOG_INFO	6	/* informational */
+#define LOG_DEBUG	7	/* debug-level messages */
+#define LOG_PID		0x01	/* log the pid with each message */
+#define LOG_CONS	0x02	/* log on the console if errors in sending */
+#define LOG_ODELAY	0x04	/* delay open until syslog() is called */
+#define LOG_NDELAY	0x08	/* don't delay open */
+#define LOG_NOWAIT	0x10	/* if forking to log on console, don't wait() */
+
+
+#define isodigit(c)    (((unsigned)(c)>=060)&((unsigned)(c)<=067))
+#define toint(c)       ((c)-'0')
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+
+char *getenv (char *name);
+char *strstr (char *cs,char *ct);
+char *strerror (int n);
+void *memmove (void *s,void *ct,size_t n);
+unsigned long strtoul (char *s,char **endp,int base);
+void *malloc (size_t byteSize);
+void free (void *ptr);
+void *realloc (void *oldptr,size_t newsize);
+u_long portable_inet_addr (char *hostname);
+
+#include "env_unix.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/phile.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,553 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	File routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	25 August 1993
+ * Last Edited:	9 May 2006
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <signal.h>
+#include "mail.h"
+#include "osdep.h"
+#include <pwd.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "rfc822.h"
+#include "misc.h"
+#include "dummy.h"
+
+/* Types returned from phile_type() */
+
+#define PTYPEBINARY 0		/* binary data */
+#define PTYPETEXT 1		/* textual data */
+#define PTYPECRTEXT 2		/* textual data with CR */
+#define PTYPE8 4		/* textual 8bit data */
+#define PTYPEISO2022JP 8	/* textual Japanese */
+#define PTYPEISO2022KR 16	/* textual Korean */
+#define PTYPEISO2022CN 32	/* textual Chinese */
+
+
+/* PHILE I/O stream local data */
+	
+typedef struct phile_local {
+  ENVELOPE *env;		/* file envelope */
+  BODY *body;			/* file body */
+  char tmp[MAILTMPLEN];		/* temporary buffer */
+} PHILELOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((PHILELOCAL *) stream->local)
+
+
+/* Function prototypes */
+
+DRIVER *phile_valid (char *name);
+int phile_isvalid (char *name,char *tmp);
+void *phile_parameters (long function,void *value);
+void phile_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void phile_list (MAILSTREAM *stream,char *ref,char *pat);
+void phile_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long phile_create (MAILSTREAM *stream,char *mailbox);
+long phile_delete (MAILSTREAM *stream,char *mailbox);
+long phile_rename (MAILSTREAM *stream,char *old,char *newname);
+long phile_status (MAILSTREAM *stream,char *mbx,long flags);
+MAILSTREAM *phile_open (MAILSTREAM *stream);
+int phile_type (unsigned char *s,unsigned long i,unsigned long *j);
+void phile_close (MAILSTREAM *stream,long options);
+ENVELOPE *phile_structure (MAILSTREAM *stream,unsigned long msgno,BODY **body,
+			   long flags);
+char *phile_header (MAILSTREAM *stream,unsigned long msgno,
+		    unsigned long *length,long flags);
+long phile_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+long phile_ping (MAILSTREAM *stream);
+void phile_check (MAILSTREAM *stream);
+long phile_expunge (MAILSTREAM *stream,char *sequence,long options);
+long phile_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long phile_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+/* File routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER philedriver = {
+  "phile",			/* driver name */
+				/* driver flags */
+  DR_LOCAL|DR_READONLY|DR_NOSTICKY,
+  (DRIVER *) NIL,		/* next driver */
+  phile_valid,			/* mailbox is valid for us */
+  phile_parameters,		/* manipulate parameters */
+  phile_scan,			/* scan mailboxes */
+  phile_list,			/* list mailboxes */
+  phile_lsub,			/* list subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  dummy_create,			/* create mailbox */
+  dummy_delete,			/* delete mailbox */
+  dummy_rename,			/* rename mailbox */
+  phile_status,			/* status of mailbox */
+  phile_open,			/* open mailbox */
+  phile_close,			/* close mailbox */
+  NIL,				/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  phile_structure,		/* fetch message envelopes */
+  phile_header,			/* fetch message header only */
+  phile_text,			/* fetch message body only */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  NIL,				/* modify flags */
+  NIL,				/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  phile_ping,			/* ping mailbox to see if still alive */
+  phile_check,			/* check for new messages */
+  phile_expunge,		/* expunge deleted messages */
+  phile_copy,			/* copy messages to another mailbox */
+  phile_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM phileproto = {&philedriver};
+
+/* File validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *phile_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+  return phile_isvalid (name,tmp) ? &philedriver : NIL;
+}
+
+
+/* File test for valid mailbox
+ * Accepts: mailbox name
+ * Returns: T if valid, NIL otherwise
+ */
+
+int phile_isvalid (char *name,char *tmp)
+{
+  struct stat sbuf;
+  char *s;
+				/* INBOX never accepted, any other name is */
+  return ((s = mailboxfile (tmp,name)) && *s && !stat (s,&sbuf) &&
+	  !(sbuf.st_mode & S_IFDIR) &&
+				/* only allow empty files if no empty proto
+				   or if #ftp */
+	  (sbuf.st_size || !default_proto (T) ||
+	   ((*name == '#') && ((name[1] == 'f') || (name[1] == 'F')) &&
+	    ((name[2] == 't') || (name[2] == 'T')) &&
+	    ((name[3] == 'p') || (name[3] == 'P')) && (name[4] == '/'))));
+}
+
+/* File manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *phile_parameters (long function,void *value)
+{
+  return NIL;
+}
+
+/* File mail scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void phile_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* File list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void phile_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_list (NIL,ref,pat);
+}
+
+
+/* File list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void phile_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_lsub (NIL,ref,pat);
+}
+
+
+/* File status
+ * Accepts: mail stream
+ *	    mailbox name
+ *	    status flags
+ * Returns: T on success, NIL on failure
+ */
+
+long phile_status (MAILSTREAM *stream,char *mbx,long flags)
+{
+  char *s,tmp[MAILTMPLEN];
+  MAILSTATUS status;
+  struct stat sbuf;
+  long ret = NIL;
+  if ((s = mailboxfile (tmp,mbx)) && *s && !stat (s,&sbuf)) {
+    status.flags = flags;	/* return status values */
+    status.unseen = (stream && mail_elt (stream,1)->seen) ? 0 : 1;
+    status.messages = status.recent = status.uidnext = 1;
+    status.uidvalidity = sbuf.st_mtime;
+				/* pass status to main program */
+    mm_status (stream,mbx,&status);
+    ret = LONGT;		/* success */
+  }
+  return ret;
+}
+
+/* File open
+ * Accepts: Stream to open
+ * Returns: Stream on success, NIL on failure
+ */
+
+MAILSTREAM *phile_open (MAILSTREAM *stream)
+{
+  int i,k,fd;
+  unsigned long j,m;
+  char *s,tmp[MAILTMPLEN];
+  struct passwd *pw;
+  struct stat sbuf;
+  struct tm *t;
+  MESSAGECACHE *elt;
+  SIZEDTEXT *buf;
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return &phileproto;
+  if (stream->local) fatal ("phile recycle stream");
+				/* open associated file */
+  if (!mailboxfile (tmp,stream->mailbox) || !tmp[0] || stat (tmp,&sbuf) ||
+      (fd = open (tmp,O_RDONLY,NIL)) < 0) {
+    sprintf (tmp,"Unable to open file %s",stream->mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+  fs_give ((void **) &stream->mailbox);
+  stream->mailbox = cpystr (tmp);
+  stream->local = fs_get (sizeof (PHILELOCAL));
+  mail_exists (stream,1);	/* make sure upper level knows */
+  mail_recent (stream,1);
+  elt = mail_elt (stream,1);	/* instantiate cache element */
+  elt->valid = elt->recent = T;	/* mark valid flags */
+  stream->sequence++;		/* bump sequence number */
+  stream->rdonly = T;		/* make sure upper level knows readonly */
+				/* instantiate a new envelope and body */
+  LOCAL->env = mail_newenvelope ();
+  LOCAL->body = mail_newbody ();
+
+  t = gmtime (&sbuf.st_mtime);	/* get UTC time and Julian day */
+  i = t->tm_hour * 60 + t->tm_min;
+  k = t->tm_yday;
+  t = localtime(&sbuf.st_mtime);/* get local time */
+				/* calculate time delta */
+  i = t->tm_hour * 60 + t->tm_min - i;
+  if (k = t->tm_yday - k) i += ((k < 0) == (abs (k) == 1)) ? -24*60 : 24*60;
+  k = abs (i);			/* time from UTC either way */
+  elt->hours = t->tm_hour; elt->minutes = t->tm_min; elt->seconds = t->tm_sec;
+  elt->day = t->tm_mday; elt->month = t->tm_mon + 1;
+  elt->year = t->tm_year - (BASEYEAR - 1900);
+  elt->zoccident = (k == i) ? 0 : 1;
+  elt->zhours = k/60;
+  elt->zminutes = k % 60;
+  sprintf (tmp,"%s, %d %s %d %02d:%02d:%02d %c%02d%02d",
+	   days[t->tm_wday],t->tm_mday,months[t->tm_mon],t->tm_year+1900,
+	   t->tm_hour,t->tm_min,t->tm_sec,elt->zoccident ? '-' : '+',
+	   elt->zhours,elt->zminutes);
+				/* set up Date field */
+  LOCAL->env->date = cpystr (tmp);
+
+				/* fill in From field from file owner */
+  LOCAL->env->from = mail_newaddr ();
+  if (pw = getpwuid (sbuf.st_uid)) strcpy (tmp,pw->pw_name);
+  else sprintf (tmp,"User-Number-%ld",(long) sbuf.st_uid);
+  LOCAL->env->from->mailbox = cpystr (tmp);
+  LOCAL->env->from->host = cpystr (mylocalhost ());
+				/* set subject to be mailbox name */
+  LOCAL->env->subject = cpystr (stream->mailbox);
+				/* slurp the data */
+  (buf = &elt->private.special.text)->size = sbuf.st_size;
+  read (fd,buf->data = (unsigned char *) fs_get (buf->size + 1),buf->size);
+  buf->data[buf->size] = '\0';
+  close (fd);			/* close the file */
+				/* analyze data type */
+  if (i = phile_type (buf->data,buf->size,&j)) {
+    LOCAL->body->type = TYPETEXT;
+    LOCAL->body->subtype = cpystr ("PLAIN");
+    if (!(i & PTYPECRTEXT)) {	/* change Internet newline format as needed */
+      s = (char *) buf->data;	/* make copy of UNIX-format string */
+      buf->data = NIL;		/* zap the buffer */
+      buf->size = strcrlfcpy (&buf->data,&m,s,buf->size);
+      fs_give ((void **) &s);	/* flush original UNIX-format string */
+    }
+    LOCAL->body->parameter = mail_newbody_parameter ();
+    LOCAL->body->parameter->attribute = cpystr ("charset");
+    LOCAL->body->parameter->value =
+      cpystr ((i & PTYPEISO2022JP) ? "ISO-2022-JP" :
+	      (i & PTYPEISO2022KR) ? "ISO-2022-KR" :
+	      (i & PTYPEISO2022CN) ? "ISO-2022-CN" :
+	      (i & PTYPE8) ? "X-UNKNOWN" : "US-ASCII");
+    LOCAL->body->encoding = (i & PTYPE8) ? ENC8BIT : ENC7BIT;
+    LOCAL->body->size.lines = j;
+  }
+  else {			/* binary data */
+    LOCAL->body->type = TYPEAPPLICATION;
+    LOCAL->body->subtype = cpystr ("OCTET-STREAM");
+    LOCAL->body->parameter = mail_newbody_parameter ();
+    LOCAL->body->parameter->attribute = cpystr ("name");
+    LOCAL->body->parameter->value =
+      cpystr ((s = (strrchr (stream->mailbox,'/'))) ? s+1 : stream->mailbox);
+    LOCAL->body->encoding = ENCBASE64;
+    buf->data = rfc822_binary (s = (char *) buf->data,buf->size,&buf->size);
+    fs_give ((void **) &s);	/* flush originary binary contents */
+  }
+  phile_header (stream,1,&j,NIL);
+  LOCAL->body->size.bytes = LOCAL->body->contents.text.size = buf->size;
+  elt->rfc822_size = j + buf->size;
+				/* only one message ever... */
+  stream->uid_validity = sbuf.st_mtime;
+  stream->uid_last = elt->private.uid = 1;
+  return stream;		/* return stream alive to caller */
+}
+
+/* File determine data type
+ * Accepts: data to examine
+ *	    size of data
+ *	    pointer to line count return
+ * Returns: PTYPE mask of data type
+ */
+
+int phile_type (unsigned char *s,unsigned long i,unsigned long *j)
+{
+  int ret = PTYPETEXT;
+  char *charvec = "bbbbbbbaaalaacaabbbbbbbbbbbebbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
+  *j = 0;			/* no lines */
+				/* check type of every character */
+  while (i--) switch (charvec[*s++]) {
+  case 'A':
+    ret |= PTYPE8;		/* 8bit character */
+    break;
+  case 'a':
+    break;			/* ASCII character */
+  case 'b':
+    return PTYPEBINARY;		/* binary byte seen, stop immediately */
+  case 'c':
+    ret |= PTYPECRTEXT;		/* CR indicates Internet text */
+    break;
+  case 'e':			/* ESC */
+    if (*s == '$') {		/* ISO-2022 sequence? */
+      switch (s[1]) {
+      case 'B': case '@': ret |= PTYPEISO2022JP; break;
+      case ')':
+	switch (s[2]) {
+	case 'A': case 'E': case 'G': ret |= PTYPEISO2022CN; break;
+	case 'C': ret |= PTYPEISO2022KR; break;
+	}
+      case '*':
+	switch (s[2]) {
+	case 'H': ret |= PTYPEISO2022CN; break;
+	}
+      case '+':
+	switch (s[2]) {
+	case 'I': case 'J': case 'K': case 'L': case 'M':
+	  ret |= PTYPEISO2022CN; break;
+	}
+      }
+    }
+    break;
+  case 'l':			/* newline */
+    (*j)++;
+    break;
+  }
+  return ret;			/* return type of data */
+}
+
+/* File close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void phile_close (MAILSTREAM *stream,long options)
+{
+  if (LOCAL) {			/* only if a file is open */
+    fs_give ((void **) &mail_elt (stream,1)->private.special.text.data);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+/* File fetch structure
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to return body
+ *	    option flags
+ * Returns: envelope of this message, body returned in body value
+ *
+ * Fetches the "fast" information as well
+ */
+
+ENVELOPE *phile_structure (MAILSTREAM *stream,unsigned long msgno,BODY **body,
+			   long flags)
+{
+  if (body) *body = LOCAL->body;
+  return LOCAL->env;		/* return the envelope */
+}
+
+
+/* File fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+char *phile_header (MAILSTREAM *stream,unsigned long msgno,
+		    unsigned long *length,long flags)
+{
+  rfc822_header (LOCAL->tmp,LOCAL->env,LOCAL->body);
+  *length = strlen (LOCAL->tmp);
+  return LOCAL->tmp;
+}
+
+
+/* File fetch message text (body only)
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned stringstruct
+ *	    option flags
+ * Returns: T, always
+ */
+
+long phile_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  SIZEDTEXT *buf = &mail_elt (stream,msgno)->private.special.text;
+  if (!(flags &FT_PEEK)) {	/* mark message as seen */
+    mail_elt (stream,msgno)->seen = T;
+    mm_flags (stream,msgno);
+  }
+  INIT (bs,mail_string,buf->data,buf->size);
+  return T;
+}
+
+/* File ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ * No-op for readonly files, since read/writer can expunge it from under us!
+ */
+
+long phile_ping (MAILSTREAM *stream)
+{
+  return T;
+}
+
+/* File check mailbox
+ * Accepts: MAIL stream
+ * No-op for readonly files, since read/writer can expunge it from under us!
+ */
+
+void phile_check (MAILSTREAM *stream)
+{
+  mm_log ("Check completed",NIL);
+}
+
+/* File expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T if success, NIL if failure
+ */
+
+long phile_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  if (!stream->silent) mm_log ("Expunge ignored on readonly mailbox",NIL);
+  return LONGT;
+}
+
+/* File copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if copy successful, else NIL
+ */
+
+long phile_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  char tmp[MAILTMPLEN];
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+  if (pc) return (*pc) (stream,sequence,mailbox,options);
+  sprintf (tmp,"Can't copy - file \"%s\" is not in valid mailbox format",
+	   stream->mailbox);
+  mm_log (tmp,ERROR);
+  return NIL;
+}
+
+
+/* File append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback function
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long phile_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  char tmp[MAILTMPLEN],file[MAILTMPLEN];
+  char *s = mailboxfile (file,mailbox);
+  if (s && *s) 
+    sprintf (tmp,"Can't append - not in valid mailbox format: %.80s",s);
+  else sprintf (tmp,"Can't append - invalid name: %.80s",mailbox);
+  mm_log (tmp,ERROR);
+  return NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/pmatch.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,89 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	IMAP Wildcard Matching Routines (case-dependent)
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	15 June 2000
+ * Last Edited:	30 August 2006
+ */
+
+/* Wildcard pattern match
+ * Accepts: base string
+ *	    pattern string
+ *	    delimiter character
+ * Returns: T if pattern matches base, else NIL
+ */
+
+long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim)
+{
+  switch (*pat) {
+  case '%':			/* non-recursive */
+				/* % at end, OK if no inferiors */
+    if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T;
+                                /* scan remainder of string until delimiter */
+    do if (pmatch_full (s,pat+1,delim)) return T;
+    while ((*s != delim) && *s++);
+    break;
+  case '*':			/* match 0 or more characters */
+    if (!pat[1]) return T;	/* * at end, unconditional match */
+				/* scan remainder of string */
+    do if (pmatch_full (s,pat+1,delim)) return T;
+    while (*s++);
+    break;
+  case '\0':			/* end of pattern */
+    return *s ? NIL : T;	/* success if also end of base */
+  default:			/* match this character */
+    return (*pat == *s) ? pmatch_full (s+1,pat+1,delim) : NIL;
+  }
+  return NIL;
+}
+
+/* Directory pattern match
+ * Accepts: base string
+ *	    pattern string
+ *	    delimiter character
+ * Returns: T if base is a matching directory of pattern, else NIL
+ */
+
+long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim)
+{
+  switch (*pat) {
+  case '%':			/* non-recursive */
+    if (!*s) return T;		/* end of base means have a subset match */
+    if (!*++pat) return NIL;	/* % at end, no inferiors permitted */
+				/* scan remainder of string until delimiter */
+    do if (dmatch (s,pat,delim)) return T;
+    while ((*s != delim) && *s++);
+    if (*s && !s[1]) return T;	/* ends with delimiter, must be subset */
+    return dmatch (s,pat,delim);/* do new scan */
+  case '*':			/* match 0 or more characters */
+    return T;			/* unconditional match */
+  case '\0':			/* end of pattern */
+    break;
+  default:			/* match this character */
+    if (*s) return (*pat == *s) ? dmatch (s+1,pat+1,delim) : NIL;
+				/* end of base, return if at delimiter */
+    else if (*pat == delim) return T;
+    break;
+  }
+  return NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/pseudo.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,36 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Pseudo Header Strings
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	26 September 1996
+ * Last Edited:	30 August 2006
+ */
+
+/* Local sites may wish to alter this text */
+
+char *pseudo_from = "MAILER-DAEMON";
+char *pseudo_name = "Mail System Internal Data";
+char *pseudo_subject = "DON'T DELETE THIS MESSAGE -- FOLDER INTERNAL DATA";
+char *pseudo_msg =
+  "This text is part of the internal format of your mail folder, and is not\na real message.  It is created automatically by the mail system software.\nIf deleted, important folder data will be lost, and it will be re-created\nwith the data reset to initial values."
+  ;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/pseudo.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,30 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Pseudo Header Strings
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	26 September 1996
+ * Last Edited:	30 August 2006
+ */
+
+
+extern char *pseudo_from,*pseudo_name,*pseudo_subject,*pseudo_msg;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/rename.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,44 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Rename file
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	20 May 1996
+ * Last Edited:	30 August 2006
+ */
+ 
+/* Emulator for working Unix rename() call
+ * Accepts: old file name
+ *	    new file name
+ * Returns: 0 if success, -1 if error with error in errno
+ */
+
+int Rename (char *oldname,char *newname)
+{
+  int ret;
+  unlink (newname);		/* make sure the old name doesn't exist */
+				/* link to new name, unlink old name */
+  if (!(ret = link (oldname,newname))) unlink (oldname);
+  return ret;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/scandir.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,81 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Scan directories
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	15 September 2006
+ */
+ 
+/* Emulator for BSD scandir() call
+ * Accepts: directory name
+ *	    destination pointer of names array
+ *	    selection function
+ *	    comparison function
+ * Returns: number of elements in the array or -1 if error
+ */
+
+int scandir (char *dirname,struct direct ***namelist,select_t select,
+	     compar_t compar)
+{
+  struct direct *p,*d,**names;
+  int nitems;
+  struct stat stb;
+  long nlmax;
+  DIR *dirp = opendir (dirname);/* open directory and get status poop */
+  if ((!dirp) || (fstat (dirp->dd_fd,&stb) < 0)) return -1;
+  nlmax = stb.st_size / 24;	/* guesstimate at number of files */
+  names = (struct direct **) fs_get (nlmax * sizeof (struct direct *));
+  nitems = 0;			/* initially none found */
+  while (d = readdir (dirp)) {	/* read directory item */
+				/* matches select criterion? */
+    if (select && !(*select) (d)) continue;
+				/* get size of direct record for this file */
+    p = (struct direct *) fs_get (DIR_SIZE (d));
+    p->d_ino = d->d_ino;	/* copy the poop */
+    strcpy (p->d_name,d->d_name);
+    if (++nitems >= nlmax) {	/* if out of space, try bigger guesstimate */
+      void *s = (void *) names;	/* stupid language */
+      nlmax *= 2;		/* double it */
+      fs_resize ((void **) &s,nlmax * sizeof (struct direct *));
+      names = (struct direct **) s;
+    }
+    names[nitems - 1] = p;	/* store this file there */
+  }
+  closedir (dirp);		/* done with directory */
+				/* sort if necessary */
+  if (nitems && compar) qsort (names,nitems,sizeof (struct direct *),compar);
+  *namelist = names;		/* return directory */
+  return nitems;		/* and size */
+}
+
+/* Alphabetic file name comparision
+ * Accepts: first candidate directory entry
+ *	    second candidate directory entry
+ * Returns: negative if d1 < d2, 0 if d1 == d2, postive if d1 > d2
+ */
+
+int alphasort (void *d1,void *d2)
+{
+  return strcmp ((*(struct direct **) d1)->d_name,
+		 (*(struct direct **) d2)->d_name);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/setpgrp.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,39 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Set process group emulator
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	3 May 1995
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Emulator for BSD setpgrp() call
+ * Accepts: process ID
+ *	    group ID
+ * Returns: 0 if successful, -1 if failure
+ */
+
+int Setpgrp (int pid,int gid)
+{
+  return setpgrp ();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/sig_bsd.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,40 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	BSD Signals
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	29 April 1997
+ * Last Edited:	30 August 2006
+ */
+ 
+#include <signal.h>
+
+/* Arm a signal
+ * Accepts: signal number
+ *	    desired action
+ * Returns: old action
+ */
+
+void *arm_signal (int sig,void *action)
+{
+  return (void *) signal (sig,action);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/sig_psx.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,51 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	POSIX Signals
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	29 April 1997
+ * Last Edited:	30 August 2006
+ */
+ 
+#include <signal.h>
+#include <string.h>
+
+#ifndef SA_RESTART
+#define SA_RESTART 0
+#endif
+
+/* Arm a signal
+ * Accepts: signal number
+ *	    desired action
+ * Returns: old action
+ */
+
+void *arm_signal (int sig,void *action)
+{
+  struct sigaction nact,oact;
+  memset (&nact,0,sizeof (struct sigaction));
+  sigemptyset (&nact.sa_mask);	/* no signals blocked */
+  nact.sa_handler = action;	/* set signal handler */
+  nact.sa_flags = SA_RESTART;	/* needed on Linux, nice on SVR4 */
+  sigaction (sig,&nact,&oact);	/* do the signal action */
+  return (void *) oact.sa_handler;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/sig_sv4.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,40 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	SVR4 Signals
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	29 April 1997
+ * Last Edited:	30 August 2006
+ */
+ 
+#include <signal.h>
+
+/* Arm a signal
+ * Accepts: signal number
+ *	    desired action
+ * Returns: old action
+ */
+
+void *arm_signal (int sig,void *action)
+{
+  return (void *) sigset (sig,action);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ssl_none.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,141 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Dummy (no SSL) authentication/encryption module
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	7 February 2001
+ * Last Edited:	30 August 2006
+ */
+
+/* Init server for SSL
+ * Accepts: server name
+ */
+
+void ssl_server_init (char *server)
+{
+  syslog (LOG_ERR,"This server does not support SSL");
+  exit (1);			/* punt this program too */
+}
+
+
+/* Start TLS
+ * Accepts: /etc/services service name
+ * Returns: cpystr'd error string if TLS failed, else NIL for success
+ */
+
+char *ssl_start_tls (char *server)
+{
+  return cpystr ("This server does not support TLS");
+}
+
+/* Get character
+ * Returns: character or EOF
+ */
+
+int PBIN (void)
+{
+  return getchar ();
+}
+
+
+/* Get string
+ * Accepts: destination string pointer
+ *	    number of bytes available
+ * Returns: destination string pointer or NIL if EOF
+ */
+
+char *PSIN (char *s,int n)
+{
+  return fgets (s,n,stdin);
+}
+
+
+/* Get record
+ * Accepts: destination string pointer
+ *	    number of bytes to read
+ * Returns: T if success, NIL otherwise
+ */
+
+long PSINR (char *s,unsigned long n)
+{
+  unsigned long i;
+  while (n && ((i = fread (s,1,n,stdin)) || (errno == EINTR))) s += i,n -= i;
+  return n ? NIL : LONGT;
+}
+
+
+/* Wait for input
+ * Accepts: timeout in seconds
+ * Returns: T if have input on stdin, else NIL
+ */
+
+long INWAIT (long seconds)
+{
+  return server_input_wait (seconds);
+}
+
+/* Put character
+ * Accepts: character
+ * Returns: character written or EOF
+ */
+
+int PBOUT (int c)
+{
+  return putchar (c);
+}
+
+
+/* Put string
+ * Accepts: source string pointer
+ * Returns: 0 or EOF if error
+ */
+
+int PSOUT (char *s)
+{
+  return fputs (s,stdout);
+}
+
+
+/* Put record
+ * Accepts: source sized text
+ * Returns: 0 or EOF if error
+ */
+
+int PSOUTR (SIZEDTEXT *s)
+{
+  unsigned char *t;
+  unsigned long i,j;
+  for (t = s->data,i = s->size;
+       (i && ((j = fwrite (t,1,i,stdout)) || (errno == EINTR)));
+       t += j,i -= j);
+  return i ? EOF : NIL;
+}
+
+
+/* Flush output
+ * Returns: 0 or EOF if error
+ */
+
+int PFLUSH (void)
+{
+  return fflush (stdout);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/ssl_unix.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,821 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	SSL authentication/encryption module
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	22 September 1998
+ * Last Edited:	13 January 2007
+ */
+
+#define crypt ssl_private_crypt
+#include <x509v3.h>
+#include <ssl.h>
+#include <err.h>
+#include <pem.h>
+#include <buffer.h>
+#include <bio.h>
+#include <crypto.h>
+#include <rand.h>
+#undef crypt
+
+#define SSLBUFLEN 8192
+#define SSLCIPHERLIST "ALL:!LOW"
+
+
+/* SSL I/O stream */
+
+typedef struct ssl_stream {
+  TCPSTREAM *tcpstream;		/* TCP stream */
+  SSL_CTX *context;		/* SSL context */
+  SSL *con;			/* SSL connection */
+  int ictr;			/* input counter */
+  char *iptr;			/* input pointer */
+  char ibuf[SSLBUFLEN];		/* input buffer */
+} SSLSTREAM;
+
+#include "sslio.h"
+
+/* Function prototypes */
+
+static SSLSTREAM *ssl_start(TCPSTREAM *tstream,char *host,unsigned long flags);
+static char *ssl_start_work (SSLSTREAM *stream,char *host,unsigned long flags);
+static int ssl_open_verify (int ok,X509_STORE_CTX *ctx);
+static char *ssl_validate_cert (X509 *cert,char *host);
+static long ssl_compare_hostnames (unsigned char *s,unsigned char *pat);
+static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size,
+			       long *contd);
+static long ssl_abort (SSLSTREAM *stream);
+static RSA *ssl_genkey (SSL *con,int export,int keylength);
+
+
+/* Secure Sockets Layer network driver dispatch */
+
+static struct ssl_driver ssldriver = {
+  ssl_open,			/* open connection */
+  ssl_aopen,			/* open preauthenticated connection */
+  ssl_getline,			/* get a line */
+  ssl_getbuffer,		/* get a buffer */
+  ssl_soutr,			/* output pushed data */
+  ssl_sout,			/* output string */
+  ssl_close,			/* close connection */
+  ssl_host,			/* return host name */
+  ssl_remotehost,		/* return remote host name */
+  ssl_port,			/* return port number */
+  ssl_localhost			/* return local host name */
+};
+				/* non-NIL if doing SSL primary I/O */
+static SSLSTDIOSTREAM *sslstdio = NIL;
+static char *start_tls = NIL;	/* non-NIL if start TLS requested */
+
+/* One-time SSL initialization */
+
+static int sslonceonly = 0;
+
+void ssl_onceonlyinit (void)
+{
+  if (!sslonceonly++) {		/* only need to call it once */
+    int fd;
+    char tmp[MAILTMPLEN];
+    struct stat sbuf;
+				/* if system doesn't have /dev/urandom */
+    if (stat ("/dev/urandom",&sbuf)) {
+      while ((fd = open (tmpnam (tmp),O_WRONLY|O_CREAT|O_EXCL,0600)) < 0)
+	sleep (1);
+      unlink (tmp);		/* don't need the file */
+      fstat (fd,&sbuf);		/* get information about the file */
+      close (fd);		/* flush descriptor */
+				/* not great but it'll have to do */
+      sprintf (tmp + strlen (tmp),"%.80s%lx%.80s%lx%lx%lx%lx%lx",
+	       tcp_serveraddr (),(unsigned long) tcp_serverport (),
+	       tcp_clientaddr (),(unsigned long) tcp_clientport (),
+	       (unsigned long) sbuf.st_ino,(unsigned long) time (0),
+	       (unsigned long) gethostid (),(unsigned long) getpid ());
+      RAND_seed (tmp,strlen (tmp));
+    }
+				/* apply runtime linkage */
+    mail_parameters (NIL,SET_SSLDRIVER,(void *) &ssldriver);
+    mail_parameters (NIL,SET_SSLSTART,(void *) ssl_start);
+    SSL_library_init ();	/* add all algorithms */
+  }
+}
+
+/* SSL open
+ * Accepts: host name
+ *	    contact service name
+ *	    contact port number
+ * Returns: SSL stream if success else NIL
+ */
+
+SSLSTREAM *ssl_open (char *host,char *service,unsigned long port)
+{
+  TCPSTREAM *stream = tcp_open (host,service,port);
+  return stream ? ssl_start (stream,host,port) : NIL;
+}
+
+
+/* SSL authenticated open
+ * Accepts: host name
+ *	    service name
+ *	    returned user name buffer
+ * Returns: SSL stream if success else NIL
+ */
+
+SSLSTREAM *ssl_aopen (NETMBX *mb,char *service,char *usrbuf)
+{
+  return NIL;			/* don't use this mechanism with SSL */
+}
+
+/* Start SSL/TLS negotiations
+ * Accepts: open TCP stream of session
+ *	    user's host name
+ *	    flags
+ * Returns: SSL stream if success else NIL
+ */
+
+static SSLSTREAM *ssl_start (TCPSTREAM *tstream,char *host,unsigned long flags)
+{
+  char *reason,tmp[MAILTMPLEN];
+  sslfailure_t sf = (sslfailure_t) mail_parameters (NIL,GET_SSLFAILURE,NIL);
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  void *data = (*bn) (BLOCK_SENSITIVE,NIL);
+  SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
+					    sizeof (SSLSTREAM));
+  stream->tcpstream = tstream;	/* bind TCP stream */
+				/* do the work */
+  reason = ssl_start_work (stream,host,flags);
+  (*bn) (BLOCK_NONSENSITIVE,data);
+  if (reason) {			/* failed? */
+    ssl_close (stream);		/* failed to do SSL */
+    stream = NIL;		/* no stream returned */
+    switch (*reason) {		/* analyze reason */
+    case '*':			/* certificate failure */
+      ++reason;			/* skip over certificate failure indication */
+				/* pass to error callback */
+      if (sf) (*sf) (host,reason,flags);
+      else {			/* no error callback, build error message */
+	sprintf (tmp,"Certificate failure for %.80s: %.512s",host,reason);
+	mm_log (tmp,ERROR);
+      }
+    case '\0':			/* user answered no to certificate callback */
+      if (flags & NET_TRYSSL)	/* return dummy stream to stop tryssl */
+	stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
+				       sizeof (SSLSTREAM));
+      break;
+    default:			/* non-certificate failure */
+      if (flags & NET_TRYSSL);	/* no error output if tryssl */
+				/* pass to error callback */
+      else if (sf) (*sf) (host,reason,flags);
+      else {			/* no error callback, build error message */
+	sprintf (tmp,"TLS/SSL failure for %.80s: %.512s",host,reason);
+	mm_log (tmp,ERROR);
+      }
+      break;
+    }
+  }
+  return stream;
+}
+
+/* Start SSL/TLS negotiations worker routine
+ * Accepts: SSL stream
+ *	    user's host name
+ *	    flags
+ * Returns: NIL if success, else error reason
+ */
+
+				/* evil but I had no choice */
+static char *ssl_last_error = NIL;
+static char *ssl_last_host = NIL;
+
+static char *ssl_start_work (SSLSTREAM *stream,char *host,unsigned long flags)
+{
+  BIO *bio;
+  X509 *cert;
+  unsigned long sl,tl;
+  char *s,*t,*err,tmp[MAILTMPLEN];
+  sslcertificatequery_t scq =
+    (sslcertificatequery_t) mail_parameters (NIL,GET_SSLCERTIFICATEQUERY,NIL);
+  sslclientcert_t scc =
+    (sslclientcert_t) mail_parameters (NIL,GET_SSLCLIENTCERT,NIL);
+  sslclientkey_t sck =
+    (sslclientkey_t) mail_parameters (NIL,GET_SSLCLIENTKEY,NIL);
+  if (ssl_last_error) fs_give ((void **) &ssl_last_error);
+  ssl_last_host = host;
+  if (!(stream->context = SSL_CTX_new ((flags & NET_TLSCLIENT) ?
+				       TLSv1_client_method () :
+				       SSLv23_client_method ())))
+    return "SSL context failed";
+  SSL_CTX_set_options (stream->context,0);
+				/* disable certificate validation? */
+  if (flags & NET_NOVALIDATECERT)
+    SSL_CTX_set_verify (stream->context,SSL_VERIFY_NONE,NIL);
+  else SSL_CTX_set_verify (stream->context,SSL_VERIFY_PEER,ssl_open_verify);
+				/* set default paths to CAs... */
+  SSL_CTX_set_default_verify_paths (stream->context);
+				/* ...unless a non-standard path desired */
+  if (s = (char *) mail_parameters (NIL,GET_SSLCAPATH,NIL))
+    SSL_CTX_load_verify_locations (stream->context,NIL,s);
+				/* want to send client certificate? */
+  if (scc && (s = (*scc) ()) && (sl = strlen (s))) {
+    if (cert = PEM_read_bio_X509 (bio = BIO_new_mem_buf (s,sl),NIL,NIL,NIL)) {
+      SSL_CTX_use_certificate (stream->context,cert);
+      X509_free (cert);
+    }
+    BIO_free (bio);
+    if (!cert) return "SSL client certificate failed";
+				/* want to supply private key? */
+    if ((t = (sck ? (*sck) () : s)) && (tl = strlen (t))) {
+      EVP_PKEY *key;
+      if (key = PEM_read_bio_PrivateKey (bio = BIO_new_mem_buf (t,tl),
+					 NIL,NIL,"")) {
+	SSL_CTX_use_PrivateKey (stream->context,key);
+	EVP_PKEY_free (key);
+      }
+      BIO_free (bio);
+      memset (t,0,tl);		/* erase key */
+    }
+    if (s != t) memset (s,0,sl);/* erase certificate if different from key */
+  }
+
+				/* create connection */
+  if (!(stream->con = (SSL *) SSL_new (stream->context)))
+    return "SSL connection failed";
+  bio = BIO_new_socket (stream->tcpstream->tcpsi,BIO_NOCLOSE);
+  SSL_set_bio (stream->con,bio,bio);
+  SSL_set_connect_state (stream->con);
+  if (SSL_in_init (stream->con)) SSL_total_renegotiations (stream->con);
+				/* now negotiate SSL */
+  if (SSL_write (stream->con,"",0) < 0)
+    return ssl_last_error ? ssl_last_error : "SSL negotiation failed";
+				/* need to validate host names? */
+  if (!(flags & NET_NOVALIDATECERT) &&
+      (err = ssl_validate_cert (cert = SSL_get_peer_certificate (stream->con),
+				host))) {
+				/* application callback */
+    if (scq) return (*scq) (err,host,cert ? cert->name : "???") ? NIL : "";
+				/* error message to return via mm_log() */
+    sprintf (tmp,"*%.128s: %.255s",err,cert ? cert->name : "???");
+    return ssl_last_error = cpystr (tmp);
+  }
+  return NIL;
+}
+
+/* SSL certificate verification callback
+ * Accepts: error flag
+ *	    X509 context
+ * Returns: error flag
+ */
+
+static int ssl_open_verify (int ok,X509_STORE_CTX *ctx)
+{
+  char *err,cert[256],tmp[MAILTMPLEN];
+  sslcertificatequery_t scq =
+    (sslcertificatequery_t) mail_parameters (NIL,GET_SSLCERTIFICATEQUERY,NIL);
+  if (!ok) {			/* in case failure */
+    err = (char *) X509_verify_cert_error_string
+      (X509_STORE_CTX_get_error (ctx));
+    X509_NAME_oneline (X509_get_subject_name
+		       (X509_STORE_CTX_get_current_cert (ctx)),cert,255);
+    if (!scq) {			/* mm_log() error message if no callback */
+      sprintf (tmp,"*%.128s: %.255s",err,cert);
+      ssl_last_error = cpystr (tmp);
+    }
+				/* ignore error if application says to */
+    else if ((*scq) (err,ssl_last_host,cert)) ok = T;
+				/* application wants punt */
+    else ssl_last_error = cpystr ("");
+  }
+  return ok;
+}
+
+
+/* SSL validate certificate
+ * Accepts: certificate
+ *	    host to validate against
+ * Returns: NIL if validated, else string of error message
+ */
+
+static char *ssl_validate_cert (X509 *cert,char *host)
+{
+  int i,n;
+  char *s,*t,*ret;
+  void *ext;
+  GENERAL_NAME *name;
+				/* make sure have a certificate */
+  if (!cert) ret = "No certificate from server";
+				/* and that it has a name */
+  else if (!cert->name) ret = "No name in certificate";
+				/* locate CN */
+  else if (s = strstr (cert->name,"/CN=")) {
+    if (t = strchr (s += 4,'/')) *t = '\0';
+				/* host name matches pattern? */
+    ret = ssl_compare_hostnames (host,s) ? NIL :
+      "Server name does not match certificate";
+    if (t) *t = '/';		/* restore smashed delimiter */
+				/* if mismatch, see if in extensions */
+    if (ret && (ext = X509_get_ext_d2i (cert,NID_subject_alt_name,NIL,NIL)) &&
+	(n = sk_GENERAL_NAME_num (ext)))
+      /* older versions of OpenSSL use "ia5" instead of dNSName */
+      for (i = 0; ret && (i < n); i++)
+	if ((name = sk_GENERAL_NAME_value (ext,i)) &&
+	    (name->type = GEN_DNS) && (s = name->d.ia5->data) &&
+	    ssl_compare_hostnames (host,s)) ret = NIL;
+  }
+  else ret = "Unable to locate common name in certificate";
+  return ret;
+}
+
+/* Case-independent wildcard pattern match
+ * Accepts: base string
+ *	    pattern string
+ * Returns: T if pattern matches base, else NIL
+ */
+
+static long ssl_compare_hostnames (unsigned char *s,unsigned char *pat)
+{
+  long ret = NIL;
+  switch (*pat) {
+  case '*':			/* wildcard */
+    if (pat[1]) {		/* there must be a pattern suffix */
+				/* there is, scan base against it */
+      do if (ssl_compare_hostnames (s,pat+1)) ret = LONGT;
+      while (!ret && (*s != '.') && *s++);
+    }
+    break;
+  case '\0':			/* end of pattern */
+    if (!*s) ret = LONGT;	/* success if base is also at end */
+    break;
+  default:			/* non-wildcard, recurse if match */
+    if (!compare_uchar (*pat,*s)) ret = ssl_compare_hostnames (s+1,pat+1);
+    break;
+  }
+  return ret;
+}
+
+/* SSL receive line
+ * Accepts: SSL stream
+ * Returns: text line string or NIL if failure
+ */
+
+char *ssl_getline (SSLSTREAM *stream)
+{
+  unsigned long n,contd;
+  char *ret = ssl_getline_work (stream,&n,&contd);
+  if (ret && contd) {		/* got a line needing continuation? */
+    STRINGLIST *stl = mail_newstringlist ();
+    STRINGLIST *stc = stl;
+    do {			/* collect additional lines */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+      stc = stc->next = mail_newstringlist ();
+      ret = ssl_getline_work (stream,&n,&contd);
+    } while (ret && contd);
+    if (ret) {			/* stash final part of line on list */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+				/* determine how large a buffer we need */
+      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
+      ret = fs_get (n + 1);	/* copy parts into buffer */
+      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
+	memcpy (ret + n,stc->text.data,stc->text.size);
+      ret[n] = '\0';
+    }
+    mail_free_stringlist (&stl);/* either way, done with list */
+  }
+  return ret;
+}
+
+/* SSL receive line or partial line
+ * Accepts: SSL stream
+ *	    pointer to return size
+ *	    pointer to return continuation flag
+ * Returns: text line string, size and continuation flag, or NIL if failure
+ */
+
+static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size,
+			       long *contd)
+{
+  unsigned long n;
+  char *s,*ret,c,d;
+  *contd = NIL;			/* assume no continuation */
+				/* make sure have data */
+  if (!ssl_getdata (stream)) return NIL;
+  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
+    d = *stream->iptr++;	/* slurp another character */
+    if ((c == '\015') && (d == '\012')) {
+      ret = (char *) fs_get (n--);
+      memcpy (ret,s,*size = n);	/* copy into a free storage string */
+      ret[n] = '\0';		/* tie off string with null */
+      return ret;
+    }
+  }
+				/* copy partial string from buffer */
+  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
+				/* get more data from the net */
+  if (!ssl_getdata (stream)) fs_give ((void **) &ret);
+				/* special case of newline broken by buffer */
+  else if ((c == '\015') && (*stream->iptr == '\012')) {
+    stream->iptr++;		/* eat the line feed */
+    stream->ictr--;
+    ret[*size = --n] = '\0';	/* tie off string with null */
+  }
+  else *contd = LONGT;		/* continuation needed */
+  return ret;
+}
+
+/* SSL receive buffer
+ * Accepts: SSL stream
+ *	    size in bytes
+ *	    buffer to read into
+ * Returns: T if success, NIL otherwise
+ */
+
+long ssl_getbuffer (SSLSTREAM *stream,unsigned long size,char *buffer)
+{
+  unsigned long n;
+  while (size > 0) {		/* until request satisfied */
+    if (!ssl_getdata (stream)) return NIL;
+    n = min (size,stream->ictr);/* number of bytes to transfer */
+				/* do the copy */
+    memcpy (buffer,stream->iptr,n);
+    buffer += n;		/* update pointer */
+    stream->iptr += n;
+    size -= n;			/* update # of bytes to do */
+    stream->ictr -= n;
+  }
+  buffer[0] = '\0';		/* tie off string */
+  return T;
+}
+
+/* SSL receive data
+ * Accepts: TCP/IP stream
+ * Returns: T if success, NIL otherwise
+ */
+
+long ssl_getdata (SSLSTREAM *stream)
+{
+  int i,sock;
+  fd_set fds,efds;
+  struct timeval tmo;
+  tcptimeout_t tmoh = (tcptimeout_t) mail_parameters (NIL,GET_TIMEOUT,NIL);
+  long ttmo_read = (long) mail_parameters (NIL,GET_READTIMEOUT,NIL);
+  time_t t = time (0);
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  if (!stream->con || ((sock = SSL_get_fd (stream->con)) < 0)) return NIL;
+				/* tcp_unix should have prevented this */
+  if (sock >= FD_SETSIZE) fatal ("unselectable socket in ssl_getdata()");
+  (*bn) (BLOCK_TCPREAD,NIL);
+  while (stream->ictr < 1) {	/* if nothing in the buffer */
+    time_t tl = time (0);	/* start of request */
+    time_t now = tl;
+    int ti = ttmo_read ? now + ttmo_read : 0;
+    if (SSL_pending (stream->con)) i = 1;
+    else {
+      if (tcpdebug) mm_log ("Reading SSL data",TCPDEBUG);
+      tmo.tv_usec = 0;
+      FD_ZERO (&fds);		/* initialize selection vector */
+      FD_ZERO (&efds);		/* handle errors too */
+      FD_SET (sock,&fds);	/* set bit in selection vector */
+      FD_SET (sock,&efds);	/* set bit in error selection vector */
+      errno = NIL;		/* block and read */
+      do {			/* block under timeout */
+	tmo.tv_sec = ti ? ti - now : 0;
+	i = select (sock+1,&fds,0,&efds,ti ? &tmo : 0);
+	now = time (0);		/* fake timeout if interrupt & time expired */
+	if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0;
+      } while ((i < 0) && (errno == EINTR));
+    }
+    if (i) {			/* non-timeout result from select? */
+      errno = 0;		/* just in case */
+      if (i > 0)		/* read what we can */
+	while (((i = SSL_read (stream->con,stream->ibuf,SSLBUFLEN)) < 0) &&
+	       ((errno == EINTR) ||
+		(SSL_get_error (stream->con,i) == SSL_ERROR_WANT_READ)));
+      if (i <= 0) {		/* error seen? */
+	if (tcpdebug) {
+	  char *s,tmp[MAILTMPLEN];
+	  if (i) sprintf (s = tmp,"SSL data read I/O error %d SSL error %d",
+			  errno,SSL_get_error (stream->con,i));
+	  else s = "SSL data read end of file";
+	  mm_log (s,TCPDEBUG);
+	}
+	return ssl_abort (stream);
+      }
+      stream->iptr = stream->ibuf;/* point at TCP buffer */
+      stream->ictr = i;		/* set new byte count */
+      if (tcpdebug) mm_log ("Successfully read SSL data",TCPDEBUG);
+    }
+				/* timeout, punt unless told not to */
+    else if (!tmoh || !(*tmoh) (now - t,now - tl)) {
+      if (tcpdebug) mm_log ("SSL data read timeout",TCPDEBUG);
+      return ssl_abort (stream);
+    }
+  }
+  (*bn) (BLOCK_NONE,NIL);
+  return T;
+}
+
+/* SSL send string as record
+ * Accepts: SSL stream
+ *	    string pointer
+ * Returns: T if success else NIL
+ */
+
+long ssl_soutr (SSLSTREAM *stream,char *string)
+{
+  return ssl_sout (stream,string,(unsigned long) strlen (string));
+}
+
+
+/* SSL send string
+ * Accepts: SSL stream
+ *	    string pointer
+ *	    byte count
+ * Returns: T if success else NIL
+ */
+
+long ssl_sout (SSLSTREAM *stream,char *string,unsigned long size)
+{
+  long i;
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  if (!stream->con) return NIL;
+  (*bn) (BLOCK_TCPWRITE,NIL);
+  if (tcpdebug) mm_log ("Writing to SSL",TCPDEBUG);
+				/* until request satisfied */
+  for (i = 0; size > 0; string += i,size -= i)
+				/* write as much as we can */
+    if ((i = SSL_write (stream->con,string,(int) min (SSLBUFLEN,size))) < 0) {
+      if (tcpdebug) {
+	char tmp[MAILTMPLEN];
+	sprintf (tmp,"SSL data write I/O error %d SSL error %d",
+		 errno,SSL_get_error (stream->con,i));
+	mm_log (tmp,TCPDEBUG);
+      }
+      return ssl_abort (stream);/* write failed */
+    }
+  if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG);
+  (*bn) (BLOCK_NONE,NIL);
+  return LONGT;			/* all done */
+}
+
+/* SSL close
+ * Accepts: SSL stream
+ */
+
+void ssl_close (SSLSTREAM *stream)
+{
+  ssl_abort (stream);		/* nuke the stream */
+  fs_give ((void **) &stream);	/* flush the stream */
+}
+
+
+/* SSL abort stream
+ * Accepts: SSL stream
+ * Returns: NIL always
+ */
+
+static long ssl_abort (SSLSTREAM *stream)
+{
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  if (stream->con) {		/* close SSL connection */
+    SSL_shutdown (stream->con);
+    SSL_free (stream->con);
+    stream->con = NIL;
+  }
+  if (stream->context) {	/* clean up context */
+    SSL_CTX_free (stream->context);
+    stream->context = NIL;
+  }
+  if (stream->tcpstream) {	/* close TCP stream */
+    tcp_close (stream->tcpstream);
+    stream->tcpstream = NIL;
+  }
+  (*bn) (BLOCK_NONE,NIL);
+  return NIL;
+}
+
+/* SSL get host name
+ * Accepts: SSL stream
+ * Returns: host name for this stream
+ */
+
+char *ssl_host (SSLSTREAM *stream)
+{
+  return tcp_host (stream->tcpstream);
+}
+
+
+/* SSL get remote host name
+ * Accepts: SSL stream
+ * Returns: host name for this stream
+ */
+
+char *ssl_remotehost (SSLSTREAM *stream)
+{
+  return tcp_remotehost (stream->tcpstream);
+}
+
+
+/* SSL return port for this stream
+ * Accepts: SSL stream
+ * Returns: port number for this stream
+ */
+
+unsigned long ssl_port (SSLSTREAM *stream)
+{
+  return tcp_port (stream->tcpstream);
+}
+
+
+/* SSL get local host name
+ * Accepts: SSL stream
+ * Returns: local host name
+ */
+
+char *ssl_localhost (SSLSTREAM *stream)
+{
+  return tcp_localhost (stream->tcpstream);
+}
+
+/* Start TLS
+ * Accepts: /etc/services service name
+ * Returns: cpystr'd error string if TLS failed, else NIL for success
+ */
+
+char *ssl_start_tls (char *server)
+{
+  char tmp[MAILTMPLEN];
+  struct stat sbuf;
+  if (sslstdio) return cpystr ("Already in an SSL session");
+  if (start_tls) return cpystr ("TLS already started");
+  if (server) {			/* build specific certificate/key file name */
+    sprintf (tmp,"%s/%s-%s.pem",SSL_CERT_DIRECTORY,server,tcp_serveraddr ());
+    if (stat (tmp,&sbuf)) {	/* use non-specific name if no specific file */
+      sprintf (tmp,"%s/%s.pem",SSL_CERT_DIRECTORY,server);
+      if (stat (tmp,&sbuf)) return cpystr ("Server certificate not installed");
+    }
+    start_tls = server;		/* switch to STARTTLS mode */
+  }
+  return NIL;
+}
+
+/* Init server for SSL
+ * Accepts: server name
+ */
+
+void ssl_server_init (char *server)
+{
+  char cert[MAILTMPLEN],key[MAILTMPLEN];
+  unsigned long i;
+  struct stat sbuf;
+  SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
+					    sizeof (SSLSTREAM));
+  ssl_onceonlyinit ();		/* make sure algorithms added */
+  ERR_load_crypto_strings ();
+  SSL_load_error_strings ();
+				/* build specific certificate/key file names */
+  sprintf (cert,"%s/%s-%s.pem",SSL_CERT_DIRECTORY,server,tcp_serveraddr ());
+  sprintf (key,"%s/%s-%s.pem",SSL_KEY_DIRECTORY,server,tcp_serveraddr ());
+				/* use non-specific name if no specific cert */
+  if (stat (cert,&sbuf)) sprintf (cert,"%s/%s.pem",SSL_CERT_DIRECTORY,server);
+  if (stat (key,&sbuf)) {	/* use non-specific name if no specific key */
+    sprintf (key,"%s/%s.pem",SSL_KEY_DIRECTORY,server);
+				/* use cert file as fallback for key */
+    if (stat (key,&sbuf)) strcpy (key,cert);
+  }
+				/* create context */
+  if (!(stream->context = SSL_CTX_new (start_tls ?
+				       TLSv1_server_method () :
+				       SSLv23_server_method ())))
+    syslog (LOG_ALERT,"Unable to create SSL context, host=%.80s",
+	    tcp_clienthost ());
+  else {			/* set context options */
+    SSL_CTX_set_options (stream->context,SSL_OP_ALL);
+				/* set cipher list */
+    if (!SSL_CTX_set_cipher_list (stream->context,SSLCIPHERLIST))
+      syslog (LOG_ALERT,"Unable to set cipher list %.80s, host=%.80s",
+	      SSLCIPHERLIST,tcp_clienthost ());
+				/* load certificate */
+    else if (!SSL_CTX_use_certificate_chain_file (stream->context,cert))
+      syslog (LOG_ALERT,"Unable to load certificate from %.80s, host=%.80s",
+	      cert,tcp_clienthost ());
+				/* load key */
+    else if (!(SSL_CTX_use_RSAPrivateKey_file (stream->context,key,
+					       SSL_FILETYPE_PEM)))
+      syslog (LOG_ALERT,"Unable to load private key from %.80s, host=%.80s",
+	      key,tcp_clienthost ());
+
+    else {			/* generate key if needed */
+      if (SSL_CTX_need_tmp_RSA (stream->context))
+	SSL_CTX_set_tmp_rsa_callback (stream->context,ssl_genkey);
+				/* create new SSL connection */
+      if (!(stream->con = SSL_new (stream->context)))
+	syslog (LOG_ALERT,"Unable to create SSL connection, host=%.80s",
+		tcp_clienthost ());
+      else {			/* set file descriptor */
+	SSL_set_fd (stream->con,0);
+				/* all OK if accepted */
+	if (SSL_accept (stream->con) < 0)
+	  syslog (LOG_INFO,"Unable to accept SSL connection, host=%.80s",
+		  tcp_clienthost ());
+	else {			/* server set up */
+	  sslstdio = (SSLSTDIOSTREAM *)
+	    memset (fs_get (sizeof(SSLSTDIOSTREAM)),0,sizeof (SSLSTDIOSTREAM));
+	  sslstdio->sslstream = stream;
+				/* available space in output buffer */
+	  sslstdio->octr = SSLBUFLEN;
+				/* current output buffer pointer */
+	  sslstdio->optr = sslstdio->obuf;
+				/* allow plaintext if disable value was 2 */
+	  if ((long) mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL) > 1)
+	    mail_parameters (NIL,SET_DISABLEPLAINTEXT,NIL);
+				/* unhide PLAIN SASL authenticator */
+	  mail_parameters (NIL,UNHIDE_AUTHENTICATOR,"PLAIN");
+	  mail_parameters (NIL,UNHIDE_AUTHENTICATOR,"LOGIN");
+	  return;
+	}
+      }
+    }  
+  }
+  while (i = ERR_get_error ())	/* SSL failure */
+    syslog (LOG_ERR,"SSL error status: %.80s",ERR_error_string (i,NIL));
+  ssl_close (stream);		/* punt stream */
+  exit (1);			/* punt this program too */
+}
+
+/* Generate one-time key for server
+ * Accepts: SSL connection
+ *	    export flag
+ *	    keylength
+ * Returns: generated key, always
+ */
+
+static RSA *ssl_genkey (SSL *con,int export,int keylength)
+{
+  unsigned long i;
+  static RSA *key = NIL;
+  if (!key) {			/* if don't have a key already */
+				/* generate key */
+    if (!(key = RSA_generate_key (export ? keylength : 1024,RSA_F4,NIL,NIL))) {
+      syslog (LOG_ALERT,"Unable to generate temp key, host=%.80s",
+	      tcp_clienthost ());
+      while (i = ERR_get_error ())
+	syslog (LOG_ALERT,"SSL error status: %s",ERR_error_string (i,NIL));
+      exit (1);
+    }
+  }
+  return key;
+}
+
+/* Wait for stdin input
+ * Accepts: timeout in seconds
+ * Returns: T if have input on stdin, else NIL
+ */
+
+long ssl_server_input_wait (long seconds)
+{
+  int i,sock;
+  fd_set fds,efd;
+  struct timeval tmo;
+  SSLSTREAM *stream;
+  if (!sslstdio) return server_input_wait (seconds);
+				/* input available in buffer */
+  if (((stream = sslstdio->sslstream)->ictr > 0) ||
+      !stream->con || ((sock = SSL_get_fd (stream->con)) < 0)) return LONGT;
+				/* sock ought to be 0 always */
+  if (sock >= FD_SETSIZE) fatal ("unselectable socket in ssl_getdata()");
+				/* input available from SSL */
+  if (SSL_pending (stream->con) &&
+      ((i = SSL_read (stream->con,stream->ibuf,SSLBUFLEN)) > 0)) {
+    stream->iptr = stream->ibuf;/* point at TCP buffer */
+    stream->ictr = i;		/* set new byte count */
+    return LONGT;
+  }
+  FD_ZERO (&fds);		/* initialize selection vector */
+  FD_ZERO (&efd);		/* initialize selection vector */
+  FD_SET (sock,&fds);		/* set bit in selection vector */
+  FD_SET (sock,&efd);		/* set bit in selection vector */
+  tmo.tv_sec = seconds; tmo.tv_usec = 0;
+				/* see if input available from the socket */
+  return select (sock+1,&fds,0,&efd,&tmo) ? LONGT : NIL;
+}
+
+#include "sslstdio.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/sslstdio.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,169 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	SSL standard I/O routines for server use
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	22 September 1998
+ * Last Edited:	30 August 2006
+ */
+
+/* Get character
+ * Returns: character or EOF
+ */
+
+int PBIN (void)
+{
+  if (!sslstdio) return getchar ();
+  if (!ssl_getdata (sslstdio->sslstream)) return EOF;
+				/* one last byte available */
+  sslstdio->sslstream->ictr--;
+  return (int) *(sslstdio->sslstream->iptr)++;
+}
+
+
+/* Get string
+ * Accepts: destination string pointer
+ *	    number of bytes available
+ * Returns: destination string pointer or NIL if EOF
+ */
+
+char *PSIN (char *s,int n)
+{
+  int i,c;
+  if (start_tls) {		/* doing a start TLS? */
+    ssl_server_init (start_tls);/* enter the mode */
+    start_tls = NIL;		/* don't do this again */
+  }
+  if (!sslstdio) return fgets (s,n,stdin);
+  for (i = c = 0, n-- ; (c != '\n') && (i < n); sslstdio->sslstream->ictr--) {
+    if ((sslstdio->sslstream->ictr <= 0) && !ssl_getdata (sslstdio->sslstream))
+      return NIL;		/* read error */
+    c = s[i++] = *(sslstdio->sslstream->iptr)++;
+  }
+  s[i] = '\0';			/* tie off string */
+  return s;
+}
+
+
+/* Get record
+ * Accepts: destination string pointer
+ *	    number of bytes to read
+ * Returns: T if success, NIL otherwise
+ */
+
+long PSINR (char *s,unsigned long n)
+{
+  unsigned long i;
+  if (start_tls) {		/* doing a start TLS? */
+    ssl_server_init (start_tls);/* enter the mode */
+    start_tls = NIL;		/* don't do this again */
+  }
+  if (sslstdio) return ssl_getbuffer (sslstdio->sslstream,n,s);
+				/* non-SSL case */
+  while (n && ((i = fread (s,1,n,stdin)) || (errno == EINTR))) s += i,n -= i;
+  return n ? NIL : LONGT;
+}
+
+
+/* Wait for stdin input
+ * Accepts: timeout in seconds
+ * Returns: T if have input on stdin, else NIL
+ */
+
+long INWAIT (long seconds)
+{
+  return (sslstdio ? ssl_server_input_wait : server_input_wait) (seconds);
+}
+
+/* Put character
+ * Accepts: character
+ * Returns: character written or EOF
+ */
+
+int PBOUT (int c)
+{
+  if (!sslstdio) return putchar (c);
+				/* flush buffer if full */
+  if (!sslstdio->octr && PFLUSH ()) return EOF;
+  sslstdio->octr--;		/* count down one character */
+  *sslstdio->optr++ = c;	/* write character */
+  return c;			/* return that character */
+}
+
+
+/* Put string
+ * Accepts: destination string pointer
+ * Returns: 0 or EOF if error
+ */
+
+int PSOUT (char *s)
+{
+  if (!sslstdio) return fputs (s,stdout);
+  while (*s) {			/* flush buffer if full */
+    if (!sslstdio->octr && PFLUSH ()) return EOF;
+    *sslstdio->optr++ = *s++;	/* write one more character */
+    sslstdio->octr--;		/* count down one character */
+  }
+  return 0;			/* success */
+}
+
+/* Put record
+ * Accepts: source sized text
+ * Returns: 0 or EOF if error
+ */
+
+int PSOUTR (SIZEDTEXT *s)
+{
+  unsigned char *t = s->data;
+  unsigned long i = s->size;
+  unsigned long j;
+  if (sslstdio) while (i) {	/* until request satisfied */
+				/* flush buffer if full */
+    if (!sslstdio->octr && PFLUSH ()) break;
+				/* blat as big a chucnk as we can */
+    memcpy (sslstdio->optr,t,j = min (i,sslstdio->octr));
+    sslstdio->optr += j;	/* account for chunk */
+    sslstdio->octr -= j;
+    t += j;
+    i -= j;
+  }
+  else while (i && ((j = fwrite (t,1,i,stdout)) || (errno == EINTR)))
+    t += j,i -= j;
+  return i ? EOF : NIL;
+}
+
+
+/* Flush output
+ * Returns: 0 or EOF if error
+ */
+
+int PFLUSH (void)
+{
+  if (!sslstdio) return fflush (stdout);
+				/* force out buffer */
+  if (!ssl_sout (sslstdio->sslstream,sslstdio->obuf,
+		 SSLBUFLEN - sslstdio->octr)) return EOF;
+				/* renew output buffer */
+  sslstdio->optr = sslstdio->obuf;
+  sslstdio->octr = SSLBUFLEN;
+  return 0;			/* success */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/strerror.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,37 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Error number to string
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+ 
+/* Return implementation-defined string corresponding to error
+ * Accepts: error number
+ * Returns: string for that error
+ */
+
+char *strerror (int n)
+{
+  return (n >= 0 && n < sys_nerr) ? sys_errlist[n] : NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/tcp_unix.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1043 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX TCP/IP routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	13 January 2008
+ */
+
+#include "ip_unix.c"
+
+#undef write			/* don't use redefined write() */
+ 
+static tcptimeout_t tmoh = NIL;	/* TCP timeout handler routine */
+static long ttmo_open = 0;	/* TCP timeouts, in seconds */
+static long ttmo_read = 0;
+static long ttmo_write = 0;
+static long rshtimeout = 15;	/* rsh timeout */
+static char *rshcommand = NIL;	/* rsh command */
+static char *rshpath = NIL;	/* rsh path */
+static long sshtimeout = 15;	/* ssh timeout */
+static char *sshcommand = NIL;	/* ssh command */
+static char *sshpath = NIL;	/* ssh path */
+static long allowreversedns = T;/* allow reverse DNS lookup */
+static long tcpdebug = NIL;	/* extra TCP debugging telemetry */
+static char *myClientAddr = NIL;/* client IP address */
+static char *myClientHost = NIL;/* client DNS name */
+static long myClientPort = -1;	/* client port number */
+static char *myServerAddr = NIL;/* server IP address */
+static char *myServerHost = NIL;/* server DNS name */
+static long myServerPort = -1;	/* server port number */
+
+extern long maxposint;		/* get this from write.c */
+
+/* Local function prototypes */
+
+int tcp_socket_open (int family,void *adr,size_t adrlen,unsigned short port,
+		     char *tmp,int *ctr,char *hst);
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+			       long *contd);
+long tcp_abort (TCPSTREAM *stream);
+char *tcp_name (struct sockaddr *sadr,long flag);
+char *tcp_name_valid (char *s);
+
+/* TCP/IP manipulate parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *tcp_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case SET_TIMEOUT:
+    tmoh = (tcptimeout_t) value;
+  case GET_TIMEOUT:
+    ret = (void *) tmoh;
+    break;
+  case SET_OPENTIMEOUT:
+    ttmo_open = (long) value;
+  case GET_OPENTIMEOUT:
+    ret = (void *) ttmo_open;
+    break;
+  case SET_READTIMEOUT:
+    ttmo_read = (long) value;
+  case GET_READTIMEOUT:
+    ret = (void *) ttmo_read;
+    break;
+  case SET_WRITETIMEOUT:
+    ttmo_write = (long) value;
+  case GET_WRITETIMEOUT:
+    ret = (void *) ttmo_write;
+    break;
+  case SET_ALLOWREVERSEDNS:
+    allowreversedns = (long) value;
+  case GET_ALLOWREVERSEDNS:
+    ret = (void *) allowreversedns;
+    break;
+  case SET_TCPDEBUG:
+    tcpdebug = (long) value;
+  case GET_TCPDEBUG:
+    ret = (void *) tcpdebug;
+    break;
+
+  case SET_RSHTIMEOUT:
+    rshtimeout = (long) value;
+  case GET_RSHTIMEOUT:
+    ret = (void *) rshtimeout;
+    break;
+  case SET_RSHCOMMAND:
+    if (rshcommand) fs_give ((void **) &rshcommand);
+    rshcommand = cpystr ((char *) value);
+  case GET_RSHCOMMAND:
+    ret = (void *) rshcommand;
+    break;
+  case SET_RSHPATH:
+    if (rshpath) fs_give ((void **) &rshpath);
+    rshpath = cpystr ((char *) value);
+  case GET_RSHPATH:
+    ret = (void *) rshpath;
+    break;
+  case SET_SSHTIMEOUT:
+    sshtimeout = (long) value;
+  case GET_SSHTIMEOUT:
+    ret = (void *) sshtimeout;
+    break;
+  case SET_SSHCOMMAND:
+    if (sshcommand) fs_give ((void **) &sshcommand);
+    sshcommand = cpystr ((char *) value);
+  case GET_SSHCOMMAND:
+    ret = (void *) sshcommand;
+    break;
+  case SET_SSHPATH:
+    if (sshpath) fs_give ((void **) &sshpath);
+    sshpath = cpystr ((char *) value);
+  case GET_SSHPATH:
+    ret = (void *) sshpath;
+    break;
+  }
+  return ret;
+}
+
+/* TCP/IP open
+ * Accepts: host name
+ *	    contact service name
+ *	    contact port number and optional silent flag
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
+{
+  TCPSTREAM *stream = NIL;
+  int family;
+  int sock = -1;
+  int ctr = 0;
+  int silent = (port & NET_SILENT) ? T : NIL;
+  int *ctrp = (port & NET_NOOPENTIMEOUT) ? NIL : &ctr;
+  char *s,*hostname,tmp[MAILTMPLEN];
+  void *adr;
+  size_t adrlen;
+  struct servent *sv = NIL;
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  void *data,*next;
+  port &= 0xffff;		/* erase flags */
+				/* lookup service */
+  if (service && (sv = getservbyname (service,"tcp")))
+    port = ntohs (sv->s_port);
+  /* The domain literal form is used (rather than simply the dotted decimal
+     as with other Unix programs) because it has to be a valid "host name"
+     in mailsystem terminology. */
+				/* look like domain literal? */
+  if (host[0] == '[' && host[(strlen (host))-1] == ']') {
+    strcpy (tmp,host+1);	/* yes, copy number part */
+    tmp[(strlen (tmp))-1] = '\0';
+    if (adr = ip_stringtoaddr (tmp,&adrlen,&family)) {
+      (*bn) (BLOCK_TCPOPEN,NIL);
+				/* get an open socket for this system */
+      sock = tcp_socket_open (family,adr,adrlen,port,tmp,ctrp,hostname = host);
+      (*bn) (BLOCK_NONE,NIL);
+      fs_give ((void **) &adr);
+    }
+    else sprintf (tmp,"Bad format domain-literal: %.80s",host);
+  }
+
+  else {			/* lookup host name */
+    if (tcpdebug) {
+      sprintf (tmp,"DNS resolution %.80s",host);
+      mm_log (tmp,TCPDEBUG);
+    }
+    (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */
+    data = (*bn) (BLOCK_SENSITIVE,NIL);
+    if (!(s = ip_nametoaddr (host,&adrlen,&family,&hostname,&next)))
+      sprintf (tmp,"No such host as %.80s",host);
+    (*bn) (BLOCK_NONSENSITIVE,data);
+    (*bn) (BLOCK_NONE,NIL);
+    if (s) {			/* DNS resolution won? */
+      if (tcpdebug) mm_log ("DNS resolution done",TCPDEBUG);
+      do {
+	(*bn) (BLOCK_TCPOPEN,NIL);
+	if (((sock = tcp_socket_open (family,s,adrlen,port,tmp,ctrp,
+				      hostname)) < 0) &&
+	    (s = ip_nametoaddr (NIL,&adrlen,&family,&hostname,&next)) &&
+	    !silent) mm_log (tmp,WARN);
+	(*bn) (BLOCK_NONE,NIL);
+      } while ((sock < 0) && s);/* repeat until success or no more addreses */
+    }
+  }
+  if (sock >= 0)  {		/* won */
+    stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0,
+				   sizeof (TCPSTREAM));
+    stream->port = port;	/* port number */
+				/* init sockets */
+    stream->tcpsi = stream->tcpso = sock;
+				/* stash in the snuck-in byte */
+    if (stream->ictr = ctr) *(stream->iptr = stream->ibuf) = tmp[0];
+				/* copy official host name */
+    stream->host = cpystr (hostname);
+    if (tcpdebug) mm_log ("Stream open and ready for read",TCPDEBUG);
+  }
+  else if (!silent) mm_log (tmp,ERROR);
+  return stream;		/* return success */
+}
+
+/* Open a TCP socket
+ * Accepts: protocol family
+ *	    address to connect to
+ *	    address length
+ *	    port
+ *	    scratch buffer
+ *	    pointer to "first byte read in" storage or NIL
+ *	    host name for error message
+ * Returns: socket if success, else -1 with error string in scratch buffer
+ */
+
+int tcp_socket_open (int family,void *adr,size_t adrlen,unsigned short port,
+		     char *tmp,int *ctr,char *hst)
+{
+  int i,ti,sock,flgs;
+  size_t len;
+  time_t now;
+  struct protoent *pt = getprotobyname ("tcp");
+  fd_set fds,efds;
+  struct timeval tmo;
+  struct sockaddr *sadr = ip_sockaddr (family,adr,adrlen,port,&len);
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+				/* fetid Solaris */
+  void *data = (*bn) (BLOCK_SENSITIVE,NIL);
+  sprintf (tmp,"Trying IP address [%s]",ip_sockaddrtostring (sadr));
+  mm_log (tmp,NIL);
+				/* make a socket */
+  if ((sock = socket (sadr->sa_family,SOCK_STREAM,pt ? pt->p_proto : 0)) < 0) {
+    sprintf (tmp,"Unable to create TCP socket: %s",strerror (errno));
+    (*bn) (BLOCK_NONSENSITIVE,data);
+  }
+  else if (sock >= FD_SETSIZE) {/* unselectable sockets are useless */
+    sprintf (tmp,"Unable to create selectable TCP socket (%d >= %d)",
+	     sock,FD_SETSIZE);
+    (*bn) (BLOCK_NONSENSITIVE,data);
+    close (sock);
+    sock = -1;
+    errno = EMFILE;
+  }
+
+  else {			/* get current socket flags */
+    flgs = fcntl (sock,F_GETFL,0);
+				/* set non-blocking if want open timeout */
+    if (ctr) fcntl (sock,F_SETFL,flgs | FNDELAY);
+				/* open connection */
+    while ((i = connect (sock,sadr,len)) < 0 && (errno == EINTR));
+    (*bn) (BLOCK_NONSENSITIVE,data);
+    if (i < 0) switch (errno) {	/* failed? */
+    case EAGAIN:		/* DG brain damage */
+    case EINPROGRESS:		/* what we expect to happen */
+    case EALREADY:		/* or another form of it */
+    case EISCONN:		/* restart after interrupt? */
+    case EADDRINUSE:		/* restart after interrupt? */
+      break;			/* well, not really, it was interrupted */
+    default:
+      sprintf (tmp,"Can't connect to %.80s,%u: %s",hst,(unsigned int) port,
+	       strerror (errno));
+      close (sock);		/* flush socket */
+      sock = -1;
+    }
+    if ((sock >= 0) && ctr) {	/* want open timeout? */
+      now = time (0);		/* open timeout */
+      ti = ttmo_open ? now + ttmo_open : 0;
+      tmo.tv_usec = 0;
+      FD_ZERO (&fds);		/* initialize selection vector */
+      FD_ZERO (&efds);		/* handle errors too */
+      FD_SET (sock,&fds);	/* block for error or readable */
+      FD_SET (sock,&efds);
+      do {			/* block under timeout */
+	tmo.tv_sec = ti ? ti - now : 0;
+	i = select (sock+1,&fds,NIL,&efds,ti ? &tmo : NIL);
+	now = time (0);		/* fake timeout if interrupt & time expired */
+	if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0;
+      } while ((i < 0) && (errno == EINTR));
+      if (i > 0) {		/* success, make sure really connected */
+				/* restore blocking status */
+	fcntl (sock,F_SETFL,flgs);
+	/* This used to be a zero-byte read(), but that crashes Solaris */
+				/* get socket status */
+	while (((i = *ctr = read (sock,tmp,1)) < 0) && (errno == EINTR));
+      }	
+      if (i <= 0) {		/* timeout or error? */
+	i = i ? errno : ETIMEDOUT;/* determine error code */
+	close (sock);		/* flush socket */
+	sock = -1;
+	errno = i;		/* return error code */
+	sprintf (tmp,"Connection failed to %.80s,%lu: %s",hst,
+		 (unsigned long) port,strerror (errno));
+      }
+    }
+  }
+  fs_give ((void **) &sadr);
+  return sock;			/* return the socket */
+}
+  
+/* TCP/IP authenticated open
+ * Accepts: host name
+ *	    service name
+ *	    returned user name buffer
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+#define MAXARGV 20
+
+TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
+{
+  TCPSTREAM *stream = NIL;
+  void *adr;
+  char host[MAILTMPLEN],tmp[MAILTMPLEN],*path,*argv[MAXARGV+1],*r;
+  int i,ti,pipei[2],pipeo[2];
+  size_t len;
+  time_t now;
+  struct timeval tmo;
+  fd_set fds,efds;
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+#ifdef SSHPATH			/* ssh path defined yet? */
+  if (!sshpath) sshpath = cpystr (SSHPATH);
+#endif
+#ifdef RSHPATH			/* rsh path defined yet? */
+  if (!rshpath) rshpath = cpystr (RSHPATH);
+#endif
+  if (*service == '*') {	/* want ssh? */
+				/* return immediately if ssh disabled */
+    if (!(sshpath && (ti = sshtimeout))) return NIL;
+				/* ssh command prototype defined yet? */
+    if (!sshcommand) sshcommand = cpystr ("%s %s -l %s exec /etc/r%sd");
+  }
+				/* want rsh? */
+  else if (rshpath && (ti = rshtimeout)) {
+				/* rsh command prototype defined yet? */
+    if (!rshcommand) rshcommand = cpystr ("%s %s -l %s exec /etc/r%sd");
+  }
+  else return NIL;		/* rsh disabled */
+				/* look like domain literal? */
+  if (mb->host[0] == '[' && mb->host[i = (strlen (mb->host))-1] == ']') {
+    strcpy (host,mb->host+1);	/* yes, copy without brackets */
+    host[i-1] = '\0';
+				/* validate domain literal */
+    if (adr = ip_stringtoaddr (host,&len,&i)) fs_give ((void **) &adr);
+    else {
+      sprintf (tmp,"Bad format domain-literal: %.80s",host);
+      mm_log (tmp,ERROR);
+      return NIL;
+    }
+  }
+  else strcpy (host,tcp_canonical (mb->host));
+
+  if (*service == '*')		/* build ssh command */
+    sprintf (tmp,sshcommand,sshpath,host,
+	     mb->user[0] ? mb->user : myusername (),service + 1);
+  else sprintf (tmp,rshcommand,rshpath,host,
+		mb->user[0] ? mb->user : myusername (),service);
+  if (tcpdebug) {
+    char msg[MAILTMPLEN];
+    sprintf (msg,"Trying %.100s",tmp);
+    mm_log (msg,TCPDEBUG);
+  }
+				/* parse command into argv */
+  for (i = 1,path = argv[0] = strtok_r (tmp," ",&r);
+       (i < MAXARGV) && (argv[i] = strtok_r (NIL," ",&r)); i++);
+  argv[i] = NIL;		/* make sure argv tied off */
+				/* make command pipes */
+  if (pipe (pipei) < 0) return NIL;
+  if ((pipei[0] >= FD_SETSIZE) || (pipei[1] >= FD_SETSIZE) ||
+      (pipe (pipeo) < 0)) {
+    close (pipei[0]); close (pipei[1]);
+    return NIL;
+  }
+  (*bn) (BLOCK_TCPOPEN,NIL);	/* quell alarm up here for NeXT */
+  if ((pipeo[0] >= FD_SETSIZE) || (pipeo[1] >= FD_SETSIZE) ||
+      ((i = fork ()) < 0)) {	/* make inferior process */
+    close (pipei[0]); close (pipei[1]);
+    close (pipeo[0]); close (pipeo[1]);
+    (*bn) (BLOCK_NONE,NIL);
+    return NIL;
+  }
+  if (!i) {			/* if child */
+    alarm (0);			/* never have alarms in children */
+    if (!fork ()) {		/* make grandchild so it's inherited by init */
+      int cf;			/* don't alter parent vars in case vfork() */
+      int maxfd = max (20,max (max(pipei[0],pipei[1]),max(pipeo[0],pipeo[1])));
+      dup2 (pipei[1],1);	/* parent's input is my output */
+      dup2 (pipei[1],2);	/* parent's input is my error output too */
+      dup2 (pipeo[0],0);	/* parent's output is my input */
+				/* close all unnecessary descriptors */
+      for (cf = 3; cf <= maxfd; cf++) close (cf);
+      setpgrp (0,getpid ());	/* be our own process group */
+      _exit (execv (path,argv));/* now run it */
+    }
+    _exit (1);			/* child is done */
+  }
+  grim_pid_reap (i,NIL);	/* reap child; grandchild now owned by init */
+  close (pipei[1]);		/* close child's side of the pipes */
+  close (pipeo[0]);
+
+				/* create TCP/IP stream */
+  stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0,
+				 sizeof (TCPSTREAM));
+				/* copy remote host name from argument */
+  stream->remotehost = cpystr (stream->host = cpystr (host));
+  stream->tcpsi = pipei[0];	/* init sockets */
+  stream->tcpso = pipeo[1];
+  stream->ictr = 0;		/* init input counter */
+  stream->port = 0xffffffff;	/* no port number */
+  ti += now = time (0);		/* open timeout */
+  tmo.tv_usec = 0;		/* initialize usec timeout */
+  FD_ZERO (&fds);		/* initialize selection vector */
+  FD_ZERO (&efds);		/* handle errors too */
+  FD_SET (stream->tcpsi,&fds);	/* set bit in selection vector */
+  FD_SET (stream->tcpsi,&efds);	/* set bit in error selection vector */
+  FD_SET (stream->tcpso,&efds);	/* set bit in error selection vector */
+  do {				/* block under timeout */
+    tmo.tv_sec = ti - now;
+    i = select (max (stream->tcpsi,stream->tcpso)+1,&fds,NIL,&efds,&tmo);
+    now = time (0);		/* fake timeout if interrupt & time expired */
+    if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0;
+  } while ((i < 0) && (errno == EINTR));
+  if (i <= 0) {			/* timeout or error? */
+    sprintf (tmp,i ? "error in %s to IMAP server" :
+	     "%s to IMAP server timed out",(*service == '*') ? "ssh" : "rsh");
+    mm_log (tmp,WARN);
+    tcp_close (stream);		/* punt stream */
+    stream = NIL;
+  }
+  (*bn) (BLOCK_NONE,NIL);
+				/* return user name */
+  strcpy (usrbuf,mb->user[0] ? mb->user : myusername ());
+  return stream;		/* return success */
+}
+
+/* TCP receive line
+ * Accepts: TCP stream
+ * Returns: text line string or NIL if failure
+ */
+
+char *tcp_getline (TCPSTREAM *stream)
+{
+  unsigned long n,contd;
+  char *ret = tcp_getline_work (stream,&n,&contd);
+  if (ret && contd) {		/* got a line needing continuation? */
+    STRINGLIST *stl = mail_newstringlist ();
+    STRINGLIST *stc = stl;
+    do {			/* collect additional lines */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+      stc = stc->next = mail_newstringlist ();
+      ret = tcp_getline_work (stream,&n,&contd);
+    } while (ret && contd);
+    if (ret) {			/* stash final part of line on list */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+				/* determine how large a buffer we need */
+      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
+      ret = fs_get (n + 1);	/* copy parts into buffer */
+      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
+	memcpy (ret + n,stc->text.data,stc->text.size);
+      ret[n] = '\0';
+    }
+    mail_free_stringlist (&stl);/* either way, done with list */
+  }
+  return ret;
+}
+
+/* TCP receive line or partial line
+ * Accepts: TCP stream
+ *	    pointer to return size
+ *	    pointer to return continuation flag
+ * Returns: text line string, size and continuation flag, or NIL if failure
+ */
+
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+			       long *contd)
+{
+  unsigned long n;
+  char *s,*ret,c,d;
+  *contd = NIL;			/* assume no continuation */
+				/* make sure have data */
+  if (!tcp_getdata (stream)) return NIL;
+  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
+    d = *stream->iptr++;	/* slurp another character */
+    if ((c == '\015') && (d == '\012')) {
+      ret = (char *) fs_get (n--);
+      memcpy (ret,s,*size = n);	/* copy into a free storage string */
+      ret[n] = '\0';		/* tie off string with null */
+      return ret;
+    }
+  }
+				/* copy partial string from buffer */
+  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
+				/* get more data from the net */
+  if (!tcp_getdata (stream)) fs_give ((void **) &ret);
+				/* special case of newline broken by buffer */
+  else if ((c == '\015') && (*stream->iptr == '\012')) {
+    stream->iptr++;		/* eat the line feed */
+    stream->ictr--;
+    ret[*size = --n] = '\0';	/* tie off string with null */
+  }
+  else *contd = LONGT;		/* continuation needed */
+  return ret;
+}
+
+/* TCP/IP receive buffer
+ * Accepts: TCP/IP stream
+ *	    size in bytes
+ *	    buffer to read into
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *s)
+{
+  unsigned long n;
+				/* make sure socket still alive */
+  if (stream->tcpsi < 0) return NIL;
+				/* can transfer bytes from buffer? */
+  if (n = min (size,stream->ictr)) {
+    memcpy (s,stream->iptr,n);	/* yes, slurp as much as we can from it */
+    s += n;			/* update pointer */
+    stream->iptr +=n;
+    size -= n;			/* update # of bytes to do */
+    stream->ictr -=n;
+  }
+  if (size) {
+    int i;
+    fd_set fds,efds;
+    struct timeval tmo;
+    time_t t = time (0);
+    blocknotify_t bn=(blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+    (*bn) (BLOCK_TCPREAD,NIL);
+    while (size > 0) {		/* until request satisfied */
+      time_t tl = time (0);
+      time_t now = tl;
+      time_t ti = ttmo_read ? now + ttmo_read : 0;
+      if (tcpdebug) mm_log ("Reading TCP buffer",TCPDEBUG);
+      tmo.tv_usec = 0;
+      FD_ZERO (&fds);		/* initialize selection vector */
+      FD_ZERO (&efds);		/* handle errors too */
+				/* set bit in selection vectors */
+      FD_SET (stream->tcpsi,&fds);
+      FD_SET (stream->tcpsi,&efds);
+      errno = NIL;		/* initially no error */
+      do {			/* block under timeout */
+	tmo.tv_sec = ti ? ti - now : 0;
+	i = select (stream->tcpsi+1,&fds,NIL,&efds,ti ? &tmo : NIL);
+	now = time (0);		/* fake timeout if interrupt & time expired */
+	if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0;
+      } while ((i < 0) && (errno == EINTR));
+      if (i) {			/* non-timeout result from select? */
+	if (i > 0)		/* read what we can */
+	  while (((i = read (stream->tcpsi,s,(int) min (maxposint,size))) < 0)
+		 && (errno == EINTR));
+	if (i <= 0) {		/* error seen? */
+	  if (tcpdebug) {
+	    char tmp[MAILTMPLEN];
+	    if (i) sprintf (s = tmp,"TCP buffer read I/O error %d",errno);
+	    else s = "TCP buffer read end of file";
+	    mm_log (s,TCPDEBUG);
+	  }
+	  return tcp_abort (stream);
+	}
+	s += i;			/* success, point at new place to write */
+	size -= i;		/* reduce byte count */
+	if (tcpdebug) mm_log ("Successfully read TCP buffer",TCPDEBUG);
+      }
+				/* timeout, punt unless told not to */
+      else if (!tmoh || !(*tmoh) (now - t,now - tl)) {
+	if (tcpdebug) mm_log ("TCP buffer read timeout",TCPDEBUG);
+	return tcp_abort (stream);
+      }
+    }
+    (*bn) (BLOCK_NONE,NIL);
+  }
+  *s = '\0';			/* tie off string */
+  return LONGT;
+}
+
+/* TCP/IP receive data
+ * Accepts: TCP/IP stream
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getdata (TCPSTREAM *stream)
+{
+  int i;
+  fd_set fds,efds;
+  struct timeval tmo;
+  time_t t = time (0);
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  if (stream->tcpsi < 0) return NIL;
+  (*bn) (BLOCK_TCPREAD,NIL);
+  while (stream->ictr < 1) {	/* if nothing in the buffer */
+    time_t tl = time (0);	/* start of request */
+    time_t now = tl;
+    time_t ti = ttmo_read ? now + ttmo_read : 0;
+    if (tcpdebug) mm_log ("Reading TCP data",TCPDEBUG);
+    tmo.tv_usec = 0;
+    FD_ZERO (&fds);		/* initialize selection vector */
+    FD_ZERO (&efds);		/* handle errors too */
+    FD_SET (stream->tcpsi,&fds);/* set bit in selection vectors */
+    FD_SET (stream->tcpsi,&efds);
+    errno = NIL;		/* initially no error */
+    do {			/* block under timeout */
+      tmo.tv_sec = ti ? ti - now : 0;
+      i = select (stream->tcpsi+1,&fds,NIL,&efds,ti ? &tmo : NIL);
+      now = time (0);		/* fake timeout if interrupt & time expired */
+      if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0;
+    } while ((i < 0) && (errno == EINTR));
+    if (i) {			/* non-timeout result from select? */
+				/* read what we can */
+      if (i > 0) while (((i = read (stream->tcpsi,stream->ibuf,BUFLEN)) < 0) &&
+			(errno == EINTR));
+      if (i <= 0) {		/* error seen? */
+	if (tcpdebug) {
+	  char *s,tmp[MAILTMPLEN];
+	  if (i) sprintf (s = tmp,"TCP data read I/O error %d",errno);
+	  else s = "TCP data read end of file";
+	  mm_log (s,TCPDEBUG);
+	}
+	return tcp_abort (stream);
+      }
+      stream->ictr = i;		/* success, set new count and pointer */
+      stream->iptr = stream->ibuf;
+      if (tcpdebug) mm_log ("Successfully read TCP data",TCPDEBUG);
+    }
+				/* timeout, punt unless told not to */
+    else if (!tmoh || !(*tmoh) (now - t,now - tl)) {
+      if (tcpdebug) mm_log ("TCP data read timeout",TCPDEBUG);
+      return tcp_abort (stream);/* error or timeout no-continue */
+    }
+  }
+  (*bn) (BLOCK_NONE,NIL);
+  return T;
+}
+
+/* TCP/IP send string as record
+ * Accepts: TCP/IP stream
+ *	    string pointer
+ * Returns: T if success else NIL
+ */
+
+long tcp_soutr (TCPSTREAM *stream,char *string)
+{
+  return tcp_sout (stream,string,(unsigned long) strlen (string));
+}
+
+
+/* TCP/IP send string
+ * Accepts: TCP/IP stream
+ *	    string pointer
+ *	    byte count
+ * Returns: T if success else NIL
+ */
+
+long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
+{
+  int i;
+  fd_set fds,efds;
+  struct timeval tmo;
+  time_t t = time (0);
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  if (stream->tcpso < 0) return NIL;
+  (*bn) (BLOCK_TCPWRITE,NIL);
+  while (size > 0) {		/* until request satisfied */
+    time_t tl = time (0);	/* start of request */
+    time_t now = tl;
+    time_t ti = ttmo_write ? now + ttmo_write : 0;
+    if (tcpdebug) mm_log ("Writing to TCP",TCPDEBUG);
+    tmo.tv_usec = 0;
+    FD_ZERO (&fds);		/* initialize selection vector */
+    FD_ZERO (&efds);		/* handle errors too */
+    FD_SET (stream->tcpso,&fds);/* set bit in selection vector */
+    FD_SET(stream->tcpso,&efds);/* set bit in error selection vector */
+    errno = NIL;		/* block and write */
+    do {			/* block under timeout */
+      tmo.tv_sec = ti ? ti - now : 0;
+      i = select (stream->tcpso+1,NIL,&fds,&efds,ti ? &tmo : NIL);
+      now = time (0);		/* fake timeout if interrupt & time expired */
+      if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0;
+    } while ((i < 0) && (errno == EINTR));
+    if (i) {			/* non-timeout result from select? */
+				/* write what we can */
+      if (i > 0) while (((i = write (stream->tcpso,string,size)) < 0) &&
+			(errno == EINTR));
+      if (i <= 0) {		/* error seen? */
+	if (tcpdebug) {
+	  char tmp[MAILTMPLEN];
+	  sprintf (tmp,"TCP write I/O error %d",errno);
+	  mm_log (tmp,TCPDEBUG);
+	}
+	return tcp_abort (stream);
+      }
+      string += i;		/* how much we sent */
+      size -= i;		/* count this size */
+      if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG);
+    }
+				/* timeout, punt unless told not to */
+    else if (!tmoh || !(*tmoh) (now - t,now - tl)) {
+      if (tcpdebug) mm_log ("TCP write timeout",TCPDEBUG);
+      return tcp_abort (stream);
+    }
+  }
+  (*bn) (BLOCK_NONE,NIL);
+  return T;			/* all done */
+}
+
+/* TCP/IP close
+ * Accepts: TCP/IP stream
+ */
+
+void tcp_close (TCPSTREAM *stream)
+{
+  tcp_abort (stream);		/* nuke the stream */
+				/* flush host names */
+  if (stream->host) fs_give ((void **) &stream->host);
+  if (stream->remotehost) fs_give ((void **) &stream->remotehost);
+  if (stream->localhost) fs_give ((void **) &stream->localhost);
+  fs_give ((void **) &stream);	/* flush the stream */
+}
+
+
+/* TCP/IP abort stream
+ * Accepts: TCP/IP stream
+ * Returns: NIL always
+ */
+
+long tcp_abort (TCPSTREAM *stream)
+{
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  if (stream->tcpsi >= 0) {	/* no-op if no socket */
+    (*bn) (BLOCK_TCPCLOSE,NIL);
+    close (stream->tcpsi);	/* nuke the socket */
+    if (stream->tcpsi != stream->tcpso) close (stream->tcpso);
+    stream->tcpsi = stream->tcpso = -1;
+  }
+  (*bn) (BLOCK_NONE,NIL);
+  return NIL;
+}
+
+/* TCP/IP get host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_host (TCPSTREAM *stream)
+{
+  return stream->host;		/* use tcp_remotehost() if want guarantees */
+}
+
+
+/* TCP/IP get remote host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_remotehost (TCPSTREAM *stream)
+{
+  if (!stream->remotehost) {
+    size_t sadrlen;
+    struct sockaddr *sadr = ip_newsockaddr (&sadrlen);
+    stream->remotehost =	/* get socket's peer name */
+      getpeername (stream->tcpsi,sadr,(void *) &sadrlen) ?
+        cpystr (stream->host) : tcp_name (sadr,NIL);
+    fs_give ((void **) &sadr);
+  }
+  return stream->remotehost;
+}
+
+
+/* TCP/IP return port for this stream
+ * Accepts: TCP/IP stream
+ * Returns: port number for this stream
+ */
+
+unsigned long tcp_port (TCPSTREAM *stream)
+{
+  return stream->port;		/* return port number */
+}
+
+
+/* TCP/IP get local host name
+ * Accepts: TCP/IP stream
+ * Returns: local host name
+ */
+
+char *tcp_localhost (TCPSTREAM *stream)
+{
+  if (!stream->localhost) {
+    size_t sadrlen;
+    struct sockaddr *sadr = ip_newsockaddr (&sadrlen);
+    stream->localhost =		/* get socket's name */
+      ((stream->port & 0xffff000) ||
+       getsockname (stream->tcpsi,sadr,(void *) &sadrlen)) ?
+      cpystr (mylocalhost ()) : tcp_name (sadr,NIL);
+    fs_give ((void **) &sadr);
+  }
+  return stream->localhost;	/* return local host name */
+}
+
+/* TCP/IP get client host address (server calls only)
+ * Returns: client host address
+ */
+
+char *tcp_clientaddr ()
+{
+  if (!myClientAddr) {
+    size_t sadrlen;
+    struct sockaddr *sadr = ip_newsockaddr (&sadrlen);
+    if (getpeername (0,sadr,(void *) &sadrlen))
+      myClientAddr = cpystr ("UNKNOWN");
+    else {			/* get stdin's peer name */
+      myClientAddr = cpystr (ip_sockaddrtostring (sadr));
+      if (myClientPort < 0) myClientPort = ip_sockaddrtoport (sadr);
+    }
+    fs_give ((void **) &sadr);
+  }
+  return myClientAddr;
+}
+
+
+/* TCP/IP get client host name (server calls only)
+ * Returns: client host name
+ */
+
+char *tcp_clienthost ()
+{
+  if (!myClientHost) {
+    size_t sadrlen;
+    struct sockaddr *sadr = ip_newsockaddr (&sadrlen);
+    if (getpeername (0,sadr,(void *) &sadrlen)) {
+      char *s,*t,*v,tmp[MAILTMPLEN];
+      if ((s = getenv (t = "SSH_CLIENT")) ||
+	  (s = getenv (t = "KRB5REMOTEADDR")) ||
+	  (s = getenv (t = "SSH2_CLIENT"))) {
+	if (v = strchr (s,' ')) *v = '\0';
+	sprintf (v = tmp,"%.80s=%.80s",t,s);
+      }
+      else v = "UNKNOWN";
+      myClientHost = cpystr (v);
+    }
+    else {			/* get stdin's peer name */
+      myClientHost = tcp_name (sadr,T);
+      if (!myClientAddr) myClientAddr = cpystr (ip_sockaddrtostring (sadr));
+      if (myClientPort < 0) myClientPort = ip_sockaddrtoport (sadr);
+    }
+    fs_give ((void **) &sadr);
+  }
+  return myClientHost;
+}
+
+
+/* TCP/IP get client port number (server calls only)
+ * Returns: client port number
+ */
+
+long tcp_clientport ()
+{
+  if (!myClientHost && !myClientAddr) tcp_clientaddr ();
+  return myClientPort;
+}
+
+/* TCP/IP get server host address (server calls only)
+ * Returns: server host address
+ */
+
+char *tcp_serveraddr ()
+{
+  if (!myServerAddr) {
+    size_t sadrlen;
+    struct sockaddr *sadr = ip_newsockaddr (&sadrlen);
+    if (getsockname (0,sadr,(void *) &sadrlen))
+      myServerAddr = cpystr ("UNKNOWN");
+    else {			/* get stdin's name */
+      myServerAddr = cpystr (ip_sockaddrtostring (sadr));
+      if (myServerPort < 0) myServerPort = ip_sockaddrtoport (sadr);
+    }
+    fs_give ((void **) &sadr);
+  }
+  return myServerAddr;
+}
+
+
+/* TCP/IP get server host name (server calls only)
+ * Returns: server host name
+ */
+
+char *tcp_serverhost ()
+{
+  if (!myServerHost) {		/* once-only */
+    size_t sadrlen;
+    struct sockaddr *sadr = ip_newsockaddr (&sadrlen);
+				/* get stdin's name */
+    if (getsockname (0,sadr,(void *) &sadrlen))
+      myServerHost = cpystr (mylocalhost ());
+    else {			/* get stdin's name */
+      myServerHost = tcp_name (sadr,NIL);
+      if (!myServerAddr) myServerAddr = cpystr (ip_sockaddrtostring (sadr));
+      if (myServerPort < 0) myServerPort = ip_sockaddrtoport (sadr);
+    }
+    fs_give ((void **) &sadr);
+  }
+  return myServerHost;
+}
+
+
+/* TCP/IP get server port number (server calls only)
+ * Returns: server port number
+ */
+
+long tcp_serverport ()
+{
+  if (!myServerHost && !myServerAddr) tcp_serveraddr ();
+  return myServerPort;
+}
+
+/* TCP/IP return canonical form of host name
+ * Accepts: host name
+ * Returns: canonical form of host name
+ */
+
+char *tcp_canonical (char *name)
+{
+  char *ret,host[MAILTMPLEN];
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  void *data;
+				/* look like domain literal? */
+  if (name[0] == '[' && name[strlen (name) - 1] == ']') return name;
+  (*bn) (BLOCK_DNSLOOKUP,NIL);	/* quell alarms */
+  data = (*bn) (BLOCK_SENSITIVE,NIL);
+  if (tcpdebug) {
+    sprintf (host,"DNS canonicalization %.80s",name);
+    mm_log (host,TCPDEBUG);
+  }
+				/* get canonical name */
+  if (!ip_nametoaddr (name,NIL,NIL,&ret,NIL)) ret = name;
+  (*bn) (BLOCK_NONSENSITIVE,data);
+  (*bn) (BLOCK_NONE,NIL);	/* alarms OK now */
+  if (tcpdebug) mm_log ("DNS canonicalization done",TCPDEBUG);
+  return ret;
+}
+
+/* TCP/IP return name from socket
+ * Accepts: socket
+ *	    verbose flag
+ * Returns: cpystr name
+ */
+
+char *tcp_name (struct sockaddr *sadr,long flag)
+{
+  char *ret,*t,adr[MAILTMPLEN],tmp[MAILTMPLEN];
+  sprintf (ret = adr,"[%.80s]",ip_sockaddrtostring (sadr));
+  if (allowreversedns) {
+    blocknotify_t bn = (blocknotify_t)mail_parameters(NIL,GET_BLOCKNOTIFY,NIL);
+    void *data;
+    if (tcpdebug) {
+      sprintf (tmp,"Reverse DNS resolution %s",adr);
+      mm_log (tmp,TCPDEBUG);
+    }
+    (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */
+    data = (*bn) (BLOCK_SENSITIVE,NIL);
+				/* translate address to name */
+    if (t = tcp_name_valid (ip_sockaddrtoname (sadr))) {
+				/* produce verbose form if needed */
+      if (flag)	sprintf (ret = tmp,"%s %s",t,adr);
+      else ret = t;
+    }
+    (*bn) (BLOCK_NONSENSITIVE,data);
+    (*bn) (BLOCK_NONE,NIL);	/* alarms OK now */
+    if (tcpdebug) mm_log ("Reverse DNS resolution done",TCPDEBUG);
+  }
+  return cpystr (ret);
+}
+
+
+/* TCP/IP validate name
+ * Accepts: domain name
+ * Returns: name if valid, NIL otherwise
+ */
+
+char *tcp_name_valid (char *s)
+{
+  int c;
+  char *ret,*tail;
+				/* must be non-empty and not too long */
+  if ((ret = (s && *s) ? s : NIL) && (tail = ret + NETMAXHOST)) {
+				/* must be alnum, dot, or hyphen */
+    while ((c = *s++) && (s <= tail) &&
+	   (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) ||
+	    ((c >= '0') && (c <= '9')) || (c == '-') || (c == '.')));
+    if (c) ret = NIL;
+  }
+  return ret;
+}
+
+/* TCP/IP check if client is given host name
+ * Accepts: candidate host name
+ * Returns: T if match, NIL otherwise
+ */
+
+long tcp_isclienthost (char *host)
+{
+  int family;
+  size_t adrlen,sadrlen,len;
+  void *adr,*next;
+  struct sockaddr *sadr;
+  long ret = NIL;
+				/* make sure that myClientAddr is set */
+  if (tcp_clienthost () && myClientAddr)
+				/* get sockaddr of client */
+    for (adr = ip_nametoaddr (host,&adrlen,&family,NIL,&next); adr && !ret;
+	 adr = ip_nametoaddr (NIL,&adrlen,&family,NIL,&next)) {
+				/* build sockaddr of given address */
+      sadr = ip_sockaddr (family,adr,adrlen,1,&len);
+      if (!strcmp (myClientAddr,ip_sockaddrtostring (sadr))) ret = LONGT;
+      fs_give ((void **) &sadr);	/* done with client sockaddr */
+    }
+  return ret;
+}
+
+/* Following statement must be at end of this module */
+
+#undef fork			/* undo any use of vfork() */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/tcp_unix.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,48 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX TCP/IP routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+/* TCP input buffer */
+
+#define BUFLEN 8192
+
+
+/* TCP I/O stream */
+
+#define TCPSTREAM struct tcp_stream
+TCPSTREAM {
+  char *host;			/* host name */
+  unsigned long port;		/* port number */
+  char *localhost;		/* local host name */
+  char *remotehost;		/* remote host name */
+  int tcpsi;			/* input socket */
+  int tcpso;			/* output socket */
+  int ictr;			/* input counter */
+  char *iptr;			/* input pointer */
+  char ibuf[BUFLEN];		/* input buffer */
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/tenex.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1470 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Tenex mail routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	22 May 1990
+ * Last Edited:	11 October 2007
+ */
+
+
+/*				FILE TIME SEMANTICS
+ *
+ * The atime is the last read time of the file.
+ * The mtime is the last flags update time of the file.
+ * The ctime is the last write time of the file.
+ *
+ *				TEXT SIZE SEMANTICS
+ *
+ * Most of the text sizes are in internal (LF-only) form, except for the
+ * msg.text size.  Beware.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "mail.h"
+#include "osdep.h"
+#include <sys/stat.h>
+#include "misc.h"
+#include "dummy.h"
+
+/* TENEX I/O stream local data */
+	
+typedef struct tenex_local {
+  unsigned int shouldcheck: 1;	/* if ping should do a check instead */
+  unsigned int mustcheck: 1;	/* if ping must do a check instead */
+  int fd;			/* file descriptor for I/O */
+  off_t filesize;		/* file size parsed */
+  time_t filetime;		/* last file time */
+  time_t lastsnarf;		/* local snarf time */
+  unsigned char *buf;		/* temporary buffer */
+  unsigned long buflen;		/* current size of temporary buffer */
+  unsigned long uid;		/* current text uid */
+  SIZEDTEXT text;		/* current text */
+} TENEXLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((TENEXLOCAL *) stream->local)
+
+
+/* Function prototypes */
+
+DRIVER *tenex_valid (char *name);
+int tenex_isvalid (char *name,char *tmp);
+void *tenex_parameters (long function,void *value);
+void tenex_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void tenex_list (MAILSTREAM *stream,char *ref,char *pat);
+void tenex_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long tenex_create (MAILSTREAM *stream,char *mailbox);
+long tenex_delete (MAILSTREAM *stream,char *mailbox);
+long tenex_rename (MAILSTREAM *stream,char *old,char *newname);
+long tenex_status (MAILSTREAM *stream,char *mbx,long flags);
+MAILSTREAM *tenex_open (MAILSTREAM *stream);
+void tenex_close (MAILSTREAM *stream,long options);
+void tenex_fast (MAILSTREAM *stream,char *sequence,long flags);
+void tenex_flags (MAILSTREAM *stream,char *sequence,long flags);
+char *tenex_header (MAILSTREAM *stream,unsigned long msgno,
+		    unsigned long *length,long flags);
+long tenex_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+void tenex_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags);
+void tenex_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
+long tenex_ping (MAILSTREAM *stream);
+void tenex_check (MAILSTREAM *stream);
+void tenex_snarf (MAILSTREAM *stream);
+long tenex_expunge (MAILSTREAM *stream,char *sequence,long options);
+long tenex_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long tenex_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+unsigned long tenex_size (MAILSTREAM *stream,unsigned long m);
+char *tenex_file (char *dst,char *name);
+long tenex_parse (MAILSTREAM *stream);
+MESSAGECACHE *tenex_elt (MAILSTREAM *stream,unsigned long msgno);
+void tenex_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt);
+void tenex_update_status (MAILSTREAM *stream,unsigned long msgno,
+			  long syncflag);
+unsigned long tenex_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			    unsigned long *size);
+
+/* Tenex mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER tenexdriver = {
+  "tenex",			/* driver name */
+  DR_LOCAL|DR_MAIL|DR_NOSTICKY|DR_LOCKING,
+				/* driver flags */
+  (DRIVER *) NIL,		/* next driver */
+  tenex_valid,			/* mailbox is valid for us */
+  tenex_parameters,		/* manipulate parameters */
+  tenex_scan,			/* scan mailboxes */
+  tenex_list,			/* list mailboxes */
+  tenex_lsub,			/* list subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  dummy_create,			/* create mailbox */
+  tenex_delete,			/* delete mailbox */
+  tenex_rename,			/* rename mailbox */
+  tenex_status,			/* status of mailbox */
+  tenex_open,			/* open mailbox */
+  tenex_close,			/* close mailbox */
+  tenex_fast,			/* fetch message "fast" attributes */
+  tenex_flags,			/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  tenex_header,			/* fetch message header */
+  tenex_text,			/* fetch message body */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  tenex_flag,			/* modify flags */
+  tenex_flagmsg,		/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  tenex_ping,			/* ping mailbox to see if still alive */
+  tenex_check,			/* check for new messages */
+  tenex_expunge,		/* expunge deleted messages */
+  tenex_copy,			/* copy messages to another mailbox */
+  tenex_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM tenexproto = {&tenexdriver};
+
+/* Tenex mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *tenex_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+  return tenex_isvalid (name,tmp) ? &tenexdriver : NIL;
+}
+
+
+/* Tenex mail test for valid mailbox
+ * Accepts: mailbox name
+ * Returns: T if valid, NIL otherwise
+ */
+
+int tenex_isvalid (char *name,char *tmp)
+{
+  int fd;
+  int ret = NIL;
+  char *s,file[MAILTMPLEN];
+  struct stat sbuf;
+  time_t tp[2];
+  errno = EINVAL;		/* assume invalid argument */
+				/* if file, get its status */
+  if ((s = tenex_file (file,name)) && !stat (s,&sbuf)) {
+    if (!sbuf.st_size) {	/* allow empty file if INBOX */
+      if ((s = mailboxfile (tmp,name)) && !*s) ret = T;
+      else errno = 0;		/* empty file */
+    }
+    else if ((fd = open (file,O_RDONLY,NIL)) >= 0) {
+      memset (tmp,'\0',MAILTMPLEN);
+      if ((read (fd,tmp,64) >= 0) && (s = strchr (tmp,'\012')) &&
+	  (s[-1] != '\015')) {	/* valid format? */
+	*s = '\0';		/* tie off header */
+				/* must begin with dd-mmm-yy" */
+	ret = (((tmp[2] == '-' && tmp[6] == '-') ||
+		(tmp[1] == '-' && tmp[5] == '-')) &&
+	       (s = strchr (tmp+18,',')) && strchr (s+2,';')) ? T : NIL;
+      }
+      else errno = -1;		/* bogus format */
+      close (fd);		/* close the file */
+				/* \Marked status? */
+      if (sbuf.st_ctime > sbuf.st_atime) {
+	tp[0] = sbuf.st_atime;	/* preserve atime and mtime */
+	tp[1] = sbuf.st_mtime;
+	utime (file,tp);	/* set the times */
+      }
+    }
+  }
+				/* in case INBOX but not tenex format */
+  else if ((errno == ENOENT) && !compare_cstring (name,"INBOX")) errno = -1;
+  return ret;			/* return what we should */
+}
+
+/* Tenex manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *tenex_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case GET_INBOXPATH:
+    if (value) ret = tenex_file ((char *) value,"INBOX");
+    break;
+  }
+  return ret;
+}
+
+
+/* Tenex mail scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void tenex_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* Tenex mail list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void tenex_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_list (NIL,ref,pat);
+}
+
+
+/* Tenex mail list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void tenex_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_lsub (NIL,ref,pat);
+}
+
+/* Tenex mail delete mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long tenex_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return tenex_rename (stream,mailbox,NIL);
+}
+
+
+/* Tenex mail rename mailbox
+ * Accepts: MAIL stream
+ *	    old mailbox name
+ *	    new mailbox name (or NIL for delete)
+ * Returns: T on success, NIL on failure
+ */
+
+long tenex_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  long ret = T;
+  char c,*s,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  int fd,ld;
+  struct stat sbuf;
+  if (!tenex_file (file,old) ||
+      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
+		   ((s = strrchr (tmp,'/')) && !s[1])))) {
+    sprintf (tmp,newname ?
+	     "Can't rename mailbox %.80s to %.80s: invalid name" :
+	     "Can't delete mailbox %.80s: invalid name",
+	     old,newname);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+  else if ((fd = open (file,O_RDWR,NIL)) < 0) {
+    sprintf (tmp,"Can't open mailbox %.80s: %s",old,strerror (errno));
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+				/* get exclusive parse/append permission */
+  if ((ld = lockfd (fd,lock,LOCK_EX)) < 0) {
+    MM_LOG ("Unable to lock rename mailbox",ERROR);
+    return NIL;
+  }
+				/* lock out other users */
+  if (flock (fd,LOCK_EX|LOCK_NB)) {
+    close (fd);			/* couldn't lock, give up on it then */
+    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
+    MM_LOG (tmp,ERROR);
+    unlockfd (ld,lock);		/* release exclusive parse/append permission */
+    return NIL;
+  }
+
+  if (newname) {		/* want rename? */
+    if (s = strrchr (tmp,'/')) {/* found superior to destination name? */
+      c = *++s;			/* remember first character of inferior */
+      *s = '\0';		/* tie off to get just superior */
+				/* name doesn't exist, create it */
+      if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+	  !dummy_create_path (stream,tmp,get_dir_protection (newname)))
+	ret = NIL;
+      else *s = c;		/* restore full name */
+    }
+				/* rename the file */
+    if (ret && rename (file,tmp)) {
+      sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
+	       strerror (errno));
+      MM_LOG (tmp,ERROR);
+      ret = NIL;		/* set failure */
+    }
+  }
+  else if (unlink (file)) {
+    sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
+    MM_LOG (tmp,ERROR);
+    ret = NIL;			/* set failure */
+  }
+  flock (fd,LOCK_UN);		/* release lock on the file */
+  close (fd);			/* close the file */
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+				/* recreate file if renamed INBOX */
+  if (ret && !compare_cstring (old,"INBOX")) dummy_create (NIL,"mail.txt");
+  return ret;			/* return success */
+}
+
+/* Tenex Mail status
+ * Accepts: mail stream
+ *	    mailbox name
+ *	    status flags
+ * Returns: T on success, NIL on failure
+ */
+
+long tenex_status (MAILSTREAM *stream,char *mbx,long flags)
+{
+  MAILSTATUS status;
+  unsigned long i;
+  MAILSTREAM *tstream = NIL;
+  MAILSTREAM *systream = NIL;
+				/* make temporary stream (unless this mbx) */
+  if (!stream && !(stream = tstream =
+		   mail_open (NIL,mbx,OP_READONLY|OP_SILENT))) return NIL;
+  status.flags = flags;		/* return status values */
+  status.messages = stream->nmsgs;
+  status.recent = stream->recent;
+  if (flags & SA_UNSEEN)	/* must search to get unseen messages */
+    for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++)
+      if (!mail_elt (stream,i)->seen) status.unseen++;
+  status.uidnext = stream->uid_last + 1;
+  status.uidvalidity = stream->uid_validity;
+				/* calculate post-snarf results */
+  if (!status.recent && stream->inbox &&
+      (systream = mail_open (NIL,sysinbox (),OP_READONLY|OP_SILENT))) {
+    status.messages += systream->nmsgs;
+    status.recent += systream->recent;
+    if (flags & SA_UNSEEN)	/* must search to get unseen messages */
+      for (i = 1; i <= systream->nmsgs; i++)
+	if (!mail_elt (systream,i)->seen) status.unseen++;
+				/* kludge but probably good enough */
+    status.uidnext += systream->nmsgs;
+  }
+  MM_STATUS(stream,mbx,&status);/* pass status to main program */
+  if (tstream) mail_close (tstream);
+  if (systream) mail_close (systream);
+  return T;			/* success */
+}
+
+/* Tenex mail open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *tenex_open (MAILSTREAM *stream)
+{
+  int fd,ld;
+  char tmp[MAILTMPLEN];
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return user_flags (&tenexproto);
+  if (stream->local) fatal ("tenex recycle stream");
+  user_flags (stream);		/* set up user flags */
+				/* canonicalize the mailbox name */
+  if (!tenex_file (tmp,stream->mailbox)) {
+    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
+    MM_LOG (tmp,ERROR);
+  }
+  if (stream->rdonly ||
+      (fd = open (tmp,O_RDWR,NIL)) < 0) {
+    if ((fd = open (tmp,O_RDONLY,NIL)) < 0) {
+      sprintf (tmp,"Can't open mailbox: %s",strerror (errno));
+      MM_LOG (tmp,ERROR);
+      return NIL;
+    }
+    else if (!stream->rdonly) {	/* got it, but readonly */
+      MM_LOG ("Can't get write access to mailbox, access is readonly",WARN);
+      stream->rdonly = T;
+    }
+  }
+  stream->local = fs_get (sizeof (TENEXLOCAL));
+  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
+  LOCAL->buflen = CHUNKSIZE - 1;
+  LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE);
+  LOCAL->text.size = CHUNKSIZE - 1;
+
+				/* note if an INBOX or not */
+  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
+  LOCAL->fd = fd;		/* bind the file */
+				/* flush old name */
+  fs_give ((void **) &stream->mailbox);
+				/* save canonical name */
+  stream->mailbox = cpystr (tmp);
+				/* get shared parse permission */
+  if ((ld = lockfd (fd,tmp,LOCK_SH)) < 0) {
+    MM_LOG ("Unable to lock open mailbox",ERROR);
+    return NIL;
+  }
+  (*bn) (BLOCK_FILELOCK,NIL);
+  flock (LOCAL->fd,LOCK_SH);	/* lock the file */
+  (*bn) (BLOCK_NONE,NIL);
+  unlockfd (ld,tmp);		/* release shared parse permission */
+  LOCAL->filesize = 0;		/* initialize parsed file size */
+				/* time not set up yet */
+  LOCAL->lastsnarf = LOCAL->filetime = 0;
+  LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
+  stream->sequence++;		/* bump sequence number */
+				/* parse mailbox */
+  stream->nmsgs = stream->recent = 0;
+  if (tenex_ping (stream) && !stream->nmsgs)
+    MM_LOG ("Mailbox is empty",(long) NIL);
+  if (!LOCAL) return NIL;	/* failure if stream died */
+  stream->perm_seen = stream->perm_deleted =
+    stream->perm_flagged = stream->perm_answered = stream->perm_draft =
+      stream->rdonly ? NIL : T;
+  stream->perm_user_flags = stream->rdonly ? NIL : 0xffffffff;
+  return stream;		/* return stream to caller */
+}
+
+/* Tenex mail close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void tenex_close (MAILSTREAM *stream,long options)
+{
+  if (stream && LOCAL) {	/* only if a file is open */
+    int silent = stream->silent;
+    stream->silent = T;		/* note this stream is dying */
+    if (options & CL_EXPUNGE) tenex_expunge (stream,NIL,NIL);
+    stream->silent = silent;	/* restore previous status */
+    flock (LOCAL->fd,LOCK_UN);	/* unlock local file */
+    close (LOCAL->fd);		/* close the local file */
+				/* free local text buffer */
+    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+    if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+/* Tenex mail fetch fast data
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ */
+
+void tenex_fast (MAILSTREAM *stream,char *sequence,long flags)
+{
+  STRING bs;
+  MESSAGECACHE *elt;
+  unsigned long i;
+  if (stream && LOCAL &&
+      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
+       mail_sequence (stream,sequence)))
+    for (i = 1; i <= stream->nmsgs; i++)
+      if ((elt = mail_elt (stream,i))->sequence) {
+	if (!elt->rfc822_size) { /* have header size yet? */
+	  lseek (LOCAL->fd,elt->private.special.offset +
+		 elt->private.special.text.size,L_SET);
+				/* resize bigbuf if necessary */
+	  if (LOCAL->buflen < elt->private.msg.full.text.size) {
+	    fs_give ((void **) &LOCAL->buf);
+	    LOCAL->buflen = elt->private.msg.full.text.size;
+	    LOCAL->buf = (char *) fs_get (LOCAL->buflen + 1);
+	  }
+				/* tie off string */
+	  LOCAL->buf[elt->private.msg.full.text.size] = '\0';
+				/* read in the message */
+	  read (LOCAL->fd,LOCAL->buf,elt->private.msg.full.text.size);
+	  INIT (&bs,mail_string,(void *) LOCAL->buf,
+		elt->private.msg.full.text.size);
+				/* calculate its CRLF size */
+	  elt->rfc822_size = strcrlflen (&bs);
+	}
+	tenex_elt (stream,i);	/* get current flags from file */
+      }
+}
+
+
+/* Tenex mail fetch flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    option flags
+ * Sniffs at file to get flags
+ */
+
+void tenex_flags (MAILSTREAM *stream,char *sequence,long flags)
+{
+  unsigned long i;
+  if (stream && LOCAL &&
+      ((flags & FT_UID) ? mail_uid_sequence (stream,sequence) :
+       mail_sequence (stream,sequence)))
+    for (i = 1; i <= stream->nmsgs; i++)
+      if (mail_elt (stream,i)->sequence) tenex_elt (stream,i);
+}
+
+/* TENEX mail fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+char *tenex_header (MAILSTREAM *stream,unsigned long msgno,
+		    unsigned long *length,long flags)
+{
+  char *s;
+  unsigned long i;
+  *length = 0;			/* default to empty */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+				/* get to header position */
+  lseek (LOCAL->fd,tenex_hdrpos (stream,msgno,&i),L_SET);
+  if (flags & FT_INTERNAL) {
+    if (i > LOCAL->buflen) {	/* resize if not enough space */
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get (LOCAL->buflen = i + 1);
+    }
+				/* slurp the data */
+    read (LOCAL->fd,LOCAL->buf,*length = i);
+  }
+  else {
+    s = (char *) fs_get (i + 1);/* get readin buffer */
+    s[i] = '\0';		/* tie off string */
+    read (LOCAL->fd,s,i);	/* slurp the data */
+				/* make CRLF copy of string */
+    *length = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen,s,i);
+    fs_give ((void **) &s);	/* free readin buffer */
+  }
+  return (char *) LOCAL->buf;
+}
+
+/* TENEX mail fetch message text (body only)
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned stringstruct
+ *	    option flags
+ * Returns: T, always
+ */
+
+long tenex_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  char *s;
+  unsigned long i,j;
+  MESSAGECACHE *elt;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+				/* get message status */
+  elt = tenex_elt (stream,msgno);
+				/* if message not seen */
+  if (!(flags & FT_PEEK) && !elt->seen) {
+    elt->seen = T;		/* mark message as seen */
+				/* recalculate status */
+    tenex_update_status (stream,msgno,T);
+    MM_FLAGS (stream,msgno);
+  }
+  if (flags & FT_INTERNAL) {	/* if internal representation wanted */
+				/* find header position */
+    i = tenex_hdrpos (stream,msgno,&j);
+    if (i > LOCAL->buflen) {	/* resize if not enough space */
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get (LOCAL->buflen = i + 1);
+    }
+				/* go to text position */
+    lseek (LOCAL->fd,i + j,L_SET);
+				/* slurp the data */
+    read (LOCAL->fd,LOCAL->buf,i);
+				/* set up stringstruct for internal */
+    INIT (bs,mail_string,LOCAL->buf,i);
+  }
+  else {			/* normal form, previous text cached? */
+    if (elt->private.uid == LOCAL->uid)
+      i = elt->private.msg.text.text.size;
+    else {			/* not cached, cache it now */
+      LOCAL->uid = elt->private.uid;
+				/* find header position */
+      i = tenex_hdrpos (stream,msgno,&j);
+				/* go to text position */
+      lseek (LOCAL->fd,i + j,L_SET);
+      s = (char *) fs_get ((i = tenex_size (stream,msgno) - j) + 1);
+      s[i] = '\0';		/* tie off string */
+      read (LOCAL->fd,s,i);	/* slurp the data */
+				/* make CRLF copy of string */
+      i = elt->private.msg.text.text.size =
+	strcrlfcpy (&LOCAL->text.data,&LOCAL->text.size,s,i);
+      fs_give ((void **) &s);	/* free readin buffer */
+    }
+				/* set up stringstruct */
+    INIT (bs,mail_string,LOCAL->text.data,i);
+  }
+  return T;			/* success */
+}
+
+/* Tenex mail modify flags
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    flag(s)
+ *	    option flags
+ */
+
+void tenex_flag (MAILSTREAM *stream,char *sequence,char *flag,long flags)
+{
+  time_t tp[2];
+  struct stat sbuf;
+  if (!stream->rdonly) {	/* make sure the update takes */
+    fsync (LOCAL->fd);
+    fstat (LOCAL->fd,&sbuf);	/* get current write time */
+    tp[1] = LOCAL->filetime = sbuf.st_mtime;
+    tp[0] = time (0);		/* make sure read comes after all that */
+    utime (stream->mailbox,tp);
+  }
+}
+
+
+/* Tenex mail per-message modify flags
+ * Accepts: MAIL stream
+ *	    message cache element
+ */
+
+void tenex_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  struct stat sbuf;
+				/* maybe need to do a checkpoint? */
+  if (LOCAL->filetime && !LOCAL->shouldcheck) {
+    fstat (LOCAL->fd,&sbuf);	/* get current write time */
+    if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
+    LOCAL->filetime = 0;	/* don't do this test for any other messages */
+  }
+				/* recalculate status */
+  tenex_update_status (stream,elt->msgno,NIL);
+}
+
+/* Tenex mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream still alive, NIL if not
+ */
+
+long tenex_ping (MAILSTREAM *stream)
+{
+  unsigned long i = 1;
+  long r = T;
+  int ld;
+  char lock[MAILTMPLEN];
+  struct stat sbuf;
+  if (stream && LOCAL) {	/* only if stream already open */
+    fstat (LOCAL->fd,&sbuf);	/* get current file poop */
+    if (LOCAL->filetime && !(LOCAL->mustcheck || LOCAL->shouldcheck) &&
+	(LOCAL->filetime < sbuf.st_mtime)) LOCAL->shouldcheck = T;
+				/* check for changed message status */
+    if (LOCAL->mustcheck || LOCAL->shouldcheck) {
+      LOCAL->filetime = sbuf.st_mtime;
+      if (LOCAL->shouldcheck)	/* babble when we do this unilaterally */
+	MM_NOTIFY (stream,"[CHECK] Checking for flag updates",NIL);
+      while (i <= stream->nmsgs) tenex_elt (stream,i++);
+      LOCAL->mustcheck = LOCAL->shouldcheck = NIL;
+    }
+				/* get shared parse/append permission */
+    if ((sbuf.st_size != LOCAL->filesize) &&
+	((ld = lockfd (LOCAL->fd,lock,LOCK_SH)) >= 0)) {
+				/* parse resulting mailbox */
+      r = (tenex_parse (stream)) ? T : NIL;
+      unlockfd (ld,lock);	/* release shared parse/append permission */
+    }
+    if (LOCAL) {		/* stream must still be alive */
+				/* snarf if this is a read-write inbox */
+      if (stream->inbox && !stream->rdonly) {
+	tenex_snarf (stream);
+	fstat (LOCAL->fd,&sbuf);/* see if file changed now */
+	if ((sbuf.st_size != LOCAL->filesize) &&
+	    ((ld = lockfd (LOCAL->fd,lock,LOCK_SH)) >= 0)) {
+				/* parse resulting mailbox */
+	  r = (tenex_parse (stream)) ? T : NIL;
+	  unlockfd (ld,lock);	/* release shared parse/append permission */
+	}
+      }
+    }
+  }
+  return r;			/* return result of the parse */
+}
+
+
+/* Tenex mail check mailbox (reparses status too)
+ * Accepts: MAIL stream
+ */
+
+void tenex_check (MAILSTREAM *stream)
+{
+				/* mark that a check is desired */
+  if (LOCAL) LOCAL->mustcheck = T;
+  if (tenex_ping (stream)) MM_LOG ("Check completed",(long) NIL);
+}
+
+/* Tenex mail snarf messages from system inbox
+ * Accepts: MAIL stream
+ */
+
+void tenex_snarf (MAILSTREAM *stream)
+{
+  unsigned long i = 0;
+  unsigned long j,r,hdrlen,txtlen;
+  struct stat sbuf;
+  char *hdr,*txt,lock[MAILTMPLEN],tmp[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  MAILSTREAM *sysibx = NIL;
+  int ld;
+				/* give up if can't get exclusive permission */
+  if ((time (0) >= (LOCAL->lastsnarf +
+		    (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL))) &&
+      strcmp (sysinbox (),stream->mailbox) &&
+      ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) >= 0)) {
+    MM_CRITICAL (stream);	/* go critical */
+				/* sizes match and anything in sysinbox? */
+    if (!stat (sysinbox (),&sbuf) && sbuf.st_size &&
+	!fstat (LOCAL->fd,&sbuf) && (sbuf.st_size == LOCAL->filesize) && 
+	(sysibx = mail_open (sysibx,sysinbox (),OP_SILENT)) &&
+	(!sysibx->rdonly) && (r = sysibx->nmsgs)) {
+				/* yes, go to end of file in our mailbox */
+      lseek (LOCAL->fd,sbuf.st_size,L_SET);
+				/* for each message in sysibx mailbox */
+      while (r && (++i <= sysibx->nmsgs)) {
+				/* snarf message from system INBOX */
+	hdr = cpystr (mail_fetchheader_full(sysibx,i,NIL,&hdrlen,FT_INTERNAL));
+	txt = mail_fetchtext_full (sysibx,i,&txtlen,FT_INTERNAL|FT_PEEK);
+				/* if have a message */
+	if (j = hdrlen + txtlen) {
+				/* calculate header line */
+	  mail_date (LOCAL->buf,elt = mail_elt (sysibx,i));
+	  sprintf (LOCAL->buf + strlen (LOCAL->buf),
+		   ",%lu;0000000000%02o\n",j,(unsigned)
+		   ((fSEEN * elt->seen) + (fDELETED * elt->deleted) +
+		    (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
+		    (fDRAFT * elt->draft)));
+				/* copy message */
+	  if ((write (LOCAL->fd,LOCAL->buf,strlen (LOCAL->buf)) < 0) ||
+	      (write (LOCAL->fd,hdr,hdrlen) < 0) ||
+	      (write (LOCAL->fd,txt,txtlen) < 0)) r = 0;
+	}
+	fs_give ((void **) &hdr);
+      }
+
+				/* make sure all the updates take */
+      if (fsync (LOCAL->fd)) r = 0;
+      if (r) {			/* delete all the messages we copied */
+	if (r == 1) strcpy (tmp,"1");
+	else sprintf (tmp,"1:%lu",r);
+	mail_flag (sysibx,tmp,"\\Deleted",ST_SET);
+	mail_expunge (sysibx);	/* now expunge all those messages */
+      }
+      else {
+	sprintf (LOCAL->buf,"Can't copy new mail: %s",strerror (errno));
+	MM_LOG (LOCAL->buf,WARN);
+	ftruncate (LOCAL->fd,sbuf.st_size);
+      }
+      fstat (LOCAL->fd,&sbuf);	/* yes, get current file size */
+      LOCAL->filetime = sbuf.st_mtime;
+    }
+    if (sysibx) mail_close (sysibx);
+    MM_NOCRITICAL (stream);	/* release critical */
+    unlockfd (ld,lock);		/* release exclusive parse/append permission */
+    LOCAL->lastsnarf = time (0);/* note time of last snarf */
+  }
+}
+
+/* Tenex mail expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long tenex_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  long ret;
+  time_t tp[2];
+  struct stat sbuf;
+  off_t pos = 0;
+  int ld;
+  unsigned long i = 1;
+  unsigned long j,k,m,recent;
+  unsigned long n = 0;
+  unsigned long delta = 0;
+  char lock[MAILTMPLEN];
+  MESSAGECACHE *elt;
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  if (!(ret = (sequence ? ((options & EX_UID) ?
+			   mail_uid_sequence (stream,sequence) :
+			   mail_sequence (stream,sequence)) : LONGT) &&
+	tenex_ping (stream)));	/* parse sequence if given, ping stream */
+  else if (stream->rdonly) MM_LOG ("Expunge ignored on readonly mailbox",WARN);
+  else {
+    if (LOCAL->filetime && !LOCAL->shouldcheck) {
+      fstat (LOCAL->fd,&sbuf);	/* get current write time */
+      if (LOCAL->filetime < sbuf.st_mtime) LOCAL->shouldcheck = T;
+    }
+  /* The cretins who designed flock() created a window of vulnerability in
+   * upgrading locks from shared to exclusive or downgrading from exclusive
+   * to shared.  Rather than maintain the lock at shared status at a minimum,
+   * flock() actually *releases* the former lock.  Obviously they never talked
+   * to any database guys.  Fortunately, we have the parse/append permission
+   * lock.  If we require this lock before going exclusive on the mailbox,
+   * another process can not sneak in and steal the exclusive mailbox lock on
+   * us, because it will block on trying to get parse/append permission first.
+   */
+				/* get exclusive parse/append permission */
+    if ((ld = lockfd (LOCAL->fd,lock,LOCK_EX)) < 0)
+      MM_LOG ("Unable to lock expunge mailbox",ERROR);
+				/* make sure see any newly-arrived messages */
+    else if (!tenex_parse (stream));
+				/* get exclusive access */
+    else if (flock (LOCAL->fd,LOCK_EX|LOCK_NB)) {
+      (*bn) (BLOCK_FILELOCK,NIL);
+      flock (LOCAL->fd,LOCK_SH);/* recover previous lock */
+      (*bn) (BLOCK_NONE,NIL);
+      MM_LOG ("Can't expunge because mailbox is in use by another process",
+	      ERROR);
+      unlockfd (ld,lock);	/* release exclusive parse/append permission */
+    }
+
+    else {
+      MM_CRITICAL (stream);	/* go critical */
+      recent = stream->recent;	/* get recent now that pinged and locked */
+				/* for each message */
+      while (i <= stream->nmsgs) {
+				/* get cache element */
+	elt = tenex_elt (stream,i);
+				/* number of bytes to smash or preserve */
+	k = elt->private.special.text.size + tenex_size (stream,i);
+				/* if need to expunge this message */
+	if (elt->deleted && (sequence ? elt->sequence : T)) {
+				/* if recent, note one less recent message */
+	  if (elt->recent) --recent;
+	  delta += k;		/* number of bytes to delete */
+				/* notify upper levels */
+	  mail_expunged (stream,i);
+	  n++;			/* count up one more expunged message */
+	}
+	else if (i++ && delta) {/* preserved message */
+				/* first byte to preserve */
+	  j = elt->private.special.offset;
+	  do {			/* read from source position */
+	    m = min (k,LOCAL->buflen);
+	    lseek (LOCAL->fd,j,L_SET);
+	    read (LOCAL->fd,LOCAL->buf,m);
+	    pos = j - delta;	/* write to destination position */
+	    lseek (LOCAL->fd,pos,L_SET);
+	    while (T) {
+	      lseek (LOCAL->fd,pos,L_SET);
+	      if (write (LOCAL->fd,LOCAL->buf,m) > 0) break;
+	      MM_NOTIFY (stream,strerror (errno),WARN);
+	      MM_DISKERROR (stream,errno,T);
+	    }
+	    pos += m;		/* new position */
+	    j += m;		/* next chunk, perhaps */
+	  } while (k -= m);		/* until done */
+				/* note the new address of this text */
+	  elt->private.special.offset -= delta;
+	}
+				/* preserved but no deleted messages */
+	else pos = elt->private.special.offset + k;
+      }
+
+      if (n) {			/* truncate file after last message */
+	if (pos != (LOCAL->filesize -= delta)) {
+	  sprintf (LOCAL->buf,
+		   "Calculated size mismatch %lu != %lu, delta = %lu",
+		   (unsigned long) pos,(unsigned long) LOCAL->filesize,delta);
+	  MM_LOG (LOCAL->buf,WARN);
+	  LOCAL->filesize = pos;/* fix it then */
+	}
+	ftruncate (LOCAL->fd,LOCAL->filesize);
+	sprintf (LOCAL->buf,"Expunged %lu messages",n);
+				/* output the news */
+	MM_LOG (LOCAL->buf,(long) NIL);
+      }
+      else MM_LOG ("No messages deleted, so no update needed",(long) NIL);
+      fsync (LOCAL->fd);		/* force disk update */
+      fstat (LOCAL->fd,&sbuf);	/* get new write time */
+      tp[1] = LOCAL->filetime = sbuf.st_mtime;
+      tp[0] = time (0);		/* reset atime to now */
+      utime (stream->mailbox,tp);
+      MM_NOCRITICAL (stream);	/* release critical */
+				/* notify upper level of new mailbox size */
+      mail_exists (stream,stream->nmsgs);
+      mail_recent (stream,recent);
+      (*bn) (BLOCK_FILELOCK,NIL);
+      flock (LOCAL->fd,LOCK_SH);/* allow sharers again */
+      (*bn) (BLOCK_NONE,NIL);
+      unlockfd (ld,lock);	/* release exclusive parse/append permission */
+    }
+  }
+  return LONGT;
+}
+
+/* Tenex mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if success, NIL if failed
+ */
+
+long tenex_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  struct stat sbuf;
+  time_t tp[2];
+  MESSAGECACHE *elt;
+  unsigned long i,j,k;
+  long ret = LONGT;
+  int fd,ld;
+  char file[MAILTMPLEN],lock[MAILTMPLEN];
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+				/* make sure valid mailbox */
+  if (!tenex_isvalid (mailbox,LOCAL->buf)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
+    return NIL;
+  case 0:			/* merely empty file? */
+    break;
+  case EACCES:			/* file protected */
+    sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
+    MM_LOG (LOCAL->buf,ERROR);
+    return NIL;
+  case EINVAL:
+    if (pc) return (*pc) (stream,sequence,mailbox,options);
+    sprintf (LOCAL->buf,"Invalid Tenex-format mailbox name: %.80s",mailbox);
+    MM_LOG (LOCAL->buf,ERROR);
+    return NIL;
+  default:
+    if (pc) return (*pc) (stream,sequence,mailbox,options);
+    sprintf (LOCAL->buf,"Not a Tenex-format mailbox: %.80s",mailbox);
+    MM_LOG (LOCAL->buf,ERROR);
+    return NIL;
+  }
+  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+	mail_sequence (stream,sequence))) return NIL;
+				/* got file? */  
+  if ((fd = open (tenex_file(file,mailbox),O_RDWR,NIL)) < 0) {
+    sprintf (LOCAL->buf,"Unable to open copy mailbox: %s",strerror (errno));
+    MM_LOG (LOCAL->buf,ERROR);
+    return NIL;
+  }
+  MM_CRITICAL (stream);		/* go critical */
+				/* get exclusive parse/append permission */
+  if (flock (fd,LOCK_SH) || ((ld = lockfd (fd,lock,LOCK_EX)) < 0)) {
+    MM_LOG ("Unable to lock copy mailbox",ERROR);
+    MM_NOCRITICAL (stream);
+    return NIL;
+  }
+  fstat (fd,&sbuf);		/* get current file size */
+  lseek (fd,sbuf.st_size,L_SET);/* move to end of file */
+
+				/* for each requested message */
+  for (i = 1; ret && (i <= stream->nmsgs); i++) 
+    if ((elt = mail_elt (stream,i))->sequence) {
+      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
+				/* number of bytes to copy */
+      k = elt->private.special.text.size + tenex_size (stream,i);
+      do {			/* read from source position */
+	j = min (k,LOCAL->buflen);
+	read (LOCAL->fd,LOCAL->buf,j);
+	if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
+      } while (ret && (k -= j));/* until done */
+    }
+				/* make sure all the updates take */
+  if (!(ret && (ret = !fsync (fd)))) {
+    sprintf (LOCAL->buf,"Unable to write message: %s",strerror (errno));
+    MM_LOG (LOCAL->buf,ERROR);
+    ftruncate (fd,sbuf.st_size);
+  }
+  if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */
+				/* else preserve \Marked status */
+  else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0);
+  tp[1] = sbuf.st_mtime;	/* preserve mtime */
+  utime (file,tp);		/* set the times */
+  close (fd);			/* close the file */
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+  MM_NOCRITICAL (stream);	/* release critical */
+				/* delete all requested messages */
+  if (ret && (options & CP_MOVE)) {
+    for (i = 1; i <= stream->nmsgs; i++)
+      if ((elt = tenex_elt (stream,i))->sequence) {
+	elt->deleted = T;	/* mark message deleted */
+				/* recalculate status */
+	tenex_update_status (stream,i,NIL);
+      }
+    if (!stream->rdonly) {	/* make sure the update takes */
+      fsync (LOCAL->fd);
+      fstat (LOCAL->fd,&sbuf);	/* get current write time */
+      tp[1] = LOCAL->filetime = sbuf.st_mtime;
+      tp[0] = time (0);		/* make sure atime remains greater */
+      utime (stream->mailbox,tp);
+    }
+  }
+  if (ret && mail_parameters (NIL,GET_COPYUID,NIL))
+    MM_LOG ("Can not return meaningful COPYUID with this mailbox format",WARN);
+  return ret;
+}
+
+/* Tenex mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long tenex_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct stat sbuf;
+  int fd,ld,c;
+  char *flags,*date,tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  time_t tp[2];
+  FILE *df;
+  MESSAGECACHE elt;
+  long f;
+  unsigned long i,j,uf,size;
+  STRING *message;
+  long ret = LONGT;
+				/* default stream to prototype */
+  if (!stream) stream = user_flags (&tenexproto);
+				/* make sure valid mailbox */
+  if (!tenex_isvalid (mailbox,tmp)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    if (!compare_cstring (mailbox,"INBOX")) dummy_create (NIL,"mail.txt");
+    else {
+      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+      return NIL;
+    }
+				/* falls through */
+  case 0:			/* merely empty file? */
+    break;
+  case EACCES:			/* file protected */
+    sprintf (tmp,"Can't access destination: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  case EINVAL:
+    sprintf (tmp,"Invalid TENEX-format mailbox name: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  default:
+    sprintf (tmp,"Not a TENEX-format mailbox: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+				/* get first message */
+  if (!MM_APPEND (af) (stream,data,&flags,&date,&message)) return NIL;
+
+				/* open destination mailbox */
+  if (((fd = open (tenex_file (file,mailbox),O_WRONLY|O_APPEND,NIL)) < 0) ||
+      !(df = fdopen (fd,"ab"))) {
+    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+				/* get parse/append permission */
+  if (flock (fd,LOCK_SH) || ((ld = lockfd (fd,lock,LOCK_EX)) < 0)) {
+    MM_LOG ("Unable to lock append mailbox",ERROR);
+    close (fd);
+    return NIL;
+  }
+  MM_CRITICAL (stream);		/* go critical */
+  fstat (fd,&sbuf);		/* get current file size */
+  errno = 0;
+  do {				/* parse flags */ 
+    if (!SIZE (message)) {	/* guard against zero-length */
+      MM_LOG ("Append of zero-length message",ERROR);
+      ret = NIL;
+      break;
+    }
+    f = mail_parse_flags (stream,flags,&i);
+				/* reverse bits (dontcha wish we had CIRC?) */
+    for (uf = 0; i; uf |= 1 << (29 - find_rightmost_bit (&i)));
+    if (date) {			/* parse date if given */
+      if (!mail_parse_date (&elt,date)) {
+	sprintf (tmp,"Bad date in append: %.80s",date);
+	MM_LOG (tmp,ERROR);
+	ret = NIL;		/* mark failure */
+	break;
+      }
+      mail_date (tmp,&elt);	/* write preseved date */
+    }
+    else internal_date (tmp);	/* get current date in IMAP format */
+    i = GETPOS (message);	/* remember current position */
+    for (j = SIZE (message), size = 0; j; --j)
+      if (SNX (message) != '\015') ++size;
+    SETPOS (message,i);		/* restore position */
+				/* write header */
+    if (fprintf (df,"%s,%lu;%010lo%02lo\n",tmp,size,uf,(unsigned long) f) < 0)
+      ret = NIL;
+    else {			/* write message */
+      while (size) if ((c = 0xff & SNX (message)) != '\015') {
+	if (putc (c,df) != EOF) --size;
+	else break;
+      }
+				/* get next message */
+      if (size || !MM_APPEND (af) (stream,data,&flags,&date,&message))
+	ret = NIL;
+    }
+  } while (ret && message);
+				/* if error... */
+  if (!ret || (fflush (df) == EOF)) {
+    ftruncate (fd,sbuf.st_size);/* revert file */
+    close (fd);			/* make sure fclose() doesn't corrupt us */
+    if (errno) {
+      sprintf (tmp,"Message append failed: %s",strerror (errno));
+      MM_LOG (tmp,ERROR);
+    }
+    ret = NIL;
+  }
+  if (ret) tp[0] = time (0) - 1;/* set atime to now-1 if successful copy */
+				/* else preserve \Marked status */
+  else tp[0] = (sbuf.st_ctime > sbuf.st_atime) ? sbuf.st_atime : time(0);
+  tp[1] = sbuf.st_mtime;	/* preserve mtime */
+  utime (file,tp);		/* set the times */
+  fclose (df);			/* close the file */
+  unlockfd (ld,lock);		/* release exclusive parse/append permission */
+  MM_NOCRITICAL (stream);	/* release critical */
+  if (ret && mail_parameters (NIL,GET_APPENDUID,NIL))
+    MM_LOG ("Can not return meaningful APPENDUID with this mailbox format",
+	    WARN);
+  return ret;
+}
+
+/* Internal routines */
+
+
+/* Tenex mail return internal message size in bytes
+ * Accepts: MAIL stream
+ *	    message #
+ * Returns: internal size of message
+ */
+
+unsigned long tenex_size (MAILSTREAM *stream,unsigned long m)
+{
+  MESSAGECACHE *elt = mail_elt (stream,m);
+  return ((m < stream->nmsgs) ? mail_elt (stream,m+1)->private.special.offset :
+	  LOCAL->filesize) -
+	    (elt->private.special.offset + elt->private.special.text.size);
+}
+
+
+/* Tenex mail generate file string
+ * Accepts: temporary buffer to write into
+ *	    mailbox name string
+ * Returns: local file string or NIL if failure
+ */
+
+char *tenex_file (char *dst,char *name)
+{
+  char tmp[MAILTMPLEN];
+  char *s = mailboxfile (dst,name);
+				/* return our standard inbox */
+  return (s && !*s) ? mailboxfile (dst,tenex_isvalid ("~/INBOX",tmp) ?
+				   "~/INBOX" : "mail.txt") : s;
+}
+
+/* Tenex mail parse mailbox
+ * Accepts: MAIL stream
+ * Returns: T if parse OK
+ *	    NIL if failure, stream aborted
+ */
+
+long tenex_parse (MAILSTREAM *stream)
+{
+  struct stat sbuf;
+  MESSAGECACHE *elt = NIL;
+  unsigned char c,*s,*t,*x;
+  char tmp[MAILTMPLEN];
+  unsigned long i,j;
+  long curpos = LOCAL->filesize;
+  long nmsgs = stream->nmsgs;
+  long recent = stream->recent;
+  short added = NIL;
+  short silent = stream->silent;
+  fstat (LOCAL->fd,&sbuf);	/* get status */
+  if (sbuf.st_size < curpos) {	/* sanity check */
+    sprintf (tmp,"Mailbox shrank from %lu to %lu!",
+	     (unsigned long) curpos,(unsigned long) sbuf.st_size);
+    MM_LOG (tmp,ERROR);
+    tenex_close (stream,NIL);
+    return NIL;
+  }
+  stream->silent = T;		/* don't pass up exists events yet */
+  while (sbuf.st_size - curpos){/* while there is stuff to parse */
+				/* get to that position in the file */
+    lseek (LOCAL->fd,curpos,L_SET);
+    if ((i = read (LOCAL->fd,LOCAL->buf,64)) <= 0) {
+      sprintf (tmp,"Unable to read internal header at %lu, size = %lu: %s",
+	       (unsigned long) curpos,(unsigned long) sbuf.st_size,
+	       i ? strerror (errno) : "no data read");
+      MM_LOG (tmp,ERROR);
+      tenex_close (stream,NIL);
+      return NIL;
+    }
+    LOCAL->buf[i] = '\0';	/* tie off buffer just in case */
+    if (!(s = strchr (LOCAL->buf,'\012'))) {
+      sprintf (tmp,"Unable to find newline at %lu in %lu bytes, text: %s",
+	       (unsigned long) curpos,i,(char *) LOCAL->buf);
+      MM_LOG (tmp,ERROR);
+      tenex_close (stream,NIL);
+      return NIL;
+    }
+    *s = '\0';			/* tie off header line */
+    i = (s + 1) - LOCAL->buf;	/* note start of text offset */
+    if (!((s = strchr (LOCAL->buf,',')) && (t = strchr (s+1,';')))) {
+      sprintf (tmp,"Unable to parse internal header at %lu: %s",
+	       (unsigned long) curpos,(char *) LOCAL->buf);
+      MM_LOG (tmp,ERROR);
+      tenex_close (stream,NIL);
+      return NIL;
+    }
+    *s++ = '\0'; *t++ = '\0';	/* tie off fields */
+
+    added = T;			/* note that a new message was added */
+				/* swell the cache */
+    mail_exists (stream,++nmsgs);
+				/* instantiate an elt for this message */
+    (elt = mail_elt (stream,nmsgs))->valid = T;
+    elt->private.uid = ++stream->uid_last;
+				/* note file offset of header */
+    elt->private.special.offset = curpos;
+				/* in case error */
+    elt->private.special.text.size = 0;
+				/* header size not known yet */
+    elt->private.msg.header.text.size = 0;
+    x = s;			/* parse the header components */
+    if (mail_parse_date (elt,LOCAL->buf) &&
+	(elt->private.msg.full.text.size = strtoul (s,(char **) &s,10)) &&
+	(!(s && *s)) && isdigit (t[0]) && isdigit (t[1]) && isdigit (t[2]) &&
+	isdigit (t[3]) && isdigit (t[4]) && isdigit (t[5]) &&
+	isdigit (t[6]) && isdigit (t[7]) && isdigit (t[8]) &&
+	isdigit (t[9]) && isdigit (t[10]) && isdigit (t[11]) && !t[12])
+      elt->private.special.text.size = i;
+    else {			/* oops */
+      sprintf (tmp,"Unable to parse internal header elements at %ld: %s,%s;%s",
+	       curpos,(char *) LOCAL->buf,(char *) x,(char *) t);
+      MM_LOG (tmp,ERROR);
+      tenex_close (stream,NIL);
+      return NIL;
+    }
+				/* make sure didn't run off end of file */
+    if ((curpos += (elt->private.msg.full.text.size + i)) > sbuf.st_size) {
+      sprintf (tmp,"Last message (at %lu) runs past end of file (%lu > %lu)",
+	       elt->private.special.offset,(unsigned long) curpos,
+	       (unsigned long) sbuf.st_size);
+      MM_LOG (tmp,ERROR);
+      tenex_close (stream,NIL);
+      return NIL;
+    }
+    c = t[10];			/* remember first system flags byte */
+    t[10] = '\0';		/* tie off flags */
+    j = strtoul (t,NIL,8);	/* get user flags value */
+    t[10] = c;			/* restore first system flags byte */
+				/* set up all valid user flags (reversed!) */
+    while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
+		  stream->user_flags[i]) elt->user_flags |= 1 << i;
+				/* calculate system flags */
+    if ((j = ((t[10]-'0') * 8) + t[11]-'0') & fSEEN) elt->seen = T;
+    if (j & fDELETED) elt->deleted = T;
+    if (j & fFLAGGED) elt->flagged = T;
+    if (j & fANSWERED) elt->answered = T;
+    if (j & fDRAFT) elt->draft = T;
+    if (!(j & fOLD)) {		/* newly arrived message? */
+      elt->recent = T;
+      recent++;			/* count up a new recent message */
+				/* mark it as old */
+      tenex_update_status (stream,nmsgs,NIL);
+    }
+  }
+  fsync (LOCAL->fd);		/* make sure all the fOLD flags take */
+				/* update parsed file size and time */
+  LOCAL->filesize = sbuf.st_size;
+  fstat (LOCAL->fd,&sbuf);	/* get status again to ensure time is right */
+  LOCAL->filetime = sbuf.st_mtime;
+  if (added && !stream->rdonly){/* make sure atime updated */
+    time_t tp[2];
+    tp[0] = time (0);
+    tp[1] = LOCAL->filetime;
+    utime (stream->mailbox,tp);
+  }
+  stream->silent = silent;	/* can pass up events now */
+  mail_exists (stream,nmsgs);	/* notify upper level of new mailbox size */
+  mail_recent (stream,recent);	/* and of change in recent messages */
+  return LONGT;			/* return the winnage */
+}
+
+/* Tenex get cache element with status updating from file
+ * Accepts: MAIL stream
+ *	    message number
+ * Returns: cache element
+ */
+
+MESSAGECACHE *tenex_elt (MAILSTREAM *stream,unsigned long msgno)
+{
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  struct {			/* old flags */
+    unsigned int seen : 1;
+    unsigned int deleted : 1;
+    unsigned int flagged : 1;
+    unsigned int answered : 1;
+    unsigned int draft : 1;
+    unsigned long user_flags;
+  } old;
+  old.seen = elt->seen; old.deleted = elt->deleted; old.flagged = elt->flagged;
+  old.answered = elt->answered; old.draft = elt->draft;
+  old.user_flags = elt->user_flags;
+  tenex_read_flags (stream,elt);
+  if ((old.seen != elt->seen) || (old.deleted != elt->deleted) ||
+      (old.flagged != elt->flagged) || (old.answered != elt->answered) ||
+      (old.draft != elt->draft) || (old.user_flags != elt->user_flags))
+    MM_FLAGS (stream,msgno);	/* let top level know */
+  return elt;
+}
+
+/* Tenex read flags from file
+ * Accepts: MAIL stream
+ * Returns: cache element
+ */
+
+void tenex_read_flags (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+  unsigned long i,j;
+				/* noop if readonly and have valid flags */
+  if (stream->rdonly && elt->valid) return;
+				/* set the seek pointer */
+  lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	 elt->private.special.text.size - 13,L_SET);
+				/* read the new flags */
+  if (read (LOCAL->fd,LOCAL->buf,12) < 0) {
+    sprintf (LOCAL->buf,"Unable to read new status: %s",strerror (errno));
+    fatal (LOCAL->buf);
+  }
+				/* calculate system flags */
+  i = (((LOCAL->buf[10]-'0') * 8) + LOCAL->buf[11]-'0');
+  elt->seen = i & fSEEN ? T : NIL; elt->deleted = i & fDELETED ? T : NIL;
+  elt->flagged = i & fFLAGGED ? T : NIL;
+  elt->answered = i & fANSWERED ? T : NIL; elt->draft = i & fDRAFT ? T : NIL;
+  LOCAL->buf[10] = '\0';	/* tie off flags */
+  j = strtoul(LOCAL->buf,NIL,8);/* get user flags value */
+				/* set up all valid user flags (reversed!) */
+  while (j) if (((i = 29 - find_rightmost_bit (&j)) < NUSERFLAGS) &&
+		stream->user_flags[i]) elt->user_flags |= 1 << i;
+  elt->valid = T;		/* have valid flags now */
+}
+
+/* Tenex update status string
+ * Accepts: MAIL stream
+ *	    message number
+ *	    flag saying whether or not to sync
+ */
+
+void tenex_update_status (MAILSTREAM *stream,unsigned long msgno,long syncflag)
+{
+  time_t tp[2];
+  struct stat sbuf;
+  MESSAGECACHE *elt = mail_elt (stream,msgno);
+  unsigned long j,k = 0;
+				/* readonly */
+  if (stream->rdonly || !elt->valid) tenex_read_flags (stream,elt);
+  else {			/* readwrite */
+    j = elt->user_flags;	/* get user flags */
+				/* reverse bits (dontcha wish we had CIRC?) */
+    while (j) k |= 1 << (29 - find_rightmost_bit (&j));
+				/* print new flag string */
+    sprintf (LOCAL->buf,"%010lo%02o",k,(unsigned)
+	     (fOLD + (fSEEN * elt->seen) + (fDELETED * elt->deleted) +
+	      (fFLAGGED * elt->flagged) + (fANSWERED * elt->answered) +
+	      (fDRAFT * elt->draft)));
+				/* get to that place in the file */
+    lseek (LOCAL->fd,(off_t) elt->private.special.offset +
+	   elt->private.special.text.size - 13,L_SET);
+				/* write new flags */
+    write (LOCAL->fd,LOCAL->buf,12);
+    if (syncflag) {		/* sync if requested */
+      fsync (LOCAL->fd);
+      fstat (LOCAL->fd,&sbuf);	/* get new write time */
+      tp[1] = LOCAL->filetime = sbuf.st_mtime;
+      tp[0] = time (0);		/* make sure read is later */
+      utime (stream->mailbox,tp);
+    }
+  }
+}
+
+/* Tenex locate header for a message
+ * Accepts: MAIL stream
+ *	    message number
+ *	    pointer to returned header size
+ * Returns: position of header in file
+ */
+
+unsigned long tenex_hdrpos (MAILSTREAM *stream,unsigned long msgno,
+			    unsigned long *size)
+{
+  unsigned long siz;
+  long i = 0;
+  char c = '\0';
+  char *s = NIL;
+  MESSAGECACHE *elt = tenex_elt (stream,msgno);
+  unsigned long ret = elt->private.special.offset +
+    elt->private.special.text.size;
+  unsigned long msiz = tenex_size (stream,msgno);
+				/* is header size known? */
+  if (!(*size = elt->private.msg.header.text.size)) {
+    lseek (LOCAL->fd,ret,L_SET);/* get to header position */
+				/* search message for LF LF */
+    for (siz = 0; siz < msiz; siz++) {
+      if (--i <= 0)		/* read another buffer as necessary */
+	read (LOCAL->fd,s = LOCAL->buf,i = min (msiz-siz,(long) MAILTMPLEN));
+				/* two newline sequence? */
+      if ((c == '\012') && (*s == '\012')) {
+				/* yes, note for later */
+	elt->private.msg.header.text.size = (*size = siz + 1);
+		
+	return ret;		/* return to caller */
+      }
+      else c = *s++;		/* next character */
+    }
+				/* header consumes entire message */
+    elt->private.msg.header.text.size = *size = msiz;
+  }
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/truncate.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,43 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Truncate a file
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	30 June 1994
+ * Last Edited:	30 August 2006
+ */
+
+/* Emulator for ftruncate() call
+ * Accepts: file descriptor
+ *	    length
+ * Returns: 0 if success, -1 if failure
+ */
+
+int ftruncate (int fd,off_t length)
+{
+  struct flock fb;
+  fb.l_whence = 0;
+  fb.l_len = 0;
+  fb.l_start = length;
+  fb.l_type = F_WRLCK;		/* write lock on file space */
+  return fcntl (fd,F_FREESP,&fb);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/tz_bsd.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,38 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	BSD-style Time Zone String
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	30 August 1994
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Append local timezone name
+ * Accepts: destination string
+ */
+
+void rfc822_timezone (char *s,void *t)
+{
+				/* append timezone from tm struct */
+  sprintf (s + strlen (s)," (%.50s)",((struct tm *) t)->tm_zone);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/tz_nul.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,36 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Null Time Zone String (unknown)
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	30 August 1994
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Append local timezone name
+ * Accepts: destination string
+ */
+
+void rfc822_timezone (char *s,void *t)
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/tz_sv4.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,39 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	SVR4-style Time Zone String
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	30 August 1994
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Append local timezone name
+ * Accepts: destination string
+ */
+
+void rfc822_timezone (char *s,void *t)
+{
+  tzset ();			/* get timezone from TZ environment stuff */
+  sprintf (s + strlen (s)," (%.50s)",
+	   tzname[daylight ? (((struct tm *) t)->tm_isdst > 0) : 0]);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/unix.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,2708 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX mail routines
+ *
+ * Author:	Mark Crispin
+ *		UW Technology
+ *		University of Washington
+ *		Seattle, WA  98195
+ *		Internet: MRC@Washington.EDU
+ *
+ * Date:	20 December 1989
+ * Last Edited:	27 March 2008
+ */
+
+
+/*				DEDICATION
+ *
+ *  This file is dedicated to my dog, Unix, also known as Yun-chan and
+ * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast.  Unix
+ * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after
+ * a two-month bout with cirrhosis of the liver.
+ *
+ *  He was a dear friend, and I miss him terribly.
+ *
+ *  Lift a leg, Yunie.  Luv ya forever!!!!
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <signal.h>
+#include "mail.h"
+#include "osdep.h"
+#include <time.h>
+#include <sys/stat.h>
+#include "unix.h"
+#include "pseudo.h"
+#include "fdstring.h"
+#include "misc.h"
+#include "dummy.h"
+
+/* UNIX I/O stream local data */
+
+typedef struct unix_local {
+  unsigned int dirty : 1;	/* disk copy needs updating */
+  unsigned int ddirty : 1;	/* double-dirty, ping becomes checkpoint */
+  unsigned int pseudo : 1;	/* uses a pseudo message */
+  unsigned int appending : 1;	/* don't mark new messages as old */
+  int fd;			/* mailbox file descriptor */
+  int ld;			/* lock file descriptor */
+  char *lname;			/* lock file name */
+  off_t filesize;		/* file size parsed */
+  time_t filetime;		/* last file time */
+  time_t lastsnarf;		/* last snarf time (for mbox driver) */
+  unsigned char *buf;		/* temporary buffer */
+  unsigned long buflen;		/* current size of temporary buffer */
+  unsigned long uid;		/* current text uid */
+  SIZEDTEXT text;		/* current text */
+  unsigned long textlen;	/* current text length */
+  char *line;			/* returned line */
+  char *linebuf;		/* line readin buffer */
+  unsigned long linebuflen;	/* current line readin buffer length */
+} UNIXLOCAL;
+
+
+/* Convenient access to local data */
+
+#define LOCAL ((UNIXLOCAL *) stream->local)
+
+
+/* UNIX protected file structure */
+
+typedef struct unix_file {
+  MAILSTREAM *stream;		/* current stream */
+  off_t curpos;			/* current file position */
+  off_t protect;		/* protected position */
+  off_t filepos;		/* current last written file position */
+  char *buf;			/* overflow buffer */
+  size_t buflen;		/* current overflow buffer length */
+  char *bufpos;			/* current buffer position */
+} UNIXFILE;
+
+/* Function prototypes */
+
+DRIVER *unix_valid (char *name);
+long unix_isvalid_fd (int fd);
+void *unix_parameters (long function,void *value);
+void unix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void unix_list (MAILSTREAM *stream,char *ref,char *pat);
+void unix_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long unix_create (MAILSTREAM *stream,char *mailbox);
+long unix_delete (MAILSTREAM *stream,char *mailbox);
+long unix_rename (MAILSTREAM *stream,char *old,char *newname);
+MAILSTREAM *unix_open (MAILSTREAM *stream);
+void unix_close (MAILSTREAM *stream,long options);
+char *unix_header (MAILSTREAM *stream,unsigned long msgno,
+		   unsigned long *length,long flags);
+long unix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags);
+char *unix_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
+		      unsigned long *length,long flags);
+void unix_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt);
+long unix_ping (MAILSTREAM *stream);
+void unix_check (MAILSTREAM *stream);
+long unix_expunge (MAILSTREAM *stream,char *sequence,long options);
+long unix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long unix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+int unix_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
+		     STRING *msg);
+int unix_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set);
+
+void unix_abort (MAILSTREAM *stream);
+char *unix_file (char *dst,char *name);
+int unix_lock (char *file,int flags,int mode,DOTLOCK *lock,int op);
+void unix_unlock (int fd,MAILSTREAM *stream,DOTLOCK *lock);
+int unix_parse (MAILSTREAM *stream,DOTLOCK *lock,int op);
+char *unix_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size);
+unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr);
+unsigned long unix_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt,
+			    unsigned long uid,long flag);
+long unix_rewrite (MAILSTREAM *stream,unsigned long *nexp,DOTLOCK *lock,
+		   long flags);
+long unix_extend (MAILSTREAM *stream,unsigned long size);
+void unix_write (UNIXFILE *f,char *s,unsigned long i);
+void unix_phys_write (UNIXFILE *f,char *buf,size_t size);
+
+/* mbox mail routines */
+
+/* Function prototypes */
+
+DRIVER *mbox_valid (char *name);
+long mbox_create (MAILSTREAM *stream,char *mailbox);
+long mbox_delete (MAILSTREAM *stream,char *mailbox);
+long mbox_rename (MAILSTREAM *stream,char *old,char *newname);
+long mbox_status (MAILSTREAM *stream,char *mbx,long flags);
+MAILSTREAM *mbox_open (MAILSTREAM *stream);
+long mbox_ping (MAILSTREAM *stream);
+void mbox_check (MAILSTREAM *stream);
+long mbox_expunge (MAILSTREAM *stream,char *sequence,long options);
+long mbox_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+
+/* UNIX mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER unixdriver = {
+  "unix",			/* driver name */
+				/* driver flags */
+  DR_LOCAL|DR_MAIL|DR_LOCKING|DR_NONEWMAILRONLY|DR_XPOINT,
+  (DRIVER *) NIL,		/* next driver */
+  unix_valid,			/* mailbox is valid for us */
+  unix_parameters,		/* manipulate parameters */
+  unix_scan,			/* scan mailboxes */
+  unix_list,			/* list mailboxes */
+  unix_lsub,			/* list subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  unix_create,			/* create mailbox */
+  unix_delete,			/* delete mailbox */
+  unix_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  unix_open,			/* open mailbox */
+  unix_close,			/* close mailbox */
+  NIL,				/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message envelopes */
+  unix_header,			/* fetch message header */
+  unix_text,			/* fetch message text */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  NIL,				/* modify flags */
+  unix_flagmsg,			/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  unix_ping,			/* ping mailbox to see if still alive */
+  unix_check,			/* check for new messages */
+  unix_expunge,			/* expunge deleted messages */
+  unix_copy,			/* copy messages to another mailbox */
+  unix_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM unixproto = {&unixdriver};
+
+				/* driver parameters */
+static long unix_fromwidget = T;
+
+/* UNIX mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *unix_valid (char *name)
+{
+  int fd;
+  DRIVER *ret = NIL;
+  char *t,file[MAILTMPLEN];
+  struct stat sbuf;
+  time_t tp[2];
+  errno = EINVAL;		/* assume invalid argument */
+				/* must be non-empty file */
+  if ((t = dummy_file (file,name)) && !stat (t,&sbuf)) {
+    if (!sbuf.st_size)errno = 0;/* empty file */
+    else if ((fd = open (file,O_RDONLY,NIL)) >= 0) {
+				/* OK if mailbox format good */
+      if (unix_isvalid_fd (fd)) ret = &unixdriver;
+      else errno = -1;		/* invalid format */
+      close (fd);		/* close the file */
+				/* \Marked status? */
+      if ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) {
+	tp[0] = sbuf.st_atime;	/* yes, preserve atime and mtime */
+	tp[1] = sbuf.st_mtime;
+	utime (file,tp);	/* set the times */
+      }
+    }
+  }
+  return ret;			/* return what we should */
+}
+
+/* UNIX mail test for valid mailbox
+ * Accepts: file descriptor
+ *	    scratch buffer
+ * Returns: T if valid, NIL otherwise
+ */
+
+long unix_isvalid_fd (int fd)
+{
+  int zn;
+  int ret = NIL;
+  char tmp[MAILTMPLEN],*s,*t,c = '\n';
+  memset (tmp,'\0',MAILTMPLEN);
+  if (read (fd,tmp,MAILTMPLEN-1) >= 0) {
+    for (s = tmp; (*s == '\r') || (*s == '\n') || (*s == ' ') || (*s == '\t');)
+      c = *s++;
+    if (c == '\n') VALID (s,t,ret,zn);
+  }
+  return ret;			/* return what we should */
+}
+
+
+/* UNIX manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *unix_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case GET_INBOXPATH:
+    if (value) ret = dummy_file ((char *) value,"INBOX");
+    break;
+  case SET_FROMWIDGET:
+    unix_fromwidget = (long) value;
+  case GET_FROMWIDGET:
+    ret = (void *) unix_fromwidget;
+    break;
+  }
+  return ret;
+}
+
+/* UNIX mail scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void unix_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+  if (stream) dummy_scan (NIL,ref,pat,contents);
+}
+
+
+/* UNIX mail list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void unix_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_list (NIL,ref,pat);
+}
+
+
+/* UNIX mail list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void unix_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+  if (stream) dummy_lsub (NIL,ref,pat);
+}
+
+/* UNIX mail create mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long unix_create (MAILSTREAM *stream,char *mailbox)
+{
+  char *s,mbx[MAILTMPLEN],tmp[MAILTMPLEN];
+  long ret = NIL;
+  int i,fd;
+  time_t ti = time (0);
+  if (!(s = dummy_file (mbx,mailbox))) {
+    sprintf (tmp,"Can't create %.80s: invalid name",mailbox);
+    MM_LOG (tmp,ERROR);
+  }
+				/* create underlying file */
+  else if (dummy_create_path (stream,s,get_dir_protection (mailbox))) {
+				/* done if dir-only or whiner */
+    if (((s = strrchr (s,'/')) && !s[1]) ||
+	mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) ret = T;
+    else if ((fd = open (mbx,O_WRONLY,
+		    (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL))) < 0) {
+      sprintf (tmp,"Can't reopen mailbox node %.80s: %s",mbx,strerror (errno));
+      MM_LOG (tmp,ERROR);
+      unlink (mbx);		/* delete the file */
+    }
+    else {			/* initialize header */
+      memset (tmp,'\0',MAILTMPLEN);
+      sprintf (tmp,"From %s %sDate: ",pseudo_from,ctime (&ti));
+      rfc822_fixed_date (s = tmp + strlen (tmp));
+				/* write the pseudo-header */
+      sprintf (s += strlen (s),
+	       "\nFrom: %s <%s@%s>\nSubject: %s\nX-IMAP: %010lu 0000000000",
+	       pseudo_name,pseudo_from,mylocalhost (),pseudo_subject,
+	       (unsigned long) ti);
+      for (i = 0; i < NUSERFLAGS; ++i) if (default_user_flag (i))
+	sprintf (s += strlen (s)," %s",default_user_flag (i));
+      sprintf (s += strlen (s),"\nStatus: RO\n\n%s\n\n",pseudo_msg);
+      if (write (fd,tmp,strlen (tmp)) > 0) ret = T;
+      else {
+	sprintf (tmp,"Can't initialize mailbox node %.80s: %s",mbx,
+		 strerror (errno));
+	MM_LOG (tmp,ERROR);
+	unlink (mbx);		/* delete the file */
+      }
+      close (fd);		/* close file */
+    }
+  }
+				/* set proper protections */
+  return ret ? set_mbx_protections (mailbox,mbx) : NIL;
+}
+
+/* UNIX mail delete mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long unix_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return unix_rename (stream,mailbox,NIL);
+}
+
+
+/* UNIX mail rename mailbox
+ * Accepts: MAIL stream
+ *	    old mailbox name
+ *	    new mailbox name (or NIL for delete)
+ * Returns: T on success, NIL on failure
+ */
+
+long unix_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  long ret = NIL;
+  char c,*s = NIL;
+  char tmp[MAILTMPLEN],file[MAILTMPLEN],lock[MAILTMPLEN];
+  DOTLOCK lockx;
+  int fd,ld;
+  long i;
+  struct stat sbuf;
+  MM_CRITICAL (stream);		/* get the c-client lock */
+  if (!dummy_file (file,old) ||
+      (newname && (!((s = mailboxfile (tmp,newname)) && *s) ||
+		   ((s = strrchr (tmp,'/')) && !s[1]))))
+    sprintf (tmp,newname ?
+	     "Can't rename mailbox %.80s to %.80s: invalid name" :
+	     "Can't delete mailbox %.80s: invalid name",
+	     old,newname);
+				/* lock out other c-clients */
+  else if ((ld = lockname (lock,file,LOCK_EX|LOCK_NB,&i)) < 0)
+    sprintf (tmp,"Mailbox %.80s is in use by another process",old);
+
+  else {
+    if ((fd = unix_lock (file,O_RDWR,
+			 (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
+			 &lockx,LOCK_EX)) < 0)
+      sprintf (tmp,"Can't lock mailbox %.80s: %s",old,strerror (errno));
+    else {
+      if (newname) {		/* want rename? */
+				/* found superior to destination name? */
+	if (s = strrchr (s,'/')) {
+	  c = *++s;		/* remember first character of inferior */
+	  *s = '\0';		/* tie off to get just superior */
+				/* name doesn't exist, create it */
+	  if ((stat (tmp,&sbuf) || ((sbuf.st_mode & S_IFMT) != S_IFDIR)) &&
+	      !dummy_create_path (stream,tmp,get_dir_protection (newname))) {
+	    unix_unlock (fd,NIL,&lockx);
+	    unix_unlock (ld,NIL,NIL);
+	    unlink (lock);
+	    MM_NOCRITICAL (stream);
+	    return ret;		/* return success or failure */
+	  }
+	  *s = c;		/* restore full name */
+	}
+	if (rename (file,tmp))
+	  sprintf (tmp,"Can't rename mailbox %.80s to %.80s: %s",old,newname,
+		   strerror (errno));
+	else ret = T;		/* set success */
+      }
+      else if (unlink (file))
+	sprintf (tmp,"Can't delete mailbox %.80s: %s",old,strerror (errno));
+      else ret = T;		/* set success */
+      unix_unlock (fd,NIL,&lockx);
+    }
+    unix_unlock (ld,NIL,NIL);	/* flush the lock */
+    unlink (lock);
+  }
+  MM_NOCRITICAL (stream);	/* no longer critical */
+  if (!ret) MM_LOG (tmp,ERROR);	/* log error */
+  return ret;			/* return success or failure */
+}
+
+/* UNIX mail open
+ * Accepts: Stream to open
+ * Returns: Stream on success, NIL on failure
+ */
+
+MAILSTREAM *unix_open (MAILSTREAM *stream)
+{
+  long i;
+  int fd;
+  char tmp[MAILTMPLEN];
+  DOTLOCK lock;
+  long retry;
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return user_flags (&unixproto);
+  retry = stream->silent ? 1 : KODRETRY;
+  if (stream->local) fatal ("unix recycle stream");
+  stream->local = memset (fs_get (sizeof (UNIXLOCAL)),0,sizeof (UNIXLOCAL));
+				/* note if an INBOX or not */
+  stream->inbox = !compare_cstring (stream->mailbox,"INBOX");
+				/* canonicalize the stream mailbox name */
+  if (!dummy_file (tmp,stream->mailbox)) {
+    sprintf (tmp,"Can't open - invalid name: %.80s",stream->mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+				/* flush old name */
+  fs_give ((void **) &stream->mailbox);
+				/* save canonical name */
+  stream->mailbox = cpystr (tmp);
+  LOCAL->fd = LOCAL->ld = -1;	/* no file or state locking yet */
+  LOCAL->buf = (char *) fs_get (CHUNKSIZE);
+  LOCAL->buflen = CHUNKSIZE - 1;
+  LOCAL->text.data = (unsigned char *) fs_get (CHUNKSIZE);
+  LOCAL->text.size = CHUNKSIZE - 1;
+  LOCAL->linebuf = (char *) fs_get (CHUNKSIZE);
+  LOCAL->linebuflen = CHUNKSIZE - 1;
+  stream->sequence++;		/* bump sequence number */
+
+				/* make lock for read/write access */
+  if (!stream->rdonly) while (retry) {
+				/* try to lock file */
+    if ((fd = lockname (tmp,stream->mailbox,LOCK_EX|LOCK_NB,&i)) < 0) {
+				/* suppressing kiss-of-death? */
+      if (stream->nokod) retry = 0;
+				/* no, first time through? */
+      else if (retry-- == KODRETRY) {
+				/* learned other guy's PID and can signal? */
+	if (i && !kill ((int) i,SIGUSR2)) {
+	  sprintf (tmp,"Trying to get mailbox lock from process %ld",i);
+	  MM_LOG (tmp,WARN);
+	}
+	else retry = 0;		/* give up */
+      }
+      if (!stream->silent) {	/* nothing if silent stream */
+	if (retry) sleep (1);	/* wait a second before trying again */
+	else MM_LOG ("Mailbox is open by another process, access is readonly",
+		     WARN);
+      }
+    }
+    else {			/* got the lock, nobody else can alter state */
+      LOCAL->ld = fd;		/* note lock's fd and name */
+      LOCAL->lname = cpystr (tmp);
+				/* make sure mode OK (don't use fchmod()) */
+      chmod (LOCAL->lname,(long) mail_parameters (NIL,GET_LOCKPROTECTION,NIL));
+      if (stream->silent) i = 0;/* silent streams won't accept KOD */
+      else {			/* note our PID in the lock */
+	sprintf (tmp,"%d",getpid ());
+	write (fd,tmp,(i = strlen (tmp))+1);
+      }
+      ftruncate (fd,i);		/* make sure tied off */
+      fsync (fd);		/* make sure it's available */
+      retry = 0;		/* no more need to try */
+    }
+  }
+
+				/* parse mailbox */
+  stream->nmsgs = stream->recent = 0;
+				/* will we be able to get write access? */
+  if ((LOCAL->ld >= 0) && access (stream->mailbox,W_OK) && (errno == EACCES)) {
+    MM_LOG ("Can't get write access to mailbox, access is readonly",WARN);
+    flock (LOCAL->ld,LOCK_UN);	/* release the lock */
+    close (LOCAL->ld);		/* close the lock file */
+    LOCAL->ld = -1;		/* no more lock fd */
+    unlink (LOCAL->lname);	/* delete it */
+  }
+				/* reset UID validity */
+  stream->uid_validity = stream->uid_last = 0;
+  if (stream->silent && !stream->rdonly && (LOCAL->ld < 0))
+    unix_abort (stream);	/* abort if can't get RW silent stream */
+				/* parse mailbox */
+  else if (unix_parse (stream,&lock,LOCK_SH)) {
+    unix_unlock (LOCAL->fd,stream,&lock);
+    mail_unlock (stream);
+    MM_NOCRITICAL (stream);	/* done with critical */
+  }
+  if (!LOCAL) return NIL;	/* failure if stream died */
+				/* make sure upper level knows readonly */
+  stream->rdonly = (LOCAL->ld < 0);
+				/* notify about empty mailbox */
+  if (!(stream->nmsgs || stream->silent)) MM_LOG ("Mailbox is empty",NIL);
+  if (!stream->rdonly) {	/* flags stick if readwrite */
+    stream->perm_seen = stream->perm_deleted =
+      stream->perm_flagged = stream->perm_answered = stream->perm_draft = T;
+    if (!stream->uid_nosticky) {/* users with lives get permanent keywords */
+      stream->perm_user_flags = 0xffffffff;
+				/* and maybe can create them too! */
+      stream->kwd_create = stream->user_flags[NUSERFLAGS-1] ? NIL : T;
+    }
+  }
+  return stream;		/* return stream alive to caller */
+}
+
+
+/* UNIX mail close
+ * Accepts: MAIL stream
+ *	    close options
+ */
+
+void unix_close (MAILSTREAM *stream,long options)
+{
+  int silent = stream->silent;
+  stream->silent = T;		/* go silent */
+				/* expunge if requested */
+  if (options & CL_EXPUNGE) unix_expunge (stream,NIL,NIL);
+				/* else dump final checkpoint */
+  else if (LOCAL->dirty) unix_check (stream);
+  stream->silent = silent;	/* restore old silence state */
+  unix_abort (stream);		/* now punt the file and local data */
+}
+
+/* UNIX mail fetch message header
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned header text length
+ *	    option flags
+ * Returns: message header in RFC822 format
+ */
+
+				/* lines to filter from header */
+static STRINGLIST *unix_hlines = NIL;
+
+char *unix_header (MAILSTREAM *stream,unsigned long msgno,
+		   unsigned long *length,long flags)
+{
+  MESSAGECACHE *elt;
+  unsigned char *s,*t,*tl;
+  *length = 0;			/* default to empty */
+  if (flags & FT_UID) return "";/* UID call "impossible" */
+  elt = mail_elt (stream,msgno);/* get cache */
+  if (!unix_hlines) {		/* once only code */
+    STRINGLIST *lines = unix_hlines = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "Status"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-Status"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-Keywords"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-UID"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-IMAP"));
+    lines = lines->next = mail_newstringlist ();
+    lines->text.size = strlen ((char *) (lines->text.data =
+					 (unsigned char *) "X-IMAPbase"));
+  }
+				/* go to header position */
+  lseek (LOCAL->fd,elt->private.special.offset +
+	 elt->private.msg.header.offset,L_SET);
+
+  if (flags & FT_INTERNAL) {	/* initial data OK? */
+    if (elt->private.msg.header.text.size > LOCAL->buflen) {
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
+				     elt->private.msg.header.text.size) + 1);
+    }
+				/* read message */
+    read (LOCAL->fd,LOCAL->buf,elt->private.msg.header.text.size);
+				/* got text, tie off string */
+    LOCAL->buf[*length = elt->private.msg.header.text.size] = '\0';
+				/* squeeze out CRs (in case from PC) */
+    for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++)
+      if (*t != '\r') *s++ = *t;
+    *s = '\0';
+    *length = s - LOCAL->buf;	/* adjust length */
+  }
+  else {			/* need to make a CRLF version */
+    read (LOCAL->fd,s = (char *) fs_get (elt->private.msg.header.text.size+1),
+	  elt->private.msg.header.text.size);
+				/* tie off string, and convert to CRLF */
+    s[elt->private.msg.header.text.size] = '\0';
+    *length = strcrlfcpy (&LOCAL->buf,&LOCAL->buflen,s,
+			  elt->private.msg.header.text.size);
+    fs_give ((void **) &s);	/* free readin buffer */
+				/* squeeze out spurious CRs */
+    for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++)
+      if ((*t != '\r') || (t[1] == '\n')) *s++ = *t;
+    *s = '\0';
+    *length = s - LOCAL->buf;	/* adjust length */
+  }
+  *length = mail_filter (LOCAL->buf,*length,unix_hlines,FT_NOT);
+  return (char *) LOCAL->buf;	/* return processed copy */
+}
+
+/* UNIX mail fetch message text
+ * Accepts: MAIL stream
+ *	    message # to fetch
+ *	    pointer to returned stringstruct
+ *	    option flags
+ * Returns: T on success, NIL if failure
+ */
+
+long unix_text (MAILSTREAM *stream,unsigned long msgno,STRING *bs,long flags)
+{
+  char *s;
+  unsigned long i;
+  MESSAGECACHE *elt;
+				/* UID call "impossible" */
+  if (flags & FT_UID) return NIL;
+  elt = mail_elt (stream,msgno);/* get cache element */
+				/* if message not seen */
+  if (!(flags & FT_PEEK) && !elt->seen) {
+				/* mark message seen and dirty */
+    elt->seen = elt->private.dirty = LOCAL->dirty = T;
+    MM_FLAGS (stream,msgno);
+  }
+  s = unix_text_work (stream,elt,&i,flags);
+  INIT (bs,mail_string,s,i);	/* set up stringstruct */
+  return T;			/* success */
+}
+
+/* UNIX mail fetch message text worker routine
+ * Accepts: MAIL stream
+ *	    message cache element
+ *	    pointer to returned header text length
+ *	    option flags
+ */
+
+char *unix_text_work (MAILSTREAM *stream,MESSAGECACHE *elt,
+		      unsigned long *length,long flags)
+{
+  FDDATA d;
+  STRING bs;
+  unsigned char c,*s,*t,*tl,tmp[CHUNKSIZE];
+				/* go to text position */
+  lseek (LOCAL->fd,elt->private.special.offset +
+	 elt->private.msg.text.offset,L_SET);
+  if (flags & FT_INTERNAL) {	/* initial data OK? */
+    if (elt->private.msg.text.text.size > LOCAL->buflen) {
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get ((LOCAL->buflen =
+				     elt->private.msg.text.text.size) + 1);
+    }
+				/* read message */
+    read (LOCAL->fd,LOCAL->buf,elt->private.msg.text.text.size);
+				/* got text, tie off string */
+    LOCAL->buf[*length = elt->private.msg.text.text.size] = '\0';
+				/* squeeze out CRs (in case from PC) */
+    for (s = t = LOCAL->buf,tl = LOCAL->buf + *length; t < tl; t++)
+      if (*t != '\r') *s++ = *t;
+    *s = '\0';
+    *length = s - LOCAL->buf;	/* adjust length */
+    return (char *) LOCAL->buf;
+  }
+
+				/* have it cached already? */
+  if (elt->private.uid != LOCAL->uid) {
+				/* not cached, cache it now */
+    LOCAL->uid = elt->private.uid;
+				/* is buffer big enough? */
+    if (elt->rfc822_size > LOCAL->text.size) {
+      /* excessively conservative, but the right thing is too hard to do */
+      fs_give ((void **) &LOCAL->text.data);
+      LOCAL->text.data = (unsigned char *)
+	fs_get ((LOCAL->text.size = elt->rfc822_size) + 1);
+    }
+    d.fd = LOCAL->fd;		/* yes, set up file descriptor */
+    d.pos = elt->private.special.offset + elt->private.msg.text.offset;
+    d.chunk = tmp;		/* initial buffer chunk */
+    d.chunksize = CHUNKSIZE;	/* file chunk size */
+    INIT (&bs,fd_string,&d,elt->private.msg.text.text.size);
+    for (s = (char *) LOCAL->text.data; SIZE (&bs);) switch (c = SNX (&bs)) {
+    case '\r':			/* carriage return seen */
+      break;
+    case '\n':
+      *s++ = '\r';		/* insert a CR */
+    default:
+      *s++ = c;			/* copy characters */
+    }
+    *s = '\0';			/* tie off buffer */
+				/* calculate length of cached data */
+    LOCAL->textlen = s - LOCAL->text.data;
+  }
+  *length = LOCAL->textlen;	/* return from cache */
+  return (char *) LOCAL->text.data;
+}
+
+/* UNIX per-message modify flag
+ * Accepts: MAIL stream
+ *	    message cache element
+ */
+
+void unix_flagmsg (MAILSTREAM *stream,MESSAGECACHE *elt)
+{
+				/* only after finishing */
+  if (elt->valid) elt->private.dirty = LOCAL->dirty = T;
+}
+
+
+/* UNIX mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ */
+
+long unix_ping (MAILSTREAM *stream)
+{
+  DOTLOCK lock;
+  struct stat sbuf;
+  long reparse;
+				/* big no-op if not readwrite */
+  if (LOCAL && (LOCAL->ld >= 0) && !stream->lock) {
+    if (stream->rdonly) {	/* does he want to give up readwrite? */
+				/* checkpoint if we changed something */
+      if (LOCAL->dirty) unix_check (stream);
+      flock (LOCAL->ld,LOCK_UN);/* release readwrite lock */
+      close (LOCAL->ld);	/* close the readwrite lock file */
+      LOCAL->ld = -1;		/* no more readwrite lock fd */
+      unlink (LOCAL->lname);	/* delete the readwrite lock file */
+    }
+    else {			/* see if need to reparse */
+      if (!(reparse = (long) mail_parameters (NIL,GET_NETFSSTATBUG,NIL))) {
+				/* get current mailbox size */
+	if (LOCAL->fd >= 0) fstat (LOCAL->fd,&sbuf);
+	else if (stat (stream->mailbox,&sbuf)) {
+	  sprintf (LOCAL->buf,"Mailbox stat failed, aborted: %s",
+		   strerror (errno));
+	  MM_LOG (LOCAL->buf,ERROR);
+	  unix_abort (stream);
+	  return NIL;
+	}
+	reparse = (sbuf.st_size != LOCAL->filesize);
+      }
+				/* parse if mailbox changed */
+      if ((LOCAL->ddirty || reparse) && unix_parse (stream,&lock,LOCK_EX)) {
+				/* force checkpoint if double-dirty */
+	if (LOCAL->ddirty) unix_rewrite (stream,NIL,&lock,NIL);
+				/* unlock mailbox */
+	else unix_unlock (LOCAL->fd,stream,&lock);
+	mail_unlock (stream);	/* and stream */
+	MM_NOCRITICAL (stream);	/* done with critical */
+      }
+    }
+  }
+  return LOCAL ? LONGT : NIL;	/* return if still alive */
+}
+
+/* UNIX mail check mailbox
+ * Accepts: MAIL stream
+ */
+
+void unix_check (MAILSTREAM *stream)
+{
+  DOTLOCK lock;
+				/* parse and lock mailbox */
+  if (LOCAL && (LOCAL->ld >= 0) && !stream->lock &&
+      unix_parse (stream,&lock,LOCK_EX)) {
+				/* any unsaved changes? */
+    if (LOCAL->dirty && unix_rewrite (stream,NIL,&lock,NIL)) {
+      if (!stream->silent) MM_LOG ("Checkpoint completed",NIL);
+    }
+				/* no checkpoint needed, just unlock */
+    else unix_unlock (LOCAL->fd,stream,&lock);
+    mail_unlock (stream);	/* unlock the stream */
+    MM_NOCRITICAL (stream);	/* done with critical */
+  }
+}
+
+
+/* UNIX mail expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long unix_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  long ret;
+  unsigned long i;
+  DOTLOCK lock;
+  char *msg = NIL;
+				/* parse and lock mailbox */
+  if (ret = (sequence ? ((options & EX_UID) ?
+			 mail_uid_sequence (stream,sequence) :
+			 mail_sequence (stream,sequence)) : LONGT) &&
+      LOCAL && (LOCAL->ld >= 0) && !stream->lock &&
+      unix_parse (stream,&lock,LOCK_EX)) {
+				/* check expunged messages if not dirty */
+    for (i = 1; !LOCAL->dirty && (i <= stream->nmsgs); i++) {
+      MESSAGECACHE *elt = mail_elt (stream,i);
+      if (mail_elt (stream,i)->deleted) LOCAL->dirty = T;
+    }
+    if (!LOCAL->dirty) {	/* not dirty and no expunged messages */
+      unix_unlock (LOCAL->fd,stream,&lock);
+      msg = "No messages deleted, so no update needed";
+    }
+    else if (unix_rewrite (stream,&i,&lock,sequence ? LONGT : NIL)) {
+      if (i) sprintf (msg = LOCAL->buf,"Expunged %lu messages",i);
+      else msg = "Mailbox checkpointed, but no messages expunged";
+    }
+				/* rewrite failed */
+    else unix_unlock (LOCAL->fd,stream,&lock);
+    mail_unlock (stream);	/* unlock the stream */
+    MM_NOCRITICAL (stream);	/* done with critical */
+    if (msg && !stream->silent) MM_LOG (msg,NIL);
+  }
+  else if (!stream->silent) MM_LOG("Expunge ignored on readonly mailbox",WARN);
+  return ret;
+}
+
+/* UNIX mail copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    copy options
+ * Returns: T if copy successful, else NIL
+ */
+
+long unix_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  struct stat sbuf;
+  int fd;
+  char *s,file[MAILTMPLEN];
+  DOTLOCK lock;
+  time_t tp[2];
+  unsigned long i,j;
+  MESSAGECACHE *elt;
+  long ret = T;
+  mailproxycopy_t pc =
+    (mailproxycopy_t) mail_parameters (stream,GET_MAILPROXYCOPY,NIL);
+  copyuid_t cu = (copyuid_t) (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ?
+			      NIL : mail_parameters (NIL,GET_COPYUID,NIL));
+  SEARCHSET *source = cu ? mail_newsearchset () : NIL;
+  SEARCHSET *dest = cu ? mail_newsearchset () : NIL;
+  MAILSTREAM *tstream = NIL;
+  DRIVER *d;
+  for (d = (DRIVER *) mail_parameters (NIL,GET_DRIVERS,NIL);
+       (d && strcmp (d->name,"mbox") && !(d->flags & DR_DISABLE));
+       d = d->next);		/* see if mbox driver active */
+  if (!((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+	mail_sequence (stream,sequence))) return NIL;
+				/* make sure destination is valid */
+  if (!((d && mbox_valid (mailbox) && (mailbox = "mbox")) ||
+	unix_valid (mailbox) || !errno))
+    switch (errno) {
+    case ENOENT:		/* no such file? */
+      if (compare_cstring (mailbox,"INBOX")) {
+	MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before copy",NIL);
+	return NIL;
+      }
+      if (pc) return (*pc) (stream,sequence,mailbox,options);
+      unix_create (NIL,"INBOX");/* create empty INBOX */
+    case EACCES:		/* file protected */
+      sprintf (LOCAL->buf,"Can't access destination: %.80s",mailbox);
+      MM_LOG (LOCAL->buf,ERROR);
+      return NIL;
+    case EINVAL:
+      if (pc) return (*pc) (stream,sequence,mailbox,options);
+      sprintf (LOCAL->buf,"Invalid UNIX-format mailbox name: %.80s",mailbox);
+      MM_LOG (LOCAL->buf,ERROR);
+      return NIL;
+    default:
+      if (pc) return (*pc) (stream,sequence,mailbox,options);
+      sprintf (LOCAL->buf,"Not a UNIX-format mailbox: %.80s",mailbox);
+      MM_LOG (LOCAL->buf,ERROR);
+      return NIL;
+    }
+
+				/* try to open rewrite for UIDPLUS */
+  if ((tstream = mail_open_work (&unixdriver,NIL,mailbox,
+				 OP_SILENT|OP_NOKOD)) && tstream->rdonly)
+    tstream = mail_close (tstream);
+  if (cu && !tstream) {		/* wanted a COPYUID? */
+    sprintf (LOCAL->buf,"Unable to write-open mailbox for COPYUID: %.80s",
+	     mailbox);
+    MM_LOG (LOCAL->buf,WARN);
+    cu = NIL;			/* don't try to do COPYUID */
+  }
+  LOCAL->buf[0] = '\0';
+  MM_CRITICAL (stream);		/* go critical */
+  if ((fd = unix_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND,
+		       (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
+		       &lock,LOCK_EX)) < 0) {
+    MM_NOCRITICAL (stream);	/* done with critical */
+    sprintf (LOCAL->buf,"Can't open destination mailbox: %s",strerror (errno));
+    MM_LOG (LOCAL->buf,ERROR);/* log the error */
+    return NIL;			/* failed */
+  }
+  fstat (fd,&sbuf);		/* get current file size */
+				/* write all requested messages to mailbox */
+  for (i = 1; ret && (i <= stream->nmsgs); i++)
+    if ((elt = mail_elt (stream,i))->sequence) {
+      lseek (LOCAL->fd,elt->private.special.offset,L_SET);
+      read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size);
+      if (write (fd,LOCAL->buf,elt->private.special.text.size) < 0) ret = NIL;
+      else {			/* internal header succeeded */
+	s = unix_header (stream,i,&j,FT_INTERNAL);
+				/* header size, sans trailing newline */
+	if (j && (s[j - 2] == '\n')) j--;
+	if (write (fd,s,j) < 0) ret = NIL;
+	else {			/* message header succeeded */
+	  j = tstream ?		/* write UIDPLUS data if have readwrite */
+	    unix_xstatus (stream,LOCAL->buf,elt,++(tstream->uid_last),LONGT) :
+	    unix_xstatus (stream,LOCAL->buf,elt,NIL,NIL);
+	  if (write (fd,LOCAL->buf,j) < 0) ret = NIL;
+	  else {		/* message status succeeded */
+	    s = unix_text_work (stream,elt,&j,FT_INTERNAL);
+	    if ((write (fd,s,j) < 0) || (write (fd,"\n",1) < 0)) ret = NIL;
+	    else if (cu) {	/* need to pass back new UID? */
+	      mail_append_set (source,mail_uid (stream,i));
+	      mail_append_set (dest,tstream->uid_last);
+	    }
+	  }
+	}
+      }
+    }
+
+  if (!ret || fsync (fd)) {	/* force out the update */
+    sprintf (LOCAL->buf,"Message copy failed: %s",strerror (errno));
+    ftruncate (fd,sbuf.st_size);
+    ret = NIL;
+  }
+				/* force UIDVALIDITY assignment now */
+  if (tstream && !tstream->uid_validity) tstream->uid_validity = time (0);
+				/* return sets if doing COPYUID */
+  if (cu && ret) (*cu) (stream,mailbox,tstream->uid_validity,source,dest);
+  else {			/* flush any sets we may have built */
+    mail_free_searchset (&source);
+    mail_free_searchset (&dest);
+  }
+  tp[1] = time (0);		/* set mtime to now */
+  if (ret) tp[0] = tp[1] - 1;	/* set atime to now-1 if successful copy */
+  else tp[0] =			/* else preserve \Marked status */
+	 ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ?
+	 sbuf.st_atime : tp[1];
+  utime (file,tp);		/* set the times */
+  unix_unlock (fd,NIL,&lock);	/* unlock and close mailbox */
+  if (tstream) {		/* update last UID if we can */
+    UNIXLOCAL *local = (UNIXLOCAL *) tstream->local;
+    local->dirty = T;		/* do a rewrite */
+    local->appending = T;	/* but not at the cost of marking as old */
+    tstream = mail_close (tstream);
+  }
+				/* log the error */
+  if (!ret) MM_LOG (LOCAL->buf,ERROR);
+				/* delete if requested message */
+  else if (options & CP_MOVE) for (i = 1; i <= stream->nmsgs; i++)
+    if ((elt = mail_elt (stream,i))->sequence)
+      elt->deleted = elt->private.dirty = LOCAL->dirty = T;
+  MM_NOCRITICAL (stream);	/* release critical */
+  return ret;
+}
+
+/* UNIX mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+#define BUFLEN 8*MAILTMPLEN
+
+long unix_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  struct stat sbuf;
+  int fd;
+  unsigned long i;
+  char *flags,*date,buf[BUFLEN],tmp[MAILTMPLEN],file[MAILTMPLEN];
+  time_t tp[2];
+  FILE *sf,*df;
+  MESSAGECACHE elt;
+  DOTLOCK lock;
+  STRING *message;
+  unsigned long uidlocation = 0;
+  appenduid_t au = (appenduid_t)
+    (mail_parameters (NIL,GET_USERHASNOLIFE,NIL) ? NIL :
+     mail_parameters (NIL,GET_APPENDUID,NIL));
+  SEARCHSET *dst = au ? mail_newsearchset () : NIL;
+  long ret = LONGT;
+  MAILSTREAM *tstream = NIL;
+  if (!stream) {		/* stream specified? */
+    stream = &unixproto;	/* no, default stream to prototype */
+    for (i = 0; i < NUSERFLAGS && stream->user_flags[i]; ++i)
+      fs_give ((void **) &stream->user_flags[i]);
+  }
+  if (!unix_valid (mailbox)) switch (errno) {
+  case ENOENT:			/* no such file? */
+    if (compare_cstring (mailbox,"INBOX")) {
+      MM_NOTIFY (stream,"[TRYCREATE] Must create mailbox before append",NIL);
+      return NIL;
+    }
+    unix_create (NIL,"INBOX");	/* create empty INBOX */
+  case 0:			/* merely empty file? */
+    tstream = stream;
+    break;
+  case EACCES:			/* file protected */
+    sprintf (tmp,"Can't access destination: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  case EINVAL:
+    sprintf (tmp,"Invalid UNIX-format mailbox name: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  default:
+    sprintf (tmp,"Not a UNIX-format mailbox: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+				/* get sniffing stream for keywords */
+  else if (!(tstream = mail_open (NIL,mailbox,
+				  OP_READONLY|OP_SILENT|OP_NOKOD|OP_SNIFF))) {
+    sprintf (tmp,"Unable to examine mailbox for APPEND: %.80s",mailbox);
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+
+				/* get first message */
+  if (!MM_APPEND (af) (tstream,data,&flags,&date,&message)) return NIL;
+  if (!(sf = tmpfile ())) {	/* must have scratch file */
+    sprintf (tmp,".%lx.%lx",(unsigned long) time (0),(unsigned long)getpid ());
+    if (!stat (tmp,&sbuf) || !(sf = fopen (tmp,"wb+"))) {
+      sprintf (tmp,"Unable to create scratch file: %.80s",strerror (errno));
+      MM_LOG (tmp,ERROR);
+      return NIL;
+    }
+    unlink (tmp);
+  }
+  do {				/* parse date */
+    if (!date) rfc822_date (date = tmp);
+    if (!mail_parse_date (&elt,date)) {
+      sprintf (tmp,"Bad date in append: %.80s",date);
+      MM_LOG (tmp,ERROR);
+    }
+    else {			/* user wants to suppress time zones? */
+      if (mail_parameters (NIL,GET_NOTIMEZONES,NIL)) {
+	time_t when = mail_longdate (&elt);
+	date = ctime (&when);	/* use traditional date */
+      }
+				/* use POSIX-style date */
+      else date = mail_cdate (tmp,&elt);
+      if (!SIZE (message)) MM_LOG ("Append of zero-length message",ERROR);
+      else if (!unix_collect_msg (tstream,sf,flags,date,message)) {
+	sprintf (tmp,"Error writing scratch file: %.80s",strerror (errno));
+	MM_LOG (tmp,ERROR);
+      }
+				/* get next message */
+      else if (MM_APPEND (af) (tstream,data,&flags,&date,&message)) continue;
+    }
+    fclose (sf);		/* punt scratch file */
+    return NIL;			/* give up */
+  } while (message);		/* until no more messages */
+  if (fflush (sf)) {
+    sprintf (tmp,"Error finishing scratch file: %.80s",strerror (errno));
+    MM_LOG (tmp,ERROR);
+    fclose (sf);		/* punt scratch file */
+    return NIL;			/* give up */
+  }
+  i = ftell (sf);		/* size of scratch file */
+				/* close sniffing stream */
+  if (tstream != stream) tstream = mail_close (tstream);
+
+  MM_CRITICAL (stream);		/* go critical */
+				/* try to open readwrite for UIDPLUS */
+  if ((tstream = mail_open_work (&unixdriver,NIL,mailbox,
+				 OP_SILENT|OP_NOKOD)) && tstream->rdonly)
+    tstream = mail_close (tstream);
+  if (au && !tstream) {		/* wanted an APPENDUID? */
+    sprintf (tmp,"Unable to re-open mailbox for APPENDUID: %.80s",mailbox);
+    MM_LOG (tmp,WARN);
+    au = NIL;
+  }
+  if (((fd = unix_lock (dummy_file (file,mailbox),O_WRONLY|O_APPEND,
+		       (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
+			&lock,LOCK_EX)) < 0) ||
+      !(df = fdopen (fd,"ab"))) {
+    MM_NOCRITICAL (stream);	/* done with critical */
+    sprintf (tmp,"Can't open append mailbox: %s",strerror (errno));
+    MM_LOG (tmp,ERROR);
+    return NIL;
+  }
+  fstat (fd,&sbuf);		/* get current file size */
+  rewind (sf);
+  tp[1] = time (0);		/* set mtime to now */
+				/* write all messages */
+  if (!unix_append_msgs (tstream,sf,df,au ? dst : NIL) ||
+      (fflush (df) == EOF) || fsync (fd)) {
+    sprintf (buf,"Message append failed: %s",strerror (errno));
+    MM_LOG (buf,ERROR);
+    ftruncate (fd,sbuf.st_size);
+    tp[0] =			/* preserve \Marked status */
+      ((sbuf.st_ctime > sbuf.st_atime) || (sbuf.st_mtime > sbuf.st_atime)) ?
+      sbuf.st_atime : tp[1];
+    ret = NIL;			/* return error */
+  }
+  else tp[0] = tp[1] - 1;	/* set atime to now-1 if successful copy */
+  utime (file,tp);		/* set the times */
+  fclose (sf);			/* done with scratch file */
+				/* force UIDVALIDITY assignment now */
+  if (tstream && !tstream->uid_validity) tstream->uid_validity = time (0);
+				/* return sets if doing APPENDUID */
+  if (au && ret) (*au) (mailbox,tstream->uid_validity,dst);
+  else mail_free_searchset (&dst);
+  unix_unlock (fd,NIL,&lock);	/* unlock and close mailbox */
+  fclose (df);			/* note that unix_unlock() released the fd */
+  if (tstream) {		/* update last UID if we can */
+    UNIXLOCAL *local = (UNIXLOCAL *) tstream->local;
+    local->dirty = T;		/* do a rewrite */
+    local->appending = T;	/* but not at the cost of marking as old */
+    tstream = mail_close (tstream);
+  }
+  MM_NOCRITICAL (stream);	/* release critical */
+  return ret;
+}
+
+/* Collect and write single message to append scratch file
+ * Accepts: MAIL stream
+ *	    scratch file
+ *	    flags
+ *	    date
+ *	    message stringstruct
+ * Returns: NIL if write error, else T
+ */
+
+int unix_collect_msg (MAILSTREAM *stream,FILE *sf,char *flags,char *date,
+		     STRING *msg)
+{
+  unsigned char *s,*t;
+  unsigned long uf;
+  long f = mail_parse_flags (stream,flags,&uf);
+				/* write metadata, note date ends with NL */
+  if (fprintf (sf,"%ld %lu %s",f,SIZE (msg) + 1,date) < 0) return NIL;
+  while (uf)			/* write user flags */    
+    if ((s = stream->user_flags[find_rightmost_bit (&uf)]) &&
+	(fprintf (sf," %s",s) < 0)) return NIL;
+  if (putc ('\n',sf) == EOF) return NIL;
+  while (SIZE (msg)) {		/* copy text to scratch file */
+    for (s = (unsigned char *) msg->curpos, t = s + msg->cursize; s < t; ++s)
+      if (!*s) *s = 0x80;	/* disallow NUL */
+				/* write buffered text */
+    if (fwrite (msg->curpos,1,msg->cursize,sf) == msg->cursize)
+      SETPOS (msg,GETPOS (msg) + msg->cursize);
+    else return NIL;		/* failed */
+  }
+				/* write trailing newline and return */
+  return (putc ('\n',sf) == EOF) ? NIL : T;
+}
+
+/* Append messages from scratch file to mailbox
+ * Accepts: MAIL stream
+ *	    source file
+ *	    destination file
+ *	    uidset to update if non-NIL
+ * Returns: T if success, NIL if failure
+ */
+
+int unix_append_msgs (MAILSTREAM *stream,FILE *sf,FILE *df,SEARCHSET *set)
+{
+  int ti,zn,c;
+  long f;
+  unsigned long i,j;
+  char *x,tmp[MAILTMPLEN];
+  int hdrp = T;
+				/* get message metadata line */
+  while (fgets (tmp,MAILTMPLEN,sf)) {
+    if (!(isdigit (tmp[0]) && strchr (tmp,'\n'))) return NIL;
+    f = strtol (tmp,&x,10);	/* get flags */
+    if (!((*x++ == ' ') && isdigit (*x))) return NIL;
+    i = strtoul (x,&x,10);	/* get message size */
+    if ((*x++ != ' ') ||	/* build initial header */
+	(fprintf (df,"From %s@%s %sStatus: ",myusername(),mylocalhost(),x)<0)||
+	(f&fSEEN && (putc ('R',df) == EOF)) ||
+	(fputs ("\nX-Status: ",df) == EOF) ||
+	(f&fDELETED && (putc ('D',df) == EOF)) ||
+	(f&fFLAGGED && (putc ('F',df) == EOF)) ||
+	(f&fANSWERED && (putc ('A',df) == EOF)) ||
+	(f&fDRAFT && (putc ('T',df) == EOF)) ||
+	(fputs ("\nX-Keywords:",df) == EOF)) return NIL;
+				/* copy keywords */
+    while ((c = getc (sf)) != '\n') switch (c) {
+    case EOF:
+      return NIL;
+    default:
+      if (putc (c,df) == EOF) return NIL;
+    }
+    if ((putc ('\n',df) == EOF) ||
+	(set && (fprintf (df,"X-UID: %lu\n",++(stream->uid_last)) < 0)))
+      return NIL;
+
+    for (c = '\n'; i && fgets (tmp,MAILTMPLEN,sf); c = tmp[j-1]) {
+				/* get read line length */
+      if (i < (j = strlen (tmp))) fatal ("unix_append_msgs overrun");
+      i -= j;			/* number of bytes left */
+				/* squish out CRs (note also copies NUL) */
+      for (x = tmp; x = strchr (x,'\r'); --j) memmove (x,x+1,j-(x-tmp));
+      if (!j) continue;		/* do nothing if line emptied */
+				/* start of line? */
+      if ((c == '\n')) switch (tmp[0]) {
+      case 'F':			/* possible "From " (case counts here) */
+	if ((j > 4) && (tmp[0] == 'F') && (tmp[1] == 'r') && (tmp[2] == 'o') &&
+	    (tmp[3] == 'm') && (tmp[4] == ' ')) {
+	  if (!unix_fromwidget) {
+	    VALID (tmp,x,ti,zn);/* conditional, only write widget if */
+	    if (!ti) break;	/*  it looks like a valid header */
+	  }			/* write the widget */
+	  if (putc ('>',df) == EOF) return NIL;
+	}
+	break;
+      case 'S': case 's':	/* possible "Status:" */
+	if (hdrp && (j > 6) && ((tmp[1] == 't') || (tmp[1] == 'T')) &&
+	    ((tmp[2] == 'a') || (tmp[2] == 'A')) &&
+	    ((tmp[3] == 't') || (tmp[3] == 'T')) &&
+	    ((tmp[4] == 'u') || (tmp[4] == 'U')) &&
+	    ((tmp[5] == 's') || (tmp[5] == 'S')) && (tmp[6] == ':') &&
+	    (fputs ("X-Original-",df) == EOF)) return NIL;
+	break;
+      case 'X': case 'x':	/* possible X-??? header */
+	if (hdrp && (tmp[1] == '-') &&
+				/* possible X-UID: */
+	    (((j > 5) && ((tmp[2] == 'U') || (tmp[2] == 'u')) &&
+	      ((tmp[3] == 'I') || (tmp[3] == 'i')) &&
+	      ((tmp[4] == 'D') || (tmp[4] == 'd')) && (tmp[5] == ':')) ||
+				/* possible X-IMAP: */
+	     ((j > 6) && ((tmp[2] == 'I') || (tmp[2] == 'i')) &&
+	      ((tmp[3] == 'M') || (tmp[3] == 'm')) &&
+	      ((tmp[4] == 'A') || (tmp[4] == 'a')) &&
+	      ((tmp[5] == 'P') || (tmp[5] == 'p')) &&
+	      ((tmp[6] == ':') ||
+				/* or X-IMAPbase: */
+	       ((j > 10) && ((tmp[6] == 'b') || (tmp[6] == 'B')) &&
+		((tmp[7] == 'a') || (tmp[7] == 'A')) &&
+		((tmp[8] == 's') || (tmp[8] == 'S')) &&
+		((tmp[9] == 'e') || (tmp[9] == 'E')) && (tmp[10] == ':')))) ||
+				/* possible X-Status: */
+	     ((j > 8) && ((tmp[2] == 'S') || (tmp[2] == 's')) &&
+	      ((tmp[3] == 't') || (tmp[3] == 'T')) &&
+	      ((tmp[4] == 'a') || (tmp[4] == 'A')) &&
+	      ((tmp[5] == 't') || (tmp[5] == 'T')) &&
+	      ((tmp[6] == 'u') || (tmp[6] == 'U')) &&
+	      ((tmp[7] == 's') || (tmp[7] == 'S')) && (tmp[8] == ':')) ||
+				/* possible X-Keywords: */
+	     ((j > 10) && ((tmp[2] == 'K') || (tmp[2] == 'k')) &&
+	      ((tmp[3] == 'e') || (tmp[3] == 'E')) &&
+	      ((tmp[4] == 'y') || (tmp[4] == 'Y')) &&
+	      ((tmp[5] == 'w') || (tmp[5] == 'W')) &&
+	      ((tmp[6] == 'o') || (tmp[6] == 'O')) &&
+	      ((tmp[7] == 'r') || (tmp[7] == 'R')) &&
+	      ((tmp[8] == 'd') || (tmp[8] == 'D')) &&
+	      ((tmp[9] == 's') || (tmp[9] == 'S')) && (tmp[10] == ':'))) &&
+	    (fputs ("X-Original-",df) == EOF)) return NIL;
+      case '\n':		/* blank line */
+	hdrp = NIL;
+	break;
+      default:			/* nothing to do */
+	break;
+      }
+				/* just write the line */
+      if (fwrite (tmp,1,j,df) != j) return NIL;
+    }
+    if (i) return NIL;		/* didn't read entire message */
+				/* update set */
+    if (stream) mail_append_set (set,stream->uid_last);
+  }
+  return T;
+}
+
+/* Internal routines */
+
+
+/* UNIX mail abort stream
+ * Accepts: MAIL stream
+ */
+
+void unix_abort (MAILSTREAM *stream)
+{
+  if (LOCAL) {			/* only if a file is open */
+    if (LOCAL->fd >= 0) close (LOCAL->fd);
+    if (LOCAL->ld >= 0) {	/* have a mailbox lock? */
+      flock (LOCAL->ld,LOCK_UN);/* yes, release the lock */
+      close (LOCAL->ld);	/* close the lock file */
+      unlink (LOCAL->lname);	/* and delete it */
+    }
+    if (LOCAL->lname) fs_give ((void **) &LOCAL->lname);
+				/* free local text buffers */
+    if (LOCAL->buf) fs_give ((void **) &LOCAL->buf);
+    if (LOCAL->text.data) fs_give ((void **) &LOCAL->text.data);
+    if (LOCAL->linebuf) fs_give ((void **) &LOCAL->linebuf);
+    if (LOCAL->line) fs_give ((void **) &LOCAL->line);
+				/* nuke the local data */
+    fs_give ((void **) &stream->local);
+    stream->dtb = NIL;		/* log out the DTB */
+  }
+}
+
+/* UNIX open and lock mailbox
+ * Accepts: file name to open/lock
+ *	    file open mode
+ *	    destination buffer for lock file name
+ *	    type of locking operation (LOCK_SH or LOCK_EX)
+ */
+
+int unix_lock (char *file,int flags,int mode,DOTLOCK *lock,int op)
+{
+  int fd;
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  (*bn) (BLOCK_FILELOCK,NIL);
+				/* try locking the easy way */
+  if (dotlock_lock (file,lock,-1)) {
+				/* got dotlock file, easy open */
+    if ((fd = open (file,flags,mode)) >= 0) flock (fd,op);
+    else dotlock_unlock (lock);	/* open failed, free the dotlock */
+  }
+				/* no dot lock file, open file now */
+  else if ((fd = open (file,flags,mode)) >= 0) {
+				/* try paranoid way to make a dot lock file */
+    if (dotlock_lock (file,lock,fd)) {
+      close (fd);		/* get fresh fd in case of timing race */
+      if ((fd = open (file,flags,mode)) >= 0) flock (fd,op);
+				/* open failed, free the dotlock */
+      else dotlock_unlock (lock);
+    }
+    else flock (fd,op);		/* paranoid way failed, just flock() it */
+  }
+  (*bn) (BLOCK_NONE,NIL);
+  return fd;
+}
+
+/* UNIX unlock and close mailbox
+ * Accepts: file descriptor
+ *	    (optional) mailbox stream to check atime/mtime
+ *	    (optional) lock file name
+ */
+
+void unix_unlock (int fd,MAILSTREAM *stream,DOTLOCK *lock)
+{
+  if (stream) {			/* need to muck with times? */
+    struct stat sbuf;
+    time_t tp[2];
+    time_t now = time (0);
+    fstat (fd,&sbuf);		/* get file times */
+    if (LOCAL->ld >= 0) {	/* yes, readwrite session? */
+      tp[0] = now;		/* set atime to now */
+				/* set mtime to (now - 1) if necessary */
+      tp[1] = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1;
+    }
+    else if (stream->recent) {	/* readonly with recent messages */
+      if ((sbuf.st_atime >= sbuf.st_mtime) ||
+	  (sbuf.st_atime >= sbuf.st_ctime))
+				/* keep past mtime, whack back atime */
+	tp[0] = (tp[1] = (sbuf.st_mtime < now) ? sbuf.st_mtime : now) - 1;
+      else now = 0;		/* no time change needed */
+    }
+				/* readonly with no recent messages */
+    else if ((sbuf.st_atime < sbuf.st_mtime) ||
+	     (sbuf.st_atime < sbuf.st_ctime)) {
+      tp[0] = now;		/* set atime to now */
+				/* set mtime to (now - 1) if necessary */
+      tp[1] = (now > sbuf.st_mtime) ? sbuf.st_mtime : now - 1;
+    }
+    else now = 0;		/* no time change needed */
+				/* set the times, note change */
+    if (now && !utime (stream->mailbox,tp)) LOCAL->filetime = tp[1];
+  }
+  flock (fd,LOCK_UN);		/* release flock'ers */
+  if (!stream) close (fd);	/* close the file if no stream */
+  dotlock_unlock (lock);	/* flush the lock file if any */
+}
+
+/* UNIX mail parse and lock mailbox
+ * Accepts: MAIL stream
+ *	    space to write lock file name
+ *	    type of locking operation
+ * Returns: T if parse OK, critical & mailbox is locked shared; NIL if failure
+ */
+
+int unix_parse (MAILSTREAM *stream,DOTLOCK *lock,int op)
+{
+  int zn;
+  unsigned long i,j,k,m;
+  unsigned char c,*s,*t,*u,tmp[MAILTMPLEN],date[30];
+  int ti = 0,retain = T;
+  unsigned long nmsgs = stream->nmsgs;
+  unsigned long prevuid = nmsgs ? mail_elt (stream,nmsgs)->private.uid : 0;
+  unsigned long recent = stream->recent;
+  unsigned long oldnmsgs = stream->nmsgs;
+  short silent = stream->silent;
+  short pseudoseen = NIL;
+  struct stat sbuf;
+  STRING bs;
+  FDDATA d;
+  MESSAGECACHE *elt;
+  mail_lock (stream);		/* guard against recursion or pingers */
+				/* toss out previous descriptor */
+  if (LOCAL->fd >= 0) close (LOCAL->fd);
+  MM_CRITICAL (stream);		/* open and lock mailbox (shared OK) */
+  if ((LOCAL->fd = unix_lock (stream->mailbox,(LOCAL->ld >= 0) ?
+			      O_RDWR : O_RDONLY,
+			      (long)mail_parameters(NIL,GET_MBXPROTECTION,NIL),
+			      lock,op)) < 0) {
+    sprintf (tmp,"Mailbox open failed, aborted: %s",strerror (errno));
+    MM_LOG (tmp,ERROR);
+    unix_abort (stream);
+    mail_unlock (stream);
+    MM_NOCRITICAL (stream);	/* done with critical */
+    return NIL;
+  }
+  fstat (LOCAL->fd,&sbuf);	/* get status */
+				/* validate change in size */
+  if (sbuf.st_size < LOCAL->filesize) {
+    sprintf (tmp,"Mailbox shrank from %lu to %lu bytes, aborted",
+	     (unsigned long) LOCAL->filesize,(unsigned long) sbuf.st_size);
+    MM_LOG (tmp,ERROR);		/* this is pretty bad */
+    unix_unlock (LOCAL->fd,stream,lock);
+    unix_abort (stream);
+    mail_unlock (stream);
+    MM_NOCRITICAL (stream);	/* done with critical */
+    return NIL;
+  }
+
+				/* new data? */
+  else if (i = sbuf.st_size - LOCAL->filesize) {
+    d.fd = LOCAL->fd;		/* yes, set up file descriptor */
+    d.pos = LOCAL->filesize;	/* get to that position in the file */
+    d.chunk = LOCAL->buf;	/* initial buffer chunk */
+    d.chunksize = CHUNKSIZE;	/* file chunk size */
+    INIT (&bs,fd_string,&d,i);	/* initialize stringstruct */
+				/* skip leading whitespace for broken MTAs */
+    while (((c = CHR (&bs)) == '\n') || (c == '\r') ||
+	   (c == ' ') || (c == '\t')) SNX (&bs);
+    if (SIZE (&bs)) {		/* read new data */
+				/* remember internal header position */
+      j = LOCAL->filesize + GETPOS (&bs);
+      s = unix_mbxline (stream,&bs,&i);
+      t = NIL,zn = 0;
+      if (i) VALID (s,t,ti,zn);	/* see if valid From line */
+      if (!ti) {		/* someone pulled the rug from under us */
+	sprintf (tmp,"Unexpected changes to mailbox (try restarting): %.20s",
+		 (char *) s);
+	MM_LOG (tmp,ERROR);
+	unix_unlock (LOCAL->fd,stream,lock);
+	unix_abort (stream);
+	mail_unlock (stream);
+				/* done with critical */
+	MM_NOCRITICAL (stream);
+	return NIL;
+      }
+      stream->silent = T;	/* quell main program new message events */
+      do {			/* found a message */
+				/* instantiate first new message */
+	mail_exists (stream,++nmsgs);
+	(elt = mail_elt (stream,nmsgs))->valid = T;
+	recent++;		/* assume recent by default */
+	elt->recent = T;
+				/* note position/size of internal header */
+	elt->private.special.offset = j;
+	elt->private.msg.header.offset = elt->private.special.text.size = i;
+
+				/* generate plausible IMAPish date string */
+	date[2] = date[6] = date[20] = '-'; date[11] = ' ';
+	date[14] = date[17] = ':';
+				/* dd */
+	date[0] = t[ti - 2]; date[1] = t[ti - 1];
+				/* mmm */
+	date[3] = t[ti - 6]; date[4] = t[ti - 5]; date[5] = t[ti - 4];
+				/* hh */
+	date[12] = t[ti + 1]; date[13] = t[ti + 2];
+				/* mm */
+	date[15] = t[ti + 4]; date[16] = t[ti + 5];
+	if (t[ti += 6] == ':') {/* ss */
+	  date[18] = t[++ti]; date[19] = t[++ti];
+	  ti++;			/* move to space */
+	}
+	else date[18] = date[19] = '0';
+				/* yy -- advance over timezone if necessary */
+	if (zn == ti) ti += (((t[zn+1] == '+') || (t[zn+1] == '-')) ? 6 : 4);
+	date[7] = t[ti + 1]; date[8] = t[ti + 2];
+	date[9] = t[ti + 3]; date[10] = t[ti + 4];
+				/* zzz */
+	t = zn ? (t + zn + 1) : (unsigned char *) "LCL";
+	date[21] = *t++; date[22] = *t++; date[23] = *t++;
+	if ((date[21] != '+') && (date[21] != '-')) date[24] = '\0';
+	else {			/* numeric time zone */
+	  date[24] = *t++; date[25] = *t++;
+	  date[26] = '\0'; date[20] = ' ';
+	}
+				/* set internal date */
+	if (!mail_parse_date (elt,date)) {
+	  sprintf (tmp,"Unable to parse internal date: %s",(char *) date);
+	  MM_LOG (tmp,WARN);
+	}
+
+	do {			/* look for message body */
+	  s = t = unix_mbxline (stream,&bs,&i);
+	  if (i) switch (*s) {	/* check header lines */
+	  case 'X':		/* possible X-???: line */
+	    if (s[1] == '-') {	/* must be immediately followed by hyphen */
+				/* X-Status: becomes Status: in S case */
+	      if (s[2] == 'S' && s[3] == 't' && s[4] == 'a' && s[5] == 't' &&
+		  s[6] == 'u' && s[7] == 's' && s[8] == ':') s += 2;
+				/* possible X-Keywords */
+	      else if (s[2] == 'K' && s[3] == 'e' && s[4] == 'y' &&
+		       s[5] == 'w' && s[6] == 'o' && s[7] == 'r' &&
+		       s[8] == 'd' && s[9] == 's' && s[10] == ':') {
+		SIZEDTEXT uf;
+		retain = NIL;	/* don't retain continuation */
+		s += 11;	/* flush leading whitespace */
+		while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n'))){
+		  while (*s == ' ') s++;
+				/* find end of keyword */
+		  if (!(u = strpbrk (s," \n\r"))) u = s + strlen (s);
+				/* got a keyword? */
+		  if ((k = (u - s)) && (k <= MAXUSERFLAG)) {
+		    uf.data = (unsigned char *) s;
+		    uf.size = k;
+		    for (j = 0; (j < NUSERFLAGS) && stream->user_flags[j]; ++j)
+		      if (!compare_csizedtext (stream->user_flags[j],&uf)) {
+			elt->user_flags |= ((long) 1) << j;
+			break;
+		      }
+ 		  }
+		  s = u;	/* advance to next keyword */
+		}
+		break;
+	      }
+
+				/* possible X-IMAP */
+	      else if ((s[2] == 'I') && (s[3] == 'M') && (s[4] == 'A') &&
+		       (s[5] == 'P') && ((m = (s[6] == ':')) ||
+					 ((s[6] == 'b') && (s[7] == 'a') &&
+					  (s[8] == 's') && (s[9] == 'e') &&
+					  (s[10] == ':')))) {
+		retain = NIL;	/* don't retain continuation */
+		if ((nmsgs == 1) && !stream->uid_validity) {
+				/* advance to data */
+		  s += m ? 7 : 11;
+				/* flush whitespace */
+		  while (*s == ' ') s++;
+		  j = 0;	/* slurp UID validity */
+				/* found a digit? */
+		  while (isdigit (*s)) {
+		    j *= 10;	/* yes, add it in */
+		    j += *s++ - '0';
+		  }
+				/* flush whitespace */
+		  while (*s == ' ') s++;
+				/* must have valid UID validity and UID last */
+		  if (j && isdigit (*s)) {
+				/* pseudo-header seen if X-IMAP */
+		    if (m) pseudoseen = LOCAL->pseudo = T;
+				/* save UID validity */
+		    stream->uid_validity = j;
+		    j = 0;	/* slurp UID last */
+		    while (isdigit (*s)) {
+		      j *= 10;	/* yes, add it in */
+		      j += *s++ - '0';
+		    }
+				/* save UID last */
+		    stream->uid_last = j;
+				/* process keywords */
+		    for (j = 0; (*s != '\n') && ((*s != '\r')||(s[1] != '\n'));
+			 s = u,j++) {
+				/* flush leading whitespace */
+		      while (*s == ' ') s++;
+		      u = strpbrk (s," \n\r");
+				/* got a keyword? */
+		      if ((j < NUSERFLAGS) && (k = (u - s)) &&
+			  (k <= MAXUSERFLAG)) {
+			if (stream->user_flags[j])
+			  fs_give ((void **) &stream->user_flags[j]);
+			stream->user_flags[j] = (char *) fs_get (k + 1);
+			strncpy (stream->user_flags[j],s,k);
+			stream->user_flags[j][k] = '\0';
+		      }
+		    }
+		  }
+		}
+		break;
+	      }
+
+				/* possible X-UID */
+	      else if (s[2] == 'U' && s[3] == 'I' && s[4] == 'D' &&
+		       s[5] == ':') {
+		retain = NIL;	/* don't retain continuation */
+				/* only believe if have a UID validity */
+		if (stream->uid_validity && ((nmsgs > 1) || !pseudoseen)) {
+		  s += 6;	/* advance to UID value */
+				/* flush whitespace */
+		  while (*s == ' ') s++;
+		  j = 0;
+				/* found a digit? */
+		  while (isdigit (*s)) {
+		    j *= 10;	/* yes, add it in */
+		    j += *s++ - '0';
+		  }
+				/* flush remainder of line */
+		  while (*s != '\n') s++;
+				/* make sure not duplicated */
+		  if (elt->private.uid)
+		    sprintf (tmp,"Message %lu UID %lu already has UID %lu",
+			     pseudoseen ? elt->msgno - 1 : elt->msgno,
+			     j,elt->private.uid);
+				/* make sure UID doesn't go backwards */
+		  else if (j <= prevuid)
+		    sprintf (tmp,"Message %lu UID %lu less than %lu",
+			     pseudoseen ? elt->msgno - 1 : elt->msgno,
+			     j,prevuid + 1);
+#if 0	/* this is currently broken by UIDPLUS */
+				/* or skip by mailbox's recorded last */
+		  else if (j > stream->uid_last)
+		    sprintf (tmp,"Message %lu UID %lu greater than last %lu",
+			     pseudoseen ? elt->msgno - 1 : elt->msgno,
+			     j,stream->uid_last);
+#endif
+		  else {	/* normal UID case */
+		    prevuid = elt->private.uid = j;
+#if 1	/* temporary kludge for UIDPLUS */
+		    if (prevuid > stream->uid_last) {
+		      stream->uid_last = prevuid;
+		      LOCAL->ddirty = LOCAL->dirty = T;
+		    }		    
+#endif
+		    break;	/* exit this cruft */
+		  }
+		  MM_LOG (tmp,WARN);
+				/* invalidate UID validity */
+		  stream->uid_validity = 0;
+		  elt->private.uid = 0;
+		}
+		break;
+	      }
+	    }
+				/* otherwise fall into S case */
+
+	  case 'S':		/* possible Status: line */
+	    if (s[0] == 'S' && s[1] == 't' && s[2] == 'a' && s[3] == 't' &&
+		s[4] == 'u' && s[5] == 's' && s[6] == ':') {
+	      retain = NIL;	/* don't retain continuation */
+	      s += 6;		/* advance to status flags */
+	      do switch (*s++) {/* parse flags */
+	      case 'R':		/* message read */
+		elt->seen = T;
+		break;
+	      case 'O':		/* message old */
+		if (elt->recent) {
+		  elt->recent = NIL;
+		  recent--;	/* it really wasn't recent */
+		}
+		break;
+	      case 'D':		/* message deleted */
+		elt->deleted = T;
+		break;
+	      case 'F':		/* message flagged */
+		elt->flagged = T;
+		break;
+	      case 'A':		/* message answered */
+		elt->answered = T;
+		break;
+	      case 'T':		/* message is a draft */
+		elt->draft = T;
+		break;
+	      default:		/* some other crap */
+		break;
+	      } while (*s && (*s != '\n') && ((*s != '\r') || (s[1] != '\n')));
+	      break;		/* all done */
+	    }
+				/* otherwise fall into default case */
+
+	  default:		/* ordinary header line */
+	    if ((*s == 'S') || (*s == 's') ||
+		(((*s == 'X') || (*s == 'x')) && (s[1] == '-'))) {
+	      unsigned char *e,*v;
+				/* must match what mail_filter() does */
+	      for (u = s,v = tmp,e = u + min (i,MAILTMPLEN - 1);
+		   (u < e) && ((c = (*u ? *u : (*u = ' '))) != ':') &&
+		   ((c > ' ') || ((c != ' ') && (c != '\t') &&
+				  (c != '\r') && (c != '\n')));
+		   *v++ = *u++);
+	      *v = '\0';	/* tie off */
+				/* matches internal header? */
+	      if (!compare_cstring (tmp,"STATUS") ||
+		  !compare_cstring (tmp,"X-STATUS") ||
+		  !compare_cstring (tmp,"X-KEYWORDS") ||
+		  !compare_cstring (tmp,"X-UID") ||
+		  !compare_cstring (tmp,"X-IMAP") ||
+		  !compare_cstring (tmp,"X-IMAPBASE")) {
+		char err[MAILTMPLEN];
+		sprintf (err,"Discarding bogus %s header in message %lu",
+			 (char *) tmp,elt->msgno);
+		MM_LOG (err,WARN);
+		retain = NIL;	/* don't retain continuation */
+		break;		/* different case or something */
+	      }
+	    }
+				/* retain or non-continuation? */
+	    if (retain || ((*s != ' ') && (*s != '\t'))) {
+	      retain = T;	/* retaining continuation now */
+				/* line length in LF format newline */
+	      for (j = k = 0; j < i; ++j) if (s[j] != '\r') ++k;
+				/* "internal" header size */
+	      elt->private.spare.data += k;
+				/* message size */
+	      elt->rfc822_size += k + 1;
+	    }
+	    else {
+	      char err[MAILTMPLEN];
+	      sprintf (err,"Discarding bogus continuation in msg %lu: %.80s",
+		      elt->msgno,(char *) s);
+	      if (u = strpbrk (err,"\r\n")) *u = '\0';
+	      MM_LOG (err,WARN);
+	      break;		/* different case or something */
+	    }
+	    break;
+	  }
+	} while (i && (*t != '\n') && ((*t != '\r') || (t[1] != '\n')));
+				/* "internal" header sans trailing newline */
+	if (i) elt->private.spare.data--;
+				/* assign a UID if none found */
+	if (((nmsgs > 1) || !pseudoseen) && !elt->private.uid) {
+	  prevuid = elt->private.uid = ++stream->uid_last;
+	  elt->private.dirty = T;
+	  LOCAL->ddirty = T;	/* force update */
+	}
+	else elt->private.dirty = elt->recent;
+
+				/* note size of header, location of text */
+	elt->private.msg.header.text.size = 
+	  (elt->private.msg.text.offset =
+	   (LOCAL->filesize + GETPOS (&bs)) - elt->private.special.offset) -
+	     elt->private.special.text.size;
+	k = m = 0;		/* no previous line size yet */
+				/* note current position */
+	j = LOCAL->filesize + GETPOS (&bs);
+	if (i) do {		/* look for next message */
+	  s = unix_mbxline (stream,&bs,&i);
+	  if (i) {		/* got new data? */
+	    VALID (s,t,ti,zn);	/* yes, parse line */
+	    if (!ti) {		/* not a header line, add it to message */
+	      elt->rfc822_size += i;
+	      for (j = 0; j < i; ++j) switch (s[j]) {
+	      case '\r':	/* squeeze out CRs */
+		elt->rfc822_size -= 1;
+		break;
+	      case '\n':	/* LF becomes CRLF */
+		elt->rfc822_size += 1;
+		break;
+	      default:
+		break;
+	      }
+	      if ((i == 1) && (*s == '\n')) {
+		k = 2;
+		m = 1;
+	      }
+	      else if ((i == 2) && (*s == '\r') && (s[1] == '\n'))
+		k = m = 2;
+	      else k = m = 0;	/* file does not end with newline! */
+				/* update current position */
+	      j = LOCAL->filesize + GETPOS (&bs);
+	    }
+	  }
+	} while (i && !ti);	/* until found a header */
+	elt->private.msg.text.text.size = j -
+	  (elt->private.special.offset + elt->private.msg.text.offset);
+				/* flush ending blank line */
+	elt->private.msg.text.text.size -= m;
+	elt->rfc822_size -= k;
+				/* until end of buffer */
+      } while (!stream->sniff && i);
+      if (pseudoseen) {		/* flush pseudo-message if present */
+				/* decrement recent count */
+	if (mail_elt (stream,1)->recent) recent--;
+				/* and the exists count */
+	mail_exists (stream,nmsgs--);
+	mail_expunged(stream,1);/* fake an expunge of that message */
+      }
+				/* need to start a new UID validity? */
+      if (!stream->uid_validity) {
+	stream->uid_validity = time (0);
+				/* in case a whiner with no life */
+	if (mail_parameters (NIL,GET_USERHASNOLIFE,NIL))
+	  stream->uid_nosticky = T;
+	else if (nmsgs) {	/* don't bother if empty file */
+				/* make dirty to restart UID epoch */
+	  LOCAL->ddirty = LOCAL->dirty = T;
+				/* need to rewrite msg 1 if not pseudo */
+	  if (!LOCAL->pseudo) mail_elt (stream,1)->private.dirty = T;
+	  MM_LOG ("Assigning new unique identifiers to all messages",NIL);
+	}
+      }
+      stream->nmsgs = oldnmsgs;	/* whack it back down */
+      stream->silent = silent;	/* restore old silent setting */
+				/* notify upper level of new mailbox sizes */
+      mail_exists (stream,nmsgs);
+      mail_recent (stream,recent);
+				/* mark dirty so O flags are set */
+      if (recent) LOCAL->dirty = T;
+    }
+  }
+				/* no change, don't babble if never got time */
+  else if (LOCAL->filetime && LOCAL->filetime != sbuf.st_mtime)
+    MM_LOG ("New mailbox modification time but apparently no changes",WARN);
+				/* update parsed file size and time */
+  LOCAL->filesize = sbuf.st_size;
+  LOCAL->filetime = sbuf.st_mtime;
+  return T;			/* return the winnage */
+}
+
+/* UNIX read line from mailbox
+ * Accepts: mail stream
+ *	    stringstruct
+ *	    pointer to line size
+ * Returns: pointer to input line
+ */
+
+char *unix_mbxline (MAILSTREAM *stream,STRING *bs,unsigned long *size)
+{
+  unsigned long i,j,k,m;
+  char *s,*t,*te;
+  char *ret = "";
+				/* flush old buffer */
+  if (LOCAL->line) fs_give ((void **) &LOCAL->line);
+				/* if buffer needs refreshing */
+  if (!bs->cursize) SETPOS (bs,GETPOS (bs));
+  if (SIZE (bs)) {		/* find newline */
+				/* end of fast scan */
+    te = (t = (s = bs->curpos) + bs->cursize) - 12;
+    while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+		       (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) {
+      --s;			/* back up */
+      break;			/* exit loop */
+    }
+				/* final character-at-a-time scan */
+    while ((s < t) && (*s != '\n')) ++s;
+				/* difficult case if line spans buffer */
+    if ((i = s - bs->curpos) == bs->cursize) {
+				/* have space in line buffer? */
+      if (i > LOCAL->linebuflen) {
+	fs_give ((void **) &LOCAL->linebuf);
+	LOCAL->linebuf = (char *) fs_get (LOCAL->linebuflen = i);
+      }
+				/* remember what we have so far */
+      memcpy (LOCAL->linebuf,bs->curpos,i);
+				/* load next buffer */
+      SETPOS (bs,k = GETPOS (bs) + i);
+				/* end of fast scan */
+      te = (t = (s = bs->curpos) + bs->cursize) - 12;
+				/* fast scan in overlap buffer */
+      while (s < te) if ((*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n') ||
+			 (*s++ == '\n') || (*s++ == '\n') || (*s++ == '\n')) {
+	--s;			/* back up */
+	break;			/* exit loop */
+      }
+
+				/* final character-at-a-time scan */
+      while ((s < t) && (*s != '\n')) ++s;
+				/* huge line? */
+      if ((j = s - bs->curpos) == bs->cursize) {
+	SETPOS (bs,GETPOS (bs) + j);
+				/* look for end of line (s-l-o-w!!) */
+	for (m = SIZE (bs); m && (SNX (bs) != '\n'); --m,++j);
+	SETPOS (bs,k);		/* go back to where it started */
+      }
+				/* got size of data, make buffer for return */
+      ret = LOCAL->line = (char *) fs_get (i + j + 2);
+				/* copy first chunk */
+      memcpy (ret,LOCAL->linebuf,i);
+      while (j) {		/* copy remainder */
+	if (!bs->cursize) SETPOS (bs,GETPOS (bs));
+	memcpy (ret + i,bs->curpos,k = min (j,bs->cursize));
+	i += k;			/* account for this much read in */
+	j -= k;
+	bs->curpos += k;	/* increment new position */
+	bs->cursize -= k;	/* eat that many bytes */
+      }
+      if (!bs->cursize) SETPOS (bs,GETPOS (bs));
+				/* read newline at end */
+      if (SIZE (bs)) ret[i++] = SNX (bs);
+      ret[i] = '\0';		/* makes debugging easier */
+    }
+    else {			/* this is easy */
+      ret = bs->curpos;		/* string it at this position */
+      bs->curpos += ++i;	/* increment new position */
+      bs->cursize -= i;		/* eat that many bytes */
+    }
+    *size = i;			/* return that to user */
+  }
+  else *size = 0;		/* end of data, return empty */
+  return ret;
+}
+
+/* UNIX make pseudo-header
+ * Accepts: MAIL stream
+ *	    buffer to write pseudo-header
+ * Returns: length of pseudo-header
+ */
+
+unsigned long unix_pseudo (MAILSTREAM *stream,char *hdr)
+{
+  int i;
+  char *s,tmp[MAILTMPLEN];
+  time_t now = time (0);
+  rfc822_fixed_date (tmp);
+  sprintf (hdr,"From %s %.24s\nDate: %s\nFrom: %s <%s@%.80s>\nSubject: %s\nMessage-ID: <%lu@%.80s>\nX-IMAP: %010lu %010lu",
+	   pseudo_from,ctime (&now),
+	   tmp,pseudo_name,pseudo_from,mylocalhost (),pseudo_subject,
+	   (unsigned long) now,mylocalhost (),stream->uid_validity,
+	   stream->uid_last);
+  for (s = hdr + strlen (hdr),i = 0; i < NUSERFLAGS; ++i)
+    if (stream->user_flags[i])
+      sprintf (s += strlen (s)," %s",stream->user_flags[i]);
+  sprintf (s += strlen (s),"\nStatus: RO\n\n%s\n\n",pseudo_msg);
+  return strlen (hdr);		/* return header length */
+}
+
+/* UNIX make status string
+ * Accepts: MAIL stream
+ *	    destination string to write
+ *	    message cache entry
+ *	    UID to write if non-zero (else use elt->private.uid)
+ *	    non-zero flag to write UID (.LT. 0 to write UID base info too)
+ * Returns: length of string
+ */
+
+unsigned long unix_xstatus (MAILSTREAM *stream,char *status,MESSAGECACHE *elt,
+			    unsigned long uid,long flag)
+{
+  char *t,stack[64];
+  char *s = status;
+  unsigned long n;
+  int pad = 50;
+  int sticky = uid ? T : !stream->uid_nosticky;
+  /* This used to use sprintf(), but thanks to certain cretinous C libraries
+     with horribly slow implementations of sprintf() I had to change it to this
+     mess.  At least it should be fast. */
+  if ((flag < 0) && sticky) {	/* need to write X-IMAPbase: header? */
+    *s++ = 'X'; *s++ = '-'; *s++ = 'I'; *s++ = 'M'; *s++ = 'A'; *s++ = 'P';
+    *s++ = 'b'; *s++ = 'a'; *s++ = 's'; *s++ = 'e'; *s++ = ':'; *s++ = ' ';
+    t = stack;
+    n = stream->uid_validity;	/* push UID validity digits on the stack */
+    do *t++ = (char) (n % 10) + '0';
+    while (n /= 10);
+				/* pop UID validity digits from stack */
+    while (t > stack) *s++ = *--t;
+    *s++ = ' ';
+    n = stream->uid_last;	/* push UID last digits on the stack */
+    do *t++ = (char) (n % 10) + '0';
+    while (n /= 10);
+				/* pop UID last digits from stack */
+    while (t > stack) *s++ = *--t;
+    for (n = 0; n < NUSERFLAGS; ++n) if (t = stream->user_flags[n])
+      for (*s++ = ' '; *t; *s++ = *t++);
+    *s++ = '\n';
+    pad += 30;			/* increased padding if have IMAPbase */
+  }
+  *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't'; *s++ = 'u'; *s++ = 's';
+  *s++ = ':'; *s++ = ' ';
+  if (elt->seen) *s++ = 'R';
+				/* only write O if have a UID */
+  if (flag && (!elt->recent || !LOCAL->appending)) *s++ = 'O';
+  *s++ = '\n';
+  *s++ = 'X'; *s++ = '-'; *s++ = 'S'; *s++ = 't'; *s++ = 'a'; *s++ = 't';
+  *s++ = 'u'; *s++ = 's'; *s++ = ':'; *s++ = ' ';
+  if (elt->deleted) *s++ = 'D';
+  if (elt->flagged) *s++ = 'F';
+  if (elt->answered) *s++ = 'A';
+  if (elt->draft) *s++ = 'T';
+  *s++ = '\n';
+
+  if (sticky) {			/* only do this if UIDs sticky */
+    *s++ = 'X'; *s++ = '-'; *s++ = 'K'; *s++ = 'e'; *s++ = 'y'; *s++ = 'w';
+    *s++ = 'o'; *s++ = 'r'; *s++ = 'd'; *s++ = 's'; *s++ = ':';
+    if (n = elt->user_flags) do {
+      *s++ = ' ';
+      for (t = stream->user_flags[find_rightmost_bit (&n)]; *t; *s++ = *t++);
+    } while (n);
+    n = s - status;		/* get size of stuff so far */
+				/* pad X-Keywords to make size constant */
+    if (n < pad) for (n = pad - n; n > 0; --n) *s++ = ' ';
+    *s++ = '\n';
+    if (flag) {			/* want to include UID? */
+      t = stack;
+				/* push UID digits on the stack */
+      n = uid ? uid : elt->private.uid;
+      do *t++ = (char) (n % 10) + '0';
+      while (n /= 10);
+      *s++ = 'X'; *s++ = '-'; *s++ = 'U'; *s++ = 'I'; *s++ = 'D'; *s++ = ':';
+      *s++ = ' ';
+				/* pop UID from stack */
+      while (t > stack) *s++ = *--t;
+      *s++ = '\n';
+    }
+  }
+  *s++ = '\n'; *s = '\0';	/* end of extended message status */
+  return s - status;		/* return size of resulting string */
+}
+
+/* Rewrite mailbox file
+ * Accepts: MAIL stream, must be critical and locked
+ *	    return pointer to number of expunged messages if want expunge
+ *	    lock file name
+ *	    expunge sequence, not deleted flag
+ * Returns: T if success and mailbox unlocked, NIL if failure
+ */
+
+#define OVERFLOWBUFLEN 8192	/* initial overflow buffer length */
+
+long unix_rewrite (MAILSTREAM *stream,unsigned long *nexp,DOTLOCK *lock,
+		   long flags)
+{
+  MESSAGECACHE *elt;
+  UNIXFILE f;
+  char *s;
+  time_t tp[2];
+  long ret,flag;
+  unsigned long i,j;
+  unsigned long recent = stream->recent;
+  unsigned long size = LOCAL->pseudo ? unix_pseudo (stream,LOCAL->buf) : 0;
+  if (nexp) *nexp = 0;		/* initially nothing expunged */
+				/* calculate size of mailbox after rewrite */
+  for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs; i++) {
+    elt = mail_elt (stream,i);	/* get cache */
+    if (!(nexp && elt->deleted && (flags ? elt->sequence : T))) {
+				/* add RFC822 size of this message */
+      size += elt->private.special.text.size + elt->private.spare.data +
+	unix_xstatus (stream,LOCAL->buf,elt,NIL,flag) +
+	  elt->private.msg.text.text.size + 1;
+      flag = 1;			/* only count X-IMAPbase once */
+    }
+  }
+				/* no messages, has a life, and no pseudo */
+  if (!size && !mail_parameters (NIL,GET_USERHASNOLIFE,NIL)) {
+    LOCAL->pseudo = T;		/* so make a pseudo-message now */
+    size = unix_pseudo (stream,LOCAL->buf);
+  }
+				/* extend the file as necessary */
+  if (ret = unix_extend (stream,size)) {
+    /* Set up buffered I/O file structure
+     * curpos	current position being written through buffering
+     * filepos	current position being written physically to the disk
+     * bufpos	current position being written in the buffer
+     * protect	current maximum position that can be written to the disk
+     *		before buffering is forced
+     * The code tries to buffer so that that disk is written in multiples of
+     * OVERBLOWBUFLEN bytes.
+     */
+    f.stream = stream;		/* note mail stream */
+    f.curpos = f.filepos = 0;	/* start of file */
+    f.protect = stream->nmsgs ?	/* initial protection pointer */
+    mail_elt (stream,1)->private.special.offset : 8192;
+    f.bufpos = f.buf = (char *) fs_get (f.buflen = OVERFLOWBUFLEN);
+
+    if (LOCAL->pseudo)		/* update pseudo-header */
+      unix_write (&f,LOCAL->buf,unix_pseudo (stream,LOCAL->buf));
+				/* loop through all messages */
+    for (i = 1,flag = LOCAL->pseudo ? 1 : -1; i <= stream->nmsgs;) {
+      elt = mail_elt (stream,i);/* get cache */
+				/* expunge this message? */
+      if (nexp && elt->deleted && (flags ? elt->sequence : T)) {
+				/* one less recent message */
+	if (elt->recent) --recent;
+	mail_expunged(stream,i);/* notify upper levels */
+	++*nexp;		/* count up one more expunged message */
+      }
+      else {			/* preserve this message */
+	i++;			/* advance to next message */
+	if ((flag < 0) ||	/* need to rewrite message? */
+	    elt->private.dirty || (f.curpos != elt->private.special.offset) ||
+	    (elt->private.msg.header.text.size !=
+	     (elt->private.spare.data +
+	      unix_xstatus (stream,LOCAL->buf,elt,NIL,flag)))) {
+	  unsigned long newoffset = f.curpos;
+				/* yes, seek to internal header */
+	  lseek (LOCAL->fd,elt->private.special.offset,L_SET);
+	  read (LOCAL->fd,LOCAL->buf,elt->private.special.text.size);
+				/* see if need to squeeze out a CR */
+	  if (LOCAL->buf[elt->private.special.text.size - 2] == '\r') {
+	    LOCAL->buf[--elt->private.special.text.size - 1] = '\n';
+	    --size;		/* squeezed out a CR from PC */
+	  }
+				/* protection pointer moves to RFC822 header */
+	  f.protect = elt->private.special.offset +
+	    elt->private.msg.header.offset;
+				/* write internal header */
+	  unix_write (&f,LOCAL->buf,elt->private.special.text.size);
+				/* get RFC822 header */
+	  s = unix_header (stream,elt->msgno,&j,FT_INTERNAL);
+				/* in case this got decremented */
+	  elt->private.msg.header.offset = elt->private.special.text.size;
+				/* header size, sans trailing newline */
+	  if ((j < 2) || (s[j - 2] == '\n')) j--;
+				/* this can happen if CRs were squeezed */
+	  if (j < elt->private.spare.data) {
+				/* so fix up counts */
+	    size -= elt->private.spare.data - j;
+	    elt->private.spare.data = j;
+	  }
+	  else if (j != elt->private.spare.data)
+	    fatal ("header size inconsistent");
+				/* protection pointer moves to RFC822 text */
+	  f.protect = elt->private.special.offset +
+	    elt->private.msg.text.offset;
+	  unix_write (&f,s,j);	/* write RFC822 header */
+				/* write status and UID */
+	  unix_write (&f,LOCAL->buf,
+		      j = unix_xstatus (stream,LOCAL->buf,elt,NIL,flag));
+	  flag = 1;		/* only write X-IMAPbase once */
+				/* new file header size */
+	  elt->private.msg.header.text.size = elt->private.spare.data + j;
+
+				/* did text move? */
+	  if (f.curpos != f.protect) {
+				/* get message text */
+	    s = unix_text_work (stream,elt,&j,FT_INTERNAL);
+				/* this can happen if CRs were squeezed */
+	    if (j < elt->private.msg.text.text.size) {
+				/* so fix up counts */
+	      size -= elt->private.msg.text.text.size - j;
+	      elt->private.msg.text.text.size = j;
+	    }
+				/* can't happen it says here */
+	    else if (j > elt->private.msg.text.text.size)
+	      fatal ("text size inconsistent");
+				/* new text offset, status/UID may change it */
+	    elt->private.msg.text.offset = f.curpos - newoffset;
+				/* protection pointer moves to next message */
+	    f.protect = (i <= stream->nmsgs) ?
+	      mail_elt (stream,i)->private.special.offset : (f.curpos + j + 1);
+	    unix_write (&f,s,j);/* write text */
+				/* write trailing newline */
+	    unix_write (&f,"\n",1);
+	  }
+	  else {		/* tie off header and status */
+	    unix_write (&f,NIL,NIL);
+				/* protection pointer moves to next message */
+	    f.protect = (i <= stream->nmsgs) ?
+	      mail_elt (stream,i)->private.special.offset : size;
+				/* locate end of message text */
+	    j = f.filepos + elt->private.msg.text.text.size;
+				/* trailing newline already there? */
+	    if (f.protect == (j + 1)) f.curpos = f.filepos = f.protect;
+	    else {		/* trailing newline missing, write it */
+	      f.curpos = f.filepos = j;
+	      unix_write (&f,"\n",1);
+	    }
+	  }
+				/* new internal header offset */
+	  elt->private.special.offset = newoffset;
+	  elt->private.dirty =NIL;/* message is now clean */
+	}
+	else {			/* no need to rewrite this message */
+				/* tie off previous message if needed */
+	  unix_write (&f,NIL,NIL);
+				/* protection pointer moves to next message */
+	  f.protect = (i <= stream->nmsgs) ?
+	    mail_elt (stream,i)->private.special.offset : size;
+				/* locate end of message text */
+	  j = f.filepos + elt->private.special.text.size +
+	    elt->private.msg.header.text.size +
+	      elt->private.msg.text.text.size;
+				/* trailing newline already there? */
+	  if (f.protect == (j + 1)) f.curpos = f.filepos = f.protect;
+	  else {		/* trailing newline missing, write it */
+	    f.curpos = f.filepos = j;
+	    unix_write (&f,"\n",1);
+	  }
+	}
+      }
+    }
+
+    unix_write (&f,NIL,NIL);	/* tie off final message */
+    if (size != f.filepos) fatal ("file size inconsistent");
+    fs_give ((void **) &f.buf);	/* free buffer */
+				/* make sure tied off */
+    ftruncate (LOCAL->fd,LOCAL->filesize = size);
+    fsync (LOCAL->fd);		/* make sure the updates take */
+    if (size && (flag < 0)) fatal ("lost UID base information");
+				/* no longer dirty */
+    LOCAL->ddirty = LOCAL->dirty = NIL;
+  				/* notify upper level of new mailbox sizes */
+    mail_exists (stream,stream->nmsgs);
+    mail_recent (stream,recent);
+				/* set atime to now, mtime a second earlier */
+    tp[1] = (tp[0] = time (0)) - 1;
+				/* set the times, note change */
+    if (!utime (stream->mailbox,tp)) LOCAL->filetime = tp[1];
+    close (LOCAL->fd);		/* close and reopen file */
+    if ((LOCAL->fd = open (stream->mailbox,O_RDWR,
+			   (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL)))
+	< 0) {
+      sprintf (LOCAL->buf,"Mailbox open failed, aborted: %s",strerror (errno));
+      MM_LOG (LOCAL->buf,ERROR);
+      unix_abort (stream);
+    }
+    dotlock_unlock (lock);	/* flush the lock file */
+  }
+  return ret;			/* return state from algorithm */
+}
+
+/* Extend UNIX mailbox file
+ * Accepts: MAIL stream
+ *	    new desired size
+ * Return: T if success, else NIL
+ */
+
+long unix_extend (MAILSTREAM *stream,unsigned long size)
+{
+  unsigned long i = (size > LOCAL->filesize) ? size - LOCAL->filesize : 0;
+  if (i) {			/* does the mailbox need to grow? */
+    if (i > LOCAL->buflen) {	/* make sure have enough space */
+				/* this user won the lottery all right */
+      fs_give ((void **) &LOCAL->buf);
+      LOCAL->buf = (char *) fs_get ((LOCAL->buflen = i) + 1);
+    }
+    memset (LOCAL->buf,'\0',i);	/* get a block of nulls */
+    while (T) {			/* until write successful or punt */
+      lseek (LOCAL->fd,LOCAL->filesize,L_SET);
+      if ((write (LOCAL->fd,LOCAL->buf,i) >= 0) && !fsync (LOCAL->fd)) break;
+      else {
+	long e = errno;		/* note error before doing ftruncate */
+	ftruncate (LOCAL->fd,LOCAL->filesize);
+	if (MM_DISKERROR (stream,e,NIL)) {
+	  fsync (LOCAL->fd);	/* user chose to punt */
+	  sprintf (LOCAL->buf,"Unable to extend mailbox: %s",strerror (e));
+	  if (!stream->silent) MM_LOG (LOCAL->buf,ERROR);
+	  return NIL;
+	}
+      }
+    }
+  }
+  return LONGT;
+}
+
+/* Write data to buffered file
+ * Accepts: buffered file pointer
+ *	    file data or NIL to indicate "flush buffer"
+ *	    date size (ignored for "flush buffer")
+ * Does not return until success
+ */
+
+void unix_write (UNIXFILE *f,char *buf,unsigned long size)
+{
+  unsigned long i,j,k;
+  if (buf) {			/* doing buffered write? */
+    i = f->bufpos - f->buf;	/* yes, get size of current buffer data */
+				/* yes, have space in current buffer chunk? */
+    if (j = i ? ((f->buflen - i) % OVERFLOWBUFLEN) : f->buflen) {
+				/* yes, fill up buffer as much as we can */
+      memcpy (f->bufpos,buf,k = min (j,size));
+      f->bufpos += k;		/* new buffer position */
+      f->curpos += k;		/* new current position */
+      if (j -= k) return;	/* all done if still have buffer free space */
+      buf += k;			/* full, get new unwritten data pointer */
+      size -= k;		/* new data size */
+      i += k;			/* new buffer data size */
+    }
+    /* This chunk of the buffer is full.  See if can make some space by
+     * writing to the disk, if there's enough unprotected space to do so.
+     * Try to fill out any unaligned chunk, along with any subsequent full
+     * chunks that will fit in unprotected space.
+     */
+				/* any unprotected space we can write to? */
+    if (j = min (i,f->protect - f->filepos)) {
+				/* yes, filepos not at chunk boundary? */
+      if ((k = f->filepos % OVERFLOWBUFLEN) && ((k = OVERFLOWBUFLEN - k) < j))
+	j -= k;			/* yes, and can write out partial chunk */
+      else k = 0;		/* no partial chunk to write */
+				/* if at least a chunk free, write that too */
+      if (j > OVERFLOWBUFLEN) k += j - (j % OVERFLOWBUFLEN);
+      if (k) {			/* write data if there is anything we can */
+	unix_phys_write (f,f->buf,k);
+				/* slide buffer */
+	if (i -= k) memmove (f->buf,f->buf + k,i);
+	f->bufpos = f->buf + i;	/* new end of buffer */
+      }
+    }
+
+    /* Have flushed the buffer as best as possible.  All done if no more
+     * data to write.  Otherwise, if the buffer is empty AND if the unwritten
+     * data is larger than a chunk AND the unprotected space is also larger
+     * than a chunk, then write as many chunks as we can directly from the
+     * data.  Buffer the rest, expanding the buffer as needed.
+     */
+    if (size) {			/* have more data that we need to buffer? */
+				/* can write any of it to disk instead? */
+      if ((f->bufpos == f->buf) && 
+	  ((j = min (f->protect - f->filepos,size)) > OVERFLOWBUFLEN)) {
+				/* write as much as we can right now */
+	unix_phys_write (f,buf,j -= (j % OVERFLOWBUFLEN));
+	buf += j;		/* new data pointer */
+	size -= j;		/* new data size */
+	f->curpos += j;		/* advance current pointer */
+      }
+      if (size) {		/* still have data that we need to buffer? */
+				/* yes, need to expand the buffer? */
+	if ((i = ((f->bufpos + size) - f->buf)) > f->buflen) {
+				/* note current position in buffer */
+	  j = f->bufpos - f->buf;
+	  i += OVERFLOWBUFLEN;	/* yes, grow another chunk */
+	  fs_resize ((void **) &f->buf,f->buflen = i - (i % OVERFLOWBUFLEN));
+				/* in case buffer relocated */
+	  f->bufpos = f->buf + j;
+	}
+				/* buffer remaining data */
+	memcpy (f->bufpos,buf,size);
+	f->bufpos += size;	/* new end of buffer */
+	f->curpos += size;	/* advance current pointer */
+      }
+    }
+  }
+  else {			/* flush buffer to disk */
+    unix_phys_write (f,f->buf,i = f->bufpos - f->buf);
+    f->bufpos = f->buf;		/* reset buffer */
+				/* update positions */
+    f->curpos = f->protect = f->filepos;
+  }
+}
+
+/* Physical disk write
+ * Accepts: buffered file pointer
+ *	    buffer address
+ *	    buffer size
+ * Does not return until success
+ */
+
+void unix_phys_write (UNIXFILE *f,char *buf,size_t size)
+{
+  MAILSTREAM *stream = f->stream;
+				/* write data at desired position */
+  while (size && ((lseek (LOCAL->fd,f->filepos,L_SET) < 0) ||
+		  (write (LOCAL->fd,buf,size) < 0))) {
+    int e;
+    char tmp[MAILTMPLEN];
+    sprintf (tmp,"Unable to write to mailbox: %s",strerror (e = errno));
+    MM_LOG (tmp,ERROR);
+    MM_DISKERROR (NIL,e,T);	/* serious problem, must retry */
+  }
+  f->filepos += size;		/* update file position */
+}
+
+/* MBOX mail routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER mboxdriver = {
+  "mbox",			/* driver name */
+				/* driver flags */
+  DR_LOCAL|DR_MAIL|DR_LOCKING|DR_NONEWMAILRONLY,
+  (DRIVER *) NIL,		/* next driver */
+  mbox_valid,			/* mailbox is valid for us */
+  unix_parameters,		/* manipulate parameters */
+  unix_scan,			/* scan mailboxes */
+  unix_list,			/* find mailboxes */
+  unix_lsub,			/* find subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  mbox_create,			/* create mailbox */
+  mbox_delete,			/* delete mailbox */
+  mbox_rename,			/* rename mailbox */
+  mbox_status,			/* status of mailbox */
+  mbox_open,			/* open mailbox */
+  unix_close,			/* close mailbox */
+  NIL,				/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message structure */
+  unix_header,			/* fetch message header */
+  unix_text,			/* fetch message body */
+  NIL,				/* fetch partial message text */
+  NIL,				/* unique identifier */
+  NIL,				/* message number */
+  NIL,				/* modify flags */
+  unix_flagmsg,			/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  mbox_ping,			/* ping mailbox to see if still alive */
+  mbox_check,			/* check for new messages */
+  mbox_expunge,			/* expunge deleted messages */
+  unix_copy,			/* copy messages to another mailbox */
+  mbox_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+				/* prototype stream */
+MAILSTREAM mboxproto = {&mboxdriver};
+
+/* MBOX mail validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *mbox_valid (char *name)
+{
+				/* only INBOX, mbox must exist */
+  if (!compare_cstring (name,"INBOX") && (unix_valid ("mbox") || !errno) &&
+      (unix_valid (sysinbox()) || !errno || (errno == ENOENT)))
+    return &mboxdriver;
+  return NIL;			/* can't win (yet, anyway) */
+}
+
+/* MBOX mail create mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long mbox_create (MAILSTREAM *stream,char *mailbox)
+{
+  char tmp[MAILTMPLEN];
+  if (!compare_cstring (mailbox,"INBOX")) return unix_create (NIL,"mbox");
+  sprintf (tmp,"Can't create non-INBOX name as mbox: %.80s",mailbox);
+  MM_LOG (tmp,ERROR);
+  return NIL;
+}
+
+
+/* MBOX mail delete mailbox
+ * Accepts: MAIL stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long mbox_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return mbox_rename (stream,mailbox,NIL);
+}
+
+
+/* MBOX mail rename mailbox
+ * Accepts: MAIL stream
+ *	    old mailbox name
+ *	    new mailbox name (or NIL for delete)
+ * Returns: T on success, NIL on failure
+ */
+
+long mbox_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  char tmp[MAILTMPLEN];
+  long ret = unix_rename (stream,"~/mbox",newname);
+				/* recreate file if renamed INBOX */
+  if (ret) unix_create (NIL,"mbox");
+  else MM_LOG (tmp,ERROR);	/* log error */
+  return ret;			/* return success */
+}
+
+/* MBOX Mail status
+ * Accepts: mail stream
+ *	    mailbox name
+ *	    status flags
+ * Returns: T on success, NIL on failure
+ */
+
+long mbox_status (MAILSTREAM *stream,char *mbx,long flags)
+{
+  MAILSTATUS status;
+  unsigned long i;
+  MAILSTREAM *tstream = NIL;
+  MAILSTREAM *systream = NIL;
+				/* make temporary stream (unless this mbx) */
+  if (!stream && !(stream = tstream =
+		   mail_open (NIL,mbx,OP_READONLY|OP_SILENT))) return NIL;
+  status.flags = flags;		/* return status values */
+  status.messages = stream->nmsgs;
+  status.recent = stream->recent;
+  if (flags & SA_UNSEEN)	/* must search to get unseen messages */
+    for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++)
+      if (!mail_elt (stream,i)->seen) status.unseen++;
+  status.uidnext = stream->uid_last + 1;
+  status.uidvalidity = stream->uid_validity;
+  if (!status.recent &&		/* calculate post-snarf results */
+      (systream = mail_open (NIL,sysinbox (),OP_READONLY|OP_SILENT))) {
+    status.messages += systream->nmsgs;
+    status.recent += systream->recent;
+    if (flags & SA_UNSEEN)	/* must search to get unseen messages */
+      for (i = 1; i <= systream->nmsgs; i++)
+	if (!mail_elt (systream,i)->seen) status.unseen++;
+				/* kludge but probably good enough */
+    status.uidnext += systream->nmsgs;
+  }
+  MM_STATUS(stream,mbx,&status);/* pass status to main program */
+  if (tstream) mail_close (tstream);
+  if (systream) mail_close (systream);
+  return T;			/* success */
+}
+
+/* MBOX mail open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *mbox_open (MAILSTREAM *stream)
+{
+  unsigned long i = 1;
+  unsigned long recent = 0;
+				/* return prototype for OP_PROTOTYPE call */
+  if (!stream) return &mboxproto;
+				/* change mailbox file name */
+  fs_give ((void **) &stream->mailbox);
+  stream->mailbox = cpystr ("mbox");
+				/* open mailbox, snarf new mail */
+  if (!(unix_open (stream) && mbox_ping (stream))) return NIL;
+  stream->inbox = T;		/* mark that this is an INBOX */
+				/* notify upper level of mailbox sizes */
+  mail_exists (stream,stream->nmsgs);
+  while (i <= stream->nmsgs) if (mail_elt (stream,i++)->recent) ++recent;
+  mail_recent (stream,recent);	/* including recent messages */
+  return stream;
+}
+
+/* MBOX mail ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ * No-op for readonly files, since read/writer can expunge it from under us!
+ */
+
+static int snarfed = 0;		/* number of snarfs */
+
+long mbox_ping (MAILSTREAM *stream)
+{
+  int sfd;
+  unsigned long size;
+  struct stat sbuf;
+  char *s;
+  DOTLOCK lock,lockx;
+				/* time to try snarf and sysinbox non-empty? */
+  if (LOCAL && !stream->rdonly && !stream->lock &&
+      (time (0) >= (LOCAL->lastsnarf +
+		    (long) mail_parameters (NIL,GET_SNARFINTERVAL,NIL))) &&
+      !stat (sysinbox (),&sbuf) && sbuf.st_size) {
+    MM_CRITICAL (stream);	/* yes, go critical */
+				/* open and lock sysinbox */
+    if ((sfd = unix_lock (sysinbox (),O_RDWR,
+			  (long) mail_parameters (NIL,GET_MBXPROTECTION,NIL),
+			  &lockx,LOCK_EX)) >= 0) {
+				/* locked sysinbox in good format? */
+      if (fstat (sfd,&sbuf) || !(size = sbuf.st_size) ||
+	  !unix_isvalid_fd (sfd)) {
+	sprintf (LOCAL->buf,"Mail drop %s is not in standard Unix format",
+		 sysinbox ());
+	MM_LOG (LOCAL->buf,ERROR);
+      }
+				/* sysinbox good, parse and excl-lock mbox */
+      else if (unix_parse (stream,&lock,LOCK_EX)) {
+	lseek (sfd,0,L_SET);	/* read entire sysinbox into memory */
+	read (sfd,s = (char *) fs_get (size + 1),size);
+	s[size] = '\0';		/* tie it off */
+				/* append to end of mbox */
+	lseek (LOCAL->fd,LOCAL->filesize,L_SET);
+
+				/* copy to mbox */
+	if ((write (LOCAL->fd,s,size) < 0) || fsync (LOCAL->fd)) {
+	  sprintf (LOCAL->buf,"New mail move failed: %s",strerror (errno));
+	  MM_LOG (LOCAL->buf,WARN);
+				/* revert mbox to previous size */
+	  ftruncate (LOCAL->fd,LOCAL->filesize);
+	}
+				/* sysinbox better not have changed */
+	else if (fstat (sfd,&sbuf) || (size != sbuf.st_size)) {
+	  sprintf (LOCAL->buf,"Mail drop %s lock failure, old=%lu now=%lu",
+		   sysinbox (),size,(unsigned long) sbuf.st_size);
+	  MM_LOG (LOCAL->buf,ERROR);
+				/* revert mbox to previous size */
+	  ftruncate (LOCAL->fd,LOCAL->filesize);
+	  /* Believe it or not, a Singaporean government system actually had
+	   * symlinks from /var/mail/user to ~user/mbox.  To compound this
+	   * error, they used an SVR4 system; BSD and OSF locks would have
+	   * prevented it but not SVR4 locks.
+	   */
+	  if (!fstat (sfd,&sbuf) && (size == sbuf.st_size))
+	    syslog (LOG_ALERT,"File %s and %s are the same file!",
+		    sysinbox (),stream->mailbox);
+	}
+	else {			/* data copied OK */
+	  ftruncate (sfd,0);	/* truncate sysinbox to zero bytes */
+	  if (!snarfed++) {	/* have we snarfed before? */
+				/* syslog if server, else user log */
+	    sprintf (LOCAL->buf,"Moved %lu bytes of new mail to %s from %s",
+		     size,stream->mailbox,sysinbox ());
+	    if (strcmp ((char *) mail_parameters (NIL,GET_SERVICENAME,NIL),
+			"unknown"))
+	      syslog (LOG_INFO,"%s host= %s",LOCAL->buf,tcp_clienthost ());
+	    else MM_LOG (LOCAL->buf,WARN);
+	  }
+	}
+				/* done with sysinbox text */
+	fs_give ((void **) &s);
+				/* all done with mbox */
+	unix_unlock (LOCAL->fd,stream,&lock);
+	mail_unlock (stream);	/* unlock the stream */
+	MM_NOCRITICAL (stream);	/* done with critical */
+      }
+				/* all done with sysinbox */
+      unix_unlock (sfd,NIL,&lockx);
+    }
+    MM_NOCRITICAL (stream);	/* done with critical */
+    LOCAL->lastsnarf = time (0);/* note time of last snarf */
+  }
+  return unix_ping (stream);	/* do the unix routine now */
+}
+
+/* MBOX mail check mailbox
+ * Accepts: MAIL stream
+ */
+
+void mbox_check (MAILSTREAM *stream)
+{
+				/* do local ping, then do unix routine */
+  if (mbox_ping (stream)) unix_check (stream);
+}
+
+
+/* MBOX mail expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long mbox_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  long ret = unix_expunge (stream,sequence,options);
+  mbox_ping (stream);		/* do local ping */
+  return ret;
+}
+
+
+/* MBOX mail append message from stringstruct
+ * Accepts: MAIL stream
+ *	    destination mailbox
+ *	    append callback
+ *	    data for callback
+ * Returns: T if append successful, else NIL
+ */
+
+long mbox_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  char tmp[MAILTMPLEN];
+  if (mbox_valid (mailbox)) return unix_append (stream,"mbox",af,data);
+  sprintf (tmp,"Can't append to that name: %.80s",mailbox);
+  MM_LOG (tmp,ERROR);
+  return NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/unix.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,161 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX mail routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	20 December 1989
+ * Last Edited:	30 August 2006
+ */
+
+
+/*				DEDICATION
+ *
+ *  This file is dedicated to my dog, Unix, also known as Yun-chan and
+ * Unix J. Terwilliker Jehosophat Aloysius Monstrosity Animal Beast.  Unix
+ * passed away at the age of 11 1/2 on September 14, 1996, 12:18 PM PDT, after
+ * a two-month bout with cirrhosis of the liver.
+ *
+ *  He was a dear friend, and I miss him terribly.
+ *
+ *  Lift a leg, Yunie.  Luv ya forever!!!!
+ */
+
+/* Validate line
+ * Accepts: pointer to candidate string to validate as a From header
+ *	    return pointer to end of date/time field
+ *	    return pointer to offset from t of time (hours of ``mmm dd hh:mm'')
+ *	    return pointer to offset from t of time zone (if non-zero)
+ * Returns: t,ti,zn set if valid From string, else ti is NIL
+ */
+
+#define VALID(s,x,ti,zn) {						\
+  ti = 0;								\
+  if ((*s == 'F') && (s[1] == 'r') && (s[2] == 'o') && (s[3] == 'm') &&	\
+      (s[4] == ' ')) {							\
+    for (x = s + 5; *x && *x != '\012'; x++);				\
+    if (*x) {								\
+      if (x[-1] == '\015') --x;						\
+      if (x - s >= 41) {						\
+	for (zn = -1; x[zn] != ' '; zn--);				\
+	if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') &&	\
+	    (x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') &&	\
+	    (x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') &&	\
+	    (x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))\
+	  x += zn - 12;							\
+      }									\
+      if (x - s >= 27) {						\
+	if (x[-5] == ' ') {						\
+	  if (x[-8] == ':') zn = 0,ti = -5;				\
+	  else if (x[-9] == ' ') ti = zn = -9;				\
+	  else if ((x[-11] == ' ') && ((x[-10]=='+') || (x[-10]=='-')))	\
+	    ti = zn = -11;						\
+	}								\
+	else if (x[-4] == ' ') {					\
+	  if (x[-9] == ' ') zn = -4,ti = -9;				\
+	}								\
+	else if (x[-6] == ' ') {					\
+	  if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-')))	\
+	    zn = -6,ti = -11;						\
+	}								\
+	if (ti && !((x[ti - 3] == ':') &&				\
+		    (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') &&	\
+		    (x[ti - 3] == ' ') && (x[ti - 7] == ' ') &&		\
+		    (x[ti - 11] == ' '))) ti = 0;			\
+      }									\
+    }									\
+  }									\
+}
+
+/* You are not expected to understand this macro, but read the next page if
+ * you are not faint of heart.
+ *
+ * Known formats to the VALID macro are:
+ *		From user Wed Dec  2 05:53 1992
+ * BSD		From user Wed Dec  2 05:53:22 1992
+ * SysV		From user Wed Dec  2 05:53 PST 1992
+ * rn		From user Wed Dec  2 05:53:22 PST 1992
+ *		From user Wed Dec  2 05:53 -0700 1992
+ * emacs	From user Wed Dec  2 05:53:22 -0700 1992
+ *		From user Wed Dec  2 05:53 1992 PST
+ *		From user Wed Dec  2 05:53:22 1992 PST
+ *		From user Wed Dec  2 05:53 1992 -0700
+ * Solaris	From user Wed Dec  2 05:53:22 1992 -0700
+ *
+ * Plus all of the above with `` remote from xxx'' after it. Thank you very
+ * much, smail and Solaris, for making my life considerably more complicated.
+ */
+
+/*
+ * What?  You want to understand the VALID macro anyway?  Alright, since you
+ * insist.  Actually, it isn't really all that difficult, provided that you
+ * take it step by step.
+ *
+ * Line 1	Initializes the return ti value to failure (0);
+ * Lines 2-3	Validates that the 1st-5th characters are ``From ''.
+ * Lines 4-6	Validates that there is an end of line and points x at it.
+ * Lines 7-14	First checks to see if the line is at least 41 characters long.
+ *		If so, it scans backwards to find the rightmost space.  From
+ *		that point, it scans backwards to see if the string matches
+ *		`` remote from''.  If so, it sets x to point to the space at
+ *		the start of the string.
+ * Line 15	Makes sure that there are at least 27 characters in the line.
+ * Lines 16-21	Checks if the date/time ends with the year (there is a space
+ *		five characters back).  If there is a colon three characters
+ *		further back, there is no timezone field, so zn is set to 0
+ *		and ti is set in front of the year.  Otherwise, there must
+ *		either to be a space four characters back for a three-letter
+ *		timezone, or a space six characters back followed by a + or -
+ *		for a numeric timezone; in either case, zn and ti become the
+ *		offset of the space immediately before it.
+ * Lines 22-24	Are the failure case for line 14.  If there is a space four
+ *		characters back, it is a three-letter timezone; there must be a
+ *		space for the year nine characters back.  zn is the zone
+ *		offset; ti is the offset of the space.
+ * Lines 25-28	Are the failure case for line 20.  If there is a space six
+ *		characters back, it is a numeric timezone; there must be a
+ *		space eleven characters back and a + or - five characters back.
+ *		zn is the zone offset; ti is the offset of the space.
+ * Line 29-32	If ti is valid, make sure that the string before ti is of the
+ *		form www mmm dd hh:mm or www mmm dd hh:mm:ss, otherwise
+ *		invalidate ti.  There must be a colon three characters back
+ *		and a space six or nine	characters back (depending upon
+ *		whether or not the character six characters back is a colon).
+ *		There must be a space three characters further back (in front
+ *		of the day), one seven characters back (in front of the month),
+ *		and one eleven characters back (in front of the day of week).
+ *		ti is set to be the offset of the space before the time.
+ *
+ * Why a macro?  It gets invoked a *lot* in a tight loop.  On some of the
+ * newer pipelined machines it is faster being open-coded than it would be if
+ * subroutines are called.
+ *
+ * Why does it scan backwards from the end of the line, instead of doing the
+ * much easier forward scan?  There is no deterministic way to parse the
+ * ``user'' field, because it may contain unquoted spaces!  Yes, I tested it to
+ * see if unquoted spaces were possible.  They are, and I've encountered enough
+ * evil mail to be totally unwilling to trust that ``it will never happen''.
+ */
+
+/* Build parameters */
+
+#define KODRETRY 15		/* kiss-of-death retry in seconds */
+#define LOCKTIMEOUT 5		/* lock timeout in minutes */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/utime.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,45 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	BSD utime() emulator
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 October 1996
+ * Last Edited:	30 August 2006
+ */
+
+#undef utime
+
+/* Portable utime() that takes it args like real Unix systems
+ * Accepts: file path
+ *	    traditional utime() argument
+ * Returns: utime() results
+ */
+
+int portable_utime (char *file,time_t timep[2])
+{
+  struct utimbuf times;
+				/* in case there's other cruft there */
+  memset (&times,0,sizeof (struct utimbuf));
+  times.actime = timep[0];	/* copy the portable values */
+  times.modtime = timep[1];
+  return utime (file,&times);	/* now call the SVR4 routine */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/unix/write.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,59 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Write data, treating partial writes as an error
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	26 May 1995
+ * Last Edited:	30 August 2006
+ */
+
+/*  The whole purpose of this unfortunate routine is to deal with DOS and
+ * certain cretinous versions of UNIX which decided that the "bytes actually
+ * written" return value from write() gave them license to use that for things
+ * that are really errors, such as disk quota exceeded, maximum file size
+ * exceeded, disk full, etc.
+ * 
+ *  BSD won't screw us this way on the local filesystem, but who knows what
+ * some NFS-mounted filesystem will do.
+ */
+
+#undef write
+
+/* Write data to file
+ * Accepts: file descriptor
+ *	    I/O vector structure
+ *	    number of vectors in structure
+ * Returns: number of bytes written if successful, -1 if failure
+ */
+
+long maxposint = (long)((((unsigned long) 1) << ((sizeof(int) * 8) - 1)) - 1);
+
+long safe_write (int fd,char *buf,long nbytes)
+{
+  long i,j;
+  if (nbytes > 0) for (i = nbytes; i; i -= j,buf += j) {
+    while (((j = write (fd,buf,(int) min (maxposint,i))) < 0) &&
+	   (errno == EINTR));
+    if (j < 0) return j;
+  }
+  return nbytes;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/vms/build.com	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,99 @@
+$! ========================================================================
+$! Copyright 1988-2006 University of Washington
+$!
+$! Licensed under the Apache License, Version 2.0 (the "License");
+$! you may not use this file except in compliance with the License.
+$! You may obtain a copy of the License at
+$!
+$!     http://www.apache.org/licenses/LICENSE-2.0
+$!
+$! 
+$! ========================================================================
+$!
+$! Program:	Portable c-client build for VMS
+$!
+$! Author:	Mark Crispin
+$!		Networks and Distributed Computing
+$!		Computing & Communications
+$!		University of Washington
+$!		Administration Building, AG-44
+$!		Seattle, WA  98195
+$!		Internet: MRC@CAC.Washington.EDU
+$!
+$! Date:	2 August 1994
+$! Last Edited:	30 August 2006
+$!
+$!  Change this to your local timezone.  This value is the number of minutes
+$! east of UTC (formerly known as GMT).  Sample values: -300 (US east coast),
+$! -480 (US west coast), 540 (Japan), 60 (western Europe).
+$!  VAX C's HELP information says that you should be able to use gmtime(), but
+$! it returns 0 for the struct.  ftime(), you ask?  It, too, returns 0 for a
+$! timezone.  Nothing sucks like a VAX!
+$!
+$ CC_TIMEZONE=-480
+$!
+$! CC options
+$!
+$ CC_PREF = "/OPTIMIZE/INCLUDE=[]"
+$ CC_PREF = CC_PREF + "/DEFINE=net_getbuffer=NET_GETBUF"
+$ CC_PREF = CC_PREF + "/DEFINE=LOCALTIMEZONE='CC_TIMEZONE'"
+$!
+$! Determine TCP type
+$!
+$ TCP_TYPE = "VMSN"		! default to none
+$ IF F$LOCATE("MULTINET", P1) .LT. F$LENGTH(P1)
+$ THEN
+$	DEFINE SYS MULTINET_ROOT:[MULTINET.INCLUDE.SYS],sys$library
+$	DEFINE NETINET MULTINET_ROOT:[MULTINET.INCLUDE.NETINET]
+$	DEFINE ARPA MULTINET_ROOT:[MULTINET.INCLUDE.ARPA]
+$	TCP_TYPE = "VMSM"	! Multinet
+$	LINK_OPT = ",LINK_MNT/OPTION"
+$ ENDIF
+$ IF F$LOCATE("NETLIB", P1) .LT. F$LENGTH(P1)
+$ THEN
+$	DEFINE SYS SYS$LIBRARY:	! normal .H location
+$	DEFINE NETINET SYS$LIBRARY:
+$	DEFINE ARPA SYS$LIBRARY:
+$	LINK_OPT = ",LINK_NLB/OPTION"
+$	TCP_TYPE = "VMSL"	! NETLIB
+$ ENDIF
+$ IF TCP_TYPE .EQS. "VMSN"
+$ THEN
+$	DEFINE SYS SYS$LIBRARY:	! normal .H location
+$	DEFINE NETINET SYS$LIBRARY:
+$	DEFINE ARPA SYS$LIBRARY:
+$	LINK_OPT = ""
+$ ENDIF
+$!
+$ COPY TCP_'TCP_TYPE'.C TCP_VMS.C;
+$!
+$ COPY OS_VMS.H OSDEP.H;
+$ SET VERIFY
+$ CC'CC_PREF' MAIL
+$ CC'CC_PREF' IMAP4R1
+$ CC'CC_PREF' SMTP
+$ CC'CC_PREF' NNTP
+$ CC'CC_PREF' POP3
+$ CC'CC_PREF' DUMMYVMS
+$ CC'CC_PREF' RFC822
+$ CC'CC_PREF' MISC
+$ CC'CC_PREF' OS_VMS
+$ CC'CC_PREF' SMANAGER
+$ CC'CC_PREF' FLSTRING
+$ CC'CC_PREF' NEWSRC
+$ CC'CC_PREF' NETMSG
+$ CC'CC_PREF' UTF8
+$ CC'CC_PREF' UTF8AUX
+$ CC'CC_PREF' MTEST
+$ CC'CC_PREF' MAILUTIL
+$!
+$ LINK MTEST,OS_VMS,MAIL,IMAP4R1,SMTP,NNTP,POP3,DUMMYVMS,RFC822,MISC,UTF8,-
+	UTF8AUX,SMANAGER,FLSTRING,NEWSRC,NETMSG,-
+	SYS$INPUT:/OPTION'LINK_OPT',LINK/OPTION
+PSECT=_CTYPE_,NOWRT
+$ LINK MAILUTIL,OS_VMS,MAIL,IMAP4R1,SMTP,NNTP,POP3,DUMMYVMS,RFC822,MISC,UTF8,-
+	UTF8AUX,SMANAGER,FLSTRING,NEWSRC,NETMSG,-
+	SYS$INPUT:/OPTION'LINK_OPT',LINK/OPTION
+PSECT=_CTYPE_,NOWRT
+$ SET NOVERIFY
+$ EXIT
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/vms/clean.com	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,26 @@
+$! ========================================================================
+$! Copyright 1988-2006 University of Washington
+$!
+$! Licensed under the Apache License, Version 2.0 (the "License");
+$! you may not use this file except in compliance with the License.
+$! You may obtain a copy of the License at
+$!
+$!     http://www.apache.org/licenses/LICENSE-2.0
+$!
+$! 
+$! ========================================================================
+$!
+$! Program:	Portable c-client cleanup for VMS
+$!
+$! Author:	Mark Crispin
+$!		Networks and Distributed Computing
+$!		Computing & Communications
+$!		University of Washington
+$!		Administration Building, AG-44
+$!		Seattle, WA  98195
+$!		Internet: MRC@CAC.Washington.EDU
+$!
+$! Date:	14 June 1995
+$! Last Edited:	30 August 2006
+$!
+$ DELETE *.OBJ;*,OSDEP.*;*,TCP_VMS.C;*,MTEST.EXE;*,MAILUTIL.EXE;*
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/vms/dummy.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,43 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Dummy routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	9 May 1991
+ * Last Edited:	30 August 2006
+ */
+
+/* Exported function prototypes */
+
+void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void dummy_list (MAILSTREAM *stream,char *ref,char *pat);
+void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long scan_contents (DRIVER *dtb,char *name,char *contents,
+		    unsigned long csiz,unsigned long fsiz);
+long dummy_scan_contents (char *name,char *contents,unsigned long csiz,
+			  unsigned long fsiz);
+long dummy_create (MAILSTREAM *stream,char *mailbox);
+long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode);
+long dummy_delete (MAILSTREAM *stream,char *mailbox);
+long dummy_rename (MAILSTREAM *stream,char *old,char *newname);
+char *dummy_file (char *dst,char *name);
+long dummy_canonicalize (char *tmp,char *ref,char *pat);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/vms/dummyvms.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,295 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Dummy routines for VMS
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	24 May 1993
+ * Last Edited:	30 August 2006
+ */
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include "mail.h"
+#include "osdep.h"
+#include "dummy.h"
+#include "misc.h"
+
+/* Function prototypes */
+
+DRIVER *dummy_valid (char *name);
+void *dummy_parameters (long function,void *value);
+MAILSTREAM *dummy_open (MAILSTREAM *stream);
+void dummy_close (MAILSTREAM *stream,long options);
+long dummy_ping (MAILSTREAM *stream);
+void dummy_check (MAILSTREAM *stream);
+long dummy_expunge (MAILSTREAM *stream,char *sequence,long options);
+long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+/* Dummy routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER dummydriver = {
+  "dummy",			/* driver name */
+  DR_LOCAL|DR_MAIL,		/* driver flags */
+  (DRIVER *) NIL,		/* next driver */
+  dummy_valid,			/* mailbox is valid for us */
+  dummy_parameters,		/* manipulate parameters */
+  dummy_scan,			/* scan mailboxes */
+  dummy_list,			/* list mailboxes */
+  dummy_lsub,			/* list subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  dummy_create,			/* create mailbox */
+  dummy_delete,			/* delete mailbox */
+  dummy_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  dummy_open,			/* open mailbox */
+  dummy_close,			/* close mailbox */
+  NIL,				/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message structure */
+  NIL,				/* fetch header */
+  NIL,				/* fetch text */
+  NIL,				/* fetch message data */
+  NIL,				/* unique identifier */
+  NIL,				/* message number from UID */
+  NIL,				/* modify flags */
+  NIL,				/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  dummy_ping,			/* ping mailbox to see if still alive */
+  dummy_check,			/* check for new messages */
+  dummy_expunge,		/* expunge deleted messages */
+  dummy_copy,			/* copy messages to another mailbox */
+  dummy_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+
+				/* prototype stream */
+MAILSTREAM dummyproto = {&dummydriver};
+
+/* Dummy validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *dummy_valid (char *name)
+{
+  char tmp[MAILTMPLEN];
+				/* must be valid local mailbox */
+  return (name && *name && (*name != '{') && !compare_cstring (name,"INBOX")) ?
+    &dummydriver : NIL;
+}
+
+
+/* Dummy manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *dummy_parameters (long function,void *value)
+{
+  return NIL;
+}
+
+/* Dummy scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+				/* return silently */
+}
+
+
+/* Dummy list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void dummy_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+				/* return silently */
+}
+
+
+/* Dummy list subscribed mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+				/* return silently */
+}
+
+/* Dummy create mailbox
+ * Accepts: mail stream
+ *	    mailbox name to create
+ *	    driver type to use
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_create (MAILSTREAM *stream,char *mailbox)
+{
+  return NIL;			/* always fails */
+}
+
+
+/* Dummy delete mailbox
+ * Accepts: mail stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return NIL;			/* always fails */
+}
+
+
+/* Mail rename mailbox
+ * Accepts: mail stream
+ *	    old mailbox name
+ *	    new mailbox name
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  return NIL;			/* always fails */
+}
+
+/* Dummy open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *dummy_open (MAILSTREAM *stream)
+{
+  char tmp[MAILTMPLEN];
+				/* OP_PROTOTYPE call or silence */
+  if (!stream || stream->silent) return NIL;
+  if (compare_cstring (stream->mailbox,"INBOX")) {
+    sprintf (tmp,"Not a mailbox: %s",stream->mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;			/* always fails */
+  }
+  if (!stream->silent) {	/* only if silence not requested */
+    mail_exists (stream,0);	/* say there are 0 messages */
+    mail_recent (stream,0);
+    stream->uid_validity = time (0);
+  }
+  stream->inbox = T;		/* note that it's an INBOX */
+  return stream;		/* return success */
+}
+
+
+/* Dummy close
+ * Accepts: MAIL stream
+ *	    options
+ */
+
+void dummy_close (MAILSTREAM *stream,long options)
+{
+				/* return silently */
+}
+
+/* Dummy ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ * No-op for readonly files, since read/writer can expunge it from under us!
+ */
+
+long dummy_ping (MAILSTREAM *stream)
+{
+  return T;
+}
+
+
+/* Dummy check mailbox
+ * Accepts: MAIL stream
+ * No-op for readonly files, since read/writer can expunge it from under us!
+ */
+
+void dummy_check (MAILSTREAM *stream)
+{
+  dummy_ping (stream);		/* invoke ping */
+}
+
+
+/* Dummy expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long dummy_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  return LONGT;
+}
+
+/* Dummy copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    options
+ * Returns: T if copy successful, else NIL
+ */
+
+long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+      mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy");
+  return NIL;
+}
+
+
+/* Dummy append message string
+ * Accepts: mail stream
+ *	    destination mailbox
+ *	    append callback function
+ *	    data for callback
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  char tmp[MAILTMPLEN];
+  sprintf (tmp,"Can't append to %s",mailbox);
+  mm_log (tmp,ERROR);		/* pass up error */
+  return NIL;			/* always fails */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/vms/env_vms.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,174 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	VMS environment routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	2 August 1994
+ * Last Edited:	30 August 2006
+ */
+
+
+static char *myUserName = NIL;	/* user name */
+static char *myLocalHost = NIL;	/* local host name */
+static char *myHomeDir = NIL;	/* home directory name */
+static char *myNewsrc = NIL;	/* newsrc file name */
+
+#include "pmatch.c"		/* include wildcard pattern matcher */
+
+/* Environment manipulate parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *env_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case SET_USERNAME:
+    myUserName = cpystr ((char *) value);
+  case GET_USERNAME:
+    ret = (void *) myUserName;
+    break;
+  case SET_HOMEDIR:
+    myHomeDir = cpystr ((char *) value);
+  case GET_HOMEDIR:
+    ret = (void *) myHomeDir;
+    break;
+  case SET_LOCALHOST:
+    myLocalHost = cpystr ((char *) value);
+  case GET_LOCALHOST:
+    ret = (void *) myLocalHost;
+    break;
+  case SET_NEWSRC:
+    if (myNewsrc) fs_give ((void **) &myNewsrc);
+    myNewsrc = cpystr ((char *) value);
+  case GET_NEWSRC:
+    if (!myNewsrc) {		/* set news file name if not defined */
+      char tmp[MAILTMPLEN];
+      sprintf (tmp,"%s:.newsrc",myhomedir ());
+      myNewsrc = cpystr (tmp);
+    }
+    ret = (void *) myNewsrc;
+    break;
+  }
+  return ret;
+}
+ 
+/* Write current time
+ * Accepts: destination string
+ *	    optional format of day-of-week prefix
+ *	    format of date and time
+ */
+
+static void do_date (char *date,char *prefix,char *fmt)
+{
+  time_t tn = time (0);
+  struct tm *t = localtime (&tn);
+  int zone = LOCALTIMEZONE + (t->tm_isdst ? 60 : 0);
+  if (prefix) {			/* want day of week? */
+    sprintf (date,prefix,days[t->tm_wday]);
+    date += strlen (date);	/* make next sprintf append */
+  }
+				/* output the date */
+  sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
+	   t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
+}
+
+
+/* Write current time in RFC 822 format
+ * Accepts: destination string
+ */
+
+void rfc822_date (char *date)
+{
+  do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d");
+}
+
+
+/* Write current time in internal format
+ * Accepts: destination string
+ */
+
+void internal_date (char *date)
+{
+  do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d");
+}
+
+/* Return my user name
+ * Returns: my user name
+ */
+
+char *myusername ()
+{
+  struct stat sbuf;
+  char tmp[MAILTMPLEN];
+
+  if (!myUserName) {		/* get user name if don't have it yet */
+    myUserName = cpystr (cuserid (NIL));
+    myHomeDir = cpystr ("SYS$LOGIN");
+  }
+  return myUserName;
+}
+
+
+/* Return my home directory name
+ * Returns: my home directory name
+ */
+
+char *myhomedir ()
+{
+  if (!myHomeDir) myusername ();/* initialize if first time */
+  return myHomeDir;
+}
+
+
+/* Determine default prototype stream to user
+ * Accepts: type (NIL for create, T for append)
+ * Returns: default prototype stream
+ */
+
+MAILSTREAM *default_proto (long type)
+{
+  return NIL;			/* no default prototype */
+}
+
+/* Emulator for BSD syslog() routine
+ * Accepts: priority
+ *	    message
+ *	    parameters
+ */
+
+void syslog (int priority,const char *message,...)
+{
+}
+
+
+/* Emulator for BSD openlog() routine
+ * Accepts: identity
+ *	    options
+ *	    facility
+ */
+
+void openlog (const char *ident,int logopt,int facility)
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/vms/env_vms.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,60 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	VMS environment routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	2 August 1994
+ * Last Edited:	30 August 2006
+ */
+
+
+#define SUBSCRIPTIONFILE(t) sprintf (t,"%s\\SUBSCRIPTIONS.TXT",myhomedir ())
+#define SUBSCRIPTIONTEMP(t) sprintf (t,"%s\\SUBSCRIPTIONS.TMP",myhomedir ())
+
+/* Function prototypes */
+
+#include "env.h"
+
+char *myusername ();
+
+
+/* syslog() emulation */
+
+#define LOG_MAIL	(2<<3)	/* mail system */
+#define LOG_DAEMON	(3<<3)	/* system daemons */
+#define LOG_AUTH	(4<<3)	/* security/authorization messages */
+#define LOG_EMERG	0	/* system is unusable */
+#define LOG_ALERT	1	/* action must be taken immediately */
+#define LOG_CRIT	2	/* critical conditions */
+#define LOG_ERR		3	/* error conditions */
+#define LOG_WARNING	4	/* warning conditions */
+#define LOG_NOTICE	5	/* normal but signification condition */
+#define LOG_INFO	6	/* informational */
+#define LOG_DEBUG	7	/* debug-level messages */
+#define LOG_PID		0x01	/* log the pid with each message */
+#define LOG_CONS	0x02	/* log on the console if errors in sending */
+#define LOG_ODELAY	0x04	/* delay open until syslog() is called */
+#define LOG_NDELAY	0x08	/* don't delay open */
+#define LOG_NOWAIT	0x10	/* if forking to log on console, don't wait() */
+
+void openlog (const char *ident,int logopt,int facility);
+void syslog (int priority,const char *message,...);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/vms/fs_vms.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,62 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Free storage management routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Get a block of free storage
+ * Accepts: size of desired block
+ * Returns: free storage block
+ */
+
+void *fs_get (size_t size)
+{
+  void *block = malloc (size ? size : (size_t) 1);
+  if (!block) fatal ("Out of memory");
+  return (block);
+}
+
+
+/* Resize a block of free storage
+ * Accepts: ** pointer to current block
+ *	    new size
+ */
+
+void fs_resize (void **block,size_t size)
+{
+  if (!(*block = realloc (*block,size ? size : (size_t) 1)))
+    fatal ("Can't resize memory");
+}
+
+
+/* Return a block of free storage
+ * Accepts: ** pointer to free storage block
+ */
+
+void fs_give (void **block)
+{
+  free (*block);
+  *block = NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/vms/ftl_vms.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,38 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	DOS/VMS/TOPS-20 crash management routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Report a fatal error
+ * Accepts: string to output
+ */
+
+void fatal (char *string)
+{
+  mm_fatal (string);		/* pass up the string */
+  abort ();			/* die horribly */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/vms/link.opt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1 @@
+SYS$SHARE:VAXCRTL/SHARE
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/vms/link_mnt.opt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1 @@
+MULTINET:MULTINET_SOCKET_LIBRARY/SHARE
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/vms/link_nlb.opt	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,1 @@
+NETLIB_SHR/SHARE
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/vms/linkage.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,37 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Default driver linkage
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	13 June 1995
+ * Last Edited:	23 May 2007
+ */
+
+  mail_link (&imapdriver);		/* link in the imap driver */
+  mail_link (&nntpdriver);		/* link in the nntp driver */
+  mail_link (&pop3driver);		/* link in the pop3 driver */
+  mail_link (&dummydriver);		/* link in the dummy driver */
+  auth_link (&auth_ext);		/* link in the ext authenticator */
+  auth_link (&auth_md5);		/* link in the md5 authenticator */
+  auth_link (&auth_pla);		/* link in the plain authenticator */
+  auth_link (&auth_log);		/* link in the log authenticator */
+  mail_versioncheck (CCLIENTVERSION);	/* validate version */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/vms/linkage.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,36 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Default driver linkage
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	13 June 1995
+ * Last Edited:	30 August 2006
+ */
+
+extern DRIVER imapdriver;
+extern DRIVER nntpdriver;
+extern DRIVER pop3driver;
+extern DRIVER dummydriver;
+extern AUTHENTICATOR auth_ext;
+extern AUTHENTICATOR auth_log;
+extern AUTHENTICATOR auth_md5;
+extern AUTHENTICATOR auth_pla;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/vms/nl_vms.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,92 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	UNIX/VMS newline routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Copy string with CRLF newlines
+ * Accepts: destination string
+ *	    pointer to size of destination string buffer
+ *	    source string
+ *	    length of source string
+ * Returns: length of copied string
+ */
+
+unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl,
+			  unsigned char *src,unsigned long srcl)
+{
+  long i = srcl * 2,j;
+  unsigned char c,*d = src;
+  if (*dst) {			/* candidate destination provided? */
+				/* count NLs if doesn't fit worst-case */
+    if (i > *dstl) for (i = j = srcl; j; --j) if (*d++ == '\012') i++;
+				/* still too small, must reset destination */
+    if (i > *dstl) fs_give ((void **) dst);
+  }
+				/* make a new buffer if needed */
+  if (!*dst) *dst = (char *) fs_get ((*dstl = i) + 1);
+  d = *dst;			/* destination string */
+  if (srcl) do {		/* main copy loop */
+    if ((c = *src++) < '\016') {
+				/* prepend CR to LF */
+      if (c == '\012') *d++ = '\015';
+				/* unlikely CR */
+      else if ((c == '\015') && (srcl > 1) && (*src == '\012')) {
+	*d++ = c;		/* copy the CR */
+	c = *src++;		/* grab the LF */
+	--srcl;			/* adjust the count */
+      }
+    }
+    *d++ = c;			/* copy character */
+  } while (--srcl);
+  *d = '\0';			/* tie off destination */
+  return d - *dst;		/* return length */
+}
+
+/* Length of string after strcrlfcpy applied
+ * Accepts: source string
+ * Returns: length of string
+ */
+
+unsigned long strcrlflen (STRING *s)
+{
+  unsigned long pos = GETPOS (s);
+  unsigned long i = SIZE (s);
+  unsigned long j = i;
+  while (j--) switch (SNX (s)) {/* search for newlines */
+  case '\015':			/* unlikely carriage return */
+    if (j && (CHR (s) == '\012')) {
+      SNX (s);			/* eat the line feed */
+      j--;
+    }
+    break;
+  case '\012':			/* line feed? */
+    i++;
+  default:			/* ordinary chararacter */
+    break;
+  }
+  SETPOS (s,pos);		/* restore old position */
+  return i;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/vms/os_vms.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,76 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- VMS version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	2 August 1994
+ * Last Edited:	30 August 2006
+ */
+ 
+#include "tcp_vms.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include "misc.h"
+
+
+#include "fs_vms.c"
+#include "ftl_vms.c"
+#include "nl_vms.c"
+#include "env_vms.c"
+#include "tcp_vms.c"
+
+#define server_login(user,pass,authuser,argc,argv) NIL
+#define authserver_login(user,authuser,argc,argv) NIL
+#define myusername() ""		/* dummy definition to prevent build errors */
+#define MD5ENABLE ""
+
+#include "auth_md5.c"
+#include "auth_pla.c"
+#include "auth_log.c"
+
+
+/* Emulator for UNIX getpass() call
+ * Accepts: prompt
+ * Returns: password
+ */
+
+#define PWDLEN 128		/* used by Linux */
+
+char *getpass (const char *prompt)
+{
+  char *s;
+  static char pwd[PWDLEN];
+  fputs (prompt,stdout);
+  fgets (pwd,PWDLEN-1,stdin);
+  if (s = strchr (pwd,'\n')) *s = '\0';
+  return pwd;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/vms/os_vms.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,52 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- VMS version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	2 August 1994
+ * Last Edited:	30 January 2007
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unixio.h>
+#include <file.h>
+#include <stat.h>
+
+#define L_SET SEEK_SET
+#define L_INCR SEEK_CUR
+#define L_XTND SEEK_END
+
+#include "env_vms.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+
+#define	gethostid clock
+#define random rand
+#define unlink delete
+
+char *getpass (const char *prompt);
+
+#define strtok_r(a,b,c) strtok(a,b)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/vms/pmatch.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,89 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	IMAP Wildcard Matching Routines (case-independent)
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	15 June 2000
+ * Last Edited:	30 August 2006
+ */
+
+/* Wildcard pattern match
+ * Accepts: base string
+ *	    pattern string
+ *	    delimiter character
+ * Returns: T if pattern matches base, else NIL
+ */
+
+long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim)
+{
+  switch (*pat) {
+  case '%':			/* non-recursive */
+				/* % at end, OK if no inferiors */
+    if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T;
+                                /* scan remainder of string until delimiter */
+    do if (pmatch_full (s,pat+1,delim)) return T;
+    while ((*s != delim) && *s++);
+    break;
+  case '*':			/* match 0 or more characters */
+    if (!pat[1]) return T;	/* * at end, unconditional match */
+				/* scan remainder of string */
+    do if (pmatch_full (s,pat+1,delim)) return T;
+    while (*s++);
+    break;
+  case '\0':			/* end of pattern */
+    return *s ? NIL : T;	/* success if also end of base */
+  default:			/* match this character */
+    return compare_uchar (*pat,*s) ? NIL : pmatch_full (s+1,pat+1,delim);
+  }
+  return NIL;
+}
+
+/* Directory pattern match
+ * Accepts: base string
+ *	    pattern string
+ *	    delimiter character
+ * Returns: T if base is a matching directory of pattern, else NIL
+ */
+
+long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim)
+{
+  switch (*pat) {
+  case '%':			/* non-recursive */
+    if (!*s) return T;		/* end of base means have a subset match */
+    if (!*++pat) return NIL;	/* % at end, no inferiors permitted */
+				/* scan remainder of string until delimiter */
+    do if (dmatch (s,pat,delim)) return T;
+    while ((*s != delim) && *s++);
+    if (*s && !s[1]) return T;	/* ends with delimiter, must be subset */
+    return dmatch (s,pat,delim);/* do new scan */
+  case '*':			/* match 0 or more characters */
+    return T;			/* unconditional match */
+  case '\0':			/* end of pattern */
+    break;
+  default:			/* match this character */
+    if (*s) return compare_uchar (*pat,*s) ? NIL : dmatch (s+1,pat+1,delim);
+				/* end of base, return if at delimiter */
+    else if (*pat == delim) return T;
+    break;
+  }
+  return NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/vms/tcp_vms.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,52 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	VMS TCP/IP routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+/* TCP input buffer */
+
+#define BUFLEN 8192
+
+
+/* TCP I/O stream */
+
+#define TCPSTREAM struct tcp_stream
+TCPSTREAM {
+  char *host;			/* host name */
+  unsigned long port;		/* port number */
+  char *localhost;		/* local host name */
+  int tcpsi;			/* input socket */
+  int tcpso;			/* output socket */
+  int ictr;			/* input counter */
+  char *iptr;			/* input pointer */
+  char ibuf[BUFLEN];		/* input buffer */
+};
+
+
+/* Local function prototypes */
+
+long tcp_abort (TCPSTREAM *stream);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/vms/tcp_vmsl.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,378 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	VMS TCP/IP routines for Netlib.
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	2 August 1994
+ * Last Edited:	13 January 2008
+ */
+
+/* Thanks to Yehavi Bourvine at The Hebrew University of Jerusalem who
+   contributed the original VMS code */
+
+#include <descrip.h>
+
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+			       long *contd);
+
+/* TCP/IP manipulate parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *tcp_parameters (long function,void *value)
+{
+  return NIL;
+}
+
+ 
+/* TCP/IP open
+ * Accepts: host name
+ *	    contact service name
+ *	    contact port number
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
+{
+  TCPSTREAM *stream = NIL;
+  unsigned long sock;
+  int status;
+  char tmp[MAILTMPLEN];
+				/* hostname to connect to */
+  struct dsc$descriptor HostDesc = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
+  port &= 0xffff;		/* erase flags */
+				/* assign a local socket */
+  if (!((status = net_assign (&sock)) & 0x1)) {
+    sprintf (tmp,"Unable to assign to net, status=%d",status);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+  if (!((status = net_bind (&sock,1)) & 0x1)) {
+    sprintf (tmp,"Unable to create local socket, status=%d",status);
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* open connection */
+  HostDesc.dsc$w_length = strlen (host);
+  HostDesc.dsc$a_pointer = host;
+  if (!((status = tcp_connect (&sock,&HostDesc,port)) & 0x1)) {
+    sprintf (tmp,"Can't connect to %.80s,%lu: %s",host,port,strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* create TCP/IP stream */
+  stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
+  stream->host = cpystr (host);	/* copy official host name */
+				/* copy local host name */
+  stream->localhost = cpystr (mylocalhost ());
+  stream->port = port;		/* copy port number */
+				/* init sockets */
+  stream->tcpsi = stream->tcpso = sock;
+  stream->ictr = 0;		/* init input counter */
+  return stream;		/* return success */
+}
+
+/* TCP/IP authenticated open
+ * Accepts: NETMBX specifier
+ *	    service name
+ *	    returned user name buffer
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
+{
+  return NIL;
+}
+
+/* TCP receive line
+ * Accepts: TCP stream
+ * Returns: text line string or NIL if failure
+ */
+
+char *tcp_getline (TCPSTREAM *stream)
+{
+  unsigned long n,contd;
+  char *ret = tcp_getline_work (stream,&n,&contd);
+  if (ret && contd) {		/* got a line needing continuation? */
+    STRINGLIST *stl = mail_newstringlist ();
+    STRINGLIST *stc = stl;
+    do {			/* collect additional lines */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+      stc = stc->next = mail_newstringlist ();
+      ret = tcp_getline_work (stream,&n,&contd);
+    } while (ret && contd);
+    if (ret) {			/* stash final part of line on list */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+				/* determine how large a buffer we need */
+      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
+      ret = fs_get (n + 1);	/* copy parts into buffer */
+      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
+	memcpy (ret + n,stc->text.data,stc->text.size);
+      ret[n] = '\0';
+    }
+    mail_free_stringlist (&stl);/* either way, done with list */
+  }
+  return ret;
+}
+
+/* TCP receive line or partial line
+ * Accepts: TCP stream
+ *	    pointer to return size
+ *	    pointer to return continuation flag
+ * Returns: text line string, size and continuation flag, or NIL if failure
+ */
+
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+			       long *contd)
+{
+  unsigned long n;
+  char *s,*ret,c,d;
+  *contd = NIL;			/* assume no continuation */
+				/* make sure have data */
+  if (!tcp_getdata (stream)) return NIL;
+  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
+    d = *stream->iptr++;	/* slurp another character */
+    if ((c == '\015') && (d == '\012')) {
+      ret = (char *) fs_get (n--);
+      memcpy (ret,s,*size = n);	/* copy into a free storage string */
+      ret[n] = '\0';		/* tie off string with null */
+      return ret;
+    }
+  }
+				/* copy partial string from buffer */
+  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
+				/* get more data from the net */
+  if (!tcp_getdata (stream)) fs_give ((void **) &ret);
+				/* special case of newline broken by buffer */
+  else if ((c == '\015') && (*stream->iptr == '\012')) {
+    stream->iptr++;		/* eat the line feed */
+    stream->ictr--;
+    ret[*size = --n] = '\0';	/* tie off string with null */
+  }
+  else *contd = LONGT;		/* continuation needed */
+  return ret;
+}
+
+/* TCP/IP receive buffer
+ * Accepts: TCP/IP stream
+ *	    size in bytes
+ *	    buffer to read into
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
+{
+  unsigned long n;
+  char *bufptr = buffer;
+  while (size > 0) {		/* until request satisfied */
+    if (!tcp_getdata (stream)) return NIL;
+    n = min (size,stream->ictr);/* number of bytes to transfer */
+				/* do the copy */
+    memcpy (bufptr,stream->iptr,n);
+    bufptr += n;		/* update pointer */
+    stream->iptr +=n;
+    size -= n;			/* update # of bytes to do */
+    stream->ictr -=n;
+  }
+  bufptr[0] = '\0';		/* tie off string */
+  return T;
+}
+
+
+/* TCP/IP receive data
+ * Accepts: TCP/IP stream
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getdata (TCPSTREAM *stream)
+{
+  char tmp[MAILTMPLEN];
+  int i,status;
+  /* Note: the doc says we need here dynamic descriptor, but we need static
+   * one... */
+  struct dsc$descriptor BufDesc = {BUFLEN,DSC$K_DTYPE_T,DSC$K_CLASS_S,
+				     stream->ibuf};
+  static short iosb[4];
+  if (stream->tcpsi < 0) return NIL;
+  while (stream->ictr < 1) {	/* if nothing in the buffer */
+    if (!((status = tcp_receive(&(stream->tcpsi), &BufDesc, iosb)) & 0x1)) {
+      sprintf (tmp,"Error reading from TcpIp/NETLIB, status=%d",status);
+      mm_log (tmp,ERROR);
+      return tcp_abort (stream);
+    }
+    if (iosb[1] > BUFLEN) i = BUFLEN;
+    else i = iosb[1];
+    if (i < 1) return tcp_abort (stream);
+    stream->ictr = i;		/* set new byte count */
+    stream->iptr = stream->ibuf;/* point at TCP buffer */
+  }
+  return T;
+}
+
+/* TCP/IP send string as record
+ * Accepts: TCP/IP stream
+ *	    string pointer
+ * Returns: T if success else NIL
+ */
+
+long tcp_soutr (TCPSTREAM *stream,char *string)
+{
+  return tcp_sout (stream,string,(unsigned long) strlen (string));
+}
+
+
+/* TCP/IP send string
+ * Accepts: TCP/IP stream
+ *	    string pointer
+ *	    byte count
+ * Returns: T if success else NIL
+ */
+
+long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
+{
+  int status;
+  struct dsc$descriptor_s BufDesc = {strlen(string),DSC$K_DTYPE_T,
+				       DSC$K_CLASS_S,string };
+				/* 2 = Do not add \r\n */
+  return ((status = tcp_send (&(stream->tcpso),&BufDesc,2)) & 0x1) ? T :
+    tcp_abort (stream);
+}
+
+/* TCP/IP close
+ * Accepts: TCP/IP stream
+ */
+
+void tcp_close (TCPSTREAM *stream)
+{
+  tcp_abort (stream);		/* nuke the stream */
+				/* flush host names */
+  fs_give ((void **) &stream->host);
+  fs_give ((void **) &stream->localhost);
+  fs_give ((void **) &stream);	/* flush the stream */
+}
+
+
+/* TCP/IP abort stream
+ * Accepts: TCP/IP stream
+ * Returns: NIL always
+ */
+
+long tcp_abort (TCPSTREAM *stream)
+{
+  if (stream->tcpsi >= 0) {	/* no-op if no socket */
+				/* nuke the socket */
+    tcp_disconnect (&(stream->tcpsi));
+    stream->tcpsi = stream->tcpso = -1;
+  }
+  return NIL;
+}
+
+/* TCP/IP get host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_host (TCPSTREAM *stream)
+{
+  return stream->host;		/* return host name */
+}
+
+
+/* TCP/IP get remote host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_remotehost (TCPSTREAM *stream)
+{
+  return stream->host;		/* return host name */
+}
+
+
+/* TCP/IP return port for this stream
+ * Accepts: TCP/IP stream
+ * Returns: port number for this stream
+ */
+
+unsigned long tcp_port (TCPSTREAM *stream)
+{
+  return stream->port;		/* return port number */
+}
+
+
+/* TCP/IP get local host name
+ * Accepts: TCP/IP stream
+ * Returns: local host name
+ */
+
+char *tcp_localhost (TCPSTREAM *stream)
+{
+  return stream->localhost;	/* return local host name */
+}
+
+/* Return my local host name
+ * Returns: my local host name
+ */
+
+char *mylocalhost ()
+{
+  int status;
+  char tmp[MAILTMPLEN];
+  if (!myLocalHost) {		/* have local host yet? */
+				/* receives local host name */
+    struct dsc$descriptor LocalhostDesc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_D,NULL};
+    if (!((status = net_get_hostname (&LocalhostDesc)) & 0x1)) {
+      sprintf (tmp,"Can't get local hostname, status=%d",status);
+      mm_log (tmp,ERROR);
+      return "UNKNOWN";
+    }
+    strncpy (tmp,LocalhostDesc.dsc$a_pointer,LocalhostDesc.dsc$w_length);
+    tmp[LocalhostDesc.dsc$w_length] = '\0';
+    str$free1_dx (&LocalhostDesc);
+    myLocalHost = cpystr (tmp);
+  }
+  return myLocalHost;
+}
+
+/* TCP/IP return canonical form of host name
+ * Accepts: host name
+ * Returns: canonical form of host name
+ */
+
+char *tcp_canonical (char *name)
+{
+  return name;
+}
+
+
+/* TCP/IP get client host name (server calls only)
+ * Returns: client host name
+ */
+
+char *tcp_clienthost ()
+{
+  return "UNKNOWN";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/vms/tcp_vmsm.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,479 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	VMS TCP/IP routines for Multinet
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	2 August 1994
+ * Last Edited:	13 January 2008
+ */
+
+			
+static tcptimeout_t tmoh = NIL;	/* TCP timeout handler routine */
+static long ttmo_read = 0;	/* TCP timeouts, in seconds */
+static long ttmo_write = 0;
+
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+			       long *contd);
+
+/* TCP/IP manipulate parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *tcp_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case SET_TIMEOUT:
+    tmoh = (tcptimeout_t) value;
+  case GET_TIMEOUT:
+    ret = (void *) tmoh;
+    break;
+  case SET_READTIMEOUT:
+    ttmo_read = (long) value;
+  case GET_READTIMEOUT:
+    ret = (void *) ttmo_read;
+    break;
+  case SET_WRITETIMEOUT:
+    ttmo_write = (long) value;
+  case GET_WRITETIMEOUT:
+    ret = (void *) ttmo_write;
+    break;
+  }
+  return ret;
+}
+ 
+/* TCP/IP open
+ * Accepts: host name
+ *	    contact service name
+ *	    contact port number
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
+{
+  TCPSTREAM *stream = NIL;
+  int sock;
+  char *s;
+  struct sockaddr_in sin;
+  struct hostent *host_name;
+  char hostname[MAILTMPLEN];
+  char tmp[MAILTMPLEN];
+  struct protoent *pt = getprotobyname ("tcp");
+  struct servent *sv = NIL;
+  port &= 0xffff;		/* erase flags */
+  if (service) {		/* service specified? */
+    if (*service == '*') {	/* yes, special alt driver kludge? */
+      sv = getservbyname (service + 1,"tcp");
+    }
+    else sv = getservbyname (service,"tcp");
+  }
+				/* user service name port */
+  if (sv) port = ntohs (sin.sin_port = sv->s_port);
+ 				/* copy port number in network format */
+  else sin.sin_port = htons (port);
+  /* The domain literal form is used (rather than simply the dotted decimal
+     as with other Unix programs) because it has to be a valid "host name"
+     in mailsystem terminology. */
+				/* look like domain literal? */
+  if (host[0] == '[' && host[(strlen (host))-1] == ']') {
+    strcpy (hostname,host+1);	/* yes, copy number part */
+    hostname[(strlen (hostname))-1] = '\0';
+    if ((sin.sin_addr.s_addr = inet_addr (hostname)) != -1) {
+      sin.sin_family = AF_INET;	/* family is always Internet */
+      strcpy (hostname,host);	/* hostname is user's argument */
+    }
+    else {
+      sprintf (tmp,"Bad format domain-literal: %.80s",host);
+      mm_log (tmp,ERROR);
+      return NIL;
+    }
+  }
+
+  else {			/* lookup host name, note that brain-dead Unix
+				   requires lowercase! */
+    strcpy (hostname,host);	/* in case host is in write-protected memory */
+    if ((host_name = gethostbyname (lcase (hostname)))) {
+				/* copy address type */
+      sin.sin_family = host_name->h_addrtype;
+				/* copy host name */
+      strcpy (hostname,host_name->h_name);
+				/* copy host addresses */
+      memcpy (&sin.sin_addr,host_name->h_addr,host_name->h_length);
+    }
+    else {
+      sprintf (tmp,"No such host as %.80s",host);
+      mm_log (tmp,ERROR);
+      return NIL;
+    }
+  }
+				/* get a TCP stream */
+  if ((sock = socket (sin.sin_family,SOCK_STREAM,pt ? pt->p_proto : 0)) < 0) {
+    sprintf (tmp,"Unable to create TCP socket: %s",strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+#if 0
+  /* Maybe this test is necessary.  It depends upon how VMS implements
+   * fd_set.  UNIX-style fd_set needs it; Windows-style does not.
+   */
+  else if (sock >= FD_SETSIZE) {/* unselectable sockets are useless */
+    sprintf (tmp,"Unable to create selectable TCP socket (%d >= %d)",
+	     sock,FD_SETSIZE);
+    close (sock);
+    return NIL;
+  }
+#endif
+				/* open connection */
+  if (connect (sock,(struct sockaddr *)&sin,sizeof (sin)) < 0) {
+    sprintf (tmp,"Can't connect to %.80s,%d: %s",hostname,port,
+	     strerror (errno));
+    mm_log (tmp,ERROR);
+    return NIL;
+  }
+				/* create TCP/IP stream */
+  stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
+				/* copy official host name */
+  stream->host = cpystr (hostname);
+				/* get local name */
+  gethostname (tmp,MAILTMPLEN-1);
+  stream->localhost = cpystr ((host_name = gethostbyname (tmp)) ?
+			      host_name->h_name : tmp);
+				/* init sockets */
+  stream->port = port;		/* port number */
+  stream->tcpsi = stream->tcpso = sock;
+  stream->ictr = 0;		/* init input counter */
+  return stream;		/* return success */
+}
+
+/* TCP/IP authenticated open
+ * Accepts: NETMBX specifier
+ *	    service name
+ *	    returned user name buffer
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
+{
+  return NIL;
+}
+
+/* TCP receive line
+ * Accepts: TCP stream
+ * Returns: text line string or NIL if failure
+ */
+
+char *tcp_getline (TCPSTREAM *stream)
+{
+  unsigned long n,contd;
+  char *ret = tcp_getline_work (stream,&n,&contd);
+  if (ret && contd) {		/* got a line needing continuation? */
+    STRINGLIST *stl = mail_newstringlist ();
+    STRINGLIST *stc = stl;
+    do {			/* collect additional lines */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+      stc = stc->next = mail_newstringlist ();
+      ret = tcp_getline_work (stream,&n,&contd);
+    } while (ret && contd);
+    if (ret) {			/* stash final part of line on list */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+				/* determine how large a buffer we need */
+      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
+      ret = fs_get (n + 1);	/* copy parts into buffer */
+      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
+	memcpy (ret + n,stc->text.data,stc->text.size);
+      ret[n] = '\0';
+    }
+    mail_free_stringlist (&stl);/* either way, done with list */
+  }
+  return ret;
+}
+
+/* TCP receive line or partial line
+ * Accepts: TCP stream
+ *	    pointer to return size
+ *	    pointer to return continuation flag
+ * Returns: text line string, size and continuation flag, or NIL if failure
+ */
+
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+			       long *contd)
+{
+  unsigned long n;
+  char *s,*ret,c,d;
+  *contd = NIL;			/* assume no continuation */
+				/* make sure have data */
+  if (!tcp_getdata (stream)) return NIL;
+  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
+    d = *stream->iptr++;	/* slurp another character */
+    if ((c == '\015') && (d == '\012')) {
+      ret = (char *) fs_get (n--);
+      memcpy (ret,s,*size = n);	/* copy into a free storage string */
+      ret[n] = '\0';		/* tie off string with null */
+      return ret;
+    }
+  }
+				/* copy partial string from buffer */
+  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
+				/* get more data from the net */
+  if (!tcp_getdata (stream)) fs_give ((void **) &ret);
+				/* special case of newline broken by buffer */
+  else if ((c == '\015') && (*stream->iptr == '\012')) {
+    stream->iptr++;		/* eat the line feed */
+    stream->ictr--;
+    ret[*size = --n] = '\0';	/* tie off string with null */
+  }
+  else *contd = LONGT;		/* continuation needed */
+  return ret;
+}
+
+/* TCP/IP receive buffer
+ * Accepts: TCP/IP stream
+ *	    size in bytes
+ *	    buffer to read into
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
+{
+  unsigned long n;
+  char *bufptr = buffer;
+  while (size > 0) {		/* until request satisfied */
+    if (!tcp_getdata (stream)) return NIL;
+    n = min (size,stream->ictr);/* number of bytes to transfer */
+				/* do the copy */
+    memcpy (bufptr,stream->iptr,n);
+    bufptr += n;		/* update pointer */
+    stream->iptr +=n;
+    size -= n;			/* update # of bytes to do */
+    stream->ictr -=n;
+  }
+  bufptr[0] = '\0';		/* tie off string */
+  return T;
+}
+
+/* TCP/IP receive data
+ * Accepts: TCP/IP stream
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getdata (TCPSTREAM *stream)
+{
+  int i;
+  fd_set fds,efds;
+  struct timeval tmo;
+  time_t t = time (0);
+  if (stream->tcpsi < 0) return NIL;
+  while (stream->ictr < 1) {	/* if nothing in the buffer */
+    time_t tl = time (0);	/* start of request */
+    tmo.tv_sec = ttmo_read;	/* read timeout */
+    tmo.tv_usec = 0;
+    FD_ZERO (&fds);		/* initialize selection vector */
+    FD_ZERO (&efds);		/* handle errors too */
+    FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */
+    FD_SET(stream->tcpsi,&efds);/* set bit in error selection vector */
+    errno = NIL;		/* block and read */
+    while (((i = select (getdtablesize (),&fds,0,&efds,ttmo_read ? &tmo:0))<0)
+	   && (errno == EINTR));
+    if (!i) {			/* timeout? */
+      time_t tc = time (0);
+      if (tmoh && ((*tmoh) (tc - t,tc - tl))) continue;
+      else return tcp_abort (stream);
+    }
+    else if (i < 0) return tcp_abort (stream);
+    while (((i = socket_read (stream->tcpsi,stream->ibuf,BUFLEN)) < 0) &&
+	   (errno == EINTR));
+    if (i < 1) return tcp_abort (stream);
+    stream->iptr = stream->ibuf;/* point at TCP buffer */
+    stream->ictr = i;		/* set new byte count */
+  }
+  return T;
+}
+
+/* TCP/IP send string as record
+ * Accepts: TCP/IP stream
+ *	    string pointer
+ * Returns: T if success else NIL
+ */
+
+long tcp_soutr (TCPSTREAM *stream,char *string)
+{
+  return tcp_sout (stream,string,(unsigned long) strlen (string));
+}
+
+
+/* TCP/IP send string
+ * Accepts: TCP/IP stream
+ *	    string pointer
+ *	    byte count
+ * Returns: T if success else NIL
+ */
+
+long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
+{
+  int i;
+  fd_set fds;
+  struct timeval tmo;
+  time_t t = time (0);
+  if (stream->tcpso < 0) return NIL;
+  while (size > 0) {		/* until request satisfied */
+    time_t tl = time (0);	/* start of request */
+    tmo.tv_sec = ttmo_write;	/* write timeout */
+    tmo.tv_usec = 0;
+    FD_ZERO (&fds);		/* initialize selection vector */
+    FD_SET (stream->tcpso,&fds);/* set bit in selection vector */
+    errno = NIL;		/* block and write */
+    while (((i = select (getdtablesize (),0,&fds,0,ttmo_write ? &tmo : 0)) < 0)
+	   && (errno == EINTR));
+    if (!i) {			/* timeout? */
+      time_t tc = time (0);
+      if (tmoh && ((*tmoh) (tc - t,tc - tl))) continue;
+      else return tcp_abort (stream);
+    }
+    else if (i < 0) return tcp_abort (stream);
+    while (((i = socket_write (stream->tcpso,string,size)) < 0) &&
+	   (errno == EINTR));
+    if (i < 0) return tcp_abort (stream);
+    size -= i;			/* how much we sent */
+    string += i;
+  }
+  return T;			/* all done */
+}
+
+/* TCP/IP close
+ * Accepts: TCP/IP stream
+ */
+
+void tcp_close (TCPSTREAM *stream)
+{
+  tcp_abort (stream);		/* nuke the stream */
+				/* flush host names */
+  fs_give ((void **) &stream->host);
+  fs_give ((void **) &stream->localhost);
+  fs_give ((void **) &stream);	/* flush the stream */
+}
+
+
+/* TCP/IP abort stream
+ * Accepts: TCP/IP stream
+ * Returns: NIL always
+ */
+
+long tcp_abort (TCPSTREAM *stream)
+{
+  int i;
+  if (stream->tcpsi >= 0) {	/* no-op if no socket */
+				/* nuke the socket */
+    socket_close (stream->tcpsi);
+    if (stream->tcpsi != stream->tcpso) socket_close (stream->tcpso);
+    stream->tcpsi = stream->tcpso = -1;
+  }
+  return NIL;
+}
+
+/* TCP/IP get host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_host (TCPSTREAM *stream)
+{
+  return stream->host;		/* return host name */
+}
+
+
+/* TCP/IP get remote host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_remotehost (TCPSTREAM *stream)
+{
+  return stream->host;		/* return host name */
+}
+
+
+/* TCP/IP return port for this stream
+ * Accepts: TCP/IP stream
+ * Returns: port number for this stream
+ */
+
+unsigned long tcp_port (TCPSTREAM *stream)
+{
+  return stream->port;		/* return port number */
+}
+
+
+/* TCP/IP get local host name
+ * Accepts: TCP/IP stream
+ * Returns: local host name
+ */
+
+char *tcp_localhost (TCPSTREAM *stream)
+{
+  return stream->localhost;	/* return local host name */
+}
+
+/* Return my local host name
+ * Returns: my local host name
+ */
+
+char *mylocalhost ()
+{
+  char tmp[MAILTMPLEN];
+  struct hostent *hn;
+  if (!myLocalHost) {		/* have local host yet? */
+    gethostname(tmp,MAILTMPLEN);/* get local host name */
+    myLocalHost = cpystr ((hn = gethostbyname (tmp)) ? hn->h_name : tmp);
+  }
+  return myLocalHost;
+}
+
+
+/* TCP/IP return canonical form of host name
+ * Accepts: host name
+ * Returns: canonical form of host name
+ */
+
+char *tcp_canonical (char *name)
+{
+  char host[MAILTMPLEN];
+  struct hostent *he;
+				/* look like domain literal? */
+  if (name[0] == '[' && name[strlen (name) - 1] == ']') return name;
+				/* note that Unix requires lowercase! */
+  else return (he = gethostbyname (lcase (strcpy (host,name)))) ?
+    he->h_name : name;
+}
+
+
+/* TCP/IP get client host name (server calls only)
+ * Returns: client host name
+ */
+
+char *tcp_clienthost ()
+{
+  return "UNKNOWN";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/vms/tcp_vmsn.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,222 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Dummy VMS TCP/IP routines for non-TCP/IP systems
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	2 August 1994
+ * Last Edited:	30 August 2006
+ */
+ 
+/* TCP/IP manipulate parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *tcp_parameters (long function,void *value)
+{
+  return NIL;
+}
+
+
+/* TCP/IP open
+ * Accepts: host name
+ *	    contact service name
+ *	    contact port number
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
+{
+  char tmp[MAILTMPLEN];
+  port &= 0xffff;		/* erase flags */
+  if (port) sprintf (tmp,"Can't connect to %.80s,%d: no TCP",host,port);
+  else sprintf (tmp,"Can't connect to %.80s,%s: no TCP",host,service);
+  mm_log (tmp,ERROR);
+  return NIL;
+}
+
+
+/* TCP/IP authenticated open
+ * Accepts: NETMBX specifier
+ *	    service name
+ *	    returned user name buffer
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
+{
+  return NIL;
+}
+
+/* TCP/IP receive line
+ * Accepts: TCP/IP stream
+ * Returns: text line string or NIL if failure
+ */
+
+char *tcp_getline (TCPSTREAM *stream)
+{
+  return NIL;
+}
+
+
+/* TCP/IP receive buffer
+ * Accepts: TCP/IP stream
+ *	    size in bytes
+ *	    buffer to read into
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
+{
+  return NIL;
+}
+
+
+/* TCP/IP receive data
+ * Accepts: TCP/IP stream
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getdata (TCPSTREAM *stream)
+{
+  return NIL;
+}
+
+/* TCP/IP send string as record
+ * Accepts: TCP/IP stream
+ *	    string pointer
+ * Returns: T if success else NIL
+ */
+
+long tcp_soutr (TCPSTREAM *stream,char *string)
+{
+  return NIL;
+}
+
+
+/* TCP/IP send string
+ * Accepts: TCP/IP stream
+ *	    string pointer
+ *	    byte count
+ * Returns: T if success else NIL
+ */
+
+long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
+{
+  return NIL;
+}
+
+
+/* TCP/IP close
+ * Accepts: TCP/IP stream
+ */
+
+void tcp_close (TCPSTREAM *stream)
+{
+}
+
+
+/* TCP/IP abort stream
+ * Accepts: TCP/IP stream
+ * Returns: NIL always
+ */
+
+long tcp_abort (TCPSTREAM *stream)
+{
+  return NIL;
+}
+
+/* TCP/IP get host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_host (TCPSTREAM *stream)
+{
+  return NIL;
+}
+
+
+/* TCP/IP get remote host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_remotehost (TCPSTREAM *stream)
+{
+  return NIL;
+}
+
+
+/* TCP/IP get local host name
+ * Accepts: TCP/IP stream
+ * Returns: local host name
+ */
+
+char *tcp_localhost (TCPSTREAM *stream)
+{
+  return NIL;
+}
+
+
+/* TCP/IP return port for this stream
+ * Accepts: TCP/IP stream
+ * Returns: port number for this stream
+ */
+
+unsigned long tcp_port (TCPSTREAM *stream)
+{
+  return 0xffffffff;		/* return port number */
+}
+
+
+/* Return my local host name
+ * Returns: my local host name
+ */
+
+char *mylocalhost ()
+{
+				/* have local host yet? */
+  if (!myLocalHost) myLocalHost = cpystr (getenv ("SYS$NODE"));
+  return myLocalHost;
+}
+
+/* TCP/IP return canonical form of host name
+ * Accepts: host name
+ * Returns: canonical form of host name
+ */
+
+char *tcp_canonical (char *name)
+{
+  return name;
+}
+
+
+/* TCP/IP get client host name (server calls only)
+ * Returns: client host name
+ */
+
+char *tcp_clienthost ()
+{
+  return "UNKNOWN";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/wce/drivers.bat	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,33 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM     http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM 
+REM ========================================================================
+
+REM Program:	Driver Linkage Generator for DOS/NT
+REM
+REM Author:	Mark Crispin
+REM		Networks and Distributed Computing
+REM		Computing & Communications
+REM		University of Washington
+REM		Administration Building, AG-44
+REM		Seattle, WA  98195
+REM		Internet: MRC@CAC.Washington.EDU
+REM
+REM Date:	11 October 1989
+REM Last Edited:30 August 2006
+
+REM Erase old driver linkage
+IF EXIST LINKAGE.* DEL LINKAGE.*
+
+REM Now define the new list
+FOR %%D IN (%1 %2 %3 %4 %5 %6 %7 %8 %9) DO CALL DRIVRAUX %%D
+
+EXIT 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/wce/drivraux.bat	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,30 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM     http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM 
+REM ========================================================================
+
+REM Program:	Driver Linkage Generator auxillary for NT/Win9x
+REM
+REM Author:	Mark Crispin
+REM		Networks and Distributed Computing
+REM		Computing & Communications
+REM		University of Washington
+REM		Administration Building, AG-44
+REM		Seattle, WA  98195
+REM		Internet: MRC@CAC.Washington.EDU
+REM
+REM Date:	11 October 1989
+REM Last Edited:30 August 2006
+
+ECHO extern DRIVER %1driver; >> LINKAGE.H
+REM Note the introduction of the caret to quote the ampersand in NT
+if "%OS%" == "Windows_NT" ECHO   mail_link (^&%1driver);	/* link in the %1 driver */ >> LINKAGE.C
+if "%OS%" == "" ECHO   mail_link (&%1driver);	/* link in the %1 driver */ >> LINKAGE.C
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/wce/dummy.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,43 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Dummy routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	9 May 1991
+ * Last Edited:	30 August 2006
+ */
+
+/* Exported function prototypes */
+
+void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents);
+void dummy_list (MAILSTREAM *stream,char *ref,char *pat);
+void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat);
+long scan_contents (DRIVER *dtb,char *name,char *contents,
+		    unsigned long csiz,unsigned long fsiz);
+long dummy_scan_contents (char *name,char *contents,unsigned long csiz,
+			  unsigned long fsiz);
+long dummy_create (MAILSTREAM *stream,char *mailbox);
+long dummy_create_path (MAILSTREAM *stream,char *path,long dirmode);
+long dummy_delete (MAILSTREAM *stream,char *mailbox);
+long dummy_rename (MAILSTREAM *stream,char *old,char *newname);
+char *dummy_file (char *dst,char *name);
+long dummy_canonicalize (char *tmp,char *ref,char *pat);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/wce/dummywce.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,301 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Dummy routines for WCE
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	24 May 1993
+ * Last Edited:	30 August 2006
+ */
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <direct.h>
+#include "mail.h"
+#include "osdep.h"
+#include <sys\stat.h>
+#include <dos.h>
+#include "dummy.h"
+#include "misc.h"
+
+/* Function prototypes */
+
+DRIVER *dummy_valid (char *name);
+void *dummy_parameters (long function,void *value);
+MAILSTREAM *dummy_open (MAILSTREAM *stream);
+void dummy_close (MAILSTREAM *stream,long options);
+long dummy_ping (MAILSTREAM *stream);
+void dummy_check (MAILSTREAM *stream);
+long dummy_expunge (MAILSTREAM *stream,char *sequence,long options);
+long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options);
+long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data);
+
+/* Dummy routines */
+
+
+/* Driver dispatch used by MAIL */
+
+DRIVER dummydriver = {
+  "dummy",			/* driver name */
+  DR_LOCAL|DR_MAIL,		/* driver flags */
+  (DRIVER *) NIL,		/* next driver */
+  dummy_valid,			/* mailbox is valid for us */
+  dummy_parameters,		/* manipulate parameters */
+  dummy_scan,			/* scan mailboxes */
+  dummy_list,			/* list mailboxes */
+  dummy_lsub,			/* list subscribed mailboxes */
+  NIL,				/* subscribe to mailbox */
+  NIL,				/* unsubscribe from mailbox */
+  dummy_create,			/* create mailbox */
+  dummy_delete,			/* delete mailbox */
+  dummy_rename,			/* rename mailbox */
+  mail_status_default,		/* status of mailbox */
+  dummy_open,			/* open mailbox */
+  dummy_close,			/* close mailbox */
+  NIL,				/* fetch message "fast" attributes */
+  NIL,				/* fetch message flags */
+  NIL,				/* fetch overview */
+  NIL,				/* fetch message structure */
+  NIL,				/* fetch header */
+  NIL,				/* fetch text */
+  NIL,				/* fetch message data */
+  NIL,				/* unique identifier */
+  NIL,				/* message number from UID */
+  NIL,				/* modify flags */
+  NIL,				/* per-message modify flags */
+  NIL,				/* search for message based on criteria */
+  NIL,				/* sort messages */
+  NIL,				/* thread messages */
+  dummy_ping,			/* ping mailbox to see if still alive */
+  dummy_check,			/* check for new messages */
+  dummy_expunge,		/* expunge deleted messages */
+  dummy_copy,			/* copy messages to another mailbox */
+  dummy_append,			/* append string message to mailbox */
+  NIL				/* garbage collect stream */
+};
+
+
+				/* prototype stream */
+MAILSTREAM dummyproto = {&dummydriver};
+
+				/* driver parameters */
+static char *file_extension = NIL;
+
+/* Dummy validate mailbox
+ * Accepts: mailbox name
+ * Returns: our driver if name is valid, NIL otherwise
+ */
+
+DRIVER *dummy_valid (char *name)
+{
+  char *s,tmp[MAILTMPLEN];
+  struct stat sbuf;
+				/* must be valid local mailbox */
+  return (name && *name && (*name != '{') &&
+	  (s = mailboxfile (tmp,name)) && (!*s || !stat (s,&sbuf))) ?
+	    &dummydriver : NIL;
+}
+
+
+/* Dummy manipulate driver parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *dummy_parameters (long function,void *value)
+{
+  return value;
+}
+
+/* Dummy scan mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ *	    string to scan
+ */
+
+void dummy_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents)
+{
+				/* return silently */
+}
+
+/* Dummy list mailboxes
+ * Accepts: mail stream
+ *	    reference
+ *	    pattern to search
+ */
+
+void dummy_list (MAILSTREAM *stream,char *ref,char *pat)
+{
+				/* return silently */
+}
+
+
+/* Dummy list subscribed mailboxes
+ * Accepts: mail stream
+ *	    pattern to search
+ */
+
+void dummy_lsub (MAILSTREAM *stream,char *ref,char *pat)
+{
+				/* return silently */
+}
+
+/* Dummy create mailbox
+ * Accepts: mail stream
+ *	    mailbox name to create
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_create (MAILSTREAM *stream,char *mailbox)
+{
+  return NIL;			/* always fails */
+}
+
+
+/* Dummy delete mailbox
+ * Accepts: mail stream
+ *	    mailbox name to delete
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_delete (MAILSTREAM *stream,char *mailbox)
+{
+  return NIL;			/* always fails */
+}
+
+
+/* Mail rename mailbox
+ * Accepts: mail stream
+ *	    old mailbox name
+ *	    new mailbox name
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_rename (MAILSTREAM *stream,char *old,char *newname)
+{
+  return NIL;			/* always fails */
+}
+
+/* Dummy open
+ * Accepts: stream to open
+ * Returns: stream on success, NIL on failure
+ */
+
+MAILSTREAM *dummy_open (MAILSTREAM *stream)
+{
+  char tmp[MAILTMPLEN];
+				/* OP_PROTOTYPE call or silence */
+  if (!stream || stream->silent) return NIL;
+  if (compare_cstring (stream->mailbox,"INBOX")) {
+    sprintf (tmp,"Not a mailbox: %s",stream->mailbox);
+    mm_log (tmp,ERROR);
+    return NIL;			/* always fails */
+  }
+  if (!stream->silent) {	/* only if silence not requested */
+    mail_exists (stream,0);	/* say there are 0 messages */
+    mail_recent (stream,0);
+    stream->uid_validity = time (0);
+  }
+  stream->inbox = T;		/* note that it's an INBOX */
+  return stream;		/* return success */
+}
+
+
+/* Dummy close
+ * Accepts: MAIL stream
+ *	    options
+ */
+
+void dummy_close (MAILSTREAM *stream,long options)
+{
+				/* return silently */
+}
+
+/* Dummy ping mailbox
+ * Accepts: MAIL stream
+ * Returns: T if stream alive, else NIL
+ * No-op for readonly files, since read/writer can expunge it from under us!
+ */
+
+long dummy_ping (MAILSTREAM *stream)
+{
+  return T;
+}
+
+
+/* Dummy check mailbox
+ * Accepts: MAIL stream
+ * No-op for readonly files, since read/writer can expunge it from under us!
+ */
+
+void dummy_check (MAILSTREAM *stream)
+{
+  dummy_ping (stream);		/* invoke ping */
+}
+
+
+/* Dummy expunge mailbox
+ * Accepts: MAIL stream
+ *	    sequence to expunge if non-NIL
+ *	    expunge options
+ * Returns: T, always
+ */
+
+long dummy_expunge (MAILSTREAM *stream,char *sequence,long options)
+{
+  return LONGT;
+}
+
+/* Dummy copy message(s)
+ * Accepts: MAIL stream
+ *	    sequence
+ *	    destination mailbox
+ *	    options
+ * Returns: T if copy successful, else NIL
+ */
+
+long dummy_copy (MAILSTREAM *stream,char *sequence,char *mailbox,long options)
+{
+  if ((options & CP_UID) ? mail_uid_sequence (stream,sequence) :
+      mail_sequence (stream,sequence)) fatal ("Impossible dummy_copy");
+  return NIL;
+}
+
+
+/* Dummy append message string
+ * Accepts: mail stream
+ *	    destination mailbox
+ *	    stringstruct of message to append
+ * Returns: T on success, NIL on failure
+ */
+
+long dummy_append (MAILSTREAM *stream,char *mailbox,append_t af,void *data)
+{
+  char tmp[MAILTMPLEN];
+  sprintf (tmp,"Can't append to %s",mailbox);
+  mm_log (tmp,ERROR);		/* pass up error */
+  return NIL;			/* always fails */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/wce/env_wce.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,301 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	WCE environment routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+static char *myUserName = NIL;	/* user name */
+static char *myLocalHost = NIL;	/* local host name */
+static char *myClientHost = NIL;/* client host name */
+static char *myServerHost = NIL;/* server host name */
+static char *myHomeDir = NIL;	/* home directory name */
+static char *myNewsrc = NIL;	/* newsrc file name */
+static char *sysInbox = NIL;	/* system inbox name */
+static long list_max_level = 5;	/* maximum level of list recursion */
+static short no822tztext = NIL;	/* disable RFC [2]822 timezone text */
+				/* home namespace */
+static NAMESPACE nshome = {"",'\\',NIL,NIL};
+				/* namespace list */
+static NAMESPACE *nslist[3] = {&nshome,NIL,NIL};
+static long alarm_countdown = 0;/* alarm count down */
+static void (*alarm_rang) ();	/* alarm interrupt function */
+static unsigned int rndm = 0;	/* initial `random' number */
+
+
+/* Dummy definitions to prevent errors */
+
+#define server_login(user,pass,authuser,argc,argv) NIL
+#define authserver_login(user,authuser,argc,argv) NIL
+#define myusername() ""
+#define MD5ENABLE "\\.nosuch.."
+
+#include "pmatch.c"		/* include wildcard pattern matcher */
+
+/* Environment manipulate parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *env_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case GET_NAMESPACE:
+    ret = (void *) nslist;
+    break;
+  case SET_HOMEDIR:
+    myHomeDir = cpystr ((char *) value);
+  case GET_HOMEDIR:
+    ret = (void *) myHomeDir;
+    break;
+  case SET_LOCALHOST:
+    myLocalHost = cpystr ((char *) value);
+  case GET_LOCALHOST:
+    ret = (void *) myLocalHost;
+    break;
+  case SET_NEWSRC:
+    if (myNewsrc) fs_give ((void **) &myNewsrc);
+    myNewsrc = cpystr ((char *) value);
+  case GET_NEWSRC:
+    if (!myNewsrc) {		/* set news file name if not defined */
+      char tmp[MAILTMPLEN];
+      sprintf (tmp,"%s\\NEWSRC",myhomedir ());
+      myNewsrc = cpystr (tmp);
+    }
+    ret = (void *) myNewsrc;
+    break;
+  case SET_SYSINBOX:
+    if (sysInbox) fs_give ((void **) &sysInbox);
+    sysInbox = cpystr ((char *) value);
+  case GET_SYSINBOX:
+    ret = (void *) sysInbox;
+    break;
+  case SET_LISTMAXLEVEL:
+    list_max_level = (long) value;
+  case GET_LISTMAXLEVEL:
+    ret = (void *) list_max_level;
+    break;
+  case SET_DISABLE822TZTEXT:
+    no822tztext = value ? T : NIL;
+  case GET_DISABLE822TZTEXT:
+    ret = (void *) (no822tztext ? VOIDT : NIL);
+    break;
+  }
+  return ret;
+}
+
+/* Write current time
+ * Accepts: destination string
+ *	    optional format of day-of-week prefix
+ *	    format of date and time
+ *	    flag whether to append symbolic timezone
+ */
+
+static void do_date (char *date,char *prefix,char *fmt,int suffix)
+{
+  time_t tn = time (0);
+  struct tm *t = gmtime (&tn);
+  int zone = t->tm_hour * 60 + t->tm_min;
+  int julian = t->tm_yday;
+  t = localtime (&tn);		/* get local time now */
+				/* minus UTC minutes since midnight */
+  zone = t->tm_hour * 60 + t->tm_min - zone;
+  /* julian can be one of:
+   *  36x  local time is December 31, UTC is January 1, offset -24 hours
+   *    1  local time is 1 day ahead of UTC, offset +24 hours
+   *    0  local time is same day as UTC, no offset
+   *   -1  local time is 1 day behind UTC, offset -24 hours
+   * -36x  local time is January 1, UTC is December 31, offset +24 hours
+   */
+  if (julian = t->tm_yday -julian)
+    zone += ((julian < 0) == (abs (julian) == 1)) ? -24*60 : 24*60;
+  if (prefix) {			/* want day of week? */
+    sprintf (date,prefix,days[t->tm_wday]);
+    date += strlen (date);	/* make next sprintf append */
+  }
+				/* output the date */
+  sprintf (date,fmt,t->tm_mday,months[t->tm_mon],t->tm_year+1900,
+	   t->tm_hour,t->tm_min,t->tm_sec,zone/60,abs (zone) % 60);
+  if (suffix) {			/* append timezone suffix if desired */
+    char *tz;
+    tzset ();			/* get timezone from TZ environment stuff */
+    tz = tzname[daylight ? (((struct tm *) t)->tm_isdst > 0) : 0];
+    if (tz && tz[0]) sprintf (date + strlen (date)," (%s)",tz);
+  }
+}
+
+
+/* Write current time in RFC 822 format
+ * Accepts: destination string
+ */
+
+void rfc822_date (char *date)
+{
+  do_date (date,"%s, ","%d %s %d %02d:%02d:%02d %+03d%02d",
+	   no822tztext ? NIL : T);
+}
+
+
+/* Write current time in internal format
+ * Accepts: destination string
+ */
+
+void internal_date (char *date)
+{
+  do_date (date,NIL,"%02d-%s-%d %02d:%02d:%02d %+03d%02d",NIL);
+}
+
+/* Return random number
+ */
+
+long random ()
+{
+  if (!rndm) srand (rndm = (unsigned) time (0L));
+  return (long) rand ();
+}
+
+/* Return default drive
+ * Returns: default drive
+ */
+
+static char *defaultDrive (void)
+{
+  char *s;
+  return ((s = getenv ("SystemDrive")) && *s) ? s : "C:";
+}
+
+
+/* Return home drive from environment variables
+ * Returns: home drive
+ */
+
+static char *homeDrive (void)
+{
+  char *s;
+  return ((s = getenv ("HOMEDRIVE")) && *s) ? s : defaultDrive ();
+}
+
+
+/* Return home path from environment variables
+ * Accepts: path to write into
+ * Returns: home path or NIL if it can't be determined
+ */
+
+static char *homePath (char *path)
+{
+  int i;
+  char *s;
+  if (!((s = getenv ("HOMEPATH")) && (i = strlen (s)))) return NIL;
+  if (((s[i-1] == '\\') || (s[i-1] == '/'))) s[i-1] = '\0';
+  sprintf (path,"%s%s",homeDrive (),s);
+  return path;
+}
+
+/* Return my home directory name
+ * Returns: my home directory name
+ */
+
+char *myhomedir ()
+{
+  char tmp[MAILTMPLEN];
+				/* initialize if first time */
+  if (!myHomeDir) myHomeDir = homePath (tmp);
+  return myHomeDir ? myHomeDir : homeDrive ();
+}
+
+/* Return system standard INBOX
+ * Accepts: buffer string
+ */
+
+char *sysinbox ()
+{
+  char tmp[MAILTMPLEN];
+  if (!sysInbox) {		/* initialize if first time */
+    sprintf (tmp,"%s\\INBOX",myhomedir ());
+    sysInbox = cpystr (tmp);	/* system inbox is from mail spool */
+  }
+  return sysInbox;
+}
+
+
+/* Return mailbox file name
+ * Accepts: destination buffer
+ *	    mailbox name
+ * Returns: file name
+ */
+
+char *mailboxfile (char *dst,char *name)
+{
+  char *dir = myhomedir ();
+  *dst = '\0';			/* default to empty string */
+  if (((name[0] == 'I') || (name[0] == 'i')) &&
+      ((name[1] == 'N') || (name[1] == 'n')) &&
+      ((name[2] == 'B') || (name[2] == 'b')) &&
+      ((name[3] == 'O') || (name[3] == 'o')) &&
+      ((name[4] == 'X') || (name[4] == 'x')) && !name[5]) name = NIL;
+				/* reject namespace names or names with / */
+  if (name && ((*name == '#') || strchr (name,'/'))) return NIL;
+  else if (!name) return dst;	/* driver selects the INBOX name */
+				/* absolute path name? */
+  else if ((*name == '\\') || (name[1] == ':')) return strcpy (dst,name);
+				/* build resulting name */
+  sprintf (dst,"%s\\%s",dir,name);
+  return dst;			/* return it */
+}
+
+
+/* Determine default prototype stream to user
+ * Accepts: type (NIL for create, T for append)
+ * Returns: default prototype stream
+ */
+
+MAILSTREAM *default_proto (long type)
+{
+  extern MAILSTREAM CREATEPROTO,APPENDPROTO;
+  return type ? &APPENDPROTO : &CREATEPROTO;
+}
+
+/* Emulator for BSD syslog() routine
+ * Accepts: priority
+ *	    message
+ *	    parameters
+ */
+
+void syslog (int priority,const char *message,...)
+{
+}
+
+
+/* Emulator for BSD openlog() routine
+ * Accepts: identity
+ *	    options
+ *	    facility
+ */
+
+void openlog (const char *ident,int logopt,int facility)
+{
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/wce/env_wce.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,70 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	WCE environment routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+#define SUBSCRIPTIONFILE(t) sprintf (t,"%s\\MAILBOX.LST",myhomedir ())
+#define SUBSCRIPTIONTEMP(t) sprintf (t,"%s\\MAILBOX.TMP",myhomedir ())
+
+#define L_SET SEEK_SET
+
+/* Function prototypes */
+
+#include "env.h"
+
+static char *defaultDrive (void);
+static char *homeDrive (void);
+static char *homePath (char *path);
+char *sysinbox ();
+long random ();
+unsigned long unix_crlfcpy (char **dst,unsigned long *dstl,char *src,
+			    unsigned long srcl);
+unsigned long unix_crlflen (STRING *s);
+#define getpid random
+
+
+/* syslog() emulation */
+
+#define LOG_MAIL	(2<<3)	/* mail system */
+#define LOG_DAEMON	(3<<3)	/* system daemons */
+#define LOG_AUTH	(4<<3)	/* security/authorization messages */
+#define LOG_EMERG	0	/* system is unusable */
+#define LOG_ALERT	1	/* action must be taken immediately */
+#define LOG_CRIT	2	/* critical conditions */
+#define LOG_ERR		3	/* error conditions */
+#define LOG_WARNING	4	/* warning conditions */
+#define LOG_NOTICE	5	/* normal but signification condition */
+#define LOG_INFO	6	/* informational */
+#define LOG_DEBUG	7	/* debug-level messages */
+#define LOG_PID		0x01	/* log the pid with each message */
+#define LOG_CONS	0x02	/* log on the console if errors in sending */
+#define LOG_ODELAY	0x04	/* delay open until syslog() is called */
+#define LOG_NDELAY	0x08	/* don't delay open */
+#define LOG_NOWAIT	0x10	/* if forking to log on console, don't wait() */
+
+void openlog (const char *ident,int logopt,int facility);
+void syslog (int priority,const char *message,...);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/wce/fs_wce.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,62 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Free storage management routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Get a block of free storage
+ * Accepts: size of desired block
+ * Returns: free storage block
+ */
+
+void *fs_get (size_t size)
+{
+  void *block = malloc (size ? size : (size_t) 1);
+  if (!block) fatal ("Out of memory");
+  return (block);
+}
+
+
+/* Resize a block of free storage
+ * Accepts: ** pointer to current block
+ *	    new size
+ */
+
+void fs_resize (void **block,size_t size)
+{
+  if (!(*block = realloc (*block,size ? size : (size_t) 1)))
+    fatal ("Can't resize memory");
+}
+
+
+/* Return a block of free storage
+ * Accepts: ** pointer to free storage block
+ */
+
+void fs_give (void **block)
+{
+  free (*block);
+  *block = NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/wce/ftl_wce.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,38 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	DOS/VMS/TOPS-20 crash management routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+
+/* Report a fatal error
+ * Accepts: string to output
+ */
+
+void fatal (char *string)
+{
+  mm_fatal (string);		/* pass up the string */
+  abort ();			/* die horribly */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/wce/makefile.wce	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,96 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+# Program:	Portable C client makefile -- WCE version
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		11 May 1989
+# Last Edited:	30 August 2006
+
+
+EXTRAAUTHENTICATORS=
+DEFAULTAUTHENTICATORS=ext md5 pla log
+EXTRADRIVERS =
+DRIVERS = imap nntp pop3
+DEFAULTDRIVER = dummy
+CFLAGS= /MT /W3 /D_SH3_ -nologo $(EXTRACFLAGS)
+CC = shcl
+CCLIENTLIB= cclient.lib
+
+all:	$(CCLIENTLIB)
+
+.c.obj:
+	$(CC) -c $(CFLAGS) $*.c
+
+osdep.h: os_wce.h
+	copy os_wce.h osdep.h
+	drivers $(EXTRADRIVERS) $(DRIVERS) dummy
+	setproto $(DEFAULTDRIVER) $(DEFAULTDRIVER)
+	mkauths $(EXTRAAUTHENTICATORS) $(DEFAULTAUTHENTICATORS)
+
+mail.obj: mail.h misc.h osdep.h mail.c
+
+misc.obj: mail.h misc.h misc.c
+
+flstring.obj: mail.h misc.h osdep.h flstring.h flstring.c
+
+netmsg.obj: mail.h misc.h netmsg.h osdep.h netmsg.c
+
+newsrc.obj: mail.h misc.h newsrc.h osdep.h newsrc.c
+
+rfc822.obj: mail.h rfc822.h misc.h rfc822.c
+
+smanager.obj: mail.h misc.h smanager.c
+
+utf8.obj: mail.h misc.h osdep.h utf8.h
+
+utf8aux.obj: mail.h misc.h osdep.h utf8.h
+
+imap4r1.obj: mail.h imap4r1.h misc.h osdep.h imap4r1.c
+
+nntp.obj: mail.h nntp.h smtp.h rfc822.h misc.h osdep.h nntp.c
+
+pop3.obj: mail.h pop3.h rfc822.h misc.h osdep.h pop3.c
+
+smtp.obj: mail.h smtp.h rfc822.h misc.h osdep.h smtp.c
+
+os_wce.obj: mail.h osdep.h env_wce.h fs.h ftl.h nl.h tcp.h tcp_wce.h \
+	os_wce.c fs_wce.c ftl_wce.c nl_wce.c env_wce.c tcp_wce.c \
+	auth_md5.c auth_log.c pmatch.c
+
+dummywce.obj: mail.h dummy.h misc.h osdep.h dummywce.c
+
+$(CCLIENTLIB): mail.obj misc.obj flstring.obj netmsg.obj \
+	newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
+	imap4r1.obj nntp.obj pop3.obj smtp.obj os_wce.obj \
+	dummywce.obj
+	erase $(CCLIENTLIB)
+	LIB /NOLOGO /OUT:cclient.lib \
+	mail.obj misc.obj flstring.obj netmsg.obj \
+	newsrc.obj rfc822.obj smanager.obj utf8.obj utf8aux.obj \
+	imap4r1.obj nntp.obj pop3.obj smtp.obj os_wce.obj \
+	dummywce.obj
+
+clean:
+	del *.lib *.obj linkage.* osdep.* auths.c *.exe *.exp || rem
+
+# A monument to a hack of long ago and far away...
+
+love:
+	@echo not war?
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/wce/mkautaux.bat	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,31 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM     http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM 
+REM ========================================================================
+
+REM Program:	Authenticator Linkage Generator auxillary for NT/Win9x
+REM
+REM Author:	Mark Crispin
+REM		Networks and Distributed Computing
+REM		Computing & Communications
+REM		University of Washington
+REM		Administration Building, AG-44
+REM		Seattle, WA  98195
+REM		Internet: MRC@CAC.Washington.EDU
+REM
+REM Date:	6 December 1995
+REM Last Edited:30 August 2006
+
+ECHO extern AUTHENTICATOR auth_%1; >> LINKAGE.H
+REM Note the introduction of the caret to quote the ampersand in NT
+if "%OS%" == "Windows_NT" ECHO   auth_link (^&auth_%1);		/* link in the %1 authenticator */ >> LINKAGE.C
+if "%OS%" == "" ECHO   auth_link (&auth_%1);		/* link in the %1 authenticator */ >> LINKAGE.C
+ECHO #include "auth_%1.c" >> AUTHS.C
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/wce/mkauths.bat	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,33 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM     http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM 
+REM ========================================================================
+
+REM Program:	Authenticator Linkage Generator for DOS and Windows
+REM
+REM Author:	Mark Crispin
+REM		Networks and Distributed Computing
+REM		Computing & Communications
+REM		University of Washington
+REM		Administration Building, AG-44
+REM		Seattle, WA  98195
+REM		Internet: MRC@CAC.Washington.EDU
+REM
+REM Date:	6 December 1995
+REM Last Edited:30 August 2006
+
+REM Erase old authenticators list
+IF EXIST AUTHS.C DEL AUTHS.C
+
+REM Now define the new list
+FOR %%D IN (%1 %2 %3 %4 %5 %6 %7 %8 %9) DO CALL MKAUTAUX %%D
+
+EXIT 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/wce/nl_wce.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,61 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Windows/TOPS-20 newline routines
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 August 1988
+ * Last Edited:	30 August 2006
+ */
+
+/* Copy string with CRLF newlines
+ * Accepts: destination string
+ *	    pointer to size of destination string buffer
+ *	    source string
+ *	    length of source string
+ * Returns: length of copied string
+ */
+
+unsigned long strcrlfcpy (unsigned char **dst,unsigned long *dstl,
+			  unsigned char *src,unsigned long srcl)
+{
+				/* flush destination buffer if too small */
+  if (*dst && (srcl > *dstl)) fs_give ((void **) dst);
+  if (!*dst) {			/* make a new buffer if needed */
+    *dst = (char *) fs_get ((size_t) (*dstl = srcl) + 1);
+    if (dstl) *dstl = srcl;	/* return new buffer length to main program */
+  }
+				/* copy strings */
+  if (srcl) memcpy (*dst,src,(size_t) srcl);
+  *(*dst + srcl) = '\0';	/* tie off destination */
+  return srcl;			/* return length */
+}
+
+
+/* Length of string after strcrlfcpy applied
+ * Accepts: source string
+ * Returns: length of string
+ */
+
+unsigned long strcrlflen (STRING *s)
+{
+  return SIZE (s);		/* no-brainer on DOS! */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/wce/os_wce.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,45 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- WCE version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 April 1989
+ * Last Edited:	30 August 2006
+ */
+
+#include "tcp_wce.h"		/* must be before osdep includes tcp.h */
+#include "mail.h"
+#include "osdep.h"
+#include <winsock.h>
+#include <stdio.h>
+#include <time.h>
+#include <sys\timeb.h>
+#include <fcntl.h>
+#include <sys\stat.h>
+#include "misc.h"
+
+#include "fs_wce.c"
+#include "ftl_wce.c"
+#include "nl_wce.c"
+#include "env_wce.c"
+#include "tcp_wce.c"
+#include "auths.c"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/wce/os_wce.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,53 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Operating-system dependent routines -- WCE version
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 May 1989
+ * Last Edited:	30 August 2006
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+				/* missing in string.h */
+_CRTIMP char * __cdecl strpbrk (const char *, const char *);
+_CRTIMP	char * __cdecl strrchr(const char *, int);
+#include <sys\types.h>
+#undef ERROR
+#include <windows.h>
+#undef ERROR
+#define ERROR (long) 2		/* must match mail.h */
+#include <time.h>
+#include <io.h>
+
+#define gethostid clock
+#define	WSA_VERSION	((1 << 8) | 1)
+
+#include "env_wce.h"
+#include "fs.h"
+#include "ftl.h"
+#include "nl.h"
+#include "tcp.h"
+
+#undef noErr
+#undef MAC
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/wce/pmatch.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,89 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	IMAP Wildcard Matching Routines (case-independent)
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	15 June 2000
+ * Last Edited:	30 August 2006
+ */
+
+/* Wildcard pattern match
+ * Accepts: base string
+ *	    pattern string
+ *	    delimiter character
+ * Returns: T if pattern matches base, else NIL
+ */
+
+long pmatch_full (unsigned char *s,unsigned char *pat,unsigned char delim)
+{
+  switch (*pat) {
+  case '%':			/* non-recursive */
+				/* % at end, OK if no inferiors */
+    if (!pat[1]) return (delim && strchr (s,delim)) ? NIL : T;
+                                /* scan remainder of string until delimiter */
+    do if (pmatch_full (s,pat+1,delim)) return T;
+    while ((*s != delim) && *s++);
+    break;
+  case '*':			/* match 0 or more characters */
+    if (!pat[1]) return T;	/* * at end, unconditional match */
+				/* scan remainder of string */
+    do if (pmatch_full (s,pat+1,delim)) return T;
+    while (*s++);
+    break;
+  case '\0':			/* end of pattern */
+    return *s ? NIL : T;	/* success if also end of base */
+  default:			/* match this character */
+    return compare_uchar (*pat,*s) ? NIL : pmatch_full (s+1,pat+1,delim);
+  }
+  return NIL;
+}
+
+/* Directory pattern match
+ * Accepts: base string
+ *	    pattern string
+ *	    delimiter character
+ * Returns: T if base is a matching directory of pattern, else NIL
+ */
+
+long dmatch (unsigned char *s,unsigned char *pat,unsigned char delim)
+{
+  switch (*pat) {
+  case '%':			/* non-recursive */
+    if (!*s) return T;		/* end of base means have a subset match */
+    if (!*++pat) return NIL;	/* % at end, no inferiors permitted */
+				/* scan remainder of string until delimiter */
+    do if (dmatch (s,pat,delim)) return T;
+    while ((*s != delim) && *s++);
+    if (*s && !s[1]) return T;	/* ends with delimiter, must be subset */
+    return dmatch (s,pat,delim);/* do new scan */
+  case '*':			/* match 0 or more characters */
+    return T;			/* unconditional match */
+  case '\0':			/* end of pattern */
+    break;
+  default:			/* match this character */
+    if (*s) return compare_uchar (*pat,*s) ? NIL : dmatch (s+1,pat+1,delim);
+				/* end of base, return if at delimiter */
+    else if (*pat == delim) return T;
+    break;
+  }
+  return NIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/wce/setproto.bat	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,29 @@
+@ECHO OFF
+REM ========================================================================
+REM Copyright 1988-2006 University of Washington
+REM
+REM Licensed under the Apache License, Version 2.0 (the "License");
+REM you may not use this file except in compliance with the License.
+REM You may obtain a copy of the License at
+REM
+REM     http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM 
+REM ========================================================================
+
+REM Program:	Set default prototype for DOS/NT
+REM
+REM Author:	Mark Crispin
+REM		Networks and Distributed Computing
+REM		Computing & Communications
+REM		University of Washington
+REM		Administration Building, AG-44
+REM		Seattle, WA  98195
+REM		Internet: MRC@CAC.Washington.EDU
+REM
+REM Date:	 9 October 1995
+REM Last Edited: 30 August 2006
+
+REM Set the default drivers
+ECHO #define CREATEPROTO %1proto >> LINKAGE.H
+ECHO #define APPENDPROTO %2proto >> LINKAGE.H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/wce/tcp_wce.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,818 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Winsock TCP/IP routines
+ *
+ * Author:	Mark Crispin from Mike Seibel's Winsock code
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 April 1989
+ * Last Edited:	13 January 2008
+ */
+
+
+#define TCPMAXSEND 32768
+
+/* Private functions */
+
+int tcp_socket_open (struct sockaddr_in *sin,char *tmp,char *hst,
+		     unsigned long port);
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+			       long *contd);
+long tcp_abort (TCPSTREAM *stream);
+long tcp_close_socket (SOCKET *sock);
+char *tcp_name (struct sockaddr_in *sin,long flag);
+char *tcp_name_valid (char *s);
+
+
+/* Private data */
+
+int wsa_initted = 0;		/* init ? */
+static int wsa_sock_open = 0;	/* keep track of open sockets */
+static tcptimeout_t tmoh = NIL;	/* TCP timeout handler routine */
+static long ttmo_read = 0;	/* TCP timeouts, in seconds */
+static long ttmo_write = 0;
+static long allowreversedns = T;/* allow reverse DNS lookup */
+static long tcpdebug = NIL;	/* extra TCP debugging telemetry */
+
+/* TCP/IP manipulate parameters
+ * Accepts: function code
+ *	    function-dependent value
+ * Returns: function-dependent return value
+ */
+
+void *tcp_parameters (long function,void *value)
+{
+  void *ret = NIL;
+  switch ((int) function) {
+  case SET_TIMEOUT:
+    tmoh = (tcptimeout_t) value;
+  case GET_TIMEOUT:
+    ret = (void *) tmoh;
+    break;
+  case SET_READTIMEOUT:
+    ttmo_read = (long) value;
+  case GET_READTIMEOUT:
+    ret = (void *) ttmo_read;
+    break;
+  case SET_WRITETIMEOUT:
+    ttmo_write = (long) value;
+  case GET_WRITETIMEOUT:
+    ret = (void *) ttmo_write;
+    break;
+  case SET_ALLOWREVERSEDNS:
+    allowreversedns = (long) value;
+  case GET_ALLOWREVERSEDNS:
+    ret = (void *) allowreversedns;
+    break;
+  case SET_TCPDEBUG:
+    tcpdebug = (long) value;
+  case GET_TCPDEBUG:
+    ret = (void *) tcpdebug;
+    break;
+  }
+  return ret;
+}
+
+/* TCP/IP open
+ * Accepts: host name
+ *	    contact service name
+ *	    contact port number and optional silent flag
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
+{
+  TCPSTREAM *stream = NIL;
+  int i;
+  SOCKET sock = INVALID_SOCKET;
+  int silent = (port & NET_SILENT) ? T : NIL;
+  char *s;
+  struct sockaddr_in sin;
+  struct hostent *he;
+  char hostname[MAILTMPLEN];
+  char tmp[MAILTMPLEN];
+  struct servent *sv = NIL;
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  if (!wsa_initted++) {		/* init Windows Sockets */
+    WSADATA wsock;
+    if (i = (int) WSAStartup (WSA_VERSION,&wsock)) {
+      wsa_initted = 0;		/* in case we try again */
+      sprintf (tmp,"Unable to start Windows Sockets (%d)",i);
+      mm_log (tmp,ERROR);
+      return NIL;
+    }
+  }
+  port &= 0xffff;		/* erase flags */
+				/* lookup service */
+  if (service && (sv = getservbyname (service,"tcp")))
+    port = ntohs (sin.sin_port = sv->s_port);
+ 				/* copy port number in network format */
+  else sin.sin_port = htons ((u_short) port);
+  /* The domain literal form is used (rather than simply the dotted decimal
+     as with other Windows programs) because it has to be a valid "host name"
+     in mailsystem terminology. */
+  sin.sin_family = AF_INET;	/* family is always Internet */
+				/* look like domain literal? */
+  if (host[0] == '[' && host[(strlen (host))-1] == ']') {
+    strcpy (tmp,host+1);	/* yes, copy number part */
+    tmp[strlen (tmp)-1] = '\0';
+    if ((sin.sin_addr.s_addr = inet_addr (tmp)) == INADDR_NONE) {
+      sprintf (tmp,"Bad format domain-literal: %.80s",host);
+      mm_log (tmp,ERROR);
+      return NIL;
+    }
+    else {
+      sin.sin_family = AF_INET;	/* family is always Internet */
+      strcpy (hostname,host);
+      (*bn) (BLOCK_TCPOPEN,NIL);
+      sock = tcp_socket_open (&sin,tmp,hostname,port);
+      (*bn) (BLOCK_NONE,NIL);
+    }
+  }
+
+  else {			/* lookup host name */
+    if (tcpdebug) {
+      sprintf (tmp,"DNS resolution %.80s",host);
+      mm_log (tmp,TCPDEBUG);
+    }
+    (*bn) (BLOCK_DNSLOOKUP,NIL);/* look up name */
+    if (!(he = gethostbyname (lcase (strcpy (tmp,host)))))
+      sprintf (tmp,"Host not found (#%d): %s",WSAGetLastError(),host);
+    (*bn) (BLOCK_NONE,NIL);
+    if (he) {			/* DNS resolution won? */
+      if (tcpdebug) mm_log ("DNS resolution done",TCPDEBUG);
+				/* copy address type */
+      sin.sin_family = he->h_addrtype;
+				/* copy host name */
+      strcpy (hostname,he->h_name);
+      wsa_sock_open++;		/* prevent tcp_close_socket() from freeing in
+				   loop */
+      for (i = 0; (sock == INVALID_SOCKET) && (s = he->h_addr_list[i]); i++) {
+	if (i && !silent) mm_log (tmp,WARN);
+	memcpy (&sin.sin_addr,s,he->h_length);
+	(*bn) (BLOCK_TCPOPEN,NIL);
+	sock = tcp_socket_open (&sin,tmp,hostname,port);
+	(*bn) (BLOCK_NONE,NIL);
+      }
+      wsa_sock_open--;		/* undo protection */
+    }
+  }
+  if (sock == INVALID_SOCKET) {	/* error? */
+    if (!silent) mm_log (tmp,ERROR);
+    tcp_close_socket (&sock);	/* do possible cleanup action */
+  }
+  else {			/* got a socket, create TCP/IP stream */
+    stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0,
+				   sizeof (TCPSTREAM));
+    stream->port = port;	/* port number */
+				/* init socket */
+    stream->tcpsi = stream->tcpso = sock;
+    stream->ictr = 0;		/* init input counter */
+				/* copy official host name */
+    stream->host = cpystr (hostname);
+    if (tcpdebug) mm_log ("Stream open and ready for read",TCPDEBUG);
+  }
+  return stream;		/* return success */
+}
+
+/* Open a TCP socket
+ * Accepts: Internet socket address block
+ *	    scratch buffer
+ *	    host name for error message
+ *	    port number for error message
+ * Returns: socket if success, else -1 with error string in scratch buffer
+ */
+
+int tcp_socket_open (struct sockaddr_in *sin,char *tmp,char *hst,
+		     unsigned long port)
+{
+  int sock;
+  char *s;
+  sprintf (tmp,"Trying IP address [%s]",inet_ntoa (sin->sin_addr));
+  mm_log (tmp,NIL);
+				/* get a TCP stream */
+  if ((sock = socket (sin->sin_family,SOCK_STREAM,0)) == INVALID_SOCKET) {
+    sprintf (tmp,"Unable to create TCP socket (%d)",WSAGetLastError());
+    return -1;
+  }
+  wsa_sock_open++;		/* count this socket as open */
+				/* open connection */
+  if (connect (sock,(struct sockaddr *) sin,sizeof (struct sockaddr_in)) ==
+      SOCKET_ERROR) {
+    switch (WSAGetLastError ()){/* analyze error */
+    case WSAECONNREFUSED:
+      s = "Refused";
+      break;
+    case WSAENOBUFS:
+      s = "Insufficient system resources";
+      break;
+    case WSAETIMEDOUT:
+      s = "Timed out";
+      break;
+    case WSAEHOSTUNREACH:
+      s = "Host unreachable";
+      break;
+    default:
+      s = "Unknown error";
+      break;
+    }
+    sprintf (tmp,"Can't connect to %.80s,%ld: %s (%d)",hst,port,s,
+	     WSAGetLastError ());
+    tcp_close_socket (&sock);	/* flush socket */
+    sock = INVALID_SOCKET;
+  }
+  return sock;			/* return the socket */
+}
+  
+/* TCP/IP authenticated open
+ * Accepts: NETMBX specifier
+ *	    service name
+ *	    returned user name buffer
+ * Returns: TCP/IP stream if success else NIL
+ */
+
+TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
+{
+  return NIL;			/* always NIL on Windows */
+}
+
+/* TCP receive line
+ * Accepts: TCP stream
+ * Returns: text line string or NIL if failure
+ */
+
+char *tcp_getline (TCPSTREAM *stream)
+{
+  unsigned long n,contd;
+  char *ret = tcp_getline_work (stream,&n,&contd);
+  if (ret && contd) {		/* got a line needing continuation? */
+    STRINGLIST *stl = mail_newstringlist ();
+    STRINGLIST *stc = stl;
+    do {			/* collect additional lines */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+      stc = stc->next = mail_newstringlist ();
+      ret = tcp_getline_work (stream,&n,&contd);
+    } while (ret && contd);
+    if (ret) {			/* stash final part of line on list */
+      stc->text.data = (unsigned char *) ret;
+      stc->text.size = n;
+				/* determine how large a buffer we need */
+      for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
+      ret = fs_get (n + 1);	/* copy parts into buffer */
+      for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
+	memcpy (ret + n,stc->text.data,stc->text.size);
+      ret[n] = '\0';
+    }
+    mail_free_stringlist (&stl);/* either way, done with list */
+  }
+  return ret;
+}
+
+/* TCP receive line or partial line
+ * Accepts: TCP stream
+ *	    pointer to return size
+ *	    pointer to return continuation flag
+ * Returns: text line string, size and continuation flag, or NIL if failure
+ */
+
+static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
+			       long *contd)
+{
+  unsigned long n;
+  char *s,*ret,c,d;
+  *contd = NIL;			/* assume no continuation */
+				/* make sure have data */
+  if (!tcp_getdata (stream)) return NIL;
+  for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
+    d = *stream->iptr++;	/* slurp another character */
+    if ((c == '\015') && (d == '\012')) {
+      ret = (char *) fs_get (n--);
+      memcpy (ret,s,*size = n);	/* copy into a free storage string */
+      ret[n] = '\0';		/* tie off string with null */
+      return ret;
+    }
+  }
+				/* copy partial string from buffer */
+  memcpy ((ret = (char *) fs_get (n)),s,*size = n);
+				/* get more data from the net */
+  if (!tcp_getdata (stream)) fs_give ((void **) &ret);
+				/* special case of newline broken by buffer */
+  else if ((c == '\015') && (*stream->iptr == '\012')) {
+    stream->iptr++;		/* eat the line feed */
+    stream->ictr--;
+    ret[*size = --n] = '\0';	/* tie off string with null */
+  }
+  else *contd = LONGT;		/* continuation needed */
+  return ret;
+}
+
+/* TCP/IP receive buffer
+ * Accepts: TCP/IP stream
+ *	    size in bytes
+ *	    buffer to read into
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *s)
+{
+  unsigned long n;
+				/* make sure socket still alive */
+  if (stream->tcpsi == INVALID_SOCKET) return NIL;
+				/* can transfer bytes from buffer? */
+  if (n = min (size,stream->ictr)) {
+    memcpy (s,stream->iptr,n);	/* yes, slurp as much as we can from it */
+    s += n;			/* update pointer */
+    stream->iptr +=n;
+    size -= n;			/* update # of bytes to do */
+    stream->ictr -=n;
+  }
+  if (size) {
+    int i;
+    fd_set fds;
+    struct timeval tmo;
+    time_t tc,t = time (0);
+    blocknotify_t bn=(blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+    (*bn) (BLOCK_TCPREAD,NIL);
+    while (size > 0) {		/* until request satisfied */
+      time_t tl = time (0);
+      if (tcpdebug) mm_log ("Reading TCP buffer",TCPDEBUG);
+      FD_ZERO (&fds);		/* initialize selection vector */
+      FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */
+      tmo.tv_sec = ttmo_read;
+      tmo.tv_usec = 0;
+				/* block and read */
+      switch ((stream->tcpsi == stream->tcpso) ?
+	      select (stream->tcpsi+1,&fds,0,0,
+		      ttmo_read ? &tmo : (struct timeval *) 0) : 1) {
+      case SOCKET_ERROR:		/* error */
+	if (WSAGetLastError () != WSAEINTR) return tcp_abort (stream);
+	break;
+      case 0:			/* timeout */
+	tc = time (0);
+	if (tmoh && ((*tmoh) (tc - t,tc - tl))) break;
+	return tcp_abort (stream);
+      default:
+	if (stream->tcpsi == stream->tcpso)
+	  while (((i = recv (stream->tcpsi,s,(int) min (maxposint,size),0)) ==
+		  SOCKET_ERROR) && (WSAGetLastError () == WSAEINTR));
+	else while (((i = read (stream->tcpsi,s,(int) min (maxposint,size))) <
+		     0) && (errno == EINTR));
+	switch (i) {
+	case SOCKET_ERROR:	/* error */
+	case 0:			/* no data read */
+	  return tcp_abort (stream);
+	default:
+	  s += i;		/* point at new place to write */
+	  size -= i;		/* reduce byte count */
+	  if (tcpdebug) mm_log ("Successfully read TCP buffer",TCPDEBUG);
+	}
+      }
+    }
+    (*bn) (BLOCK_NONE,NIL);
+  }
+  *s = '\0';			/* tie off string */
+  return T;
+}
+
+/* TCP/IP receive data
+ * Accepts: TCP/IP stream
+ * Returns: T if success, NIL otherwise
+ */
+
+long tcp_getdata (TCPSTREAM *stream)
+{
+  struct timeval tmo;
+  int i;
+  fd_set fds;
+  time_t tc,t = time (0);
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  FD_ZERO (&fds);		/* initialize selection vector */
+  if (stream->tcpsi == INVALID_SOCKET) return NIL;
+  (*bn) (BLOCK_TCPREAD,NIL);
+  tmo.tv_sec = ttmo_read;
+  tmo.tv_usec = 0;
+  while (stream->ictr < 1) {	/* if nothing in the buffer */
+    time_t tl = time (0);
+    if (tcpdebug) mm_log ("Reading TCP data",TCPDEBUG);
+    FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */
+				/* block and read */
+    switch ((stream->tcpsi == stream->tcpso) ?
+	    select (stream->tcpsi+1,&fds,0,0,
+		    ttmo_read ? &tmo : (struct timeval *) 0) : 1) {
+    case SOCKET_ERROR:		/* error */
+      if (WSAGetLastError () != WSAEINTR) return tcp_abort (stream);
+      break;
+    case 0:			/* timeout */
+      tc = time (0);
+      if (tmoh && ((*tmoh) (tc - t,tc - tl))) break;
+      return tcp_abort (stream);
+    default:
+      if (stream->tcpsi == stream->tcpso)
+	while (((i = recv (stream->tcpsi,stream->ibuf,BUFLEN,0)) ==
+		SOCKET_ERROR) && (WSAGetLastError () == WSAEINTR));
+      else while (((i = read (stream->tcpsi,stream->ibuf,BUFLEN)) < 0) &&
+		  (errno == EINTR));
+      switch (i) {
+      case SOCKET_ERROR:	/* error */
+      case 0:			/* no data read */
+	return tcp_abort (stream);
+      default:
+	stream->ictr = i;	/* set new byte count */
+				/* point at TCP buffer */
+	stream->iptr = stream->ibuf;
+	if (tcpdebug) mm_log ("Successfully read TCP data",TCPDEBUG);
+      }
+    }
+  }
+  (*bn) (BLOCK_NONE,NIL);
+  return T;
+}
+
+/* TCP/IP send string as record
+ * Accepts: TCP/IP stream
+ *	    string pointer
+ * Returns: T if success else NIL
+ */
+
+long tcp_soutr (TCPSTREAM *stream,char *string)
+{
+  return tcp_sout (stream,string,(unsigned long) strlen (string));
+}
+
+
+/* TCP/IP send string
+ * Accepts: TCP/IP stream
+ *	    string pointer
+ *	    byte count
+ * Returns: T if success else NIL
+ */
+
+long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
+{
+  int i;
+  struct timeval tmo;
+  fd_set fds;
+  time_t tc,t = time (0);
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+  tmo.tv_sec = ttmo_write;
+  tmo.tv_usec = 0;
+  FD_ZERO (&fds);		/* initialize selection vector */
+  if (stream->tcpso == INVALID_SOCKET) return NIL;
+  (*bn) (BLOCK_TCPWRITE,NIL);
+  while (size > 0) {		/* until request satisfied */
+    time_t tl = time (0);
+    if (tcpdebug) mm_log ("Writing to TCP",TCPDEBUG);
+    FD_SET (stream->tcpso,&fds);/* set bit in selection vector */
+				/* block and write */
+    switch ((stream->tcpsi == stream->tcpso) ?
+	    select (stream->tcpso+1,NULL,&fds,NULL,
+		    tmo.tv_sec ? &tmo : (struct timeval *) 0) : 1) {
+    case SOCKET_ERROR:		/* error */
+      if (WSAGetLastError () != WSAEINTR) return tcp_abort (stream);
+      break;
+    case 0:			/* timeout */
+      tc = time (0);
+      if (tmoh && ((*tmoh) (tc - t,tc - tl))) break;
+      return tcp_abort (stream);
+    default:
+      if (stream->tcpsi == stream->tcpso)
+	while (((i = send (stream->tcpso,string,
+			   (int) min (size,TCPMAXSEND),0)) == SOCKET_ERROR) &&
+	       (WSAGetLastError () == WSAEINTR));
+      else while (((i = write (stream->tcpso,string,
+			       min (size,TCPMAXSEND))) < 0) &&
+		  (errno == EINTR));
+      if (i == SOCKET_ERROR) return tcp_abort (stream);
+      size -= i;		/* count this size */
+      if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG);
+      string += i;
+    }
+  }
+  (*bn) (BLOCK_NONE,NIL);
+  return T;			/* all done */
+}
+
+
+/* TCP/IP close
+ * Accepts: TCP/IP stream
+ */
+
+void tcp_close (TCPSTREAM *stream)
+{
+  tcp_abort (stream);		/* nuke the sockets */
+				/* flush host names */
+  if (stream->host) fs_give ((void **) &stream->host);
+  if (stream->remotehost) fs_give ((void **) &stream->remotehost);
+  if (stream->localhost) fs_give ((void **) &stream->localhost);
+  fs_give ((void **) &stream);	/* flush the stream */
+}
+
+
+/* TCP/IP abort sockets
+ * Accepts: TCP/IP stream
+ * Returns: NIL, always
+ */
+
+long tcp_abort (TCPSTREAM *stream)
+{
+  if (stream->tcpsi != stream->tcpso) tcp_close_socket (&stream->tcpso);
+  else stream->tcpso = INVALID_SOCKET;
+  return tcp_close_socket (&stream->tcpsi);
+}
+
+
+/* TCP/IP abort stream
+ * Accepts: WinSock socket
+ * Returns: NIL, always
+ */
+
+long tcp_close_socket (SOCKET *sock)
+{
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+				/* something to close? */
+  if (sock && (*sock != INVALID_SOCKET)) {
+    (*bn) (BLOCK_TCPCLOSE,NIL);
+    closesocket (*sock);	/* WinSock socket close */
+    *sock = INVALID_SOCKET;
+    (*bn) (BLOCK_NONE,NIL);
+    wsa_sock_open--;		/* drop this socket */
+  }
+				/* no more open streams? */
+  if (wsa_initted && !wsa_sock_open) {
+    mm_log ("Winsock cleanup",NIL);
+    wsa_initted = 0;		/* no more sockets, so... */
+    WSACleanup ();		/* free up resources until needed */
+  }
+  return NIL;
+}
+
+/* TCP/IP get host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_host (TCPSTREAM *stream)
+{
+  return stream->host;		/* use tcp_remotehost() if want guarantees */
+}
+
+
+/* TCP/IP get remote host name
+ * Accepts: TCP/IP stream
+ * Returns: host name for this stream
+ */
+
+char *tcp_remotehost (TCPSTREAM *stream)
+{
+  if (!stream->remotehost) {
+    struct sockaddr_in sin;
+    int sinlen = sizeof (struct sockaddr_in);
+    stream->remotehost =	/* get socket's peer name */
+      ((getpeername (stream->tcpsi,(struct sockaddr *) &sin,&sinlen) ==
+	SOCKET_ERROR) || (sinlen <= 0)) ?
+	  cpystr (stream->host) : tcp_name (&sin,NIL);
+  }
+  return stream->remotehost;
+}
+
+
+/* TCP/IP return port for this stream
+ * Accepts: TCP/IP stream
+ * Returns: port number for this stream
+ */
+
+unsigned long tcp_port (TCPSTREAM *stream)
+{
+  return stream->port;		/* return port number */
+}
+
+
+/* TCP/IP get local host name
+ * Accepts: TCP/IP stream
+ * Returns: local host name
+ */
+
+char *tcp_localhost (TCPSTREAM *stream)
+{
+  if (!stream->localhost) {
+    struct sockaddr_in sin;
+    int sinlen = sizeof (struct sockaddr_in);
+    stream->localhost =		/* get socket's name */
+      ((stream->port & 0xffff000) ||
+       ((getsockname (stream->tcpsi,(struct sockaddr *) &sin,&sinlen) ==
+	 SOCKET_ERROR) || (sinlen <= 0))) ?
+	   cpystr (mylocalhost ()) : tcp_name (&sin,NIL);
+  }
+  return stream->localhost;	/* return local host name */
+}
+
+/* TCP/IP get client host address (server calls only)
+ * Returns: client host address
+ */
+
+char *tcp_clientaddr ()
+{
+  if (!myClientAddr) {
+    struct sockaddr_in sin;
+    int sinlen = sizeof (struct sockaddr_in);
+    myClientAddr =		/* get stdin's peer name */
+      ((getpeername (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) ||
+       (sinlen <= 0)) ? cpystr ("UNKNOWN") : cpystr (inet_ntoa (sin.sin_addr));
+  }
+  return myClientAddr;
+}
+
+
+/* TCP/IP get client host name (server calls only)
+ * Returns: client host name
+ */
+
+char *tcp_clienthost ()
+{
+  if (!myClientHost) {
+    struct sockaddr_in sin;
+    int sinlen = sizeof (struct sockaddr_in);
+    myClientHost =		/* get stdin's peer name */
+      ((getpeername (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) ||
+       (sinlen <= 0)) ? cpystr ("UNKNOWN") : tcp_name (&sin,T);
+  }
+  return myClientHost;
+}
+
+/* TCP/IP get server host address (server calls only)
+ * Returns: server host address
+ */
+
+char *tcp_serveraddr ()
+{
+  if (!myServerAddr) {
+    struct sockaddr_in sin;
+    int sinlen = sizeof (struct sockaddr_in);
+    myServerAddr =		/* get stdin's peer name */
+      ((getsockname (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) ||
+       (sinlen <= 0)) ? cpystr ("UNKNOWN") : cpystr (inet_ntoa (sin.sin_addr));
+  }
+  return myServerAddr;
+}
+
+
+/* TCP/IP get server host name (server calls only)
+ * Returns: server host name
+ */
+
+static long myServerPort = -1;
+
+char *tcp_serverhost ()
+{
+  if (!myServerHost) {
+    struct sockaddr_in sin;
+    int sinlen = sizeof (struct sockaddr_in);
+    if (!wsa_initted++) {	/* init Windows Sockets */
+      WSADATA wsock;
+      if (WSAStartup (WSA_VERSION,&wsock)) {
+	wsa_initted = 0;
+	return "random-pc";	/* try again later? */
+      }
+    }
+				/* get stdin's name */
+    if ((getsockname (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) ||
+	(sinlen <= 0)) myServerHost = cpystr (mylocalhost ());
+    else {
+      myServerHost = tcp_name (&sin,NIL);
+      myServerPort = ntohs (sin.sin_port);
+    }
+  }
+  return myServerHost;
+}
+
+
+/* TCP/IP get server port number (server calls only)
+ * Returns: server port number
+ */
+
+long tcp_serverport ()
+{
+  if (!myServerHost) tcp_serverhost ();
+  return myServerPort;
+}
+
+/* TCP/IP return canonical form of host name
+ * Accepts: host name
+ * Returns: canonical form of host name
+ */
+
+char *tcp_canonical (char *name)
+{
+  char *ret,host[MAILTMPLEN];
+  struct hostent *he;
+  blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+				/* look like domain literal? */
+  if (name[0] == '[' && name[strlen (name) - 1] == ']') return name;
+  (*bn) (BLOCK_DNSLOOKUP,NIL);
+  if (tcpdebug) {
+    sprintf (host,"DNS canonicalization %.80s",name);
+    mm_log (host,TCPDEBUG);
+  }
+				/* note that NT requires lowercase! */
+  ret = (he = gethostbyname (lcase (strcpy (host,name)))) ? he->h_name : name;
+  (*bn) (BLOCK_NONE,NIL);
+  if (tcpdebug) mm_log ("DNS canonicalization done",TCPDEBUG);
+  return ret;
+}
+
+
+/* TCP/IP return name from socket
+ * Accepts: socket
+ *	    verbose flag
+ * Returns: cpystr name
+ */
+
+char *tcp_name (struct sockaddr_in *sin,long flag)
+{
+  char *ret,*t,adr[MAILTMPLEN],tmp[MAILTMPLEN];
+  sprintf (ret = adr,"[%.80s]",inet_ntoa (sin->sin_addr));
+  if (allowreversedns) {
+    struct hostent *he;
+    blocknotify_t bn = (blocknotify_t)mail_parameters(NIL,GET_BLOCKNOTIFY,NIL);
+    void *data;
+    if (tcpdebug) {
+      sprintf (tmp,"Reverse DNS resolution %s",adr);
+      mm_log (tmp,TCPDEBUG);
+    }
+    (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */
+    data = (*bn) (BLOCK_SENSITIVE,NIL);
+				/* translate address to name */
+    if (t = tcp_name_valid ((he = gethostbyaddr ((char *) &sin->sin_addr,
+						 sizeof (struct in_addr),
+						 sin->sin_family)) ?
+			    (char *) he->h_name : NIL)) {
+				/* produce verbose form if needed */
+      if (flag)	sprintf (ret = tmp,"%s %s",t,adr);
+      else ret = t;
+    }
+    (*bn) (BLOCK_NONSENSITIVE,data);
+    (*bn) (BLOCK_NONE,NIL);	/* alarms OK now */
+    if (tcpdebug) mm_log ("Reverse DNS resolution done",TCPDEBUG);
+  }
+  return cpystr (ret);
+}
+
+/* Return my local host name
+ * Returns: my local host name
+ */
+
+char *mylocalhost (void)
+{
+  if (!myLocalHost) {
+    char tmp[MAILTMPLEN];
+    if (!wsa_initted++) {	/* init Windows Sockets */
+      WSADATA wsock;
+      if (WSAStartup (WSA_VERSION,&wsock)) {
+	wsa_initted = 0;
+	return "random-pc";	/* try again later? */
+      }
+    }
+    myLocalHost = cpystr ((gethostname (tmp,MAILTMPLEN-1) == SOCKET_ERROR) ?
+			  "random-pc" : tcp_canonical (tmp));
+  }
+  return myLocalHost;
+}
+
+
+/* Validate name
+ * Accepts: domain name
+ * Returns: T if valid, NIL otherwise
+ */
+
+char *tcp_name_valid (char *s)
+{
+  int c;
+  char *ret,*tail;
+				/* must be non-empty and not too long */
+  if ((ret = (s && *s) ? s : NIL) && (tail = ret + NETMAXHOST)) {
+				/* must be alnum, dot, or hyphen */
+    while ((c = *s++) && (s <= tail) &&
+	   (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) ||
+	    ((c >= '0') && (c <= '9')) || (c == '-') || (c == '.')));
+    if (c) ret = NIL;
+  }
+  return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/osdep/wce/tcp_wce.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,46 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Winsock TCP/IP routines
+ *
+ * Author:	Mike Seibel from Unix version by Mark Crispin
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	11 April 1989
+ * Last Edited:	30 August 2006
+ */
+
+/* TCP input buffer -- must be large enough to prevent overflow */
+
+#define BUFLEN 8192
+
+
+/* TCP I/O stream (must be before osdep.h is included) */
+
+#define TCPSTREAM struct tcp_stream
+TCPSTREAM {
+  char *host;			/* host name */
+  char *remotehost;		/* remote host name */
+  unsigned long port;		/* port number */
+  char *localhost;		/* local host name */
+  int tcpsi;			/* input tcp socket */
+  int tcpso;			/* output tcp socket */
+  long ictr;			/* input counter */
+  char *iptr;			/* input pointer */
+  char ibuf[BUFLEN];		/* input buffer */
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tmail/Makefile	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,53 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+
+# Program:	tmail Makefile
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+#
+# Date:		5 April 1993
+# Last Edited:	10 September 2007
+
+
+C = ../c-client
+CCLIENTLIB = $C/c-client.a
+SHELL = /bin/sh
+
+# Get local definitions from c-client directory
+
+CC = `cat $C/CCTYPE`
+CFLAGS = -I$C `cat $C/CFLAGS`
+LDFLAGS = $(CCLIENTLIB) `cat $C/LDFLAGS`
+
+tmail: $(CCLIENTLIB) tmail.o tquota.o
+	$(CC) $(CFLAGS) -o tmail tmail.o tquota.o $(LDFLAGS)
+
+tmail.o: $C/mail.h $C/misc.h $C/osdep.h tquota.h
+
+tquota.o: tquota.h
+
+$(CCLIENTLIB):
+	cd $C;make
+
+clean:
+	rm -f *.o tmail
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo 'not war?'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tmail/tmail.1	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,205 @@
+.ig
+ * ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+..
+.TH TMAIL 1 "September 27, 2007"
+.SH NAME
+tmail \- Mail Delivery Module
+.nh
+.SH SYNOPSIS
+.B tmail
+.I [-b format] [\-D] [-f from_name] [\-I inbox_specifier] user[+folder] ...
+.SH DESCRIPTION
+.I tmail
+delivers mail to a user's INBOX or a designated folder.
+.I tmail
+may be configured as a drop-in replacement for
+.IR binmail (1),
+.IR mail.local (1)
+or any program intended for use for mail delivery by a mail delivery program
+such as
+.IR sendmail (8).
+.PP
+.I tmail
+is intended to be used for direct delivery by the mailer daemon;
+.IR dmail (1)
+is the preferred tool for user applications, e.g. a mail delivery
+filter such as
+.IR procmail (1) .
+If
+.I tmail
+is used for a user application,
+then the calling program must be aware of the restrictions noted below.
+.PP
+When
+.I tmail
+exits, it returns exit status values to enable the mail delivery program
+to determine whether a message was delivered successfully or had a
+temporary (requeue for later delivery) or permanent (return to sender)
+failure.
+.PP
+If the 
+.I +folder
+extension is included in the user argument, 
+.I tmail
+will attempt to deliver to the designated folder.  If the folder does not 
+exist or the extension is not included, the message is delivered to the 
+user's INBOX.
+If delivery is to INBOX and no INBOX currently exists,
+.I tmail
+will create a new INBOX, using the \fB-I\fR or \fB-b\fR flag if specified.
+.I tmail
+recognizes the format of an existing INBOX or folder, and appends the new
+message in that format.
+.PP
+The \fB-b\fR flag specifies a format to create INBOX if INBOX does not
+already exist.  This flag requires privileges, and can not be used with
+\fB-I\fR.  The argument is
+a format name such as mix, mbx, etc.
+.PP
+The \fB-D\fR flag specifies debugging; this enables additional message
+telemetry.
+.PP
+The \fB-f\fR or \fB-r\fR flag is used by
+the mail delivery program to specify a Return-Path.  The header
+.br
+   Return-Path: <\fIfrom_name\fR> 
+.br 
+is prepended to the message before delivery.  
+.PP
+The \fB-I\fR flag is used by the mail delivery program
+to specify an alternative INBOX name.  This flag requires privileges,
+and can not be used with \fB-b\fR.  This affects the location and format
+of INBOX.  If specified, it should be in one of three forms:
+.sp
+The first form of argument to \fB-I\fR is the string "INBOX", which
+means to write to the system default inbox using the system default
+mailbox format.  These system defaults are defined when the c-client
+library is built.
+.sp
+The second form of argument to \fB-I\fR is a delivery specification,
+consisting of "#driver.", a c-client mailbox format driver name, "/",
+and a file name.  This will write to the specified file in the
+specified format.  For example, #driver.mbx/INBOX will write to file
+"INBOX" in the home directory in mbx format; and
+#driver.unix/mail/incoming will write to file "incoming" in the
+user's "mail" subdirectory in unix (default UNIX) format.
+.sp
+The third form of argument to \fB-I\fR is any other name.  Normally,
+this will write to the specified file on the user's home directory in
+the specified format.  However, certain names are special.  These are:
+.PP
+.nf
+  value       equivalant to
+  -----       -------------
+  INBOX.MTX   #driver.mtx/INBOX.MTX
+  mbox        #driver.unix/mbox
+  mail.txt    #driver.tenex/mail.txt
+.fi
+.PP
+If \fB-I\fR is not specified, the default action is \fB-I INBOX\fR.
+.PP
+If multiple recipients are specified on the command line,
+.I tmail
+spawns one child process per recipient to perform actual delivery.  This
+way of calling
+.I tmail
+is not recommended; see below under
+.IR RESTRICTIONS .
+.SH INSTALLATION
+If 
+.I tmail
+is to be used for mail delivery from the mail delivery program, it 
+.I must
+be installed setuid root.
+.sp
+If sendmail is the mail delivery program,
+.I tmail
+is invoked from sendmail.cf.  Look for the "Mlocal" line, and substitute
+the path name for the
+.I tmail
+binary in place of /bin/mail, /usr/lib/mail.local, etc.  You should also
+add the flag to invoke
+.I tmail
+with CRLF style newlines; this is usually done with E=\\r\\n in the Mlocal
+line.
+.sp
+Here is an example of an Mlocal line in sendmail version 8:
+.sp
+.nf
+Mlocal, P=/usr/local/etc/tmail, F=lsDFMAw5:/|@qPrn+,
+  S=10/30, R=20/40, E=\\r\\n, T=DNS/RFC822/X-Unix,
+  A=tmail $u
+.fi
+.PP
+If
+.I tmail
+is to be called with the \fB-I\fR flag, it must be invoked with both
+real and effective UID root.  Many sendmail configurations invoke the
+local mailer as the sending user when that user is local, which
+will prevent \fB-b\fR or \fB-I\fR from working.
+.SH SECURITY CONSIDERATIONS
+If
+.I tmail
+is invoked by an ordinary user, the Received: header line will
+indicate the name or UID of the user that invoked it.
+.PP
+Ordinary users are not permitted to use the \fB-b\fR or \fB-I\fR flag since
+otherwise a user could create any file on another user's directory.
+.PP
+.I tmail
+can deliver mail to home directories.  In addition,
+.I tmail
+can be used to deliver mail to other mail folders in a home directory
+or an inferior directory of a home directory.
+.SH RESTRICTIONS
+The calling program should invoke
+.I tmail
+with CRLF newlines, otherwise
+.I tmail
+will complain in syslog.
+.PP
+Absolute pathnames and 
+.I ~user
+specifications are not permitted in
+.I +folder
+extensions.
+.PP
+Ordinary users are not permitted to use the \fB-I\fR flag.
+.PP
+IMAP4 namespace names are not yet supported in 
+.I +folder
+extensions.
+.PP
+It is not possible to use
+.I tmail
+to deliver to
+.IR mh (1)
+format mailboxes.
+.PP
+If delivery to multiple users is specified and delivery to any single user
+fails, the entire delivery will be reported as having failed, even though
+delivery to other users may have succeeded.  If
+.I tmail
+is used for mail delivery from
+.IR sendmail (8),
+a separate tmail invocation should be done for each user.  Otherwise a
+delivery failure for a single user in a message going to multiple users
+will cause multiple deliveries to all the other users every time
+.IR sendmail (8),
+retries.
+.SH AUTHOR
+Mark Crispin, MRC@CAC.Washington.EDU
+.SH "SEE ALSO"
+binmail(1)
+.br
+sendmail(8)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tmail/tmail.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,800 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Mail Delivery Module
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	5 April 1993
+ * Last Edited:	30 October 2008
+ */
+
+#include <stdio.h>
+#include <pwd.h>
+#include <errno.h>
+extern int errno;		/* just in case */
+#include <sysexits.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include "c-client.h"
+#include "tquota.h"
+
+
+/* Globals */
+
+char *version = "22";		/* tmail edit version */
+int debug = NIL;		/* debugging (don't fork) */
+int trycreate = NIL;		/* flag saying gotta create before appending */
+int critical = NIL;		/* flag saying in critical code */
+char *sender = NIL;		/* message origin */
+char *inbox = NIL;		/* inbox file */
+long precedence = 0;		/* delivery precedence - used by quota hook */
+DRIVER *format = NIL;		/* desired format */
+
+
+/* Function prototypes */
+
+void file_string_init (STRING *s,void *data,unsigned long size);
+char file_string_next (STRING *s);
+void file_string_setpos (STRING *s,unsigned long i);
+int main (int argc,char *argv[]);
+int deliver (FILE *f,unsigned long msglen,char *user);
+long ibxpath (MAILSTREAM *ds,char **mailbox,char *path);
+int deliver_safely (MAILSTREAM *prt,STRING *st,char *mailbox,char *path,
+		    uid_t uid,char *tmp);
+int delivery_unsafe (char *path,uid_t uid,struct stat *sbuf,char *tmp);
+int fail (char *string,int code);
+char *getusername (char *s,char **t);
+
+
+/* File string driver for file stringstructs */
+
+STRINGDRIVER file_string = {
+  file_string_init,		/* initialize string structure */
+  file_string_next,		/* get next byte in string structure */
+  file_string_setpos		/* set position in string structure */
+};
+
+
+/* Cache buffer for file stringstructs */
+
+#define CHUNKLEN 16384
+char chunk[CHUNKLEN];
+
+/* Initialize file string structure for file stringstruct
+ * Accepts: string structure
+ *	    pointer to string
+ *	    size of string
+ */
+
+void file_string_init (STRING *s,void *data,unsigned long size)
+{
+  s->data = data;		/* note fd */
+  s->size = size;		/* note size */
+  s->chunk = chunk;
+  s->chunksize = (unsigned long) CHUNKLEN;
+  SETPOS (s,0);			/* set initial position */
+}
+
+
+/* Get next character from file stringstruct
+ * Accepts: string structure
+ * Returns: character, string structure chunk refreshed
+ */
+
+char file_string_next (STRING *s)
+{
+  char c = *s->curpos++;	/* get next byte */
+  SETPOS (s,GETPOS (s));	/* move to next chunk */
+  return c;			/* return the byte */
+}
+
+
+/* Set string pointer position for file stringstruct
+ * Accepts: string structure
+ *	    new position
+ */
+
+void file_string_setpos (STRING *s,unsigned long i)
+{
+  if (i > s->size) i = s->size;	/* don't permit setting beyond EOF */
+  s->offset = i;		/* set new offset */
+  s->curpos = s->chunk;		/* reset position */
+				/* set size of data */
+  if (s->cursize = min (s->chunksize,SIZE (s))) {
+				/* move to that position in the file */
+    fseek ((FILE *) s->data,s->offset,SEEK_SET);
+    fread (s->curpos,sizeof (char),(unsigned int) s->cursize,(FILE *) s->data);
+  }
+}
+
+/* Main program */
+
+int main (int argc,char *argv[])
+{
+  FILE *f = NIL;
+  int pid,c,ret = 0;
+  unsigned long msglen,status = 0;
+  char *s,tmp[MAILTMPLEN];
+  uid_t ruid = getuid ();
+  struct passwd *pwd;
+  openlog ("tmail",LOG_PID,LOG_MAIL);
+#include "linkage.c"
+				/* make sure have some arguments */
+  if (--argc < 1) _exit (fail ("usage: tmail [-D] user[+folder]",EX_USAGE));
+				/* process all flags */
+  while (argc && (*(s = *++argv)) == '-') {
+    argc--;			/* gobble this argument */
+    switch (s[1]) {		/* what is this flag? */
+    case 'D':			/* debug */
+      debug = T;		/* don't fork */
+      break;
+    case 'I':			/* inbox specifier */
+      if (inbox || format) _exit (fail ("duplicate -b or -I",EX_USAGE));
+      if (argc--) inbox = cpystr (*++argv);
+      else _exit (fail ("missing argument to -I",EX_USAGE));
+      break;
+    case 'f':			/* new name for this flag */
+    case 'r':			/* flag giving return path */
+      if (sender) _exit (fail ("duplicate -f or -r",EX_USAGE));
+      if (argc--) sender = cpystr (*++argv);
+      else _exit (fail ("missing argument to -f or -r",EX_USAGE));
+      break;
+    case 'b':			/* create INBOX in this format */
+      if (inbox || format) _exit (fail ("duplicate -b or -I",EX_USAGE));
+      if (!argc--) _exit (fail ("missing argument to -b",EX_USAGE));
+      if (!(format = mail_parameters (NIL,GET_DRIVER,*++argv)))
+	_exit (fail ("unknown format to -b",EX_USAGE));
+      else if (!(format->flags & DR_LOCAL) ||
+	       !compare_cstring (format->name,"dummy"))
+	_exit (fail ("invalid format to -b",EX_USAGE));
+      break;
+    /* following flags are undocumented */
+    case 'p':			/* precedence for quota */
+      if (s[2] && ((s[2] == '-') || isdigit (s[2]))) precedence = atol (s + 2);
+      else if (argc-- && ((*(s = *++argv) == '-') || isdigit (*s)))
+	precedence = atol (s);
+      else _exit (fail ("missing argument to -p",EX_USAGE));
+      break;
+    case 'd':			/* obsolete flag meaning multiple users */
+      break;			/* ignore silently */
+    /* -s has been deprecated and replaced by the -s and -k flags in dmail.
+     * dmail's -k flag does what -s once did in tmail; dmail's -s flag
+     * takes no argument and just sets \Seen.  Flag setting is more properly
+     * done in dmail which runs as the user and is clearly at the user's
+     * behest.  Since tmail runs privileged, -s would have to be disabled
+     * unless the caller is also privileged.
+     */
+    case 's':			/* obsolete flag meaning delivery flags */
+      if (!argc--)		/* takes an argument */
+	_exit (fail ("missing argument to deprecated flag",EX_USAGE));
+      syslog (LOG_INFO,"tmail called with deprecated flag: -s %.200s",*++argv);
+      break;
+    default:			/* anything else */
+      _exit (fail ("unknown switch",EX_USAGE));
+    }
+  }
+
+  if (!argc) ret = fail ("no recipients",EX_USAGE);
+  else if (!(f = tmpfile ())) ret = fail ("can't make temp file",EX_TEMPFAIL);
+  else {			/* build delivery headers */
+    if (sender) fprintf (f,"Return-Path: <%s>\015\012",sender);
+				/* start Received line: */
+    fprintf (f,"Received: via tmail-%s.%s",CCLIENTVERSION,version);
+				/* not root or daemon? */
+    if (ruid && !((pwd = getpwnam ("daemon")) && (ruid == pwd->pw_uid))) {
+      pwd = getpwuid (ruid);	/* get unprivileged user's information */
+      if (inbox || format) {
+	if (pwd) sprintf (tmp,"user %.80s",pwd->pw_name);
+	else sprintf (tmp,"UID %ld",(long) ruid);
+	strcat (tmp," is not privileged to use -b or -I");
+	_exit (fail (tmp,EX_USAGE));
+      }
+      fputs (" (invoked by ",f);
+      if (pwd) fprintf (f,"user %s",pwd->pw_name);
+      else fprintf (f,"UID %ld",(long) ruid);
+      fputs (")",f);
+    }
+				/* write "for" if single recipient */
+    if (argc == 1) fprintf (f," for %s",*argv);
+    fputs ("; ",f);
+    rfc822_date (tmp);
+    fputs (tmp,f);
+    fputs ("\015\012",f);
+				/* copy text from standard input */
+    if (!fgets (tmp,MAILTMPLEN-1,stdin) || !(s = strchr (tmp,'\n')) ||
+	(s == tmp) || s[1]) _exit (fail ("bad first message line",EX_USAGE));
+    if (s[-1] == '\015') {	/* nuke leading "From " line */
+      if ((tmp[0] != 'F') || (tmp[1] != 'r') || (tmp[2] != 'o') ||
+	  (tmp[3] != 'm') || (tmp[4] != ' ')) fputs (tmp,f);
+      while ((c = getchar ()) != EOF) putc (c,f);
+    }
+    else {
+      mm_log ("tmail called with LF-only newlines",WARN);
+      if ((tmp[0] != 'F') || (tmp[1] != 'r') || (tmp[2] != 'o') ||
+	  (tmp[3] != 'm') || (tmp[4] != ' ')) {
+	*s++ = '\015';		/* overwrite NL with CRLF */
+	*s++ = '\012';
+	*s = '\0';		/* tie off string */
+	fputs (tmp,f);		/* write line */
+      }
+				/* copy text from standard input */
+      while ((c = getchar ()) != EOF) {
+				/* add CR if needed */
+	if (c == '\012') putc ('\015',f);
+	putc (c,f);
+      }
+    }
+    msglen = ftell (f);		/* size of message */
+    fflush (f);			/* make sure all changes written out */
+
+    if (ferror (f)) ret = fail ("error writing temp file",EX_TEMPFAIL);
+    else if (!msglen) ret = fail ("empty message",EX_TEMPFAIL);
+				/* single delivery */
+    else if (argc == 1) ret = deliver (f,msglen,*argv);
+    else do {			/* multiple delivery uses daughter forks */
+      if ((pid = fork ()) < 0) ret = fail (strerror (errno),EX_OSERR);
+      else if (pid) {		/* mother process */
+	grim_pid_reap_status (pid,NIL,(void *) status);
+				/* normal termination? */
+	if (!ret) ret = (status & 0xff) ? EX_SOFTWARE : (status & 0xff00) >> 8;
+      }
+				/* daughter process */
+      else _exit (deliver (f,msglen,*argv));
+    } while (--argc && *argv++);
+    mm_dlog (ret ? "error in delivery" : "all recipients delivered");
+  }
+  if (f) fclose (f);		/* all done with temporary file */
+  _exit (ret);			/* normal exit */
+  return 0;			/* stupid gcc */
+}
+
+/* Deliver message to recipient list
+ * Accepts: file description of message temporary file
+ *	    size of message temporary file in bytes
+ *	    recipient name
+ * Returns: NIL if success, else error code
+ */
+
+int deliver (FILE *f,unsigned long msglen,char *user)
+{
+  MAILSTREAM *ds = NIL;
+  char *s,*t,*mailbox,tmp[MAILTMPLEN],path[MAILTMPLEN];
+  struct passwd *pwd;
+  STRING st;
+  struct stat sbuf;
+  uid_t duid;
+  uid_t euid = geteuid ();
+				/* get user record */
+  if (!(pwd = getpwnam (getusername (user,&mailbox)))) {
+    sprintf (tmp,"no such user as %.80s",user);
+    return fail (tmp,EX_NOUSER);
+  }
+				/* absurd is absurd */
+  if (mailbox && (strlen (mailbox) > 256))
+    return fail ("absurd folder name",EX_NOUSER);
+				/* big security hole if this is allowed */
+  if (!(duid = pwd->pw_uid)) return fail ("mail to root prohibited",EX_NOUSER);
+				/* log in as user if different than euid */
+  if ((duid != euid) && !loginpw (pwd,1,&user)) {
+    sprintf (tmp,"unable to log in UID %ld from UID %ld",
+	     (long) duid,(long) euid);
+    return fail (tmp,EX_NOUSER);
+  }
+				/* can't use pwd after this point */
+  env_init (pwd->pw_name,pwd->pw_dir);
+  sprintf (tmp,"delivering to %.80s+%.80s",user,mailbox ? mailbox : "INBOX");
+  mm_dlog (tmp);
+				/* prepare stringstruct */
+  INIT (&st,file_string,(void *) f,msglen);
+  if (mailbox) {		/* non-INBOX name */
+    switch (mailbox[0]) {	/* make sure a valid name */
+    default:			/* other names, try to deliver if not INBOX */
+      if (!strstr (mailbox,"..") && !strstr (mailbox,"//") &&
+	  !strstr (mailbox,"/~") && mailboxfile (path,mailbox) && path[0] &&
+	  !deliver_safely (NIL,&st,mailbox,path,duid,tmp)) return NIL;
+    case '%': case '*':		/* wildcards not valid */
+    case '#':			/* namespace name not valid */
+    case '/':			/* absolute path names not valid */
+    case '~':			/* user names not valid */
+      sprintf (tmp,"invalid mailbox name %.80s+%.80s",user,mailbox);
+      mm_log (tmp,WARN);
+      break;
+    }
+    mm_dlog ("retrying delivery to INBOX");
+    SETPOS (&st,0);		/* rewind stringstruct just in case */
+  }
+
+				/* -I specified and not "-I INBOX"? */
+  if (inbox && !(((inbox[0] == 'I') || (inbox[0] == 'i')) &&
+		 ((inbox[1] == 'N') || (inbox[1] == 'n')) &&
+		 ((inbox[2] == 'B') || (inbox[2] == 'b')) &&
+		 ((inbox[3] == 'O') || (inbox[3] == 'o')) &&
+		 ((inbox[4] == 'X') || (inbox[4] == 'x')) && !inbox[5])) {
+    DRIVER *dv = NIL;
+				/* "-I #driver.xxx/name"? */
+    if ((*inbox == '#') && ((inbox[1] == 'd') || (inbox[1] == 'D')) &&
+	((inbox[2] == 'r') || (inbox[2] == 'R')) &&
+	((inbox[3] == 'i') || (inbox[3] == 'I')) &&
+	((inbox[4] == 'v') || (inbox[4] == 'V')) &&
+	((inbox[5] == 'e') || (inbox[5] == 'E')) &&
+	((inbox[6] == 'r') || (inbox[6] == 'R')) && (inbox[7] == '.') &&
+	(s = strchr (inbox+8,'/'))) {
+      *s = '\0';		/* temporarily tie off driver name */
+      if (!((dv = mail_parameters (NIL,GET_DRIVER,(void *) (inbox+8))) &&
+	    (mailboxfile (path,s[1] ? s + 1 : "&&&&&") == path) &&
+	    (s[1] || ((t = strstr (path,"&&&&&")) && strcpy (t,"INBOX"))))) {
+	path[0] = '\0';		/* bad -I argument, no path resolved */
+	sprintf (tmp,"Unable to resolve driver in %.80s, -I ignored",inbox);
+	mm_log (tmp,WARN);
+      }
+      *s = '/';			/* restore delimiter */
+    }
+				/* resolve "-I other" specification */
+    else if (mailboxfile (path,inbox) && path[0]) {
+				/* resolution succeeded, impute driver */
+      if (!strcmp (inbox,"mail.txt"))
+	dv = mail_parameters (NIL,GET_DRIVER,(void *) "tenex");
+      else if (!strcmp (inbox,"INBOX.MTX"))
+	dv = mail_parameters (NIL,GET_DRIVER,(void *) "mtx");
+      else if (!strcmp (inbox,"mbox"))
+	dv = mail_parameters (NIL,GET_DRIVER,(void *) "unix");
+    }
+    else {			/* bad -I argument */
+      path[0] = '\0';		/* no path resolved */
+      sprintf (tmp,"Unable to resolve %.80s, -I ignored",inbox);
+      mm_log (tmp,WARN);
+    }
+    if (*path) {		/* -I successfully resolved a path? */
+      MAILSTREAM dpr;
+      dpr.dtb = dv;
+      if (dv) ds = &dpr;
+				/* supplicate to the Evil One if necessary */
+      if (lstat (path,&sbuf) && !path_create (ds,path)) {
+				/* the Evil One rejected the plea */
+	sprintf (tmp,"Unable to create %.80s, -I ignored",path);
+	mm_log (tmp,WARN);
+      }
+				/* now attempt delivery */
+      else return deliver_safely (ds,&st,inbox,path,duid,tmp);
+    }
+  }
+
+				/* no -I, resolve "INBOX" into path */
+  if (mailboxfile (path,mailbox = "INBOX") && !path[0]) {
+				/* clear box, get generic INBOX prototype */
+    if (!(ds = mail_open (NIL,"INBOX",OP_PROTOTYPE)))
+      fatal ("no INBOX prototype");
+				/* standard system driver? */
+    if (!strcmp (ds->dtb->name,"unix") || !strcmp (ds->dtb->name,"mmdf")) {
+      strcpy (path,sysinbox ());/* use system INBOX */
+      if (!lstat (path,&sbuf))	/* deliver to existing system INBOX */
+	return deliver_safely (ds,&st,mailbox,path,duid,tmp);
+    }
+    else {			/* other driver, try ~/INBOX */
+      if ((mailboxfile (path,"&&&&&") == path) &&
+	  (s = strstr (path,"&&&&&")) && strcpy (s,"INBOX") &&
+	  !lstat (path,&sbuf)){	/* deliver to existing ~/INBOX */
+	sprintf (tmp,"#driver.%s/INBOX",ds->dtb->name);
+	return deliver_safely (ds,&st,cpystr (tmp),path,duid,tmp);
+      }
+    }
+				/* not dummy, deliver to driver imputed path */
+    if (strcmp (ds->dtb->name,"dummy"))
+      return (ibxpath (ds,&mailbox,path) && !lstat (path,&sbuf)) ?
+	deliver_safely (ds,&st,mailbox,path,duid,tmp) :
+	  fail ("unable to resolve INBOX path",EX_CANTCREAT);
+				/* dummy, empty imputed append path exist? */
+    if (ibxpath (ds = default_proto (T),&mailbox,path) &&
+	!lstat (path,&sbuf) && !sbuf.st_size)
+      return deliver_safely (ds,&st,mailbox,path,duid,tmp);
+				/* impute path that we will create */
+    if (!ibxpath (ds = format ? (format->open) (NIL) : default_proto (NIL),
+		  &mailbox,path))
+      return fail ("unable to resolve INBOX",EX_CANTCREAT);
+  }
+				/* black box, must create, get create proto */
+  else if (lstat (path,&sbuf)) ds = default_proto (NIL);
+  else {			/* black box, existing file */
+				/* empty file, get append prototype */
+    if (!sbuf.st_size) ds = default_proto (T);
+				/* non-empty, get prototype from its data */
+    else if (!(ds = mail_open (NIL,"INBOX",OP_PROTOTYPE)))
+      fatal ("no INBOX prototype");
+				/* error if unknown format */
+    if (!strcmp (ds->dtb->name,"phile"))
+      return fail ("unknown format INBOX",EX_UNAVAILABLE);
+				/* otherwise can deliver to it */
+    return deliver_safely (ds,&st,mailbox,path,duid,tmp);
+  }
+  sprintf (tmp,"attempting to create mailbox %.80s path %.80s",mailbox,path);
+  mm_dlog (tmp);
+				/* supplicate to the Evil One */
+  if (!path_create (ds,path)) return fail ("can't create INBOX",EX_CANTCREAT);
+  sprintf (tmp,"created %.80s",path);
+  mm_dlog (tmp);
+				/* deliver the message */
+  return deliver_safely (ds,&st,mailbox,path,duid,tmp);
+}
+
+/* Resolve INBOX from driver prototype into mailbox name and filesystem path
+ * Accepts: driver prototype
+ * 	    pointer to mailbox name string pointer
+ *	    buffer to return mailbox path
+ * Returns: T if success, NIL if error
+ */
+
+long ibxpath (MAILSTREAM *ds,char **mailbox,char *path)
+{
+  char *s,tmp[MAILTMPLEN];
+  long ret = T;
+  if (!ds) ret = NIL;
+  else if (!strcmp (ds->dtb->name,"unix") || !strcmp (ds->dtb->name,"mmdf"))
+    strcpy (path,sysinbox ());	/* use system INBOX for unix and MMDF */
+  else if (!strcmp (ds->dtb->name,"tenex"))
+    ret = (mailboxfile (path,"mail.txt") == path) ? T : NIL;
+  else if (!strcmp (ds->dtb->name,"mtx"))
+    ret = (mailboxfile (path,"INBOX.MTX") == path) ? T : NIL;
+  else if (!strcmp (ds->dtb->name,"mbox"))
+    ret = (mailboxfile (path,"mbox") == path) ? T : NIL;
+				/* better not be a namespace driver */
+  else if (ds->dtb->flags & DR_NAMESPACE) return NIL;
+				/* INBOX in home directory */
+  else ret = ((mailboxfile (path,"&&&&&") == path) &&
+	      (s = strstr (path,"&&&&&")) && strcpy (s,"INBOX")) ? T : NIL;
+  if (ret) {			/* don't bother if lossage */
+    sprintf (tmp,"#driver.%s/INBOX",ds->dtb->name);
+    *mailbox = cpystr (tmp);	/* name of INBOX in this namespace */
+  }
+  return ret;
+}
+
+/* Deliver safely
+ * Accepts: prototype stream to force mailbox format
+ *	    stringstruct of message temporary file
+ *	    mailbox name
+ *	    filesystem path name
+ *	    user id
+ *	    scratch buffer for messages
+ * Returns: NIL if success, else error code
+ */
+
+int deliver_safely (MAILSTREAM *prt,STRING *st,char *mailbox,char *path,
+		    uid_t uid,char *tmp)
+{
+  struct stat sbuf;
+  int i = delivery_unsafe (path,uid,&sbuf,tmp);
+  if (i) return i;		/* give up now if delivery unsafe */
+				/* directory, not file */
+  if ((sbuf.st_mode & S_IFMT) == S_IFDIR) {
+    if (sbuf.st_mode & 0001) {	/* listable directories may be worrisome */
+      sprintf (tmp,"WARNING: directory %.80s is listable",path);
+      mm_log (tmp,WARN);
+    }
+  }
+  else {			/* file, not directory */
+    if (sbuf.st_nlink != 1) {	/* multiple links may be worrisome */
+      sprintf (tmp,"WARNING: multiple links to file %.80s",path);
+      mm_log (tmp,WARN);
+    }
+    if (sbuf.st_mode & 0111) {	/* executable files may be worrisome */
+      sprintf (tmp,"WARNING: file %.80s is executable",path);
+      mm_log (tmp,WARN);
+    }
+  }
+  if (sbuf.st_mode & 0002) {	/* public-write files may be worrisome */
+    sprintf (tmp,"WARNING: file %.80s is publicly-writable",path);
+    mm_log (tmp,WARN);
+  }
+  if (sbuf.st_mode & 0004) {	/* public-write files may be worrisome */
+    sprintf (tmp,"WARNING: file %.80s is publicly-readable",path);
+    mm_log (tmp,WARN);
+  }
+				/* check site-written quota procedure */
+  if (!tmail_quota (st,path,uid,tmp,sender,precedence)) return fail (tmp,-1);
+				/* so far, so good */
+  sprintf (tmp,"%s appending to %.80s (%s %.80s)",
+	   prt ? prt->dtb->name : "default",mailbox,
+	   ((sbuf.st_mode & S_IFMT) == S_IFDIR) ? "directory" : "file",path);
+  mm_dlog (tmp);
+				/* do the append now! */
+  if (!mail_append (prt,mailbox,st)) {
+    sprintf (tmp,"message delivery failed to %.80s",path);
+    return fail (tmp,EX_CANTCREAT);
+  }
+				/* note success */
+  sprintf (tmp,"delivered to %.80s",path);
+  mm_log (tmp,NIL);
+				/* make sure nothing evil this way comes */
+  return delivery_unsafe (path,uid,&sbuf,tmp);
+}
+
+/* Verify that delivery is safe
+ * Accepts: path name
+ *	    user id
+ *	    stat buffer
+ *	    scratch buffer for messages
+ * Returns: NIL if delivery is safe, error code if unsafe
+ */
+
+int delivery_unsafe (char *path,uid_t uid,struct stat *sbuf,char *tmp)
+{
+  u_short type;
+  sprintf (tmp,"Verifying safe delivery to %.80s by UID %ld",path,(long) uid);
+  mm_dlog (tmp);
+				/* prepare message just in case */
+  sprintf (tmp,"delivery to %.80s unsafe: ",path);
+				/* unsafe if can't get its status */
+  if (lstat (path,sbuf)) strcat (tmp,strerror (errno));
+  else if (sbuf->st_uid != uid)	/* unsafe if UID does not match */
+    sprintf (tmp + strlen (tmp),"uid mismatch (%ld != %ld)",
+	     (long) sbuf->st_uid,(long) uid);
+				/* check file type */
+  else switch (sbuf->st_mode & S_IFMT) {
+  case S_IFDIR:			/* directory is always OK */
+    return NIL;
+  case S_IFREG:			/* file is unsafe if setuid */
+    if (sbuf->st_mode & S_ISUID) strcat (tmp,"setuid file");
+				/* or setgid */
+    else if (sbuf->st_mode & S_ISGID) strcat (tmp,"setgid file");
+    else return NIL;		/* otherwise safe */
+    break;
+  case S_IFCHR: strcat (tmp,"character special"); break;
+  case S_IFBLK: strcat (tmp,"block special"); break;
+  case S_IFLNK: strcat (tmp,"symbolic link"); break;
+  case S_IFSOCK: strcat (tmp,"socket"); break;
+  default:
+    sprintf (tmp + strlen (tmp),"file type %07o",(unsigned int) type);
+  }
+  return fail (tmp,EX_CANTCREAT);
+}
+
+/* Report an error
+ * Accepts: string to output
+ */
+
+int fail (char *string,int code)
+{
+  mm_log (string,ERROR);	/* pass up the string */
+  switch (code) {
+#if T
+  case EX_USAGE:
+  case EX_OSERR:
+  case EX_SOFTWARE:
+  case EX_NOUSER:
+  case EX_CANTCREAT:
+  case EX_UNAVAILABLE:
+    code = EX_TEMPFAIL;		/* coerce these to TEMPFAIL */
+#endif
+    break;
+  case -1:			/* quota failure... */
+    code = EX_CANTCREAT;	/* ...really returns this code */
+    break;
+  default:
+    break;
+  }
+  return code;			/* error code to return */
+}
+
+
+/* Get user name from username+mailbox specifier
+ * Accepts: username/mailbox specifier
+ *	    pointer to return location for mailbox specifier
+ * Returns: user name, mailbox specifier value NIL if INBOX, patches out +
+ */
+
+char *getusername (char *s,char **t)
+{
+  if (*t = strchr (s,'+')) {	/* have a mailbox specifier? */
+    *(*t)++ = '\0';		/* yes, tie off user name */
+				/* user+ and user+INBOX same as user */
+    if (!**t || !compare_cstring ((unsigned char *) *t,"INBOX")) *t = NIL;
+  }
+  return s;			/* return user name */
+}
+
+/* Co-routines from MAIL library */
+
+
+/* Message matches a search
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void mm_searched (MAILSTREAM *stream,unsigned long msgno)
+{
+  fatal ("mm_searched() call");
+}
+
+
+/* Message exists (i.e. there are that many messages in the mailbox)
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void mm_exists (MAILSTREAM *stream,unsigned long number)
+{
+  fatal ("mm_exists() call");
+}
+
+
+/* Message expunged
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void mm_expunged (MAILSTREAM *stream,unsigned long number)
+{
+  fatal ("mm_expunged() call");
+}
+
+
+/* Message flags update seen
+ * Accepts: MAIL stream
+ *	    message number
+ */
+
+void mm_flags (MAILSTREAM *stream,unsigned long number)
+{
+}
+
+/* Mailbox found
+ * Accepts: MAIL stream
+ *	    delimiter
+ *	    mailbox name
+ *	    mailbox attributes
+ */
+
+void mm_list (MAILSTREAM *stream,int delimiter,char *name,long attributes)
+{
+  fatal ("mm_list() call");
+}
+
+
+/* Subscribed mailbox found
+ * Accepts: MAIL stream
+ *	    delimiter
+ *	    mailbox name
+ *	    mailbox attributes
+ */
+
+void mm_lsub (MAILSTREAM *stream,int delimiter,char *name,long attributes)
+{
+  fatal ("mm_lsub() call");
+}
+
+
+/* Mailbox status
+ * Accepts: MAIL stream
+ *	    mailbox name
+ *	    mailbox status
+ */
+
+void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
+{
+  fatal ("mm_status() call");
+}
+
+/* Notification event
+ * Accepts: MAIL stream
+ *	    string to log
+ *	    error flag
+ */
+
+void mm_notify (MAILSTREAM *stream,char *string,long errflg)
+{
+  char tmp[MAILTMPLEN];
+  tmp[11] = '\0';		/* see if TRYCREATE */
+  if (!strcmp (ucase (strncpy (tmp,string,11)),"[TRYCREATE]")) trycreate = T;
+  mm_log (string,errflg);	/* just do mm_log action */
+}
+
+
+/* Log an event for the user to see
+ * Accepts: string to log
+ *	    error flag
+ */
+
+void mm_log (char *string,long errflg)
+{
+  if (trycreate)mm_dlog(string);/* debug logging only if trycreate in effect */
+  else {			/* ordinary logging */
+    fprintf (stderr,"%s\n",string);
+    switch (errflg) {  
+    case NIL:			/* no error */
+      syslog (LOG_INFO,"%s",string);
+      break;
+    case PARSE:			/* parsing problem */
+    case WARN:			/* warning */
+      syslog (LOG_WARNING,"%s",string);
+      break;
+    case ERROR:			/* error */
+    default:
+      syslog (LOG_ERR,"%s",string);
+      break;
+    }
+  }
+}
+
+
+/* Log an event to debugging telemetry
+ * Accepts: string to log
+ */
+
+void mm_dlog (char *string)
+{
+  if (debug) fprintf (stderr,"%s\n",string);
+  syslog (LOG_DEBUG,"%s",string);
+}
+
+/* Get user name and password for this host
+ * Accepts: parse of network mailbox name
+ *	    where to return user name
+ *	    where to return password
+ *	    trial count
+ */
+
+void mm_login (NETMBX *mb,char *username,char *password,long trial)
+{
+  fatal ("mm_login() call");
+}
+
+
+/* About to enter critical code
+ * Accepts: stream
+ */
+
+void mm_critical (MAILSTREAM *stream)
+{
+  critical = T;			/* note in critical code */
+}
+
+
+/* About to exit critical code
+ * Accepts: stream
+ */
+
+void mm_nocritical (MAILSTREAM *stream)
+{
+  critical = NIL;		/* note not in critical code */
+}
+
+
+/* Disk error found
+ * Accepts: stream
+ *	    system error code
+ *	    flag indicating that mailbox may be clobbered
+ * Returns: T if user wants to abort
+ */
+
+long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
+{
+  return T;
+}
+
+
+/* Log a fatal error event
+ * Accepts: string to log
+ */
+
+void mm_fatal (char *string)
+{
+  printf ("?%s\n",string);	/* shouldn't happen normally */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tmail/tquota.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,45 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Mail Delivery Module Quota Hook
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 September 2007
+ * Last Edited:	10 September 2007
+ */
+
+#include "c-client.h"
+
+/* Site-written routine to validate delivery per quota and policy
+ * Accepts: stringstruct of message temporary file
+ *	    filesystem path
+ *	    recipient user id
+ *	    return path
+ *	    buffer to write error message
+ *	    precedence setting
+ * Returns: T if can deliver, or NIL if quota issue and must bounce
+ */
+
+long tmail_quota (STRING *msg,char *path,uid_t uid,char *tmp,char *sender,
+		  long precedence)
+{
+  return LONGT;			/* dummy success return */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tmail/tquota.h	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,32 @@
+/* ========================================================================
+ * Copyright 1988-2007 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	Mail Delivery Module Quota Hook
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		Administration Building, AG-44
+ *		Seattle, WA  98195
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	10 September 2007
+ * Last Edited:	10 September 2007
+ */
+
+/* Function prototypes */
+
+long tmail_quota (STRING *msg,char *path,uid_t uid,char *tmp,char *sender,
+		  long precedence);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/Makefile	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,36 @@
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+# Program:	Tools Makefile
+#
+# Author:	Mark Crispin
+#		Networks and Distributed Computing
+#		Computing & Communications
+#		University of Washington
+#		Administration Building, AG-44
+#		Seattle, WA  98195
+#		Internet: MRC@CAC.Washington.EDU
+
+
+CC=cc
+RM=rm -f
+
+
+uahelper:
+	$(CC) -o uahelper uahelper.c $(LDFLAGS)
+
+clean:
+	sh -c '$(RM) *.o uahelper || true'
+
+# A monument to a hack of long ago and far away...
+love:
+	@echo 'not war?'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/an	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+# ========================================================================
+# Copyright 1988-2007 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+BASE=`pwd`
+
+if [ ! -d $3 ]; then
+ mkdir $3
+fi
+
+for i in $2/Makefile* ; do
+  if [ -f $i ] ; then
+    $1 "$BASE/$i" "$BASE/$3"
+  fi
+done
+
+if [ -f $2/drivers ]; then
+  $1 "$BASE/$2/drivers" "$BASE/$3"
+fi
+
+if [ -f $2/mkauths ]; then
+  $1 "$BASE/$2/mkauths" "$BASE/$3"
+fi
+
+cd $2
+
+for j in *.[ch]; do
+  $1 "$BASE/$2/$j" "$BASE/$3"
+done
+
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ua	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+# ========================================================================
+# Copyright 1988-2006 University of Washington
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# 
+# ========================================================================
+
+BASE=`pwd`
+
+if [ ! -f tools/uahelper ]; then
+  (cd tools;make)
+fi
+
+if [ ! -d $3 ]; then
+ mkdir $3
+fi
+
+for i in $2/Makefile* ; do
+  if [ -f $i ] ; then
+    $1 "$BASE/$i" "$BASE/$3"
+  fi
+done
+
+if [ -f $2/drivers ]; then
+  $1 "$BASE/$2/drivers" "$BASE/$3"
+fi
+
+if [ -f $2/mkauths ]; then
+  $1 "$BASE/$2/mkauths" "$BASE/$3"
+fi
+
+cd $2
+
+for j in *.[ch]; do
+  "$BASE/tools/uahelper" < $j > "$BASE/$3/$j"
+done
+
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/uahelper.c	Mon Sep 14 15:17:45 2009 +0900
@@ -0,0 +1,262 @@
+/* ========================================================================
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 
+ * ========================================================================
+ */
+
+/*
+ * Program:	unANSIify
+ *
+ * Author:	Mark Crispin
+ *		Networks and Distributed Computing
+ *		Computing & Communications
+ *		University of Washington
+ *		4545 15th Ave NE
+ *		Seattle, WA  98105-4527
+ *		Internet: MRC@CAC.Washington.EDU
+ *
+ * Date:	1 June 1995
+ * Last Edited:	30 August 2006
+ */
+
+
+/* This program is designed to make traditional C sources out of my source
+ * files which use ANSI syntax.  This program depends heavily upon knowledge
+ * of the way I write code, and is not a general purpose tool.  I hope that
+ * someday someone will provide a general purpose tool...
+ */
+
+#include <stdio.h>
+
+#define LINELENGTH 1000
+
+
+/* Find first non-whitespace
+ * Accepts: string
+ * Returns: 0 if no non-whitespace found, or pointer to non-whitespace
+ */
+
+char *fndnws (s)
+     char *s;
+{
+  while ((*s == ' ') || (*s == '\t'))
+    if ((*s++ == '\n') || !*s) return (char *) 0;
+  return s;
+}
+
+
+/* Find first whitespace
+ * Accepts: string
+ * Returns: 0 if no whitespace found, or pointer to whitespace
+ */
+
+char *fndws (s)
+     char *s;
+{
+  while ((*s != ' ') && (*s != '\t'))
+    if ((*s++ == '\n') || !*s) return (char *) 0;
+  return s;
+}
+
+
+/* Find end of commend
+ * Accepts: string
+ * Returns: -1 if end of comment found, else 0
+ */
+
+int fndcmt (s)
+     char *s;
+{
+  while (*s && (*s != '\n'))
+    if ((*s++ == '*') && (*s == '/')) return -1;
+  return 0;
+}
+
+/* Output a line
+ * Accepts: string
+ */
+
+void poot (s)
+     char *s;
+{
+  if (s) fputs (s,stdout);
+}
+
+
+/* Skip prefix
+ * Accepts: string
+ * Returns: updated string
+ */
+
+char *skipfx (s)
+     char *s;
+{
+  char c,*t = s,*tt;
+				/* skip leading whitespace too */
+  while ((*s == ' ') || (*s == '\t')) *s++;
+  if (s != t) {
+    c = *s;			/* save character */
+    *s = '\0';			/* tie off prefix */
+    poot (t);			/* output prefix */
+    *s = c;			/* restore character */
+  }
+				/* a typedef? */
+  if (((s[0] == 't') && (s[1] == 'y') && (s[2] == 'p') && (s[3] == 'e') &&
+       (s[4] == 'd') && (s[5] == 'e') && (s[6] == 'f')) &&
+      (t = fndws (s)) && (t = fndnws (t))) {
+    if ((t[0] == 'u') && (t[1] == 'n') && (t[2] == 's') && (t[3] == 'i') &&
+	(t[4] == 'g') && (t[5] == 'n') && (t[6] == 'e') && (t[7] == 'd') &&
+	(tt = fndws (t+7)) && (tt = fndnws (tt))) t = tt;
+    c = *t;			/* save character */
+    *t = '\0';			/* tie off prefix */
+    poot (s);			/* output prefix */
+    *t = c;			/* restore character */
+    s = t;			/* new string pointer */
+  }
+				/* static with known prefix */
+  else if (((s[0] == 's') && (s[1] == 't') && (s[2] == 'a') &&
+	    (s[3] == 't') && (s[4] == 'i') && (s[5] == 'c') &&
+	    (s[6] == ' ')) &&
+	   (((s[7] == 'u') && (s[8] == 'n') && (s[9] == 's') &&
+	     (s[10] == 'i') && (s[11] == 'g') && (s[12] == 'n') &&
+	     (s[13] == 'e') && (s[14] == 'd')) ||
+	    ((s[7] == 's') && (s[8] == 't') && (s[9] == 'r') &&
+	     (s[10] == 'u') && (s[11] == 'c') && (s[12] == 't')) ||
+	    ((s[7] == 'd') && (s[8] == 'o')) ||
+	    ((s[9] == 'e') && (s[10] == 'l') && (s[11] == 's') &&
+	     (s[12] == 'e'))) &&
+	   (t = fndws (s)) && (t = fndnws (t)) &&
+	   (t = fndws (t)) && (t = fndnws (t))) {
+    c = *t;			/* save character */
+    *t = '\0';			/* tie off prefix */
+    poot (s);			/* output prefix */
+    *t = c;			/* restore character */
+    s = t;			/* new string pointer */
+  }
+				/* one of the known prefixes? */
+  else if ((((s[0] == 'u') && (s[1] == 'n') && (s[2] == 's') &&
+	     (s[3] == 'i') && (s[4] == 'g') && (s[5] == 'n') &&
+	     (s[6] == 'e') && (s[7] == 'd')) ||
+	    ((s[0] == 's') && (s[1] == 't') && (s[2] == 'r') &&
+	     (s[3] == 'u') && (s[4] == 'c') && (s[5] == 't')) ||
+	    ((s[0] == 's') && (s[1] == 't') && (s[2] == 'a') &&
+	     (s[3] == 't') && (s[4] == 'i') && (s[5] == 'c')) ||
+	    ((s[0] == 'd') && (s[1] == 'o')) ||
+	    ((s[0] == 'e') && (s[1] == 'l') && (s[2] == 's') &&
+	     (s[3] == 'e'))) &&
+	   (t = fndws (s)) && (t = fndnws (t))) {
+    c = *t;			/* save character */
+    *t = '\0';			/* tie off prefix */
+    poot (s);			/* output prefix */
+    *t = c;			/* restore character */
+    s = t;			/* new string pointer */
+  }
+				/* may look like a proto, but isn't */
+  else if ((s[0] == 'r') && (s[1] == 'e') && (s[2] == 't') && (s[3] == 'u') &&
+	   (s[4] == 'r') && (s[5] == 'n')) {
+    poot (s);
+    return 0;
+  }
+  return s;
+}
+
+/* UnANSI a line
+ * Accepts: string
+ */
+
+void unansi (s)
+     char *s;
+{
+  char c,*t = s,*u,*v;
+  while (t[1] && (t[1] != '\n')) t++;
+  switch (*t) {
+  case ',':			/* continued on next line? */
+				/* slurp remainder of line */
+    fgets (t + 1,LINELENGTH - (t + 1 - s),stdin);
+    unansi (s);			/* try again */
+    break;
+  case ';':			/* function prototype? */
+				/* yes, tie it off */
+    *(fndws (fndnws (fndws (fndnws (s))))) = '\0';
+    printf ("%s ();\n",s);	/* and output non-ANSI form */
+    break;
+  case ')':
+    *t = '\0';			/* tie off args */
+    if (*(t = fndnws (fndws (fndnws (fndws (fndnws (s)))))) == '(') {
+      *t++ = '\0';		/* tie off */
+      while ((*t == ' ') || (*t == '\t')) t++;
+      if ((t[0] == 'v') && (t[1] == 'o') && (t[2] == 'i') && (t[3] == 'd') &&
+	  !t[4]) *t = '\0';	/* make void be same as null */
+      printf ("%s(",s);		/* output start of function */
+      s = t;
+      while (*s) {		/* for each argument */
+	while ((*s == ' ') || (*s == '\t')) s++;
+	for (u = v = s; (*u && (*u != ',') && (*u != '[')); u++)
+	  if ((*u == ' ') || (*u == '\t')) v = u;
+	c = *u;			/* remember delimiter */
+	*u = '\0';		/* tie off argument name */
+	while (*++v == '*');	/* remove leading pointer indication */
+	fputs (v,stdout);	/* write variable name */
+	*(s = u) = c;		/* restore delimiter */
+	while (*s && (*s != ',')) *s++;
+	if (*s) fputc (*s++,stdout);
+      }
+      puts (")");		/* end of function */
+      while (*t) {		/* for each argument */
+	fputs ("     ",stdout);
+	while ((*t == ' ') || (*t == '\t')) t++;
+	while (*t && (*t != ',')) fputc (*t++,stdout);
+	puts (";");
+	if (*t == ',') t++;
+      }
+    }
+    else printf ("%s)",s);	/* say what?? */
+    break;
+  default:			/* doesn't look like a function */
+    poot (s);
+  }
+}
+
+main ()
+{
+  char *s,*t,line[LINELENGTH];
+  int c;
+  while (s = fgets (line,LINELENGTH,stdin)) switch (line[0]) {
+  case '/':			/* comment */
+    if ((s[1] != '*') || fndcmt (s+2)) poot (line);
+    else do poot (line);
+    while (!fndcmt (line) && (s = fgets (line,LINELENGTH,stdin)));
+    break;
+  case '{':			/* open function */
+  case '}':			/* close function */
+  case '\f':			/* formfeed */
+  case '\n':			/* newline */
+  case '#':			/* preprocessor command */
+    poot (line);
+    break;
+  case '\t':			/* whitespace */
+  case ' ':
+				/* look like function arg def in structure? */
+    if ((t = skipfx (line)) && (s = fndws (t)) && (s = fndnws (s)) &&
+	(((*s == '(') && (s[1] == '*')) ||
+	 ((*s == '*') && (s[1] == '(') && (s[2] == '*'))) &&
+	(s = fndws (s)) && (s[-1] == ')') && (s = fndnws (s)) && (*s == '('))
+      unansi (t);
+    else poot (t);
+    break;
+  default:			/* begins with anything else */
+				/* look like function proto or def? */
+    if ((t = skipfx (line)) && (s = fndws (t)) && (s = fndnws (s)) &&
+	(s = fndws (s)) && (s = fndnws (s)) && (*s == '('))
+      unansi (t);
+    else poot (t);
+    break;
+  }
+}

yatex.org